diff --git a/CHANGELOG-EN.md b/CHANGELOG-EN.md
deleted file mode 100644
index 8b13789..0000000
--- a/CHANGELOG-EN.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b13789..4df6e0f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1 +1,114 @@
+# 1.0.0-beta.3 (23 февраля, 2018)
+## Расширение
+
+### Добавлено
+
+* Добавлены настройки.
+* Добавлен профиль пользователя.
+
+### Изменено
+
+* Изменено название c "2ch+" на "2ch-helper".
+* Изменен формат версии. Теперь не beta-дата, а 1.0.0-beta.версия-беты.
+
+## Проект
+
+### Добавлено
+
+* Добавлена документация для модулей.
+* Добавлена информация в CHANGELOG.
+* Добавлена информация в README.
+* Добавлены модули: background-events.js, background-user-profile.js, settings-download.js, settings-iframe.js, settings-screenshot.js, settings.js, settings-iframe.css, settings.css.
+* Добавлены страницы: settings-download.html, settings-screenshot.html.
+* Добавлены библиотеки: bootstrap-slider.min.js, bootstrap-slider.min.css.
+* Добавлен "persistent: false" в манифест.
+
+### Удалено
+
+* Changelog (EN версия).
+* Readme (EN версия).
+* License (RU версия).
+* Удален временный коментарий из content-downloads.js.
+
+### Изменено
+
+* Большинство "then" изменено на "await".
+* Незначительные изменения в коде.
+* Изменена страница настроек.
+* Изменен порядок загрузки скриптов.
+
+# 1.0.0-beta.2 (11 февраля, 2018)
+
+## Расширение
+
+### Изменено
+
+* Скачанные файлы имеют оригинальное имя.
+* Скриншот постов имеет имя `posts.jpg`.
+* Скриншот треда имеет имя `thread.jpg`.
+* Во время создания скриншота все "ненужные" детали страницы скрываются.
+* Если во время работы расширения произошла ошибка, то она появится в консоли браузера.
+
+## Проект
+
+### Добавлено
+
+* Changelog (RU и EN версия).
+* Readme (EN версия).
+* License (RU версия).
+
+### Удалено
+
+* удалена папка `libs` из `extension/interaction/js/`.
+
+### Изменено
+
+* Произведено разделение логики расширения на модули.
+ * Исчезли глобальные переменные. Теперь каждая переменная закреплена за собственным модулем.
+ * Общие функции или специфические функции перенесены в главный модуль API (`content-API.js`, `background-API.js`).
+* Произведен рефакторинг всех скриптов.
+ * Большинство функций реализованы через `Promise`.
+ * Переменные `var` заменены на `const` и `let`.
+ * Изменена логика каждого модуля.
+ * Изменен формат сообщений между модулями. Теперь в сообщении обязательно должен содержаться тип сообщения.
+* Модули скриншота полностью переписаны.
+ * Изменен алгоритм получения координат.
+ * Скриншоты делаются в формате JPEG c качеством 100%.
+ * Появилась обработка ошибок.
+
+### Улучшение производительности
+
+* Модули инжектятся в страницу не сразу, а по мере их необходимости.
+* Память освобождается от мусора после создания скриншота.
+
+# 1.0.0-beta.1 (5 февраля, 2018)
+
+## Расширение
+
+### Новые функции
+
+* **скриншот**:
+ * создание скриншота треда.
+* **загрузка**:
+ * скачивание изображений.
+ * скачивание видео.
+ * скачивание медиаконтента (изображения + видео).
+ * скачивание треда.
+
+## Проект
+
+### Изменено
+
+* Скрипты взаимодействия теперь находятся в папке `scripts`.
+
+# 1.0.0-beta.0 (3 февраля, 2018)
+
+Релиз проекта.
+
+## Расширение
+
+### Новые функции
+
+* **скриншот:**
+ * создание скриншота постов.
diff --git a/LICENSE-RU b/LICENSE-RU
deleted file mode 100644
index 8b13789..0000000
--- a/LICENSE-RU
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/README-EN.md b/README-EN.md
deleted file mode 100644
index 8b13789..0000000
--- a/README-EN.md
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/README.md b/README.md
index a8b8855..e02a6b4 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,39 @@
-# 2ch-helper
-Расширение для Google Chrome, которое упрощает взаимодействие с сайтом 2ch.hk
+
+ 2ch-helper
+
+
+
+ Расширение для браузера, которое облегчает взаимодействие с имиджбордой 2ch.hk.
+
+
+
+
+## Содержание
+
+- [Возможности](#Возможности)
+- [Системные требования](#Системные-требования)
+- [Установка](#Установка)
+- [Лицензия](#Лицензия)
+
+## Возможности
+
+- создание скриншота постов и треда.
+- загрузка изображений, видео и треда.
+
+## Системные требования
+
+- Браузер: Google Chrome.
+
+## Установка
+
+**GitHub**
+
+1. Скачайте этот репозиторий.
+2. Перейдите на вкладку .
+3. Включите режим разработчика.
+4. Нажмите на "Загрузить распакованное расширение...".
+5. Выберите папку "extension".
+
+## Лицензия
+
+Исходный код находится под [лицензией MIT](https://github.com/Amaimersion/2ch-helper/blob/master/LICENSE "Лицензия").
\ No newline at end of file
diff --git a/extension/interaction/js/scripts/background/background-API.js b/extension/interaction/js/scripts/background/background-API.js
index 36f0238..0f29a96 100644
--- a/extension/interaction/js/scripts/background/background-API.js
+++ b/extension/interaction/js/scripts/background/background-API.js
@@ -1,11 +1,69 @@
+/**
+ * The common module for usage in others background modules.
+ *
+ * @module BackgroundAPI
+ */
function BackgroundAPI() {}
+/**
+ * Settings of user.
+ *
+ * @memberof BackgroundAPI
+ * @static
+ * @type {Object}
+ */
+BackgroundAPI.userSettings = {};
+
+
+/**
+ * Clears a cashe of the background page.
+ * It just reload a page, but it's works.
+ *
+ * @memberof BackgroundAPI
+ * @static
+ */
BackgroundAPI.clearCashe = function() {
window.location.reload(true);
}
+/**
+ * Gets an user settings from chome storage.
+ * After getting they will be setted to BackgroundAPI.userSettings.
+ *
+ * @memberof BackgroundAPI
+ * @static
+ * @async
+ */
+BackgroundAPI.getUserSettings = function() {
+ // what settings to receive.
+ const settings = [
+ 'settings_screenshot',
+ 'settings_download'
+ ];
+
+ chrome.storage.sync.get(settings, (data) => {
+ this.userSettings = data;
+ });
+}
+
+
+/**
+ * Injects a script into the page.
+ *
+ * @memberof BackgroundAPI
+ * @static
+ * @async
+ *
+ * @param {Object} options
+ * An options for execute.
+ * See https://developer.chrome.com/extensions/tabs#method-executeScript
+ *
+ * @returns {Promise}
+ * A promise for the inject that will resolve when injects are successfully completed.
+ * Resolve will contain nothing if success, otherwise reject will contain an error.
+ */
BackgroundAPI.injectScript = function(options) {
return new Promise((resolve, reject) => {
chrome.tabs.executeScript(options, (result) => {
diff --git a/extension/interaction/js/scripts/background/background-downloads.js b/extension/interaction/js/scripts/background/background-downloads.js
index 404fb4a..b98a476 100644
--- a/extension/interaction/js/scripts/background/background-downloads.js
+++ b/extension/interaction/js/scripts/background/background-downloads.js
@@ -1,6 +1,22 @@
+/**
+ * The module that handles download requests.
+ *
+ * @module BackgroundDownloads
+ */
function BackgroundDownloads() {}
+/**
+ * Downloads a thread.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ * @async
+ *
+ * @returns {Promise}
+ * A promise for the download that will resolve when download are successfully completed.
+ * Resolve will contain nothing if success.
+ */
BackgroundDownloads.downloadThread = function() {
return new Promise((resolve, reject) => {
const query = {active: true, currentWindow: true};
@@ -10,44 +26,89 @@ BackgroundDownloads.downloadThread = function() {
let name = (tabs[0].title || 'thread') + '.mhtml';
name = this.fixFileName(name);
- chrome.pageCapture.saveAsMHTML(captureOptions, (mhtml) => {
+ chrome.pageCapture.saveAsMHTML(captureOptions, async (mhtml) => {
const url = URL.createObjectURL(mhtml);
const downloadOptions = {
url: url,
filename: name
};
- this.download(downloadOptions).then(() => {
- return resolve();
- });
+ await this.download(downloadOptions);
+
+ return resolve();
});
});
});
}
+/**
+ * Downloads an images.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ * @async
+ *
+ * @param {Array} urls An urls for download.
+ *
+ * @returns {Promise}
+ * A promise for the download that will resolve when download are successfully completed.
+ * Resolve will contain nothing if success, otherwise reject will contain an error.
+ */
BackgroundDownloads.downloadImages = function(urls) {
- return new Promise((resolve, reject) => {
- this.downloadData(urls).then(() => {
- return resolve();
- }, (error) => {
- return reject(error);
- });
+ return new Promise(async (resolve, reject) => {
+ try {
+ await this.downloadData(urls);
+ } catch (error) {
+ return reject(error);
+ }
+
+ return resolve();
});
}
+/**
+ * Downloads a video.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ * @async
+ *
+ * @param {Array} urls An urls for download.
+ *
+ * @returns {Promise}
+ * A promise for the download that will resolve when download are successfully completed.
+ * Resolve will contain nothing if success, otherwise reject will contain an error.
+ */
BackgroundDownloads.downloadVideo = function(urls) {
- return new Promise((resolve, reject) => {
- this.downloadData(urls).then(() => {
- return resolve();
- }, (error) => {
- return reject(error);
- });
+ return new Promise(async (resolve, reject) => {
+ try {
+ await this.downloadData(urls);
+ } catch (error) {
+ return reject(error);
+ }
+
+ return resolve();
});
}
+/**
+ * Downloads a data.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ * @async
+ *
+ * @param {Object} options
+ * An options for download.
+ * See https://developer.chrome.com/extensions/downloads#method-download
+ *
+ * @returns {Promise}
+ * A promise for the download that will resolve when download are successfully completed.
+ * Resolve will contain the id of the new download item if success.
+ */
BackgroundDownloads.download = function(options) {
return new Promise((resolve, reject) => {
chrome.downloads.download(options, (downloadId) => {
@@ -57,6 +118,34 @@ BackgroundDownloads.download = function(options) {
}
+/**
+ * Downloads a data of the urls.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ * @async
+ *
+ * @param {Array} urls
+ * The urls for download.
+ *
+ * @param {String} [fileName]
+ * A name of the file.
+ * By default this is determined based on the url.
+ * If cannot be determined, then 'undefined'.
+ *
+ * @param {String} [fileFormat]
+ * A format of the file.
+ * By default this is determined based on the url.
+ * If cannot be determined, then ''.
+ *
+ * @param {Object} [downloadOptions]
+ * An options for download.
+ * See https://developer.chrome.com/extensions/downloads#method-download
+ *
+ * @returns {Promise}
+ * A promise for the download that will resolve when download are successfully completed.
+ * Resolve will contain nothing if success, otherwise reject will contain an error.
+ */
BackgroundDownloads.downloadData = function(urls, fileName, fileFormat, downloadOptions) {
return new Promise((resolve, reject) => {
downloadOptions = downloadOptions || {};
@@ -65,25 +154,27 @@ BackgroundDownloads.downloadData = function(urls, fileName, fileFormat, download
for (let url of urls) {
downloadPromise = downloadPromise.then(() => {
return new Promise((res) => {
- const name = (
- fileName ||
- this.determineFileName(url) ||
- 'undefined'
- );
const format = (
fileFormat ||
this.determineFileFormat(url) ||
''
);
+ let name = '';
+
+ if (BackgroundAPI.userSettings.settings_download.autoDetectionName) {
+ name = this.determineFileName(url) || 'undefined';
+ } else {
+ name = BackgroundAPI.userSettings.settings_download.fileName;
+ }
downloadOptions.url = url;
downloadOptions.filename = name + format;
-
+
window.setTimeout(() => {
this.download(downloadOptions).then(() => {
return res();
});
- }, 500);
+ }, BackgroundAPI.userSettings.settings_download.delay);
});
});
}
@@ -100,6 +191,22 @@ BackgroundDownloads.downloadData = function(urls, fileName, fileFormat, download
}
+/**
+ * Determines the file name based on the url.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ *
+ * @param {String} url
+ *
+ * @returns {String}
+ * The name of the url.
+ * If cannot be determined, then undefined.
+ *
+ * @example
+ * // returns '123'.
+ * BackgroundDownloads.determineFileName('https://2ch.hk/pr/src/987/123.jpg').
+ */
BackgroundDownloads.determineFileName = function(url) {
const lastIndex = url.lastIndexOf('.');
const preLastIndex = url.lastIndexOf('/');
@@ -112,6 +219,22 @@ BackgroundDownloads.determineFileName = function(url) {
}
+/**
+ * Determines the file format based on the url.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ *
+ * @param {String} url
+ *
+ * @returns {String}
+ * The format of the url.
+ * If cannot be determined, then undefined.
+ *
+ * @example
+ * // returns '.jpg'.
+ * BackgroundDownloads.determineFileName('https://2ch.hk/pr/src/987/123.jpg').
+ */
BackgroundDownloads.determineFileFormat = function(url) {
const lastIndex = url.lastIndexOf('.');
@@ -123,6 +246,21 @@ BackgroundDownloads.determineFileFormat = function(url) {
}
+/**
+ * Removes invalid characters from the file name.
+ *
+ * @memberof BackgroundDownloads
+ * @static
+ *
+ * @param {String} name
+ * A file name for fix.
+ *
+ * @param {String} [char='']
+ * A char for replace. Defaults to ''.
+ *
+ * @returns {String}
+ * A valid file name.
+ */
BackgroundDownloads.fixFileName = function(name, char) {
return name.replace(/[\\\/\:\*\?\"\<\>\|]/g, char || '');
}
diff --git a/extension/interaction/js/scripts/background/background-events.js b/extension/interaction/js/scripts/background/background-events.js
new file mode 100644
index 0000000..d3ae234
--- /dev/null
+++ b/extension/interaction/js/scripts/background/background-events.js
@@ -0,0 +1,46 @@
+/**
+ * The module that handles background events.
+ * An events that gets handling: first install, DOMContentLoaded.
+ *
+ * @module BackgroundEvents
+ */
+function BackgroundEvents() {}
+
+
+/**
+ * Handles DOMContentLoaded event.
+ *
+ * @memberof BackgroundEvents
+ * @static
+ */
+BackgroundEvents.DOMContentLoaded = function() {
+ BackgroundAPI.getUserSettings();
+}
+
+
+/**
+ * Handles first install event.
+ *
+ * @memberof BackgroundEvents
+ * @static
+ */
+BackgroundEvents.firstInstall = function() {
+ UserProfile.createProfile();
+}
+
+
+/* Sets the events. */
+
+
+if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', BackgroundEvents.DOMContentLoaded);
+} else {
+ BackgroundEvents.DOMContentLoaded();
+}
+
+
+chrome.runtime.onInstalled.addListener((details) => {
+ if (details.reason === 'install') {
+ BackgroundEvents.firstInstall();
+ }
+});
diff --git a/extension/interaction/js/scripts/background/background-on-message.js b/extension/interaction/js/scripts/background/background-on-message.js
index 7358b9c..059830f 100644
--- a/extension/interaction/js/scripts/background/background-on-message.js
+++ b/extension/interaction/js/scripts/background/background-on-message.js
@@ -1,6 +1,25 @@
+/**
+ * The module that handles messages.
+ * Can handle messages of the following types: 'command'.
+ *
+ * @module BackgroundMessage
+ */
function BackgroundMessage() {}
+/**
+ * Handles messages.
+ *
+ * @memberof BackgroundMessage
+ * @static
+ *
+ * @param {Object} request
+ * @param {Object} sender
+ * @param {Object} sendResponse
+ *
+ * @returns {Boolean}
+ * Returns true because there will be an asynchronous response.
+ */
BackgroundMessage.onMessage = function(request, sender, sendResponse) {
if (request.type === 'command') {
BackgroundMessage.commandHandler(request, sendResponse);
@@ -12,93 +31,132 @@ BackgroundMessage.onMessage = function(request, sender, sendResponse) {
}
-BackgroundMessage.commandHandler = function(request, sendResponse) {
+/**
+ * Handles command type messages.
+ *
+ * @memberof BackgroundMessage
+ * @static
+ * @async
+ *
+ * @param {Object} request
+ * @param {Object} sendResponse
+ *
+ * @throws {Error} Throws an error if occurs.
+ */
+BackgroundMessage.commandHandler = async function(request, sendResponse) {
const command = request.command;
if (command === 'downloadThread') {
- const promise = BackgroundDownloads.downloadThread();
-
- promise.then(() => {
- sendResponse({status: true});
- }, (error) => {
+ try {
+ await BackgroundDownloads.downloadThread();
+ } catch (error) {
sendResponse({status: false, error: error});
throw error;
- });
+ }
- } else if (command === 'downloadImages') {
- const promise = BackgroundDownloads.downloadImages(request.data);
+ sendResponse({status: true});
- promise.then(() => {
- sendResponse({status: true});
- }, (error) => {
+ } else if (command === 'downloadImages') {
+ try {
+ await BackgroundDownloads.downloadImages(request.data);
+ } catch (error) {
sendResponse({status: false, error: error});
throw error;
- });
+ }
- } else if (command === 'downloadVideo') {
- const promise = BackgroundDownloads.downloadVideo(request.data);
+ sendResponse({status: true});
- promise.then(() => {
- sendResponse({status: true});
- }, (error) => {
+ } else if (command === 'downloadVideo') {
+ try {
+ await BackgroundDownloads.downloadVideo(request.data);
+ } catch (error) {
sendResponse({status: false, error: error});
throw error;
- });
+ }
- } else if (command === "createScreenshot") {
- const promise = BackgroundScreenshot.createScreenshot(request.coordinate);
+ sendResponse({status: true});
- promise.then(() => {
- sendResponse({status: true});
- }, (error) => {
+ } else if (command === "createScreenshot") {
+ try {
+ await BackgroundScreenshot.createScreenshot(request.coordinate);
+ } catch (error) {
BackgroundAPI.clearCashe();
sendResponse({status: false});
throw error;
- })
+ }
+
+ sendResponse({status: true});
} else if (command === "createPostsImage") {
- const promise = BackgroundScreenshot.createPostsImage();
+ let uri = '';
- promise.then((uri) => {
- BackgroundDownloads.download({url: uri, filename: 'posts.jpg'});
- BackgroundAPI.clearCashe();
- sendResponse({status: true});
- }, (error) => {
+ try {
+ uri = await BackgroundScreenshot.createPostsImage();
+ } catch (error) {
BackgroundAPI.clearCashe();
sendResponse({status: false, error: error});
throw error;
- });
+ }
+
+ const filename = (
+ BackgroundAPI.userSettings.settings_screenshot.fileNamePosts +
+ '.' +
+ BackgroundAPI.userSettings.settings_screenshot.format
+ );
+
+ BackgroundDownloads.download({url: uri, filename: filename});
+ BackgroundAPI.clearCashe();
+ sendResponse({status: true});
} else if (command === "createThreadImage") {
- const promise = BackgroundScreenshot.createThreadImage();
+ let uri = '';
- promise.then((uri) => {
- BackgroundDownloads.download({url: uri, filename: 'thread.jpg'});
- BackgroundAPI.clearCashe();
- sendResponse({status: true});
- }, (error) => {
+ try {
+ uri = await BackgroundScreenshot.createThreadImage();
+ } catch (error) {
BackgroundAPI.clearCashe();
sendResponse({status: false, error: error});
throw error;
- });
+ }
+
+ const filename = (
+ BackgroundAPI.userSettings.settings_screenshot.fileNameThread +
+ '.' +
+ BackgroundAPI.userSettings.settings_screenshot.format
+ );
+
+ BackgroundDownloads.download({url: uri, filename: filename});
+ BackgroundAPI.clearCashe();
} else if (command === 'injectScript') {
const options = {
file: request.path
};
- const promise = BackgroundAPI.injectScript(options);
-
- promise.then(() => {
- sendResponse({status: true});
- }, (error) => {
+ try {
+ await BackgroundAPI.injectScript(options);
+ } catch (error) {
sendResponse({status: false, error: error});
throw error;
- });
+ }
+
+ sendResponse({status: true});
}
}
+/**
+ * Handles unknown type messages.
+ *
+ * @memberof BackgroundMessage
+ * @static
+ *
+ * @param {Object} request
+ * @param {Object} sender
+ * @param {Object} sendResponse
+ *
+ * @throws {Error} Throws an error with request information.
+ */
BackgroundMessage.errorHandler = function(request, sender, sendResponse) {
console.log(
'An unknown request was received.\n',
@@ -122,4 +180,7 @@ BackgroundMessage.errorHandler = function(request, sender, sendResponse) {
}
+/**
+ * Sets a message handler.
+ */
chrome.runtime.onMessage.addListener(BackgroundMessage.onMessage);
diff --git a/extension/interaction/js/scripts/background/background-screenshot.js b/extension/interaction/js/scripts/background/background-screenshot.js
index cf6bbc4..a26e12d 100644
--- a/extension/interaction/js/scripts/background/background-screenshot.js
+++ b/extension/interaction/js/scripts/background/background-screenshot.js
@@ -1,43 +1,109 @@
+/**
+ * The module that handles screenshot requests.
+ *
+ * @module BackgroundScreenshot
+ */
function BackgroundScreenshot() {}
+/**
+ * Data for further handling.
+ * Contains object with next properties: 'coordinate', 'uri'.
+ * Coordinate is position of needed region to crop.
+ * Uri is image to crop.
+ *
+ * @memberof BackgroundScreenshot
+ * @static
+ * @type {Array