diff --git a/chrome_point_plus/js/options.js b/chrome_point_plus/js/options.js index da6464c..13793de 100644 --- a/chrome_point_plus/js/options.js +++ b/chrome_point_plus/js/options.js @@ -1,151 +1,206 @@ -var ppOptions = {}; +/** + * Получает версию настроек из манифеста + * @returns {String} Версия настроек + */ +function getVersion() { + var xhr = new XMLHttpRequest(), + manifest; -// Binding event listeners -$(function() { - pp_restore_options(); - - // Delegating events - $('#tabs-content').on('click', 'input', function() { - pp_save_options(); - }); -}); + xhr.open('GET', chrome.extension.getURL('manifest.json'), false); + xhr.send(null); -// Initializing full options structure -function pp_init_options() { - var pp_version = getVersion(); - - chrome.storage.sync.get('options_version', function(data) { - console.info('Point+ %s, local options are for %s', pp_version, data.options_version); - - // Checking last options version - if (data.options_version != getVersion()) { - console.log('Initializing options...'); - - $('.option-node').find('input').each(function(idx, $input) { - console.debug($(this)); - - // Using option types - if ($(this).hasClass('option-boolean')) { - ppOptions[$(this).prop('id').replace(/-/g, '_')] = { - type: 'boolean', - value: $(this).prop('checked') - }; - } else if ($(this).hasClass('option-enum')) { - if ($(this).prop('checked')) { - ppOptions[$(this).prop('name').replace(/-/g, '_')] = { - type: 'enum', - value: $(this).val() - }; - } - } - }); - - // Updating options - chrome.storage.sync.set({ - options: ppOptions, - options_version: getVersion() - }, function() { - console.log('Default options initialized. Version upgraded to %s.', pp_version); - - if (!confirm(chrome.i18n.getMessage('options_text_new_version'))) { - window.close(); - } - }); - } - }); + manifest = JSON.parse(xhr.responseText); + + return manifest.version; } -// Saves options to sync storage. -// @todo: optimize it! (merge) -function pp_save_options() { - $('.option-node').find('input').each(function(idx, $input) { - console.log($(this)); - - // Using option types - if ($(this).hasClass('option-boolean')) { - ppOptions[$(this).prop('id').replace(/-/g, '_')] = { - type: 'boolean', - value: $(this).prop('checked') - }; - } else if ($(this).hasClass('option-enum')) { - if ($(this).prop('checked')) { - ppOptions[$(this).prop('name').replace(/-/g, '_')] = { - type: 'enum', - value: $(this).val() - }; - } +/** + * Объект, управляющий сохранением настроек на странице настроек + * + * При создании сохраняет версию, восстанавливает настройки, слушает изменения на инпутах. + * @constructor + */ +function Options() { + this.version = getVersion(); + + this.restore(); + + $('#tabs-content').on('click', 'input', this._onChange.bind(this)); +} + +/** + * Получает версию настроек. Если она не равна версии приложения, записывает в сторедж плагина настройки из инпутов + * и версию приложения. + */ +Options.prototype.init = function() { + chrome.storage.sync.get('options_version', function(data) { + this.logVersion(data.options_version); + + if (data.options_version !== this.version) { + console.log('Initializing options...'); + + chrome.storage.sync.set({ + options: this.getValues(), + options_version: this.version + }, function() { + console.log('Default options initialized. Version upgraded to %s.', this.version); + + alert(chrome.i18n.getMessage('options_text_new_version')); + }); } - }); - + }.bind(this)); +}; + +/** + * Сохраняет настройки + */ +Options.prototype.save = function() { + var ppOptions = this.getValues(); + console.log('Saving options: %O', ppOptions); // Saving parameters - chrome.storage.sync.set({options: ppOptions}, function() { + chrome.storage.sync.set({ options: ppOptions }, function() { // Update status to let user know options were saved. $('#status').html(chrome.i18n.getMessage('options_text_saved')); }); -} +}; -// Restores select box state to saved value from localStorage. -function pp_restore_options() { - // Cleaning old style options - // Delete after some time +/** + * Получает настройки из стореджа плагина, устанавливает соответствующим инпутам соответствующие значения. + */ +Options.prototype.restore = function() { + this.checkOldStyle(); + + chrome.storage.sync.get('options', function(data) { + this._options = data.options; + + try { + // Setting options in DOM + $.each(data.options, function(key, data) { + switch (data.type) { + case 'boolean': + if (data.value) { + $('#' + this.getOptionName(key)).prop('checked', true); + } + break; + + case 'enum': + $('.option-node .option-enum[name="' + this.getOptionName(key) + '"][value="' + data.value + '"]').prop('checked', true); + break; + + default: + console.warn('Invalid option "%s" type: %O', key, data); + break; + } + }.bind(this)); + } catch (ex) { + console.log('Error while loading extension options: %O', ex); + } + + this.showCopyright(); + this.init(); + }.bind(this)); +}; + +/** + * @returns {Object} Хеш настроек вида { имя_настроки: значение_настройки } + */ +Options.prototype.getValues = function() { + return this._options; +}; + +Options.prototype._onChange = function(event) { + var $input = $(event.target); + + console.log(arguments); + + if (this.isBoolean($input)) { + this._options[this.getOptionKey($input.prop('id'))] = { + type: 'boolean', + value: $input.prop('checked') + }; + } else if (this.isEnum($input)) { + this._options[this.getOptionKey($input.prop('name'))] = { + type: 'enum', + value: $input.val() + }; + } + + this.save(); +}; + +/** + * @param {jQuery} $option Элемент опции + * @returns {Boolean} Является ли настройка булевой + */ +Options.prototype.isBoolean = function($option) { + return $option.hasClass('option-boolean'); +}; + +/** + * + * @param {jQuery} $option Элемент опции + * @returns {Boolean} Является ли настройка енумом + */ +Options.prototype.isEnum = function($option) { + return $option.hasClass('option-enum'); +}; + +/** + * @param {String} name Имя инпута + * @returns {String} Ключ для хеша настроек + */ +Options.prototype.getOptionKey = function(name) { + return name.replace(/-/g, '_'); +}; + +/** + * @param {String} Ключ хеша настроек + * @returns {String} Имя инпута + */ +Options.prototype.getOptionName = function(key) { + return key.replace(/_/g, '-'); +}; + +/** + * Выводит в консоль версию настроек и версию плагина + * @param {String} optionsVersion + */ +Options.prototype.logVersion = function(optionsVersion) { + console.info('Point+ %s, local options are for %s', this.version, optionsVersion); +}; + +/** + * Добавляет копирайт в подвал + */ +Options.prototype.showCopyright = function() { + $('#pp-version').html('Point+ ' + this.version + + ' by @skobkin-ru
\n' + + '& @NokitaKaze' + ); +}; + +/** + * Проверяет, не старого ли формата настройки. И если старого, то удаляет их. + */ +Options.prototype.checkOldStyle = function() { chrome.storage.sync.get('option_fancybox', function(data) { if ((data.option_fancybox === true) || (data.option_fancybox === false)) { console.log('Found old-style options. Cleaning...'); + chrome.storage.sync.get(null, function(data) { + console.log('Old data: %O', data); + for (option in data) { chrome.storage.sync.remove(option); } + console.log('All old data removed'); }); } }); - - // Loading options - chrome.storage.sync.get('options', function(options) { - - try { - // Setting options in DOM - $.each(options.options, function(key, data) { - switch (data.type) { - case 'boolean': - if (data.value) { - $('#' + key.replace(/_/g, '-')).prop('checked', true); - } - break; +}; - case 'enum': - $('.option-node .option-enum[name="' + key.replace(/_/g, '-') + '"][value="' + data.value + '"]').prop('checked', true); - break; - - default: - console.warn('Invalid option "%s" type: %O', key, data); - break; - } - }); - } catch (ex) { - console.error('Error while loading extension options: %O', ex); - } - - - // Showing version - $('#pp-version').html('Point+ ' + getVersion() - + ' by @skobkin-ru
\n\ - & @NokitaKaze' - ); - - // Initializing new options - pp_init_options(); - }); -} - -// Getting version from manifest.json -function getVersion() { - var xhr = new XMLHttpRequest(); - xhr.open('GET', chrome.extension.getURL('manifest.json'), false); - xhr.send(null); - var manifest = JSON.parse(xhr.responseText); - return manifest.version; -} \ No newline at end of file +new Options(); diff --git a/chrome_point_plus/js/point-plus.js b/chrome_point_plus/js/point-plus.js index 4b22f23..12d830c 100644 --- a/chrome_point_plus/js/point-plus.js +++ b/chrome_point_plus/js/point-plus.js @@ -3,11 +3,49 @@ chrome.extension.sendMessage({ type: 'showPageAction' }); +/** + * Объект для получения опций + * @param {Object} options Хеш настроек + * @constructor + */ +function OptionsManager(options) { + this._options = options; +} + +/** + * @param {String} optionName Имя опции + * @returns {Boolean|String|Null} Значение опции + */ +OptionsManager.prototype.get = function(optionName) { + return this._options.hasOwnProperty(optionName) ? this._options[optionName].value : null; +}; + +/** + * Проверяет, равна ли опция значению value. Если value не переданно, проверяет задана ли она и не равна ли false/'' + * @param {String} optionName Имя опции + * @param {Boolean|String} [value=true] Значение опции + * @returns {Boolean} + */ +OptionsManager.prototype.is = function(optionName, value) { + if (typeof value !== 'undefined') { + return this.get(optionName) === value; + } else { + return Boolean(this.get(optionName)); + } +}; + +/** + * @returns {Object} Хеш опций + */ +OptionsManager.prototype.getOptions = function() { + return this._options; +}; + $(document).ready(function() { // Grouping console log console.group('point-plus'); console.info('Point+ %s', getVersion()); - + // Проверяем, загрузились ли мы var point_plus_debug = $('#point-plus-debug'); if (point_plus_debug.length > 0) { @@ -25,24 +63,24 @@ $(document).ready(function() { // Loading options chrome.storage.sync.get('options', function(sync_data) { - var options = sync_data.options; + var options = new OptionsManager(sync_data.options); // Options debug try { - console.debug('Options loaded: %O', options); + console.debug('Options loaded: %O', options.getOptions()); }catch(e){} create_tag_system(); // Embedding - if (options.option_embedding.value == true) { + if (options.is('option_embedding')) { // Load pictures from Booru, Tumblr and some other sites - if (options.option_images_load_booru.value == true) { + if (options.is('option_images_load_booru')) { load_all_booru_images(); } // Parse webm-links and create video instead - if (options.option_videos_parse_links.value == true) { - if (options.option_videos_parse_links_type.value == "all") { + if (options.is('option_videos_parse_links')) { + if (option.is('option_videos_parse_links_type', 'all')) { parse_all_videos(options); } else { parse_webm(options); @@ -50,19 +88,19 @@ $(document).ready(function() { } // Parse audio links - if (options.option_audios_parse_links.value == true) { + if (options.is('option_audios_parse_links')) { parse_all_audios(options); } // Soundcloud - if (options.option_embedding_soundcloud.value == true) { + if (options.is('option_embedding_soundcloud')) { // Injecting JS API chrome.extension.sendMessage({ type: 'injectJSFile', file: 'js/soundcloud/soundcloud.player.api.js' }); - // Processing links + // Processing links $('.post .post-content a[href*="\\:\\/\\/soundcloud\\.com\\/"]').each(function(index) { console.log($(this)); @@ -79,7 +117,7 @@ $(document).ready(function() { '); // Replace or prepend - if (options.option_embedding_soundcloud_orig_link.value == true) { + if (options.is('option_embedding_soundcloud_orig_link')) { // Before $(this).before($player); } else { @@ -91,19 +129,19 @@ $(document).ready(function() { } // Parse pleer.com links and create audio instead - if (options.option_embedding_pleercom.value == true) { + if (options.is('option_embedding_pleercom')) { parse_pleercom_links(options); } // Parse coub.com links and create iframe instead - if (options.option_embedding_coubcom.value == true) { + if (options.is('option_embedding_coubcom')) { parse_coub_links(options); } } // Fancybox - if (options.option_fancybox.value == true) { - if (options.option_fancybox_bind_images_to_one_flow.value == true) { + if (options.is('option_fancybox')) { + if (options.is('option_fancybox_bind_images_to_one_flow')) { // Linking images in posts to the galleries $('.post-content .text').each(function() { $(this).find('a.postimg:not(.youtube)').attr('data-fancybox-group', 'one_flow_gallery'); @@ -115,7 +153,7 @@ $(document).ready(function() { } // Images - if (options.option_fancybox_images.value == true) { + if (options.is('option_fancybox_images')) { // Init fancybox $('.postimg:not(.youtube)').fancybox({ type: 'image' @@ -123,14 +161,14 @@ $(document).ready(function() { } // Правим хинты у фансибокса - if (options.option_fancybox_smart_hints.value == true) { + if (options.is('option_fancybox_smart_hints')) { fancybox_set_smart_hints(); } else { $('.post .postimg').attr('data-fancybox-title', ' '); } // Videos - if (options.option_fancybox_videos.value == true) { + if (options.is('option_fancybox_videos')) { $('.postimg.youtube').addClass('fancybox-media').fancybox({ helpers: { media: { @@ -144,7 +182,7 @@ $(document).ready(function() { }); } // Posts - if (options.option_fancybox_posts.value == true) { + if (options.is('option_fancybox_posts')) { // Excluding some sort of piece-of-shit makeup $('.post-id a').not('#comments .post-id a, #top-post .post-id a').attr('data-fancybox-type', 'iframe').fancybox({ maxWidth: 780 @@ -153,10 +191,10 @@ $(document).ready(function() { } // NSFW Filtering - if (options.option_nsfw.value == true) { + if (options.is('option_nsfw')) { $('.post-tag-nsfw,.post-tag-сиськи').find('a.postimg:not(.youtube)').attr('data-fancybox-group', 'hidden-images'); - if (options.option_nsfw_hide_posts.value == true) { + if (options.is('option_nsfw_hide_posts')) { if ($('#comments').length == 0) { console.log('Hide NSFW posts in feed, %i hidden', $('.post').length); $('.post').addClass('hide-nsfw-posts'); @@ -164,20 +202,20 @@ $(document).ready(function() { } // Blurred posts - if (options.option_nsfw_blur_posts_entire.value == true) { + if (options.is('option_nsfw_blur_posts_entire')) { console.log('Bluring NSFW posts'); $('.post').addClass('blur-nsfw-entire'); - } else if (options.option_nsfw_blur_posts_images.value == true) { + } else if (options.is('option_nsfw_blur_posts_images')) { console.log('Bluring images in NSFW posts'); $('.post').addClass('blur-nsfw-images'); } // Blurred comments if ($('.post').hasClass('post-tag-nsfw') || $('.post').hasClass('post-tag-сиськи')) { - if (options.option_nsfw_blur_comments_entire.value == true) { + if (options.is('option_nsfw_blur_comments_entire')) { console.log('Bluring comments'); $('#comments').addClass('blur-nsfw-entire'); - } else if (options.option_nsfw_blur_comments_images.value == true) { + } else if (options.is('option_nsfw_blur_comments_images')) { // @hint Никита Ветров официально складывает с себя все претензии, если у кого-то от этого говна упадёт драйвер видео-карты console.log('Bluring images in comments'); $('#comments').addClass('blur-nsfw-images'); @@ -187,7 +225,7 @@ $(document).ready(function() { // Hotkeys // Send by CTRL+Enter - if (options.option_ctrl_enter.value == true) { + if (options.is('option_ctrl_enter')) { // Reply // Delegated event for all comments $('.content-wrap #comments').on('keydown.point_plus', '.reply-form textarea', function(e) { @@ -206,7 +244,7 @@ $(document).ready(function() { } // Look and feel // Fluid #main layout - if (options.option_fluid_layout.value == true) { + if (options.is('option_fluid_layout')) { $('#main, #header, #subheader, #footer').css({ 'width': '95%', 'max-width': '95%' @@ -214,7 +252,7 @@ $(document).ready(function() { // TODO: fix #main #left-menu #top-link position } // Image resizing - if (options.option_images_load_original.value == true) { + if (options.is('option_images_load_original')) { // Setting new image source $('.postimg:not(.youtube) img').each(function() { console.log($(this).parent('.postimg').attr('href')); @@ -229,14 +267,14 @@ $(document).ready(function() { }); } // Visual editor - if (options.option_visual_editor_post.value == true) { + if (options.is('option_visual_editor_post')) { // Add classes $('#new-post-form #text-input, .post-content #text-input').addClass('markitup').css('height', '20em'); // Init $('.markitup').markItUp(mySettings); // Send by CTRL+Enter - if (options.option_ctrl_enter.value == true) { + if (options.is('option_ctrl_enter')) { // New post $('#new-post-form #text-input, .post-content #text-input').on('keydown.point_plus', function(e) { if (e.ctrlKey && (e.keyCode == 10 || e.keyCode == 13)) { @@ -247,7 +285,7 @@ $(document).ready(function() { } } // Google search - if (options.option_search_with_google.value == true) { + if (options.is('option_search_with_google')) { $('#search-form input[type="text"]').attr('placeholder', 'Google').keydown(function(e) { if (e.keyCode == 10 || e.keyCode == 13) { e.preventDefault(); @@ -256,11 +294,11 @@ $(document).ready(function() { }); } // WebSocket - if (options.option_ws.value == true) { + if (options.is('option_ws')) { // SSL or plain ws = new WebSocket(((location.protocol == 'https:') ? 'wss' : 'ws') + '://point.im/ws'); console.log('WebSocket created: %O', ws); - + // @todo: унести в опцию // Adding event listener for notification click chrome.extension.sendMessage({ @@ -297,7 +335,7 @@ $(document).ready(function() { console.debug(wsMessage); // Check option - if (options.option_ws_comments.value != true) { + if ( ! options.is('option_ws_comments')) { console.log('Comments processing disabled'); console.groupEnd(); break; @@ -335,7 +373,7 @@ $(document).ready(function() { // Date and time of comment var date = new Date(); - + // @todo: унести наверх // Data for template var userLink = '//' + wsMessage.author + '.point.im/'; @@ -344,7 +382,7 @@ $(document).ready(function() { var userAvatar = '//point.im/avatar/' + wsMessage.author; var commentLink = '//point.im/' + wsMessage.post_id + '#' + wsMessage.comment_id; var csRfToken = $('.reply-form input[name="csrf_token"').val(); - + // Filling template console.info('Changing data in the comment element'); // Date and time @@ -411,13 +449,13 @@ $(document).ready(function() { $commentTemplate.before($anchor); // Fading out highlight if needed - if (options.option_ws_comments_color_fadeout.value == true) { + if (options.is('option_ws_comments_color_fadeout')) { console.log('Fading out the highlight'); $commentTemplate.children('.pp-highlight').fadeOut(20000); } // Desktop notifications - if (options.option_ws_comments_notifications.value == true) { + if (options.is('option_ws_comments_notifications')) { console.log('Showing desktop notification'); chrome.extension.sendMessage({ type: 'showNotification', @@ -473,11 +511,11 @@ $(document).ready(function() { }; } // Font size - if ((options.option_enlarge_font.value == true) && (options.option_enlarge_font_size.value !== undefined)) { - $('body').css('font-size', (options.option_enlarge_font_size.value / 100) + 'em'); + if ((options.is('option_enlarge_font')) && (option.get('option_enlarge_font_size'))) { + $('body').css('font-size', (option.get('option_enlarge_font_size') / 100) + 'em'); } // @ before username - if (options.option_at_before_username.value == true) { + if (options.is('option_at_before_username')) { chrome.extension.sendMessage({ type: 'injectCSSFile', file: 'css/modules/at_before_username.css' @@ -485,35 +523,35 @@ $(document).ready(function() { } // Hightlight post with new comments - if (options.option_other_hightlight_post_comments.value == true) { + if (options.is('option_other_hightlight_post_comments')) { mark_unread_post(); } // Show recommendation count and unique commentators count - if (options.option_other_show_recommendation_count.value == true) { + if (options.is('option_other_show_recommendation_count')) { set_posts_count_label(); } // `Space` key scroll handler - if (options.option_other_scroll_space_key.value == true){ + if (options.is('option_other_scroll_space_key')){ set_space_key_skip_handler(); } // Система комментариев у пользователей - if (options.option_other_comments_user_system.value == true) { + if (options.is('option_other_comments_user_system')) { hints_init_user_system(); } // Nesting level indicator - if (options.option_other_comments_nesting_level.value == true) { + if (options.is('option_other_comments_nesting_level')) { draw_nesting_level_indicator(); } // Обновляем кол-во постов и непрочитанных комментариев - if (options.option_other_comments_count_refresh.value == true){ + if (options.is('option_other_comments_count_refresh')) { set_comments_refresh_tick(options); } // Твиты из Твиттера - if (options.option_embedding_twitter_tweets.value == true){ + if (options.is('option_embedding_twitter_tweets')) { twitter_tweet_embedding_init(); } @@ -665,7 +703,7 @@ function parse_webm(current_options) { obj.parentElement.insertBefore(player, obj); - if (current_options.option_videos_parse_leave_links.value == false) { + if (current_options.is('option_videos_parse_leave_links', false)) { $(obj).hide(); } } @@ -692,7 +730,7 @@ function parse_all_videos(current_options) { obj.parentElement.insertBefore(player, obj); - if (current_options.option_videos_parse_leave_links.value == false) { + if (current_options.is('option_videos_parse_leave_links', false)) { $(obj).hide(); } } @@ -741,7 +779,7 @@ function parse_all_audios(current_options){ obj.parentElement.insertBefore(player, obj); - if (current_options.option_audios_parse_leave_links.value == false) { + if (current_options.is('option_audios_parse_leave_links', false)) { $(obj).hide(); } } @@ -801,7 +839,7 @@ function set_posts_count_label() { } function parse_pleercom_links(current_options) { - if (current_options.option_embedding_pleercom_nokita_server.value) { + if (current_options.is('option_embedding_pleercom_nokita_server')) { parse_pleercom_links_nokita(); } else { parse_pleercom_links_ajax(current_options); @@ -852,7 +890,6 @@ function create_pleercom_ajax(id, current_options) { 'postdata': 'action=download&id=' + id, 'dont_set_content_type': true, 'pleer_id': id, - 'current_options':current_options, 'headers': [['Accept', '*'], ['Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8']], 'success': function(a) { var answer = JSON.parse(a); @@ -865,7 +902,7 @@ function create_pleercom_ajax(id, current_options) { }); $('.embeded_audio_' + this.settings.pleer_id)[0].appendChild(player); - if (this.settings.current_options.option_embedding_pleercom_orig_link.value == false){ + if (current_options.is('option_embedding_pleercom_orig_link', false)){ $('.pleercom_original_link_'+this.settings.pleer_id).hide(); } }, @@ -1001,7 +1038,7 @@ function parse_coub_links(current_options) { obj.parentElement.insertBefore(player, obj); - if (current_options.option_embedding_coubcom_orig_link.value == false) { + if (current_options.is('option_embedding_coubcom_orig_link', false)) { $(obj).hide(); } } @@ -1238,7 +1275,7 @@ function set_comments_refresh_tick(current_options) { }, 60000); // Ставим слежение за позицией мыши - if (current_options.option_other_comments_count_refresh_title.value == true) { + if (current_options.is('option_other_comments_count_refresh_title')) { $(document). on('mouseenter', function() { set_comments_refresh_clear_title_marks(); @@ -1311,7 +1348,7 @@ function comments_count_refresh_tick(current_options) { $('#main #left-menu #menu-comments .unread').text('0').hide(); } - if ((current_options.option_other_comments_count_refresh_title.value == true) && + if ((current_options.is('option_other_comments_count_refresh_title')) && (!window_focused)) { var new_title = document.title.replace(new RegExp('^\\[[0-9]+\\; [0-9]+\\] '), ''); if ((count_recent > 0) || (count_comments > 0)) {