diff --git a/api/backlog/index.php b/api/backlog/index.php index 25cd8b1398af622ef3ef93ca235cd096b14a60a7..cc397ee28a0c967cc9c08b13a087cd8779372205 100644 --- a/api/backlog/index.php +++ b/api/backlog/index.php @@ -3,9 +3,9 @@ namespace QuasselRestSearch; require_once '../../qrs_config.php'; -require_once '../../backend/Database.php'; -require_once '../../backend/helper/RendererHelper.php'; -require_once '../../backend/helper/SessionHelper.php'; +require_once '../../database/Database.php'; +require_once '../../database/helper/RendererHelper.php'; +require_once '../../database/helper/SessionHelper.php'; $config = Config::createFromGlobals(); $renderer = new RendererHelper($config); diff --git a/api/search/index.php b/api/search/index.php index 9d3fccc15c175f2c03904646a22bb8eedf674642..1c58235f9b1b1ef17797afbcb9b274a70927a555 100644 --- a/api/search/index.php +++ b/api/search/index.php @@ -3,9 +3,9 @@ namespace QuasselRestSearch; require_once '../../qrs_config.php'; -require_once '../../backend/Database.php'; -require_once '../../backend/helper/RendererHelper.php'; -require_once '../../backend/helper/SessionHelper.php'; +require_once '../../database/Database.php'; +require_once '../../database/helper/RendererHelper.php'; +require_once '../../database/helper/SessionHelper.php'; $config = Config::createFromGlobals(); $renderer = new RendererHelper($config); @@ -13,7 +13,7 @@ $backend = Database::createFromConfig($config); try { $backend->authenticateFromHeader($_SERVER['HTTP_AUTHORIZATION'] ?: ""); - $renderer->renderJson($backend->findBuffers($_REQUEST['query'] ?: "", $_REQUEST['since'] ?: null, $_REQUEST['before'] ?: null, $_REQUEST['buffer'] ?: null, $_REQUEST['network'] ?: null)); + $renderer->renderJson($backend->find($_REQUEST['query'] ?: "", $_REQUEST['since'] ?: null, $_REQUEST['before'] ?: null, $_REQUEST['buffer'] ?: null, $_REQUEST['network'] ?: null, $_REQUEST['sender'] ?: null, $_REQUEST['limit'] ?: null)); } catch (\Exception $e) { $renderer->renderJson(["error" => $e->getMessage()]); } \ No newline at end of file diff --git a/api/searchbuffer/index.php b/api/searchbuffer/index.php index 73b119ebfdd4bab112a1753720a67152acdd1f96..9d2f626dbf1763c739500f6aa5badc823f8ddaa9 100644 --- a/api/searchbuffer/index.php +++ b/api/searchbuffer/index.php @@ -3,9 +3,9 @@ namespace QuasselRestSearch; require_once '../../qrs_config.php'; -require_once '../../backend/Database.php'; -require_once '../../backend/helper/RendererHelper.php'; -require_once '../../backend/helper/SessionHelper.php'; +require_once '../../database/Database.php'; +require_once '../../database/helper/RendererHelper.php'; +require_once '../../database/helper/SessionHelper.php'; $config = Config::createFromGlobals(); $renderer = new RendererHelper($config); diff --git a/api/searchbuffers/index.php b/api/searchbuffers/index.php deleted file mode 100644 index 11f14a2437d93310d350807e35d05feb95f8912d..0000000000000000000000000000000000000000 --- a/api/searchbuffers/index.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php - -namespace QuasselRestSearch; - -require_once '../../qrs_config.php'; -require_once '../../backend/Database.php'; -require_once '../../backend/helper/RendererHelper.php'; -require_once '../../backend/helper/SessionHelper.php'; - -$config = Config::createFromGlobals(); -$renderer = new RendererHelper($config); -$backend = Database::createFromConfig($config); - -try { - $backend->authenticateFromHeader($_SERVER['HTTP_AUTHORIZATION'] ?: ""); - $renderer->renderJson($backend->findInBufferMultiple($_REQUEST['q'] ?: "", $_REQUEST['since'] ?: null, $_REQUEST['before'] ?: null, $_REQUEST['limit'] ?: 4)); -} catch (\Exception $e) { - $renderer->renderJson(["error" => $e->getMessage()]); -} \ No newline at end of file diff --git a/backend/Config.php b/backend/Config.php deleted file mode 100644 index 4d466df4d64dc6d6c6689833eda469af6d11fe51..0000000000000000000000000000000000000000 --- a/backend/Config.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -namespace QuasselRestSearch; - - -class Config { - public $database_connector; - public $username; - public $password; - - public $path_prefix; - - public function __construct(string $path_prefix, string $database_connector, string $username, string $password) { - $this->database_connector = $database_connector; - $this->username = $username; - $this->password = $password; - $this->path_prefix = $path_prefix; - } - - public static function createFromGlobals() { - if (defined(db_connector) && null !== db_connector) - return new Config(path_prefix, db_connector, db_user, db_pass); - else - return new Config(path_prefix, 'pgsql:host=' . db_host . ';port=' . db_port . ';dbname=' . db_name . '', db_user, db_pass); - } -} diff --git a/backend/Database.php b/backend/Database.php deleted file mode 100644 index 1fc2024be1c987ce56c001e46702a66dc06d115c..0000000000000000000000000000000000000000 --- a/backend/Database.php +++ /dev/null @@ -1,285 +0,0 @@ -<?php - -namespace QuasselRestSearch; - -use PDO; - -require_once 'User.php'; -require_once 'Config.php'; -require_once 'helper/AuthHelper.php'; - -class Database { - private $storedFindBuffers; - private $storedFindInBuffer; - private $loadBefore; - private $loadAfter; - - private $findUser; - - private $user; - - private function __construct(string $database_connector, string $username, string $password) { - $db = new \PDO($database_connector, $username, $password); - - $this->storedFindBuffers = $db->prepare(" - SELECT backlog.bufferid, - buffer.buffername, - network.networkname - FROM backlog - JOIN buffer ON backlog.bufferid = buffer.bufferid - JOIN network ON buffer.networkid = network.networkid, - phraseto_tsquery_multilang(:query) query - WHERE (backlog.type & 23559) > 0 - AND buffer.userid = :userid - AND (NOT(:_since) OR backlog.time > to_timestamp(:since)) - AND (NOT(:_before) OR backlog.time < to_timestamp(:before)) - AND (NOT(:_network) OR network.networkname ILIKE :network) - AND (NOT(:_buffer) OR buffer.buffername ILIKE :buffer) - AND backlog.tsv @@ query - GROUP BY backlog.bufferid, - buffer.buffername, - network.networkname - ORDER BY MIN((1 + log(GREATEST(1::DOUBLE PRECISION, EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - TIME))))) * (1 - ts_rank(tsv, query, 32)) * (1 + ln(backlog.type))) ASC; - "); - $this->storedFindInBufferMultiple = $db->prepare(" - SELECT tmp.bufferid, - tmp.messageid, - sender.sender, - tmp.time, - replace(replace(tmp.message, '<', '<'), '>', '>') AS message, - ts_headline(replace(replace(tmp.message, '<', '<'), '>', '>'), query) AS preview - FROM - (SELECT backlog.messageid, - backlog.bufferid, - backlog.senderid, - backlog.time, - backlog.message, - query, - rank() OVER(PARTITION BY backlog.bufferid - ORDER BY (1 + log(GREATEST(1, EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - TIME))))) * (1 - ts_rank(tsv, query, 32)) * (1 + ln(backlog.type)) ASC - ) AS rank - FROM backlog - JOIN buffer ON backlog.bufferid = buffer.bufferid, - phraseto_tsquery_multilang(:query) query - WHERE (backlog.type & 23559) > 0 - AND (NOT(:_since) OR backlog.time > to_timestamp(:since)) - AND (NOT(:_before) OR backlog.time < to_timestamp(:before)) - AND buffer.userid = :userid - AND backlog.tsv @@ query - ORDER BY (1 + log(GREATEST(1, EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - TIME))))) * (1 - ts_rank(tsv, query, 32)) * (1 + ln(backlog.type)) ASC - ) tmp - JOIN sender ON tmp.senderid = sender.senderid - WHERE tmp.rank <= :limit; - "); - $this->storedFindInBuffer = $db->prepare(" - SELECT backlog.messageid, - sender.sender, - backlog.time, - replace(replace(backlog.message, '<', '<'), '>', '>') AS message, - ts_headline(replace(replace(backlog.message, '<', '<'), '>', '>'), query) AS preview - FROM backlog - JOIN sender ON backlog.senderid = sender.senderid - JOIN buffer ON backlog.bufferid = buffer.bufferid, - phraseto_tsquery_multilang(:query) query - WHERE (backlog.type & 23559) > 0 - AND (NOT(:_since) OR backlog.time > to_timestamp(:since)) - AND (NOT(:_before) OR backlog.time < to_timestamp(:before)) - AND buffer.userid = :userid - AND backlog.bufferid = :bufferid - AND backlog.tsv @@ query - ORDER BY (1 + log(GREATEST(1, EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - TIME))))) * (1 - ts_rank(tsv, query, 32)) * ( 1 + ln(backlog.type)) ASC - LIMIT :limit OFFSET :offset; - "); - $this->loadAfter = $db->prepare(" - SELECT backlog.messageid, - backlog.bufferid, - buffer.buffername, - sender.sender, - backlog.time, - network.networkname, - replace(replace(backlog.message, '<', '<'), '>', '>') AS message - FROM backlog - JOIN sender ON backlog.senderid = sender.senderid - JOIN buffer ON backlog.bufferid = buffer.bufferid - JOIN network ON buffer.networkid = network.networkid - WHERE buffer.userid = :userid - AND backlog.bufferid = :bufferid - AND backlog.messageid >= :anchor - ORDER BY backlog.messageid ASC - LIMIT :limit; - "); - $this->loadBefore = $db->prepare(" - SELECT backlog.messageid, - backlog.bufferid, - buffer.buffername, - sender.sender, - backlog.time, - network.networkname, - replace(replace(backlog.message, '<', '<'), '>', '>') AS message - FROM backlog - JOIN sender ON backlog.senderid = sender.senderid - JOIN buffer ON backlog.bufferid = buffer.bufferid - JOIN network ON buffer.networkid = network.networkid - WHERE buffer.userid = :userid - AND backlog.bufferid = :bufferid - AND backlog.messageid < :anchor - ORDER BY backlog.messageid DESC - LIMIT :limit; - "); - $this->findUser = $db->prepare(" - SELECT * - FROM quasseluser - WHERE quasseluser.username = :username - "); - } - - public static function createFromOptions(string $database_connector, string $username, string $password) : Database { - return new Database($database_connector, $username, $password); - } - - public static function createFromConfig(Config $config) : Database { - return new Database($config->database_connector, $config->username, $config->password); - } - - public function authenticateFromHeader(string $header) : bool { - $parsedHeader = AuthHelper::parseAuthHeader($header); - return $this->authenticate($parsedHeader['username'], $parsedHeader['password']); - } - - public function authenticate(string $username, string $password) : bool { - if (!isset($username) || !isset($password)) { - syslog(LOG_ERR, "Username or password not set"); - return false; - } - - $this->findUser->bindParam(":username", $username); - $this->findUser->execute(); - - $result = $this->findUser->fetch(\PDO::FETCH_ASSOC); - if ($result === FALSE) { - syslog(LOG_ERR, "Couldn’t find user " . $username); - return false; - } - - $user = new User($result); - - if (!AuthHelper::initialAuthenticateUser($password, $user->password, $user->hashversion)) { - syslog(LOG_ERR, "Password does not match for user " . $username); - return false; - } - - $this->user = $user; - return true; - } - - public function find(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null, int $limitPerBuffer = 4) : array { - $truncatedLimit = max(min($limitPerBuffer, 10), 0); - $truncatedLimit = 20; - - $buffers = $this->findBuffers($query, $since, $before, $buffer, $network); - $messages = $this->findInBufferMultiple($query, $since, $before, $truncatedLimit); - - $buffermap = []; - foreach ($buffers as &$buffer) { - $buffer['messages'] = []; - $buffermap[$buffer['bufferid']] = &$buffer; - } - - foreach ($messages as $message) { - if (!is_null($buffermap[$message['bufferid']])) - array_push($buffermap[$message['bufferid']]['messages'], $message); - } - - return array_values($buffermap); - } - - public function findBuffers(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null) : array { - $_since = $since!==null; - $_before = $before!==null; - $_buffer = $buffer!==null; - $_network = $network!==null; - - $this->storedFindBuffers->bindParam(':userid', $this->user->userid); - $this->storedFindBuffers->bindParam(':query', $query); - - $this->storedFindBuffers->bindValue(':since', $_since ? (int) $since : 0, PDO::PARAM_INT); - $this->storedFindBuffers->bindValue(':before', $_before ? (int) $before : 0, PDO::PARAM_INT); - $this->storedFindBuffers->bindValue(':buffer', $_buffer ? (string) $buffer : ""); - $this->storedFindBuffers->bindValue(':network', $_network ? (string) $network : ""); - $this->storedFindBuffers->bindParam(':_since', $_since, PDO::PARAM_INT); - $this->storedFindBuffers->bindParam(':_before', $_before, PDO::PARAM_INT); - $this->storedFindBuffers->bindParam(':_buffer', $_buffer, PDO::PARAM_INT); - $this->storedFindBuffers->bindParam(':_network', $_network, PDO::PARAM_INT); - - $this->storedFindBuffers->execute(); - return $this->storedFindBuffers->fetchAll(\PDO::FETCH_ASSOC); - } - - public function findInBufferMultiple(string $query, int $since = null, int $before = null, int $limit = 4) : array { - $_since = $since!==null; - $_before = $before!==null; - - $this->storedFindInBufferMultiple->bindParam(':userid', $this->user->userid); - $this->storedFindInBufferMultiple->bindParam(':query', $query); - $this->storedFindInBufferMultiple->bindParam(':limit', $limit); - - $this->storedFindInBufferMultiple->bindValue(':since', $_since ? (int) $since : 0, PDO::PARAM_INT); - $this->storedFindInBufferMultiple->bindValue(':before', $_before ? (int) $before : 0, PDO::PARAM_INT); - $this->storedFindInBufferMultiple->bindParam(':_since', $_since, PDO::PARAM_INT); - $this->storedFindInBufferMultiple->bindParam(':_before', $_before, PDO::PARAM_INT); - - $this->storedFindInBufferMultiple->execute(); - return $this->storedFindInBufferMultiple->fetchAll(\PDO::FETCH_ASSOC); - } - - public function findInBuffer(string $query, int $since = null, int $before = null, int $bufferid, int $offset = 0, int $limit = 20) : array { - $truncatedLimit = max(min($limit, 50), 0); - $_since = $since!==null; - $_before = $before!==null; - - $this->storedFindInBuffer->bindParam(':userid', $this->user->userid); - $this->storedFindInBuffer->bindParam(':bufferid', $bufferid); - $this->storedFindInBuffer->bindParam(':query', $query); - - $this->storedFindInBuffer->bindValue(':since', $_since ? (int) $since : 0, PDO::PARAM_INT); - $this->storedFindInBuffer->bindValue(':before', $_before ? (int) $before : 0, PDO::PARAM_INT); - $this->storedFindInBuffer->bindParam(':_since', $_since, PDO::PARAM_INT); - $this->storedFindInBuffer->bindParam(':_before', $_before, PDO::PARAM_INT); - - $this->storedFindInBuffer->bindParam(':limit', $truncatedLimit); - $this->storedFindInBuffer->bindParam(':offset', $offset); - - $this->storedFindInBuffer->execute(); - return $this->storedFindInBuffer->fetchAll(\PDO::FETCH_ASSOC); - } - - public function context(int $anchor, int $buffer, int $loadBefore, int $loadAfter) : array { - return array_merge(array_reverse($this->before($anchor, $buffer, $loadBefore)), $this->after($anchor, $buffer, $loadAfter)); - } - - public function before(int $anchor, int $buffer, int $limit) : array { - $truncatedLimit = max(min($limit, 50), 0); - - $this->loadBefore->bindParam(":userid", $this->user->userid); - $this->loadBefore->bindParam(":bufferid", $buffer); - $this->loadBefore->bindParam(":anchor", $anchor); - - $this->loadBefore->bindParam(":limit", $truncatedLimit); - - $this->loadBefore->execute(); - return $this->loadBefore->fetchAll(\PDO::FETCH_ASSOC); - } - - public function after(int $anchor, int $buffer, int $limit) : array { - $truncatedLimit = max(min($limit + 1, 50), 1); - - $this->loadAfter->bindParam(":userid", $this->user->userid); - $this->loadAfter->bindParam(":bufferid", $buffer); - $this->loadAfter->bindParam(":anchor", $anchor); - - $this->loadAfter->bindParam(":limit", $truncatedLimit); - - $this->loadAfter->execute(); - return $this->loadAfter->fetchAll(\PDO::FETCH_ASSOC); - } -} \ No newline at end of file diff --git a/database/Config.php b/database/Config.php new file mode 100644 index 0000000000000000000000000000000000000000..bb9bdb8ff3979710aacc5edd5519149bb5c7974c --- /dev/null +++ b/database/Config.php @@ -0,0 +1,32 @@ +<?php + +namespace QuasselRestSearch; + + +class Config +{ + public $database_connector; + public $username; + public $password; + + public $backend; + + public $path_prefix; + + public function __construct(string $path_prefix, string $database_connector, string $username, string $password, string $backend) + { + $this->database_connector = $database_connector; + $this->username = $username; + $this->password = $password; + $this->path_prefix = $path_prefix; + $this->backend = $backend; + } + + public static function createFromGlobals() + { + if (defined(qrs_db_connector) && null !== qrs_db_connector) + return new Config(qrs_path_prefix, qrs_db_connector, qrs_db_user, qrs_db_pass, qrs_backend); + else + return new Config(qrs_path_prefix, 'pgsql:host=' . qrs_db_host . ';port=' . qrs_db_port . ';dbname=' . qrs_db_name . '', qrs_db_user, qrs_db_pass, qrs_backend); + } +} diff --git a/database/Database.php b/database/Database.php new file mode 100644 index 0000000000000000000000000000000000000000..6d0100f36237f904732d87c8c2db5790de5fb6e8 --- /dev/null +++ b/database/Database.php @@ -0,0 +1,266 @@ +<?php + +namespace QuasselRestSearch; + +use PDO; + +require_once 'User.php'; +require_once 'Config.php'; +require_once 'helper/AuthHelper.php'; +require_once 'backends/BackendFactory.php'; + +class Database +{ + private $user; + + private $backend; + + private function __construct(string $database_connector, string $username, string $password, string $type) + { + $this->backend = BackendFactory::create($type, new \PDO($database_connector, $username, $password)); + } + + public static function createFromConfig(Config $config): Database + { + return Database::createFromOptions($config->database_connector, $config->username, $config->password, $config->backend); + } + + public static function createFromOptions(string $database_connector, string $username, string $password, string $type): Database + { + return new Database($database_connector, $username, $password, $type); + } + + public function authenticateFromHeader(string $header): bool + { + $parsedHeader = AuthHelper::parseAuthHeader($header); + return $this->authenticate($parsedHeader['username'], $parsedHeader['password']); + } + + public function authenticate(string $username, string $password): bool + { + if (!isset($username) || !isset($password)) { + syslog(LOG_ERR, "Username or password not set"); + return false; + } + + $stmt = $this->backend->findUser(); + + $stmt->bindParam(":username", $username); + $stmt->execute(); + $result = $stmt->fetch(\PDO::FETCH_ASSOC); + + if ($result === FALSE) { + syslog(LOG_ERR, "Couldn’t find user " . $username); + return false; + } + + $user = new User($result); + + if (!AuthHelper::initialAuthenticateUser($password, $user->password, $user->hashversion)) { + syslog(LOG_ERR, "Password does not match for user " . $username); + return false; + } + + $this->user = $user; + return true; + } + + private function apply_config(\PDOStatement $stmt) + { + $stmt->bindValue(':config_normalization', 0, PDO::PARAM_INT); + + $stmt->bindValue(':weight_content', 1, PDO::PARAM_INT); + $stmt->bindValue(':weight_type', 1, PDO::PARAM_INT); + $stmt->bindValue(':weight_time', 12, PDO::PARAM_INT); + } + + public function find(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null, string $sender = null, int $limitPerBuffer = 4): array + { + $truncatedLimit = max(min($limitPerBuffer, 10), 0); + $truncatedLimit = 20; + + $messages = $this->findInBufferMultiple($query, $since, $before, $buffer, $network, $sender, $truncatedLimit); + $hasMore = $this->findInBufferMultipleCount($query, $since, $before, $buffer, $network, $sender, 0, $truncatedLimit); + + $buffermap = []; + + foreach ($messages as $message) { + if (!array_key_exists($message['bufferid'], $buffermap)) { + $buffermap[$message['bufferid']] = [ + "bufferid" => $message['bufferid'], + "buffername" => $message['buffername'], + "networkname" => $message['networkname'], + "messages" => [] + ]; + } + + array_push($buffermap[$message['bufferid']]['messages'], $message); + } + + foreach ($hasMore as $hasMoreResult) { + if (!is_null($buffermap[$hasMoreResult['bufferid']])) + $buffermap[$hasMoreResult['bufferid']]['hasmore'] = $hasMoreResult['hasmore']; + } + + return array_values($buffermap); + } + + public function findInBufferMultiple(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null, string $sender = null, int $limit = 4): array + { + $ignore_since = $since === null; + $ignore_before = $before === null; + $ignore_network = $network === null; + $ignore_buffer = $buffer === null; + $ignore_sender = $sender === null; + + $stmt = $this->backend->findInBuffers(); + $this->apply_config($stmt); + + $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT); + $stmt->bindParam(':query', $query, PDO::PARAM_STR); + $stmt->bindParam(':limit', $limit, PDO::PARAM_INT); + + $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':buffer', !$ignore_buffer ? (string)$buffer : "", PDO::PARAM_STR); + $stmt->bindValue(':network', !$ignore_network ? (string)$network : "", PDO::PARAM_STR); + $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR); + $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT); + $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT); + $stmt->bindParam(':ignore_buffer', $ignore_network, PDO::PARAM_INT); + $stmt->bindParam(':ignore_network', $ignore_buffer, PDO::PARAM_INT); + $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT); + + $stmt->execute(); + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } + + public function findInBufferMultipleCount(string $query, int $since = null, int $before = null, string $buffer = null, string $network = null, string $sender = null, int $offset = 0, int $limit = 4): array + { + $truncatedLimit = max(min($limit, 50), 0); + $ignore_since = $since === null; + $ignore_before = $before === null; + $ignore_network = $network === null; + $ignore_buffer = $buffer === null; + $ignore_sender = $sender === null; + + $stmt = $this->backend->findInBuffersCount(); + + $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT); + $stmt->bindParam(':query', $query, PDO::PARAM_STR); + + $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':buffer', !$ignore_buffer ? (string)$buffer : "", PDO::PARAM_STR); + $stmt->bindValue(':network', !$ignore_network ? (string)$network : "", PDO::PARAM_STR); + $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR); + $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT); + $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT); + $stmt->bindParam(':ignore_buffer', $ignore_network, PDO::PARAM_INT); + $stmt->bindParam(':ignore_network', $ignore_buffer, PDO::PARAM_INT); + $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT); + + $stmt->bindParam(':limit', $truncatedLimit, PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + + $success = $stmt->execute(); + $result = $stmt->fetchAll(\PDO::FETCH_ASSOC); + + return $result; + } + + public function findInBuffer(string $query, int $since = null, int $before = null, string $sender = null, int $bufferid, int $offset = 0, int $limit = 20): array + { + $truncatedLimit = max(min($limit, 50), 0); + $ignore_since = $since === null; + $ignore_before = $before === null; + $ignore_sender = $sender === null; + + $stmt = $this->backend->findInBuffer(); + $this->apply_config($stmt); + + $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT); + $stmt->bindParam(':bufferid', $bufferid, PDO::PARAM_INT); + $stmt->bindParam(':query', $query, PDO::PARAM_STR); + + $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR); + $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT); + $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT); + $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT); + + $stmt->bindParam(':limit', $truncatedLimit, PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + + $stmt->execute(); + return [ + 'results' => $stmt->fetchAll(\PDO::FETCH_ASSOC), + 'hasmore' => $this->findInBufferCount($query, $since, $before, $bufferid, $offset, $limit) + ]; + } + + public function findInBufferCount(string $query, int $since = null, int $before = null, string $sender = null, int $bufferid, int $offset = 0, int $limit = 4): array + { + $truncatedLimit = max(min($limit, 50), 0); + $ignore_since = $since === null; + $ignore_before = $before === null; + $ignore_sender = $sender === null; + + $stmt = $this->backend->findInBufferCount(); + + $stmt->bindParam(':userid', $this->user->userid, PDO::PARAM_INT); + $stmt->bindParam(':bufferid', $bufferid, PDO::PARAM_INT); + $stmt->bindParam(':query', $query, PDO::PARAM_STR); + + $stmt->bindValue(':since', !$ignore_since ? (string)$since : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':before', !$ignore_before ? (string)$before : "1970-01-01", PDO::PARAM_STR); + $stmt->bindValue(':sender', !$ignore_sender ? (string)$sender : "", PDO::PARAM_STR); + $stmt->bindParam(':ignore_since', $ignore_since, PDO::PARAM_INT); + $stmt->bindParam(':ignore_before', $ignore_before, PDO::PARAM_INT); + $stmt->bindParam(':ignore_sender', $ignore_sender, PDO::PARAM_INT); + + $stmt->bindParam(':limit', $truncatedLimit, PDO::PARAM_INT); + $stmt->bindParam(':offset', $offset, PDO::PARAM_INT); + + $stmt->execute(); + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } + + public function context(int $anchor, int $buffer, int $loadBefore, int $loadAfter): array + { + return array_merge(array_reverse($this->before($anchor, $buffer, $loadBefore)), $this->after($anchor, $buffer, $loadAfter)); + } + + public function before(int $anchor, int $buffer, int $limit): array + { + $truncatedLimit = max(min($limit, 50), 0); + + $stmt = $this->backend->loadBefore(); + + $stmt->bindParam(":userid", $this->user->userid, PDO::PARAM_INT); + $stmt->bindParam(":bufferid", $buffer, PDO::PARAM_INT); + $stmt->bindParam(":anchor", $anchor, PDO::PARAM_INT); + + $stmt->bindParam(":limit", $truncatedLimit, PDO::PARAM_INT); + + $stmt->execute(); + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } + + public function after(int $anchor, int $buffer, int $limit): array + { + $truncatedLimit = max(min($limit + 1, 50), 1); + + $stmt = $this->backend->loadAfter(); + + $stmt->bindParam(":userid", $this->user->userid, PDO::PARAM_INT); + $stmt->bindParam(":bufferid", $buffer, PDO::PARAM_INT); + $stmt->bindParam(":anchor", $anchor, PDO::PARAM_INT); + + $stmt->bindParam(":limit", $truncatedLimit, PDO::PARAM_INT); + + $stmt->execute(); + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } +} \ No newline at end of file diff --git a/backend/User.php b/database/User.php similarity index 83% rename from backend/User.php rename to database/User.php index 5d0d93a97e6401f841497d09fda9c54acaebbc0a..8afdabe965f46ba515d1a6e9a6abad5d29ce2180 100644 --- a/backend/User.php +++ b/database/User.php @@ -3,13 +3,15 @@ namespace QuasselRestSearch; -class User { +class User +{ public $userid; public $username; public $password; public $hashversion; - public function __construct(array $userArray) { + public function __construct(array $userArray) + { $this->userid = $userArray['userid']; $this->username = $userArray['username']; $this->password = $userArray['password']; diff --git a/database/backends/Backend.php b/database/backends/Backend.php new file mode 100644 index 0000000000000000000000000000000000000000..26656ca95975316b57ea0f4d5855b9814a119bca --- /dev/null +++ b/database/backends/Backend.php @@ -0,0 +1,20 @@ +<?php + +namespace QuasselRestSearch; + +interface Backend +{ + public function findUser(): \PDOStatement; + + public function findInBuffers(): \PDOStatement; + + public function findInBuffersCount(): \PDOStatement; + + public function findInBuffer(): \PDOStatement; + + public function findInBufferCount(): \PDOStatement; + + public function loadAfter(): \PDOStatement; + + public function loadBefore(): \PDOStatement; +} \ No newline at end of file diff --git a/database/backends/BackendFactory.php b/database/backends/BackendFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..d2d56406d06108b994bdeb60e16964ea81bdbf4a --- /dev/null +++ b/database/backends/BackendFactory.php @@ -0,0 +1,22 @@ +<?php + +namespace QuasselRestSearch; + +require_once 'PostgresSmartBackend.php'; +require_once 'SQLiteSmartBackend.php'; + +class BackendFactory +{ + + public static function create(string $type, \PDO $db): Backend + { + switch ($type) { + case 'pgsql-smart': + return new PostgresSmartBackend($db); + case 'sqlite-smart': + return new SQLiteSmartBackend($db); + default: + return null; + } + } +} \ No newline at end of file diff --git a/database/backends/PostgresSmartBackend.php b/database/backends/PostgresSmartBackend.php new file mode 100644 index 0000000000000000000000000000000000000000..852ad5651cc0157b7dbd0469b9c2415b749e0c95 --- /dev/null +++ b/database/backends/PostgresSmartBackend.php @@ -0,0 +1,207 @@ +<?php + +namespace QuasselRestSearch; + +require_once 'Backend.php'; + +class PostgresSmartBackend implements Backend +{ + private $db; + + function __construct(\PDO $db) + { + $this->db = $db; + $this->db->exec("SET statement_timeout = 5000;"); + } + + public function findUser(): \PDOStatement + { + return $this->db->prepare(" + SELECT * + FROM quasseluser + WHERE quasseluser.username = :username + "); + } + + public function findInBuffers(): \PDOStatement + { + return $this->db->prepare(" + SELECT + tmp.bufferid, + tmp.buffername, + network.networkname, + tmp.messageid, + sender.sender, + tmp.time, + replace(replace(tmp.message, '<', '<'), '>', '>') AS message, + ts_headline(replace(replace(tmp.message, '<', '<'), '>', '>'), query) AS preview + FROM + (SELECT + backlog.messageid, + backlog.bufferid, + buffer.buffername, + buffer.networkid, + backlog.senderid, + backlog.time, + backlog.message, + query, + rank() OVER ( + PARTITION BY backlog.bufferid + ORDER BY ( + (ts_rank(tsv, query, :config_normalization) ^ :weight_content) * + ((CASE + WHEN type IN (1, 4) THEN 1.0 + WHEN type IN (2, 1024, 2048, 4096, 16384) THEN 0.75 + WHEN type IN (32, 64, 128, 256, 512, 32768, 65536) THEN 0.5 + WHEN type IN (8, 16, 8192, 131072) THEN 0.25 + ELSE 0.1 END) ^ :weight_type) * + ((EXTRACT(EPOCH FROM time) / EXTRACT(EPOCH FROM CURRENT_TIMESTAMP)) ^ :weight_time) + ) DESC + ) AS rank + FROM backlog + JOIN buffer ON backlog.bufferid = buffer.bufferid, + phraseto_tsquery_multilang(:query) query + WHERE buffer.userid = :userid + AND (:ignore_since::BOOLEAN OR backlog.time > :since::TIMESTAMP) + AND (:ignore_before::BOOLEAN OR backlog.time < :before::TIMESTAMP) + AND (:ignore_buffer::BOOLEAN OR buffer.buffername ~* :buffer) + AND backlog.tsv @@ query AND backlog.type & 23559 > 0 + ) tmp + JOIN sender ON tmp.senderid = sender.senderid + JOIN network ON tmp.networkid = network.networkid + WHERE tmp.rank <= :limit + AND (:ignore_network::BOOLEAN OR network.networkname ~* :network) + AND (:ignore_sender::BOOLEAN OR sender.sender ~* :sender); + "); + } + + public function findInBuffersCount(): \PDOStatement + { + return $this->db->prepare(" + SELECT + backlog.bufferid, + COUNT(backlog.messageid) > (:limit::INT + :offset::INT) AS hasmore + FROM backlog + JOIN buffer ON backlog.bufferid = buffer.bufferid + JOIN sender ON backlog.senderid = sender.senderid + JOIN network ON buffer.networkid = network.networkid, + phraseto_tsquery_multilang(:query) query + WHERE buffer.userid = :userid + AND (:ignore_since::BOOLEAN OR backlog.time > :since::TIMESTAMP) + AND (:ignore_before::BOOLEAN OR backlog.time < :before::TIMESTAMP) + AND (:ignore_buffer::BOOLEAN OR buffer.buffername ~* :buffer) + AND (:ignore_network::BOOLEAN OR network.networkname ~* :network) + AND (:ignore_sender::BOOLEAN OR sender.sender ~* :sender) + AND backlog.tsv @@ query AND backlog.type & 23559 > 0 + GROUP BY backlog.bufferid; + "); + } + + public function findInBuffer(): \PDOStatement + { + return $this->db->prepare(" + SELECT + tmp.bufferid, + tmp.messageid, + sender.sender, + tmp.time, + replace(replace(tmp.message, '<', '<'), '>', '>') AS message, + ts_headline(replace(replace(tmp.message, '<', '<'), '>', '>'), query) AS preview + FROM + (SELECT + backlog.messageid, + backlog.bufferid, + backlog.senderid, + backlog.time, + backlog.message, + query + FROM backlog + JOIN buffer ON backlog.bufferid = buffer.bufferid, + phraseto_tsquery_multilang(:query) query + WHERE buffer.userid = :userid + AND backlog.bufferid = :bufferid + AND (:ignore_since::BOOLEAN OR backlog.time > :since::TIMESTAMP) + AND (:ignore_before::BOOLEAN OR backlog.time < :before::TIMESTAMP) + AND backlog.tsv @@ query AND backlog.type & 23559 > 0 + ORDER BY ( + (ts_rank(tsv, query, :config_normalization) ^ :weight_content) * + ((CASE + WHEN type IN (1, 4) THEN 1.0 + WHEN type IN (2, 1024, 2048, 4096, 16384) THEN 0.75 + WHEN type IN (32, 64, 128, 256, 512, 32768, 65536) THEN 0.5 + WHEN type IN (8, 16, 8192, 131072) THEN 0.25 + ELSE 0.1 END) ^ :weight_type) * + ((EXTRACT(EPOCH FROM time) / EXTRACT(EPOCH FROM CURRENT_TIMESTAMP)) ^ :weight_time) + ) DESC + ) tmp + JOIN sender ON tmp.senderid = sender.senderid + WHERE (:ignore_sender::BOOLEAN OR sender.sender ~* :sender) + LIMIT :limit + OFFSET :offset; + "); + } + + public function findInBufferCount(): \PDOStatement + { + return $this->db->prepare(" + SELECT + backlog.bufferid, + COUNT(backlog.messageid) > (:limit::INT + :offset::INT) AS hasmore + FROM backlog + JOIN buffer ON backlog.bufferid = buffer.bufferid + JOIN sender ON backlog.senderid = sender.senderid, + phraseto_tsquery_multilang(:query) query + WHERE buffer.userid = :userid + AND backlog.bufferid = :bufferid + AND (:ignore_since::BOOLEAN OR backlog.time > :since::TIMESTAMP) + AND (:ignore_before::BOOLEAN OR backlog.time < :before::TIMESTAMP) + AND (:ignore_sender::BOOLEAN OR sender.sender ~* :sender) + AND backlog.tsv @@ query AND backlog.type & 23559 > 0 + GROUP BY backlog.bufferid; + "); + } + + public function loadAfter(): \PDOStatement + { + return $this->db->prepare(" + SELECT backlog.messageid, + backlog.bufferid, + buffer.buffername, + sender.sender, + backlog.time, + network.networkname, + replace(replace(replace(backlog.message, '&', '&'), '<', '<'), '>', '>') AS message + FROM backlog + JOIN sender ON backlog.senderid = sender.senderid + JOIN buffer ON backlog.bufferid = buffer.bufferid + JOIN network ON buffer.networkid = network.networkid + WHERE buffer.userid = :userid + AND backlog.bufferid = :bufferid + AND backlog.messageid >= :anchor + ORDER BY backlog.messageid ASC + LIMIT :limit; + "); + } + + public function loadBefore(): \PDOStatement + { + return $this->db->prepare(" + SELECT backlog.messageid, + backlog.bufferid, + buffer.buffername, + sender.sender, + backlog.time, + network.networkname, + replace(replace(replace(backlog.message, '&', '&'), '<', '<'), '>', '>') AS message + FROM backlog + JOIN sender ON backlog.senderid = sender.senderid + JOIN buffer ON backlog.bufferid = buffer.bufferid + JOIN network ON buffer.networkid = network.networkid + WHERE buffer.userid = :userid + AND backlog.bufferid = :bufferid + AND backlog.messageid < :anchor + ORDER BY backlog.messageid DESC + LIMIT :limit; + "); + } +} diff --git a/database/backends/SQLiteSmartBackend.php b/database/backends/SQLiteSmartBackend.php new file mode 100644 index 0000000000000000000000000000000000000000..0d83a467db7484c50d3bf43100452503515c4bab --- /dev/null +++ b/database/backends/SQLiteSmartBackend.php @@ -0,0 +1,88 @@ +<?php + +namespace QuasselRestSearch; + +require_once 'Backend.php'; + +class SQLiteSmartBackend implements Backend +{ + private $db; + + function __construct(\PDO $db) + { + $this->db = $db; + } + + public function findUser(): \PDOStatement + { + return $this->db->prepare(" + SELECT * + FROM quasseluser + WHERE quasseluser.username = :username + "); + } + + public function findInBuffers(): \PDOStatement + { + // TODO: Implement findInBuffers() method. + } + + public function findInBuffersCount(): \PDOStatement + { + // TODO: Implement findInBuffersCount() method. + } + + public function findInBuffer(): \PDOStatement + { + // TODO: Implement findInBuffer() method. + } + + public function findInBufferCount(): \PDOStatement + { + // TODO: Implement findInBufferCount() method. + } + + public function loadAfter(): \PDOStatement + { + return $this->db->prepare(" + SELECT backlog.messageid, + backlog.bufferid, + buffer.buffername, + sender.sender, + backlog.time, + network.networkname, + replace(replace(replace(backlog.message, '&', '&'), '<', '<'), '>', '>') AS message + FROM backlog + JOIN sender ON backlog.senderid = sender.senderid + JOIN buffer ON backlog.bufferid = buffer.bufferid + JOIN network ON buffer.networkid = network.networkid + WHERE buffer.userid = :userid + AND backlog.bufferid = :bufferid + AND backlog.messageid >= :anchor + ORDER BY backlog.messageid ASC + LIMIT :limit; + "); + } + + public function loadBefore(): \PDOStatement + { + return $this->db->prepare(" + SELECT backlog.messageid, + backlog.bufferid, + buffer.buffername, + sender.sender, + backlog.time, + network.networkname, + replace(replace(replace(backlog.message, '&', '&'), '<', '<'), '>', '>') AS message + FROM backlog + JOIN sender ON backlog.senderid = sender.senderid + JOIN buffer ON backlog.bufferid = buffer.bufferid + JOIN network ON buffer.networkid = network.networkid + WHERE buffer.userid = :userid + AND backlog.bufferid = :bufferid + AND backlog.messageid < :anchor + ORDER BY backlog.messageid DESC + LIMIT :limit; + "); + } +} \ No newline at end of file diff --git a/backend/helper/AuthHelper.php b/database/helper/AuthHelper.php similarity index 88% rename from backend/helper/AuthHelper.php rename to database/helper/AuthHelper.php index 90d2caf7b2fd2e865a54cc152e1e98270e0242a2..4abba76a8f505b6aea1f35004f0dcb77de01a466 100644 --- a/backend/helper/AuthHelper.php +++ b/database/helper/AuthHelper.php @@ -3,8 +3,10 @@ namespace QuasselRestSearch; -class AuthHelper { - public static function initialAuthenticateUser($plainPassword, $dbHashedPassword, $hashVersion) { +class AuthHelper +{ + public static function initialAuthenticateUser($plainPassword, $dbHashedPassword, $hashVersion) + { switch ($hashVersion) { case null: case 0: @@ -19,7 +21,8 @@ class AuthHelper { } } - public static function initialCheckHashedPasswordSha1($plainPassword, $dbHashedPassword) { + public static function initialCheckHashedPasswordSha1($plainPassword, $dbHashedPassword) + { $calculatedPasswordHash = hash("sha1", $plainPassword); if ($calculatedPasswordHash == $dbHashedPassword) { @@ -29,7 +32,8 @@ class AuthHelper { return false; } - public static function initialCheckHashedPasswordSha2_512($plainPassword, $dbHashedPassword) { + public static function initialCheckHashedPasswordSha2_512($plainPassword, $dbHashedPassword) + { $dbHashedPasswordArray = explode(":", $dbHashedPassword); if (count($dbHashedPasswordArray) == 2) { @@ -42,7 +46,8 @@ class AuthHelper { return false; } - public static function parseAuthHeader($authHeader) : array { + public static function parseAuthHeader($authHeader): array + { $arr = explode(':', base64_decode($authHeader)); if (count($arr) != 2) { throw new \Exception("Can’t parse authentication header"); @@ -54,7 +59,8 @@ class AuthHelper { } } - public static function generateAuthHeader(string $password, string $username) : string { + public static function generateAuthHeader(string $password, string $username): string + { return base64_encode(base64_encode($username) . ":" . base64_encode($password)); } } \ No newline at end of file diff --git a/backend/helper/RendererHelper.php b/database/helper/RendererHelper.php similarity index 84% rename from backend/helper/RendererHelper.php rename to database/helper/RendererHelper.php index 285f4d176e9e6c7206dd3e3a07b4e93188a78dc1..4a502ac6ae8a50b7f7420bd5ed778321bcbe297f 100644 --- a/backend/helper/RendererHelper.php +++ b/database/helper/RendererHelper.php @@ -5,44 +5,51 @@ namespace QuasselRestSearch; require_once 'ViewHelper.php'; require_once 'TranslationHelper.php'; -class RendererHelper { +class RendererHelper +{ private $config; private $translator; private $sessionHelper; - public function __construct(Config $config, SessionHelper $sessionHelper = null) { + public function __construct(Config $config, SessionHelper $sessionHelper = null) + { $this->config = $config; $this->translator = new TranslationHelper($config); $this->sessionHelper = $sessionHelper; } - public function renderError($e) { + public function renderError($e) + { header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); header('Status: 403 Forbidden'); echo 'Error 403: Forbidden' . "\n"; echo $e . "\n"; } - public function renderJsonError($json) { + public function renderJsonError($json) + { header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden'); header('Status: 403 Forbidden'); header('Content-Type: application/json'); echo json_encode($json) . "\n"; } - public function renderJson($json) { + public function renderJson($json) + { header('Content-Type: application/json'); echo json_encode($json) . "\n"; } - public function renderPage(string $template, array $vars = []) { + public function renderPage(string $template, array $vars = []) + { $translation = $this->translator->loadTranslation($this->translator->findMatchingLanguage($_SERVER['HTTP_ACCEPT_LANGUAGE'])); $viewHelper = new ViewHelper($translation, array_merge($this->sessionHelper->vars, $vars)); $viewHelper->render($template); $this->sessionHelper->vars = []; } - public function redirect(string $page, array $vars = []) { + public function redirect(string $page, array $vars = []) + { header('Location: ' . $this->config->path_prefix . $page); $this->sessionHelper->startSession(); $this->sessionHelper->vars = $vars; diff --git a/backend/helper/SessionHelper.php b/database/helper/SessionHelper.php similarity index 71% rename from backend/helper/SessionHelper.php rename to database/helper/SessionHelper.php index f1882fec145f6abd97b76ed1975bacc87bfb560e..286ca7f2bd8003ebcf1b69d34216495d555b7fca 100644 --- a/backend/helper/SessionHelper.php +++ b/database/helper/SessionHelper.php @@ -2,17 +2,20 @@ namespace QuasselRestSearch; -class SessionHelper { +class SessionHelper +{ const SESSION_STARTED = TRUE; const SESSION_NOT_STARTED = FALSE; private static $instance; private $sessionState = self::SESSION_NOT_STARTED; - private function __construct() { + private function __construct() + { } - public static function getInstance() : SessionHelper { + public static function getInstance(): SessionHelper + { if (!isset(self::$instance)) { self::$instance = new self; } @@ -23,7 +26,8 @@ class SessionHelper { } - public function startSession() : bool { + public function startSession(): bool + { if ($this->sessionState == self::SESSION_NOT_STARTED) { $this->sessionState = session_start(); } @@ -31,7 +35,8 @@ class SessionHelper { return $this->sessionState; } - public function __get(string $name) { + public function __get(string $name) + { if (isset($_SESSION[$name])) { return $_SESSION[$name]; } else { @@ -39,21 +44,25 @@ class SessionHelper { } } - public function __set(string $name, $value) { + public function __set(string $name, $value) + { $_SESSION[$name] = $value; } - public function __isset(string $name) : bool { + public function __isset(string $name): bool + { return isset($_SESSION[$name]); } - public function __unset(string $name) { + public function __unset(string $name) + { unset($_SESSION[$name]); } - public function destroy() : bool { + public function destroy(): bool + { if ($this->sessionState == self::SESSION_STARTED) { $this->sessionState = !session_destroy(); unset($_SESSION); diff --git a/backend/helper/TranslationHelper.php b/database/helper/TranslationHelper.php similarity index 65% rename from backend/helper/TranslationHelper.php rename to database/helper/TranslationHelper.php index 6e5cdbc422eb451a8c0840d41ccb8d40a19cba74..49547a8900f6dd4973e4063ca389502d0edf99f2 100644 --- a/backend/helper/TranslationHelper.php +++ b/database/helper/TranslationHelper.php @@ -2,18 +2,22 @@ namespace QuasselRestSearch; -class TranslationHelper { +class TranslationHelper +{ protected $template_dir; - public function __construct($translation) { + public function __construct($translation) + { $this->setPath('../../translations/'); } - public function setPath(string $path) { + public function setPath(string $path) + { $this->template_dir = realpath(dirname(__FILE__) . '/' . $path); } - public function findMatchingLanguage(string $language_str) : string { + public function findMatchingLanguage(string $language_str): string + { $languages = explode(",", $language_str); foreach ($languages as $language) { $language = explode(";", $language)[0]; @@ -24,15 +28,18 @@ class TranslationHelper { return "en"; } - public function exists($language) : bool { + public function exists($language): bool + { return file_exists($this->path($language)); } - private function path($language) : string { + private function path($language): string + { return $this->template_dir . '/' . $language . '.json'; } - public function loadTranslation($language) : array { + public function loadTranslation($language): array + { return json_decode(file_get_contents($this->path($language)), true); } } \ No newline at end of file diff --git a/backend/helper/ViewHelper.php b/database/helper/ViewHelper.php similarity index 78% rename from backend/helper/ViewHelper.php rename to database/helper/ViewHelper.php index 1d22ba96d6ee6eb94f0cff1b5970a5a06c1ce826..9bf186d284ed0c4d040949ed9c30ebd46daa7a8a 100644 --- a/backend/helper/ViewHelper.php +++ b/database/helper/ViewHelper.php @@ -2,12 +2,14 @@ namespace QuasselRestSearch; -class ViewHelper { +class ViewHelper +{ protected $template_dir; protected $translation; protected $vars = []; - public function __construct($translation, $vars = null) { + public function __construct($translation, $vars = null) + { $this->translation = $translation; $this->setPath('../../templates/'); if ($vars !== null) { @@ -15,11 +17,13 @@ class ViewHelper { } } - public function setPath(string $path) { + public function setPath(string $path) + { $this->template_dir = realpath(dirname(__FILE__) . '/' . $path); } - public function render($template_file) { + public function render($template_file) + { $translation = $this->translation; $t = function ($path) use ($translation) { $arr = explode(".", $path); @@ -38,11 +42,13 @@ class ViewHelper { } } - public function __get($name) { + public function __get($name) + { return $this->vars[$name]; } - public function __set($name, $value) { + public function __set($name, $value) + { $this->vars[$name] = $value; } } \ No newline at end of file diff --git a/index.php b/index.php index e068fc0b4f92266d37e67f76e7f95e538798ed1a..92d65dca5576a367fa93fa55d84d349ed67fffd9 100644 --- a/index.php +++ b/index.php @@ -3,9 +3,9 @@ namespace QuasselRestSearch; require_once 'qrs_config.php'; -require_once 'backend/Database.php'; -require_once 'backend/helper/RendererHelper.php'; -require_once 'backend/helper/SessionHelper.php'; +require_once 'database/Database.php'; +require_once 'database/helper/RendererHelper.php'; +require_once 'database/helper/SessionHelper.php'; $session = SessionHelper::getInstance(); $config = Config::createFromGlobals(); diff --git a/login.php b/login.php index 2968c6d078f907422bbb0d4120f6c8dcf6f2295a..293cf2da20bf26b886fd907b1d63b641e921c852 100644 --- a/login.php +++ b/login.php @@ -3,9 +3,9 @@ namespace QuasselRestSearch; require_once 'qrs_config.php'; -require_once 'backend/Database.php'; -require_once 'backend/helper/RendererHelper.php'; -require_once 'backend/helper/SessionHelper.php'; +require_once 'database/Database.php'; +require_once 'database/helper/RendererHelper.php'; +require_once 'database/helper/SessionHelper.php'; $session = SessionHelper::getInstance(); $config = Config::createFromGlobals(); diff --git a/qrs_config.default.php b/qrs_config.default.php index fa29c937b5a1dfc6424f77f4043fba6f8ef41314..4ef34f9c0f7769b298198ff7c7fb232e5c7f0cbc 100644 --- a/qrs_config.default.php +++ b/qrs_config.default.php @@ -1,14 +1,14 @@ <?php -define('db_host', 'example.com'); -define('db_port', 5432); -define('db_name', 'quassel'); +define('qrs_db_host', 'example.com'); +define('qrs_db_port', 5432); +define('qrs_db_name', 'quassel'); //Only change this if you know what you are doing -define('db_connector', null); +define('qrs_db_connector', null); -define('db_user', 'quassel'); -define('db_pass', 'password'); +define('qrs_db_user', 'quassel'); +define('qrs_db_pass', 'password'); -define('backend', 'pgsql-smart'); +define('qrs_backend', 'pgsql-smart'); -define('path_prefix', ''); +define('qrs_path_prefix', ''); diff --git a/res/css/_content.sass b/res/css/_content.sass index c3b8d75df90afe672351a6591013bb740ff80d4d..ef301e5f4ddb644ad09aa0f33edefbe831119747 100644 --- a/res/css/_content.sass +++ b/res/css/_content.sass @@ -91,7 +91,7 @@ will-change: background &:hover - background-color: rgba(0,0,0,0.06) + background-color: rgba(0, 0, 0, 0.06) &:after content: "" @@ -118,10 +118,9 @@ .close display: none - &:not(.focus) .context:nth-child(4)~.context + &:not(.focus) .secondary display: none - &:before content: "" display: block diff --git a/res/css/_mirccolor.sass b/res/css/_mirccolor.sass index 2116826edf5f187b635bdd3b4436f382e5356091..fe20c12d15c7241f30fe97cfa7a4081e8e2d30fc 100644 --- a/res/css/_mirccolor.sass +++ b/res/css/_mirccolor.sass @@ -1,72 +1,104 @@ .irc_bold font-weight: bold + .irc_italic font-style: italic + .irc_underline text-decoration: underline [data-irc_foreground="0"] color: #ffffff + [data-irc_foreground="1"] color: #000000 + [data-irc_foreground="2"] color: #000080 + [data-irc_foreground="3"] color: #008000 + [data-irc_foreground="4"] color: #ff0000 + [data-irc_foreground="5"] color: #800000 + [data-irc_foreground="6"] color: #800080 + [data-irc_foreground="7"] color: #ffa500 + [data-irc_foreground="8"] color: #ffff00 + [data-irc_foreground="9"] color: #00ff00 + [data-irc_foreground="10"] color: #008080 + [data-irc_foreground="11"] color: #00ffff + [data-irc_foreground="12"] color: #4169e1 + [data-irc_foreground="13"] color: #ff00ff + [data-irc_foreground="14"] color: #808080 + [data-irc_foreground="15"] color: #c0c0c0 [data-irc_background="0"] background-color: #ffffff + [data-irc_background="1"] background-color: #000000 + [data-irc_background="2"] background-color: #000080 + [data-irc_background="3"] background-color: #008000 + [data-irc_background="4"] background-color: #ff0000 + [data-irc_background="5"] background-color: #800000 + [data-irc_background="6"] background-color: #800080 + [data-irc_background="7"] background-color: #ffa500 + [data-irc_background="8"] background-color: #ffff00 + [data-irc_background="9"] background-color: #00ff00 + [data-irc_background="10"] background-color: #008080 + [data-irc_background="11"] background-color: #00ffff + [data-irc_background="12"] background-color: #4169e1 + [data-irc_background="13"] background-color: #ff00ff + [data-irc_background="14"] background-color: #808080 + [data-irc_background="15"] background-color: #c0c0c0 \ No newline at end of file diff --git a/res/css/_nav.sass b/res/css/_nav.sass index 219f60cfb0fd9d1fca8775fab9aea1c58c103b0f..fad78bbafe34c1bacf8d65b1ee3ce9e7458c95ad 100644 --- a/res/css/_nav.sass +++ b/res/css/_nav.sass @@ -191,5 +191,5 @@ .history transform: translateY(0) - &+.results + & + .results opacity: 0 \ No newline at end of file diff --git a/res/css/_sendercolor.sass b/res/css/_sendercolor.sass index 30614938fe6f9a643637d289396bd99e79ba5c5a..066acfcdca599faedce4edf8b75987e47f308d45 100644 --- a/res/css/_sendercolor.sass +++ b/res/css/_sendercolor.sass @@ -1,6 +1,6 @@ [data-sendercolor="0"] color: #e90d7f - + [data-sendercolor="1"] color: #8e55e9 diff --git a/res/css/search.css b/res/css/search.css index b5d18570ccf80337dae9e1619e71767a6506cac4..cd780afda6a6364d6445c999e6ad5c1276eb6eef 100644 --- a/res/css/search.css +++ b/res/css/search.css @@ -1,66 +1,84 @@ @font-face { - font-family: "Material Icons"; - font-style: normal; - font-weight: 400; - src: local("Material Icons"), local("MaterialIcons-Regular"), url(../icons/MaterialIcons-Regular.woff2) format("woff2"), url(../icons/MaterialIcons-Regular.woff) format("woff"); } + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../icons/MaterialIcons-Regular.woff2) format("woff2"), url(../icons/MaterialIcons-Regular.woff) format("woff"); +} + .icon { - font-family: "Material Icons", sans-serif; - font-weight: normal; - font-style: normal; - font-size: 24px; - display: inline-block; - width: 1em; - height: 1em; - line-height: 1; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - white-space: nowrap; - direction: ltr; - /* Support for all WebKit browsers. */ - -webkit-font-smoothing: antialiased; - /* Support for Safari and Chrome. */ - text-rendering: optimizeLegibility; - /* Support for Firefox. */ - -moz-osx-font-smoothing: grayscale; - /* Support for IE. */ - font-feature-settings: "liga"; } + font-family: "Material Icons", sans-serif; + font-weight: normal; + font-style: normal; + font-size: 24px; + display: inline-block; + width: 1em; + height: 1em; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} @font-face { - font-family: "Roboto"; - font-style: normal; - font-weight: 400; - src: local("Roboto"), local("Roboto-Regular"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-regular.woff2") format("woff2"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-regular.woff") format("woff"); } + font-family: "Roboto"; + font-style: normal; + font-weight: 400; + src: local("Roboto"), local("Roboto-Regular"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-regular.woff2") format("woff2"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-regular.woff") format("woff"); +} + @font-face { - font-family: "Roboto"; - font-style: normal; - font-weight: 700; - src: local("Roboto Bold"), local("Roboto-Bold"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-700.woff2") format("woff2"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-700.woff") format("woff"); } + font-family: "Roboto"; + font-style: normal; + font-weight: 700; + src: local("Roboto Bold"), local("Roboto-Bold"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-700.woff2") format("woff2"), url("../fonts/roboto-v15-latin-ext_cyrillic_greek-ext_cyrillic-ext_latin_greek_vietnamese-700.woff") format("woff"); +} + * { - padding: 0; - margin: 0; - box-sizing: border-box; - -webkit-tap-highlight-color: transparent; } + padding: 0; + margin: 0; + box-sizing: border-box; + -webkit-tap-highlight-color: transparent; +} body { - background: #F2F2F2; - font-family: "Roboto", sans-serif; - font-size: 81.25%; } + background: #F2F2F2; + font-family: "Roboto", sans-serif; + font-size: 81.25%; +} *:focus { - outline: none; } + outline: none; +} ::-moz-focus-inner { - border: 0; } + border: 0; +} + +*.hidden { + visibility: hidden !important; + display: none !important; +} .nav { - position: fixed; - left: 0; - right: 0; - top: 0; - height: 56px; - z-index: 2; } - .nav .bar { + position: fixed; + left: 0; + right: 0; + top: 0; + height: 56px; + z-index: 2; +} + +.nav .bar { background-color: #0271B3; z-index: 1; position: absolute; @@ -69,543 +87,746 @@ body { right: 0; box-shadow: 0 -1px 0 #e0e0e0, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); transition: background-color 0.15s; - will-change: background-color; } + will-change: background-color; +} + +.nav .bar .container { + max-width: 1136px; + margin: 0 auto; + padding: 0 2rem; + display: flex; +} + +@media (max-width: 800px) { .nav .bar .container { - max-width: 1136px; - margin: 0 auto; - padding: 0 2rem; - display: flex; } -@media(max-width: 800px) { - .nav .bar .container { - padding: 0 0 0 8px; } } - .nav .bar .container .searchBar { - margin: 8px auto; - height: 40px; - display: flex; - position: relative; - border: none; - background: #358dc2; - border-radius: 2px; - padding: 0 0 0 72px; - color: #ffffff; - flex-direction: row; - flex: 1; - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06); - transition: background-color 0.15s; } - .nav .bar .container .searchBar:hover { - background-color: rgba(255, 255, 255, 0.3); } - .nav .bar .container .searchBar .icon { - display: inline-block; - width: 72px; - height: 40px; - position: absolute; - text-align: center; - line-height: 40px; - left: 0; - top: 0; } - .nav .bar .container .searchBar .search { - display: inline-block; - flex-grow: 1; - flex-shrink: 1; - background: none; - border: none; - line-height: 100%; - color: #ffffff; - font-size: 1rem; - margin-right: 8px; - -webkit-appearance: textfield; - -webkit-box-sizing: content-box; } - .nav .bar .container .searchBar .search::-moz-placeholder { - color: #ffffff; - opacity: 1; - -moz-osx-font-smoothing: grayscale; } - .nav .bar .container .searchBar .search::-webkit-input-placeholder { - color: #ffffff; - opacity: 1; - -webkit-font-smoothing: antialiased; } - .nav .bar .container .searchBar .search::-webkit-search-decoration, .nav .bar .container .searchBar .search::-webkit-search-cancel-button { - display: none; } - .nav .bar .container .actions { - display: flex; - align-items: center; - justify-content: flex-end; } - .nav .bar a { - height: 56px; - width: 56px; - position: relative; - padding: 16px 13px; - cursor: pointer; - color: #fff; - transition: all 0.15s; - text-decoration: none; - text-align: center; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; } - .nav .bar a:before { - background-color: rgba(255, 255, 255, 0.12); - bottom: 9px; - content: " "; - left: 9px; - margin: auto; - padding: 4px; - position: absolute; - right: 9px; - top: 9px; - z-index: -1; - border-radius: 50%; - opacity: 0; - transition: opacity 100ms; } - .nav .bar a:hover:before { - opacity: 1; } - .nav .history { + padding: 0 0 0 8px; + } +} + +.nav .bar .container .searchBar { + margin: 8px auto; + height: 40px; + display: flex; + position: relative; + border: none; + background: #358dc2; + border-radius: 2px; + padding: 0 0 0 72px; + color: #ffffff; + flex-direction: row; + flex: 1; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06); + transition: background-color 0.15s; +} + +.nav .bar .container .searchBar:hover { + background-color: rgba(255, 255, 255, 0.3); +} + +.nav .bar .container .searchBar .icon { + display: inline-block; + width: 72px; + height: 40px; + position: absolute; + text-align: center; + line-height: 40px; + left: 0; + top: 0; +} + +.nav .bar .container .searchBar .search { + display: inline-block; + flex-grow: 1; + flex-shrink: 1; + background: none; + border: none; + line-height: 100%; + color: #ffffff; + font-size: 1rem; + margin-right: 8px; + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; +} + +.nav .bar .container .searchBar .search::-moz-placeholder { + color: #ffffff; + opacity: 1; + -moz-osx-font-smoothing: grayscale; +} + +.nav .bar .container .searchBar .search::-webkit-input-placeholder { + color: #ffffff; + opacity: 1; + -webkit-font-smoothing: antialiased; +} + +.nav .bar .container .searchBar .search::-webkit-search-decoration, .nav .bar .container .searchBar .search::-webkit-search-cancel-button { + display: none; +} + +.nav .bar .container .actions { + display: flex; + align-items: center; + justify-content: flex-end; +} + +.nav .bar a { + height: 56px; + width: 56px; + position: relative; + padding: 16px 13px; + cursor: pointer; + color: #fff; + transition: all 0.15s; + text-decoration: none; + text-align: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.nav .bar a:before { + background-color: rgba(255, 255, 255, 0.12); + bottom: 9px; + content: " "; + left: 9px; + margin: auto; + padding: 4px; + position: absolute; + right: 9px; + top: 9px; + z-index: -1; + border-radius: 50%; + opacity: 0; + transition: opacity 100ms; +} + +.nav .bar a:hover:before { + opacity: 1; +} + +.nav .history { top: 100%; max-width: 1136px; margin: auto; padding: 0 2rem; transform: translateY(-200%); transition: transform 400ms; - position: relative; } -@media(max-width: 800px) { - .nav .history { - padding: 0; } } - .nav .history ul { - list-style-type: none; - margin: 0; - padding: 6px 0; - background: #fff; - box-shadow: 0 -1px 0 #e0e0e0, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); } - .nav .history ul li { - cursor: pointer; - line-height: 36px; - overflow: hidden; - padding: 0 24px; - text-overflow: ellipsis; - white-space: nowrap; } - .nav .history ul li:hover, .nav .history ul li:focus, .nav .history ul li.focus { - background: rgba(0, 0, 0, 0.03); } - .nav .history ul li .icon { - border-radius: 12px; - height: 24px; - margin-right: 24px; - vertical-align: middle; - width: 24px; - display: inline-block; - background-size: cover; - opacity: 0.6; } - .nav .history ul p { - cursor: default; - line-height: 36px; - overflow: hidden; - padding: 0 24px; - text-overflow: ellipsis; - white-space: nowrap; - font-style: italic; - color: #646464; } - .nav.focus .bar { - background: #f2f2f2; } - .nav.focus .bar .container .searchBar { - background: #ffffff; } - .nav.focus .bar .container .searchBar .search { - color: #333333; } - .nav.focus .bar .container .searchBar .search::-moz-placeholder { - color: #757575; } - .nav.focus .bar .container .searchBar .search::-webkit-input-placeholder { - color: #757575; } - .nav.focus .bar .container .icon { - color: #757575; } - .nav.focus .history { - transform: translateY(0); } - .nav.focus + .results { - opacity: 0; } + position: relative; +} + +@media (max-width: 800px) { + .nav .history { + padding: 0; + } +} + +.nav .history ul { + list-style-type: none; + margin: 0; + padding: 6px 0; + background: #fff; + box-shadow: 0 -1px 0 #e0e0e0, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); +} + +.nav .history ul li { + cursor: pointer; + line-height: 36px; + overflow: hidden; + padding: 0 24px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.nav .history ul li:hover, .nav .history ul li:focus, .nav .history ul li.focus { + background: rgba(0, 0, 0, 0.03); +} + +.nav .history ul li .icon { + border-radius: 12px; + height: 24px; + margin-right: 24px; + vertical-align: middle; + width: 24px; + display: inline-block; + background-size: cover; + opacity: 0.6; +} + +.nav .history ul p { + cursor: default; + line-height: 36px; + overflow: hidden; + padding: 0 24px; + text-overflow: ellipsis; + white-space: nowrap; + font-style: italic; + color: #646464; +} + +.nav.focus .bar { + background: #f2f2f2; +} + +.nav.focus .bar .container .searchBar { + background: #ffffff; +} + +.nav.focus .bar .container .searchBar .search { + color: #333333; +} + +.nav.focus .bar .container .searchBar .search::-moz-placeholder { + color: #757575; +} + +.nav.focus .bar .container .searchBar .search::-webkit-input-placeholder { + color: #757575; +} + +.nav.focus .bar .container .icon { + color: #757575; +} + +.nav.focus .history { + transform: translateY(0); +} + +.nav.focus + .results { + opacity: 0; +} [data-sendercolor="0"] { - color: #e90d7f; } + color: #e90d7f; +} [data-sendercolor="1"] { - color: #8e55e9; } + color: #8e55e9; +} [data-sendercolor="2"] { - color: #b30e0e; } + color: #b30e0e; +} [data-sendercolor="3"] { - color: #17b339; } + color: #17b339; +} [data-sendercolor="4"] { - color: #58afb3; } + color: #58afb3; +} [data-sendercolor="5"] { - color: #9d54b3; } + color: #9d54b3; +} [data-sendercolor="6"] { - color: #b39775; } + color: #b39775; +} [data-sendercolor="7"] { - color: #3176b3; } + color: #3176b3; +} [data-sendercolor="8"] { - color: #e90d7f; } + color: #e90d7f; +} [data-sendercolor="9"] { - color: #8e55e9; } + color: #8e55e9; +} [data-sendercolor="a"] { - color: #b30e0e; } + color: #b30e0e; +} [data-sendercolor="b"] { - color: #17b339; } + color: #17b339; +} [data-sendercolor="c"] { - color: #58afb3; } + color: #58afb3; +} [data-sendercolor="d"] { - color: #9d54b3; } + color: #9d54b3; +} [data-sendercolor="e"] { - color: #b39775; } + color: #b39775; +} [data-sendercolor="f"] { - color: #3176b3; } + color: #3176b3; +} .irc_bold { - font-weight: bold; } + font-weight: bold; +} .irc_italic { - font-style: italic; } + font-style: italic; +} .irc_underline { - text-decoration: underline; } + text-decoration: underline; +} [data-irc_foreground="0"] { - color: #ffffff; } + color: #ffffff; +} [data-irc_foreground="1"] { - color: #000000; } + color: #000000; +} [data-irc_foreground="2"] { - color: #000080; } + color: #000080; +} [data-irc_foreground="3"] { - color: #008000; } + color: #008000; +} [data-irc_foreground="4"] { - color: #ff0000; } + color: #ff0000; +} [data-irc_foreground="5"] { - color: #800000; } + color: #800000; +} [data-irc_foreground="6"] { - color: #800080; } + color: #800080; +} [data-irc_foreground="7"] { - color: #ffa500; } + color: #ffa500; +} [data-irc_foreground="8"] { - color: #ffff00; } + color: #ffff00; +} [data-irc_foreground="9"] { - color: #00ff00; } + color: #00ff00; +} [data-irc_foreground="10"] { - color: #008080; } + color: #008080; +} [data-irc_foreground="11"] { - color: #00ffff; } + color: #00ffff; +} [data-irc_foreground="12"] { - color: #4169e1; } + color: #4169e1; +} [data-irc_foreground="13"] { - color: #ff00ff; } + color: #ff00ff; +} [data-irc_foreground="14"] { - color: #808080; } + color: #808080; +} [data-irc_foreground="15"] { - color: #c0c0c0; } + color: #c0c0c0; +} [data-irc_background="0"] { - background-color: #ffffff; } + background-color: #ffffff; +} [data-irc_background="1"] { - background-color: #000000; } + background-color: #000000; +} [data-irc_background="2"] { - background-color: #000080; } + background-color: #000080; +} [data-irc_background="3"] { - background-color: #008000; } + background-color: #008000; +} [data-irc_background="4"] { - background-color: #ff0000; } + background-color: #ff0000; +} [data-irc_background="5"] { - background-color: #800000; } + background-color: #800000; +} [data-irc_background="6"] { - background-color: #800080; } + background-color: #800080; +} [data-irc_background="7"] { - background-color: #ffa500; } + background-color: #ffa500; +} [data-irc_background="8"] { - background-color: #ffff00; } + background-color: #ffff00; +} [data-irc_background="9"] { - background-color: #00ff00; } + background-color: #00ff00; +} [data-irc_background="10"] { - background-color: #008080; } + background-color: #008080; +} [data-irc_background="11"] { - background-color: #00ffff; } + background-color: #00ffff; +} [data-irc_background="12"] { - background-color: #4169e1; } + background-color: #4169e1; +} [data-irc_background="13"] { - background-color: #ff00ff; } + background-color: #ff00ff; +} [data-irc_background="14"] { - background-color: #808080; } + background-color: #808080; +} [data-irc_background="15"] { - background-color: #c0c0c0; } + background-color: #c0c0c0; +} .results { - max-width: 1136px; - padding: 56px 2rem 4rem 2rem; - margin: 0 auto; - transition: opacity 400ms; } -@media(max-width: 800px) { - .results { - padding-left: 0; - padding-right: 0; - padding-bottom: 0; } } - .results .buffer { + max-width: 1136px; + padding: 56px 2rem 4rem 2rem; + margin: 0 auto; + transition: opacity 400ms; +} + +@media (max-width: 800px) { + .results { + padding-left: 0; + padding-right: 0; + padding-bottom: 0; + } +} + +.results .buffer { display: block; margin-top: 0; margin-bottom: 20px; - position: relative; } - .results .buffer .title { - border-bottom: 1px solid transparent; - border-top: 1px solid transparent; - color: #616161; - margin: 0; - padding: 20px 6px 10px 22px; - position: sticky; - top: 55px; - z-index: 1; - transition: all 400ms; - display: flex; } - .results .buffer .title:before { - content: ""; - display: block; - left: -16px; - right: -16px; - top: 0; - bottom: 0; - background-color: #f2f2f2; - position: absolute; - z-index: -2; } -@media(max-width: 800px) { - .results .buffer .title:before { - left: 0; - right: 0; } } - .results .buffer .title:after { - content: ""; - display: block; + position: relative; +} + +.results .buffer .title { + border-bottom: 1px solid transparent; + border-top: 1px solid transparent; + color: #616161; + margin: 0; + padding: 20px 6px 10px 22px; + position: sticky; + top: 55px; + z-index: 1; + transition: all 400ms; + display: flex; +} + +.results .buffer .title:before { + content: ""; + display: block; + left: -16px; + right: -16px; + top: 0; + bottom: 0; + background-color: #f2f2f2; + position: absolute; + z-index: -2; +} + +@media (max-width: 800px) { + .results .buffer .title:before { left: 0; right: 0; - top: 0; - bottom: 0; - background-color: transparent; - transition: margin-left 400ms, margin-right 400ms, background-color 400ms; - will-change: margin-left, margin-right, background-color; - position: absolute; - z-index: -1; } - .results .buffer .title h2 { - flex: 1; - line-height: 36px; } - .results .buffer .title button { - border-radius: 3px; - box-shadow: none; - color: #444444; - text-transform: uppercase; - border: none; - transition: all 0.4s; - position: relative; - font-weight: normal; - display: inline-block; - margin-bottom: 0; - text-align: center; - vertical-align: middle; - touch-action: manipulation; - cursor: pointer; - background: transparent none; - white-space: nowrap; - padding: 6px 16px; - font-size: 13px; - line-height: 1.846; - -moz-user-select: none; - text-decoration: none; - box-sizing: border-box; - font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; - will-change: background; } - .results .buffer .title button:hover { - background-color: rgba(0, 0, 0, 0.06); } - .results .buffer .title button:after { - content: ""; - display: block; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background: radial-gradient(circle, #444444 10%, transparent 10.01%) no-repeat 50%; - background-size: 1000% 1000%; - opacity: 0; - pointer-events: none; - transition: background 0.5s, opacity 1s; } - .results .buffer .title button:active:after { - background-size: 0 0; - opacity: 0.2; - transition: 0s; } - .results .buffer .title button .open { - display: initial; } - .results .buffer .title button .close { - display: none; } - .results .buffer:not(.focus) .context:nth-child(4) ~ .context { - display: none; } - .results .buffer:before { - content: ""; - display: block; - left: 0; - right: 0; - top: 0; - bottom: 0; - background-color: transparent; - transition: margin-left 400ms, margin-right 400ms, margin-bottom 400ms, background-color 400ms; - will-change: margin-left, margin-right, margin-bottom, background-color; - position: absolute; - z-index: -1; } + } +} + +.results .buffer .title:after { + content: ""; + display: block; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-color: transparent; + transition: margin-left 400ms, margin-right 400ms, background-color 400ms; + will-change: margin-left, margin-right, background-color; + position: absolute; + z-index: -1; +} + +.results .buffer .title h2 { + flex: 1; + line-height: 36px; +} + +.results .buffer .title button { + border-radius: 3px; + box-shadow: none; + color: #444444; + text-transform: uppercase; + border: none; + transition: all 0.4s; + position: relative; + font-weight: normal; + display: inline-block; + margin-bottom: 0; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background: transparent none; + white-space: nowrap; + padding: 6px 16px; + font-size: 13px; + line-height: 1.846; + -moz-user-select: none; + text-decoration: none; + box-sizing: border-box; + font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; + will-change: background; +} + +.results .buffer .title button:hover { + background-color: rgba(0, 0, 0, 0.06); +} + +.results .buffer .title button:after { + content: ""; + display: block; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + background: radial-gradient(circle, #444444 10%, transparent 10.01%) no-repeat 50%; + background-size: 1000% 1000%; + opacity: 0; + pointer-events: none; + transition: background 0.5s, opacity 1s; +} + +.results .buffer .title button:active:after { + background-size: 0 0; + opacity: 0.2; + transition: 0s; +} + +.results .buffer .title button .open { + display: initial; +} + +.results .buffer .title button .close { + display: none; +} + +.results .buffer:not(.focus) .secondary { + display: none; +} + +.results .buffer:before { + content: ""; + display: block; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-color: transparent; + transition: margin-left 400ms, margin-right 400ms, margin-bottom 400ms, background-color 400ms; + will-change: margin-left, margin-right, margin-bottom, background-color; + position: absolute; + z-index: -1; +} + +.results .buffer.focus:before { + margin-bottom: -16px; + background-color: #ddd; +} + +@media (min-width: 800px) { .results .buffer.focus:before { - margin-bottom: -16px; - background-color: #ddd; } -@media(min-width: 800px) { - .results .buffer.focus:before { - margin-left: -16px; - margin-right: -16px; } } + margin-left: -16px; + margin-right: -16px; + } +} + +.results .buffer.focus .title:after { + background-color: #ddd; +} + +@media (min-width: 800px) { .results .buffer.focus .title:after { - background-color: #ddd; } -@media(min-width: 800px) { - .results .buffer.focus .title:after { - margin-left: -16px; - margin-right: -16px; } } - .results .buffer.focus .title button .open { - display: none; } - .results .buffer.focus .title button .close { - display: initial; } - .results .buffer.focus .container > .inline-button { - height: 48px; } - .results .buffer .container { - font-size: 13px; } - .results .buffer .container > .inline-button { - height: 0; - overflow: hidden; - background: #f5f5f5; - font-size: 16px; - line-height: 48px; - color: #717171; - text-align: center; - font-style: italic; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - -o-user-select: none; - user-select: none; - position: sticky; - bottom: 0; - box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); - transition: height 400ms; } - .results .buffer .container .context:not(.focus) > .before, .results .buffer .container .context:not(.focus) > .after { - display: none; } - .results .buffer .container .context:not(.focus) > .inline-button { - display: none; } - .results .buffer .container .context .message { - display: flex; - line-height: 24px; - padding: 12px 24px; - border-bottom: 1px solid #e5e5e5; - color: #212121; - background: #fff; - position: relative; } - .results .buffer .container .context .message:before { - bottom: 0; - box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); - content: ""; - display: block; - left: 0; - pointer-events: none; - position: absolute; - right: 0; - top: 0; } - .results .buffer .container .context .message:last-child { - border-bottom: none; } - .results .buffer .container .context .message time { - width: 132px; - display: inline-block; - text-align: right; - flex-shrink: 0; } -@media(max-width: 800px) { - .results .buffer .container .context .message time { - position: absolute; - right: 8px; - bottom: 8px; - width: initial; + margin-left: -16px; + margin-right: -16px; + } +} + +.results .buffer.focus .title button .open { + display: none; +} + +.results .buffer.focus .title button .close { + display: initial; +} + +.results .buffer.focus .container > .inline-button { + height: 48px; +} + +.results .buffer .container { + font-size: 13px; +} + +.results .buffer .container > .inline-button { + height: 0; + overflow: hidden; + background: #f5f5f5; + font-size: 16px; + line-height: 48px; + color: #717171; + text-align: center; font-style: italic; - color: #777; } } - .results .buffer .container .context .message .container { - display: flex; - flex-grow: 1; - flex-shrink: 1; - overflow: hidden; } -@media(max-width: 800px) { - .results .buffer .container .context .message .container { + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + position: sticky; + bottom: 0; + box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); + transition: height 400ms; +} + +.results .buffer .container .context:not(.focus) > .before, .results .buffer .container .context:not(.focus) > .after { + display: none; +} + +.results .buffer .container .context:not(.focus) > .inline-button { + display: none; +} + +.results .buffer .container .context .message { + display: flex; + line-height: 24px; + padding: 12px 24px; + border-bottom: 1px solid #e5e5e5; + color: #212121; + background: #fff; + position: relative; +} + +.results .buffer .container .context .message:before { + bottom: 0; + box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24); + content: ""; display: block; - padding-bottom: 16px; } } - .results .buffer .container .context .message .container .sender { - width: 148px; - display: inline-block; - padding: 0 24px; - font-weight: bold; - flex-shrink: 0; } -@media(max-width: 800px) { - .results .buffer .container .context .message .container .sender { - width: initial; - padding: 0; } } -@media(max-width: 800px) { - .results .buffer .container .context .message .container .sender:after { - content: ": "; - margin-right: 8px; } } - .results .buffer .container .context .message .container .preview { - flex: 50%; - min-width: 0; - overflow: hidden; } -@media(max-width: 800px) { - .results .buffer .container .context .message .container .preview { - display: none; } } - .results .buffer .container .context .message .container .preview .irc_highlight { - background-color: rgba(251, 246, 167, 0.5); } - .results .buffer .container .context .message .container .content { - flex: 50%; - min-width: 0; - overflow: hidden; } -@media(max-width: 800px) { - .results .buffer .container .context .message .container .content { - display: inline; } } + left: 0; + pointer-events: none; + position: absolute; + right: 0; + top: 0; +} + +.results .buffer .container .context .message:last-child { + border-bottom: none; +} + +.results .buffer .container .context .message time { + width: 132px; + display: inline-block; + text-align: right; + flex-shrink: 0; +} + +@media (max-width: 800px) { + .results .buffer .container .context .message time { + position: absolute; + right: 8px; + bottom: 8px; + width: initial; + font-style: italic; + color: #777; + } +} + +.results .buffer .container .context .message .container { + display: flex; + flex-grow: 1; + flex-shrink: 1; + overflow: hidden; +} + +@media (max-width: 800px) { + .results .buffer .container .context .message .container { + display: block; + padding-bottom: 16px; + } +} + +.results .buffer .container .context .message .container .sender { + width: 148px; + display: inline-block; + padding: 0 24px; + font-weight: bold; + flex-shrink: 0; +} + +@media (max-width: 800px) { + .results .buffer .container .context .message .container .sender { + width: initial; + padding: 0; + } +} + +@media (max-width: 800px) { + .results .buffer .container .context .message .container .sender:after { + content: ": "; + margin-right: 8px; + } +} + +.results .buffer .container .context .message .container .preview { + flex: 50%; + min-width: 0; + overflow: hidden; +} + +@media (max-width: 800px) { + .results .buffer .container .context .message .container .preview { + display: none; + } +} + +.results .buffer .container .context .message .container .preview .irc_highlight { + background-color: rgba(251, 246, 167, 0.5); +} + +.results .buffer .container .context .message .container .content { + flex: 50%; + min-width: 0; + overflow: hidden; +} + +@media (max-width: 800px) { + .results .buffer .container .context .message .container .content { + display: inline; + } +} /*# sourceMappingURL=search.css.map */ diff --git a/res/css/search.css.map b/res/css/search.css.map index 45fd867cca05675ccbff26b36fdd8e892179cbaa..fa4d8241954d18f081f06e64abe75308601757d1 100644 --- a/res/css/search.css.map +++ b/res/css/search.css.map @@ -1,7 +1,16 @@ { -"version": 3, -"mappings": "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", -"sources": ["_icons.sass","_font.sass","search.sass","_nav.sass","_util.sass","_sendercolor.sass","_mirccolor.sass","_content.sass"], -"names": [], -"file": "search.css" + "version": 3, + "mappings": ";EACE,WAAW,EAAE,gBAAgB;EAC7B,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,2KAA2K;AAElL,KAAK;EACH,WAAW,EAAE,4BAA4B;EACzC,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,MAAM;EAClB,SAAS,EAAE,IAAI;EACf,OAAO,EAAE,YAAY;EACrB,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,GAAG;EACX,WAAW,EAAE,CAAC;EACd,cAAc,EAAE,IAAI;EACpB,cAAc,EAAE,MAAM;EACtB,SAAS,EAAE,MAAM;EACjB,WAAW,EAAE,MAAM;EACnB,SAAS,EAAE,GAAG;;EAGd,sBAAsB,EAAE,WAAW;;EAEnC,cAAc,EAAE,kBAAkB;;EAGlC,uBAAuB,EAAE,SAAS;;EAGlC,qBAAqB,EAAE,MAAM;;;EC7B7B,WAAW,EAAE,QAAQ;EACrB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,4RAA4R;;EAGjS,WAAW,EAAE,QAAQ;EACrB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,sRAAsR;ACN7R,CAAC;EACC,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;EACT,UAAU,EAAE,UAAU;EACtB,2BAA2B,EAAE,WAAgB;;AAE/C,IAAI;EACF,UAAU,EAAE,OAAO;EACnB,WAAW,EAAE,oBAAoB;EACjC,SAAS,EAAE,MAAM;;AAEnB,OAAO;EACL,OAAO,EAAE,IAAI;;AACf,kBAAkB;EAChB,MAAM,EAAE,CAAC;;AAEX,QAAQ;EACN,UAAU,EAAE,iBAAiB;EAC7B,OAAO,EAAE,eAAe;;ACpB1B,IAAI;EACF,QAAQ,EAAE,KAAK;EACf,IAAI,EAAE,CAAC;EACP,KAAK,EAAE,CAAC;EACR,GAAG,EAAE,CAAC;EACN,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,CAAC;EAEV,SAAI;IACF,gBAAgB,EAAE,OAAO;IACzB,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,QAAQ;IAClB,GAAG,EAAE,CAAC;IACN,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,UAAU,EAAE,4EAA0E;IACtF,UAAU,EAAE,sBAAqB;IACjC,WAAW,EAAE,gBAAgB;IAE7B,oBAAU;MACR,SAAS,EAAE,MAAM;MACjB,MAAM,EAAE,MAAM;MACd,OAAO,EAAE,MAAM;MACf,OAAO,EAAE,IAAI;;EAJf,oBAAU;IAON,OAAO,EAAE,SAAS;MAEpB,+BAAU;QACR,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,OAAO;QACnB,aAAa,EAAE,GAAG;QAClB,OAAO,EAAE,UAAU;QACnB,KAAK,EAAE,OAAO;QACd,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC;QACP,UAAU,EAAE,6BAA4B;QACxC,UAAU,EAAE,sBAAqB;QAEjC,qCAAO;UACL,gBAAgB,EAAE,wBAAuB;QAE3C,qCAAK;UACH,OAAO,EAAE,YAAY;UACrB,KAAK,EAAE,IAAI;UACX,MAAM,EAAE,IAAI;UACZ,QAAQ,EAAE,QAAQ;UAClB,UAAU,EAAE,MAAM;UAClB,WAAW,EAAE,IAAI;UACjB,IAAI,EAAE,CAAC;UACP,GAAG,EAAE,CAAC;QAER,uCAAO;UACL,OAAO,EAAE,YAAY;UACrB,SAAS,EAAE,CAAC;UACZ,WAAW,EAAE,CAAC;UACd,UAAU,EAAE,IAAI;UAChB,MAAM,EAAE,IAAI;UACZ,WAAW,EAAE,IAAI;UACjB,KAAK,EAAE,OAAO;UACd,SAAS,EAAE,IAAI;UACf,YAAY,EAAE,GAAG;UACjB,kBAAkB,EAAE,SAAS;UAC7B,kBAAkB,EAAE,WAAW;UAE/B,yDAAmB;YACjB,KAAK,EAAE,OAAO;YACd,OAAO,EAAE,CAAC;YACV,uBAAuB,EAAE,SAAS;UAEpC,kEAA4B;YAC1B,KAAK,EAAE,OAAO;YACd,OAAO,EAAE,CAAC;YACV,sBAAsB,EAAE,WAAW;UAErC,yIAA6D;YAC3D,OAAO,EAAE,IAAI;MAEnB,6BAAQ;QACN,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,MAAM;QACnB,eAAe,EAAE,QAAQ;IAE7B,WAAC;MACC,MAAM,EAAE,IAAI;MACZ,KAAK,EAAE,IAAI;MACX,QAAQ,EAAE,QAAQ;MAClB,OAAO,EAAE,SAAS;MAClB,MAAM,EAAE,OAAO;MACf,KAAK,EAAE,IAAI;MACX,UAAU,EAAE,SAAQ;MACpB,eAAe,EAAE,IAAI;MACrB,UAAU,EAAE,MAAM;MChGpB,mBAAkB,EAAE,IAAS;MAA7B,gBAAkB,EAAE,IAAS;MAA7B,eAAkB,EAAE,IAAS;MAA7B,cAAkB,EAAE,IAAS;MAA7B,WAAkB,EAAE,IAAS;MDmG3B,kBAAQ;QACN,gBAAgB,EAAE,yBAAwB;QAC1C,MAAM,EAAE,GAAG;QACX,OAAO,EAAE,GAAG;QACZ,IAAI,EAAE,GAAG;QACT,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,GAAG;QACZ,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,GAAG;QACV,GAAG,EAAE,GAAG;QACR,OAAO,EAAE,EAAE;QACX,aAAa,EAAE,GAAG;QAClB,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,aAAa;MAE3B,wBAAc;QACZ,OAAO,EAAE,CAAC;EAEhB,aAAQ;IACN,GAAG,EAAE,IAAI;IACT,SAAS,EAAE,MAAM;IACjB,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,MAAM;IACf,SAAS,EAAE,iBAAiB;IAC5B,UAAU,EAAE,eAAe;IAC3B,QAAQ,EAAE,QAAQ;;EAPpB,aAAQ;IAUJ,OAAO,EAAE,CAAC;IAEZ,gBAAE;MACA,eAAe,EAAE,IAAI;MACrB,MAAM,EAAE,CAAC;MACT,OAAO,EAAE,KAAK;MACd,UAAU,EAAE,IAAI;MAChB,UAAU,EAAE,4EAA0E;MAEtF,mBAAE;QACA,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ;QACvB,WAAW,EAAE,MAAM;QAEnB,+EAAyB;UACvB,UAAU,EAAE,mBAAmB;QAEjC,yBAAK;UACH,aAAa,EAAE,IAAI;UACnB,MAAM,EAAE,IAAI;UACZ,YAAY,EAAE,IAAI;UAClB,cAAc,EAAE,MAAM;UACtB,KAAK,EAAE,IAAI;UACX,OAAO,EAAE,YAAY;UACrB,eAAe,EAAE,KAAK;UACtB,OAAO,EAAE,GAAG;MAEhB,kBAAC;QACC,MAAM,EAAE,OAAO;QACf,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,MAAM;QAChB,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ;QACvB,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,MAAM;QAClB,KAAK,EAAE,OAAO;EAGlB,eAAI;IACF,UAAU,EAAE,OAAO;IAIjB,qCAAU;MACR,UAAU,EAAE,OAAO;MAEnB,6CAAO;QACL,KAAK,EAAE,OAAO;QAEd,+DAAmB;UACjB,KAAK,EAAE,OAAO;QAEhB,wEAA4B;UAC1B,KAAK,EAAE,OAAO;IAEpB,gCAAK;MACH,KAAK,EAAE,OAAO;EAEpB,mBAAQ;IACN,SAAS,EAAE,aAAa;EAE1B,qBAAU;IACR,OAAO,EAAE,CAAC;;AElMhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AAEhB,sBAAsB;EACpB,KAAK,EAAE,OAAO;;AC9ChB,SAAS;EACP,WAAW,EAAE,IAAI;;AACnB,WAAW;EACT,UAAU,EAAE,MAAM;;AACpB,cAAc;EACZ,eAAe,EAAE,SAAS;;AAE5B,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,yBAAyB;EACvB,KAAK,EAAE,OAAO;;AAChB,0BAA0B;EACxB,KAAK,EAAE,OAAO;;AAChB,0BAA0B;EACxB,KAAK,EAAE,OAAO;;AAChB,0BAA0B;EACxB,KAAK,EAAE,OAAO;;AAChB,0BAA0B;EACxB,KAAK,EAAE,OAAO;;AAChB,0BAA0B;EACxB,KAAK,EAAE,OAAO;;AAChB,0BAA0B;EACxB,KAAK,EAAE,OAAO;;AAEhB,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,yBAAyB;EACvB,gBAAgB,EAAE,OAAO;;AAC3B,0BAA0B;EACxB,gBAAgB,EAAE,OAAO;;AAC3B,0BAA0B;EACxB,gBAAgB,EAAE,OAAO;;AAC3B,0BAA0B;EACxB,gBAAgB,EAAE,OAAO;;AAC3B,0BAA0B;EACxB,gBAAgB,EAAE,OAAO;;AAC3B,0BAA0B;EACxB,gBAAgB,EAAE,OAAO;;AAC3B,0BAA0B;EACxB,gBAAgB,EAAE,OAAO;;ACnE3B,QAAQ;EACN,SAAS,EAAE,MAAM;EACjB,OAAO,EAAE,mBAAmB;EAC5B,MAAM,EAAE,MAAM;EAEd,UAAU,EAAE,aAAa;;EAL3B,QAAQ;IAQJ,YAAY,EAAE,CAAC;IACf,aAAa,EAAE,CAAC;IAChB,cAAc,EAAE,CAAC;EAEnB,gBAAO;IACL,OAAO,EAAE,KAAK;IACd,UAAU,EAAE,CAAC;IACb,aAAa,EAAE,IAAI;IACnB,QAAQ,EAAE,QAAQ;IAElB,uBAAM;MACJ,aAAa,EAAE,qBAAqB;MACpC,UAAU,EAAE,qBAAqB;MACjC,KAAK,EAAE,OAAO;MACd,MAAM,EAAE,CAAC;MACT,OAAO,EAAE,kBAAkB;MAC3B,QAAQ,EAAE,MAAM;MAChB,GAAG,EAAE,IAAI;MACT,OAAO,EAAE,CAAC;MACV,UAAU,EAAE,SAAS;MACrB,OAAO,EAAE,IAAI;MAEb,8BAAQ;QACN,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,KAAK;QACX,KAAK,EAAE,KAAK;QACZ,GAAG,EAAE,CAAC;QACN,MAAM,EAAE,CAAC;QACT,gBAAgB,EAAE,OAAO;QACzB,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,EAAE;;EATb,8BAAQ;IAYJ,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;MAEZ,6BAAO;QACL,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,CAAC;QACR,GAAG,EAAE,CAAC;QACN,MAAM,EAAE,CAAC;QACT,gBAAgB,EAAE,WAAW;QAC7B,UAAU,EAAE,6DAA6D;QACzE,WAAW,EAAE,2CAA2C;QACxD,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,EAAE;MAEb,0BAAE;QACA,IAAI,EAAE,CAAC;QACP,WAAW,EAAE,IAAI;MAEnB,8BAAM;QACJ,aAAa,EAAE,GAAG;QAClB,UAAU,EAAE,IAAI;QAChB,KAAK,EAAE,OAAO;QACd,cAAc,EAAE,SAAS;QACzB,MAAM,EAAE,IAAI;QACZ,UAAU,EAAE,QAAQ;QACpB,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,YAAY;QACrB,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,MAAM;QAClB,cAAc,EAAE,MAAM;QACtB,YAAY,EAAE,YAAY;QAC1B,MAAM,EAAE,OAAO;QACf,UAAU,EAAE,gBAAgB;QAC5B,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,QAAQ;QACjB,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,KAAK;QAClB,gBAAgB,EAAE,IAAI;QACtB,eAAe,EAAE,IAAI;QACrB,UAAU,EAAE,UAAU;QACtB,WAAW,EAAE,wDAAwD;QACrE,WAAW,EAAE,UAAU;QAEvB,oCAAO;UACL,gBAAgB,EAAE,mBAAgB;QAEpC,oCAAO;UACL,OAAO,EAAE,EAAE;UACX,OAAO,EAAE,KAAK;UACd,QAAQ,EAAE,QAAQ;UAClB,KAAK,EAAE,IAAI;UACX,MAAM,EAAE,IAAI;UACZ,GAAG,EAAE,CAAC;UACN,IAAI,EAAE,CAAC;UACP,UAAU,EAAE,sEAAsE;UAClF,eAAe,EAAE,WAAW;UAC5B,OAAO,EAAE,CAAC;UACV,cAAc,EAAE,IAAI;UACpB,UAAU,EAAE,2BAA0B;QAGtC,2CAAO;UACL,eAAe,EAAE,GAAG;UACpB,OAAO,EAAE,GAAE;UACX,UAAU,EAAE,EAAE;QAElB,oCAAK;UACH,OAAO,EAAE,OAAO;QAClB,qCAAM;UACJ,OAAO,EAAE,IAAI;IAEnB,uCAAwB;MACtB,OAAO,EAAE,IAAI;IAGf,uBAAQ;MACN,OAAO,EAAE,EAAE;MACX,OAAO,EAAE,KAAK;MACd,IAAI,EAAE,CAAC;MACP,KAAK,EAAE,CAAC;MACR,GAAG,EAAE,CAAC;MACN,MAAM,EAAE,CAAC;MACT,gBAAgB,EAAE,WAAW;MAC7B,UAAU,EAAE,kFAAkF;MAC9F,WAAW,EAAE,0DAA0D;MACvE,QAAQ,EAAE,QAAQ;MAClB,OAAO,EAAE,EAAE;IAGX,6BAAQ;MACN,aAAa,EAAE,KAAK;MACpB,gBAAgB,EAAE,IAAI;;EAFxB,6BAAQ;IAKJ,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,KAAK;IAGrB,mCAAO;MACL,gBAAgB,EAAE,IAAI;;EADxB,mCAAO;IAIH,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,KAAK;IAGrB,0CAAK;MACH,OAAO,EAAE,IAAI;IACf,2CAAM;MACJ,OAAO,EAAE,OAAO;IAGpB,kDAAgB;MACd,MAAM,EAAE,IAAI;IAElB,2BAAU;MACR,SAAS,EAAE,IAAI;MAEf,4CAAgB;QACd,MAAM,EAAE,CAAC;QACT,QAAQ,EAAE,MAAM;QAChB,UAAU,EAAE,OAAO;QACnB,SAAS,EAAE,IAAI;QACf,WAAW,EAAE,IAAI;QACjB,KAAK,EAAE,OAAkB;QACzB,UAAU,EAAE,MAAM;QAClB,UAAU,EAAE,MAAM;QAClB,MAAM,EAAE,OAAO;QH9KnB,mBAAkB,EAAE,IAAS;QAA7B,gBAAkB,EAAE,IAAS;QAA7B,eAAkB,EAAE,IAAS;QAA7B,cAAkB,EAAE,IAAS;QAA7B,WAAkB,EAAE,IAAS;QGgLzB,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,CAAC;QACT,UAAU,EAAE,4EAA0E;QACtF,UAAU,EAAE,YAAY;MAQtB,qHAAmB;QACjB,OAAO,EAAE,IAAI;MAEf,iEAAgB;QACd,OAAO,EAAE,IAAI;MAEjB,6CAAQ;QACN,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,IAAI;QACjB,OAAO,EAAE,SAAS;QAClB,aAAa,EAAE,iBAAiB;QAChC,KAAK,EAAE,OAAO;QACd,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,QAAQ;QAElB,oDAAQ;UACN,MAAM,EAAE,CAAC;UACT,UAAU,EAAE,4EAA0E;UACtF,OAAO,EAAE,EAAE;UACX,OAAO,EAAE,KAAK;UACd,IAAI,EAAE,CAAC;UACP,cAAc,EAAE,IAAI;UACpB,QAAQ,EAAE,QAAQ;UAClB,KAAK,EAAE,CAAC;UACR,GAAG,EAAE,CAAC;QAER,wDAAY;UACV,aAAa,EAAE,IAAI;QAErB,kDAAI;UACF,KAAK,EAAE,KAAK;UACZ,OAAO,EAAE,YAAY;UACrB,UAAU,EAAE,KAAK;UACjB,WAAW,EAAE,CAAC;;EAJhB,kDAAI;IAOA,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,GAAG;IACX,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,MAAM;IAClB,KAAK,EAAE,IAAI;QAEf,wDAAU;UACR,OAAO,EAAE,IAAI;UACb,SAAS,EAAE,CAAC;UACZ,WAAW,EAAE,CAAC;UACd,QAAQ,EAAE,MAAM;;EAJlB,wDAAU;IAON,OAAO,EAAE,KAAK;IACd,cAAc,EAAE,IAAI;UAEtB,gEAAO;YACL,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,YAAY;YACrB,OAAO,EAAE,MAAM;YACf,WAAW,EAAE,IAAI;YACjB,WAAW,EAAE,CAAC;;EALhB,gEAAO;IAQH,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,CAAC;;EAEZ,sEAAO;IAEH,OAAO,EAAE,IAAI;IACb,YAAY,EAAE,GAAG;UAEvB,iEAAQ;YACN,IAAI,EAAE,GAAG;YACT,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,MAAM;;EAHlB,iEAAQ;IAMJ,OAAO,EAAE,IAAI;YAEf,gFAAc;cACZ,gBAAgB,EAAE,wBAAwB;UAE9C,iEAAQ;YACN,IAAI,EAAE,GAAG;YACT,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,MAAM;;EAHlB,iEAAQ;IAMJ,OAAO,EAAE,MAAM", + "sources": [ + "_icons.sass", + "_font.sass", + "search.sass", + "_nav.sass", + "_util.sass", + "_sendercolor.sass", + "_mirccolor.sass", + "_content.sass" + ], + "names": [], + "file": "search.css" } \ No newline at end of file diff --git a/res/css/search.sass b/res/css/search.sass index 0029e52a72d4a28453edd96b31e9745f3ff60df7..3e1a6be0339e821f29338178290cc1841ea181a9 100644 --- a/res/css/search.sass +++ b/res/css/search.sass @@ -15,8 +15,13 @@ body *:focus outline: none + ::-moz-focus-inner border: 0 +*.hidden + visibility: hidden !important + display: none !important + @import "nav" @import "content" \ No newline at end of file diff --git a/res/js/app.js b/res/js/app.js index a942d8bb778016889be0a1ae9100c4ccb241e62d..177828ed1e8dde8044c1a227fe8036f3c983ff2c 100644 --- a/res/js/app.js +++ b/res/js/app.js @@ -15,10 +15,10 @@ class App { render() { const wrapper = document.createElement("div"); - wrapper.appendChild(this.navigation.elem); - const results = document.createElement("div"); - results.classList.add("results"); - wrapper.appendChild(results); + wrapper.appendChild(this.navigation.elem); + const results = document.createElement("div"); + results.classList.add("results"); + wrapper.appendChild(results); this.elem = wrapper; this.resultContainer = results; @@ -43,7 +43,7 @@ class App { return; this.buffers = result.map((buffer) => { - return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.messages.map((msg) => { + return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map((msg) => { return new Context(new MessagePreview(msg.messageid, msg.time, msg.sender, msg.message, msg.preview)); })); }); diff --git a/res/js/component/buffer.js b/res/js/component/buffer.js index 8803f084ca0824defa5b421fc62669ed4f472c50..3a8c660d94a97bb5bf8dcb0508c56ddf4c667bcf 100644 --- a/res/js/component/buffer.js +++ b/res/js/component/buffer.js @@ -1,5 +1,5 @@ class Buffer extends Component { - constructor(id, name, network, contextList = []) { + constructor(id, name, network, hasMore, contextList = []) { super(); this.id = id; this.name = name; @@ -7,6 +7,7 @@ class Buffer extends Component { this.contextList = contextList; this.render(); this.contextList.forEach(context => this.insert(context)); + this.loadMoreBtn.setVisible(hasMore); } render() { return this.elem = function () { @@ -32,12 +33,20 @@ class Buffer extends Component { $$j.setAttribute('class', 'close'); $$g.appendChild($$j); $$j.appendChildren(translation.buffer.close); - $$a.appendChildren(this.insertContainer = function () { - var $$m = document.createElement('div'); - $$m.setAttribute('class', 'container'); - $$m.appendChildren((this.loadMoreBtn = new LoadMore(translation.results.show_more, this.loadMore)).elem); - return $$m; + var $$l = document.createElement('div'); + $$l.setAttribute('class', 'container'); + $$a.appendChild($$l); + $$l.appendChildren(this.insertContainerFirst = function () { + var $$n = document.createElement('div'); + $$n.setAttribute('class', 'primary'); + return $$n; }.call(this)); + $$l.appendChildren(this.insertContainer = function () { + var $$p = document.createElement('div'); + $$p.setAttribute('class', 'secondary'); + return $$p; + }.call(this)); + $$l.appendChildren((this.loadMoreBtn = new LoadMore(translation.results.show_more, this.loadMore)).elem); return $$a; }.call(this); } @@ -50,6 +59,7 @@ class Buffer extends Component { this.sendEvent('focus', focus); } insert(context) { - this.insertContainer.insertBefore(context.elem, this.loadMoreBtn.elem); + let container = this.insertContainerFirst.childElementCount < 4 ? this.insertContainerFirst : this.insertContainer; + container.appendChild(context.elem); } } \ No newline at end of file diff --git a/res/js/component/buffer.jsx b/res/js/component/buffer.jsx index 8e30c7205834d8ae21047aa87df84d19446c9eb8..359764ef3144733ce1e7805a2000fdc05e8c8c37 100644 --- a/res/js/component/buffer.jsx +++ b/res/js/component/buffer.jsx @@ -1,5 +1,5 @@ class Buffer extends Component { - constructor(id, name, network, contextList = []) { + constructor(id, name, network, hasMore, contextList = []) { super(); this.id = id; @@ -9,6 +9,7 @@ class Buffer extends Component { this.render(); this.contextList.forEach((context) => this.insert(context)); + this.loadMoreBtn.setVisible(hasMore); } render() { @@ -21,11 +22,16 @@ class Buffer extends Component { <span className="close">{translation.buffer.close}</span> </button> </div> - {this.insertContainer = ( - <div className="container"> - {(this.loadMoreBtn = new LoadMore(translation.results.show_more, this.loadMore)).elem} - </div> - )} + <div className="container"> + {this.insertContainerFirst = ( + <div className="primary"/> + )} + {this.insertContainer = ( + <div className="secondary"> + </div> + )} + {(this.loadMoreBtn = new LoadMore(translation.results.show_more, this.loadMore)).elem} + </div> </div> ); } @@ -43,6 +49,7 @@ class Buffer extends Component { } insert(context) { - this.insertContainer.insertBefore(context.elem, this.loadMoreBtn.elem); + let container = (this.insertContainerFirst.childElementCount < 4 ? this.insertContainerFirst : this.insertContainer); + container.appendChild(context.elem); } } \ No newline at end of file diff --git a/res/js/component/context.jsx b/res/js/component/context.jsx index 877c7fa0341d74dc6f17a59ad90d0a87be3e4c3e..3a6b3b9173dae55255497c347086d8d26e6e7cb9 100644 --- a/res/js/component/context.jsx +++ b/res/js/component/context.jsx @@ -1,5 +1,5 @@ class Context { - constructor(preview, beforeList=[], afterList=[]) { + constructor(preview, beforeList = [], afterList = []) { this.preview = preview; this.beforeList = beforeList; this.afterList = afterList; diff --git a/res/js/component/history.js b/res/js/component/history.js index f7d4969dbf4d356ac0013c3159595245187a976a..fd147d944bffb4317f219b87753a0e0fb3c2e85b 100644 --- a/res/js/component/history.js +++ b/res/js/component/history.js @@ -7,7 +7,7 @@ class HistoryView { return new HistoryElement(query); }); this.render(); - this.elements.reverse().forEach(elem => this.insert(elem)); + this.insert(this.elements); } render() { return this.elem = function () { @@ -21,13 +21,17 @@ class HistoryView { return $$a; }.call(this); } - insert(item) { - this.list.insertBefore(item.elem, this.list.firstChild); - if (this.noHistory.elem.parentNode === this.list) + + insert(items) { + if (!(items instanceof Array)) + return this.insert([items]); + const anchor = this.list.firstChild; + items.forEach(item => this.list.insertBefore(item.elem, anchor)); + if (items.length && this.noHistory.elem.parentNode === this.list) this.list.removeChild(this.noHistory.elem); } add(item) { - if (item.query == '') + if (item.query === '') return; const idx = this.elements.map(item => item.query).indexOf(item.query); if (idx !== -1) { diff --git a/res/js/component/history.jsx b/res/js/component/history.jsx index 0a9c0897a9726bdd4880c025f7f1b6ebedcb33a0..b709b74230a88a4188fca3cbdece2a6b59c20db8 100644 --- a/res/js/component/history.jsx +++ b/res/js/component/history.jsx @@ -10,7 +10,7 @@ class HistoryView { }); this.render(); - this.elements.reverse().forEach((elem) => this.insert(elem)); + this.insert(this.elements); } render() { @@ -25,14 +25,18 @@ class HistoryView { ); } - insert(item) { - this.list.insertBefore(item.elem, this.list.firstChild); - if (this.noHistory.elem.parentNode === this.list) + insert(items) { + if (!(items instanceof Array)) + return this.insert([items]); + + const anchor = this.list.firstChild; + items.forEach(item => this.list.insertBefore(item.elem, anchor)); + if (items.length && this.noHistory.elem.parentNode === this.list) this.list.removeChild(this.noHistory.elem); } add(item) { - if (item.query == "") + if (item.query === "") return; const idx = this.elements.map((item) => item.query).indexOf(item.query); @@ -59,7 +63,7 @@ class HistoryView { load() { const loaded = localStorage[HISTORY_KEY]; - return JSON.parse(loaded===undefined ? "[]" : loaded); + return JSON.parse(loaded === undefined ? "[]" : loaded); } store() { diff --git a/res/js/component/historyelement.js b/res/js/component/historyelement.js index d08ccb1f9c372a929e609f2cfc45b4f74ce165d1..0925d89b7a36658d894fa5573d3ac3cff6ee5122 100644 --- a/res/js/component/historyelement.js +++ b/res/js/component/historyelement.js @@ -3,8 +3,10 @@ class HistoryElement { this.query = query; this.render(); this.elem.addEventListener('mousedown', event => { - statehandler.replace(this.query); - event.preventDefault(); + if (event.buttons === 0 || event.buttons === 1) { + statehandler.replace(this.query); + event.preventDefault(); + } }); } render() { diff --git a/res/js/component/historyelement.jsx b/res/js/component/historyelement.jsx index 047c6d728d0c9cb29fd66702ea51b2b866274620..bd6c56338a9dafac8ed01dfe6130d26e39edf942 100644 --- a/res/js/component/historyelement.jsx +++ b/res/js/component/historyelement.jsx @@ -4,8 +4,10 @@ class HistoryElement { this.render(); this.elem.addEventListener("mousedown", (event) => { - statehandler.replace(this.query); - event.preventDefault(); + if (event.buttons === 0 || event.buttons === 1) { + statehandler.replace(this.query); + event.preventDefault(); + } }); } diff --git a/res/js/util/component.js b/res/js/util/component.js index 9f0cb16a217824c1566322bb8e2aae3bca07f55d..2664d863571c645b58f53532d815bbb6dc29c18a 100644 --- a/res/js/util/component.js +++ b/res/js/util/component.js @@ -23,4 +23,9 @@ class Component { listener.apply(null, argv); }) } + + setVisible(value) { + if (this.elem) + this.elem.classList.toggle("hidden", !value); + } } \ No newline at end of file diff --git a/res/js/util/loader.js b/res/js/util/loader.js index b0efe4ffeb558c2aaff9d98613610f4b56513229..ec2e911f6f593b8c222d36385814803ac7c8940b 100644 --- a/res/js/util/loader.js +++ b/res/js/util/loader.js @@ -1,4 +1,4 @@ -function load(url, data=null) { +function load(url, data = null) { return new Promise((resolve, reject) => { const encodeData = (data) => { const result = []; @@ -11,7 +11,7 @@ function load(url, data=null) { }; const request = new XMLHttpRequest(); - const method = data===null ? "GET" : "POST"; + const method = data === null ? "GET" : "POST"; request.onreadystatechange = () => { if (request.readyState == 4) { if (request.status >= 200 && request.status < 300) { @@ -26,7 +26,7 @@ function load(url, data=null) { } }; request.open(method, url, true); - if (data!==null) { + if (data !== null) { request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); request.send(encodeData(data)); } else { diff --git a/res/js/util/mirccolorhandler.js b/res/js/util/mirccolorhandler.js index 25ca13f1b22e206387e134370ae4da5352ad6747..2dc8b90120b922656ac86f652f650e3e1ba20c6d 100644 --- a/res/js/util/mirccolorhandler.js +++ b/res/js/util/mirccolorhandler.js @@ -73,28 +73,28 @@ class MircColorHandler { for (let i = 0; i < str.length; i++) { const character = str.charAt(i); switch (character) { - case CODE_BOLD: { + case CODE_BOLD: { apply(lastTag, str, i, normalCount, nodes); normalCount = 0; state.bold = !state.bold; lastTag = fromState(state); } - break; - case CODE_ITALIC: { + break; + case CODE_ITALIC: { apply(lastTag, str, i, normalCount, nodes); normalCount = 0; state.italic = !state.italic; lastTag = fromState(state); } - break; - case CODE_UNDERLINE: { + break; + case CODE_UNDERLINE: { apply(lastTag, str, i, normalCount, nodes); normalCount = 0; state.underline = !state.underline; lastTag = fromState(state); } - break; - case CODE_COLOR: { + break; + case CODE_COLOR: { apply(lastTag, str, i, normalCount, nodes); normalCount = 0; let foregroundStart = i + 1; @@ -122,8 +122,8 @@ class MircColorHandler { lastTag = fromState(state); } } - break; - case CODE_SWAP: { + break; + case CODE_SWAP: { apply(lastTag, str, i, normalCount, nodes); normalCount = 0; if (state.foreground != null) { @@ -132,8 +132,8 @@ class MircColorHandler { lastTag = fromState(state); } } - break; - case CODE_RESET: { + break; + case CODE_RESET: { apply(lastTag, str, i, normalCount, nodes); normalCount = 0; state.bold = false; @@ -143,11 +143,11 @@ class MircColorHandler { state.background = null; lastTag = fromState(state); } - break; - default: { + break; + default: { normalCount++; } - break; + break; } } apply(lastTag, str, str.length, normalCount, nodes); @@ -155,6 +155,7 @@ class MircColorHandler { }; return formatString(text); } + static highlight(text) { let nodes = []; let highlight = false; diff --git a/res/js/util/nativejsx-prototypes.js b/res/js/util/nativejsx-prototypes.js index 02f4d782d7e65fe0815dde9787b3ea42e815b8cc..08cdd8e9b42075e1bb774bbfb67a6e16982402c4 100644 --- a/res/js/util/nativejsx-prototypes.js +++ b/res/js/util/nativejsx-prototypes.js @@ -1,163 +1,207 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; /******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 6); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -(function () { - if (typeof HTMLElement.prototype.appendChildren !== 'function') { - HTMLElement.prototype.appendChildren = function (children) { - return __webpack_require__(3)(this, children) - } - } -})() - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -(function () { - if (typeof HTMLElement.prototype.setAttributes !== 'function') { - HTMLElement.prototype.setAttributes = function (attributes) { - return __webpack_require__(4)(this, attributes) - } - } -})() - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -(function () { - if (typeof HTMLElement.prototype.setStyles !== 'function') { - HTMLElement.prototype.setStyles = function (styles) { - return __webpack_require__(5)(this, styles) - } - } -})() - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -module.exports = function appendChildren (element, children) { - children = Array.isArray(children) ? children : [children] - children.forEach(function (child) { - if (child instanceof HTMLElement) { - element.appendChild(child) - } else if (child || typeof child === 'string') { - element.appendChild(document.createTextNode(child.toString())) - } - }) -} - - -/***/ }), -/* 4 */ -/***/ (function(module, exports) { - -module.exports = function setAttributes (element, attributes) { - var isPlainObject = Object.prototype.toString.call(attributes) === '[object Object]' && - typeof attributes.constructor === 'function' && - Object.prototype.toString.call(attributes.constructor.prototype) === '[object Object]' && - attributes.constructor.prototype.hasOwnProperty('isPrototypeOf') - - if (isPlainObject) { - for (var key in attributes) { - element.setAttribute(key, attributes[key]) +(function (modules) { // webpackBootstrap + /******/ // The module cache + /******/ + var installedModules = {}; + /******/ + /******/ // The require function + /******/ + function __webpack_require__(moduleId) { + /******/ + /******/ // Check if module is in cache + /******/ + if (installedModules[moduleId]) + /******/ return installedModules[moduleId].exports; + /******/ + /******/ // Create a new module (and put it into the cache) + /******/ + var module = installedModules[moduleId] = { + /******/ i: moduleId, + /******/ l: false, + /******/ exports: {} + /******/ + }; + /******/ + /******/ // Execute the module function + /******/ + modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + /******/ + /******/ // Flag the module as loaded + /******/ + module.l = true; + /******/ + /******/ // Return the exports of the module + /******/ + return module.exports; + /******/ } - } else { - throw new DOMException('Failed to execute \'setAttributes\' on \'Element\': ' + Object.prototype.toString.call(attributes) + ' is not a plain object.') - } -} - - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - -module.exports = function setStyles (element, styles) { - for (var style in styles) element.style[style] = styles[style] -} - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -__webpack_require__(1) -__webpack_require__(2) -__webpack_require__(0) - - -/***/ }) -/******/ ]); \ No newline at end of file + /******/ + /******/ + /******/ // expose the modules object (__webpack_modules__) + /******/ + __webpack_require__.m = modules; + /******/ + /******/ // expose the module cache + /******/ + __webpack_require__.c = installedModules; + /******/ + /******/ // identity function for calling harmony imports with the correct context + /******/ + __webpack_require__.i = function (value) { + return value; + }; + /******/ + /******/ // define getter function for harmony exports + /******/ + __webpack_require__.d = function (exports, name, getter) { + /******/ + if (!__webpack_require__.o(exports, name)) { + /******/ + Object.defineProperty(exports, name, { + /******/ configurable: false, + /******/ enumerable: true, + /******/ get: getter + /******/ + }); + /******/ + } + /******/ + }; + /******/ + /******/ // getDefaultExport function for compatibility with non-harmony modules + /******/ + __webpack_require__.n = function (module) { + /******/ + var getter = module && module.__esModule ? + /******/ function getDefault() { + return module['default']; + } : + /******/ function getModuleExports() { + return module; + }; + /******/ + __webpack_require__.d(getter, 'a', getter); + /******/ + return getter; + /******/ + }; + /******/ + /******/ // Object.prototype.hasOwnProperty.call + /******/ + __webpack_require__.o = function (object, property) { + return Object.prototype.hasOwnProperty.call(object, property); + }; + /******/ + /******/ // __webpack_public_path__ + /******/ + __webpack_require__.p = ""; + /******/ + /******/ // Load entry module and return exports + /******/ + return __webpack_require__(__webpack_require__.s = 6); + /******/ +}) +/************************************************************************/ +/******/([ + /* 0 */ + /***/ (function (module, exports, __webpack_require__) { + + (function () { + if (typeof HTMLElement.prototype.appendChildren !== 'function') { + HTMLElement.prototype.appendChildren = function (children) { + return __webpack_require__(3)(this, children) + } + } + })() + + + /***/ + }), + /* 1 */ + /***/ (function (module, exports, __webpack_require__) { + + (function () { + if (typeof HTMLElement.prototype.setAttributes !== 'function') { + HTMLElement.prototype.setAttributes = function (attributes) { + return __webpack_require__(4)(this, attributes) + } + } + })() + + + /***/ + }), + /* 2 */ + /***/ (function (module, exports, __webpack_require__) { + + (function () { + if (typeof HTMLElement.prototype.setStyles !== 'function') { + HTMLElement.prototype.setStyles = function (styles) { + return __webpack_require__(5)(this, styles) + } + } + })() + + + /***/ + }), + /* 3 */ + /***/ (function (module, exports) { + + module.exports = function appendChildren(element, children) { + children = Array.isArray(children) ? children : [children] + children.forEach(function (child) { + if (child instanceof HTMLElement) { + element.appendChild(child) + } else if (child || typeof child === 'string') { + element.appendChild(document.createTextNode(child.toString())) + } + }) + } + + + /***/ + }), + /* 4 */ + /***/ (function (module, exports) { + + module.exports = function setAttributes(element, attributes) { + var isPlainObject = Object.prototype.toString.call(attributes) === '[object Object]' && + typeof attributes.constructor === 'function' && + Object.prototype.toString.call(attributes.constructor.prototype) === '[object Object]' && + attributes.constructor.prototype.hasOwnProperty('isPrototypeOf') + + if (isPlainObject) { + for (var key in attributes) { + element.setAttribute(key, attributes[key]) + } + } else { + throw new DOMException('Failed to execute \'setAttributes\' on \'Element\': ' + Object.prototype.toString.call(attributes) + ' is not a plain object.') + } + } + + + /***/ + }), + /* 5 */ + /***/ (function (module, exports) { + + module.exports = function setStyles(element, styles) { + for (var style in styles) element.style[style] = styles[style] + } + + + /***/ + }), + /* 6 */ + /***/ (function (module, exports, __webpack_require__) { + + __webpack_require__(1) + __webpack_require__(2) + __webpack_require__(0) + + + /***/ + }) + /******/]); \ No newline at end of file diff --git a/res/js/util/statehandler.js b/res/js/util/statehandler.js index 3115fd9838430d3a20d22350ecc7902bef6c20b7..b57dadf6b003a733fb601910550c524a139abb28 100644 --- a/res/js/util/statehandler.js +++ b/res/js/util/statehandler.js @@ -11,12 +11,12 @@ class StateHandler extends Component { } replace(value) { - history.replaceState(null, null, "#"+encodeURIComponent(value)); + history.replaceState(null, null, "#" + encodeURIComponent(value)); this.update(); } push(value) { - history.pushState(null, null, "#"+encodeURIComponent(value)); + history.pushState(null, null, "#" + encodeURIComponent(value)); this.update(); } diff --git a/web/backlog/index.php b/web/backlog/index.php index a70db8b3830021d27d7e69cca73d1ff62a03318c..eba903b2cdaf4aaf3cea4f43c6f1239ccf13a345 100644 --- a/web/backlog/index.php +++ b/web/backlog/index.php @@ -3,9 +3,9 @@ namespace QuasselRestSearch; require_once '../../qrs_config.php'; -require_once '../../backend/Database.php'; -require_once '../../backend/helper/RendererHelper.php'; -require_once '../../backend/helper/SessionHelper.php'; +require_once '../../database/Database.php'; +require_once '../../database/helper/RendererHelper.php'; +require_once '../../database/helper/SessionHelper.php'; $session = SessionHelper::getInstance(); $config = Config::createFromGlobals(); diff --git a/web/search/index.php b/web/search/index.php index dac580a0bf3413e7e324ce55bf85274d83fc3395..4e2b5342f27c7b360430055a9cc885530f801676 100644 --- a/web/search/index.php +++ b/web/search/index.php @@ -3,18 +3,31 @@ namespace QuasselRestSearch; require_once '../../qrs_config.php'; -require_once '../../backend/Database.php'; -require_once '../../backend/helper/RendererHelper.php'; -require_once '../../backend/helper/SessionHelper.php'; +require_once '../../database/Database.php'; +require_once '../../database/helper/RendererHelper.php'; +require_once '../../database/helper/SessionHelper.php'; $session = SessionHelper::getInstance(); $config = Config::createFromGlobals(); $renderer = new RendererHelper($config); $backend = Database::createFromConfig($config); +function param(string $key, $default = null) +{ + return array_key_exists($key, $_REQUEST) ? $_REQUEST[$key] : $default; +} + if (!$backend->authenticate($session->username ?: '', $session->password ?: '')) { $session->destroy(); $renderer->renderJsonError(false); } else { - $renderer->renderJson($backend->find($_REQUEST['query'] ?: "", $_REQUEST['since'] ?: null, $_REQUEST['before'] ?: null, $_REQUEST['buffer'] ?: null, $_REQUEST['network'] ?: null, 4)); + $renderer->renderJson($backend->find( + param('query', ""), + param('since'), + param('before'), + param('buffer'), + param('network'), + param('sender'), + param('limit', 4) + )); } \ No newline at end of file diff --git a/web/searchbuffer/index.php b/web/searchbuffer/index.php index ff679a7cf6cf88d5eb4fadfabbe0f3e099fecb63..9df1ab14fe3cb1e808a66f27deeaa7ae5c6db5df 100644 --- a/web/searchbuffer/index.php +++ b/web/searchbuffer/index.php @@ -3,18 +3,30 @@ namespace QuasselRestSearch; require_once '../../qrs_config.php'; -require_once '../../backend/Database.php'; -require_once '../../backend/helper/RendererHelper.php'; -require_once '../../backend/helper/SessionHelper.php'; +require_once '../../database/Database.php'; +require_once '../../database/helper/RendererHelper.php'; +require_once '../../database/helper/SessionHelper.php'; $session = SessionHelper::getInstance(); $config = Config::createFromGlobals(); $renderer = new RendererHelper($config); $backend = Database::createFromConfig($config); +function param(string $key, $default = null) +{ + return array_key_exists($key, $_REQUEST) ? $_REQUEST[$key] : $default; +} + if (!$backend->authenticate($session->username ?: '', $session->password ?: '')) { $session->destroy(); $renderer->renderJsonError(false); } else { - $renderer->renderJson($backend->findInBuffer($_REQUEST['query'] ?: "", $_REQUEST['since'] ?: null, $_REQUEST['before'] ?: null, $_REQUEST['buffer'] ?: 0, $_REQUEST['offset'] ?: 0, $_REQUEST['limit'] ?: 20)); + $renderer->renderJson($backend->findInBuffer( + param('query', ""), + param('since'), + param('before'), + param('buffer', 0), + param('offset', 0), + param('limit', 20) + )); } \ No newline at end of file