From 08fb912b9b8ee70987b2387e8df585322f747bc8 Mon Sep 17 00:00:00 2001 From: nertyog Date: Sun, 5 Jul 2026 22:31:44 +0300 Subject: [PATCH] Implement full support for OpenCart 2.0 - 2.2 with unified folder structures and cross-version templates/views --- Instruction ru-uk-en.txt | 8 +- install.xml | 95 +++++ poll_widget_nat_OC_20_22_1_0.ocmod.zip | Bin 0 -> 47502 bytes readme.txt | 2 +- .../controller/module/poll_widget_nat.php | 370 ++++++++++++++++++ .../language/en-gb/module/poll_widget_nat.php | 93 +++++ .../english/module/poll_widget_nat.php | 93 +++++ .../language/ru-ru/module/poll_widget_nat.php | 93 +++++ .../russian/module/poll_widget_nat.php | 93 +++++ .../language/uk-ua/module/poll_widget_nat.php | 90 +++++ .../ukrainian/module/poll_widget_nat.php | 90 +++++ upload/admin/model/module/poll_widget_nat.php | 163 ++++++++ .../template/module/poll_widget_nat_form.tpl | 352 +++++++++++++++++ .../template/module/poll_widget_nat_list.tpl | 224 +++++++++++ .../controller/module/poll_widget_nat.php | 210 ++++++++++ .../language/en-gb/module/poll_widget_nat.php | 6 + .../english/module/poll_widget_nat.php | 6 + .../language/ru-ru/module/poll_widget_nat.php | 6 + .../russian/module/poll_widget_nat.php | 6 + .../language/uk-ua/module/poll_widget_nat.php | 6 + .../ukrainian/module/poll_widget_nat.php | 6 + .../catalog/model/module/poll_widget_nat.php | 63 +++ .../template/module/poll_widget_nat.tpl | 196 ++++++++++ 23 files changed, 2266 insertions(+), 5 deletions(-) create mode 100644 install.xml create mode 100644 poll_widget_nat_OC_20_22_1_0.ocmod.zip create mode 100644 upload/admin/controller/module/poll_widget_nat.php create mode 100644 upload/admin/language/en-gb/module/poll_widget_nat.php create mode 100644 upload/admin/language/english/module/poll_widget_nat.php create mode 100644 upload/admin/language/ru-ru/module/poll_widget_nat.php create mode 100644 upload/admin/language/russian/module/poll_widget_nat.php create mode 100644 upload/admin/language/uk-ua/module/poll_widget_nat.php create mode 100644 upload/admin/language/ukrainian/module/poll_widget_nat.php create mode 100644 upload/admin/model/module/poll_widget_nat.php create mode 100644 upload/admin/view/template/module/poll_widget_nat_form.tpl create mode 100644 upload/admin/view/template/module/poll_widget_nat_list.tpl create mode 100644 upload/catalog/controller/module/poll_widget_nat.php create mode 100644 upload/catalog/language/en-gb/module/poll_widget_nat.php create mode 100644 upload/catalog/language/english/module/poll_widget_nat.php create mode 100644 upload/catalog/language/ru-ru/module/poll_widget_nat.php create mode 100644 upload/catalog/language/russian/module/poll_widget_nat.php create mode 100644 upload/catalog/language/uk-ua/module/poll_widget_nat.php create mode 100644 upload/catalog/language/ukrainian/module/poll_widget_nat.php create mode 100644 upload/catalog/model/module/poll_widget_nat.php create mode 100644 upload/catalog/view/theme/default/template/module/poll_widget_nat.tpl diff --git a/Instruction ru-uk-en.txt b/Instruction ru-uk-en.txt index ca6a12b..f7c9d5f 100644 --- a/Instruction ru-uk-en.txt +++ b/Instruction ru-uk-en.txt @@ -1,7 +1,7 @@ ============================================================================= Poll Widget [NAT] Version: 1.0.0 -Compatibility: OpenCart 3.0.x / ocStore 3.0.x +Compatibility: OpenCart 2.0.x - 2.2.x / ocStore 2.1.x - 2.2.x Author: NAT Contact: info@nat.od.ua ============================================================================= @@ -18,7 +18,7 @@ Poll Widget [NAT] — это функциональный модуль для с УСТАНОВКА: 1. Перейдите в панель управления OpenCart: "Модули / Расширения" -> "Установка расширений". -2. Загрузите архив `poll_widget_nat.ocmod.zip`. +2. Загрузите архив poll_widget_nat_OC_20_22_1_0.ocmod.zip. 3. Перейдите в "Модули / Расширения" -> "Модификаторы" и нажмите синюю кнопку "Обновить" (Очистить кэш). 4. Перейдите в "Система" -> "Пользователи" -> "Группы пользователей", выберите вашу группу (Administrator), нажмите "Выделить все" в правах просмотра и изменения, затем сохраните. 5. Перейдите в "Модули / Расширения" -> "Расширения" -> тип "Модули", найдите "Poll Widget [NAT]" и нажмите "Установить", а затем "Редактировать". @@ -52,7 +52,7 @@ Poll Widget [NAT] — це функціональний модуль для ст ВСТАНОВЛЕННЯ: 1. Перейдіть до панелі керування OpenCart: "Модулі / Розширення" -> "Встановлення розширень". -2. Завантажте архів `poll_widget_nat.ocmod.zip`. +2. Завантажте архів poll_widget_nat_OC_20_22_1_0.ocmod.zip. 3. Перейдіть до "Модулі / Розширення" -> "Модифікатори" і натисніть синю кнопку "Оновити". 4. Перейдіть до "Система" -> "Користувачі" -> "Групи користувачів", виберіть вашу групу (Administrator), натисніть "Виділити все" у правах перегляду та зміни, збережіть. 5. Перейдіть до "Модулі / Розширення" -> "Розширення" -> тип "Модулі", знайдіть "Poll Widget [NAT]", натисніть "Встановити", а потім "Редагувати". @@ -86,7 +86,7 @@ Poll Widget [NAT] is a powerful tool for creating responsive voting widgets and INSTALLATION: 1. Go to OpenCart admin panel: "Extensions" -> "Installer". -2. Upload the `poll_widget_nat.ocmod.zip` archive. +2. Upload the poll_widget_nat_OC_20_22_1_0.ocmod.zip archive. 3. Go to "Extensions" -> "Modifications" and click the blue "Refresh" button. 4. Go to "System" -> "Users" -> "User Groups", edit your group (Top Administrator), click "Select All" for Access and Modify permissions, then Save. 5. Go to "Extensions" -> "Extensions" -> choose "Modules", find "Poll Widget [NAT]", click "Install" and then "Edit". diff --git a/install.xml b/install.xml new file mode 100644 index 0000000..79937e1 --- /dev/null +++ b/install.xml @@ -0,0 +1,95 @@ + + + Poll Widget [NAT] + poll_widget_nat + poll_widget_nat_od_ua + 1.0.0 + NAT + mailto:info@nat.od.ua + + + + user->hasPermission('access', 'catalog/product')) {]]> + load->model('setting/setting'); + if ($this->config->get('module_poll_widget_nat_status')) { + $nat_pos = $this->config->get('module_poll_widget_nat_menu_position'); + if ($nat_pos == 'sidebar' || $nat_pos == 'both') { + if ($this->user->hasPermission('access', 'module/poll_widget_nat')) { + $nat_item = array( + 'name' => 'Poll Widget', + 'href' => $this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true), + 'children' => array() + ); + + $nat_menu_index = -1; + if (isset($data['menus'])) { + foreach ($data['menus'] as $k => $menu) { + if (isset($menu['id']) && $menu['id'] == 'menu-nat') { + $nat_menu_index = $k; + break; + } + } + } + + if ($nat_menu_index > -1) { + $data['menus'][$nat_menu_index]['children'][] = $nat_item; + } else { + $data['menus'][] = array( + 'id' => 'menu-nat', + 'icon' => 'fa-rocket fw', + 'name' => '[NAT] Modules', + 'href' => '', + 'children' => array($nat_item) + ); + } + } + } + } + ]]> + + + + + + url->link('common/logout']]> + load->model('setting/setting'); + if ($this->config->get('module_poll_widget_nat_status')) { + $nat_pos = $this->config->get('module_poll_widget_nat_menu_position'); + if ($nat_pos == 'header' || $nat_pos == 'both') { + if ($this->user->hasPermission('access', 'module/poll_widget_nat')) { + $data['nat_menus'][] = array( + 'name' => 'Poll Widget', + 'href' => $this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true) + ); + } + } + } + ]]> + + + + + + + + + + + ]]> + + + \ No newline at end of file diff --git a/poll_widget_nat_OC_20_22_1_0.ocmod.zip b/poll_widget_nat_OC_20_22_1_0.ocmod.zip new file mode 100644 index 0000000000000000000000000000000000000000..a5f9717f301819be8a1a654b4cd2b38cb937967d GIT binary patch literal 47502 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 literal 0 HcmV?d00001 diff --git a/readme.txt b/readme.txt index 6785ae1..30f1200 100644 --- a/readme.txt +++ b/readme.txt @@ -24,7 +24,7 @@ Poll Widget [NAT] is a powerful tool for creating responsive voting widgets and INSTALLATION: 1. Go to OpenCart admin panel: "Extensions" -> "Installer". -2. Upload the `poll_widget_nat_OC_30_1_0.ocmod.zip` archive. +2. Upload the `poll_widget_nat_OC_20_22_1_0.ocmod.zip` archive. 3. Go to "Extensions" -> "Modifications" and click the blue "Refresh" button. 4. Go to "System" -> "Users" -> "User Groups", edit your group (Top Administrator), click "Select All" for Access and Modify permissions, then Save. 5. Go to "Extensions" -> "Extensions" -> choose "Modules", find "Poll Widget [NAT]", click "Install" and then "Edit". diff --git a/upload/admin/controller/module/poll_widget_nat.php b/upload/admin/controller/module/poll_widget_nat.php new file mode 100644 index 0000000..eb66f96 --- /dev/null +++ b/upload/admin/controller/module/poll_widget_nat.php @@ -0,0 +1,370 @@ +db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "poll_widget_nat` ( + `poll_id` int(11) NOT NULL AUTO_INCREMENT, + `status` tinyint(1) NOT NULL DEFAULT '1', + `config` text NOT NULL, + `colors` text NOT NULL, + `custom_stats` text NOT NULL, + `date_added` datetime NOT NULL, + PRIMARY KEY (`poll_id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8;"); + + $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "poll_widget_nat_description` ( + `poll_id` int(11) NOT NULL, + `language_id` int(11) NOT NULL, + `question` varchar(255) NOT NULL, + `answers` text NOT NULL, + `thanks_text` text NOT NULL, + PRIMARY KEY (`poll_id`,`language_id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8;"); + + $this->db->query("CREATE TABLE IF NOT EXISTS `" . DB_PREFIX . "poll_widget_nat_vote` ( + `vote_id` int(11) NOT NULL AUTO_INCREMENT, + `poll_id` int(11) NOT NULL, + `answer_index` int(11) NOT NULL, + `customer_id` int(11) NOT NULL DEFAULT '0', + `ip` varchar(40) NOT NULL, + `user_agent` varchar(255) NOT NULL, + `page_url` text NOT NULL, + `date_added` datetime NOT NULL, + PRIMARY KEY (`vote_id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8;"); + + $this->load->model('setting/setting'); + $this->model_setting_setting->editSetting('module_poll_widget_nat', array( + 'module_poll_widget_nat_status' => 1, + 'module_poll_widget_nat_menu_position' => 'both' + )); + } + + public function uninstall() { + $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "poll_widget_nat`;"); + $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "poll_widget_nat_description`;"); + $this->db->query("DROP TABLE IF EXISTS `" . DB_PREFIX . "poll_widget_nat_vote`;"); + } + + private function checkLicense($key) { + if (empty($key)) return false; + $host = explode(':', str_replace(array('http://', 'https://', 'www.'), '', strtolower($this->request->server['HTTP_HOST'])))[0]; + $parts = explode('.', $host); + $v_core = '_redis'; + $v_end = 'aet_'; + $v_bit = '_lom'; + $v_to = 'to'; + $v_k = 'k'; + $v_mid = 'tot'; + $v_sfx = 'ka'; + + $salt = ($v_k . $v_to . $v_bit) . ($v_end . $v_mid) . ($v_core . $v_sfx); + while(count($parts) >= 2) { + $domain = implode('.', $parts); + if ($key === strtoupper(implode('-', str_split(substr(md5($domain . $salt), 0, 16), 4)))) return true; + array_shift($parts); + } + return false; + } + + public function index() { + $this->load->language('module/poll_widget_nat'); + $this->document->setTitle($this->language->get('heading_title_raw')); + $this->load->model('module/poll_widget_nat'); + $this->load->model('setting/setting'); + + if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) { + $this->model_setting_setting->editSetting('module_poll_widget_nat', $this->request->post); + $this->session->data['success'] = $this->language->get('text_success'); + $this->response->redirect($this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true)); + } + + $this->getList(); + } + + protected function getList() { + $data = array_merge(array(), $this->language->all()); + + $data['breadcrumbs'] = array(); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], true) + ); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_extension'), + 'href' => $this->url->link('extension/module', 'token=' . $this->session->data['token'], true) + ); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('heading_title_raw'), + 'href' => $this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true) + ); + + $data['action'] = $this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true); + $data['add'] = $this->url->link('module/poll_widget_nat/add', 'token=' . $this->session->data['token'], true); + $data['cancel'] = $this->url->link('extension/module', 'token=' . $this->session->data['token'], true); + + if (isset($this->request->post['module_poll_widget_nat_status'])) { + $data['module_poll_widget_nat_status'] = $this->request->post['module_poll_widget_nat_status']; + } else { + $data['module_poll_widget_nat_status'] = $this->config->get('module_poll_widget_nat_status'); + } + + if (isset($this->request->post['module_poll_widget_nat_license'])) { + $data['module_poll_widget_nat_license'] = $this->request->post['module_poll_widget_nat_license']; + } else { + $data['module_poll_widget_nat_license'] = $this->config->get('module_poll_widget_nat_license'); + } + + if (isset($this->request->post['module_poll_widget_nat_menu_position'])) { + $data['module_poll_widget_nat_menu_position'] = $this->request->post['module_poll_widget_nat_menu_position']; + } else { + $data['module_poll_widget_nat_menu_position'] = $this->config->get('module_poll_widget_nat_menu_position'); + } + + $data['is_licensed'] = $this->checkLicense($data['module_poll_widget_nat_license']); + + $data['polls'] = array(); + $results = $this->model_module_poll_widget_nat->getPolls(); + + foreach ($results as $result) { + $data['polls'][] = array( + 'poll_id' => (int)$result['poll_id'], + 'question'=> (string)$result['question'], + 'status' => ($result['status'] ? $this->language->get('text_enabled') : $this->language->get('text_disabled')), + 'edit' => $this->url->link('module/poll_widget_nat/edit', 'token=' . $this->session->data['token'] . '&poll_id=' . (int)$result['poll_id'], true), + 'delete' => $this->url->link('module/poll_widget_nat/delete', 'token=' . $this->session->data['token'] . '&poll_id=' . (int)$result['poll_id'], true) + ); + } + + if (isset($this->session->data['success'])) { + $data['success'] = $this->session->data['success']; + unset($this->session->data['success']); + } else { + $data['success'] = ''; + } + + if (isset($this->error['warning'])) { + $data['error_warning'] = $this->error['warning']; + } else { + $data['error_warning'] = ''; + } + + $data['header'] = $this->load->controller('common/header'); + $data['column_left'] = $this->load->controller('common/column_left'); + $data['footer'] = $this->load->controller('common/footer'); + + if (version_compare(VERSION, '2.2.0.0', '<')) { + $this->response->setOutput($this->load->view('module/poll_widget_nat_list.tpl', $data)); + } else { + $this->response->setOutput($this->load->view('module/poll_widget_nat_list', $data)); + } + } + + public function add() { + $this->load->language('module/poll_widget_nat'); + $this->document->setTitle($this->language->get('heading_title_raw')); + $this->load->model('module/poll_widget_nat'); + + if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validateForm()) { + $this->model_module_poll_widget_nat->addPoll($this->request->post); + $this->session->data['success'] = $this->language->get('text_success'); + $this->response->redirect($this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true)); + } + + $this->getForm(); + } + + public function edit() { + $this->load->language('module/poll_widget_nat'); + $this->document->setTitle($this->language->get('heading_title_raw')); + $this->load->model('module/poll_widget_nat'); + + if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validateForm()) { + $this->model_module_poll_widget_nat->editPoll((int)$this->request->get['poll_id'], $this->request->post); + $this->session->data['success'] = $this->language->get('text_success'); + $this->response->redirect($this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true)); + } + + $this->getForm(); + } + + public function delete() { + $this->load->language('module/poll_widget_nat'); + $this->load->model('module/poll_widget_nat'); + + if (isset($this->request->get['poll_id']) && $this->validate()) { + $this->model_module_poll_widget_nat->deletePoll((int)$this->request->get['poll_id']); + $this->session->data['success'] = $this->language->get('text_success'); + } + + $this->response->redirect($this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true)); + } + + protected function getForm() { + $data = array_merge(array(), $this->language->all()); + + if (isset($this->error['warning'])) { + $data['error_warning'] = $this->error['warning']; + } else { + $data['error_warning'] = ''; + } + + if (isset($this->error['question'])) { + $data['error_question'] = $this->error['question']; + } else { + $data['error_question'] = array(); + } + + $data['breadcrumbs'] = array(); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('text_home'), + 'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], true) + ); + $data['breadcrumbs'][] = array( + 'text' => $this->language->get('heading_title_raw'), + 'href' => $this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true) + ); + + if (!isset($this->request->get['poll_id'])) { + $poll_id = 0; + $data['action'] = $this->url->link('module/poll_widget_nat/add', 'token=' . $this->session->data['token'], true); + } else { + $poll_id = (int)$this->request->get['poll_id']; + $data['action'] = $this->url->link('module/poll_widget_nat/edit', 'token=' . $this->session->data['token'] . '&poll_id=' . $poll_id, true); + } + + $data['cancel'] = $this->url->link('module/poll_widget_nat', 'token=' . $this->session->data['token'], true); + + $poll_info = array(); + if ($poll_id && ($this->request->server['REQUEST_METHOD'] != 'POST')) { + $poll_info = $this->model_module_poll_widget_nat->getPoll($poll_id); + if ($poll_info) { + $poll_info['config'] = json_decode($poll_info['config'], true); + $poll_info['colors'] = json_decode($poll_info['colors'], true); + $poll_info['custom_stats'] = json_decode($poll_info['custom_stats'], true); + } + } + + $this->load->model('localisation/language'); + $data['languages'] = $this->model_localisation_language->getLanguages(); + + if (isset($this->request->post['poll_description'])) { + $data['poll_description'] = $this->request->post['poll_description']; + } elseif ($poll_id) { + $data['poll_description'] = $this->model_module_poll_widget_nat->getPollDescriptions($poll_id); + } else { + $data['poll_description'] = array(); + } + + $data['status'] = isset($this->request->post['status']) ? (int)$this->request->post['status'] : (!empty($poll_info) ? (int)$poll_info['status'] : 1); + $data['config'] = isset($this->request->post['config']) ? $this->request->post['config'] : (!empty($poll_info['config']) ? $poll_info['config'] : array()); + $data['custom_stats'] = isset($this->request->post['custom_stats']) ? $this->request->post['custom_stats'] : (!empty($poll_info['custom_stats']) ? $poll_info['custom_stats'] : array()); + + $default_colors = array( + 'bg' => '#ffffff', + 'text' => '#333333', + 'border' => '#e5e5e5', + 'btn_bg' => '#2980b9', + 'btn_color' => '#ffffff', + 'bar_bg' => '#eeeeee', + 'bar_fill' => '#2980b9' + ); + + if (isset($this->request->post['colors'])) { + $data['colors'] = $this->request->post['colors']; + } elseif (!empty($poll_info['colors'])) { + $data['colors'] = array_merge($default_colors, (array)$poll_info['colors']); + } else { + $data['colors'] = $default_colors; + } + + $answers_map = array(); + $current_lang_id = (int)$this->config->get('config_language_id'); + + if (isset($data['poll_description'][$current_lang_id])) { + $raw_answers = explode("\n", str_replace("\r", "", $data['poll_description'][$current_lang_id]['answers'])); + foreach ($raw_answers as $i => $text) { + if (trim($text)) { + $answers_map[$i] = trim($text); + } + } + } + + $data['answers_map'] = $answers_map; + + if (isset($this->request->get['page'])) { + $page = (int)$this->request->get['page']; + } else { + $page = 1; + } + + $limit = 15; + $data['voted_total'] = array(); + $data['latest_votes'] = array(); + $data['total_votes_count'] = 0; + + if ($poll_id) { + $data['voted_total'] = $this->model_module_poll_widget_nat->getVotesCountByIndex($poll_id); + $data['total_votes_count'] = $this->model_module_poll_widget_nat->getTotalVotes($poll_id); + + $results = $this->model_module_poll_widget_nat->getVotes($poll_id, ($page - 1) * $limit, $limit); + + foreach ($results as $result) { + $user_info = $result['customer_id'] ? $result['firstname'] . ' ' . $result['lastname'] . ' (' . $result['email'] . ')' : $this->language->get('text_guest'); + $answer_text = isset($answers_map[$result['answer_index']]) ? $answers_map[$result['answer_index']] : $this->language->get('text_answer_index') . ' ' . (int)$result['answer_index']; + + $data['latest_votes'][] = array( + 'answer' => $answer_text, + 'user' => $user_info, + 'ip' => $result['ip'], + 'page_url' => isset($result['page_url']) ? $result['page_url'] : '', + 'date' => date('d.m.Y H:i', strtotime($result['date_added'])) + ); + } + } + + $pagination = new Pagination(); + $pagination->total = $data['total_votes_count']; + $pagination->page = $page; + $pagination->limit = $limit; + $pagination->url = $this->url->link('module/poll_widget_nat/edit', 'token=' . $this->session->data['token'] . '&poll_id=' . $poll_id . '&page={page}', true); + + $data['pagination'] = $pagination->render(); + + $data['header'] = $this->load->controller('common/header'); + $data['column_left'] = $this->load->controller('common/column_left'); + $data['footer'] = $this->load->controller('common/footer'); + + if (version_compare(VERSION, '2.2.0.0', '<')) { + $this->response->setOutput($this->load->view('module/poll_widget_nat_form.tpl', $data)); + } else { + $this->response->setOutput($this->load->view('module/poll_widget_nat_form', $data)); + } + } + + protected function validate() { + if (!$this->user->hasPermission('modify', 'module/poll_widget_nat')) { + $this->error['warning'] = $this->language->get('error_permission'); + } + return !$this->error; + } + + protected function validateForm() { + if (!$this->user->hasPermission('modify', 'module/poll_widget_nat')) { + $this->error['warning'] = $this->language->get('error_permission'); + } + if (isset($this->request->post['poll_description']) && is_array($this->request->post['poll_description'])) { + foreach ($this->request->post['poll_description'] as $language_id => $value) { + if ((utf8_strlen($value['question']) < 3) || (utf8_strlen($value['question']) > 255)) { + $this->error['question'][$language_id] = $this->language->get('error_question'); + } + } + } else { + $this->error['warning'] = $this->language->get('error_form'); + } + return !$this->error; + } +} \ No newline at end of file diff --git a/upload/admin/language/en-gb/module/poll_widget_nat.php b/upload/admin/language/en-gb/module/poll_widget_nat.php new file mode 100644 index 0000000..e625736 --- /dev/null +++ b/upload/admin/language/en-gb/module/poll_widget_nat.php @@ -0,0 +1,93 @@ +Poll Widget [NAT]: Polls and Voting'; +$_['heading_title_raw'] = 'Poll Widget [NAT]: Polls and Voting'; +$_['text_extension'] = 'Extensions'; +$_['text_success'] = 'Module settings successfully updated!'; +$_['text_edit'] = 'Edit Poll'; +$_['text_add'] = 'Create Poll'; +$_['text_list'] = 'Poll List'; +$_['tab_general'] = 'General Settings'; +$_['tab_visual'] = 'Design & Colors'; +$_['tab_stats'] = 'Statistics'; +$_['tab_info'] = 'Info'; +$_['tab_polls'] = 'Polls'; +$_['entry_status'] = 'Status'; +$_['entry_question'] = 'Question'; +$_['entry_answers'] = 'Answers'; +$_['help_answers'] = 'Each answer on a new line.'; +$_['entry_thanks_text'] = 'Thank you text'; +$_['entry_guest'] = 'Guest voting'; +$_['entry_limit'] = 'Vote limit'; +$_['help_limit'] = 'How many times one user/IP can vote (0 - unlimited)'; +$_['entry_result_type'] = 'Results format'; +$_['text_res_percent'] = 'Percents (%)'; +$_['text_res_count'] = 'Vote count'; +$_['text_res_both'] = 'Both ( % / Count )'; +$_['text_res_none'] = 'Hide (thanks text only)'; +$_['entry_bg_color'] = 'Background'; +$_['entry_text_color'] = 'Text Color'; +$_['entry_border_color'] = 'Border Color'; +$_['entry_btn_bg'] = 'Button Background'; +$_['entry_btn_color'] = 'Button Text'; +$_['entry_bar_bg'] = 'Progress Bar BG'; +$_['entry_bar_fill'] = 'Progress Bar Fill'; +$_['column_question'] = 'Question'; +$_['column_status'] = 'Status'; +$_['column_action'] = 'Action'; +$_['text_stats_info'] = 'Statistics management: real data and manual adjustments.'; +$_['column_answer'] = 'Answer'; +$_['column_real'] = 'Real Votes'; +$_['column_custom'] = 'Adjust Stats (+/-)'; +$_['text_no_answers_yet'] = 'Fill in the answers and save the poll first!'; +$_['text_log_title'] = 'Vote Log (Total: %s)'; +$_['column_who'] = 'Who'; +$_['column_ip'] = 'IP'; +$_['column_page'] = 'Page'; +$_['column_date'] = 'Date'; +$_['text_answer_prefix'] = 'Answer:'; +$_['text_guest'] = 'Guest'; +$_['text_no_results'] = 'No data to display'; +$_['text_ecosystem'] = 'Ecosystem [NAT]'; +$_['text_catalog_opt_desc'] = 'Hide empty categories/brands + SEO sorting + DB cleanup.'; +$_['text_img_opt_desc'] = 'Compress originals to WebP + Mass cleanup of unused images.'; +$_['text_domain_scan_desc'] = 'Find and clean external links in DB (perfect for HTTPS transition).'; +$_['text_support_info'] = 'Support and suggestions:'; +$_['button_all_modules'] = 'View all [NAT] modules'; +$_['error_permission'] = 'You do not have permission to modify this module!'; +$_['error_question'] = 'Question must be between 3 and 255 characters!'; +$_['entry_license'] = 'License Key'; +$_['entry_show_total'] = 'Show "Total Votes"'; +$_['entry_total_access'] = 'Who can see total votes'; +$_['text_access_all'] = 'All visitors'; +$_['text_access_reg'] = 'Registered only'; +$_['text_footer_ecosystem'] = 'Developed for the [NAT] ecosystem. Support: info@nat.od.ua'; +$_['text_other_modules'] = 'Other modules in the [NAT] series:'; +$_['text_new_arrivals_title'] = 'New Arrivals [NAT]: True Sort by Date'; +$_['text_new_arrivals_desc'] = 'Automatic SEO page for new arrivals. Displays items strictly by actual added date. Sliders, grids, and smart date archive sidebar.'; +$_['text_catalog_opt_title'] = 'Catalog Optimizer [NAT]'; +$_['text_catalog_opt_desc'] = 'Hide empty categories/brands + SEO sorting (in-stock first) + DB garbage cleanup.'; +$_['text_img_opt_title'] = 'Image Optimizer [NAT]'; +$_['text_img_opt_desc'] = 'Original image compression to WebP + Mass cleanup of unused images on the server.'; +$_['text_domain_scan_title'] = 'Domain Scanner [NAT]'; +$_['text_domain_scan_desc'] = 'Search and clean external links and HTTP images in DB and theme files. Perfect for HTTPS migration or parsing cleanup.'; +$_['text_confirm_delete'] = 'Delete this poll? All votes will be permanently erased!'; +$_['text_license_warning'] = 'Enter a valid license key to activate the module.'; +$_['entry_menu_position'] = 'Admin Menu Position'; +$_['text_menu_module'] = 'Only in modules list'; +$_['text_menu_header'] = 'In Header (top panel)'; +$_['text_menu_sidebar'] = 'In Sidebar (left menu)'; +$_['text_menu_both'] = 'Both (Header + Sidebar)'; +$_['error_form'] = 'Please check the form carefully for errors!'; +$_['text_database_opt_title'] = 'Database Optimizer [NAT]'; +$_['text_database_opt_desc'] = 'Intelligent database garbage collection, system log management, and adding critical indexes for site speedup.'; +$_['text_admin_tools_title'] = 'Admin Tools [NAT]'; +$_['text_admin_tools_desc'] = 'Handy administrator tools: login as customer, admin customization, user permissions management, and hiding unnecessary menu items.'; +$_['text_easy_import_title'] = 'Easy Import/Export [NAT]'; +$_['text_easy_import_desc'] = 'Fast import/export of prices, stocks and products from XLS/XLSX/CSV/XML/JSON. Field mapping, Cron jobs and URL support.'; +$_['text_utm_tracker_title'] = 'Order UTM Tracker [NAT]'; +$_['text_utm_tracker_desc'] = 'Automatic tracking of UTM tags during checkout. Saves the traffic source, campaign, keywords, and displays this data in order details to analyze advertising effectiveness.'; +$_['text_poll_widget_title'] = 'Poll Widget [NAT]'; +$_['text_poll_widget_desc'] = 'Create polls and voting widgets with a visual design builder, detailed statistics, and fraud protection.'; +$_['text_current_module'] = 'Current module'; +$_['text_info_title_promo_top_bar'] = 'Promo Top Bar [NAT]: Upper promotional info-banner, information bar above header, marquee and top-banner'; +$_['text_info_desc_promo_top_bar'] = 'Create interactive promo bars and header slideshows with a block builder, countdown timers, subscription forms, and flexible targeting.'; \ No newline at end of file diff --git a/upload/admin/language/english/module/poll_widget_nat.php b/upload/admin/language/english/module/poll_widget_nat.php new file mode 100644 index 0000000..e625736 --- /dev/null +++ b/upload/admin/language/english/module/poll_widget_nat.php @@ -0,0 +1,93 @@ +Poll Widget [NAT]: Polls and Voting'; +$_['heading_title_raw'] = 'Poll Widget [NAT]: Polls and Voting'; +$_['text_extension'] = 'Extensions'; +$_['text_success'] = 'Module settings successfully updated!'; +$_['text_edit'] = 'Edit Poll'; +$_['text_add'] = 'Create Poll'; +$_['text_list'] = 'Poll List'; +$_['tab_general'] = 'General Settings'; +$_['tab_visual'] = 'Design & Colors'; +$_['tab_stats'] = 'Statistics'; +$_['tab_info'] = 'Info'; +$_['tab_polls'] = 'Polls'; +$_['entry_status'] = 'Status'; +$_['entry_question'] = 'Question'; +$_['entry_answers'] = 'Answers'; +$_['help_answers'] = 'Each answer on a new line.'; +$_['entry_thanks_text'] = 'Thank you text'; +$_['entry_guest'] = 'Guest voting'; +$_['entry_limit'] = 'Vote limit'; +$_['help_limit'] = 'How many times one user/IP can vote (0 - unlimited)'; +$_['entry_result_type'] = 'Results format'; +$_['text_res_percent'] = 'Percents (%)'; +$_['text_res_count'] = 'Vote count'; +$_['text_res_both'] = 'Both ( % / Count )'; +$_['text_res_none'] = 'Hide (thanks text only)'; +$_['entry_bg_color'] = 'Background'; +$_['entry_text_color'] = 'Text Color'; +$_['entry_border_color'] = 'Border Color'; +$_['entry_btn_bg'] = 'Button Background'; +$_['entry_btn_color'] = 'Button Text'; +$_['entry_bar_bg'] = 'Progress Bar BG'; +$_['entry_bar_fill'] = 'Progress Bar Fill'; +$_['column_question'] = 'Question'; +$_['column_status'] = 'Status'; +$_['column_action'] = 'Action'; +$_['text_stats_info'] = 'Statistics management: real data and manual adjustments.'; +$_['column_answer'] = 'Answer'; +$_['column_real'] = 'Real Votes'; +$_['column_custom'] = 'Adjust Stats (+/-)'; +$_['text_no_answers_yet'] = 'Fill in the answers and save the poll first!'; +$_['text_log_title'] = 'Vote Log (Total: %s)'; +$_['column_who'] = 'Who'; +$_['column_ip'] = 'IP'; +$_['column_page'] = 'Page'; +$_['column_date'] = 'Date'; +$_['text_answer_prefix'] = 'Answer:'; +$_['text_guest'] = 'Guest'; +$_['text_no_results'] = 'No data to display'; +$_['text_ecosystem'] = 'Ecosystem [NAT]'; +$_['text_catalog_opt_desc'] = 'Hide empty categories/brands + SEO sorting + DB cleanup.'; +$_['text_img_opt_desc'] = 'Compress originals to WebP + Mass cleanup of unused images.'; +$_['text_domain_scan_desc'] = 'Find and clean external links in DB (perfect for HTTPS transition).'; +$_['text_support_info'] = 'Support and suggestions:'; +$_['button_all_modules'] = 'View all [NAT] modules'; +$_['error_permission'] = 'You do not have permission to modify this module!'; +$_['error_question'] = 'Question must be between 3 and 255 characters!'; +$_['entry_license'] = 'License Key'; +$_['entry_show_total'] = 'Show "Total Votes"'; +$_['entry_total_access'] = 'Who can see total votes'; +$_['text_access_all'] = 'All visitors'; +$_['text_access_reg'] = 'Registered only'; +$_['text_footer_ecosystem'] = 'Developed for the [NAT] ecosystem. Support: info@nat.od.ua'; +$_['text_other_modules'] = 'Other modules in the [NAT] series:'; +$_['text_new_arrivals_title'] = 'New Arrivals [NAT]: True Sort by Date'; +$_['text_new_arrivals_desc'] = 'Automatic SEO page for new arrivals. Displays items strictly by actual added date. Sliders, grids, and smart date archive sidebar.'; +$_['text_catalog_opt_title'] = 'Catalog Optimizer [NAT]'; +$_['text_catalog_opt_desc'] = 'Hide empty categories/brands + SEO sorting (in-stock first) + DB garbage cleanup.'; +$_['text_img_opt_title'] = 'Image Optimizer [NAT]'; +$_['text_img_opt_desc'] = 'Original image compression to WebP + Mass cleanup of unused images on the server.'; +$_['text_domain_scan_title'] = 'Domain Scanner [NAT]'; +$_['text_domain_scan_desc'] = 'Search and clean external links and HTTP images in DB and theme files. Perfect for HTTPS migration or parsing cleanup.'; +$_['text_confirm_delete'] = 'Delete this poll? All votes will be permanently erased!'; +$_['text_license_warning'] = 'Enter a valid license key to activate the module.'; +$_['entry_menu_position'] = 'Admin Menu Position'; +$_['text_menu_module'] = 'Only in modules list'; +$_['text_menu_header'] = 'In Header (top panel)'; +$_['text_menu_sidebar'] = 'In Sidebar (left menu)'; +$_['text_menu_both'] = 'Both (Header + Sidebar)'; +$_['error_form'] = 'Please check the form carefully for errors!'; +$_['text_database_opt_title'] = 'Database Optimizer [NAT]'; +$_['text_database_opt_desc'] = 'Intelligent database garbage collection, system log management, and adding critical indexes for site speedup.'; +$_['text_admin_tools_title'] = 'Admin Tools [NAT]'; +$_['text_admin_tools_desc'] = 'Handy administrator tools: login as customer, admin customization, user permissions management, and hiding unnecessary menu items.'; +$_['text_easy_import_title'] = 'Easy Import/Export [NAT]'; +$_['text_easy_import_desc'] = 'Fast import/export of prices, stocks and products from XLS/XLSX/CSV/XML/JSON. Field mapping, Cron jobs and URL support.'; +$_['text_utm_tracker_title'] = 'Order UTM Tracker [NAT]'; +$_['text_utm_tracker_desc'] = 'Automatic tracking of UTM tags during checkout. Saves the traffic source, campaign, keywords, and displays this data in order details to analyze advertising effectiveness.'; +$_['text_poll_widget_title'] = 'Poll Widget [NAT]'; +$_['text_poll_widget_desc'] = 'Create polls and voting widgets with a visual design builder, detailed statistics, and fraud protection.'; +$_['text_current_module'] = 'Current module'; +$_['text_info_title_promo_top_bar'] = 'Promo Top Bar [NAT]: Upper promotional info-banner, information bar above header, marquee and top-banner'; +$_['text_info_desc_promo_top_bar'] = 'Create interactive promo bars and header slideshows with a block builder, countdown timers, subscription forms, and flexible targeting.'; \ No newline at end of file diff --git a/upload/admin/language/ru-ru/module/poll_widget_nat.php b/upload/admin/language/ru-ru/module/poll_widget_nat.php new file mode 100644 index 0000000..9ab18fb --- /dev/null +++ b/upload/admin/language/ru-ru/module/poll_widget_nat.php @@ -0,0 +1,93 @@ +Poll Widget [NAT]: Опросы и голосования'; +$_['heading_title_raw'] = 'Poll Widget [NAT]: Опросы и голосования'; +$_['text_extension'] = 'Расширения'; +$_['text_success'] = 'Настройки модуля успешно обновлены!'; +$_['text_edit'] = 'Редактирование опроса'; +$_['text_add'] = 'Создать опрос'; +$_['text_list'] = 'Список опросов'; +$_['tab_general'] = 'Основные настройки'; +$_['tab_visual'] = 'Дизайн и цвета'; +$_['tab_stats'] = 'Статистика и накрутка'; +$_['tab_info'] = 'Инфо'; +$_['tab_polls'] = 'Опросы'; +$_['entry_status'] = 'Статус'; +$_['entry_question'] = 'Вопрос'; +$_['entry_answers'] = 'Варианты ответов'; +$_['help_answers'] = 'Каждый вариант с новой строки.'; +$_['entry_thanks_text'] = 'Текст благодарности'; +$_['entry_guest'] = 'Голосование гостей'; +$_['entry_limit'] = 'Лимит голосов'; +$_['help_limit'] = 'Сколько раз может проголосовать один пользователь/IP (0 - без лимита)'; +$_['entry_result_type'] = 'Формат результатов'; +$_['text_res_percent'] = 'Проценты (%)'; +$_['text_res_count'] = 'Количество голосов'; +$_['text_res_both'] = 'Всё вместе ( % / Кол-во )'; +$_['text_res_none'] = 'Скрыть (только благодарность)'; +$_['entry_bg_color'] = 'Фон блока'; +$_['entry_text_color'] = 'Цвет текста'; +$_['entry_border_color'] = 'Цвет рамок'; +$_['entry_btn_bg'] = 'Цвет кнопки'; +$_['entry_btn_color'] = 'Текст кнопки'; +$_['entry_bar_bg'] = 'Фон полосы прогресса'; +$_['entry_bar_fill'] = 'Заливка полосы прогресса'; +$_['column_question'] = 'Вопрос'; +$_['column_status'] = 'Статус'; +$_['column_action'] = 'Действие'; +$_['text_stats_info'] = 'Управление статистикой: здесь отображаются реальные данные и возможность их корректировки.'; +$_['column_answer'] = 'Вариант ответа'; +$_['column_real'] = 'Реально'; +$_['column_custom'] = 'Управление статистикой (+/-)'; +$_['text_no_answers_yet'] = 'Сначала заполните варианты ответов и сохраните опрос!'; +$_['text_log_title'] = 'Журнал голосов (Всего: %s)'; +$_['column_who'] = 'Кто'; +$_['column_ip'] = 'IP'; +$_['column_page'] = 'Страница'; +$_['column_date'] = 'Дата'; +$_['text_answer_prefix'] = 'Ответ:'; +$_['text_guest'] = 'Guest'; +$_['text_no_results'] = 'Нет данных для отображения'; +$_['text_ecosystem'] = 'Экосистема [NAT]'; +$_['text_catalog_opt_desc'] = 'Скрытие пустых категорий и брендов + SEO сортировка товаров (в наличии сверху) + Очистка мусора БД.'; +$_['text_img_opt_desc'] = 'Сжатие оригиналов (image/catalog) в WebP + Массовая очистка хостинга от лишних картинок.'; +$_['text_domain_scan_desc'] = 'Поиск и чистка внешних ссылок и HTTP-картинок в описаниях БД (идеально для перехода на HTTPS).'; +$_['text_support_info'] = 'Техническая поддержка и пожелания:'; +$_['button_all_modules'] = 'Смотреть все модули [NAT]'; +$_['error_permission'] = 'У вас нет прав для управления этим модулем!'; +$_['error_question'] = 'Вопрос должен быть от 3 до 255 символов!'; +$_['entry_license'] = 'Лицензионный ключ'; +$_['entry_show_total'] = 'Показывать "Всего проголосовало"'; +$_['entry_total_access'] = 'Кто видит счетчик'; +$_['text_access_all'] = 'Все посетители'; +$_['text_access_reg'] = 'Только авторизованные'; +$_['text_footer_ecosystem'] = 'Разработано для экосистемы [NAT]. Поддержка: info@nat.od.ua'; +$_['text_other_modules'] = 'Другие модули серии [NAT]:'; +$_['text_new_arrivals_title'] = 'New Arrivals [NAT]: True Sort by Date'; +$_['text_new_arrivals_desc'] = 'Автоматическая SEO-страница новинок. Отображение товаров строго по реальной дате добавления. Слайдеры, сетки и умный сайдбар архива дат.'; +$_['text_catalog_opt_title'] = 'Catalog Optimizer [NAT]'; +$_['text_catalog_opt_desc'] = 'Скрытие пустых категорий и брендов + SEO сортировка товаров (в наличии сверху) + очистка мусора БД.'; +$_['text_img_opt_title'] = 'Image Optimizer [NAT]'; +$_['text_img_opt_desc'] = 'Сжатие оригинальных изображений в WebP + массовая очистка неиспользуемых изображений на сервере.'; +$_['text_domain_scan_title'] = 'Domain Scanner [NAT]'; +$_['text_domain_scan_desc'] = 'Поиск и очистка внешних ссылок и HTTP-изображений в БД и файлах темы. Идеально для перехода на HTTPS или очистки после парсинга.'; +$_['text_confirm_delete'] = 'Удалить этот опрос? Все голоса будут стерты!'; +$_['text_license_warning'] = 'Введите валидный лицензионный ключ для активации модуля и начала работы.'; +$_['entry_menu_position'] = 'Позиция в меню админки'; +$_['text_menu_module'] = 'Только в модулях'; +$_['text_menu_header'] = 'В шапке (верхняя панель)'; +$_['text_menu_sidebar'] = 'В боковом меню (слева)'; +$_['text_menu_both'] = 'Везде (Шапка + Сайдбар)'; +$_['error_form'] = 'Внимательно проверьте форму на наличие ошибок!'; +$_['text_database_opt_title'] = 'Database Optimizer [NAT]'; +$_['text_database_opt_desc'] = 'Интеллектуальная очистка мусора БД, управление системными логами и добавление критических индексов для ускорения сайта.'; +$_['text_admin_tools_title'] = 'Admin Tools [NAT]'; +$_['text_admin_tools_desc'] = 'Удобные инструменты администратора: вход под клиентом, кастомизация админки, управление правами и скрытие ненужных пунктов меню.'; +$_['text_easy_import_title'] = 'Easy Import/Export [NAT]'; +$_['text_easy_import_desc'] = 'Быстрый импорт/экспорт цен, остатков и товаров из XLS/XLSX/CSV/XML/JSON. Сопоставление полей, Cron и поддержка ссылок.'; +$_['text_utm_tracker_title'] = 'Order UTM Tracker [NAT]'; +$_['text_utm_tracker_desc'] = 'Автоматическое отслеживание UTM-меток при оформлении заказа. Сохраняет источник трафика, кампанию, ключевые слова и выводит эти данные в деталях заказа для анализа эффективности рекламы.'; +$_['text_poll_widget_title'] = 'Poll Widget [NAT]'; +$_['text_poll_widget_desc'] = 'Создание опросов и виджетов голосования с визуальным конструктором дизайна, детальной статистикой и защитой от накрутки.'; +$_['text_current_module'] = 'Текущий модуль'; +$_['text_info_title_promo_top_bar'] = 'Promo Top Bar [NAT]: Верхний рекламный инфо-баннер, информационная полоса над шапкой, бегущая строка и топ-баннер'; +$_['text_info_desc_promo_top_bar'] = 'Создание интерактивных промо-панелей и слайд-шоу в шапке сайта с конструктором блоков, таймерами, формой подписки и гибким таргетингом.'; \ No newline at end of file diff --git a/upload/admin/language/russian/module/poll_widget_nat.php b/upload/admin/language/russian/module/poll_widget_nat.php new file mode 100644 index 0000000..9ab18fb --- /dev/null +++ b/upload/admin/language/russian/module/poll_widget_nat.php @@ -0,0 +1,93 @@ +Poll Widget [NAT]: Опросы и голосования'; +$_['heading_title_raw'] = 'Poll Widget [NAT]: Опросы и голосования'; +$_['text_extension'] = 'Расширения'; +$_['text_success'] = 'Настройки модуля успешно обновлены!'; +$_['text_edit'] = 'Редактирование опроса'; +$_['text_add'] = 'Создать опрос'; +$_['text_list'] = 'Список опросов'; +$_['tab_general'] = 'Основные настройки'; +$_['tab_visual'] = 'Дизайн и цвета'; +$_['tab_stats'] = 'Статистика и накрутка'; +$_['tab_info'] = 'Инфо'; +$_['tab_polls'] = 'Опросы'; +$_['entry_status'] = 'Статус'; +$_['entry_question'] = 'Вопрос'; +$_['entry_answers'] = 'Варианты ответов'; +$_['help_answers'] = 'Каждый вариант с новой строки.'; +$_['entry_thanks_text'] = 'Текст благодарности'; +$_['entry_guest'] = 'Голосование гостей'; +$_['entry_limit'] = 'Лимит голосов'; +$_['help_limit'] = 'Сколько раз может проголосовать один пользователь/IP (0 - без лимита)'; +$_['entry_result_type'] = 'Формат результатов'; +$_['text_res_percent'] = 'Проценты (%)'; +$_['text_res_count'] = 'Количество голосов'; +$_['text_res_both'] = 'Всё вместе ( % / Кол-во )'; +$_['text_res_none'] = 'Скрыть (только благодарность)'; +$_['entry_bg_color'] = 'Фон блока'; +$_['entry_text_color'] = 'Цвет текста'; +$_['entry_border_color'] = 'Цвет рамок'; +$_['entry_btn_bg'] = 'Цвет кнопки'; +$_['entry_btn_color'] = 'Текст кнопки'; +$_['entry_bar_bg'] = 'Фон полосы прогресса'; +$_['entry_bar_fill'] = 'Заливка полосы прогресса'; +$_['column_question'] = 'Вопрос'; +$_['column_status'] = 'Статус'; +$_['column_action'] = 'Действие'; +$_['text_stats_info'] = 'Управление статистикой: здесь отображаются реальные данные и возможность их корректировки.'; +$_['column_answer'] = 'Вариант ответа'; +$_['column_real'] = 'Реально'; +$_['column_custom'] = 'Управление статистикой (+/-)'; +$_['text_no_answers_yet'] = 'Сначала заполните варианты ответов и сохраните опрос!'; +$_['text_log_title'] = 'Журнал голосов (Всего: %s)'; +$_['column_who'] = 'Кто'; +$_['column_ip'] = 'IP'; +$_['column_page'] = 'Страница'; +$_['column_date'] = 'Дата'; +$_['text_answer_prefix'] = 'Ответ:'; +$_['text_guest'] = 'Guest'; +$_['text_no_results'] = 'Нет данных для отображения'; +$_['text_ecosystem'] = 'Экосистема [NAT]'; +$_['text_catalog_opt_desc'] = 'Скрытие пустых категорий и брендов + SEO сортировка товаров (в наличии сверху) + Очистка мусора БД.'; +$_['text_img_opt_desc'] = 'Сжатие оригиналов (image/catalog) в WebP + Массовая очистка хостинга от лишних картинок.'; +$_['text_domain_scan_desc'] = 'Поиск и чистка внешних ссылок и HTTP-картинок в описаниях БД (идеально для перехода на HTTPS).'; +$_['text_support_info'] = 'Техническая поддержка и пожелания:'; +$_['button_all_modules'] = 'Смотреть все модули [NAT]'; +$_['error_permission'] = 'У вас нет прав для управления этим модулем!'; +$_['error_question'] = 'Вопрос должен быть от 3 до 255 символов!'; +$_['entry_license'] = 'Лицензионный ключ'; +$_['entry_show_total'] = 'Показывать "Всего проголосовало"'; +$_['entry_total_access'] = 'Кто видит счетчик'; +$_['text_access_all'] = 'Все посетители'; +$_['text_access_reg'] = 'Только авторизованные'; +$_['text_footer_ecosystem'] = 'Разработано для экосистемы [NAT]. Поддержка: info@nat.od.ua'; +$_['text_other_modules'] = 'Другие модули серии [NAT]:'; +$_['text_new_arrivals_title'] = 'New Arrivals [NAT]: True Sort by Date'; +$_['text_new_arrivals_desc'] = 'Автоматическая SEO-страница новинок. Отображение товаров строго по реальной дате добавления. Слайдеры, сетки и умный сайдбар архива дат.'; +$_['text_catalog_opt_title'] = 'Catalog Optimizer [NAT]'; +$_['text_catalog_opt_desc'] = 'Скрытие пустых категорий и брендов + SEO сортировка товаров (в наличии сверху) + очистка мусора БД.'; +$_['text_img_opt_title'] = 'Image Optimizer [NAT]'; +$_['text_img_opt_desc'] = 'Сжатие оригинальных изображений в WebP + массовая очистка неиспользуемых изображений на сервере.'; +$_['text_domain_scan_title'] = 'Domain Scanner [NAT]'; +$_['text_domain_scan_desc'] = 'Поиск и очистка внешних ссылок и HTTP-изображений в БД и файлах темы. Идеально для перехода на HTTPS или очистки после парсинга.'; +$_['text_confirm_delete'] = 'Удалить этот опрос? Все голоса будут стерты!'; +$_['text_license_warning'] = 'Введите валидный лицензионный ключ для активации модуля и начала работы.'; +$_['entry_menu_position'] = 'Позиция в меню админки'; +$_['text_menu_module'] = 'Только в модулях'; +$_['text_menu_header'] = 'В шапке (верхняя панель)'; +$_['text_menu_sidebar'] = 'В боковом меню (слева)'; +$_['text_menu_both'] = 'Везде (Шапка + Сайдбар)'; +$_['error_form'] = 'Внимательно проверьте форму на наличие ошибок!'; +$_['text_database_opt_title'] = 'Database Optimizer [NAT]'; +$_['text_database_opt_desc'] = 'Интеллектуальная очистка мусора БД, управление системными логами и добавление критических индексов для ускорения сайта.'; +$_['text_admin_tools_title'] = 'Admin Tools [NAT]'; +$_['text_admin_tools_desc'] = 'Удобные инструменты администратора: вход под клиентом, кастомизация админки, управление правами и скрытие ненужных пунктов меню.'; +$_['text_easy_import_title'] = 'Easy Import/Export [NAT]'; +$_['text_easy_import_desc'] = 'Быстрый импорт/экспорт цен, остатков и товаров из XLS/XLSX/CSV/XML/JSON. Сопоставление полей, Cron и поддержка ссылок.'; +$_['text_utm_tracker_title'] = 'Order UTM Tracker [NAT]'; +$_['text_utm_tracker_desc'] = 'Автоматическое отслеживание UTM-меток при оформлении заказа. Сохраняет источник трафика, кампанию, ключевые слова и выводит эти данные в деталях заказа для анализа эффективности рекламы.'; +$_['text_poll_widget_title'] = 'Poll Widget [NAT]'; +$_['text_poll_widget_desc'] = 'Создание опросов и виджетов голосования с визуальным конструктором дизайна, детальной статистикой и защитой от накрутки.'; +$_['text_current_module'] = 'Текущий модуль'; +$_['text_info_title_promo_top_bar'] = 'Promo Top Bar [NAT]: Верхний рекламный инфо-баннер, информационная полоса над шапкой, бегущая строка и топ-баннер'; +$_['text_info_desc_promo_top_bar'] = 'Создание интерактивных промо-панелей и слайд-шоу в шапке сайта с конструктором блоков, таймерами, формой подписки и гибким таргетингом.'; \ No newline at end of file diff --git a/upload/admin/language/uk-ua/module/poll_widget_nat.php b/upload/admin/language/uk-ua/module/poll_widget_nat.php new file mode 100644 index 0000000..9388c5d --- /dev/null +++ b/upload/admin/language/uk-ua/module/poll_widget_nat.php @@ -0,0 +1,90 @@ +Poll Widget [NAT]: Опитування та голосування'; +$_['heading_title_raw'] = 'Poll Widget [NAT]: Опитування та голосування'; +$_['text_extension'] = 'Розширення'; +$_['text_success'] = 'Налаштування модуля успішно оновлено!'; +$_['text_edit'] = 'Редагування опитування'; +$_['text_add'] = 'Створити опитування'; +$_['text_list'] = 'Список опитувань'; +$_['tab_general'] = 'Основні налаштування'; +$_['tab_visual'] = 'Дизайн та кольори'; +$_['tab_stats'] = 'Статистика'; +$_['tab_info'] = 'Інфо'; +$_['tab_polls'] = 'Опитування'; +$_['entry_status'] = 'Статус'; +$_['entry_question'] = 'Питання'; +$_['entry_answers'] = 'Варіанти відповідей'; +$_['help_answers'] = 'Кожен варіант з нового рядка.'; +$_['entry_thanks_text'] = 'Текст подяки'; +$_['entry_guest'] = 'Голосування гостей'; +$_['entry_limit'] = 'Ліміт голосів'; +$_['help_limit'] = 'Скільки разів може проголосувати один користувач/IP (0 - без ліміту)'; +$_['entry_result_type'] = 'Формат результатів'; +$_['text_res_percent'] = 'Відсотки (%)'; +$_['text_res_count'] = 'Кількість голосів'; +$_['text_res_both'] = 'Все разом ( % / Кіл-ть )'; +$_['text_res_none'] = 'Приховати (тільки подяка)'; +$_['entry_bg_color'] = 'Фон блоку'; +$_['entry_text_color'] = 'Колір тексту'; +$_['entry_border_color'] = 'Колір рамок'; +$_['entry_btn_bg'] = 'Колір кнопки'; +$_['entry_btn_color'] = 'Текст кнопки'; +$_['entry_bar_bg'] = 'Фон смуги прогресу'; +$_['entry_bar_fill'] = 'Заливка смуги прогресу'; +$_['column_question'] = 'Питання'; +$_['column_status'] = 'Статус'; +$_['column_action'] = 'Дія'; +$_['text_stats_info'] = 'Управління статистикою: реальні дані та можливість їх коригування.'; +$_['column_answer'] = 'Варіант відповіді'; +$_['column_real'] = 'Реально'; +$_['column_custom'] = 'Управління статистикою (+/-)'; +$_['text_no_answers_yet'] = 'Спочатку заповніть варіанти відповідей та збережіть опитування!'; +$_['text_log_title'] = 'Журнал голосів (Всього: %s)'; +$_['column_who'] = 'Хто'; +$_['column_ip'] = 'IP'; +$_['column_page'] = 'Сторінка'; +$_['column_date'] = 'Дата'; +$_['text_answer_prefix'] = 'Відповідь:'; +$_['text_guest'] = 'Guest'; +$_['text_no_results'] = 'Немає даних для відображення'; +$_['text_ecosystem'] = 'Екосистема [NAT]'; +$_['text_support_info'] = 'Технічна підтримка та побажання:'; +$_['button_all_modules'] = 'Дивитись усі модулі [NAT]'; +$_['error_permission'] = 'У вас немає прав для керування цим модулем!'; +$_['error_question'] = 'Питання має містити від 3 до 255 символів!'; +$_['entry_license'] = 'Ліцензійний ключ'; +$_['entry_show_total'] = 'Показувати "Всього проголосувало"'; +$_['entry_total_access'] = 'Хто бачить лічильник'; +$_['text_access_all'] = 'Всі відвідувачі'; +$_['text_access_reg'] = 'Тільки авторизовані'; +$_['text_footer_ecosystem'] = 'Розроблено для екосистеми [NAT]. Підтримка: info@nat.od.ua'; +$_['text_other_modules'] = 'Інші модулі серії [NAT]:'; +$_['text_new_arrivals_title'] = 'New Arrivals [NAT]: True Sort by Date'; +$_['text_new_arrivals_desc'] = 'Автоматична SEO-сторінка новинок. Відображення товарів суворо за реальною датою додавання. Слайдери, сітки та розумний сайдбар архіву дат.'; +$_['text_catalog_opt_title'] = 'Catalog Optimizer [NAT]'; +$_['text_catalog_opt_desc'] = 'Приховування порожніх категорій і брендів + SEO сортування товарів (в наявності зверху) + очищення сміття БД.'; +$_['text_img_opt_title'] = 'Image Optimizer [NAT]'; +$_['text_img_opt_desc'] = 'Стиснення оригінальних зображень у WebP + масове очищення невикористовуваних зображень на сервері.'; +$_['text_domain_scan_title'] = 'Domain Scanner [NAT]'; +$_['text_domain_scan_desc'] = 'Пошук та очищення зовнішніх посилань та HTTP-зображень у БД та файлах теми. Ідеально для переходу на HTTPS або очищення після парсингу.'; +$_['text_confirm_delete'] = 'Видалити це опитування? Всі голоси будуть стерті!'; +$_['text_license_warning'] = 'Введіть валідний ліцензійний ключ для активації модуля та початку роботи.'; +$_['entry_menu_position'] = 'Позиція в меню адмінки'; +$_['text_menu_module'] = 'Тільки в модулях'; +$_['text_menu_header'] = 'У шапці (верхня панель)'; +$_['text_menu_sidebar'] = 'У бічному меню (зліва)'; +$_['text_menu_both'] = 'Скрізь (Шапка + Сайдбар)'; +$_['error_form'] = 'Уважно перевірте форму на наявність помилок!'; +$_['text_database_opt_title'] = 'Database Optimizer [NAT]'; +$_['text_database_opt_desc'] = 'Інтелектуальне очищення сміття БД, керування системними логами та додавання критичних індексів для прискорення сайту.'; +$_['text_admin_tools_title'] = 'Admin Tools [NAT]'; +$_['text_admin_tools_desc'] = 'Зручні інструменти адміністратора: вхід під клієнтом, кастомізація адмінки, керування правами та приховування непотрібних пунктів меню.'; +$_['text_easy_import_title'] = 'Easy Import/Export [NAT]'; +$_['text_easy_import_desc'] = 'Швидкий імпорт/экспорт цін, залишків та товарів з XLS/XLSX/CSV/XML/JSON. Зіставлення полів, Cron та підтримка посилань.'; +$_['text_utm_tracker_title'] = 'Order UTM Tracker [NAT]'; +$_['text_utm_tracker_desc'] = 'Автоматичне відстеження UTM-міток при офомленні замовлення. Зберігає джерело трафіку, кампанію, кодові слова та виводить ці дані в деталях замовлення для аналізу ефективності реклами.'; +$_['text_poll_widget_title'] = 'Poll Widget [NAT]'; +$_['text_poll_widget_desc'] = 'Створення опитувань та віджетів голосування з візуальним конструктором дизайну, детальною статистикою та захистом від накрутки.'; +$_['text_current_module'] = 'Поточний модуль'; +$_['text_info_title_promo_top_bar'] = 'Promo Top Bar [NAT]: Верхній рекламний інфо-баннер, інформаційна смуга над шапкою, рухомий рядок та топ-баннер'; +$_['text_info_desc_promo_top_bar'] = 'Створення інтерактивних промо-панелей та слайд-шоу в шапці сайту з конструктором блоків, таймерами, формою підписки та гнучким націлюванням.'; \ No newline at end of file diff --git a/upload/admin/language/ukrainian/module/poll_widget_nat.php b/upload/admin/language/ukrainian/module/poll_widget_nat.php new file mode 100644 index 0000000..9388c5d --- /dev/null +++ b/upload/admin/language/ukrainian/module/poll_widget_nat.php @@ -0,0 +1,90 @@ +Poll Widget [NAT]: Опитування та голосування'; +$_['heading_title_raw'] = 'Poll Widget [NAT]: Опитування та голосування'; +$_['text_extension'] = 'Розширення'; +$_['text_success'] = 'Налаштування модуля успішно оновлено!'; +$_['text_edit'] = 'Редагування опитування'; +$_['text_add'] = 'Створити опитування'; +$_['text_list'] = 'Список опитувань'; +$_['tab_general'] = 'Основні налаштування'; +$_['tab_visual'] = 'Дизайн та кольори'; +$_['tab_stats'] = 'Статистика'; +$_['tab_info'] = 'Інфо'; +$_['tab_polls'] = 'Опитування'; +$_['entry_status'] = 'Статус'; +$_['entry_question'] = 'Питання'; +$_['entry_answers'] = 'Варіанти відповідей'; +$_['help_answers'] = 'Кожен варіант з нового рядка.'; +$_['entry_thanks_text'] = 'Текст подяки'; +$_['entry_guest'] = 'Голосування гостей'; +$_['entry_limit'] = 'Ліміт голосів'; +$_['help_limit'] = 'Скільки разів може проголосувати один користувач/IP (0 - без ліміту)'; +$_['entry_result_type'] = 'Формат результатів'; +$_['text_res_percent'] = 'Відсотки (%)'; +$_['text_res_count'] = 'Кількість голосів'; +$_['text_res_both'] = 'Все разом ( % / Кіл-ть )'; +$_['text_res_none'] = 'Приховати (тільки подяка)'; +$_['entry_bg_color'] = 'Фон блоку'; +$_['entry_text_color'] = 'Колір тексту'; +$_['entry_border_color'] = 'Колір рамок'; +$_['entry_btn_bg'] = 'Колір кнопки'; +$_['entry_btn_color'] = 'Текст кнопки'; +$_['entry_bar_bg'] = 'Фон смуги прогресу'; +$_['entry_bar_fill'] = 'Заливка смуги прогресу'; +$_['column_question'] = 'Питання'; +$_['column_status'] = 'Статус'; +$_['column_action'] = 'Дія'; +$_['text_stats_info'] = 'Управління статистикою: реальні дані та можливість їх коригування.'; +$_['column_answer'] = 'Варіант відповіді'; +$_['column_real'] = 'Реально'; +$_['column_custom'] = 'Управління статистикою (+/-)'; +$_['text_no_answers_yet'] = 'Спочатку заповніть варіанти відповідей та збережіть опитування!'; +$_['text_log_title'] = 'Журнал голосів (Всього: %s)'; +$_['column_who'] = 'Хто'; +$_['column_ip'] = 'IP'; +$_['column_page'] = 'Сторінка'; +$_['column_date'] = 'Дата'; +$_['text_answer_prefix'] = 'Відповідь:'; +$_['text_guest'] = 'Guest'; +$_['text_no_results'] = 'Немає даних для відображення'; +$_['text_ecosystem'] = 'Екосистема [NAT]'; +$_['text_support_info'] = 'Технічна підтримка та побажання:'; +$_['button_all_modules'] = 'Дивитись усі модулі [NAT]'; +$_['error_permission'] = 'У вас немає прав для керування цим модулем!'; +$_['error_question'] = 'Питання має містити від 3 до 255 символів!'; +$_['entry_license'] = 'Ліцензійний ключ'; +$_['entry_show_total'] = 'Показувати "Всього проголосувало"'; +$_['entry_total_access'] = 'Хто бачить лічильник'; +$_['text_access_all'] = 'Всі відвідувачі'; +$_['text_access_reg'] = 'Тільки авторизовані'; +$_['text_footer_ecosystem'] = 'Розроблено для екосистеми [NAT]. Підтримка: info@nat.od.ua'; +$_['text_other_modules'] = 'Інші модулі серії [NAT]:'; +$_['text_new_arrivals_title'] = 'New Arrivals [NAT]: True Sort by Date'; +$_['text_new_arrivals_desc'] = 'Автоматична SEO-сторінка новинок. Відображення товарів суворо за реальною датою додавання. Слайдери, сітки та розумний сайдбар архіву дат.'; +$_['text_catalog_opt_title'] = 'Catalog Optimizer [NAT]'; +$_['text_catalog_opt_desc'] = 'Приховування порожніх категорій і брендів + SEO сортування товарів (в наявності зверху) + очищення сміття БД.'; +$_['text_img_opt_title'] = 'Image Optimizer [NAT]'; +$_['text_img_opt_desc'] = 'Стиснення оригінальних зображень у WebP + масове очищення невикористовуваних зображень на сервері.'; +$_['text_domain_scan_title'] = 'Domain Scanner [NAT]'; +$_['text_domain_scan_desc'] = 'Пошук та очищення зовнішніх посилань та HTTP-зображень у БД та файлах теми. Ідеально для переходу на HTTPS або очищення після парсингу.'; +$_['text_confirm_delete'] = 'Видалити це опитування? Всі голоси будуть стерті!'; +$_['text_license_warning'] = 'Введіть валідний ліцензійний ключ для активації модуля та початку роботи.'; +$_['entry_menu_position'] = 'Позиція в меню адмінки'; +$_['text_menu_module'] = 'Тільки в модулях'; +$_['text_menu_header'] = 'У шапці (верхня панель)'; +$_['text_menu_sidebar'] = 'У бічному меню (зліва)'; +$_['text_menu_both'] = 'Скрізь (Шапка + Сайдбар)'; +$_['error_form'] = 'Уважно перевірте форму на наявність помилок!'; +$_['text_database_opt_title'] = 'Database Optimizer [NAT]'; +$_['text_database_opt_desc'] = 'Інтелектуальне очищення сміття БД, керування системними логами та додавання критичних індексів для прискорення сайту.'; +$_['text_admin_tools_title'] = 'Admin Tools [NAT]'; +$_['text_admin_tools_desc'] = 'Зручні інструменти адміністратора: вхід під клієнтом, кастомізація адмінки, керування правами та приховування непотрібних пунктів меню.'; +$_['text_easy_import_title'] = 'Easy Import/Export [NAT]'; +$_['text_easy_import_desc'] = 'Швидкий імпорт/экспорт цін, залишків та товарів з XLS/XLSX/CSV/XML/JSON. Зіставлення полів, Cron та підтримка посилань.'; +$_['text_utm_tracker_title'] = 'Order UTM Tracker [NAT]'; +$_['text_utm_tracker_desc'] = 'Автоматичне відстеження UTM-міток при офомленні замовлення. Зберігає джерело трафіку, кампанію, кодові слова та виводить ці дані в деталях замовлення для аналізу ефективності реклами.'; +$_['text_poll_widget_title'] = 'Poll Widget [NAT]'; +$_['text_poll_widget_desc'] = 'Створення опитувань та віджетів голосування з візуальним конструктором дизайну, детальною статистикою та захистом від накрутки.'; +$_['text_current_module'] = 'Поточний модуль'; +$_['text_info_title_promo_top_bar'] = 'Promo Top Bar [NAT]: Верхній рекламний інфо-баннер, інформаційна смуга над шапкою, рухомий рядок та топ-баннер'; +$_['text_info_desc_promo_top_bar'] = 'Створення інтерактивних промо-панелей та слайд-шоу в шапці сайту з конструктором блоків, таймерами, формою підписки та гнучким націлюванням.'; \ No newline at end of file diff --git a/upload/admin/model/module/poll_widget_nat.php b/upload/admin/model/module/poll_widget_nat.php new file mode 100644 index 0000000..72d3cd2 --- /dev/null +++ b/upload/admin/model/module/poll_widget_nat.php @@ -0,0 +1,163 @@ +db->escape(json_encode($data['config'])); + $colors = $this->db->escape(json_encode($data['colors'])); + $custom_stats = $this->db->escape(json_encode($data['custom_stats'])); + + $this->db->query("INSERT INTO `" . DB_PREFIX . "poll_widget_nat` SET status = '" . $status . "', config = '" . $config . "', colors = '" . $colors . "', custom_stats = '" . $custom_stats . "', date_added = NOW()"); + + $poll_id = $this->db->getLastId(); + + if (isset($data['poll_description']) && is_array($data['poll_description'])) { + foreach ($data['poll_description'] as $language_id => $value) { + $q = $this->db->escape((string)$value['question']); + $a = $this->db->escape((string)$value['answers']); + $t_text = $this->db->escape((string)$value['thanks_text']); + + $this->db->query("INSERT INTO `" . DB_PREFIX . "poll_widget_nat_description` SET poll_id = '" . (int)$poll_id . "', language_id = '" . (int)$language_id . "', question = '" . $q . "', answers = '" . $a . "', thanks_text = '" . $t_text . "'"); + } + } + + $lang_id = (int)$this->config->get('config_language_id'); + $name = isset($data['poll_description'][$lang_id]['question']) ? (string)$data['poll_description'][$lang_id]['question'] : 'Опрос #' . $poll_id; + + $setting = array( + 'name' => $name, + 'poll_id' => $poll_id, + 'status' => $status + ); + + $this->db->query("INSERT INTO `" . DB_PREFIX . "module` SET `name` = '" . $this->db->escape($name) . "', `code` = 'poll_widget_nat', `setting` = '" . $this->db->escape(json_encode($setting)) . "'"); + + return $poll_id; + } + + public function editPoll($poll_id, $data) { + $poll_id = (int)$poll_id; + $status = (int)$data['status']; + $config = $this->db->escape(json_encode($data['config'])); + $colors = $this->db->escape(json_encode($data['colors'])); + $custom_stats = $this->db->escape(json_encode($data['custom_stats'])); + + $this->db->query("UPDATE `" . DB_PREFIX . "poll_widget_nat` SET status = '" . $status . "', config = '" . $config . "', colors = '" . $colors . "', custom_stats = '" . $custom_stats . "' WHERE poll_id = '" . $poll_id . "'"); + + $this->db->query("DELETE FROM `" . DB_PREFIX . "poll_widget_nat_description` WHERE poll_id = '" . $poll_id . "'"); + + if (isset($data['poll_description']) && is_array($data['poll_description'])) { + foreach ($data['poll_description'] as $language_id => $value) { + $q = $this->db->escape((string)$value['question']); + $a = $this->db->escape((string)$value['answers']); + $t_text = $this->db->escape((string)$value['thanks_text']); + + $this->db->query("INSERT INTO `" . DB_PREFIX . "poll_widget_nat_description` SET poll_id = '" . $poll_id . "', language_id = '" . (int)$language_id . "', question = '" . $q . "', answers = '" . $a . "', thanks_text = '" . $t_text . "'"); + } + } + + $lang_id = (int)$this->config->get('config_language_id'); + $name = isset($data['poll_description'][$lang_id]['question']) ? (string)$data['poll_description'][$lang_id]['question'] : 'Опрос #' . $poll_id; + + $setting = array( + 'name' => $name, + 'poll_id' => $poll_id, + 'status' => $status + ); + + $module_query = $this->db->query("SELECT module_id, setting FROM `" . DB_PREFIX . "module` WHERE `code` = 'poll_widget_nat'"); + $found = false; + + foreach ($module_query->rows as $row) { + $mod_setting = json_decode($row['setting'], true); + if (isset($mod_setting['poll_id']) && (int)$mod_setting['poll_id'] === $poll_id) { + $this->db->query("UPDATE `" . DB_PREFIX . "module` SET `name` = '" . $this->db->escape($name) . "', `setting` = '" . $this->db->escape(json_encode($setting)) . "' WHERE module_id = '" . (int)$row['module_id'] . "'"); + $found = true; + break; + } + } + + if (!$found) { + $this->db->query("INSERT INTO `" . DB_PREFIX . "module` SET `name` = '" . $this->db->escape($name) . "', `code` = 'poll_widget_nat', `setting` = '" . $this->db->escape(json_encode($setting)) . "'"); + } + } + + public function deletePoll($poll_id) { + $poll_id = (int)$poll_id; + $this->db->query("DELETE FROM `" . DB_PREFIX . "poll_widget_nat` WHERE poll_id = '" . $poll_id . "'"); + $this->db->query("DELETE FROM `" . DB_PREFIX . "poll_widget_nat_description` WHERE poll_id = '" . $poll_id . "'"); + $this->db->query("DELETE FROM `" . DB_PREFIX . "poll_widget_nat_vote` WHERE poll_id = '" . $poll_id . "'"); + + $module_query = $this->db->query("SELECT module_id, setting FROM `" . DB_PREFIX . "module` WHERE `code` = 'poll_widget_nat'"); + foreach ($module_query->rows as $row) { + $mod_setting = json_decode($row['setting'], true); + if (isset($mod_setting['poll_id']) && (int)$mod_setting['poll_id'] === $poll_id) { + $mod_id = (int)$row['module_id']; + $this->db->query("DELETE FROM `" . DB_PREFIX . "module` WHERE module_id = '" . $mod_id . "'"); + $this->db->query("DELETE FROM `" . DB_PREFIX . "layout_module` WHERE `code` = 'poll_widget_nat." . $mod_id . "'"); + break; + } + } + } + + public function getPoll($poll_id) { + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "poll_widget_nat` WHERE poll_id = '" . (int)$poll_id . "'"); + return $query->row; + } + + public function getPollDescriptions($poll_id) { + $poll_description_data = array(); + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "poll_widget_nat_description` WHERE poll_id = '" . (int)$poll_id . "'"); + + foreach ($query->rows as $result) { + $poll_description_data[$result['language_id']] = array( + 'question' => $result['question'], + 'answers' => $result['answers'], + 'thanks_text' => $result['thanks_text'] + ); + } + + return $poll_description_data; + } + + public function getPolls() { + $lang_id = (int)$this->config->get('config_language_id'); + $sql = "SELECT p.poll_id, pd.question, p.status FROM `" . DB_PREFIX . "poll_widget_nat` p LEFT JOIN `" . DB_PREFIX . "poll_widget_nat_description` pd ON (p.poll_id = pd.poll_id) WHERE pd.language_id = '" . $lang_id . "' ORDER BY p.date_added DESC"; + $query = $this->db->query($sql); + return $query->rows; + } + + public function getVotes($poll_id, $start = 0, $limit = 10) { + $poll_id = (int)$poll_id; + $start = (int)$start; + $limit = (int)$limit; + + if ($start < 0) { + $start = 0; + } + if ($limit < 1) { + $limit = 10; + } + + $sql = "SELECT v.*, c.firstname, c.lastname, c.email FROM `" . DB_PREFIX . "poll_widget_nat_vote` v LEFT JOIN `" . DB_PREFIX . "customer` c ON (v.customer_id = c.customer_id) WHERE v.poll_id = '" . $poll_id . "' ORDER BY v.date_added DESC LIMIT " . $start . "," . $limit; + $query = $this->db->query($sql); + return $query->rows; + } + + public function getTotalVotes($poll_id) { + $query = $this->db->query("SELECT COUNT(*) AS total FROM `" . DB_PREFIX . "poll_widget_nat_vote` WHERE poll_id = '" . (int)$poll_id . "'"); + return (int)$query->row['total']; + } + + public function getVotesCountByIndex($poll_id) { + $vote_data = array(); + $query = $this->db->query("SELECT answer_index, COUNT(*) AS total FROM `" . DB_PREFIX . "poll_widget_nat_vote` WHERE poll_id = '" . (int)$poll_id . "' GROUP BY answer_index"); + + foreach ($query->rows as $result) { + $vote_data[(int)$result['answer_index']] = (int)$result['total']; + } + + return $vote_data; + } +} \ No newline at end of file diff --git a/upload/admin/view/template/module/poll_widget_nat_form.tpl b/upload/admin/view/template/module/poll_widget_nat_form.tpl new file mode 100644 index 0000000..91be029 --- /dev/null +++ b/upload/admin/view/template/module/poll_widget_nat_form.tpl @@ -0,0 +1,352 @@ + +
+ +
+ +
+ +
+ +
+
+

+
+
+
+ + + +
+
+
+ +
+ +
+
+ + + +
+ +
+
+ +
+ + +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ $entry_bg_color, + 'text' => $entry_text_color, + 'border' => $entry_border_color, + 'btn_bg' => $entry_btn_bg, + 'btn_color' => $entry_btn_color, + 'bar_bg' => $entry_bar_bg, + 'bar_fill' => $entry_bar_fill + ); + ?> + + $label) { ?> +
+ +
+
+ + + + +
+
+
+ +
+ +
+
+
+
+ + + + + + + + + + + $text) { ?> + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ + + + - + +
+
+
+
+
+
+ +
+
+ +
+ +
+
+
+

+

+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
+

+

+
+
+
+ + +
+ +
+
+
+ +
+
+
+ + \ No newline at end of file diff --git a/upload/admin/view/template/module/poll_widget_nat_list.tpl b/upload/admin/view/template/module/poll_widget_nat_list.tpl new file mode 100644 index 0000000..d701cb1 --- /dev/null +++ b/upload/admin/view/template/module/poll_widget_nat_list.tpl @@ -0,0 +1,224 @@ + +
+ +
+ +
+ +
+ + +
+ +
+ +
+
+

+
+
+ + + +
+
+
+
+
+
+ +
+ + + + +
+
+
+
+
+ +
+ + + + +
+
+
+
+
+ +
+ + + + + + + + + + + +
+
+
+
+ +
+
+
+ +
+
+
+ +
+ +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ +
+ +
+
+ +
+ +
+
+
+

+

+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+
+

+

+
+
+
+
+
+
+

+

+
+
+
+ + +
+ +
+ +
+ +
+
+
+ \ No newline at end of file diff --git a/upload/catalog/controller/module/poll_widget_nat.php b/upload/catalog/controller/module/poll_widget_nat.php new file mode 100644 index 0000000..f78972f --- /dev/null +++ b/upload/catalog/controller/module/poll_widget_nat.php @@ -0,0 +1,210 @@ +load->model('module/poll_widget_nat'); + $this->load->language('module/poll_widget_nat'); + + $poll_info = $this->model_module_poll_widget_nat->getPoll($poll_id); + if (!$poll_info) { + return false; + } + + $description = $this->model_module_poll_widget_nat->getPollDescription($poll_id); + if (!$description) { + return false; + } + + $data['poll_id'] = (int)$poll_info['poll_id']; + $data['question'] = (string)$description['question']; + $data['colors'] = is_array($poll_info['colors']) ? $poll_info['colors'] : array(); + $data['config'] = is_array($poll_info['config']) ? $poll_info['config'] : array(); + + $data['button_vote'] = $this->language->get('button_vote'); + $data['error_select'] = $this->language->get('error_select'); + + $answers_raw = explode("\n", str_replace("\r", "", $description['answers'])); + $data['answers'] = array(); + + if (!empty($answers_raw) && is_array($answers_raw)) { + foreach ($answers_raw as $index => $text) { + $text = trim((string)$text); + if ($text !== '') { + $data['answers'][] = array( + 'index' => (int)$index, + 'text' => $text + ); + } + } + } + + $limit = isset($poll_info['config']['limit']) ? (int)$poll_info['config']['limit'] : 0; + $data['voted'] = $this->model_module_poll_widget_nat->checkVoted($data['poll_id'], $limit); + + $data['show_total'] = false; + $data['total_votes'] = 0; + $data['text_total_votes'] = $this->language->get('text_total_votes'); + + if (isset($poll_info['config']['show_total']) && $poll_info['config']['show_total']) { + $access = isset($poll_info['config']['total_access']) ? (string)$poll_info['config']['total_access'] : 'all'; + + if ($access === 'all' || ($access === 'registered' && $this->customer->isLogged())) { + $data['show_total'] = true; + $results_data = $this->getResultsData($poll_info, $data['answers']); + + if (!empty($results_data) && is_array($results_data)) { + foreach ($results_data as $res) { + $data['total_votes'] += (int)$res['count']; + } + } + } + } + + if ($data['voted']) { + $data['results'] = $this->getResultsData($poll_info, $data['answers']); + $data['thanks_text'] = (string)$description['thanks_text']; + } else { + $data['results'] = array(); + $data['thanks_text'] = ''; + } + + if (version_compare(VERSION, '2.2.0.0', '<')) { + if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/poll_widget_nat.tpl')) { + return $this->load->view($this->config->get('config_template') . '/template/module/poll_widget_nat.tpl', $data); + } else { + return $this->load->view('default/template/module/poll_widget_nat.tpl', $data); + } + } else { + return $this->load->view('module/poll_widget_nat', $data); + } + } + + public function vote() { + $json = array(); + + if ($this->request->server['REQUEST_METHOD'] != 'POST') { + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode(array('error' => 'Invalid request'))); + return; + } + + $this->load->model('module/poll_widget_nat'); + $this->load->language('module/poll_widget_nat'); + + $poll_id = isset($this->request->post['poll_id']) ? (int)$this->request->post['poll_id'] : 0; + $answer_index = isset($this->request->post['answer_index']) ? (int)$this->request->post['answer_index'] : -1; + + $page_url = ''; + if (isset($this->request->post['page_url'])) { + $page_url = strip_tags(html_entity_decode((string)$this->request->post['page_url'], ENT_QUOTES, 'UTF-8')); + $page_url = mb_substr($page_url, 0, 500); + } + + $poll_info = $this->model_module_poll_widget_nat->getPoll($poll_id); + + if ($poll_info && $answer_index !== -1) { + $limit = isset($poll_info['config']['limit']) ? (int)$poll_info['config']['limit'] : 0; + $voted = $this->model_module_poll_widget_nat->checkVoted($poll_id, $limit); + + if (!$voted) { + $guest_allowed = !empty($poll_info['config']['guest']); + if (!$this->customer->isLogged() && !$guest_allowed) { + $json['error'] = $this->language->get('error_guest'); + } else { + $this->model_module_poll_widget_nat->addVote($poll_id, $answer_index, $page_url); + + $description = $this->model_module_poll_widget_nat->getPollDescription($poll_id); + $answers_raw = explode("\n", str_replace("\r", "", $description['answers'])); + $answers = array(); + + if (!empty($answers_raw) && is_array($answers_raw)) { + foreach ($answers_raw as $i => $t) { + $t = trim((string)$t); + if ($t !== '') { + $answers[] = array('index' => (int)$i, 'text' => $t); + } + } + } + + $json['success'] = true; + $json['thanks_text'] = (string)$description['thanks_text']; + $json['results'] = $this->getResultsData($poll_info, $answers); + $json['result_type'] = isset($poll_info['config']['result_type']) ? (string)$poll_info['config']['result_type'] : 'none'; + + $total_votes = 0; + if (!empty($json['results']) && is_array($json['results'])) { + foreach ($json['results'] as $res) { + $total_votes += (int)$res['count']; + } + } + $json['total_votes'] = $total_votes; + $json['text_total_votes'] = $this->language->get('text_total_votes'); + } + } else { + $json['error'] = $this->language->get('error_voted'); + } + } else { + $json['error'] = $this->language->get('error_select'); + } + + $this->response->addHeader('Content-Type: application/json'); + $this->response->setOutput(json_encode($json)); + } + + private function getResultsData($poll_info, $answers) { + $poll_id = isset($poll_info['poll_id']) ? (int)$poll_info['poll_id'] : 0; + $votes = $this->model_module_poll_widget_nat->getPollResults($poll_id); + + if (!is_array($votes)) { + $votes = array(); + } + + if (isset($poll_info['custom_stats']) && is_array($poll_info['custom_stats'])) { + foreach ($poll_info['custom_stats'] as $index => $count) { + $idx = (int)$index; + $cnt = (int)$count; + + $answer_exists = false; + foreach ($answers as $ans) { + if ($ans['index'] === $idx) { + $answer_exists = true; + break; + } + } + + if ($answer_exists) { + if (!isset($votes[$idx])) { + $votes[$idx] = 0; + } + $votes[$idx] += $cnt; + } + } + } + + $total_sum = is_array($votes) ? array_sum($votes) : 0; + $data = array(); + + if (!empty($answers) && is_array($answers)) { + foreach ($answers as $answer) { + $ans_idx = (int)$answer['index']; + $count = isset($votes[$ans_idx]) ? (int)$votes[$ans_idx] : 0; + $percent = ($total_sum > 0) ? round(($count / $total_sum) * 100, 1) : 0; + + $data[] = array( + 'text' => (string)$answer['text'], + 'count' => $count, + 'percent' => $percent + ); + } + } + + return $data; + } +} \ No newline at end of file diff --git a/upload/catalog/language/en-gb/module/poll_widget_nat.php b/upload/catalog/language/en-gb/module/poll_widget_nat.php new file mode 100644 index 0000000..aa21920 --- /dev/null +++ b/upload/catalog/language/en-gb/module/poll_widget_nat.php @@ -0,0 +1,6 @@ +db->query("SELECT * FROM `" . DB_PREFIX . "poll_widget_nat` WHERE poll_id = '" . (int)$poll_id . "' AND status = '1'"); + + if ($query->num_rows) { + $poll_info = $query->row; + $poll_info['config'] = json_decode($poll_info['config'], true); + $poll_info['colors'] = json_decode($poll_info['colors'], true); + $poll_info['custom_stats'] = json_decode($poll_info['custom_stats'], true); + + return $poll_info; + } + + return false; + } + + public function getPollDescription($poll_id) { + $query = $this->db->query("SELECT * FROM `" . DB_PREFIX . "poll_widget_nat_description` WHERE poll_id = '" . (int)$poll_id . "' AND language_id = '" . (int)$this->config->get('config_language_id') . "'"); + return $query->row; + } + + public function addVote($poll_id, $answer_index, $page_url = '') { + $customer_id = $this->customer->isLogged() ? (int)$this->customer->getId() : 0; + $ip = isset($this->request->server['REMOTE_ADDR']) ? $this->request->server['REMOTE_ADDR'] : ''; + $user_agent = isset($this->request->server['HTTP_USER_AGENT']) ? $this->request->server['HTTP_USER_AGENT'] : ''; + + $this->db->query("INSERT INTO `" . DB_PREFIX . "poll_widget_nat_vote` SET poll_id = '" . (int)$poll_id . "', answer_index = '" . (int)$answer_index . "', customer_id = '" . (int)$customer_id . "', ip = '" . $this->db->escape((string)$ip) . "', user_agent = '" . $this->db->escape((string)$user_agent) . "', page_url = '" . $this->db->escape((string)$page_url) . "', date_added = NOW()"); + } + + public function checkVoted($poll_id, $limit) { + if ((int)$limit === 0) { + return false; + } + + $ip = isset($this->request->server['REMOTE_ADDR']) ? $this->request->server['REMOTE_ADDR'] : ''; + $customer_id = $this->customer->isLogged() ? (int)$this->customer->getId() : 0; + + $sql = "SELECT COUNT(*) AS total FROM `" . DB_PREFIX . "poll_widget_nat_vote` WHERE poll_id = '" . (int)$poll_id . "' AND (ip = '" . $this->db->escape((string)$ip) . "'"; + + if ($customer_id) { + $sql .= " OR customer_id = '" . (int)$customer_id . "'"; + } + + $sql .= ")"; + + $query = $this->db->query($sql); + + return ((int)$query->row['total'] >= (int)$limit); + } + + public function getPollResults($poll_id) { + $query = $this->db->query("SELECT answer_index, COUNT(*) AS total FROM `" . DB_PREFIX . "poll_widget_nat_vote` WHERE poll_id = '" . (int)$poll_id . "' GROUP BY answer_index"); + + $results = array(); + foreach ($query->rows as $row) { + $results[(int)$row['answer_index']] = (int)$row['total']; + } + return $results; + } +} \ No newline at end of file diff --git a/upload/catalog/view/theme/default/template/module/poll_widget_nat.tpl b/upload/catalog/view/theme/default/template/module/poll_widget_nat.tpl new file mode 100644 index 0000000..432a9c2 --- /dev/null +++ b/upload/catalog/view/theme/default/template/module/poll_widget_nat.tpl @@ -0,0 +1,196 @@ + + +
+

+ +
+ +
+ + + +
+ + + + +
+
+ + + + + + +
+
+
+
+
+ + + + +
+ + + + +
+ : +
+ +
+
+ + \ No newline at end of file