diff --git a/README.md b/README.md index 52d794d..7ca1ea0 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,23 @@ -# mChat Extension +phpBB Extension - mChat +===================== -[![Build Status](https://travis-ci.org/dmzx/mChat-Extension.svg?branch=master)](https://travis-ci.org/dmzx/mChat-Extension) +[![Build Status](https://travis-ci.org/kasimi/mChat.svg?branch=master)](https://travis-ci.org/kasimi/mChat) ## Install -1. Download the latest release. +1. Download the [latest release](https://github.com/kasimi/mChat/releases). 2. Unzip the downloaded release, and change the name of the folder to `mchat`. -3. In the `ext` directory of your phpBB board, create a new directory named `dmzx` (if it does not already exist). -4. Copy the `mchat` folder to `/ext/dmzx/` (if done correctly, you'll have the main extension class at (your forum root)/ext/dmzx/mchat/composer.json). +3. In the `ext` directory of your phpBB board, create a new directory named `dmzx` if it does not already exist. +4. Copy the `mchat` folder to `/ext/dmzx/`. If done correctly, the folder structure should look like this: `your forum root)/ext/dmzx/mchat/composer.json`. 5. Navigate in the ACP to `Customise -> Manage extensions`. -6. Look for `mChat Extension` under the Disabled Extensions list, and click its `Enable` link. +6. Look for `mChat` under the `Disabled Extensions` list, and click its `Enable` link. ## Uninstall 1. Navigate in the ACP to `Customise -> Extension Management -> Extensions`. -2. Look for `mChat Extension` under the Enabled Extensions list, and click its `Disable` link. +2. Look for `mChat` under the `Enabled Extensions` list, and click its `Disable` link. 3. To permanently uninstall, click `Delete Data` and then delete the `/ext/dmzx/mchat` folder. ## License + [GNU General Public License v2](http://opensource.org/licenses/GPL-2.0) diff --git a/adm/style/acp_mchat_globalsettings.html b/adm/style/acp_mchat_globalsettings.html index 0e83c81..ecd9660 100644 --- a/adm/style/acp_mchat_globalsettings.html +++ b/adm/style/acp_mchat_globalsettings.html @@ -49,6 +49,11 @@
+
+
+
+
+
{L_MCHAT_SETTINGS_ARCHIVE} @@ -61,7 +66,7 @@
{L_MCHAT_SETTINGS_MESSAGES}
-

+

{L_MCHAT_TIMEOUT_EXPLAIN}
@@ -115,7 +120,7 @@

- {L_MCHAT_STATIC_MESSAGE_EXPLAIN}
+ {L_MCHAT_STATIC_MESSAGE_EXPLAIN}
@@ -149,15 +154,23 @@ +
+
+
+ + +
+
{L_MCHAT_SETTINGS_STATS}

- {L_MCHAT_WHOIS_REFRESH_EXPLAIN}
+ {L_MCHAT_WHOIS_REFRESH_EXPLAIN}
+
{L_MCHAT_SETTINGS_PRUNE}
@@ -167,10 +180,19 @@
-
+

+ {L_MCHAT_PRUNE_NUM_EXPLAIN}
- +
+
+
+ + + + +
+
@@ -180,12 +202,12 @@
-
+

-   - +   + {S_FORM_TOKEN}

diff --git a/composer.json b/composer.json index 4ab54d4..5bb982a 100644 --- a/composer.json +++ b/composer.json @@ -1,45 +1,42 @@ { "name": "dmzx/mchat", "type": "phpbb-extension", - "description": "mChat Extension", - "homepage": "http://www.dmzx-web.net", - "version": "2.0.0-RC5", - "time": "2016-04-03", + "description": "mChat", + "homepage": "https://github.com/kasimi/mChat", + "version": "2.0.0-RC6", + "time": "2016-09-18", "keywords": ["phpbb", "extension", "mchat"], "license": "GPL-2.0", "authors": [ + { + "name": "kasimi", + "homepage": "https://kasimi.net", + "email": "mail@kasimi.net", + "role": "Extension Developer" + }, { "name": "dmzx", "homepage": "http://www.dmzx-web.net", "email": "info@dmzx-web.net", "role": "Extension Developer" }, - { - "name": "kasimi", - "homepage": "https://www.phpbb.com/community/memberlist.php?mode=viewprofile&u=1330603", - "role": "Extension Co-Developer" - }, { "name": "RMcGirr83", "homepage": "http://rmcgirr83.org", - "role": "Author" + "role": "Original MOD author" } ], "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "phpbb/phpbb": ">=3.1.7-PL1,<3.3.0@dev" }, "require-dev": { "phpbb/epv": "dev-master" }, "extra": { - "display-name": "mChat Extension", + "display-name": "mChat", "soft-require": { "phpbb/phpbb": ">=3.1.7-PL1,<3.3.0@dev" - }, - "version-check": { - "host": "www.dmzx-web.net", - "directory": "/versions", - "filename": "mchat_version.json" } } } diff --git a/config/config_2_0_0.yml b/config/config_2_0_0.yml deleted file mode 100644 index 927cc06..0000000 --- a/config/config_2_0_0.yml +++ /dev/null @@ -1,174 +0,0 @@ -parameters: - # Global settings that only the administrator is allowed to modify. - # The values are stored in the phpbb_config table and can be - # accessed using the \phpbb\config\config $config class. - dmzx.mchat.config_global: - mchat_bbcode_disallowed: - default: '' - validation: - - 'string' - - false - - 0 - - 255 - mchat_custom_height: - default: 350 - validation: - - 'num' - - false - - 50 - - 1000 - mchat_custom_page: - default: 1 - mchat_edit_delete_limit: - default: 0 - mchat_flood_time: - default: 0 - validation: - - 'num' - - false - - 0 - - 60 - mchat_index_height: - default: 250 - validation: - - 'num' - - false - - 50 - - 1000 - mchat_live_updates: - default: 1 - mchat_max_message_lngth: - default: 500 - validation: - - 'num' - - false - - 0 - - 1000 - mchat_message_num_archive: - default: 25 - validation: - - 'num' - - false - - 10 - - 100 - mchat_message_num_custom: - default: 10 - validation: - - 'num' - - false - - 5 - - 50 - mchat_message_num_index: - default: 10 - validation: - - 'num' - - false - - 5 - - 50 - mchat_navbar_link: - default: 1 - mchat_override_min_post_chars: - default: 0 - mchat_override_smilie_limit: - default: 0 - mchat_posts_edit: - default: 0 - mchat_posts_quote: - default: 0 - mchat_posts_reply: - default: 0 - mchat_posts_topic: - default: 0 - mchat_prune: - default: 0 - mchat_prune_num: - default: 0 - mchat_refresh: - default: 10 - validation: - - 'num' - - false - - 5 - - 60 - mchat_rules: - default: '' - validation: - - 'string' - - false - - 0 - - 255 - mchat_static_message: - default: '' - validation: - - 'string' - - false - - 0 - - 255 - mchat_timeout: - default: 0 - validation: - - 'num' - - false - - 0 - - -1 # This value is replaced with $config['session_length'] in the \dmzx\mchat\core\settings class - mchat_whois: - default: 1 - mchat_whois_refresh: - default: 60 - validation: - - 'num' - - false - - 10 - - 300 - - # User-specific settings for which the administrator can set default - # values as well as adjust permissions to allow users to customize them. - # For each setting a new column is added to the phpbb_users table. - dmzx.mchat.config_ucp: - mchat_avatars: - default: 1 - type: 'BOOL' - mchat_capital_letter: - default: 1 - type: 'BOOL' - mchat_character_count: - default: 1 - type: 'BOOL' - mchat_date: - default: 'D M d, Y g:i a' - type: 'VCHAR:64' - validation: - - 'string' - - false - - 0 - - 64 - mchat_index: - default: 1 - type: 'BOOL' - mchat_input_area: - default: 1 - type: 'BOOL' - mchat_location: - default: 1 - type: 'BOOL' - mchat_message_top: - default: 1 - type: 'BOOL' - mchat_pause_on_input: - default: 0 - type: 'BOOL' - mchat_posts: - default: 1 - type: 'BOOL' - mchat_relative_time: - default: 1 - type: 'BOOL' - mchat_sound: - default: 1 - type: 'BOOL' - mchat_stats_index: - default: 0 - type: 'BOOL' - mchat_whois_index: - default: 1 - type: 'BOOL' diff --git a/config/routing.yml b/config/routing.yml index 74d1ad9..10e31df 100644 --- a/config/routing.yml +++ b/config/routing.yml @@ -1,16 +1,37 @@ -dmzx_mchat_controller: +dmzx_mchat_page_custom_controller: path: /mchat methods: [GET] - defaults: { _controller: dmzx.mchat.main.controller:page, page: custom } -dmzx_mchat_page_controller: - path: /mchat/{page} + defaults: { _controller: dmzx.mchat.core:page_custom } +dmzx_mchat_page_archive_controller: + path: /mchat/archive methods: [GET] - defaults: { _controller: dmzx.mchat.main.controller:page } - requirements: - page: 'archive|rules|whois' -dmzx_mchat_action_controller: - path: /mchat/action-{action} + defaults: { _controller: dmzx.mchat.core:page_archive } +dmzx_mchat_page_rules_controller: + path: /mchat/rules + methods: [GET] + defaults: { _controller: dmzx.mchat.core:page_rules } +dmzx_mchat_page_whois_controller: + path: /mchat/whois/{ip} + methods: [GET] + defaults: { _controller: dmzx.mchat.core:page_whois } + +dmzx_mchat_action_add_controller: + path: /mchat/action/add methods: [POST] - defaults: { _controller: dmzx.mchat.main.controller:action } - requirements: - action: 'add|edit|del|refresh|whois' + defaults: { _controller: dmzx.mchat.core:action_add } +dmzx_mchat_action_edit_controller: + path: /mchat/action/edit + methods: [POST] + defaults: { _controller: dmzx.mchat.core:action_edit } +dmzx_mchat_action_del_controller: + path: /mchat/action/del + methods: [POST] + defaults: { _controller: dmzx.mchat.core:action_del } +dmzx_mchat_action_refresh_controller: + path: /mchat/action/refresh + methods: [POST] + defaults: { _controller: dmzx.mchat.core:action_refresh } +dmzx_mchat_action_whois_controller: + path: /mchat/action/whois + methods: [POST] + defaults: { _controller: dmzx.mchat.core:action_whois } diff --git a/config/services.yml b/config/services.yml index a9e5731..fdf49be 100644 --- a/config/services.yml +++ b/config/services.yml @@ -1,11 +1,11 @@ imports: - { resource: tables.yml } - - { resource: config_2_0_0.yml } services: dmzx.mchat.acp.controller: class: dmzx\mchat\controller\acp_controller arguments: + - '@dmzx.mchat.functions' - '@template' - '@log' - '@user' @@ -14,7 +14,7 @@ services: - '@request' - '@dmzx.mchat.settings' - '%dmzx.mchat.table.mchat%' - - '%dmzx.mchat.table.mchat_deleted_messages%' + - '%dmzx.mchat.table.mchat_log%' - '%core.root_path%' - '%core.php_ext%' dmzx.mchat.ucp.controller: @@ -28,12 +28,6 @@ services: - '@dmzx.mchat.settings' - '%core.root_path%' - '%core.php_ext%' - dmzx.mchat.main.controller: - class: dmzx\mchat\controller\main_controller - arguments: - - '@user' - - '@dmzx.mchat.core' - - '@request' dmzx.mchat.core: class: dmzx\mchat\core\mchat arguments: @@ -59,10 +53,11 @@ services: - '@log' - '@dbal.conn' - '@cache.driver' + - '@dispatcher' - '%core.root_path%' - '%core.php_ext%' - '%dmzx.mchat.table.mchat%' - - '%dmzx.mchat.table.mchat_deleted_messages%' + - '%dmzx.mchat.table.mchat_log%' - '%dmzx.mchat.table.mchat_sessions%' dmzx.mchat.settings: class: dmzx\mchat\core\settings @@ -70,8 +65,6 @@ services: - '@user' - '@config' - '@auth' - - '%dmzx.mchat.config_global%' - - '%dmzx.mchat.config_ucp%' dmzx.mchat.acp.listener: class: dmzx\mchat\event\acp_listener arguments: @@ -89,6 +82,16 @@ services: - '@dmzx.mchat.core' - '@controller.helper' - '@user' + - '@request' - '%core.php_ext%' tags: - { name: event.listener } + dmzx.mchat.cron.task.mchat_prune: + class: dmzx\mchat\cron\mchat_prune + arguments: + - '@dmzx.mchat.functions' + - '@dmzx.mchat.settings' + calls: + - [set_name, [cron.task.mchat_prune]] + tags: + - { name: cron.task } diff --git a/config/tables.yml b/config/tables.yml index 29d1a82..d88d30a 100644 --- a/config/tables.yml +++ b/config/tables.yml @@ -1,4 +1,4 @@ parameters: dmzx.mchat.table.mchat: %core.table_prefix%mchat - dmzx.mchat.table.mchat_deleted_messages: %core.table_prefix%mchat_deleted_messages + dmzx.mchat.table.mchat_log: %core.table_prefix%mchat_log dmzx.mchat.table.mchat_sessions: %core.table_prefix%mchat_sessions diff --git a/controller/acp_controller.php b/controller/acp_controller.php index 47bad30..40e84bf 100644 --- a/controller/acp_controller.php +++ b/controller/acp_controller.php @@ -13,6 +13,9 @@ namespace dmzx\mchat\controller; class acp_controller { + /** @var \dmzx\mchat\core\functions */ + protected $functions; + /** @var \phpbb\template\template */ protected $template; @@ -38,7 +41,7 @@ class acp_controller protected $mchat_table; /** @var string */ - protected $mchat_deleted_messages_table; + protected $mchat_log_table; /** @var string */ protected $root_path; @@ -49,6 +52,7 @@ class acp_controller /** * Constructor * + * @param \dmzx\mchat\core\functions $functions * @param \phpbb\template\template $template * @param \phpbb\log\log_interface $log * @param \phpbb\user $user @@ -57,23 +61,24 @@ class acp_controller * @param \phpbb\request\request $request * @param \dmzx\mchat\core\settings $settings * @param string $mchat_table - * @param string $mchat_deleted_messages_table + * @param string $mchat_log_table * @param string $root_path * @param string $php_ext */ - public function __construct(\phpbb\template\template $template, \phpbb\log\log_interface $log, \phpbb\user $user, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\request\request $request, \dmzx\mchat\core\settings $settings, $mchat_table, $mchat_deleted_messages_table, $root_path, $php_ext) + public function __construct(\dmzx\mchat\core\functions $functions, \phpbb\template\template $template, \phpbb\log\log_interface $log, \phpbb\user $user, \phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\request\request $request, \dmzx\mchat\core\settings $settings, $mchat_table, $mchat_log_table, $root_path, $php_ext) { - $this->template = $template; - $this->log = $log; - $this->user = $user; - $this->db = $db; - $this->cache = $cache; - $this->request = $request; - $this->settings = $settings; - $this->mchat_table = $mchat_table; - $this->mchat_deleted_messages_table = $mchat_deleted_messages_table; - $this->root_path = $root_path; - $this->php_ext = $php_ext; + $this->functions = $functions; + $this->template = $template; + $this->log = $log; + $this->user = $user; + $this->db = $db; + $this->cache = $cache; + $this->request = $request; + $this->settings = $settings; + $this->mchat_table = $mchat_table; + $this->mchat_log_table = $mchat_log_table; + $this->root_path = $root_path; + $this->php_ext = $php_ext; } /** @@ -87,15 +92,9 @@ class acp_controller $error = array(); - if ($this->request->is_set_post('mchat_purge') && $this->request->variable('mchat_purge_confirm', false) && check_form_key('acp_mchat') && $this->user->data['user_type'] == USER_FOUNDER) - { - $this->db->sql_query('TRUNCATE TABLE ' . $this->mchat_table); - $this->db->sql_query('TRUNCATE TABLE ' . $this->mchat_deleted_messages_table); - $this->cache->destroy('sql', $this->mchat_deleted_messages_table); - $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_MCHAT_TABLE_PURGED', false, array($this->user->data['username'])); - trigger_error($this->user->lang('MCHAT_PURGED') . adm_back_link($u_action)); - } - else if ($this->request->is_set_post('submit')) + $is_founder = $this->user->data['user_type'] == USER_FOUNDER; + + if ($this->request->is_set_post('submit')) { $mchat_new_config = array(); $validation = array(); @@ -110,6 +109,13 @@ class acp_controller } } + // Don't allow changing pruning settings for non founders + if (!$is_founder) + { + unset($mchat_new_config['mchat_prune']); + unset($mchat_new_config['mchat_prune_num']); + } + if (!function_exists('validate_data')) { include($this->root_path . 'includes/functions_user.' . $this->php_ext); @@ -140,17 +146,34 @@ class acp_controller $error = array_map(array($this->user, 'lang'), $error); } + if (!$error) + { + if ($is_founder && $this->request->is_set_post('mchat_purge') && $this->request->variable('mchat_purge_confirm', false) && check_form_key('acp_mchat')) + { + $this->db->sql_query('TRUNCATE TABLE ' . $this->mchat_table); + $this->db->sql_query('TRUNCATE TABLE ' . $this->mchat_log_table); + $this->cache->destroy('sql', $this->mchat_log_table); + $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_MCHAT_TABLE_PURGED', false, array($this->user->data['username'])); + trigger_error($this->user->lang('MCHAT_PURGED') . adm_back_link($u_action)); + } + else if ($is_founder && $this->request->is_set_post('mchat_prune_now') && $this->request->variable('mchat_prune_now_confirm', false) && check_form_key('acp_mchat')) + { + $num_pruned_messages = count($this->functions->mchat_prune()); + trigger_error($this->user->lang('MCHAT_PRUNED', $num_pruned_messages) . adm_back_link($u_action)); + } + } + foreach (array_keys($this->settings->global) as $key) { $this->template->assign_var(strtoupper($key), $this->settings->cfg($key)); } $this->template->assign_vars(array( - 'MCHAT_ERROR' => $error ? implode('
', $error) : '', + 'MCHAT_ERROR' => implode('
', $error), 'MCHAT_VERSION' => $this->settings->cfg('mchat_version'), - 'MCHAT_FOUNDER' => $this->user->data['user_type'] == USER_FOUNDER, + 'MCHAT_FOUNDER' => $is_founder, 'L_MCHAT_BBCODES_DISALLOWED_EXPLAIN' => $this->user->lang('MCHAT_BBCODES_DISALLOWED_EXPLAIN', 'root_path}adm/index.$this->php_ext", 'i=bbcodes', true, $this->user->session_id) . '">', ''), - 'L_MCHAT_TIMEOUT_EXPLAIN' => $this->user->lang('MCHAT_USER_TIMEOUT_EXPLAIN','root_path}adm/index.$this->php_ext", 'i=board&mode=load', true, $this->user->session_id) . '">', '', $this->settings->cfg('session_length')), + 'L_MCHAT_TIMEOUT_EXPLAIN' => $this->user->lang('MCHAT_TIMEOUT_EXPLAIN','root_path}adm/index.$this->php_ext", 'i=board&mode=load', true, $this->user->session_id) . '">', '', $this->settings->cfg('session_length')), 'U_ACTION' => $u_action, )); } @@ -238,9 +261,9 @@ class acp_controller $this->template->assign_var('MCHAT_POSTS_ENABLED_LANG', $notifications_template_data); $this->template->assign_vars(array( - 'MCHAT_ERROR' => $error ? implode('
', $error) : '', - 'MCHAT_VERSION' => $this->settings->cfg('mchat_version'), - 'U_ACTION' => $u_action, + 'MCHAT_ERROR' => implode('
', $error), + 'MCHAT_VERSION' => $this->settings->cfg('mchat_version'), + 'U_ACTION' => $u_action, )); } } diff --git a/controller/main_controller.php b/controller/main_controller.php deleted file mode 100644 index 45644a1..0000000 --- a/controller/main_controller.php +++ /dev/null @@ -1,77 +0,0 @@ -user = $user; - $this->mchat = $mchat; - $this->request = $request; - } - - /** - * Controller for mChat - * - * @param string $page The page to render, one of custom|archive|rules|whois - * @return \Symfony\Component\HttpFoundation\Response A Symfony Response object - */ - public function page($page) - { - $this->user->add_lang_ext('dmzx/mchat', 'mchat'); - return call_user_func(array($this->mchat, 'page_' . $page)); - } - - /** - * Controller for mChat actions called with Ajax requests - * - * @param string $action The action to perform, one of add|edit|del|refresh|whois - * @return A Symfony JsonResponse object. - */ - public function action($action) - { - if (!$this->request->is_ajax()) - { - throw new \phpbb\exception\http_exception(403, 'NO_AUTH_OPERATION'); - } - - // Fix avatars & smilies - if (!defined('PHPBB_USE_BOARD_URL_PATH')) - { - define('PHPBB_USE_BOARD_URL_PATH', true); - } - - $this->user->add_lang_ext('dmzx/mchat', 'mchat'); - $data = call_user_func(array($this->mchat, 'action_' . $action)); - - return new JsonResponse($data); - } -} diff --git a/core/functions.php b/core/functions.php index 46df26e..6421281 100644 --- a/core/functions.php +++ b/core/functions.php @@ -31,6 +31,9 @@ class functions /** @var \phpbb\cache\driver\driver_interface */ protected $cache; + /** @var \phpbb\event\dispatcher_interface */ + protected $dispatcher; + /** @var string */ protected $root_path; @@ -41,13 +44,28 @@ class functions protected $mchat_table; /** @var string */ - protected $mchat_deleted_messages_table; + protected $mchat_log_table; /** @var string */ protected $mchat_sessions_table; /** @var array */ - protected $foes = null; + public $log_types = array( + 1 => 'edit', + 2 => 'del', + ); + + /** + * Value of the phpbb_mchat.post_id field for login notification + * messages if the user session is visible at the time of login + */ + const LOGIN_VISIBLE = 1; + + /** + * Value of the phpbb_mchat.post_id field for login notification + * messages if the user session is hidden at the time of login + */ + const LOGIN_HIDDEN = 2; /** * Constructor @@ -58,25 +76,27 @@ class functions * @param \phpbb\log\log_interface $log * @param \phpbb\db\driver\driver_interface $db * @param \phpbb\cache\driver\driver_interface $cache + * @param \phpbb\event\dispatcher_interface $dispatcher * @param string $root_path * @param string $php_ext * @param string $mchat_table - * @param string $mchat_deleted_messages_table + * @param string $mchat_log_table * @param string $mchat_sessions_table */ - function __construct(\dmzx\mchat\core\settings $settings, \phpbb\user $user, \phpbb\auth\auth $auth, \phpbb\log\log_interface $log, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, $root_path, $php_ext, $mchat_table, $mchat_deleted_messages_table, $mchat_sessions_table) + function __construct(\dmzx\mchat\core\settings $settings, \phpbb\user $user, \phpbb\auth\auth $auth, \phpbb\log\log_interface $log, \phpbb\db\driver\driver_interface $db, \phpbb\cache\driver\driver_interface $cache, \phpbb\event\dispatcher_interface $dispatcher, $root_path, $php_ext, $mchat_table, $mchat_log_table, $mchat_sessions_table) { - $this->settings = $settings; - $this->user = $user; - $this->auth = $auth; - $this->log = $log; - $this->db = $db; - $this->cache = $cache; - $this->root_path = $root_path; - $this->php_ext = $php_ext; - $this->mchat_table = $mchat_table; - $this->mchat_deleted_messages_table = $mchat_deleted_messages_table; - $this->mchat_sessions_table = $mchat_sessions_table; + $this->settings = $settings; + $this->user = $user; + $this->auth = $auth; + $this->log = $log; + $this->db = $db; + $this->cache = $cache; + $this->dispatcher = $dispatcher; + $this->root_path = $root_path; + $this->php_ext = $php_ext; + $this->mchat_table = $mchat_table; + $this->mchat_log_table = $mchat_log_table; + $this->mchat_sessions_table = $mchat_sessions_table; } /** @@ -115,7 +135,7 @@ class functions /** * Returns the total session time in seconds * - * @return string + * @return int */ protected function mchat_session_time() { @@ -141,25 +161,52 @@ class functions */ public function mchat_active_users() { - $mchat_users = array(); - $check_time = time() - $this->mchat_session_time(); - $sql = 'SELECT m.user_id, u.username, u.user_type, u.user_allow_viewonline, u.user_colour - FROM ' . $this->mchat_sessions_table . ' m - LEFT JOIN ' . USERS_TABLE . ' u ON m.user_id = u.user_id - WHERE m.user_lastupdate >= ' . (int) $check_time . ' - ORDER BY u.username ASC'; + $sql_array = array( + 'SELECT' => 'u.user_id, u.username, u.user_colour, s.session_viewonline', + 'FROM' => array( + $this->mchat_sessions_table => 'ms' + ), + 'LEFT_JOIN' => array( + array( + 'FROM' => array(SESSIONS_TABLE => 's'), + 'ON' => 'ms.user_id = s.session_user_id', + ), + array( + 'FROM' => array(USERS_TABLE => 'u'), + 'ON' => 'ms.user_id = u.user_id', + ), + ), + 'WHERE' => 'u.user_id <> ' . ANONYMOUS . ' AND s.session_viewonline IS NOT NULL AND ms.user_lastupdate > ' . (int) $check_time, + 'ORDER_BY' => 'u.username ASC', + ); + + /** + * Event to modify the SQL query that fetches active mChat users + * + * @event dmzx.mchat.active_users_sql_before + * @var array sql_array Array with SQL query data to fetch the current active sessions + * @since 2.0.0-RC6 + */ + $vars = array( + 'sql_array', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.active_users_sql_before', compact($vars))); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); $result = $this->db->sql_query($sql); $rows = $this->db->sql_fetchrowset($result); $this->db->sql_freeresult($result); + $mchat_users = array(); $can_view_hidden = $this->auth->acl_get('u_viewonline'); + foreach ($rows as $row) { - if (!$row['user_allow_viewonline']) + if (!$row['session_viewonline']) { - if (!$can_view_hidden) + if (!$can_view_hidden && $row['user_id'] !== $this->user->data['user_id']) { continue; } @@ -167,87 +214,146 @@ class functions $row['username'] = '' . $row['username'] . ''; } - $mchat_users[] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], $this->user->lang('GUEST')); + $mchat_users[$row['user_id']] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], $this->user->lang('GUEST')); } - return array( + $active_users = array( 'online_userlist' => implode($this->user->lang('COMMA_SEPARATOR'), $mchat_users), - 'mchat_users_count' => $this->user->lang('MCHAT_ONLINE_USERS_TOTAL', count($mchat_users)), + 'users_count_title' => $this->user->lang('MCHAT_TITLE_COUNT', count($mchat_users)), + 'users_total' => $this->user->lang('MCHAT_ONLINE_USERS_TOTAL', count($mchat_users)), 'refresh_message' => $this->mchat_format_seconds($this->mchat_session_time()), ); + + /** + * Event to modify collected data about active mChat users + * + * @event dmzx.mchat.active_users_after + * @var array mchat_users Array containing all currently active mChat sessions, mapping from user ID to full username + * @var array active_users Array containing info about currently active mChat users + * @since 2.0.0-RC6 + */ + $vars = array( + 'mchat_users', + 'active_users', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.active_users_after', compact($vars))); + + return $active_users; } /** * Inserts the current user into the mchat_sessions table * - * @return bool + * @return bool Returns true if a new session was created, otherwise false */ public function mchat_add_user_session() { - // Remove expired sessions from the database - $check_time = time() - $this->mchat_session_time(); - $sql = 'DELETE FROM ' . $this->mchat_sessions_table . ' - WHERE user_lastupdate < ' . $check_time; + if (!$this->user->data['is_registered'] || $this->user->data['user_id'] == ANONYMOUS || $this->user->data['is_bot']) + { + return false; + } + + $sql = 'UPDATE ' . $this->mchat_sessions_table . ' + SET user_lastupdate = ' . time() . ' + WHERE user_id = ' . (int) $this->user->data['user_id']; $this->db->sql_query($sql); - $is_new_session = false; + $is_new_session = $this->db->sql_affectedrows() < 1; - if ($this->user->data['user_type'] == USER_FOUNDER || $this->user->data['user_type'] == USER_NORMAL && $this->user->data['user_id'] != ANONYMOUS && !$this->user->data['is_bot']) + if ($is_new_session) { - $sql = 'SELECT * - FROM ' . $this->mchat_sessions_table . ' - WHERE user_id = ' . (int) $this->user->data['user_id']; - $result = $this->db->sql_query($sql); - $row = $this->db->sql_fetchrow($result); - $this->db->sql_freeresult($result); - - if ($row) - { - $sql = 'UPDATE ' . $this->mchat_sessions_table . ' - SET user_lastupdate = ' . time() . ' - WHERE user_id = ' . (int) $this->user->data['user_id']; - } - else - { - $is_new_session = true; - $sql = 'INSERT INTO ' . $this->mchat_sessions_table . ' ' . $this->db->sql_build_array('INSERT', array( - 'user_id' => $this->user->data['user_id'], - 'user_ip' => $this->user->data['user_ip'], - 'user_lastupdate' => time(), - )); - } - + $sql = 'INSERT INTO ' . $this->mchat_sessions_table . ' ' . $this->db->sql_build_array('INSERT', array( + 'user_id' => (int) $this->user->data['user_id'], + 'user_ip' => $this->user->data['user_ip'], + 'user_lastupdate' => time(), + )); $this->db->sql_query($sql); } return $is_new_session; } + /** + * Remove expired sessions from the database + */ + public function mchat_session_gc() + { + $check_time = time() - $this->mchat_session_time(); + + $sql = 'DELETE FROM ' . $this->mchat_sessions_table . ' + WHERE user_lastupdate <= ' . (int) $check_time; + $this->db->sql_query($sql); + } + /** * Prune messages + * + * @return array */ public function mchat_prune() { - if ($this->settings->cfg('mchat_prune')) + $sql_aray = array( + 'SELECT' => 'message_id', + 'FROM' => array($this->mchat_table => 'm'), + ); + + $prune_num = $this->settings->cfg('mchat_prune_num'); + + if (ctype_digit($prune_num)) { - $mchat_total_messages = $this->mchat_total_message_count(); - - if ($mchat_total_messages > $this->settings->cfg('mchat_prune_num')) - { - $sql = 'SELECT message_id - FROM '. $this->mchat_table . ' - ORDER BY message_id ASC'; - $result = $this->db->sql_query_limit($sql, 1); - $first_id = (int) $this->db->sql_fetchfield('message_id'); - $this->db->sql_freeresult($result); - - // Compute new oldest message id - $delete_id = $mchat_total_messages - $this->settings->cfg('mchat_prune_num') + $first_id; - - // Delete older messages - $this->mchat_action('prune', null, $delete_id); - } + // Retain fixed number of messages + $offset = $prune_num; + $sql_aray['ORDER_BY'] = 'message_id DESC'; } + else + { + // Retain messages of a time period + $time_period = strtotime($prune_num, 0); + + if ($time_period === false) + { + $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_MCHAT_TABLE_PRUNE_FAIL', false, array($this->user->data['username'])); + return false; + } + + $offset = 0; + $sql_aray['WHERE'] = 'message_time < ' . (int) (time() - $time_period); + } + + $sql = $this->db->sql_build_query('SELECT', $sql_aray); + $result = $this->db->sql_query_limit($sql, 0, $offset); + $rows = $this->db->sql_fetchrowset(); + $this->db->sql_freeresult($result); + + $prune_ids = array(); + + foreach ($rows as $row) + { + $prune_ids[] = (int) $row['message_id']; + } + + /** + * Event to modify messages that are about to be pruned + * + * @event dmzx.mchat.prune_before + * @var array prune_ids Array of message IDs that are about to be pruned + * @since 2.0.0-RC6 + */ + $vars = array( + 'prune_ids', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.prune_before', compact($vars))); + + if ($prune_ids) + { + $this->db->sql_query('DELETE FROM ' . $this->mchat_table . ' WHERE ' . $this->db->sql_in_set('message_id', $prune_ids)); + $this->db->sql_query('DELETE FROM ' . $this->mchat_log_table . ' WHERE ' . $this->db->sql_in_set('message_id', $prune_ids)); + $this->cache->destroy('sql', $this->mchat_log_table); + } + + $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_MCHAT_TABLE_PRUNED', false, array($this->user->data['username'], count($prune_ids))); + + return $prune_ids; } /** @@ -257,27 +363,77 @@ class functions */ public function mchat_total_message_count() { - return $this->db->get_row_count($this->mchat_table); + $sql_array = array( + 'SELECT' => 'COUNT(*) AS rows_total', + 'FROM' => array($this->mchat_table => 'm'), + ); + + /** + * Event to modifying the SQL query that fetches the total number of mChat messages + * + * @event dmzx.mchat.total_message_count_modify_sql + * @var array sql_array Array with SQL query data to fetch the total message count + * @since 2.0.0-RC6 + */ + $vars = array( + 'sql_array', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.total_message_count_modify_sql', compact($vars))); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); + $result = $this->db->sql_query($sql); + $rows_total = $this->db->sql_fetchfield('rows_total'); + $this->db->sql_freeresult($result); + + return (int) $rows_total; } /** * Fetch messages from the database * - * @param $sql_where + * @param int|array $message_ids IDs of specific messages to fetch, e.g. for fetching edited messages + * @param int $last_id The ID of the latest message that the user has, for fetching new messages * @param int $total * @param int $offset * @return array */ - public function mchat_get_messages($sql_where, $total = 0, $offset = 0) + public function mchat_get_messages($message_ids, $last_id = 0, $total = 0, $offset = 0) { - // Exclude post notifications - if (!$this->settings->cfg('mchat_posts')) + $sql_where_message_id = array(); + + // Fetch new messages + if ($last_id) { - if (!empty($sql_where)) + $sql_where_message_id[] = 'm.message_id > ' . (int) $last_id; + } + + // Fetch edited messages + if ($message_ids) + { + if (!is_array($message_ids)) { - $sql_where = '(' . $sql_where . ') AND '; + $message_ids = array($message_ids); } - $sql_where .= 'm.forum_id = 0'; + + $sql_where_message_id[] = $this->db->sql_in_set('m.message_id', array_map('intval', $message_ids)); + } + + $sql_where_ary = $sql_where_message_id ? array(implode(' OR ', $sql_where_message_id)) : array(); + + if ($this->settings->cfg('mchat_posts')) + { + // If the current user doesn't have permission to see hidden users, exclude their login posts + if (!$this->auth->acl_get('u_viewonline')) + { + $sql_where_ary[] = 'm.post_id <> ' . (int) self::LOGIN_HIDDEN . // Exclude all notifications that were created by hidden users ... + ' OR m.user_id = ' . (int) $this->user->data['user_id'] . // ... but include all login notifications of the current user + ' OR m.forum_id <> 0'; // ... and include all post notifications + } + } + else + { + // Exclude all post notifications + $sql_where_ary[] = 'm.post_id = 0'; } $sql_array = array( @@ -290,13 +446,33 @@ class functions ), array( 'FROM' => array(POSTS_TABLE => 'p'), - 'ON' => 'm.post_id = p.post_id', - ) + 'ON' => 'm.post_id = p.post_id AND m.forum_id <> 0', + ), ), - 'WHERE' => $sql_where, + 'WHERE' => $sql_where_ary ? $this->db->sql_escape('(' . implode(') AND (', $sql_where_ary) . ')') : '', 'ORDER_BY' => 'm.message_id DESC', ); + /** + * Event to modify the SQL query that fetches mChat messages + * + * @event dmzx.mchat.get_messages_modify_sql + * @var array message_ids IDs of specific messages to fetch, e.g. for fetching edited messages + * @var int last_id The ID of the latest message that the user has, for fetching new messages + * @var int total SQL limit + * @var int offset SQL offset + * @var array sql_array Array containing the SQL query data + * @since 2.0.0-RC6 + */ + $vars = array( + 'message_ids', + 'last_id', + 'total', + 'offset', + 'sql_array', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.get_messages_modify_sql', compact($vars))); + $sql = $this->db->sql_build_query('SELECT', $sql_array); $result = $this->db->sql_query_limit($sql, $total, $offset); $rows = $this->db->sql_fetchrowset($result); @@ -314,6 +490,59 @@ class functions return $rows; } + /** + * Fetches log entries from the database and sorts them + * + * @param int $log_id The ID of the latest log entry that the user has + * @return array + */ + public function mchat_get_logs($log_id) + { + $sql_array = array( + 'SELECT' => 'ml.*', + 'FROM' => array($this->mchat_log_table => 'ml'), + 'WHERE' => 'ml.log_id > ' . (int) $log_id, + ); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); + $result = $this->db->sql_query($sql, 3600); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + $logs = array( + 'id' => $log_id, + ); + + foreach ($rows as $row) + { + $logs['id'] = max((int) $logs['id'], (int) $row['log_id']); + $logs[] = $row; + } + + return $logs; + } + + /** + * Fetches the highest log ID + * + * @return int + */ + public function get_latest_log_id() + { + $sql_array = array( + 'SELECT' => 'ml.log_id', + 'FROM' => array($this->mchat_log_table => 'ml'), + 'ORDER_BY' => 'log_id DESC', + ); + + $sql = $this->db->sql_build_query('SELECT', $sql_array); + $result = $this->db->sql_query_limit($sql, 1); + $max_log_id = (int) $this->db->sql_fetchfield('log_id'); + $this->db->sql_freeresult($result); + + return $max_log_id; + } + /** * Generates the user legend markup * @@ -323,23 +552,27 @@ class functions { // Grab group details for legend display for who is online on the custom page $order_legend = $this->settings->cfg('legend_sort_groupname') ? 'group_name' : 'group_legend'; + + $sql_array = array( + 'SELECT' => 'g.group_id, g.group_name, g.group_colour, g.group_type', + 'FROM' => array(GROUPS_TABLE => 'g'), + 'WHERE' => 'group_legend <> 0', + 'ORDER_BY' => 'g.' . $order_legend . ' ASC', + ); + if ($this->auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) { - $sql = 'SELECT group_id, group_name, group_colour, group_type - FROM ' . GROUPS_TABLE . ' - WHERE group_legend <> 0 - ORDER BY ' . $order_legend . ' ASC'; - } - else - { - $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type - FROM ' . GROUPS_TABLE . ' g - LEFT JOIN ' . USER_GROUP_TABLE . ' ug ON (g.group_id = ug.group_id AND ug.user_id = ' . $this->user->data['user_id'] . ' AND ug.user_pending = 0) - WHERE g.group_legend <> 0 - AND (g.group_type <> ' . GROUP_HIDDEN . ' - OR ug.user_id = ' . (int) $this->user->data['user_id'] . ') - ORDER BY g.' . $order_legend . ' ASC'; + $sql_array['LEFT_JOIN'] = array( + array( + 'FROM' => array(USER_GROUP_TABLE => 'ug'), + 'ON' => 'g.group_id = ug.group_id AND ug.user_id = ' . (int) $this->user->data['user_id'] . ' AND ug.user_pending = 0', + ), + ); + + $sql_array['WHERE'] .= ' AND (g.group_type <> ' . GROUP_HIDDEN . ' OR ug.user_id = ' . (int) $this->user->data['user_id'] . ')'; } + + $sql = $this->db->sql_build_query('SELECT', $sql_array); $result = $this->db->sql_query($sql); $rows = $this->db->sql_fetchrowset($result); $this->db->sql_freeresult($result); @@ -369,23 +602,61 @@ class functions */ public function mchat_foes() { - if (is_null($this->foes)) - { - $sql = 'SELECT * - FROM ' . ZEBRA_TABLE . ' - WHERE foe = 1 AND user_id = ' . (int) $this->user->data['user_id']; - $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset($result); - $this->db->sql_freeresult($result); + $sql = 'SELECT zebra_id + FROM ' . ZEBRA_TABLE . ' + WHERE foe = 1 + AND user_id = ' . (int) $this->user->data['user_id']; + $result = $this->db->sql_query($sql); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); - $this->foes = array(); - foreach ($rows as $row) + $foes = array(); + + foreach ($rows as $row) + { + $foes[] = $row['zebra_id']; + } + + return $foes; + } + + /** + * Fetches post subjects and their forum names + * + * @param array $post_ids + * @return array + */ + public function mchat_get_post_data($post_ids) + { + if (!$post_ids) + { + return array(); + } + + $sql = 'SELECT p.post_id, p.post_subject, f.forum_name + FROM ' . POSTS_TABLE . ' p, ' . FORUMS_TABLE . ' f + WHERE p.forum_id = f.forum_id + AND ' . $this->db->sql_in_set('p.post_id', $post_ids); + + $result = $this->db->sql_query($sql); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + $post_subjects = array(); + + foreach ($rows as $row) + { + // Skip deleted posts + if (isset($row['post_subject'])) { - $this->foes[] = $row['zebra_id']; + $post_subjects[$row['post_id']] = array( + 'post_subject' => $row['post_subject'], + 'forum_name' => $row['forum_name'], + ); } } - return $this->foes; + return $post_subjects; } /** @@ -409,43 +680,67 @@ class functions /** * Inserts a message with posting information into the database * - * @param string $mode One of post|quote|edit|reply - * @param $data The post data + * @param string $mode One of post|quote|edit|reply|login + * @param int $forum_id + * @param int $post_id + * @param bool $is_hidden_login */ - public function mchat_insert_posting($mode, $data) + public function mchat_insert_posting($mode, $forum_id, $post_id, $is_hidden_login) { $mode_config = array( 'post' => 'mchat_posts_topic', 'quote' => 'mchat_posts_quote', 'edit' => 'mchat_posts_edit', 'reply' => 'mchat_posts_reply', + 'login' => 'mchat_posts_login', ); - if (empty($mode_config[$mode]) || !$this->settings->cfg($mode_config[$mode])) + $is_mode_enabled = !empty($mode_config[$mode]) && $this->settings->cfg($mode_config[$mode]); + + // Special treatment for login notifications + if ($mode === 'login') { - return; + $forum_id = 0; + $post_id = $is_hidden_login ? self::LOGIN_HIDDEN : self::LOGIN_VISIBLE; } - $board_url = generate_board_url(); - $topic_url = '[url=' . $board_url . '/viewtopic.' . $this->php_ext . '?p=' . $data['post_id'] . '#p' . $data['post_id'] . ']' . $data['post_subject'] . '[/url]'; - $forum_url = '[url=' . $board_url . '/viewforum.' . $this->php_ext . '?f=' . $data['forum_id'] . ']' . $data['forum_name'] . '[/url]'; - $message = $this->user->lang('MCHAT_NEW_' . strtoupper($mode), $topic_url, $forum_url); - - $uid = $bitfield = $options = ''; // will be modified by generate_text_for_storage - generate_text_for_storage($message, $uid, $bitfield, $options, true, false, false); - $sql_ary = array( - 'forum_id' => $data['forum_id'], - 'post_id' => $data['post_id'], - 'user_id' => $this->user->data['user_id'], + $sql_array = array( + 'forum_id' => (int) $forum_id, + 'post_id' => (int) $post_id, + 'user_id' => (int) $this->user->data['user_id'], 'user_ip' => $this->user->data['session_ip'], - 'message' => utf8_normalize_nfc($message), - 'bbcode_bitfield' => $bitfield, - 'bbcode_uid' => $uid, - 'bbcode_options' => $options, + 'message' => 'MCHAT_NEW_' . strtoupper($mode), 'message_time' => time(), ); - $sql = 'INSERT INTO ' . $this->mchat_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary); - $this->db->sql_query($sql); + + /** + * Event that allows to modify data of a posting notification before it is inserted in the database + * + * @event dmzx.mchat.insert_posting_before + * @var string mode The posting mode, one of post|quote|edit|reply|login + * @var int forum_id The ID of the forum where the post was made, or 0 if mode is login. + * @var int post_id The ID of the post that was made. If mode is login this value is + * one of the constants LOGIN_HIDDEN|LOGIN_VISIBLE + * @var bool is_hidden_login Whether or not the user session is hidden. Only used if mode is login. + * @var array is_mode_enabled Whether or not the posting should be added to the database. + * @var array sql_array An array containing the data that is about to be inserted into the messages table. + * @since 2.0.0-RC6 + */ + $vars = array( + 'mode', + 'forum_id', + 'post_id', + 'is_hidden_login', + 'is_mode_enabled', + 'sql_array', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.insert_posting_before', compact($vars))); + + if ($is_mode_enabled) + { + $sql = 'INSERT INTO ' . $this->mchat_table . ' ' . $this->db->sql_build_array('INSERT', $sql_array); + $this->db->sql_query($sql); + } } /** @@ -479,7 +774,7 @@ class functions */ public function mchat_author_for_message($message_id) { - $sql = 'SELECT u.user_id, u.username, m.message_time + $sql = 'SELECT u.user_id, u.username, m.message_time, m.forum_id, m.post_id FROM ' . $this->mchat_table . ' m LEFT JOIN ' . USERS_TABLE . ' u ON m.user_id = u.user_id WHERE m.message_id = ' . (int) $message_id; @@ -490,92 +785,97 @@ class functions return $row; } - /** - * Returns an array of message IDs that have been deleted from the message table - * - * @param $start_id - * @return array - */ - public function mchat_deleted_ids($start_id) - { - $sql = 'SELECT message_id - FROM ' . $this->mchat_deleted_messages_table . ' - WHERE message_id >= ' . (int) $start_id . ' - ORDER BY message_id DESC'; - $result = $this->db->sql_query($sql, 3600); - $rows = $this->db->sql_fetchrowset(); - $this->db->sql_freeresult($result); - - $missing_ids = array(); - foreach ($rows as $row) - { - $missing_ids[] = (int) $row['message_id']; - } - - return $missing_ids; - } - /** * Performs AJAX actions * - * @param string $action One of add|edit|del|prune + * @param string $action One of add|edit|del * @param array $sql_ary * @param int $message_id * @return bool */ public function mchat_action($action, $sql_ary = null, $message_id = 0) { + $update_session_infos = true; + + /** + * Event to modify the SQL query that adds, edits or deletes an mChat message + * + * @event dmzx.mchat.action_before + * @var string action The action that is being performed, one of add|edit|del + * @var bool sql_ary Array containing SQL data, or null if a message is deleted + * @var int message_id The ID of the message that is being edited or deleted, or 0 if a message is added + * @var bool update_session_infos Whether or not to update the user session + * @since 2.0.0-RC6 + */ + $vars = array( + 'action', + 'sql_ary', + 'message_id', + 'update_session_infos', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_before', compact($vars))); + $is_new_session = false; switch ($action) { // User adds a message case 'add': - $this->user->update_session_infos(); + if ($update_session_infos) + { + $this->user->update_session_infos(); + } $is_new_session = $this->mchat_add_user_session(); $this->db->sql_query('INSERT INTO ' . $this->mchat_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary)); break; // User edits a message case 'edit': - $this->user->update_session_infos(); + if ($update_session_infos) + { + $this->user->update_session_infos(); + } $is_new_session = $this->mchat_add_user_session(); $this->db->sql_query('UPDATE ' . $this->mchat_table . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE message_id = ' . (int) $message_id); + $this->mchat_insert_log('edit', $message_id); $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EDITED_MCHAT', false, array($this->user->data['username'])); break; // User deletes a message case 'del': - $this->user->update_session_infos(); + if ($update_session_infos) + { + $this->user->update_session_infos(); + } $is_new_session = $this->mchat_add_user_session(); $this->db->sql_query('DELETE FROM ' . $this->mchat_table . ' WHERE message_id = ' . (int) $message_id); - $this->db->sql_query('INSERT INTO ' . $this->mchat_deleted_messages_table . ' ' . $this->db->sql_build_array('INSERT', array('message_id' => (int) $message_id))); - $this->cache->destroy('sql', $this->mchat_deleted_messages_table); + $this->mchat_insert_log('del', $message_id); $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_DELETED_MCHAT', false, array($this->user->data['username'])); break; - - // User triggers messages to be pruned - case 'prune': - $sql = 'SELECT message_id - FROM ' . $this->mchat_table . ' - WHERE message_id < ' . (int) $message_id . ' - ORDER BY message_id DESC'; - $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset(); - $this->db->sql_freeresult($result); - - $prune_ids = array(); - foreach ($rows as $row) - { - $prune_ids[] = (int) $row['message_id']; - } - - $this->db->sql_query('DELETE FROM ' . $this->mchat_table . ' WHERE ' .$this->db->sql_in_set('message_id', $prune_ids)); - $this->db->sql_multi_insert($this->mchat_deleted_messages_table, $rows); - $this->cache->destroy('sql', $this->mchat_deleted_messages_table); - break; } return $is_new_session; } + + /** + * @param string $log_type The log type, one of edit|del + * @param int $message_id The ID of the message to which this log entry belongs + * @return int The ID of the newly added log row + */ + public function mchat_insert_log($log_type, $message_id) + { + $this->db->sql_query('INSERT INTO ' . $this->mchat_log_table . ' ' . $this->db->sql_build_array('INSERT', array( + 'log_type' => array_search($log_type, $this->log_types), + 'user_id' => (int) $this->user->data['user_id'], + 'message_id' => (int) $message_id, + 'log_ip' => $this->user->ip, + 'log_time' => time(), + ))); + + $log_id = (int) $this->db->sql_nextid(); + + $this->cache->destroy('sql', $this->mchat_log_table); + + return $log_id; + } } diff --git a/core/mchat.php b/core/mchat.php index 39932d6..2bb6741 100644 --- a/core/mchat.php +++ b/core/mchat.php @@ -11,6 +11,9 @@ namespace dmzx\mchat\core; +use Symfony\Component\HttpFoundation\JsonResponse; +use phpbb\exception\http_exception; + class mchat { /** @var \dmzx\mchat\core\functions */ @@ -55,6 +58,12 @@ class mchat /** @var boolean */ protected $remove_disallowed_bbcodes = false; + /** @var array */ + protected $active_users = null; + + /** @var array */ + protected $foes = null; + /** * Constructor * @@ -129,16 +138,21 @@ class mchat { if (!$this->auth->acl_get('u_mchat_view')) { - throw new \phpbb\exception\http_exception(403, 'NOT_AUTHORISED'); + if (!$this->user->data['is_registered']) + { + login_box(); + } + + throw new http_exception(403, 'NOT_AUTHORISED'); } + $this->user->add_lang_ext('dmzx/mchat', 'mchat'); + if (!$this->settings->cfg('mchat_custom_page')) { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NO_CUSTOM_PAGE'); + throw new http_exception(404, 'MCHAT_NO_CUSTOM_PAGE'); } - $this->functions->mchat_prune(); - $this->functions->mchat_add_user_session(); $this->assign_whois(); @@ -152,7 +166,7 @@ class mchat // Add to navlinks $this->template->assign_block_vars('navlinks', array( 'FORUM_NAME' => $this->user->lang('MCHAT_TITLE'), - 'U_VIEW_FORUM' => $this->helper->route('dmzx_mchat_controller'), + 'U_VIEW_FORUM' => $this->helper->route('dmzx_mchat_page_custom_controller'), )); return $this->helper->render('mchat_body.html', $this->user->lang('MCHAT_TITLE')); @@ -165,12 +179,17 @@ class mchat */ public function page_archive() { + $this->user->add_lang_ext('dmzx/mchat', 'mchat'); + if (!$this->auth->acl_get('u_mchat_view') || !$this->auth->acl_get('u_mchat_archive')) { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NOACCESS_ARCHIVE'); - } + if (!$this->user->data['is_registered']) + { + login_box(); + } - $this->functions->mchat_prune(); + throw new http_exception(403, 'MCHAT_NOACCESS_ARCHIVE'); + } $this->template->assign_var('MCHAT_IS_ARCHIVE_PAGE', true); @@ -180,11 +199,11 @@ class mchat $this->template->assign_block_vars_array('navlinks', array( array( 'FORUM_NAME' => $this->user->lang('MCHAT_TITLE'), - 'U_VIEW_FORUM' => $this->helper->route('dmzx_mchat_controller'), + 'U_VIEW_FORUM' => $this->helper->route('dmzx_mchat_page_custom_controller'), ), array( 'FORUM_NAME' => $this->user->lang('MCHAT_ARCHIVE'), - 'U_VIEW_FORUM' => $this->helper->route('dmzx_mchat_page_controller', array('page' => 'archive')), + 'U_VIEW_FORUM' => $this->helper->route('dmzx_mchat_page_archive_controller'), ), )); @@ -194,21 +213,29 @@ class mchat /** * Controller for mChat IP WHOIS * + * @param string $ip * @return \Symfony\Component\HttpFoundation\Response A Symfony Response object */ - public function page_whois() + public function page_whois($ip) { if (!$this->auth->acl_get('u_mchat_ip')) { - throw new \phpbb\exception\http_exception(403, 'NOT_AUTHORISED'); + if (!$this->user->data['is_registered']) + { + login_box(); + } + + throw new http_exception(403, 'NOT_AUTHORISED'); } + $this->user->add_lang_ext('dmzx/mchat', 'mchat'); + if (!function_exists('user_ipwhois')) { include($this->root_path . 'includes/functions_user.' . $this->php_ext); } - $this->template->assign_var('WHOIS', user_ipwhois($this->request->variable('ip', ''))); + $this->template->assign_var('WHOIS', user_ipwhois($ip)); return $this->helper->render('viewonline_whois.html', $this->user->lang('WHO_IS_ONLINE')); } @@ -222,13 +249,21 @@ class mchat { if (!$this->auth->acl_get('u_mchat_view')) { - throw new \phpbb\exception\http_exception(403, 'NOT_AUTHORISED'); + if (!$this->user->data['is_registered']) + { + login_box(); + } + + throw new http_exception(403, 'NOT_AUTHORISED'); } + $this->user->add_lang_ext('dmzx/mchat', 'mchat'); + $lang_rules = $this->user->lang('MCHAT_RULES_MESSAGE'); + if (!$this->settings->cfg('mchat_rules') && !$lang_rules) { - throw new \phpbb\exception\http_exception(404, 'MCHAT_NO_RULES'); + throw new http_exception(404, 'MCHAT_NO_RULES'); } // If the rules are defined in the language file use them, else just use the entry in the database @@ -241,185 +276,329 @@ class mchat return $this->helper->render('mchat_rules.html', $this->user->lang('MCHAT_RULES')); } + /** + * Initialize AJAX action + * + * @param string $permission Permission that is required to perform the current action + * @param bool $check_form_key + */ + protected function init_action($permission, $check_form_key = true) + { + if (!$this->request->is_ajax() || !$this->auth->acl_get($permission) || ($check_form_key && !check_form_key('mchat', -1))) + { + throw new http_exception(403, 'NO_AUTH_OPERATION'); + } + + // Fix avatars & smilies + if (!defined('PHPBB_USE_BOARD_URL_PATH')) + { + define('PHPBB_USE_BOARD_URL_PATH', true); + } + + $this->user->add_lang_ext('dmzx/mchat', 'mchat'); + } + /** * User submits a message * + * @param bool $return_raw * @return array data sent to client as JSON */ - public function action_add() + public function action_add($return_raw = false) { - if (!$this->auth->acl_get('u_mchat_use') || !check_form_key('mchat', -1)) - { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NOACCESS'); - } + $this->init_action('u_mchat_use'); if ($this->functions->mchat_is_user_flooding()) { - throw new \phpbb\exception\http_exception(400, 'MCHAT_NOACCESS'); + throw new http_exception(400, 'MCHAT_FLOOD'); } $message = $this->request->variable('message', '', true); - if ($this->settings->cfg('mchat_capital_letter')) - { - $message = utf8_ucfirst($message); - } - - $sql_ary = $this->process_message($message, array( + $message_data = array( 'user_id' => $this->user->data['user_id'], 'user_ip' => $this->user->data['session_ip'], 'message_time' => time(), - )); + ); + + /** + * Event to modify a new message before it is inserted in the database + * + * @event dmzx.mchat.action_add_before + * @var string message The message that is about to be processed and added to the database + * @var array message_data Array containing additional information that is added to the database + * @since 2.0.0-RC6 + */ + $vars = array( + 'message', + 'message_data', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_add_before', compact($vars))); + + $sql_ary = array_merge($this->process_message($message), $message_data); + + if ($this->settings->cfg('mchat_capital_letter')) + { + $sql_ary['message'] = utf8_ucfirst($sql_ary['message']); + } $is_new_session = $this->functions->mchat_action('add', $sql_ary); - /** - * Event render_helper_add - * - * @event dmzx.mchat.core.render_helper_add - * @since 0.1.2 - */ - $this->dispatcher->dispatch('dmzx.mchat.core.render_helper_add'); - - $data = $this->action_refresh(); + $response = $this->action_refresh(true); if ($is_new_session) { - $data['whois'] = true; + $response = array_merge($response, $this->action_whois(true)); } - return $data; + /** + * Event to modify message data of a user's new message before it is sent back to the user + * + * @event dmzx.mchat.action_add_after + * @var string message The message that was added to the database + * @var array message_data Array containing additional information that was added to the database + * @var bool is_new_session Indicating whether the message triggered a new mChat session to be created for the user + * @var array response The data that is sent back to the user + * @var boolean return_raw Whether to return a raw array or a JsonResponse object + * @since 2.0.0-RC6 + */ + $vars = array( + 'message', + 'message_data', + 'is_new_session', + 'response', + 'return_raw', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_add_after', compact($vars))); + + return $return_raw ? $response : new JsonResponse($response); } /** * User edits a message * + * @param bool $return_raw * @return array data sent to client as JSON */ - public function action_edit() + public function action_edit($return_raw = false) { + $this->init_action('u_mchat_use'); + $message_id = $this->request->variable('message_id', 0); - if (!$message_id || !check_form_key('mchat', -1)) + if (!$message_id) { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NOACCESS'); + throw new http_exception(403, 'NO_AUTH_OPERATION'); } $author = $this->functions->mchat_author_for_message($message_id); - if (!$author || !$this->auth_message('u_mchat_edit', $author['user_id'], $author['message_time'])) + if (!$author || $author['post_id'] || !$this->auth_message('edit', $author['user_id'], $author['message_time'])) { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NOACCESS'); + throw new http_exception(403, 'NO_AUTH_OPERATION'); } $this->template->assign_var('MCHAT_IS_ARCHIVE_PAGE', $this->request->variable('archive', false)); $message = $this->request->variable('message', '', true); - - $sql_ary = $this->process_message($message, array( - 'edit_time' => time(), - )); - + $sql_ary = $this->process_message($message); $this->functions->mchat_action('edit', $sql_ary, $message_id); - /** - * Event render_helper_edit - * - * @event dmzx.mchat.core.render_helper_edit - * @since 0.1.4 - */ - $this->dispatcher->dispatch('dmzx.mchat.core.render_helper_edit'); - - $sql_where = 'm.message_id = ' . (int) $message_id; - $rows = $this->functions->mchat_get_messages($sql_where, 1); + $rows = $this->functions->mchat_get_messages($message_id); $this->assign_global_template_data(); $this->assign_messages($rows); - return array('edit' => $this->render_template('mchat_messages.html')); + $response = array('edit' => $this->render_template('mchat_messages.html')); + + /** + * Event to modify the data of an edited message + * + * @event dmzx.mchat.action_edit_after + * @var int message_id The ID of the edited message + * @var string message The content of the edited message that was added to the database + * @var array author Information about the message author + * @var array response The data that is sent back to the user + * @var boolean return_raw Whether to return a raw array or a JsonResponse object + * @since 2.0.0-RC6 + */ + $vars = array( + 'message_id', + 'message', + 'author', + 'response', + 'return_raw', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_edit_after', compact($vars))); + + return $return_raw ? $response : new JsonResponse($response); } /** * User deletes a message * + * @param bool $return_raw * @return array data sent to client as JSON */ - public function action_del() + public function action_del($return_raw = false) { + $this->init_action('u_mchat_use'); + $message_id = $this->request->variable('message_id', 0); - if (!$message_id || !check_form_key('mchat', -1)) + if (!$message_id) { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NOACCESS'); + throw new http_exception(403, 'NO_AUTH_OPERATION'); } $author = $this->functions->mchat_author_for_message($message_id); - if (!$author || !$this->auth_message('u_mchat_delete', $author['user_id'], $author['message_time'])) + if (!$author || !$this->auth_message('delete', $author['user_id'], $author['message_time'])) { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NOACCESS'); + throw new http_exception(403, 'NO_AUTH_OPERATION'); } - /** - * Event render_helper_delete - * - * @event dmzx.mchat.core.render_helper_delete - * @since 0.1.4 - */ - $this->dispatcher->dispatch('dmzx.mchat.core.render_helper_delete'); - $this->functions->mchat_action('del', null, $message_id); - return array('del' => true); + $response = array('del' => true); + + /** + * Event that is triggered after an mChat message was deleted + * + * @event dmzx.mchat.action_delete_after + * @var int message_id The ID of the deleted message + * @var array author Information about the message author + * @var array response The data that is sent back to the user + * @var boolean return_raw Whether to return a raw array or a JsonResponse object + * @since 2.0.0-RC6 + */ + $vars = array( + 'message_id', + 'author', + 'response', + 'return_raw', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_delete_after', compact($vars))); + + return $return_raw ? $response : new JsonResponse($response); } /** * User checks for new messages * + * @param bool $return_raw * @return array sent to client as JSON */ - public function action_refresh() + public function action_refresh($return_raw = false) { - if (!$this->auth->acl_get('u_mchat_view')) - { - throw new \phpbb\exception\http_exception(403, 'MCHAT_NOACCESS'); - } + $this->init_action('u_mchat_view', false); - // Keep the session alive forever if there is no user session timeout - if (!$this->settings->cfg('mchat_timeout')) + // Keep the session alive forever if there is no session timeout + $keep_session_alive = !$this->settings->cfg('mchat_timeout'); + + // Whether to check the log table for new entries + $need_log_update = $this->settings->cfg('mchat_live_updates'); + + /** + * Event that is triggered before new mChat messages are checked + * + * @event dmzx.mchat.action_refresh_before + * @var bool keep_session_alive Whether to the user's phpBB session + * @var bool need_log_update Whether to check the log table for new entries + * @since 2.0.0-RC6 + */ + $vars = array( + 'keep_session_alive', + 'need_log_update', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_refresh_before', compact($vars))); + + if ($keep_session_alive) { $this->user->update_session_infos(); } - $message_first_id = $this->request->variable('message_first_id', 0); - $message_last_id = $this->request->variable('message_last_id', 0); - $message_edits = $this->request->variable('message_edits', array(0)); + $response = array('refresh' => true); + $log_edit_del_ids = array( + 'edit' => array(), + 'del' => array(), + ); - // Request new messages - $sql_where = 'm.message_id > ' . (int) $message_last_id; - - // Request edited messages - if ($this->settings->cfg('mchat_live_updates') && $message_last_id > 0) + if ($need_log_update) { - $sql_where .= sprintf(' OR (m.message_id BETWEEN %d AND %d AND m.edit_time > 0)', (int) $message_first_id , (int) $message_last_id); - if ($this->settings->cfg('mchat_edit_delete_limit')) + $log_id = $this->request->variable('log', 0); + $log_rows = $this->functions->mchat_get_logs($log_id); + + $response['log'] = $log_rows['id']; + unset($log_rows['id']); + + $edit_delete_limit = $this->settings->cfg('mchat_edit_delete_limit'); + $time_limit = $edit_delete_limit ? time() - $edit_delete_limit : 0; + + foreach ($log_rows as $log_row) { - $sql_where .= sprintf(' AND m.message_time > %d', time() - $this->settings->cfg('mchat_edit_delete_limit')); + $log_type = $log_row['log_type']; + + if (isset($this->functions->log_types[$log_type])) + { + if ($log_row['user_id'] != $this->user->data['user_id'] && $log_row['log_time'] > $time_limit) + { + $log_type_name = $this->functions->log_types[$log_type]; + $log_edit_del_ids[$log_type_name][] = (int) $log_row['message_id']; + } + } + + /** + * Event that allows processing log messages + * + * @event dmzx.mchat.action_refresh_process_log_row + * @var array response The data that is sent back to the user (still incomplete at this point) + * @var array log_row The log data + * @since 2.0.0-RC6 + */ + $vars = array( + 'response', + 'log_row', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_refresh_process_log_row', compact($vars))); } } - $rows = $this->functions->mchat_get_messages($sql_where); + $last_id = $this->request->variable('last', 0); + $total = 0; + $offset = 0; + + /** + * Event that allows modifying data before new mChat messages are fetched + * + * @event dmzx.mchat.action_refresh_get_messages_before + * @var array response The data that is sent back to the user (still incomplete at this point) + * @var array log_edit_del_ids An array containing IDs of messages that have been edited or deleted since the user's last refresh + * @var int last_id The latest message that the user has + * @var int total Limit the number of messages to fetch + * @var int offset The number of messages to skip + * @since 2.0.0-RC6 + */ + $vars = array( + 'response', + 'log_edit_del_ids', + 'last_id', + 'total', + 'offset', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_refresh_get_messages_before', compact($vars))); + + $rows = $this->functions->mchat_get_messages($log_edit_del_ids['edit'], $last_id, $total, $offset); $rows_refresh = array(); $rows_edit = array(); foreach ($rows as $row) { - $message_id = $row['message_id']; - if ($message_id > $message_last_id) + if ($row['message_id'] > $last_id) { $rows_refresh[] = $row; } - else if (!isset($message_edits[$message_id]) || $message_edits[$message_id] < $row['edit_time']) + else if (in_array($row['message_id'], $log_edit_del_ids['edit'])) { $rows_edit[] = $row; } @@ -430,8 +609,6 @@ class mchat $this->assign_global_template_data(); } - $response = array('refresh' => true); - // Assign new messages if ($rows_refresh) { @@ -447,28 +624,65 @@ class mchat } // Assign deleted messages - if ($this->settings->cfg('mchat_live_updates') && $message_last_id > 0) + if ($log_edit_del_ids['del']) { - $deleted_message_ids = $this->functions->mchat_deleted_ids($message_first_id); - if ($deleted_message_ids) - { - $response['del'] = $deleted_message_ids; - } + $response['del'] = $log_edit_del_ids['del']; } - return $response; + /** + * Event to modify the data that is sent to the user after checking for new mChat message + * + * @event dmzx.mchat.action_refresh_after + * @var array rows The rows that where fetched from the database + * @var array response The data that is sent back to the user + * @var boolean return_raw Whether to return a raw array or a JsonResponse object + * @since 2.0.0-RC6 + */ + $vars = array( + 'rows', + 'response', + 'return_raw', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_refresh_after', compact($vars))); + + return $return_raw ? $response : new JsonResponse($response); } /** * User requests who is chatting * + * @param bool $return_raw * @return array data sent to client as JSON */ - public function action_whois() + public function action_whois($return_raw = false) { + $this->init_action('u_mchat_view', false); + $this->assign_whois(); - return array('whois' => $this->render_template('mchat_whois.html')); + $response = array('whois' => $this->render_template('mchat_whois.html')); + + if ($this->settings->cfg('mchat_navbar_link_count') && $this->settings->cfg('mchat_navbar_link') && $this->settings->cfg('mchat_custom_page') && $this->active_users) + { + $response['navlink'] = $this->active_users['users_count_title']; + $response['navlink_title'] = strip_tags($this->active_users['users_total']); + } + + /** + * Event to modify the result of the Who Is Online update + * + * @event dmzx.mchat.action_whois_after + * @var array response The data that is sent back to the user + * @var boolean return_raw Whether to return a raw array or a JsonResponse object + * @since 2.0.0-RC6 + */ + $vars = array( + 'response', + 'return_raw', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.action_whois_after', compact($vars))); + + return $return_raw ? $response : new JsonResponse($response); } /** @@ -476,12 +690,34 @@ class mchat */ public function render_page_header_link() { - $this->template->assign_vars(array( - 'MCHAT_ALLOW_VIEW' => $this->auth->acl_get('u_mchat_view'), - 'MCHAT_NAVBAR_LINK' => $this->settings->cfg('mchat_navbar_link'), - 'MCHAT_CUSTOM_PAGE' => $this->settings->cfg('mchat_custom_page'), - 'U_MCHAT' => $this->helper->route('dmzx_mchat_controller'), - )); + if (!$this->auth->acl_get('u_mchat_view')) + { + return; + } + + $navbar_link = $this->settings->cfg('mchat_navbar_link'); + $custom_page = $this->settings->cfg('mchat_custom_page'); + + $template_data = array( + 'MCHAT_NAVBAR_LINK' => $navbar_link, + 'MCHAT_CUSTOM_PAGE' => $custom_page, + 'MCHAT_TITLE' => $this->user->lang('MCHAT_TITLE'), + 'MCHAT_TITLE_HINT' => $this->user->lang('MCHAT_TITLE'), + 'U_MCHAT' => $this->helper->route('dmzx_mchat_page_custom_controller'), + ); + + if ($navbar_link && $custom_page && $this->settings->cfg('mchat_navbar_link_count')) + { + if ($this->active_users === null) + { + $this->active_users = $this->functions->mchat_active_users(); + } + + $template_data['MCHAT_TITLE'] = $this->active_users['users_count_title']; + $template_data['MCHAT_TITLE_HINT'] = strip_tags($this->active_users['users_total']); + } + + $this->template->assign_vars($template_data); } /** @@ -491,6 +727,18 @@ class mchat */ protected function render_page($page) { + /** + * Event that is triggered before mChat is rendered + * + * @event dmzx.mchat.render_page_before + * @var string page The page that is rendered, one of index|custom|archive + * @since 2.0.0-RC6 + */ + $vars = array( + 'page', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.render_page_before', compact($vars))); + // Add lang file $this->user->add_lang('posting'); @@ -498,11 +746,8 @@ class mchat $lang_static_message = $this->user->lang('MCHAT_STATIC_MESSAGE'); $static_message = $lang_static_message ?: $this->settings->cfg('mchat_static_message'); - $u_mchat_use = $this->auth->acl_get('u_mchat_use'); - $this->template->assign_vars(array( - 'MCHAT_ALLOW_USE' => $u_mchat_use, - 'S_BBCODE_ALLOWED' => $this->settings->cfg('allow_bbcode') && $this->auth->acl_get('u_mchat_bbcode'), + 'MCHAT_PAGE' => $page, 'MCHAT_ALLOW_SMILES' => $this->settings->cfg('allow_smilies') && $this->auth->acl_get('u_mchat_smilies'), 'MCHAT_INPUT_AREA' => $this->settings->cfg('mchat_input_area'), 'MCHAT_MESSAGE_TOP' => $this->settings->cfg('mchat_message_top'), @@ -517,18 +762,20 @@ class mchat 'MCHAT_PAUSE_ON_INPUT' => $this->settings->cfg('mchat_pause_on_input'), 'MCHAT_MESSAGE_LNGTH' => $this->settings->cfg('mchat_max_message_lngth'), 'MCHAT_WHOIS_INDEX' => $this->settings->cfg('mchat_whois_index'), - 'MCHAT_WHOIS_REFRESH' => $this->settings->cfg('mchat_whois') ? $this->settings->cfg('mchat_whois_refresh') * 1000 : 0, + 'MCHAT_WHOIS_REFRESH' => $this->settings->cfg('mchat_whois_index') || $this->settings->cfg('mchat_stats_index') ? $this->settings->cfg('mchat_whois_refresh') * 1000 : 0, 'MCHAT_REFRESH_JS' => $this->settings->cfg('mchat_refresh') * 1000, 'MCHAT_ARCHIVE' => $this->auth->acl_get('u_mchat_archive'), 'MCHAT_RULES' => $this->user->lang('MCHAT_RULES_MESSAGE') || $this->settings->cfg('mchat_rules'), 'MCHAT_WHOIS_REFRESH_EXPLAIN' => $this->user->lang('MCHAT_WHO_IS_REFRESH_EXPLAIN', $this->settings->cfg('mchat_whois_refresh')), 'MCHAT_SESSION_TIMELEFT' => $this->user->lang('MCHAT_SESSION_ENDS', gmdate('H:i:s', (int) $this->settings->cfg('mchat_timeout'))), + 'MCHAT_LOG_ID' => $this->functions->get_latest_log_id(), 'MCHAT_STATIC_MESS' => htmlspecialchars_decode($static_message), 'A_MCHAT_MESS_LONG' => addslashes($this->user->lang('MCHAT_MESS_LONG', $this->settings->cfg('mchat_max_message_lngth'))), 'A_MCHAT_REFRESH_YES' => addslashes($this->user->lang('MCHAT_REFRESH_YES', $this->settings->cfg('mchat_refresh'))), - 'U_MCHAT_CUSTOM_PAGE' => $this->helper->route('dmzx_mchat_controller'), - 'U_MCHAT_RULES' => $this->helper->route('dmzx_mchat_page_controller', array('page' => 'rules')), - 'U_MCHAT_ARCHIVE_URL' => $this->helper->route('dmzx_mchat_page_controller', array('page' => 'archive')), + 'A_COOKIE_NAME' => addslashes($this->settings->cfg('cookie_name', true) . '_'), + 'U_MCHAT_CUSTOM_PAGE' => $this->helper->route('dmzx_mchat_page_custom_controller'), + 'U_MCHAT_RULES' => $this->helper->route('dmzx_mchat_page_rules_controller'), + 'U_MCHAT_ARCHIVE_URL' => $this->helper->route('dmzx_mchat_page_archive_controller'), )); // The template needs some language variables if we display relative time for messages @@ -547,25 +794,25 @@ class mchat // Get actions which the user is allowed to perform on the current page $actions = array_keys(array_filter(array( - 'edit' => $this->auth_message('u_mchat_edit', true, time()), - 'del' => $this->auth_message('u_mchat_delete', true, time()), + 'edit' => $this->auth_message('edit', true, time()), + 'del' => $this->auth_message('delete', true, time()), 'refresh' => $page !== 'archive' && $this->auth->acl_get('u_mchat_view'), - 'add' => $page !== 'archive' && $u_mchat_use, - 'whois' => $page !== 'archive' && $this->settings->cfg('mchat_whois'), + 'add' => $page !== 'archive' && $this->auth->acl_get('u_mchat_use'), + 'whois' => $page !== 'archive' && ($this->settings->cfg('mchat_whois_index') || $this->settings->cfg('mchat_stats_index')), ))); foreach ($actions as $i => $action) { $this->template->assign_block_vars('mchaturl', array( 'ACTION' => $action, - 'URL' => $this->helper->route('dmzx_mchat_action_controller', array('action' => $action)), + 'URL' => $this->helper->route('dmzx_mchat_action_' . $action . '_controller'), 'IS_LAST' => $i + 1 === count($actions), )); } $limit = $this->settings->cfg('mchat_message_num_' . $page); $start = $page === 'archive' ? $this->request->variable('start', 0) : 0; - $rows = $this->functions->mchat_get_messages('', $limit, $start); + $rows = $this->functions->mchat_get_messages(array(), 0, $limit, $start); $this->assign_global_template_data(); $this->assign_messages($rows); @@ -573,14 +820,33 @@ class mchat // Render pagination if ($page === 'archive') { - $archive_url = $this->helper->route('dmzx_mchat_page_controller', array('page' => 'archive')); + $archive_url = $this->helper->route('dmzx_mchat_page_archive_controller'); $total_messages = $this->functions->mchat_total_message_count(); + + /** + * Event to modify mChat pagination on the archive page + * + * @event dmzx.mchat.render_page_pagination_before + * @var string archive_url Pagination base URL + * @var int total_messages Total number of messages + * @var int limit Number of messages to display per page + * @var int start The message which should be considered currently active, used to determine the page we're on + * @since 2.0.0-RC6 + */ + $vars = array( + 'archive_url', + 'total_messages', + 'limit', + 'start', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.render_page_pagination_before', compact($vars))); + $this->pagination->generate_template_pagination($archive_url, 'pagination', 'start', $total_messages, $limit, $start); $this->template->assign_var('MCHAT_TOTAL_MESSAGES', $this->user->lang('MCHAT_TOTALMESSAGES', $total_messages)); } // Render legend - if ($page !== 'index' && $this->settings->cfg('mchat_whois')) + if ($page !== 'index') { $legend = $this->functions->mchat_legend(); $this->template->assign_var('LEGEND', implode($this->user->lang('COMMA_SEPARATOR'), $legend)); @@ -593,7 +859,7 @@ class mchat $this->template->assign_vars(array( 'MCHAT_IS_COLLAPSIBLE' => true, 'S_MCHAT_HIDDEN' => in_array($cc_fid, $this->cc_operator->get_user_categories()), - 'U_MCHAT_COLLAPSE_URL' => $this->helper->route('phpbb_collapsiblecategories_main_controller', array( + 'U_MCHAT_COLLAPSE_URL' => $this->helper->route('phpbb_collapsiblecategories_main_controller', array( 'forum_id' => $cc_fid, 'hash' => generate_link_hash('collapsible_' . $cc_fid), )), @@ -602,18 +868,24 @@ class mchat $this->assign_authors(); - if ($u_mchat_use) + if ($this->auth->acl_get('u_mchat_use')) { add_form_key('mchat'); } /** - * Event render_helper_aft - * - * @event dmzx.mchat.core.render_helper_aft - * @since 0.1.2 - */ - $this->dispatcher->dispatch('dmzx.mchat.core.render_helper_aft'); + * Event that is triggered after mChat was rendered + * + * @event dmzx.mchat.render_page_after + * @var string page The page that was rendered, one of index|custom|archive + * @var array actions Array containing URLs to actions the user is allowed to perform + * @since 2.0.0-RC6 + */ + $vars = array( + 'page', + 'actions', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.render_page_after', compact($vars))); } /** @@ -627,7 +899,7 @@ class mchat $author_names = array(); $author_homepages = array(); - foreach ($meta['authors'] as $author) + foreach (array_slice($meta['authors'], 0, 2) as $author) { $author_names[] = $author['name']; $author_homepages[] = sprintf('%2$s', $author['homepage'], $author['name']); @@ -643,22 +915,38 @@ class mchat /** * Assigns common template data that is required for displaying messages */ - protected function assign_global_template_data() + public function assign_global_template_data() { - $this->template->assign_vars(array( - 'MCHAT_ALLOW_IP' => $this->auth->acl_get('u_mchat_ip'), - 'MCHAT_ALLOW_PM' => $this->auth->acl_get('u_mchat_pm'), - 'MCHAT_ALLOW_LIKE' => $this->auth->acl_get('u_mchat_like'), - 'MCHAT_ALLOW_QUOTE' => $this->auth->acl_get('u_mchat_quote'), - 'MCHAT_ALLOW_PERMISSIONS' => $this->auth->acl_get('a_authusers'), - 'MCHAT_EDIT_DELETE_LIMIT' => 1000 * $this->settings->cfg('mchat_edit_delete_limit'), - 'MCHAT_EDIT_DELETE_IGNORE' => $this->settings->cfg('mchat_edit_delete_limit') && $this->auth->acl_get('m_'), - 'MCHAT_RELATIVE_TIME' => $this->settings->cfg('mchat_relative_time'), - 'MCHAT_USER_TIMEOUT' => 1000 * $this->settings->cfg('mchat_timeout'), - 'S_MCHAT_AVATARS' => $this->display_avatars(), - 'EXT_URL' => generate_board_url() . '/ext/dmzx/mchat/', - 'STYLE_PATH' => generate_board_url() . '/styles/' . rawurlencode($this->user->style['style_path']), - )); + $template_data = array( + 'S_BBCODE_ALLOWED' => $this->auth->acl_get('u_mchat_bbcode') && $this->settings->cfg('allow_bbcode'), + 'MCHAT_ALLOW_USE' => $this->auth->acl_get('u_mchat_use'), + 'MCHAT_ALLOW_IP' => $this->auth->acl_get('u_mchat_ip'), + 'MCHAT_ALLOW_PM' => $this->auth->acl_get('u_mchat_pm'), + 'MCHAT_ALLOW_LIKE' => $this->auth->acl_get('u_mchat_like'), + 'MCHAT_ALLOW_QUOTE' => $this->auth->acl_get('u_mchat_quote'), + 'MCHAT_ALLOW_PERMISSIONS' => $this->auth->acl_get('a_authusers'), + 'MCHAT_EDIT_DELETE_LIMIT' => 1000 * $this->settings->cfg('mchat_edit_delete_limit'), + 'MCHAT_EDIT_DELETE_IGNORE' => $this->settings->cfg('mchat_edit_delete_limit') && ($this->auth->acl_get('u_mchat_moderator_edit') || $this->auth->acl_get('u_mchat_moderator_delete')), + 'MCHAT_RELATIVE_TIME' => $this->settings->cfg('mchat_relative_time'), + 'MCHAT_TIMEOUT' => 1000 * $this->settings->cfg('mchat_timeout'), + 'S_MCHAT_AVATARS' => $this->display_avatars(), + 'EXT_URL' => generate_board_url() . '/ext/dmzx/mchat/', + 'STYLE_PATH' => generate_board_url() . '/styles/' . rawurlencode($this->user->style['style_path']), + ); + + /** + * Event that allows adding global templte data for mChat + * + * @event dmzx.mchat.global_modify_template_data + * @var array template_data The data that is about to be assigned to the template + * @since 2.0.0-RC6 + */ + $vars = array( + 'template_data', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.global_modify_template_data', compact($vars))); + + $this->template->assign_vars($template_data); } /** @@ -676,26 +964,9 @@ class mchat * * @param array $rows */ - protected function assign_messages($rows) + public function assign_messages($rows) { - // Auth checks - foreach ($rows as $i => $row) - { - if ($row['forum_id']) - { - // No permission to read forum - if (!$this->auth->acl_get('f_read', $row['forum_id'])) - { - unset($rows[$i]); - } - - // Post is not approved and no approval permission - if ($row['post_visibility'] != ITEM_APPROVED && !$this->auth->acl_get('m_approve', $row['forum_id'])) - { - unset($rows[$i]); - } - } - } + $rows = array_filter($rows, array($this, 'has_read_auth')); if (!$rows) { @@ -708,13 +979,18 @@ class mchat $rows = array_reverse($rows); } - $foes = $this->functions->mchat_foes(); + if ($this->foes === null) + { + $this->foes = $this->functions->mchat_foes(); + } + // Remove template data from previous render $this->template->destroy_block_vars('mchatrow'); $user_avatars = array(); - foreach ($rows as $i => $row) + // Cache avatars + foreach ($rows as $row) { if (!isset($user_avatars[$row['user_id']])) { @@ -730,10 +1006,10 @@ class mchat $board_url = generate_board_url() . '/'; - foreach ($rows as $i => $row) - { - $message_for_edit = generate_text_for_edit($row['message'], $row['bbcode_uid'], $row['bbcode_options']); + $this->process_notifications($rows, $board_url); + foreach ($rows as $row) + { $username_full = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], $this->user->lang('GUEST')); // Fix profile link root path by replacing relative paths with absolute board URL @@ -742,46 +1018,198 @@ class mchat $username_full = preg_replace('#(?<=href=")[\./]+?/(?=\w)#', $board_url, $username_full); } - if (in_array($row['user_id'], $foes)) + if (in_array($row['user_id'], $this->foes)) { $row['message'] = $this->user->lang('MCHAT_FOE', $username_full); } $message_age = time() - $row['message_time']; $minutes_ago = $this->get_minutes_ago($message_age); - $datetime = $this->user->format_date($row['message_time'], $this->settings->cfg('mchat_date')); + $datetime = $this->user->format_date($row['message_time'], $this->settings->cfg('mchat_date'), true); $is_poster = $row['user_id'] != ANONYMOUS && $this->user->data['user_id'] == $row['user_id']; - $this->template->assign_block_vars('mchatrow', array( - 'MCHAT_ALLOW_EDIT' => $this->auth_message('u_mchat_edit', $row['user_id'], $row['message_time']), - 'MCHAT_ALLOW_DEL' => $this->auth_message('u_mchat_delete', $row['user_id'], $row['message_time']), + $message_for_edit = generate_text_for_edit($row['message'], $row['bbcode_uid'], $row['bbcode_options']); + + $template_data = array( + 'MCHAT_ALLOW_EDIT' => $this->auth_message('edit', $row['user_id'], $row['message_time']), + 'MCHAT_ALLOW_DEL' => $this->auth_message('delete', $row['user_id'], $row['message_time']), 'MCHAT_USER_AVATAR' => $user_avatars[$row['user_id']], 'U_VIEWPROFILE' => $row['user_id'] != ANONYMOUS ? append_sid("{$board_url}{$this->root_path}memberlist.{$this->php_ext}", 'mode=viewprofile&u=' . $row['user_id']) : '', 'MCHAT_IS_POSTER' => $is_poster, - 'MCHAT_PM' => !$is_poster && $this->settings->cfg('allow_privmsg') && $this->auth->acl_get('u_sendpm') && ($row['user_allow_pm'] || $this->auth->acl_gets('a_', 'm_') || $this->auth->acl_getf_global('m_')) ? append_sid("{$board_url}{$this->root_path}ucp.{$this->php_ext}", 'i=pm&mode=compose&u=' . $row['user_id']) : '', + 'MCHAT_IS_NOTIFICATION' => (bool) $row['post_id'], + 'MCHAT_PM' => !$is_poster && $this->settings->cfg('allow_privmsg') && $this->auth->acl_get('u_sendpm') && ($row['user_allow_pm'] || $this->auth->acl_gets('a_', 'm_') || $this->auth->acl_getf_global('m_')) ? append_sid("{$board_url}{$this->root_path}ucp.{$this->php_ext}", 'i=pm&mode=compose&mchat_pm_quote_message=' . (int) $row['message_id'] . '&u=' . $row['user_id']) : '', 'MCHAT_MESSAGE_EDIT' => $message_for_edit['text'], 'MCHAT_MESSAGE_ID' => $row['message_id'], 'MCHAT_USERNAME_FULL' => $username_full, 'MCHAT_USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour'], $this->user->lang('GUEST')), 'MCHAT_USERNAME_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour'], $this->user->lang('GUEST')), 'MCHAT_WHOIS_USER' => $this->user->lang('MCHAT_WHOIS_USER', $row['user_ip']), - 'MCHAT_U_IP' => $this->helper->route('dmzx_mchat_page_controller', array('page' => 'whois', 'ip' => $row['user_ip'])), - 'MCHAT_U_PERMISSIONS' => append_sid("{$board_url}{$this->root_path}adm/index.{$this->php_ext}" ,'i=permissions&mode=setting_user_global&user_id[0]=' . $row['user_id'], true, $this->user->session_id), + 'MCHAT_U_IP' => $this->helper->route('dmzx_mchat_page_whois_controller', array('ip' => $row['user_ip'])), + 'MCHAT_U_PERMISSIONS' => append_sid("{$board_url}{$this->root_path}adm/index.{$this->php_ext}", 'i=permissions&mode=setting_user_global&user_id%5B0%5D=' . $row['user_id'], true, $this->user->session_id), 'MCHAT_MESSAGE' => generate_text_for_display($row['message'], $row['bbcode_uid'], $row['bbcode_bitfield'], $row['bbcode_options']), 'MCHAT_TIME' => $minutes_ago === -1 ? $datetime : $this->user->lang('MCHAT_MINUTES_AGO', $minutes_ago), 'MCHAT_DATETIME' => $datetime, 'MCHAT_MINUTES_AGO' => $minutes_ago, 'MCHAT_RELATIVE_UPDATE' => 60 - $message_age % 60, 'MCHAT_MESSAGE_TIME' => $row['message_time'], - 'MCHAT_EDIT_TIME' => $row['edit_time'], - )); + ); + + /** + * Event to modify the template data of an mChat message before it is sent to the template + * + * @event dmzx.mchat.message_modify_template_data + * @var array template_data The data that is about to be assigned to the template + * @var string username_full The link to the user profile, e.g. Username + * @var bool is_notification Whether or not this message is a notification + * @var array row The raw message data as fetched from the database + * @var int message_age The number of seconds that have passed since the message was posted + * @var int minutes_ago The number of minutes that have passed since the message was posted, or -1 + * @var string datetime The full date in the user-specific date format + * @var bool is_poster Whether or not the current user posted this message + * @var array message_for_edit The data for editing the message + * @since 2.0.0-RC6 + */ + $vars = array( + 'template_data', + 'username_full', + 'is_notification', + 'row', + 'message_age', + 'minutes_ago', + 'datetime', + 'is_poster', + 'message_for_edit', + ); + extract($this->dispatcher->trigger_event('dmzx.mchat.message_modify_template_data', compact($vars))); + + $this->template->assign_block_vars('mchatrow', $template_data); } } /** - * Calculates the number of minutes that have passed since the message was posted. If relative time is disabled - * or the message is older than 59 minutes or we render for the archive, -1 is returned. + * Returns true of the user is allowed to read the given message row + * + * @param array $row + * @return bool + */ + protected function has_read_auth($row) + { + if ($row['forum_id']) + { + // No permission to read forum + if (!$this->auth->acl_get('f_read', $row['forum_id'])) + { + return false; + } + + // Post is not approved and no approval permission + if ($row['post_visibility'] != ITEM_APPROVED && !$this->auth->acl_get('m_approve', $row['forum_id'])) + { + return false; + } + } + + return true; + } + + /** + * Checks the post rows for notifications and converts their language keys + * + * @param array $rows The rows to modify + * @param string $board_url + */ + protected function process_notifications(&$rows, $board_url) + { + $notification_post_ids = array(); + + // All language keys of valid notifications. We need to check for them here because + // notifications in < 2.0.0-RC6 are plain text and don't need to be processed here. + $notification_lang = array( + 'MCHAT_NEW_POST', + 'MCHAT_NEW_QUOTE', + 'MCHAT_NEW_EDIT', + 'MCHAT_NEW_REPLY', + 'MCHAT_NEW_LOGIN', + ); + + foreach ($rows as $i => $row) + { + // If post_id is 0 it's not a notification. + if ($row['post_id'] && in_array($row['message'], $notification_lang)) + { + if ($row['forum_id']) + { + $notification_post_ids[] = $row['post_id']; + } + else + { + $rows[$i] = $this->process_notification($row, $board_url); + } + } + } + + $notification_post_data = $this->functions->mchat_get_post_data($notification_post_ids); + + if ($notification_post_data) + { + foreach ($rows as $i => $row) + { + if (in_array($row['post_id'], $notification_post_ids)) + { + $rows[$i] = $this->process_notification($row, $board_url, $notification_post_data[$row['post_id']]); + } + } + } + } + + /** + * Converts the message field of the post row so that it can be passed to generate_text_for_display() + * + * @param array $row + * @param string $board_url + * @param array $post_data + * @return array + */ + protected function process_notification($row, $board_url, $post_data = null) + { + $args = array($row['message']); + + // If forum_id is 0 it's a login notification. + // If forum_id is not 0 it's a post notification, we need to fetch forum name and post subject. + if ($row['forum_id']) + { + $viewtopic_url = append_sid($board_url . 'viewtopic.' . $this->php_ext, array( + 'p' => $row['post_id'], + '#' => 'p' . $row['post_id'], + )); + + $viewforum_url = append_sid($board_url . 'viewforum.' . $this->php_ext, array( + 'f' => $row['forum_id'], + )); + + $args[] = '[url=' . $viewtopic_url . ']' . $post_data['post_subject'] . '[/url]'; + $args[] = '[url=' . $viewforum_url . ']' . $post_data['forum_name'] . '[/url]'; + } + else if ($row['post_id'] == functions::LOGIN_HIDDEN) + { + $row['username'] = '' . $row['username'] . ''; + } + + $row['message'] = call_user_func_array(array($this->user, 'lang'), $args); + + // Quick'n'dirty check if BBCodes are in the message + if (strpos($row['message'], '[') !== false) + { + generate_text_for_storage($row['message'], $row['bbcode_uid'], $row['bbcode_bitfield'], $row['bbcode_options'], true, true, true); + } + + return $row; + } + + /** + * Calculates the number of minutes that have passed since the message was posted. + * If relative time is disabled or the message is older than 59 minutes, -1 is returned. * * @param int $message_age * @return int @@ -852,7 +1280,7 @@ class mchat $this->template->assign_var($option['template_var'], !$is_disallowed); } - $this->template->assign_var('A_MCHAT_DISALLOWED_BBCODES', addslashes(str_replace('=', '-', $this->settings->cfg('mchat_bbcode_disallowed')))); + $this->template->assign_var('A_MCHAT_DISALLOWED_BBCODES', addslashes($this->settings->cfg('mchat_bbcode_disallowed'))); if (!function_exists('display_custom_bbcodes')) { @@ -908,14 +1336,58 @@ class mchat return $sql_ary; } - /** Inserts a message with posting information into the database + /** + * Inserts a message with posting information into the database * - * @param string $mode One of post|quote|edit|reply - * @param $data The post data + * @param string $mode One of post|quote|edit|reply|login + * @param int $forum_id Can be 0 if mode is login. + * @param int $post_id Can be 0 if mode is login. */ - public function insert_posting($mode, $data) + public function insert_posting($mode, $forum_id = 0, $post_id = 0) { - $this->functions->mchat_insert_posting($mode, $data); + $is_hidden_login = $this->request->is_set_post('viewonline') || !$this->user->data['user_allow_viewonline']; + $this->functions->mchat_insert_posting($mode, $forum_id, $post_id, $is_hidden_login); + } + + /** + * Fetches the message text of the given ID, quotes it using the current user name and assigns it to the template + * + * @param int $mchat_message_id + */ + public function quote_message_text($mchat_message_id) + { + if (!$this->auth->acl_get('u_mchat_view')) + { + return; + } + + $rows = $this->functions->mchat_get_messages($mchat_message_id); + $row = reset($rows); + + if (!$row || !$this->has_read_auth($row)) + { + return; + } + + if ($row['post_id']) + { + $rows = array($row); + $this->process_notifications($rows, generate_board_url() . '/'); + $row = reset($rows); + } + + $message_for_edit = generate_text_for_edit($row['message'], $row['bbcode_uid'], $row['bbcode_options']); + $message = '[quote="' . $row['username'] . '"]' . $message_for_edit['text'] . "[/quote]\n"; + + $this->template->assign_var('MESSAGE', $message); + } + + /** + * Remove expired sessions from the database + */ + public function session_gc() + { + $this->functions->mchat_session_gc(); } /** @@ -923,14 +1395,18 @@ class mchat */ protected function assign_whois() { - if ($this->settings->cfg('mchat_whois') || $this->settings->cfg('mchat_stats_index') && $this->settings->cfg('mchat_stats_index')) + if ($this->settings->cfg('mchat_whois_index') || $this->settings->cfg('mchat_stats_index')) { - $mchat_stats = $this->functions->mchat_active_users(); + if ($this->active_users === null) + { + $this->active_users = $this->functions->mchat_active_users(); + } + $this->template->assign_vars(array( - 'MCHAT_STATS_INDEX' => $this->settings->cfg('mchat_stats_index') && $this->settings->cfg('mchat_stats_index'), - 'MCHAT_USERS_COUNT' => $mchat_stats['mchat_users_count'], - 'MCHAT_USERS_LIST' => $mchat_stats['online_userlist'] ?: '', - 'MCHAT_ONLINE_EXPLAIN' => $mchat_stats['refresh_message'], + 'MCHAT_STATS_INDEX' => $this->settings->cfg('mchat_stats_index'), + 'MCHAT_USERS_TOTAL' => $this->active_users['users_total'], + 'MCHAT_USERS_LIST' => $this->active_users['online_userlist'] ?: '', + 'MCHAT_ONLINE_EXPLAIN' => $this->active_users['refresh_message'], )); } } @@ -938,66 +1414,59 @@ class mchat /** * Checks whether an author has edit or delete permissions for a message * - * @param string $permission One of u_mchat_edit|u_mchat_delete + * @param string $mode One of edit|delete * @param int $author_id The user id of the message * @param int $message_time The message created time * @return bool */ - protected function auth_message($permission, $author_id, $message_time) + protected function auth_message($mode, $author_id, $message_time) { - if (!$this->auth->acl_get($permission)) - { - return false; - } - - if ($this->auth->acl_get('m_')) + if ($this->auth->acl_get('u_mchat_moderator_' . $mode)) { return true; } - $can_edit_delete = !$this->settings->cfg('mchat_edit_delete_limit') || $message_time >= time() - $this->settings->cfg('mchat_edit_delete_limit'); - return $can_edit_delete && $this->user->data['user_id'] == $author_id && $this->user->data['is_registered']; + if (!$this->user->data['is_registered'] || $this->user->data['user_id'] != $author_id || !$this->auth->acl_get('u_mchat_' . $mode)) + { + return false; + } + + return !$this->settings->cfg('mchat_edit_delete_limit') || $message_time >= time() - $this->settings->cfg('mchat_edit_delete_limit'); } /** - * Performs bound checks on the message and returns an array containing the message, - * BBCode options and additional data ready to be sent to the database + * Performs bound checks on the message and returns an array containing the message + * and BBCode options ready to be sent to the database * * @param string $message - * @param array $merge_ary * @return array */ - protected function process_message($message, $merge_ary) + protected function process_message($message) { // Must have something other than bbcode in the message - $message_chars = trim(preg_replace('#\[/?[^\[\]]+\]#mi', '', $message)); - if (!utf8_strlen($message_chars)) + $message_without_bbcode = trim(preg_replace('#\[\/?[^\[\]]+\]#m', '', $message)); + if (!utf8_strlen($message_without_bbcode)) { - throw new \phpbb\exception\http_exception(501, 'MCHAT_NOACCESS'); + throw new http_exception(400, 'MCHAT_NOMESSAGEINPUT'); } // Must not exceed character limit if ($this->settings->cfg('mchat_max_message_lngth')) { - if (utf8_strlen($message_chars) > $this->settings->cfg('mchat_max_message_lngth')) + if (utf8_strlen($message) > $this->settings->cfg('mchat_max_message_lngth')) { - throw new \phpbb\exception\http_exception(413, 'MCHAT_MESS_LONG', array($this->settings->cfg('mchat_max_message_lngth'))); + throw new http_exception(400, 'MCHAT_MESS_LONG', array($this->settings->cfg('mchat_max_message_lngth'))); } } - $cfg_min_post_chars = $this->settings->cfg('min_post_chars'); - $cfg_max_post_smilies = $this->settings->cfg('max_post_smilies'); - - // We override the $this->settings->cfg('min_post_chars') entry? if ($this->settings->cfg('mchat_override_min_post_chars')) { - $this->settings->set_cfg('min_post_chars', 0); + $this->settings->set_cfg('min_post_chars', 0, true); } - // We do the same for the max number of smilies? if ($this->settings->cfg('mchat_override_smilie_limit')) { - $this->settings->cfg('max_post_smilies', 0); + $this->settings->set_cfg('max_post_smilies', 0, true); } $mchat_bbcode = $this->settings->cfg('allow_bbcode') && $this->auth->acl_get('u_mchat_bbcode'); @@ -1018,23 +1487,19 @@ class mchat if ($this->settings->cfg('mchat_bbcode_disallowed')) { $bbcode_replace = array( - '#\[(' . $this->settings->cfg('mchat_bbcode_disallowed') . ')[^\[\]]+\]#Usi', - '#\[/(' . $this->settings->cfg('mchat_bbcode_disallowed') . ')[^\[\]]+\]#Usi', + '#\[(' . str_replace('*', '\*', $this->settings->cfg('mchat_bbcode_disallowed')) . ')[^\[\]]+\]#Usi', + '#\[/(' . str_replace('*', '\*', $this->settings->cfg('mchat_bbcode_disallowed')) . ')[^\[\]]+\]#Usi', ); $message = preg_replace($bbcode_replace, '', $message); } - // Reset the config settings - $this->settings->set_cfg('min_post_chars', $cfg_min_post_chars); - $this->settings->set_cfg('max_post_smilies', $cfg_max_post_smilies); - - return array_merge($merge_ary, array( + return array( 'message' => str_replace("'", ''', $message), 'bbcode_bitfield' => $bitfield, 'bbcode_uid' => $uid, 'bbcode_options' => $options, - )); + ); } /** @@ -1043,7 +1508,7 @@ class mchat * @param string $template_file * @return string */ - protected function render_template($template_file) + public function render_template($template_file) { $this->template->set_filenames(array('body' => $template_file)); $content = $this->template->assign_display('body', '', true); diff --git a/core/settings.php b/core/settings.php index bd71852..8dff910 100644 --- a/core/settings.php +++ b/core/settings.php @@ -13,11 +13,6 @@ namespace dmzx\mchat\core; class settings { - const VALIDATE_TYPE = 0; - const VALIDATE_IS_OPTIONAL = 1; - const VALIDATE_MIN_VALUE = 2; - const VALIDATE_MAX_VALUE = 3; - /** @var \phpbb\user */ protected $user; @@ -27,10 +22,23 @@ class settings /** @var \phpbb\auth\auth */ protected $auth; - /** @var array */ + /** + * Keys for global settings that only the administrator is allowed to modify. + * The values are stored in the phpbb_config table. + * + * @var array + */ public $global; - /** @var array */ + /** + * Keys for user-specific settings for which the administrator can set default + * values as well as adjust permissions to allow users to customize them. + * The values are stored in the phpbb_users table as well as the phpbb_config table. + * If a user has permission to customize a setting, the value in the phpbb_users + * table is used, otherwise the value in the phpbb_config table is used. + * + * @var array + */ public $ucp; /** @var bool */ @@ -45,30 +53,62 @@ class settings * @param \phpbb\user $user * @param \phpbb\config\config $config * @param \phpbb\auth\auth $auth - * @param array $global - * @param array $ucp */ - public function __construct(\phpbb\user $user, \phpbb\config\config $config, \phpbb\auth\auth $auth, $global, $ucp) + public function __construct(\phpbb\user $user, \phpbb\config\config $config, \phpbb\auth\auth $auth) { $this->user = $user; $this->config = $config; $this->auth = $auth; - $this->global = $global; - $this->ucp = $ucp; - $this->is_phpbb31 = phpbb_version_compare($config['version'], '3.1.0@dev', '>=') && phpbb_version_compare($config['version'], '3.2.0@dev', '<'); - $this->is_phpbb32 = phpbb_version_compare($config['version'], '3.2.0@dev', '>=') && phpbb_version_compare($config['version'], '3.3.0@dev', '<'); + $this->global = array( + 'mchat_bbcode_disallowed' => array('default' => '', 'validation' => array('string', false, 0, 255)), + 'mchat_custom_height' => array('default' => 350, 'validation' => array('num', false, 50, 1000)), + 'mchat_custom_page' => array('default' => 1), + 'mchat_edit_delete_limit' => array('default' => 0), + 'mchat_flood_time' => array('default' => 0, 'validation' => array('num', false, 0, 60)), + 'mchat_index_height' => array('default' => 250, 'validation' => array('num', false, 50, 1000)), + 'mchat_live_updates' => array('default' => 1), + 'mchat_max_message_lngth' => array('default' => 500, 'validation' => array('num', false, 0, 1000)), + 'mchat_message_num_archive' => array('default' => 25, 'validation' => array('num', false, 10, 100)), + 'mchat_message_num_custom' => array('default' => 10, 'validation' => array('num', false, 5, 50)), + 'mchat_message_num_index' => array('default' => 10, 'validation' => array('num', false, 5, 50)), + 'mchat_navbar_link' => array('default' => 1), + 'mchat_navbar_link_count' => array('default' => 1), + 'mchat_override_min_post_chars' => array('default' => 0), + 'mchat_override_smilie_limit' => array('default' => 0), + 'mchat_posts_edit' => array('default' => 0), + 'mchat_posts_quote' => array('default' => 0), + 'mchat_posts_reply' => array('default' => 0), + 'mchat_posts_topic' => array('default' => 0), + 'mchat_posts_login' => array('default' => 0), + 'mchat_prune' => array('default' => 0), + 'mchat_prune_num' => array('default' => '0'), + 'mchat_refresh' => array('default' => 10, 'validation' => array('num', false, 5, 60)), + 'mchat_rules' => array('default' => '', 'validation' => array('string', false, 0, 255)), + 'mchat_static_message' => array('default' => '', 'validation' => array('string', false, 0, 255)), + 'mchat_timeout' => array('default' => 0, 'validation' => array('num', false, 0, (int) $this->cfg('session_length'))), + 'mchat_whois_refresh' => array('default' => 60, 'validation' => array('num', false, 10, 300)), + ); - $this->inject_core_config_values(); - } + $this->ucp = array( + 'mchat_avatars' => array('default' => 1), + 'mchat_capital_letter' => array('default' => 1), + 'mchat_character_count' => array('default' => 1), + 'mchat_date' => array('default' => 'D M d, Y g:i a', 'validation' => array('string', false, 0, 64)), + 'mchat_index' => array('default' => 1), + 'mchat_input_area' => array('default' => 1), + 'mchat_location' => array('default' => 1), + 'mchat_message_top' => array('default' => 1), + 'mchat_pause_on_input' => array('default' => 0), + 'mchat_posts' => array('default' => 1), + 'mchat_relative_time' => array('default' => 1), + 'mchat_sound' => array('default' => 1), + 'mchat_stats_index' => array('default' => 0), + 'mchat_whois_index' => array('default' => 1), + ); - /** - * Writes phpBB config values into the mChat config for validating input data - */ - protected function inject_core_config_values() - { - // Limit mChat session timeout to phpBB session length - $this->global['mchat_timeout']['validation'][self::VALIDATE_MAX_VALUE] = (int) $this->cfg('session_length'); + $this->is_phpbb31 = phpbb_version_compare(PHPBB_VERSION, '3.1.0@dev', '>=') && phpbb_version_compare(PHPBB_VERSION, '3.2.0@dev', '<'); + $this->is_phpbb32 = phpbb_version_compare(PHPBB_VERSION, '3.2.0@dev', '>=') && phpbb_version_compare(PHPBB_VERSION, '3.3.0@dev', '<'); } /** @@ -101,10 +141,18 @@ class settings /** * @param $config * @param $value + * @param bool $volatile */ - public function set_cfg($config, $value) + public function set_cfg($config, $value, $volatile = false) { - $this->config->set($config, $value); + if ($volatile) + { + $this->config[$config] = $value; + } + else + { + $this->config->set($config, $value); + } } /** @@ -146,7 +194,7 @@ class settings { $enabled_notifications_lang = array(); - foreach (array('topic', 'reply', 'quote', 'edit') as $notification) + foreach (array('topic', 'reply', 'quote', 'edit', 'login') as $notification) { if ($this->cfg('mchat_posts_' . $notification)) { diff --git a/cron/mchat_prune.php b/cron/mchat_prune.php new file mode 100644 index 0000000..2c3f087 --- /dev/null +++ b/cron/mchat_prune.php @@ -0,0 +1,67 @@ +functions = $functions; + $this->settings = $settings; + } + + /** + * Runs this cron task. + * + * @return null + */ + public function run() + { + $this->functions->mchat_prune(); + $this->settings->set_cfg('mchat_prune_last_gc', time()); + } + + /** + * Returns whether this cron task can run, given current board configuration. + * + * If warnings are set to never expire, this cron task will not run. + * + * @return bool + */ + public function is_runnable() + { + return $this->settings->cfg('mchat_prune'); + } + + /** + * Returns whether this cron task should run now, because enough time + * has passed since it was last run (24 hours). + * + * @return bool + */ + public function should_run() + { + return $this->settings->cfg('mchat_prune_last_gc') < time() - $this->settings->cfg('mchat_prune_gc'); + } +} diff --git a/event/acp_listener.php b/event/acp_listener.php index 2c73b4c..b5a655f 100644 --- a/event/acp_listener.php +++ b/event/acp_listener.php @@ -11,6 +11,7 @@ namespace dmzx\mchat\event; +use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class acp_listener implements EventSubscriberInterface @@ -66,11 +67,16 @@ class acp_listener implements EventSubscriberInterface } /** - * @param object $event The event object + * @param Event $event */ public function permissions($event) { - $mchat_permissions = array(); + $ucp_configs = array(); + + foreach (array_keys($this->settings->ucp) as $config_name) + { + $ucp_configs[] = 'u_' . $config_name; + } $permission_categories = array( 'mchat' => array( @@ -78,6 +84,8 @@ class acp_listener implements EventSubscriberInterface 'u_mchat_view', 'u_mchat_edit', 'u_mchat_delete', + 'u_mchat_moderator_edit', + 'u_mchat_moderator_delete', 'u_mchat_ip', 'u_mchat_pm', 'u_mchat_like', @@ -89,9 +97,11 @@ class acp_listener implements EventSubscriberInterface 'u_mchat_urls', 'a_mchat', ), - 'mchat_user_config' => array_map(function($key) { return 'u_' . $key; }, array_keys($this->settings->ucp)), + 'mchat_user_config' => $ucp_configs, ); + $mchat_permissions = array(); + foreach ($permission_categories as $cat => $permissions) { foreach ($permissions as $permission) @@ -107,12 +117,12 @@ class acp_listener implements EventSubscriberInterface $event['categories'] = array_merge($event['categories'], array( 'mchat' => 'ACP_CAT_MCHAT', - 'mchat_user_config' => 'ACP_CAT_MCHAT_USER_CONFIG' + 'mchat_user_config' => 'ACP_CAT_MCHAT_USER_CONFIG', )); } /** - * @param object $event The event object + * @param Event $event */ public function acp_users_prefs_modify_sql($event) { @@ -150,7 +160,7 @@ class acp_listener implements EventSubscriberInterface } /** - * @param object $event The event object + * @param Event $event */ public function acp_users_prefs_modify_template_data($event) { diff --git a/event/main_listener.php b/event/main_listener.php index 2b25236..000a120 100644 --- a/event/main_listener.php +++ b/event/main_listener.php @@ -11,6 +11,7 @@ namespace dmzx\mchat\event; +use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class main_listener implements EventSubscriberInterface @@ -24,6 +25,9 @@ class main_listener implements EventSubscriberInterface /** @var \phpbb\user */ protected $user; + /** @var \phpbb\request\request */ + protected $request; + /** @var string */ protected $php_ext; @@ -33,14 +37,16 @@ class main_listener implements EventSubscriberInterface * @param \dmzx\mchat\core\mchat $mchat * @param \phpbb\controller\helper $helper * @param \phpbb\user $user + * @param \phpbb\request\request $request * @param string $php_ext */ - public function __construct(\dmzx\mchat\core\mchat $mchat, \phpbb\controller\helper $helper, \phpbb\user $user, $php_ext) + public function __construct(\dmzx\mchat\core\mchat $mchat, \phpbb\controller\helper $helper, \phpbb\user $user, \phpbb\request\request $request, $php_ext) { - $this->mchat = $mchat; - $this->helper = $helper; - $this->user = $user; - $this->php_ext = $php_ext; + $this->mchat = $mchat; + $this->helper = $helper; + $this->user = $user; + $this->request = $request; + $this->php_ext = $php_ext; } /** @@ -53,26 +59,28 @@ class main_listener implements EventSubscriberInterface 'core.user_setup' => 'load_language_on_setup', 'core.page_header' => 'add_page_header_link', 'core.index_modify_page_title' => 'display_mchat_on_index', - 'core.posting_modify_submit_post_after' => 'posting_modify_submit_post_after', - 'core.display_custom_bbcodes_modify_sql' => 'display_custom_bbcodes_modify_sql', + 'core.submit_post_end' => 'insert_posting', + 'core.display_custom_bbcodes_modify_sql' => array(array('remove_disallowed_bbcodes'), array('pm_compose_add_quote')), 'core.user_add_modify_data' => 'user_registration_set_default_values', + 'core.login_box_redirect' => 'user_login_success', + 'core.session_gc_after' => 'session_gc', ); } /** - * @param object $event The event object + * @param Event $event */ public function add_page_viewonline($event) { if (strrpos($event['row']['session_page'], 'app.' . $this->php_ext . '/mchat') === 0) { $event['location'] = $this->user->lang('MCHAT_TITLE'); - $event['location_url'] = $this->helper->route('dmzx_mchat_controller'); + $event['location_url'] = $this->helper->route('dmzx_mchat_page_custom_controller'); } } /** - * @param object $event The event object + * @param Event $event */ public function load_language_on_setup($event) { @@ -87,7 +95,7 @@ class main_listener implements EventSubscriberInterface /** * Create a URL to the mchat controller file for the header linklist * - * @param object $event The event object + * @param Event $event */ public function add_page_header_link($event) { @@ -97,7 +105,7 @@ class main_listener implements EventSubscriberInterface /** * Check if mchat should be displayed on index. * - * @param object $event The event object + * @param Event $event */ public function display_mchat_on_index($event) { @@ -105,31 +113,58 @@ class main_listener implements EventSubscriberInterface } /** - * @param object $event The event object + * @param Event $event */ - public function posting_modify_submit_post_after($event) + public function insert_posting($event) { - $this->mchat->insert_posting($event['mode'], array( - 'forum_id' => $event['forum_id'], - 'forum_name' => $event['post_data']['forum_name'], - 'post_id' => $event['data']['post_id'], - 'post_subject' => $event['post_data']['post_subject'], - )); + $this->mchat->insert_posting($event['mode'], $event['data']['forum_id'], $event['data']['post_id']); } /** - * @param object $event The event object + * @param Event $event */ - public function display_custom_bbcodes_modify_sql($event) + public function remove_disallowed_bbcodes($event) { $event['sql_ary'] = $this->mchat->remove_disallowed_bbcodes($event['sql_ary']); } /** - * @param object $event The event object + * @param Event $event */ public function user_registration_set_default_values($event) { $event['sql_ary'] = $this->mchat->set_user_default_values($event['sql_ary']); } + + /** + * @param Event $event + */ + public function user_login_success($event) + { + if (!$event['admin']) + { + $this->mchat->insert_posting('login'); + } + } + + /** + * @param Event $event + */ + public function pm_compose_add_quote($event) + { + $mchat_message_id = $this->request->variable('mchat_pm_quote_message', 0); + + if ($mchat_message_id) + { + $this->mchat->quote_message_text($mchat_message_id); + } + } + + /** + * @param Event $event + */ + public function session_gc($event) + { + $this->mchat->session_gc(); + } } diff --git a/ext.php b/ext.php index 5ebaaaa..6fed5ca 100644 --- a/ext.php +++ b/ext.php @@ -22,6 +22,77 @@ class ext extends \phpbb\extension\base public function is_enableable() { $config = $this->container->get('config'); + + // Here we check if any modules from the mChat MOD for phpBB 3.0.x are still in the database. + // This is_enableable() method is called multiple times during the installation but we only + // need to do the following check once. Checking for the absence of the mchat_version value + // in the config guarantees that we're in the very first step of the installation process. + // Any later call of this method doesn't need to check this again and in fact will wrongly + // detect the extension's modules as being remnants. + if (empty($config['mchat_version'])) + { + $table_prefix = $this->container->getParameter('core.table_prefix'); + $module_ids = $this->get_old_module_ids($table_prefix); + + if ($module_ids) + { + if (phpbb_version_compare($config['version'], '3.2.0-dev', '>=')) + { + // For phpBB 3.2.x + $lang = $this->container->get('language'); + $lang->add_lang('mchat_acp', 'dmzx/mchat'); + } + else + { + // For phpBB 3.1.x + $user = $this->container->get('user'); + $user->add_lang_ext('dmzx/mchat', 'mchat_acp'); + $lang = $user; + } + + $php_ext = $this->container->getParameter('core.php_ext'); + $error_msg = $lang->lang('MCHAT_30X_REMNANTS', $table_prefix, implode(', ', $module_ids)) . adm_back_link(append_sid('index.' . $php_ext, 'i=acp_extensions&mode=main')); + + trigger_error($error_msg, E_USER_WARNING); + } + } + return phpbb_version_compare($config['version'], '3.1.7-PL1', '>='); } + + /** + * This method checks whether the phpbb_modules table contains remnants of the 3.0 MOD. + * It returns an array of the modules' IDs, or an empty array if no old modules are found. + * + * @var string $table_prefix + * @return array + */ + protected function get_old_module_ids($table_prefix) + { + $db = $this->container->get('dbal.conn'); + + $mchat_30x_module_langnames = array( + 'ACP_CAT_MCHAT', + 'ACP_MCHAT_CONFIG', + 'ACP_USER_MCHAT', + 'UCP_CAT_MCHAT', + 'UCP_MCHAT_CONFIG', + ); + + $sql = 'SELECT module_id + FROM ' . $table_prefix . 'modules + WHERE ' . $db->sql_in_set('module_langname', $mchat_30x_module_langnames); + $result = $db->sql_query($sql); + $rows = $db->sql_fetchrowset(); + $db->sql_freeresult($result); + + $module_ids = array(); + + foreach ($rows as $row) + { + $module_ids[] = $row['module_id']; + } + + return $module_ids; + } } diff --git a/language/en/common.php b/language/en/common.php index f4295e2..cbbd80f 100644 --- a/language/en/common.php +++ b/language/en/common.php @@ -36,13 +36,14 @@ if (empty($lang) || !is_array($lang)) $lang = array_merge($lang, array( 'MCHAT_TITLE' => 'mChat', + 'MCHAT_TITLE_COUNT' => 'mChat [%1$d]', // Who is chatting 'MCHAT_WHO_IS_CHATTING' => 'Who is chatting', 'MCHAT_ONLINE_USERS_TOTAL' => array( 0 => 'No one is chatting', - 1 => 'There is %1$d user chatting', - 2 => 'There are %1$d users chatting', + 1 => '%1$d user is chatting', + 2 => '%1$d users are chatting', ), 'MCHAT_ONLINE_EXPLAIN' => 'based on users active over the past %1$s', 'MCHAT_HOURS' => array( @@ -63,4 +64,5 @@ $lang = array_merge($lang, array( 'MCHAT_NEW_REPLY' => 'posted a reply: %1$s in %2$s', 'MCHAT_NEW_QUOTE' => 'replied with a quote: %1$s in %2$s', 'MCHAT_NEW_EDIT' => 'edited a post: %1$s in %2$s', + 'MCHAT_NEW_LOGIN' => 'just logged in', )); diff --git a/language/en/info_acp_mchat.php b/language/en/info_acp_mchat.php index 1b42daa..e05eca2 100644 --- a/language/en/info_acp_mchat.php +++ b/language/en/info_acp_mchat.php @@ -43,7 +43,8 @@ $lang = array_merge($lang, array( // Log entries (%1$s is replaced with the user name who triggered the event) 'LOG_MCHAT_CONFIG_UPDATE' => 'mChat configuration updated
» %1$s', - 'LOG_MCHAT_TABLE_PRUNED' => 'mChat messages pruned
» %1$s', + 'LOG_MCHAT_TABLE_PRUNED' => 'mChat messages pruned: %2$d
» %1$s', + 'LOG_MCHAT_TABLE_PRUNE_FAIL' => 'mChat pruning failed: invalid time period
» %1$s', 'LOG_MCHAT_TABLE_PURGED' => 'mChat messages purged
» %1$s', 'LOG_DELETED_MCHAT' => 'mChat message deleted
» %1$s', 'LOG_EDITED_MCHAT' => 'mChat message edited
» %1$s', diff --git a/language/en/mchat.php b/language/en/mchat.php index c7d547c..d73561f 100644 --- a/language/en/mchat.php +++ b/language/en/mchat.php @@ -40,23 +40,22 @@ $lang = array_merge($lang, array( 'MCHAT_ARCHIVE_PAGE' => 'mChat Archive', 'MCHAT_BBCODES' => 'BBCodes', 'MCHAT_CUSTOM_BBCODES' => 'Custom BBCodes', - 'MCHAT_DELCONFIRM' => 'Do you confirm removal?', + 'MCHAT_DELCONFIRM' => 'Are you sure you want to delete this message?', 'MCHAT_EDIT' => 'Edit', - 'MCHAT_EDITINFO' => 'Edit the message and click OK', + 'MCHAT_EDITINFO' => 'Edit the message below.', 'MCHAT_NEW_CHAT' => 'New chat message!', 'MCHAT_SEND_PM' => 'Send private message', - 'MCHAT_LIKE' => 'Like this post', - 'MCHAT_LIKES' => 'likes this post', - 'MCHAT_FLOOD' => 'You can not post another message so soon after your last', + 'MCHAT_LIKE' => 'Like this message', + 'MCHAT_LIKES' => 'likes this message', + 'MCHAT_FLOOD' => 'You can not post another message so soon after your last.', 'MCHAT_FOE' => 'This message was made by %1$s who is currently on your ignore list.', 'MCHAT_RULES' => 'Rules', 'MCHAT_WHOIS_USER' => 'IP whois for %1$s', - 'MCHAT_MESS_LONG' => 'Your message is too long. Please limit it to %1$d characters', - 'MCHAT_NO_CUSTOM_PAGE' => 'The mChat custom page is not activated at this time!', - 'MCHAT_NO_RULES' => 'The mChat rules page is not activated at this time!', - 'MCHAT_NOACCESS' => 'You don’t have permission to post in the chat', - 'MCHAT_NOACCESS_ARCHIVE' => 'You don’t have permission to view the archive', - 'MCHAT_NOJAVASCRIPT' => 'Your browser does not support JavaScript or JavaScript is disabled', + 'MCHAT_MESS_LONG' => 'Your message is too long. Please limit it to %1$d characters.', + 'MCHAT_NO_CUSTOM_PAGE' => 'The mChat custom page is not activated at this time.', + 'MCHAT_NO_RULES' => 'The mChat rules page is not activated at this time.', + 'MCHAT_NOACCESS_ARCHIVE' => 'You don’t have permission to view the archive.', + 'MCHAT_NOJAVASCRIPT' => 'Please enable JavaScript to use mChat.', 'MCHAT_NOMESSAGE' => 'No messages', 'MCHAT_NOMESSAGEINPUT' => 'You have not entered a message', 'MCHAT_OK' => 'OK', @@ -79,7 +78,7 @@ $lang = array_merge($lang, array( 2 => '%1$d minutes ago', ), - // These messages are formatted with JavaScript, hence {} and no $d + // These messages are formatted with JavaScript, hence {} and no %d 'MCHAT_CHARACTER_COUNT' => '{current} characters', 'MCHAT_CHARACTER_COUNT_LIMIT' => '{current} out of {max} characters', 'MCHAT_SESSION_ENDS_JS' => 'Chat session ends in {timeleft}', diff --git a/language/en/mchat_acp.php b/language/en/mchat_acp.php index cc8c9a0..8be7605 100644 --- a/language/en/mchat_acp.php +++ b/language/en/mchat_acp.php @@ -41,7 +41,7 @@ $lang = array_merge($lang, array( 'MCHAT_SETTINGS_ARCHIVE' => 'Archive page settings', 'MCHAT_SETTINGS_POSTS' => 'New posts settings', 'MCHAT_SETTINGS_MESSAGES' => 'Message settings', - 'MCHAT_SETTINGS_PRUNE' => 'Pruning settings', + 'MCHAT_SETTINGS_PRUNE' => 'Pruning settings (adjustable for founders only)', 'MCHAT_SETTINGS_STATS' => 'Who is chatting settings', 'MCHAT_GLOBALUSERSETTINGS_EXPLAIN' => 'Settings for which a user does not have permission to customise are applied as configured below.
New user accounts will have initial settings as configured below.

Go to the mChat in UCP tab of the user permissions section to adjust customisation permissions.
Go to the Preferences form in the user management section to see the status of each user’s settings.', @@ -70,9 +70,14 @@ $lang = array_merge($lang, array( 'MCHAT_LIVE_UPDATES' => 'Live updates of edited and deleted messages', 'MCHAT_LIVE_UPDATES_EXPLAIN' => 'When a user edits or deletes messages, the changes are updated live for all others, without them having to refresh the page. Disable this if you experience performance issues.', 'MCHAT_PRUNE' => 'Enable message pruning', - 'MCHAT_PRUNE_EXPLAIN' => 'Only occurs if a user views the custom or archive pages.', - 'MCHAT_PRUNE_NUM' => 'Number of messages to retain when pruning', + 'MCHAT_PRUNE_EXPLAIN' => 'The messages table is pruned every 24 hours.', + 'MCHAT_PRUNE_NUM' => 'Messages to retain when pruning', + 'MCHAT_PRUNE_NUM_EXPLAIN' => 'You can specify either a number to keep a fixed number of messages (example: 42) or a time period (examples: 24 hours, 5 days, 2 weeks, 1 month). All messages older than the time period at the time of pruning will be deleted.', + 'MCHAT_PRUNE_NOW' => 'Prune messages now', + 'MCHAT_PRUNE_NOW_CONFIRM' => 'Confirm pruning messages', + 'MCHAT_PRUNED' => '%1$d mChat messages have been pruned', 'MCHAT_NAVBAR_LINK' => 'Display link to the custom page in the navbar', + 'MCHAT_NAVBAR_LINK_COUNT' => 'Display number of active chat sessions in navbar link', 'MCHAT_MESSAGE_NUM_CUSTOM' => 'Initial number of messages to display on the custom page', 'MCHAT_MESSAGE_NUM_CUSTOM_EXPLAIN' => 'You are limited from 5 to 50. Default is 10.', 'MCHAT_MESSAGE_NUM_INDEX' => 'Initial number of messages to display on the index page', @@ -93,8 +98,8 @@ $lang = array_merge($lang, array( 'MCHAT_BBCODES_DISALLOWED_EXPLAIN' => 'Here you can input the bbcodes that are not to be used in a message.
Separate bbcodes with a vertical bar, for example:
b|i|u|code|list|list=|flash|quote and/or a %1$scustom bbcode tag name%2$s', 'MCHAT_STATIC_MESSAGE' => 'Static message', 'MCHAT_STATIC_MESSAGE_EXPLAIN' => 'Here you can define a static message to display to users of the chat. HTML code is allowed.
Set to empty to disable the display. You are limited to 255 characters.
This message can be translated: edit the MCHAT_STATIC_MESSAGE language key in /ext/dmzx/mchat/language/XX/mchat.php.', - 'MCHAT_USER_TIMEOUT' => 'User session timeout', - 'MCHAT_USER_TIMEOUT_EXPLAIN' => 'Set the amount of time in seconds until a user session in the chat ends.
Set to 0 for no timeout. Careful, the session of a user reading mChat will never expire!
You are limited to the %1$sforum config setting for sessions%2$s which is currently set to %3$d seconds', + 'MCHAT_TIMEOUT' => 'Session timeout', + 'MCHAT_TIMEOUT_EXPLAIN' => 'Set the number of seconds until a session in the chat ends.
Set to 0 for no timeout. Careful, the session of a user reading mChat will never expire!
You are limited to the %1$sforum config setting for sessions%2$s which is currently set to %3$d seconds', 'MCHAT_OVERRIDE_SMILIE_LIMIT' => 'Override smilie limit', 'MCHAT_OVERRIDE_SMILIE_LIMIT_EXPLAIN' => 'Set to yes to override the forums smilie limit setting for chat messages', 'MCHAT_OVERRIDE_MIN_POST_CHARS' => 'Override minimum characters limit', @@ -132,4 +137,6 @@ $lang = array_merge($lang, array( 'TOO_LARGE_MCHAT_TIMEOUT' => 'The user timeout value is too large.', 'TOO_SMALL_MCHAT_WHOIS_REFRESH' => 'The whois refresh value is too small.', 'TOO_LARGE_MCHAT_WHOIS_REFRESH' => 'The whois refresh value is too large.', + + 'MCHAT_30X_REMNANTS' => 'The installation as been aborted.
There are remnant modules from the mChat MOD for phpBB 3.0.x in the database. The mChat extension does not work correctly with these modules present.
You need to entirely uninstall the mChat MOD before being able to install the mChat extension. Specifically, the modules with the following IDs need to be deleted from the %1$smodules table: %2$s', )); diff --git a/language/en/mchat_ucp.php b/language/en/mchat_ucp.php index b1fdea1..446268b 100644 --- a/language/en/mchat_ucp.php +++ b/language/en/mchat_ucp.php @@ -51,7 +51,7 @@ $lang = array_merge($lang, array( 'MCHAT_POSTS' => 'Display new posts (currently all disabled, can be enabled in the mChat Global Settings section in the ACP)', 'MCHAT_CHARACTER_COUNT' => 'Display number of characters when typing a message', 'MCHAT_RELATIVE_TIME' => 'Display relative time for new messages', - 'MCHAT_RELATIVE_TIME_EXPLAIN' => 'Displays "just now", "1 minute ago" and so on for each message. Set to No to always display the full date.', + 'MCHAT_RELATIVE_TIME_EXPLAIN' => 'Displays “just now”, “1 minute ago” and so on for each message. Set to No to always display the full date.', 'MCHAT_PAUSE_ON_INPUT' => 'Pause on input', 'MCHAT_PAUSE_ON_INPUT_EXPLAIN' => 'Do not update mChat upon entering a message', 'MCHAT_MESSAGE_TOP' => 'Location of new chat messages', @@ -64,6 +64,7 @@ $lang = array_merge($lang, array( 'MCHAT_POSTS_REPLY' => 'Display new replies', 'MCHAT_POSTS_EDIT' => 'Display edited posts', 'MCHAT_POSTS_QUOTE' => 'Display quoted posts', + 'MCHAT_POSTS_LOGIN' => 'Display user logins', 'MCHAT_DATE_FORMAT' => 'Date format', 'MCHAT_DATE_FORMAT_EXPLAIN' => 'The syntax used is identical to the PHP date() function.', diff --git a/language/en/permissions_mchat.php b/language/en/permissions_mchat.php index 4e3751c..b646078 100644 --- a/language/en/permissions_mchat.php +++ b/language/en/permissions_mchat.php @@ -37,8 +37,10 @@ if (empty($lang) || !is_array($lang)) $lang = array_merge($lang, array( 'ACL_U_MCHAT_USE' => 'Can use mChat', 'ACL_U_MCHAT_VIEW' => 'Can view mChat', - 'ACL_U_MCHAT_EDIT' => 'Can edit messages', - 'ACL_U_MCHAT_DELETE' => 'Can delete messages', + 'ACL_U_MCHAT_EDIT' => 'Can edit own messages', + 'ACL_U_MCHAT_DELETE' => 'Can delete own messages', + 'ACL_U_MCHAT_MODERATOR_EDIT' => 'Can edit anyone’s messages', + 'ACL_U_MCHAT_MODERATOR_DELETE' => 'Can delete anyone’s messages', 'ACL_U_MCHAT_IP' => 'Can view IP addresses', 'ACL_U_MCHAT_PM' => 'Can use private message', 'ACL_U_MCHAT_LIKE' => 'Can like messages', @@ -47,7 +49,7 @@ $lang = array_merge($lang, array( 'ACL_U_MCHAT_ARCHIVE' => 'Can view the archive', 'ACL_U_MCHAT_BBCODE' => 'Can use BBCodes', 'ACL_U_MCHAT_SMILIES' => 'Can use smilies', - 'ACL_U_MCHAT_URLS' => 'Can post URLs', + 'ACL_U_MCHAT_URLS' => 'Can post automatically parsed URLs', 'ACL_U_MCHAT_AVATARS' => 'Can customise Display avatars', 'ACL_U_MCHAT_CAPITAL_LETTER' => 'Can customise Capital first letter', diff --git a/migrations/mchat_2_0_0_rc3.php b/migrations/mchat_2_0_0_rc3.php index edf8ff6..0eb085d 100644 --- a/migrations/mchat_2_0_0_rc3.php +++ b/migrations/mchat_2_0_0_rc3.php @@ -13,49 +13,60 @@ namespace dmzx\mchat\migrations; class mchat_2_0_0_rc3 extends \phpbb\db\migration\migration { - /** @var array */ - protected $mchat_config = null; - static public function depends_on() { return array('\phpbb\db\migration\data\v31x\v317pl1'); } - protected function get_config() - { - if ($this->mchat_config == null) - { - $yml_config_file = $this->phpbb_root_path . '/ext/dmzx/mchat/config/config_2_0_0.yml'; - $yml_data = \Symfony\Component\Yaml\Yaml::parse($yml_config_file); - $this->mchat_config = $yml_data['parameters']; - } - - return $this->mchat_config; - } - public function update_data() { - $config = $this->get_config(); - $update_data = array(); - - // Add configs - foreach (array('dmzx.mchat.config_global', 'dmzx.mchat.config_ucp') as $section) - { - foreach ($config[$section] as $key => $value) - { - $update_data[] = array('config.add', array($key, $value['default'])); - } - } - - // Add user permissions for customizing config values - foreach ($config['dmzx.mchat.config_ucp'] as $key => $value) - { - $update_data[] = array('permission.add', array('u_' . $key, true)); - } - - return array_merge($update_data, array( + return array( array('config.add', array('mchat_version', '2.0.0-RC3')), + // Add global configs + array('config.add', array('mchat_bbcode_disallowed', '')), + array('config.add', array('mchat_custom_height', 350)), + array('config.add', array('mchat_custom_page', 1)), + array('config.add', array('mchat_edit_delete_limit', 0)), + array('config.add', array('mchat_flood_time', 0)), + array('config.add', array('mchat_index_height', 250)), + array('config.add', array('mchat_live_updates', 1)), + array('config.add', array('mchat_max_message_lngth', 500)), + array('config.add', array('mchat_message_num_archive', 25)), + array('config.add', array('mchat_message_num_custom', 10)), + array('config.add', array('mchat_message_num_index', 10)), + array('config.add', array('mchat_navbar_link', 1)), + array('config.add', array('mchat_override_min_post_chars', 0)), + array('config.add', array('mchat_override_smilie_limit', 0)), + array('config.add', array('mchat_posts_edit', 0)), + array('config.add', array('mchat_posts_quote', 0)), + array('config.add', array('mchat_posts_reply', 0)), + array('config.add', array('mchat_posts_topic', 0)), + array('config.add', array('mchat_prune', 0)), + array('config.add', array('mchat_prune_num', '0')), + array('config.add', array('mchat_refresh', 10)), + array('config.add', array('mchat_rules', '')), + array('config.add', array('mchat_static_message', '')), + array('config.add', array('mchat_timeout', 0)), + array('config.add', array('mchat_whois', 1)), + array('config.add', array('mchat_whois_refresh', 60)), + + // Add global user configs + array('config.add', array('mchat_avatars', 1)), + array('config.add', array('mchat_capital_letter', 1)), + array('config.add', array('mchat_character_count', 1)), + array('config.add', array('mchat_date', 'D M d, Y g:i a')), + array('config.add', array('mchat_index', 1)), + array('config.add', array('mchat_input_area', 1)), + array('config.add', array('mchat_location', 1)), + array('config.add', array('mchat_message_top', 1)), + array('config.add', array('mchat_pause_on_input', 0)), + array('config.add', array('mchat_posts', 1)), + array('config.add', array('mchat_relative_time', 1)), + array('config.add', array('mchat_sound', 1)), + array('config.add', array('mchat_stats_index', 0)), + array('config.add', array('mchat_whois_index', 1)), + // Add user permissions array('permission.add', array('u_mchat_use', true)), array('permission.add', array('u_mchat_view', true)), @@ -71,6 +82,22 @@ class mchat_2_0_0_rc3 extends \phpbb\db\migration\migration array('permission.add', array('u_mchat_smilies', true)), array('permission.add', array('u_mchat_urls', true)), + // Add user permissions for customizing config values + array('permission.add', array('u_mchat_avatars', true)), + array('permission.add', array('u_mchat_capital_letter', true)), + array('permission.add', array('u_mchat_character_count', true)), + array('permission.add', array('u_mchat_date', true)), + array('permission.add', array('u_mchat_index', true)), + array('permission.add', array('u_mchat_input_area', true)), + array('permission.add', array('u_mchat_location', true)), + array('permission.add', array('u_mchat_message_top', true)), + array('permission.add', array('u_mchat_pause_on_input', true)), + array('permission.add', array('u_mchat_posts', true)), + array('permission.add', array('u_mchat_relative_time', true)), + array('permission.add', array('u_mchat_sound', true)), + array('permission.add', array('u_mchat_stats_index', true)), + array('permission.add', array('u_mchat_whois_index', true)), + // Add admin permissions array('permission.add', array('a_mchat', true)), @@ -129,22 +156,14 @@ class mchat_2_0_0_rc3 extends \phpbb\db\migration\migration 'UCP_MCHAT_CONFIG', array('module_basename' => '\dmzx\mchat\ucp\ucp_mchat_module'), )), - )); + ); } public function update_schema() { - $config = $this->get_config(); - $user_columns = array(); - - foreach ($config['dmzx.mchat.config_ucp'] as $key => $value) - { - $user_columns['user_' . $key] = array($value['type'], $value['default']); - } - return array( - 'add_tables' => array( - $this->table_prefix . 'mchat' => array( + 'add_tables' => array( + $this->table_prefix . 'mchat' => array( 'COLUMNS' => array( 'message_id' => array('UINT', null, 'auto_increment'), 'user_id' => array('UINT', 0), @@ -163,7 +182,7 @@ class mchat_2_0_0_rc3 extends \phpbb\db\migration\migration $this->table_prefix . 'mchat_deleted_messages' => array( 'COLUMNS' => array( - 'message_id' => array('UINT', null), + 'message_id' => array('UINT', 0), ), 'PRIMARY_KEY' => 'message_id', ), @@ -178,31 +197,53 @@ class mchat_2_0_0_rc3 extends \phpbb\db\migration\migration ), ), - 'add_columns' => array( - $this->table_prefix . 'users' => $user_columns, + 'add_columns' => array( + $this->table_prefix . 'users' => array( + 'user_mchat_avatars' => array('BOOL', 1), + 'user_mchat_capital_letter' => array('BOOL', 1), + 'user_mchat_character_count' => array('BOOL', 1), + 'user_mchat_date' => array('VCHAR:64', 'D M d, Y g:i a'), + 'user_mchat_index' => array('BOOL', 1), + 'user_mchat_input_area' => array('BOOL', 1), + 'user_mchat_location' => array('BOOL', 1), + 'user_mchat_message_top' => array('BOOL', 1), + 'user_mchat_pause_on_input' => array('BOOL', 0), + 'user_mchat_posts' => array('BOOL', 1), + 'user_mchat_relative_time' => array('BOOL', 1), + 'user_mchat_sound' => array('BOOL', 1), + 'user_mchat_stats_index' => array('BOOL', 0), + 'user_mchat_whois_index' => array('BOOL', 1), + ), ), ); } public function revert_schema() { - $config = $this->get_config(); - $user_columns = array(); - - foreach (array_keys($config['dmzx.mchat.config_ucp']) as $key) - { - $user_columns[] = 'user_' . $key; - } - return array( - 'drop_tables' => array( + 'drop_tables' => array( $this->table_prefix . 'mchat', $this->table_prefix . 'mchat_deleted_messages', $this->table_prefix . 'mchat_sessions', ), - 'drop_columns' => array( - $this->table_prefix . 'users' => $user_columns, + 'drop_columns' => array( + $this->table_prefix . 'users' => array( + 'user_mchat_avatars', + 'user_mchat_capital_letter', + 'user_mchat_character_count', + 'user_mchat_date', + 'user_mchat_index', + 'user_mchat_input_area', + 'user_mchat_location', + 'user_mchat_message_top', + 'user_mchat_pause_on_input', + 'user_mchat_posts', + 'user_mchat_relative_time', + 'user_mchat_sound', + 'user_mchat_stats_index', + 'user_mchat_whois_index', + ), ), ); } diff --git a/migrations/mchat_2_0_0_rc6.php b/migrations/mchat_2_0_0_rc6.php new file mode 100644 index 0000000..7448621 --- /dev/null +++ b/migrations/mchat_2_0_0_rc6.php @@ -0,0 +1,77 @@ + value is dynamic, do not cache + + array('config.remove', array('mchat_whois')), + + array('permission.add', array('u_mchat_moderator_edit', true)), + array('permission.add', array('u_mchat_moderator_delete', true)), + ); + } + + public function update_schema() + { + return array( + 'add_tables' => array( + $this->table_prefix . 'mchat_log' => array( + 'COLUMNS' => array( + 'log_id' => array('UINT', null, 'auto_increment'), + 'log_type' => array('TINT:4', 0), + 'user_id' => array('UINT', 0), + 'message_id' => array('UINT', 0), + 'log_ip' => array('VCHAR:40', ''), + 'log_time' => array('INT:11', 0), + ), + 'PRIMARY_KEY' => 'log_id', + ), + ), + 'drop_tables' => array( + $this->table_prefix . 'mchat_deleted_messages', + ), + + 'drop_columns' => array( + $this->table_prefix . 'mchat' => array( + 'edit_time', + ), + ), + ); + } + + public function revert_schema() + { + return array( + 'drop_tables' => array( + $this->table_prefix . 'mchat_log', + ), + ); + } +} diff --git a/sounds/README.txt b/sounds/README.txt new file mode 100644 index 0000000..2377467 --- /dev/null +++ b/sounds/README.txt @@ -0,0 +1,6 @@ +Credits + +add.mp3 UI Buttons and Whooshes Pack 1 by Narfstuff http://www.narfstuff.co.uk/ +edit.mp3 Scribble by TiesWijnen https://www.freesound.org/people/TiesWijnen/sounds/341738/ +del.mp3 Paper Throw http://www.soundjay.com/ +error.mp3 GUI Sound Effects by Lokif http://opengameart.org/content/gui-sound-effects diff --git a/sounds/add.mp3 b/sounds/add.mp3 index 2df0d2e..58556a3 100644 Binary files a/sounds/add.mp3 and b/sounds/add.mp3 differ diff --git a/sounds/del.mp3 b/sounds/del.mp3 index c576493..1fde917 100644 Binary files a/sounds/del.mp3 and b/sounds/del.mp3 differ diff --git a/sounds/edit.mp3 b/sounds/edit.mp3 index a871187..96672ef 100644 Binary files a/sounds/edit.mp3 and b/sounds/edit.mp3 differ diff --git a/sounds/error.mp3 b/sounds/error.mp3 index af9a34c..829dffb 100644 Binary files a/sounds/error.mp3 and b/sounds/error.mp3 differ diff --git a/styles/Subway/template/event/dmzx_mchat_messages_define_icons.html b/styles/Subway/template/event/dmzx_mchat_messages_define_icons.html new file mode 100644 index 0000000..e0c5ba2 --- /dev/null +++ b/styles/Subway/template/event/dmzx_mchat_messages_define_icons.html @@ -0,0 +1 @@ + diff --git a/styles/Subway/template/event/overall_header_head_append.html b/styles/Subway/template/event/overall_header_head_append.html new file mode 100644 index 0000000..22a6a0f --- /dev/null +++ b/styles/Subway/template/event/overall_header_head_append.html @@ -0,0 +1,2 @@ + + diff --git a/styles/Subway/template/mchat_navlink.html b/styles/Subway/template/mchat_navlink.html new file mode 100644 index 0000000..c313366 --- /dev/null +++ b/styles/Subway/template/mchat_navlink.html @@ -0,0 +1 @@ +
  • {MCHAT_TITLE}
  • diff --git a/styles/Subway/theme/mchat_custom.css b/styles/Subway/theme/mchat_custom.css new file mode 100644 index 0000000..7f475ec --- /dev/null +++ b/styles/Subway/theme/mchat_custom.css @@ -0,0 +1,16 @@ +/** + * + * @package phpBB Extension - mChat + * @copyright (c) 2016 dmzx - http://www.dmzx-web.net + * @copyright (c) 2016 kasimi + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 + * + */ + +.icon-mchat { + background: none; +} + +.icon-mchat:before, #mChat + .inner li.header dt:before { + content: '\e0e6'; +} diff --git a/styles/all/template/javascript/jquery.auto-grow-input.js b/styles/all/template/javascript/jquery.auto-grow-input.js deleted file mode 100644 index 34deeca..0000000 --- a/styles/all/template/javascript/jquery.auto-grow-input.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - jQuery autoGrowInput v1.0.3 - Copyright (c) 2014 Simon Steinberger / Pixabay - Based on stackoverflow.com/questions/931207 (James Padolsey) - GitHub: https://github.com/Pixabay/jQuery-autoGrowInput - License: http://www.opensource.org/licenses/mit-license.php -*/ - -(function($){ - var event = 'oninput' in document.createElement('input') ? 'input' : 'keydown'; - - $.fn.autoGrowInput = function(options){ - var o = $.extend({ maxWidth: 500, minWidth: 20, comfortZone: 0 }, options); - - this.each(function(){ - var input = $(this), - val = ' ', - comfortZone = (options && 'comfortZone' in options) ? o.comfortZone : parseInt(input.css('fontSize')), - span = $('').css({ - position: 'absolute', - top: -9999, - left: -9999, - width: 'auto', - fontSize: input.css('fontSize'), - fontFamily: input.css('fontFamily'), - fontWeight: input.css('fontWeight'), - letterSpacing: input.css('letterSpacing'), - textTransform: input.css('textTransform'), - whiteSpace: 'nowrap', - ariaHidden: true - }).appendTo('body'), - check = function(e){ - if (val === (val = input.val()) && e.type !== 'autogrow') return; - if (!val) val = input.attr('placeholder') || ''; - span.html(val.replace(/&/g, '&').replace(/\s/g, ' ').replace(//g, '>')); - var newWidth = span.width() + comfortZone, mw = typeof(o.maxWidth) == "function" ? o.maxWidth() : o.maxWidth; - if (newWidth > mw) newWidth = mw; - else if (newWidth < o.minWidth) newWidth = o.minWidth; - if (newWidth != input.width()) input.width(newWidth); - }; - input.on(event+'.autogrow autogrow', check); - // init on page load - check(); - }); - return this; - } -}(jQuery)); diff --git a/styles/all/template/javascript/jquery.autogrow-textarea.js b/styles/all/template/javascript/jquery.autogrow-textarea.js new file mode 100644 index 0000000..c12e45a --- /dev/null +++ b/styles/all/template/javascript/jquery.autogrow-textarea.js @@ -0,0 +1,211 @@ +// Based off https://code.google.com/p/gaequery/source/browse/trunk/src/static/scripts/jquery.autogrow-textarea.js?r=2 +// Modified by David Beck +// Mofified by kasimi (c) 2016 + +( function( factory ) { + // UMD wrapper + if ( typeof define === 'function' && define.amd ) { + // AMD + define( [ 'jquery' ], factory ); + } else if ( typeof exports !== 'undefined' ) { + // Node/CommonJS + module.exports = factory( require( 'jquery' ) ); + } else { + // Browser globals + factory( jQuery ); + } +}( function( $ ) { + + /* + * Auto-growing textareas; technique ripped from Facebook + */ + $.fn.autogrow = function(options) { + + options = $.extend( { + vertical: true, + horizontal: false, + characterSlop: 0 + }, options); + + this.filter('textarea,input').each(function() { + + var $this = $(this), + borderBox = $this.css( 'box-sizing' ) === 'border-box', + // minHeight = borderBox ? $this.outerHeight() : $this.height(), + maxHeight = $this.attr( "maxHeight" ), + minWidth = typeof( $this.attr( "minWidth" ) ) == "undefined" ? 0 : $this.attr( "minWidth" ); + + if( typeof( maxHeight ) == "undefined" ) maxHeight = 1000000; + + var shadow = $('
    ').css( { + position: 'absolute', + top: -10000, + left: -10000, + fontSize: $this.css('fontSize'), + fontFamily: $this.css('fontFamily'), + fontWeight: $this.css('fontWeight'), + lineHeight: $this.css('lineHeight'), + paddingLeft: $this.css('paddingLeft'), + paddingRight: $this.css('paddingRight'), + paddingTop: $this.css('paddingTop'), + paddingBottom: $this.css('paddingBottom'), + borderTop: $this.css('borderTop'), + borderBottom: $this.css('borderBottom'), + borderLeft: $this.css('borderLeft'), + borderRight: $this.css('borderRight'), + whiteSpace: 'pre-wrap', + resize: 'none' + } ).appendTo(document.body); + + shadow.html( 'a' ); + var characterWidth = shadow.width(); + shadow.html( '' ); + var isTextarea = $this.is('textarea'); + + var update = function( val ) { + + var times = function(string, number) { + for (var i = 0, r = ''; i < number; i ++) r += string; + return r; + }; + + if( typeof val === 'undefined' ) val = this.value; + if( val === '' && $(this).attr("placeholder") ) val = $(this).attr("placeholder"); + + if( options.vertical ) + val = val.replace(/&/g, '&') + .replace(//g, '>') + .replace(/\n$/, '
     ') + .replace(/\n/g, '
    ') + .replace(/ {2,}/g, function(space) { return times(' ', space.length -1) + ' '; }); + else + val = escapeHtml( val ); + + //if( options.horizontal ) + // val = $.trim( val ); + + // if( $(this).prop( 'tagName' ).toUpperCase() === 'INPUT' ) + // shadow.text(val).css( "width", "auto" ); + // else + shadow.html( val ).css( "width", "auto" ); // need to use html here otherwise no way to count spaces (with html we can use  ) + + if( options.horizontal ) + { + var slopWidth = options.characterSlop * characterWidth + 2; + + var newWidth = Math.max( shadow.width() + slopWidth, minWidth ); + var maxWidth = options.maxWidth; + //if( typeof( maxWidth ) === "undefined" ) maxWidth = $this.parent().width() - 12; // not sure why we were doing this but seems like a bad idea. doesn't work with inline-block parents for one thing, since it is the text area that should be "pushing" them to be wider + if( maxWidth ) newWidth = Math.min( newWidth, maxWidth ); + // Take scrollbar into account + if (isTextarea && shadow.get(0).scrollHeight > shadow.height()) { + newWidth += 20; + } + $(this).css( "width", newWidth ); + } + + if( options.vertical ) + { + var shadowWidth = $(this).width(); + if( ! borderBox ) shadowWidth = shadowWidth - parseInt($this.css('paddingLeft'),10) - parseInt($this.css('paddingRight'),10); + shadow.css( "width", shadowWidth ); + var shadowHeight = borderBox ? shadow.outerHeight() : shadow.height(); + + $(this).css( "height", "auto" ); + minHeight = borderBox ? $this.outerHeight() : $this.height(); + + var newHeight = Math.min( Math.max( shadowHeight, minHeight ), maxHeight ); + $(this).css( "height", newHeight ); + $(this).css( "overflow", newHeight == maxHeight ? "auto" : "hidden" ); + } + }; + + $(this) + .change(function(){update.call( this );return true;}) + .keyup(function(){update.call( this );return true;}) + .keypress(function( event ) { + if( event.ctrlKey || event.metaKey ) return; + + var val = this.value; + var caretInfo = _getCaretInfo( this ); + + var typedChar = event.which === 13 ? "\n" : String.fromCharCode( event.which ); + var valAfterKeypress = val.slice( 0, caretInfo.start ) + typedChar + val.slice( caretInfo.end ); + update.call( this, valAfterKeypress ); + return true; + }) + .bind( "update.autogrow", function(){ update.apply(this); } ) + .bind( "remove.autogrow", function() { + shadow.remove(); + } ); + + update.apply(this); + + }); + + return this; + }; + + // comes from https://github.com/madapaja/jquery.selection/blob/master/src/jquery.selection.js + var _getCaretInfo = function(element){ + var res = { + text: '', + start: 0, + end: 0 + }; + + if (!element.value) { + /* no value or empty string */ + return res; + } + + try { + if (window.getSelection) { + /* except IE */ + res.start = element.selectionStart; + res.end = element.selectionEnd; + res.text = element.value.slice(res.start, res.end); + } else if (doc.selection) { + /* for IE */ + element.focus(); + + var range = doc.selection.createRange(), + range2 = doc.body.createTextRange(); + + res.text = range.text; + + try { + range2.moveToElementText(element); + range2.setEndPoint('StartToStart', range); + } catch (e) { + range2 = element.createTextRange(); + range2.setEndPoint('StartToStart', range); + } + + res.start = element.value.length - range2.text.length; + res.end = res.start + range.text.length; + } + } catch (e) { + /* give up */ + } + + return res; + }; + + var entityMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''', + "/": '/', + " ": ' ' + }; + + function escapeHtml(string) { + return String(string).replace(/[&<>"'\/\ ]/g, function (s) { + return entityMap[s]; + } ); + } +} ) ); diff --git a/styles/all/template/javascript/js.cookie-2.0.4.min.js b/styles/all/template/javascript/js.cookie-2.0.4.min.js deleted file mode 100644 index e5ea49e..0000000 --- a/styles/all/template/javascript/js.cookie-2.0.4.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! js-cookie v2.0.4 | MIT */ -!function(a){if("function"==typeof define&&define.amd)define(a);else if("object"==typeof exports)module.exports=a();else{var b=window.Cookies,c=window.Cookies=a();c.noConflict=function(){return window.Cookies=b,c}}}(function(){function a(){for(var a=0,b={};a1){if(f=a({path:"/"},d.defaults,f),"number"==typeof f.expires){var h=new Date;h.setMilliseconds(h.getMilliseconds()+864e5*f.expires),f.expires=h}try{g=JSON.stringify(e),/^[\{\[]/.test(g)&&(e=g)}catch(i){}return e=encodeURIComponent(String(e)),e=e.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),b=encodeURIComponent(String(b)),b=b.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),b=b.replace(/[\(\)]/g,escape),document.cookie=[b,"=",e,f.expires&&"; expires="+f.expires.toUTCString(),f.path&&"; path="+f.path,f.domain&&"; domain="+f.domain,f.secure?"; secure":""].join("")}b||(g={});for(var j=document.cookie?document.cookie.split("; "):[],k=/(%[0-9A-Z]{2})+/g,l=0;l mChat.mssgLngth) { - alert(mChat.mssgLngthLong); + phpbb.alert(mChat.lang.err, mChat.lang.mssgLngthLong); return; } mChat.cached('add').prop('disabled', true); mChat.pauseSession(); - mChat.lastInputValue = mChat.cached('input').val(); - mChat.cached('input').val('').keyup().trigger('autogrow'); - mChat.refresh(mChat.lastInputValue).done(function() { + var originalInputValue = mChat.cached('input').val(); + var inputValue = originalInputValue; + var color = localStorage.getItem(mChat.cookie + 'mchat_color'); + if (color && inputValue.indexOf('[color=') === -1) { + inputValue = '[color=#' + color + '] ' + inputValue + ' [/color]'; + } + mChat.cached('input').val(''); + if (mChat.showCharCount) { + mChat.updateCharCount(); + } + mChat.refresh(inputValue).done(function() { mChat.resetSession(); }).fail(function() { - mChat.cached('input').val(mChat.lastInputValue).keyup().trigger('autogrow'); + mChat.cached('input').val(originalInputValue); + if (mChat.showCharCount) { + mChat.updateCharCount(); + } }).always(function() { mChat.cached('add').prop('disabled', false); setTimeout(function() { @@ -149,90 +237,65 @@ jQuery(function($) { }); }, edit: function() { - var $container = $(this).closest('.mchat-message'); - var $message = mChat.cached('confirm').find('textarea').show().val($container.data('mchat-message')); - mChat.cached('confirm').find('p').text(mChat.editInfo); - phpbb.confirm(mChat.cached('confirm'), function() { - ajaxRequest('edit', true, { - message_id: $container.data('mchat-id'), - message: $message.val(), - archive: mChat.archivePage ? 1 : 0 - }).done(function(json) { - mChat.updateMessages($(json.edit)); - mChat.resetSession(); - }); + var $message = $(this).closest('.mchat-message'); + mChat.confirm({ + container: mChat.cached('confirm'), + fields: function($container) { + return [ + $container.find('p').text(mChat.lang.editInfo), + $container.find('textarea').val($message.data('mchat-message')) + ]; + }, + confirm: function($p, $textarea) { + mChat.ajaxRequest('edit', true, { + message_id: $message.data('mchat-id'), + message: $textarea.val(), + archive: mChat.archivePage ? 1 : 0 + }).done(function(json) { + mChat.updateMessages($(json.edit)); + mChat.resetSession(); + }); + } }); }, del: function() { - var $container = $(this).closest('.mchat-message'); - mChat.cached('confirm').find('textarea').hide(); - mChat.cached('confirm').find('p').text(mChat.delConfirm); - phpbb.confirm(mChat.cached('confirm'), function() { - var delId = $container.data('mchat-id'); - ajaxRequest('del', true, { - message_id: delId - }).done(function() { - mChat.removeMessages([delId]); - mChat.resetSession(); - }); + var delId = $(this).closest('.mchat-message').data('mchat-id'); + mChat.confirm({ + container: mChat.cached('confirm'), + fields: function($container) { + return [ + $container.find('p').text(mChat.lang.delConfirm) + ]; + }, + confirm: function($p) { + mChat.ajaxRequest('del', true, { + message_id: delId + }).done(function() { + mChat.removeMessages([delId]); + mChat.resetSession(); + }); + } }); }, refresh: function(message) { if (mChat.isPaused && !message) { return false; } - var $messages = mChat.cached('messages').children(); var data = { - message_last_id: mChat.messageIds.length ? mChat.messageIds.max() : 0 + last: mChat.messageIds.length ? mChat.messageIds.max() : 0 }; if (message) { data.message = message; } if (mChat.liveUpdates) { - data.message_first_id = mChat.messageIds.length ? mChat.messageIds.min() : 0; - data.message_edits = {}; - var now = Math.floor(Date.now() / 1000); - $.each($messages, function() { - var $message = $(this); - var editTime = $message.data('mchat-edit-time'); - if (editTime && (!mChat.editDeleteLimit || $message.data('mchat-message-time') >= now - mChat.editDeleteLimit / 1000)) { - data.message_edits[$message.data('mchat-id')] = editTime; - } - }); + data.log = mChat.logId; } mChat.cached('status-ok', 'status-error', 'status-paused').hide(); mChat.cached('status-load').show(); - return ajaxRequest(message ? 'add' : 'refresh', !!message, data).done(function(json) { + return mChat.ajaxRequest(message ? 'add' : 'refresh', !!message, data).done(function(json) { + $(mChat).trigger('mchat_response_handle_data_before', [json]); if (json.add) { - var $html = $(json.add); - $('.mchat-no-messages').remove(); - $html.reverse(mChat.messageTop).hide().each(function(i) { - var $message = $(this); - if ($.inArray($message.data('mchat-id'), mChat.messageIds) !== -1) { - return; - } - mChat.messageIds.push($message.data('mchat-id')); - setTimeout(function() { - if (mChat.messageTop) { - mChat.cached('messages').prepend($message); - } else { - mChat.cached('messages').append($message); - } - $message.css('opacity', 0).slideDown().animate({opacity: 1}, {queue: false}); - mChat.cached('messages').animate({scrollTop: mChat.messageTop ? 0 : mChat.cached('messages')[0].scrollHeight}); - }, i * 400); - if (mChat.editDeleteLimit && $message.data('mchat-edit-delete-limit') && $message.find('[data-mchat-action="edit"], [data-mchat-action="del"]').length > 0) { - var id = $message.prop('id'); - setTimeout(function() { - $('#' + id).find('[data-mchat-action="edit"], [data-mchat-action="del"]').fadeOut(function() { - $(this).closest('li').remove(); - }); - }, mChat.editDeleteLimit); - } - mChat.startRelativeTimeUpdate($message); - }); - mChat.sound('add'); - mChat.notice(); + mChat.addMessages($(json.add)); } if (json.edit) { mChat.updateMessages($(json.edit)); @@ -241,12 +304,16 @@ jQuery(function($) { mChat.removeMessages(json.del); } if (json.whois) { - mChat.whois(); + mChat.handleWhoisResponse(json); + } + if (json.log) { + mChat.logId = json.log; } if (mChat.refreshInterval) { mChat.cached('status-load', 'status-error', 'status-paused').hide(); mChat.cached('status-ok').show(); } + $(mChat).trigger('mchat_response_handle_data_after', [json]); }); }, whois: function() { @@ -254,51 +321,133 @@ jQuery(function($) { mChat.cached('refresh-pending').show(); mChat.cached('refresh-explain').hide(); } - ajaxRequest('whois', false, {}).done(function(json) { - var $whois = $(json.whois); - var $userlist = $whois.find('#mchat-userlist'); - if (Cookies.get('mchat_show_userlist')) { - $userlist.show(); + mChat.ajaxRequest('whois', false, {}).done(mChat.handleWhoisResponse); + }, + handleWhoisResponse: function(json) { + var $whois = $(json.whois); + var $userlist = $whois.find('#mchat-userlist'); + if (localStorage.getItem(mChat.cookie + 'mchat_show_userlist')) { + $userlist.show(); + } + mChat.cached('whois').replaceWith($whois); + mChat.cache.whois = $whois; + mChat.cache.userlist = $userlist; + if (mChat.customPage) { + mChat.cached('refresh-pending').hide(); + mChat.cached('refresh-explain').show(); + } + if (json.navlink) { + $('.mchat-nav-link').html(json.navlink); + } + if (json.navlink_title) { + $('.mchat-nav-link-title').prop('title', json.navlink_title); + } + }, + addMessages: function($messages) { + var playSound = true; + mChat.cached('messages').find('.mchat-no-messages').remove(); + $messages.reverse(mChat.messageTop).hide().each(function(i) { + var $message = $(this); + var data = { + message: $message, + delay: mChat.refreshInterval ? 400 : 0, + abort: $.inArray($message.data('mchat-id'), mChat.messageIds) !== -1, + playSound: playSound + }; + $(mChat).trigger('mchat_add_message_before', [data]); + if (data.abort) { + return; } - mChat.cached('whois').replaceWith($whois); - mChat.cache.whois = $whois; - mChat.cache.userlist = $userlist; - if (mChat.customPage) { - mChat.cached('refresh-pending').hide(); - mChat.cached('refresh-explain').show(); + if (data.playSound) { + mChat.sound('add'); + mChat.titleAlert(); + playSound = false; } + mChat.messageIds.push($message.data('mchat-id')); + setTimeout(function() { + var $container = mChat.cached('messages'); + var data = { + container: $container, + message: $message, + add: function() { + if (mChat.messageTop) { + this.container.prepend(this.message); + } else { + this.container.append(this.message); + } + }, + show: function() { + var scrollTop, scrollHeight = mChat.messageTop ? 0 : $container.get(0).scrollHeight; + if (mChat.messageTop && (scrollTop = this.container.scrollTop()) > 0) { + this.message.show(); + this.container.scrollTop(scrollTop + this.message.outerHeight()); + } else { + this.message.css('opacity', 0).slideDown('fast').animate({opacity: 1}, {duration: 'fast', queue: false}); + } + if (!mChat.messageTop && this.container.scrollTop() >= scrollHeight - this.container.height()) { + this.container.animate({ + scrollTop: scrollHeight, + easing: 'swing', + duration: 'slow' + }); + } + } + }; + $(mChat).trigger('mchat_add_message_animate_before', [data]); + data.add(); + data.show(); + }, i * data.delay); + if (mChat.editDeleteLimit && $message.data('mchat-edit-delete-limit') && $message.find('[data-mchat-action="edit"], [data-mchat-action="del"]').length > 0) { + var id = $message.prop('id'); + setTimeout(function() { + $('#' + id).find('[data-mchat-action="edit"], [data-mchat-action="del"]').fadeOut(function() { + $(this).closest('li').remove(); + }); + }, mChat.editDeleteLimit); + } + mChat.startRelativeTimeUpdate($message); }); }, updateMessages: function($messages) { - var soundPlayed = false; + var playSound = true; $messages.each(function() { var $newMessage = $(this); - var $oldMessage = $('#mchat-message-' + $newMessage.data('mchat-id')); - mChat.stopRelativeTimeUpdate($oldMessage); - mChat.startRelativeTimeUpdate($newMessage); - $oldMessage.fadeOut(function() { - $oldMessage.replaceWith($newMessage.hide().fadeIn()); + var data = { + newMessage: $newMessage, + oldMessage: $('#mchat-message-' + $newMessage.data('mchat-id')), + playSound: playSound + }; + $(mChat).trigger('mchat_edit_message_before', [data]); + mChat.stopRelativeTimeUpdate(data.oldMessage); + mChat.startRelativeTimeUpdate(data.newMessage); + data.oldMessage.fadeOut(function() { + data.oldMessage.replaceWith(data.newMessage.hide().fadeIn()); }); - if (!soundPlayed) { - soundPlayed = true; + if (data.playSound) { mChat.sound('edit'); + playSound = false; } }); }, removeMessages: function(ids) { - var soundPlayed = false; + var playSound = true; $.each(ids, function(i, id) { - var index = 0; - while ((index = $.inArray(id, mChat.messageIds, index)) !== -1) { - mChat.messageIds.splice(index, 1); - var $message = $('#mchat-message-' + id); - mChat.stopRelativeTimeUpdate($message); - $message.fadeOut(function() { - $message.remove(); - }); - if (!soundPlayed) { - soundPlayed = true; + if (mChat.messageIds.removeValue(id)) { + var data = { + id: id, + message: $('#mchat-message-' + id), + playSound: playSound + }; + $(mChat).trigger('mchat_delete_message_before', [data]); + mChat.stopRelativeTimeUpdate(data.message); + (function($message) { + $message.fadeOut(function() { + $message.remove(); + }); + })(data.message); + if (data.playSound) { mChat.sound('del'); + playSound = false; } } }); @@ -318,7 +467,7 @@ jQuery(function($) { }, relativeTimeUpdate: function($time) { var minutesAgo = $time.data('mchat-minutes-ago') + 1; - var langMinutesAgo = mChat.minutesAgo[minutesAgo]; + var langMinutesAgo = mChat.lang.minutesAgo[minutesAgo]; if (langMinutesAgo) { $time.text(langMinutesAgo).data('mchat-minutes-ago', minutesAgo); } else { @@ -335,14 +484,14 @@ jQuery(function($) { }, countDown: function() { mChat.sessionTime -= 1; - mChat.cached('session').html(mChat.sessEnds.format({timeleft: mChat.timeLeft(mChat.sessionTime)})); + mChat.cached('session').html(mChat.lang.sessEnds.format({timeleft: mChat.timeLeft(mChat.sessionTime)})); if (mChat.sessionTime < 1) { mChat.endSession(); } }, pauseSession: function() { clearInterval(mChat.refreshInterval); - if (mChat.userTimeout) { + if (mChat.timeout) { clearInterval(mChat.sessionCountdown); } if (mChat.whoisRefresh) { @@ -353,10 +502,10 @@ jQuery(function($) { if (!mChat.archivePage) { clearInterval(mChat.refreshInterval); mChat.refreshInterval = setInterval(mChat.refresh, mChat.refreshTime); - if (mChat.userTimeout) { - mChat.sessionTime = mChat.userTimeout / 1000; + if (mChat.timeout) { + mChat.sessionTime = mChat.timeout / 1000; clearInterval(mChat.sessionCountdown); - mChat.cached('session').html(mChat.sessEnds.format({timeleft: mChat.timeLeft(mChat.sessionTime)})); + mChat.cached('session').html(mChat.lang.sessEnds.format({timeleft: mChat.timeLeft(mChat.sessionTime)})); mChat.sessionCountdown = setInterval(mChat.countDown, 1000); } if (mChat.whoisRefresh) { @@ -365,15 +514,15 @@ jQuery(function($) { } mChat.cached('status-ok').show(); mChat.cached('status-load', 'status-error', 'status-paused').hide(); - mChat.cached('refresh-text').html(mChat.refreshYes); + mChat.cached('refresh-text').html(mChat.lang.refreshYes); } }, endSession: function(skipUpdateWhois) { clearInterval(mChat.refreshInterval); mChat.refreshInterval = false; - if (mChat.userTimeout) { + if (mChat.timeout) { clearInterval(mChat.sessionCountdown); - mChat.cached('session').html(mChat.sessOut); + mChat.cached('session').html(mChat.lang.sessOut); } if (mChat.whoisRefresh) { clearInterval(mChat.whoisInterval); @@ -383,23 +532,31 @@ jQuery(function($) { } mChat.cached('status-load', 'status-ok', 'status-error').hide(); mChat.cached('status-paused').show(); - mChat.cached('refresh-text').html(mChat.refreshNo); + mChat.cached('refresh-text').html(mChat.lang.refreshNo); }, pauseStart: function() { mChat.isPaused = true; - mChat.cached('refresh-text').html(mChat.refreshNo); + mChat.cached('refresh-text').html(mChat.lang.refreshNo); mChat.cached('status-load', 'status-ok', 'status-error').hide(); mChat.cached('status-paused').show(); }, pauseEnd: function() { - mChat.cached('refresh-text').html(mChat.refreshYes); + mChat.cached('refresh-text').html(mChat.lang.refreshYes); mChat.cached('status-load', 'status-error', 'status-paused').hide(); mChat.cached('status-ok').show(); mChat.isPaused = false; }, + updateCharCount: function() { + var count = mChat.cached('input').val().length; + var charCount = mChat.lang.charCount.format({current: count, max: mChat.mssgLngth}); + var $elem = mChat.cached('character-count').html(charCount).toggleClass('hidden', count === 0); + if (mChat.mssgLngth) { + $elem.toggleClass('error', count > mChat.mssgLngth); + } + }, mention: function() { var $container = $(this).closest('.mchat-message'); - var username = mChat.entityDecode($container.data('mchat-username')); + var username = $container.data('mchat-username'); var usercolor = $container.data('mchat-usercolor'); if (usercolor) { username = '[b][color=' + usercolor + ']' + username + '[/color][/b]'; @@ -410,32 +567,19 @@ jQuery(function($) { }, quote: function() { var $container = $(this).closest('.mchat-message'); - var username = mChat.entityDecode($container.data('mchat-username')); - var quote = mChat.entityDecode($container.data('mchat-message')); + var username = $container.data('mchat-username'); + var quote = $container.data('mchat-message'); insert_text('[quote="' + username + '"] ' + quote + '[/quote]'); }, like: function() { var $container = $(this).closest('.mchat-message'); - var username = mChat.entityDecode($container.data('mchat-username')); - var quote = mChat.entityDecode($container.data('mchat-message')); - insert_text(mChat.likes + '[quote="' + username + '"] ' + quote + '[/quote]'); + var username = $container.data('mchat-username'); + var quote = $container.data('mchat-message'); + insert_text('[i]' + mChat.lang.likes + '[/i][quote="' + username + '"] ' + quote + '[/quote]'); }, ip: function() { popup(this.href, 750, 500); }, - entityDecode: function(text) { - var s = decodeURIComponent(text.toString().replace(/\+/g, ' ')); - s = s.replace(/</g, '<'); - s = s.replace(/>/g, '>'); - s = s.replace(/:/g, ':'); - s = s.replace(/./g, '.'); - s = s.replace(/&/g, '&'); - s = s.replace(/"/g, "'"); - return s; - }, - inputMessageLength: function() { - return $.trim(mChat.cached('input').val()).replace(/\[\/?[^\[\]]+\]/g, '').length; - }, cached: function() { return $($.map(arguments, function(name) { if (!mChat.cache[name]) { @@ -449,8 +593,6 @@ jQuery(function($) { }); mChat.cache = {}; - mChat.cached('confirm').detach().show(); - mChat.messageIds = mChat.cached('messages').children().map(function() { return $(this).data('mchat-id'); }).get(); @@ -469,44 +611,43 @@ jQuery(function($) { mChat.cached('messages').animate({scrollTop: mChat.cached('messages')[0].scrollHeight, easing: 'swing', duration: 'slow'}); } - if (!mChat.cached('user-sound').prop('checked')) { - Cookies.set('mchat_no_sound', 'yes'); - } - - mChat.cached('user-sound').prop('checked', mChat.playSound && !Cookies.get('mchat_no_sound')).change(function() { + mChat.cached('user-sound').prop('checked', mChat.playSound && !localStorage.getItem(mChat.cookie + 'mchat_no_sound')).change(function() { if (this.checked) { - Cookies.remove('mchat_no_sound'); + localStorage.removeItem(mChat.cookie + 'mchat_no_sound'); } else { - Cookies.set('mchat_no_sound', 'yes'); + localStorage.setItem(mChat.cookie + 'mchat_no_sound', 'yes'); } - }); + }).change(); $.each(mChat.removeBBCodes.split('|'), function(i, bbcode) { - $('#format-buttons .bbcode-' + bbcode).remove(); + var bbCodeClass = '.bbcode-' + bbcode.replaceMany({ + '=': '-', + '*': 'asterisk' + }); + $('#format-buttons').find(bbCodeClass).remove(); }); var $colourPalette = $('#colour_palette'); $colourPalette.appendTo($colourPalette.parent()).wrap('
    ').show(); - $('#bbpalette,#abbc3_bbpalette').prop('onclick', null).attr('data-mchat-toggle', 'colour'); + $('#bbpalette,#abbc3_bbpalette,#color_wheel').prop('onclick', null).attr('data-mchat-toggle', 'colour'); $.each(['userlist', 'smilies', 'bbcodes', 'colour'], function(i, elem) { - if (Cookies.get('mchat_show_' + elem)) { + if (localStorage.getItem(mChat.cookie + 'mchat_show_' + elem)) { mChat.cached(elem).toggle(); } }); - if (mChat.cached('input').is('input')) { - mChat.cached('form').keypress(function(e) { - if (e.which == 13) { - mChat.add(); - e.preventDefault(); - e.stopImmediatePropagation(); - } - }); - } + mChat.isTextarea = mChat.cached('input').is('textarea'); + mChat.cached('form').submit(function(e){ + e.preventDefault(); + }).keypress(function(e) { + if ((e.which == 10 || e.which == 13) && (!mChat.isTextarea || e.ctrlKey || e.metaKey) && mChat.cached('input').is(e.target)) { + mChat.add(); + } + }); if (mChat.pause) { - mChat.cached('form').keyup(function(e) { + mChat.cached('form').on('input', function() { if (mChat.refreshInterval !== false) { var val = mChat.cached('input').val(); if (mChat.isPaused && val === '') { @@ -519,21 +660,12 @@ jQuery(function($) { } if (mChat.showCharCount) { - mChat.cached('form').keyup(function(e) { - var count = mChat.inputMessageLength(); - var $elem = mChat.cached('character-count'); - $elem.html(mChat.charCount.format({current: count, max: mChat.mssgLngth})).css('visibility', count > 0 ? 'visible' : 'hidden'); - if (mChat.mssgLngth) { - $elem.toggleClass('error', count > mChat.mssgLngth); - } - }); + mChat.cached('form').on('input', mChat.updateCharCount); } - mChat.cached('form').one('keypress', function() { - mChat.cached('input').autoGrowInput({ - minWidth: mChat.cached('input').width(), - maxWidth: mChat.cached('form').width() - (mChat.cached('input').outerWidth(true) - mChat.cached('input').width()) - }); + mChat.cached('input').autogrow({ + vertical: false, + horizontal: true }); } @@ -543,13 +675,34 @@ jQuery(function($) { mChat.pageIsUnloading = true; }); + mChat.cached('colour').find('.colour-palette').on('click', 'a', function(e) { + if (e.ctrlKey || e.metaKey) { + e.preventDefault(); + e.stopImmediatePropagation(); + var $this = $(this); + var newColor = $this.data('color'); + if (localStorage.getItem(mChat.cookie + 'mchat_color') === newColor) { + localStorage.removeItem(mChat.cookie + 'mchat_color'); + } else { + localStorage.setItem(mChat.cookie + 'mchat_color', newColor); + mChat.cached('colour').find('.colour-palette a').removeClass('remember-color'); + } + $this.toggleClass('remember-color'); + } + }); + + var color = localStorage.getItem(mChat.cookie + 'mchat_color'); + if (color) { + mChat.cached('colour').find('.colour-palette a[data-color="' + color + '"]').addClass('remember-color'); + } + $('#phpbb').on('click', '[data-mchat-action]', function(e) { + e.preventDefault(); var action = $(this).data('mchat-action'); mChat[action].call(this); - e.preventDefault(); }).on('click', '[data-mchat-toggle]', function(e) { + e.preventDefault(); var elem = $(this).data('mchat-toggle'); mChat.toggle(elem); - e.preventDefault(); }); }); diff --git a/styles/prosilver/template/mchat_script_data.html b/styles/all/template/mchat_script_data.html similarity index 51% rename from styles/prosilver/template/mchat_script_data.html rename to styles/all/template/mchat_script_data.html index 7866495..df1fcfc 100644 --- a/styles/prosilver/template/mchat_script_data.html +++ b/styles/all/template/mchat_script_data.html @@ -1,3 +1,11 @@ + + + + + + + + diff --git a/styles/basic/template/mchat_navlink.html b/styles/basic/template/mchat_navlink.html index 99a90ef..b5d77c4 100644 --- a/styles/basic/template/mchat_navlink.html +++ b/styles/basic/template/mchat_navlink.html @@ -1 +1 @@ -
  • {L_MCHAT_TITLE}
  • +
  • {MCHAT_TITLE}
  • diff --git a/styles/basic/theme/mchat_custom.css b/styles/basic/theme/mchat_custom.css index dadd756..e1f9145 100644 --- a/styles/basic/theme/mchat_custom.css +++ b/styles/basic/theme/mchat_custom.css @@ -8,32 +8,32 @@ */ .icon-mchat { - position: relative; + position: relative; } .icon-mchat:after { - content: '\f086'; - font-family: 'FontAwesome'; - width: 18px; - text-align: center; - position: absolute; - top: 50%; - left: 0; - height: 14px; - margin-top: -7px; - font-size: 12px; - line-height: 14px; - vertical-align: baseline; - font-weight: normal; - font-style: normal; - text-transform: none; - text-indent: 0; - pointer-events: none; + content: '\f086'; + font-family: 'FontAwesome'; + width: 18px; + text-align: center; + position: absolute; + top: 50%; + left: 0; + height: 14px; + margin-top: -7px; + font-size: 12px; + line-height: 14px; + vertical-align: baseline; + font-weight: normal; + font-style: normal; + text-transform: none; + text-indent: 0; + pointer-events: none; } .navbar .nav-tabs .mchat .nav-link { position: relative; - text-indent: 999px; + text-indent: 999px; width: 15px; padding: 0 8px; overflow: hidden; @@ -41,7 +41,7 @@ .navbar .nav-tabs .mchat .nav-link:after { content: '\f086'; - font-family: 'FontAwesome'; + font-family: 'FontAwesome'; position: absolute; top: 50%; margin-top: -7.5px; @@ -51,18 +51,18 @@ font-weight: normal; font-style: normal; text-indent: 0; - text-align: center; + text-align: center; font-size: 15px; left:8px } .rtl .navbar .nav-tabs .mchat .nav-link { - padding-left: 12px; + padding-left: 12px; padding-right: 30px; } .rtl .navbar .nav-tabs .mchat .nav-link:after { - left: auto; + left: auto; right: 8px; } diff --git a/styles/black/template/event/dmzx_mchat_messages_define_icons.html b/styles/black/template/event/dmzx_mchat_messages_define_icons.html new file mode 100644 index 0000000..4be4b10 --- /dev/null +++ b/styles/black/template/event/dmzx_mchat_messages_define_icons.html @@ -0,0 +1 @@ + diff --git a/styles/black/template/mchat_navlink.html b/styles/black/template/mchat_navlink.html index 99a90ef..b5d77c4 100644 --- a/styles/black/template/mchat_navlink.html +++ b/styles/black/template/mchat_navlink.html @@ -1 +1 @@ -
  • {L_MCHAT_TITLE}
  • +
  • {MCHAT_TITLE}
  • diff --git a/styles/black/theme/mchat_custom.css b/styles/black/theme/mchat_custom.css index c5fb0fa..f4f5c3b 100644 --- a/styles/black/theme/mchat_custom.css +++ b/styles/black/theme/mchat_custom.css @@ -65,7 +65,3 @@ left: auto; right: 8px; } - -.mchat-button:before { - background-image: url("./images/message_icons.png"); -} diff --git a/styles/canvas/template/event/overall_footer_after.html b/styles/canvas/template/event/overall_footer_after.html new file mode 100644 index 0000000..c2080a8 --- /dev/null +++ b/styles/canvas/template/event/overall_footer_after.html @@ -0,0 +1,3 @@ + + + diff --git a/styles/canvas/template/event/overall_header_head_append.html b/styles/canvas/template/event/overall_header_head_append.html new file mode 100644 index 0000000..22a6a0f --- /dev/null +++ b/styles/canvas/template/event/overall_header_head_append.html @@ -0,0 +1,2 @@ + + diff --git a/styles/canvas/theme/mchat_custom.css b/styles/canvas/theme/mchat_custom.css new file mode 100644 index 0000000..332b32f --- /dev/null +++ b/styles/canvas/theme/mchat_custom.css @@ -0,0 +1,28 @@ +/** + * + * @package phpBB Extension - mChat + * @copyright (c) 2016 dmzx - http://www.dmzx-web.net + * @copyright (c) 2016 kasimi + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 + * + */ + +ul#mchat-messages.topiclist li { + padding: 0; +} + +.mchat-text { + font-size: 1.1em; +} + +ul.mchat-buttons > li { + background: none !important; +} + +#mchat-panel.cp-mini .button2 { + float: none; +} + +#mchat-panel #st_editor_buttons { + display: block !important; +} diff --git a/styles/elegance/template/mchat_navlink.html b/styles/elegance/template/mchat_navlink.html index 99a90ef..b5d77c4 100644 --- a/styles/elegance/template/mchat_navlink.html +++ b/styles/elegance/template/mchat_navlink.html @@ -1 +1 @@ -
  • {L_MCHAT_TITLE}
  • +
  • {MCHAT_TITLE}
  • diff --git a/styles/latte/template/mchat_navlink.html b/styles/latte/template/mchat_navlink.html index 99a90ef..b5d77c4 100644 --- a/styles/latte/template/mchat_navlink.html +++ b/styles/latte/template/mchat_navlink.html @@ -1 +1 @@ -
  • {L_MCHAT_TITLE}
  • +
  • {MCHAT_TITLE}
  • diff --git a/styles/metro_blue/template/mchat_navlink.html b/styles/metro_blue/template/mchat_navlink.html index b84592e..5e7bd48 100644 --- a/styles/metro_blue/template/mchat_navlink.html +++ b/styles/metro_blue/template/mchat_navlink.html @@ -1 +1 @@ -
  • {L_MCHAT_TITLE}
  • +
  • {MCHAT_TITLE}
  • diff --git a/styles/pbtech/template/mchat_navlink.html b/styles/pbtech/template/mchat_navlink.html index 3dedc11..cc5ce5b 100644 --- a/styles/pbtech/template/mchat_navlink.html +++ b/styles/pbtech/template/mchat_navlink.html @@ -1 +1 @@ -
  • {L_MCHAT_TITLE}
  • +
  • {MCHAT_TITLE}
  • diff --git a/styles/pbtech/theme/mchat_custom.css b/styles/pbtech/theme/mchat_custom.css index 11b638d..bb93233 100644 --- a/styles/pbtech/theme/mchat_custom.css +++ b/styles/pbtech/theme/mchat_custom.css @@ -12,7 +12,7 @@ font-family: 'FontAwesome'; } -#mchat-panel.cp-mini { +#mchat-body .cp-mini { background-color: #E5E4E3; } diff --git a/styles/pbwow3/template/event/dmzx_mchat_messages_define_icons.html b/styles/pbwow3/template/event/dmzx_mchat_messages_define_icons.html new file mode 100644 index 0000000..4be4b10 --- /dev/null +++ b/styles/pbwow3/template/event/dmzx_mchat_messages_define_icons.html @@ -0,0 +1 @@ + diff --git a/styles/pbwow3/template/mchat_navlink.html b/styles/pbwow3/template/mchat_navlink.html index 3dedc11..cc5ce5b 100644 --- a/styles/pbwow3/template/mchat_navlink.html +++ b/styles/pbwow3/template/mchat_navlink.html @@ -1 +1 @@ -
  • {L_MCHAT_TITLE}
  • +
  • {MCHAT_TITLE}
  • diff --git a/styles/pbwow3/theme/images/message_icons.png b/styles/pbwow3/theme/images/message_icons.png deleted file mode 100644 index 18b2fd9..0000000 Binary files a/styles/pbwow3/theme/images/message_icons.png and /dev/null differ diff --git a/styles/pbwow3/theme/mchat_custom.css b/styles/pbwow3/theme/mchat_custom.css index 8ca08b7..feb1594 100644 --- a/styles/pbwow3/theme/mchat_custom.css +++ b/styles/pbwow3/theme/mchat_custom.css @@ -20,7 +20,3 @@ content: ''; margin-right: 0; } - -.mchat-button:before { - background-image: url("./images/message_icons.png"); -} diff --git a/styles/prosilver/template/event/dmzx_mchat_custom_include.html b/styles/prosilver/template/event/dmzx_mchat_custom_include.html new file mode 100644 index 0000000..a893939 --- /dev/null +++ b/styles/prosilver/template/event/dmzx_mchat_custom_include.html @@ -0,0 +1,3 @@ + + + diff --git a/styles/prosilver/template/event/dmzx_mchat_messages_define_icons.html b/styles/prosilver/template/event/dmzx_mchat_messages_define_icons.html new file mode 100644 index 0000000..55f42b2 --- /dev/null +++ b/styles/prosilver/template/event/dmzx_mchat_messages_define_icons.html @@ -0,0 +1 @@ + diff --git a/styles/prosilver/template/event/index_body_block_online_append.html b/styles/prosilver/template/event/index_body_block_online_append.html index 15e343c..a53986f 100644 --- a/styles/prosilver/template/event/index_body_block_online_append.html +++ b/styles/prosilver/template/event/index_body_block_online_append.html @@ -3,5 +3,5 @@

    {L_MCHAT_WHO_IS_CHATTING}

    -

    {MCHAT_USERS_COUNT} {MCHAT_ONLINE_EXPLAIN}
    {MCHAT_USERS_LIST} +

    {MCHAT_USERS_TOTAL} {MCHAT_ONLINE_EXPLAIN}
    {MCHAT_USERS_LIST} diff --git a/styles/prosilver/template/event/overall_footer_copyright_append.html b/styles/prosilver/template/event/overall_footer_copyright_append.html index 878e6ca..a91abfc 100644 --- a/styles/prosilver/template/event/overall_footer_copyright_append.html +++ b/styles/prosilver/template/event/overall_footer_copyright_append.html @@ -1,3 +1,4 @@ -

    {MCHAT_DISPLAY_NAME} © {L_POST_BY_AUTHOR} {MCHAT_AUTHOR_HOMEPAGES}
    +
    + {MCHAT_DISPLAY_NAME} © {L_POST_BY_AUTHOR} {MCHAT_AUTHOR_HOMEPAGES} diff --git a/styles/prosilver/template/event/overall_header_navigation_append.html b/styles/prosilver/template/event/overall_header_navigation_append.html index 924f28d..a5415bd 100644 --- a/styles/prosilver/template/event/overall_header_navigation_append.html +++ b/styles/prosilver/template/event/overall_header_navigation_append.html @@ -1,3 +1,3 @@ - + diff --git a/styles/prosilver/template/mchat_body.html b/styles/prosilver/template/mchat_body.html index a4e9b40..bf6b4a9 100644 --- a/styles/prosilver/template/mchat_body.html +++ b/styles/prosilver/template/mchat_body.html @@ -2,16 +2,11 @@ - - - - - - - +
    + +
    - + -
    +
      @@ -46,9 +42,9 @@
    -
    - + +
    class="collapsible"> @@ -58,8 +54,10 @@
    + +
    + +
    + +
    diff --git a/styles/prosilver/template/mchat_header.html b/styles/prosilver/template/mchat_header.html index 68c4d52..a0a8f89 100644 --- a/styles/prosilver/template/mchat_header.html +++ b/styles/prosilver/template/mchat_header.html @@ -1,4 +1,4 @@
    {L_MCHAT_ARCHIVE_PAGE}{L_MCHAT_TITLE}{L_MCHAT_TITLE}
    -
     
    +
    diff --git a/styles/prosilver/template/mchat_messages.html b/styles/prosilver/template/mchat_messages.html index c0e346f..72d4aba 100644 --- a/styles/prosilver/template/mchat_messages.html +++ b/styles/prosilver/template/mchat_messages.html @@ -1,5 +1,8 @@ + + + -
  • data-mchat-usercolor="{mchatrow.MCHAT_USERNAME_COLOR}" data-mchat-message="{mchatrow.MCHAT_MESSAGE_EDIT}" data-mchat-message-time="{mchatrow.MCHAT_MESSAGE_TIME}" data-mchat-edit-time="{mchatrow.MCHAT_EDIT_TIME}" data-mchat-edit-delete-limit="1"> +
  • data-mchat-usercolor="{mchatrow.MCHAT_USERNAME_COLOR}" data-mchat-message="{mchatrow.MCHAT_MESSAGE_EDIT}" data-mchat-message-time="{mchatrow.MCHAT_MESSAGE_TIME}" data-mchat-edit-delete-limit="1" >
  • + + diff --git a/styles/prosilver/template/mchat_messages_icons.html b/styles/prosilver/template/mchat_messages_icons.html index 3e2db71..ca18f21 100644 --- a/styles/prosilver/template/mchat_messages_icons.html +++ b/styles/prosilver/template/mchat_messages_icons.html @@ -1,20 +1,20 @@ - - - + + + - + -
      -
    • {L_MCHAT_RESPOND}
    • -
    • {L_REPLY_WITH_QUOTE}
    • -
    • {L_MCHAT_LIKE}
    • -
    • {L_MCHAT_SEND_PM}
    • -
    • {mchatrow.MCHAT_WHOIS_USER}
    • -
    • {L_MCHAT_PERMISSIONS}
    • -
    • {L_MCHAT_EDIT}
    • -
    • {L_DELETE}
    • + diff --git a/styles/prosilver/template/mchat_navlink.html b/styles/prosilver/template/mchat_navlink.html index 462589b..b097aa1 100644 --- a/styles/prosilver/template/mchat_navlink.html +++ b/styles/prosilver/template/mchat_navlink.html @@ -1,5 +1,5 @@
    • class="small-icon icon-mchat"data-last-responsive="true"> - - class="icon fa fa-weixin" aria-hidden="true">{L_MCHAT_TITLE} + + class="icon fa fa-weixin" aria-hidden="true">{MCHAT_TITLE}
    • diff --git a/styles/prosilver/template/mchat_panel.html b/styles/prosilver/template/mchat_panel.html index a1ac411..4fc4005 100644 --- a/styles/prosilver/template/mchat_panel.html +++ b/styles/prosilver/template/mchat_panel.html @@ -4,7 +4,7 @@ -
      {MCHAT_CHARACTER_COUNT}
      +
      @@ -15,29 +15,31 @@ - + - +
      + - + - + - + - + - +
      +
      @@ -55,16 +57,20 @@
      -
      - - - - -
      - {MCHAT_REFRESH_YES} - {MCHAT_SESSION_TIMELEFT} - - © +
      diff --git a/styles/prosilver/template/mchat_whois.html b/styles/prosilver/template/mchat_whois.html index b5b2567..821073f 100644 --- a/styles/prosilver/template/mchat_whois.html +++ b/styles/prosilver/template/mchat_whois.html @@ -1,9 +1,9 @@
      - {MCHAT_USERS_COUNT} + {MCHAT_USERS_TOTAL} - {MCHAT_USERS_COUNT} + {MCHAT_USERS_TOTAL} diff --git a/styles/prosilver/theme/images/message_icons.png b/styles/prosilver/theme/images/message_icons_black.png similarity index 100% rename from styles/prosilver/theme/images/message_icons.png rename to styles/prosilver/theme/images/message_icons_black.png diff --git a/styles/black/theme/images/message_icons.png b/styles/prosilver/theme/images/message_icons_white.png similarity index 100% rename from styles/black/theme/images/message_icons.png rename to styles/prosilver/theme/images/message_icons_white.png diff --git a/styles/prosilver/theme/mchat.css b/styles/prosilver/theme/mchat.css index 4f7a480..07d8a2c 100644 --- a/styles/prosilver/theme/mchat.css +++ b/styles/prosilver/theme/mchat.css @@ -16,6 +16,11 @@ width: 0; } +#mchat-body { + overflow: hidden; + width: 100%; +} + .icon-mchat { background-image: url("./images/icon_mchat.png"); } @@ -24,10 +29,6 @@ display: none; } -#mchat-body { - width: 100% !important; -} - #mchat-confirm textarea { width: 100%; height: 100px; @@ -35,7 +36,6 @@ #mchat-messages { overflow: auto; - width: 100%; } .mchat-message-wrapper { @@ -59,8 +59,17 @@ @media only screen and (max-width: 700px), only screen and (max-device-width: 700px) { + #mchat-body { + overflow: visible; + } + .mchat-buttons > li { - padding: 0 8px !important; + padding: 0 6px !important; + } + + #mchat-input { + width: 95% !important; + margin: 5px 0 !important; } } @@ -69,38 +78,34 @@ display: block; } -.mchat-message .mchat-buttons li { +.mchat-wrapper .mchat-buttons li { opacity: .3; } -.mchat-message:hover .mchat-buttons li { +.mchat-wrapper li:hover .mchat-buttons li { opacity: .6; } -.mchat-message .mchat-buttons li:hover { +.mchat-wrapper li:hover .mchat-buttons li:hover { opacity: 1; } -.mchat-buttons { +.mchat-wrapper .mchat-buttons { float: right; list-style: none; margin-top: 1px; } -.mchat-message-wrapper .mchat-buttons > li { +.mchat-wrapper .mchat-buttons > li { float: left; margin: 0 3px; } -.mchat-button { - margin-left: 3px; -} - -.mchat-button.fa { +.mchat-wrapper .mchat-buttons .fa { font-size: 12pt; } -.mchat-button span { +.mchat-wrapper .mchat-buttons span { display: block; height: 0; overflow: hidden; @@ -108,9 +113,16 @@ width: 1px; } +.mchat-icons-black .mchat-icon:before { + background-image: url("./images/message_icons_black.png"); +} + +.mchat-icons-white .mchat-icon:before { + background-image: url("./images/message_icons_white.png"); +} + .mchat-icon:before { content: ''; - background-image: url("./images/message_icons.png"); background-repeat: no-repeat; width: 16px; height: 16px; @@ -118,14 +130,14 @@ float: right; } -.mchat-icon-mention:before { background-position: -2px -2px; } -.mchat-icon-edit:before { background-position: -22px -2px; } -.mchat-icon-pm:before { background-position: -42px -2px; } -.mchat-icon-quote:before { background-position: -62px -2px; } -.mchat-icon-like:before { background-position: -82px -2px; } -.mchat-icon-delete:before { background-position: -102px -2px; } -.mchat-icon-permissions:before { background-position: -122px -2px; } -.mchat-icon-ip:before { background-position: -142px -2px; } +.mchat-icon-mention:before { background-position: -2px -2px; } +.mchat-icon-edit:before { background-position: -22px -2px; } +.mchat-icon-pm:before { background-position: -42px -2px; } +.mchat-icon-quote:before { background-position: -62px -2px; } +.mchat-icon-like:before { background-position: -82px -2px; } +.mchat-icon-delete:before { background-position: -102px -2px; } +.mchat-icon-permissions:before { background-position: -122px -2px; } +.mchat-icon-ip:before { background-position: -142px -2px; } .mchat-text { clear: both; @@ -134,6 +146,10 @@ font-size: 1.2em; } +.mchat-notification-message .mchat-text { + font-style: italic; +} + .mchat-text strong { font-weight: bold !important; } @@ -160,12 +176,8 @@ list-style-type: circle; } -.mchat-text blockquote { - margin-bottom: 5px; -} - .mchat-text blockquote, .mchat-text .codebox, .mchat-text ul, .mchat-text ol { - margin-top: 5px; + margin-bottom: 5px; margin-left: 1em; } @@ -185,10 +197,13 @@ #mchat-character-count { float: right; - visibility: hidden; padding: 5px 0 0; } +#mchat-character-count.hidden { + visibility: hidden; +} + #mchat-panel { text-align: center; max-height: initial; @@ -205,11 +220,17 @@ #mchat-input { cursor: text; width: 50%; + min-width: 50%; + max-width: 90%; font-size: 1.1em; padding: 5px 5px 4px; margin: 5px 20px; } +textarea#mchat-input { + height: 8em; +} + #mchat-buttons { padding-bottom: 5px; } @@ -231,6 +252,10 @@ margin: 0 auto 5px; } +#mchat-bbcodes #colour_palette td a.remember-color { + box-shadow: 0 0 0 1px #F00; +} + #mchat-smilies { padding: 0; } @@ -288,6 +313,20 @@ background-image: url("./images/paused.gif"); } +.mchat-footer li { + display: inline; + padding-left: .1em; + white-space: nowrap; +} + +.mchat-footer li:before { + content: '\2022\A'; +} + +.mchat-footer li:first-child:before, .mchat-footer li:last-child:before { + content: ''; +} + #mchat-legend { clear: both; } @@ -342,5 +381,5 @@ } .hidden-category + .forabg #mchat-body .topiclist.forums { - display: block; + display: block; } diff --git a/styles/simplicity/template/mchat_navlink.html b/styles/simplicity/template/mchat_navlink.html index 99a90ef..36ed58b 100644 --- a/styles/simplicity/template/mchat_navlink.html +++ b/styles/simplicity/template/mchat_navlink.html @@ -1 +1 @@ -
    • {L_MCHAT_TITLE}
    • +
    • {MCHAT_TITLE}
    • diff --git a/ucp/ucp_mchat_info.php b/ucp/ucp_mchat_info.php index 51c3178..51da0b5 100644 --- a/ucp/ucp_mchat_info.php +++ b/ucp/ucp_mchat_info.php @@ -24,7 +24,7 @@ class ucp_mchat_info 'modes' => array( 'configuration' => array( 'title' => 'UCP_MCHAT_CONFIG', - 'auth' => 'ext_dmzx/mchat && acl_u_mchat_use', + 'auth' => 'ext_dmzx/mchat && acl_u_mchat_view', 'cat' => array('UCP_MCHAT_CONFIG'), ), ), diff --git a/ucp/ucp_mchat_module.php b/ucp/ucp_mchat_module.php index f6a1bb1..2166029 100644 --- a/ucp/ucp_mchat_module.php +++ b/ucp/ucp_mchat_module.php @@ -24,7 +24,7 @@ class ucp_mchat_module // Set template $this->tpl_name = 'ucp_mchat'; - $this->page_title = 'UCP_PROFILE_MCHAT'; + $this->page_title = 'UCP_MCHAT_CONFIG'; // Get an instance of the UCP controller and display the options $controller = $phpbb_container->get('dmzx.mchat.ucp.controller');