var messenger = new MessageSender(); // Showing page action messenger.sendMessage({ type: 'showPageAction' }, function(response) { console.debug('showPageAction response: %O', response); }); messenger.sendMessage({ type: 'getManifestVersion' }, function(response) { $(document).ready(function() { PointPlus(response.version || 'undefined') }); }); function PointPlus(ppVersion) { // Grouping console log console.group('point-plus'); console.info('Point+ %s', ppVersion); // Getting username var point_username = $('#name h1').text(); // Getting post id var postId = $('#top-post').attr('data-id'); console.debug('Current post id detected as #%s', postId); // Проверяем, загрузились ли мы var point_plus_debug = $('#point-plus-debug'); if (point_plus_debug.length > 0) { console.error('Point+ %s already loaded.', point_plus_debug.data('point-plus-version')); return; } $('
').attr({ 'data-point-plus-version': ppVersion }).text('Point+ ' + ppVersion + ' loading...') .insertBefore('#user-menu-cb'); // Loading options chrome.storage.sync.get('options', function(sync_data) { var options = new OptionsManager(sync_data.options); // Options debug try { console.debug('Options loaded: %O', options.getOptions()); } catch(e){} create_tag_system(); // Move "all posts" to left menu if (options.is('option_other_move_all_to_menu')) { $('div.secret a').insertAfter('a#menu-recent').css('background-image','url("img/icon-private-inactive.png")'); } // Side panel if (options.is('option_right_panel')) { // Loading side panel CSS messenger.css('css/modules/side_panel.css'); // Creating side panel var $side_panel = $('
').attr({ id: 'pp-right-panel' }); $('body').append($side_panel); if (options.is('option_right_panel_to_unread') && $('#comments').length > 0) { $go_to_unread_block = $('
').attr({ id: 'pp-go-to-unread', }).click(function() { var $unread_comment = $('#comments div.post.unread').first(); if ($unread_comment.length > 0) { $('html body').animate({ scrollTop: $unread_comment.offset().top }, 500); $unread_comment.removeClass('unread'); // Updating count update_right_panel_unread_count(); } }); $side_panel.append($go_to_unread_block); $go_to_unread_link = $('').attr({ id: 'pp-unread-count', }); $go_to_unread_block.append($go_to_unread_link); // Updating count update_right_panel_unread_count(); } } // Remove fucking button if (options.is('option_other_remove_fucking_button')) { $('#scrollToTop').remove(); } // Embedding if (options.is('option_embedding')) { // Load pictures from Booru, Tumblr and some other sites if (options.is('option_images_load_booru')) { messenger.js({ file: 'modules/booru.js' }, function() { var booru = new Booru($('.post-content .text a:not(.booru_pic)'), options); }); } // Instagram if (options.is('option_embedding_instagram_posts')){ instagram_posts_embedding_init(options); } // Parse webm-links and create video instead if (options.is('option_videos_parse_links')) { if (options.is('option_videos_parse_links_type', 'all')) { parse_all_videos(options); } else { parse_webm(options); } } // Parse audio links if (options.is('option_audios_parse_links')) { parse_all_audios(options); } // Soundcloud if (options.is('option_embedding_soundcloud')) { // Executing Soundcloud player JS API messenger.js({ file: 'vendor/soundcloud/soundcloud.player.api.js', runAt: 'document_end' }, function(response) { console.debug('Soundcloud injection response: %O', response); // If scripts are executed if (response) { // Processing links $('div.post .post-content a[href*="\\:\\/\\/soundcloud\\.com\\/"]').each(function(index) { console.log($(this)); // @todo: вынести в отдельный шаблон $player = $('
\ \ \ \ \ \
'); // Replace or prepend if (options.is('option_embedding_remove_original_link')) { $(this).replaceWith($player); } else { $(this).before($player); } }); } }); } // Parse pleer.com links and create audio instead if (options.is('option_embedding_pleercom')) { parse_pleercom_links(options); } // Parse coub.com links and create iframe instead if (options.is('option_embedding_coubcom')) { parse_coub_links(options); } } // Fancybox if (options.is('option_fancybox')) { // Injecting Fancybox to the page // CSS // @todo message response callback processing messenger.css([ 'vendor/fancybox/source/jquery.fancybox.css', 'css/fancybox/style.css' ]); // JS messenger.js([ { file: 'vendor/fancybox/source/jquery.fancybox.pack.js', runAt: 'document_end' }, { // @todo Move to the option_fancybox_videos section file: 'vendor/fancybox/source/helpers/jquery.fancybox-media.js', runAt: 'document_end' } ], function(response) { // If all JS are executed console.debug('Fancybox injection response: %O', response); if (response) { console.log('Fancybox executed. Processing...'); 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'); }); } else { $('.post-content .text').each(function(idxPost) { $(this).find('a.postimg:not(.youtube)').attr('data-fancybox-group', 'post' + idxPost); }); } // Images if (options.is('option_fancybox_images')) { // Init fancybox $('.postimg:not(.youtube)').fancybox({ type: 'image' }); } // Правим хинты у фансибокса if (options.is('option_fancybox_smart_hints')) { fancybox_set_smart_hints(); } else { $('div.post .postimg').attr('data-fancybox-title', ' '); } // Videos if (options.is('option_fancybox_videos')) { $('.postimg.youtube').addClass('fancybox-media').fancybox({ helpers: { media: { youtube: { params: { autoplay: 1 } } } } }); } // Posts 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 }); } } }); } // NSFW Filtering if (options.is('option_nsfw')) { $('.post-tag-nsfw,.post-tag-сиськи').find('a.postimg:not(.youtube)').attr('data-fancybox-group', 'hidden-images'); if (options.is('option_nsfw_hide_posts')) { if ($('#comments').length == 0) { console.log('Hide NSFW posts in feed, %i hidden', $('div.post').length); $('div.post').addClass('hide-nsfw-posts'); } } // Blurred posts if (options.is('option_nsfw_blur_posts_entire')) { console.log('Bluring NSFW posts'); $('div.post').addClass('blur-nsfw-entire'); } else if (options.is('option_nsfw_blur_posts_images')) { console.log('Bluring images in NSFW posts'); $('div.post').addClass('blur-nsfw-images'); } // Blurred comments if ($('div.post').hasClass('post-tag-nsfw') || $('div.post').hasClass('post-tag-сиськи')) { if (options.is('option_nsfw_blur_comments_entire')) { console.log('Bluring comments'); $('#comments').addClass('blur-nsfw-entire'); } else if (options.is('option_nsfw_blur_comments_images')) { // @hint Никита Ветров официально складывает с себя все претензии, если у кого-то от этого говна упадёт драйвер видео-карты console.log('Bluring images in comments'); $('#comments').addClass('blur-nsfw-images'); } } } // Hotkeys // Send by CTRL+Enter if (options.is('option_ctrl_enter')) { // Reply // Delegated event for all comments $('.content-wrap #comments').on('keydown.point_plus', '.reply-form textarea', function(e) { if (e.ctrlKey && (e.keyCode == 10 || e.keyCode == 13)) { e.preventDefault(); $(this).parent('.reply-form').submit(); } }); // New post $('#new-post-form #text-input,#new-post-form #tags-input').on('keydown.point_plus', function(e) { if (e.ctrlKey && (e.keyCode == 10 || e.keyCode == 13)) { e.preventDefault(); $(this).parent('#new-post-form').submit(); } }); } // Look and feel // Fluid #main layout if (options.is('option_fluid_layout')) { $('#main, #header, #subheader, #footer').css({ 'width': '95%', 'max-width': '95%' }); // TODO: fix #main #left-menu #top-link position } // Image resizing if (options.is('option_images_load_original')) { // Setting new image source $('.postimg:not(.youtube) img').each(function() { console.log($(this).parent('.postimg').attr('href')); $(this).attr('src', $(this).parent('.postimg').attr('href')); }); // Resizing $('.postimg:not(.youtube), .postimg:not(.youtube) img').css({ 'width': 'auto', 'height': 'auto', 'max-width': '100%', 'max-height': '100%' }); } // Visual editor if (options.is('option_visual_editor_post')) { // Add classes $('#new-post-form #text-input, .post-content #text-input').addClass('markitup').css('height', '20em'); // CSS // @todo message response callback processing messenger.css([ 'vendor/markitup/markitup/skins/markitup/style.css', 'css/markitup/skins/markitup/style.css', 'css/markitup/sets/markdown/style.css' ]); // JS messenger.js([ { file: 'vendor/markitup/markitup/jquery.markitup.js', runAt: 'document_end' }, { file: 'js/markitup/sets/markdown/set.js', runAt: 'document_end' } ], function(response) { console.debug('MarkItUp injection response: %O', response); // If scripts are executed if (response) { // Init MarkItUp $('.markitup').markItUp(mySettings); // Send by CTRL+Enter 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)) { e.preventDefault(); $(this).parents('#new-post-form,#post-edit-form').submit(); } }); } } }); } // Google search 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(); document.location.href = '//www.google.ru/search?q=site%3Apoint.im+' + $(this).val(); } }); } // WebSocket 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); // Detecting view mode treeSwitch = $('#tree-switch a.active').attr('href'); console.debug('Comments view mode: %s', treeSwitch); // Error handler ws.onerror = function(err) { console.error('WebSocket error: %O', err); }; // Close handler ws.onclose = function(evt) { console.error('WebSocket closed: %O', evt); }; // todo: refactor to background service // Message handler ws.onmessage = function(evt) { try { // ping :) if (evt.data === 'ping') { console.info('ws-ping'); } else { /** * @namespace * @property {string} a Message type ("comment" or "post") * @property {string} author * @property {number} comment_id * @property {?Array} files * @property {?string} html * @property {string} post_id * @property {?string} text * @property {?number} to_comment_id * @property {?string} to_text */ var wsMessage = JSON.parse(evt.data); if (wsMessage.hasOwnProperty('a') && wsMessage.a !== '') { console.log(wsMessage); switch (wsMessage.a) { // Recommendation comment case 'ok': // Do not break here. Using next case for this message // Comments case 'comment': console.groupCollapsed('WS \'%s\' #%s/%s', wsMessage.a, wsMessage.post_id, wsMessage.comment_id); // Check option if (!options.is('option_ws_comments')) { console.log('Comments processing disabled'); console.groupEnd(); break; } // Check we are in the post if ($('#top-post').length < 1) { console.log('Not in the post, skipping'); console.groupEnd(); break; } // Check we are in specified post if (wsMessage.post_id != postId) { console.log('The comment is not for this post'); console.groupEnd(); break; } // If comment has text if (wsMessage.hasOwnProperty('html') && typeof wsMessage.html === 'string') { // Generating comment from websocket message create_comment_elements({ id: (wsMessage.a === 'ok') ? wsMessage.rcid : wsMessage.comment_id, toId: wsMessage.to_comment_id, postId: wsMessage.post_id, author: wsMessage.author, html: wsMessage.html, fadeOut: options.is('option_ws_comments_color_fadeout'), isRec: (wsMessage.a === 'ok') ? true : false, unread: (point_username && point_username !== wsMessage.author) ? true : false, }, function($comment) { // It's time to DOM console.info('Inserting comment'); // Search for parent comment $parentComment = (wsMessage.to_comment_id) ? ($('div.post[data-comment-id="' + wsMessage.to_comment_id + '"]')) : []; console.log('Parent comment: %O', $parentComment || null); // If list mode or not addressed to other comment if ($('#comments #tree-switch a').eq(0).hasClass('active') || (wsMessage.to_comment_id === null) || (!$parentComment.length)) { // Adding to the end of the list $('.content-wrap #comments #post-reply').before($comment); } else { // Check for children $parentCommentChildren = $parentComment.next('.comments'); // If child comment already exist if ($parentCommentChildren.length > 0) { console.log('Child comments found. Appending...'); $parentCommentChildren.append($comment); } else { console.log('No child comments found. Creating...'); $parentComment.after($('
').addClass('comments').append($comment)); } } // Desktop notifications if (options.is('option_ws_comments_notifications')) { console.log('Showing desktop notification'); messenger.sendMessage({ type: 'showNotification', notificationId: 'comment_' + wsMessage.post_id + '#' + wsMessage.comment_id, avatarUrl: getProtocol() + '//point.im/avatar/' + wsMessage.author + '/80', title: '@' + wsMessage.author + ' #' + wsMessage.post_id + '/' + wsMessage.comment_id, text: wsMessage.text }, function(response) {}); } // Updating comments number update_right_panel_unread_count(); console.groupEnd(); }); } break; // Posts case 'post': console.groupCollapsed('WS post #%s', wsMessage.post_id); if (options.is('option_ws_posts')) { if (options.is('option_ws_posts_notifications')) { console.log('Showing desktop notification'); chrome.runtime.sendMessage({ type: 'showNotification', notificationId: 'post_' + wsMessage.post_id, avatarUrl: getProtocol() + '//point.im/avatar/' + wsMessage.author + '/80', title: 'Post by @' + wsMessage.author + ' #' + wsMessage.post_id, text: wsMessage.text }, function(response) {}); } } console.groupEnd(); break; // Recommendation case 'rec': console.groupCollapsed('WS recommendation'); console.groupEnd(); break; default: console.groupCollapsed('WS other'); console.groupEnd(); break; } } } } catch (e) { console.log('WebSocket exception:'); console.log(e); console.log(evt.data); } ; }; } // Font size if ((options.is('option_enlarge_font')) && (options.get('option_enlarge_font_size'))) { $('body').css('font-size', (options.get('option_enlarge_font_size') / 100) + 'em'); } // @ before username if (options.is('option_at_before_username')) { // @todo message response callback processing messenger.css('css/modules/at_before_username.css'); } if (options.is('option_ajax')) { // Comments if (options.is('option_ajax_comments')) { messenger.css({ file: 'modules/ajax-comments.css' }); messenger.js({ file: 'modules/ajax-comments.js' }, function() { var ajaxComments = new AjaxComments(); }); } } // Hightlight post with new comments if (options.is('option_other_hightlight_post_comments')) { mark_unread_post(); } // Show recommendation count and unique commentators count if (options.is('option_other_show_recommendation_count')) { set_posts_count_label(); } // `Space` key scroll handler if (options.is('option_other_scroll_space_key')){ set_space_key_skip_handler(); } // Система комментариев у пользователей if (options.is('option_other_comments_user_system')) { hints_init_user_system(); } // Nesting level indicator if (options.is('option_other_comments_nesting_level')) { $('#comments').addClass('nesting_level'); } // Обновляем кол-во постов и непрочитанных комментариев if (options.is('option_other_comments_count_refresh')) { set_comments_refresh_tick(options); } // Твиты из Твиттера if (options.is('option_embedding_twitter_tweets')) { twitter_tweet_embedding_init(); } // Post drafts if (options.is('option_other_post_draft_save')) { draft_set_save_handler(); draft_restore(); } $('#point-plus-debug').fadeOut(1000); }); } function getProtocol() { return ((location.protocol == 'http:') ? 'http:' : 'https:'); } // Monts for Date.getMonth() var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; /** * Creating new comment elements for dynamic injection into the DOM * * @param {object} commentData Comment data * @param {string|number} commentData.id ID of the created comment * @param {string|number} commentData.toId ID of the comment replying to * @param {string} commentData.postId ID of the post * @param {string} commentData.author Author of the comment * @param {string} commentData.html HTML of the comment text * @param {boolean} commentData.fadeOut Is fadeout enabled or not * @param {boolean|null} commentData.isRec Is comment also a recommendation * @param {boolean} commentData.unread Is comment unread * @param {function} onCommentCreated Callback which is called when comment is ready * */ function create_comment_elements(commentData, onCommentCreated) { var $anchor = $('').attr('name', commentData.id); // Initializing comment element var $commentTemplate = $('
').attr({ 'class': 'post' + (commentData.unread ? ' unread' : ''), 'data-id': commentData.postId, 'data-comment-id': commentData.id, 'data-to-comment-id': commentData.id || '' }); // If comment is also a recommendation if (commentData.isRec || false) { $commentTemplate.addClass('recommendation'); } // Loading HTML template $commentTemplate.load(chrome.extension.getURL('includes/comment.html'), function() { // Load complete console.info('comment.html loaded'); // Date and time of comment var date = new Date(); // Data for template var userLink = '//' + commentData.author + '.point.im/'; var csRfToken = $('.reply-form input[name="csrf_token"]').first().val(); // Filling template // Date and time $commentTemplate.find('.info .created') .append($('').html((date.getDate().toString()) + ' ' + months[date.getMonth()])) // Crutchy fix .append($('
')) ///Crutchy fix .append($('').html(date.getHours() + ':' + ((date.getMinutes().toString().length < 2) ? ('0' + date.getMinutes().toString()) : (date.getMinutes().toString())))); // Comment text $commentTemplate.find('.text').html(commentData.html); // Author $commentTemplate.find('.author a.user').attr('href', userLink).text(commentData.author); // Avatar and link $commentTemplate.find('.info a').attr('href', userLink).children('img.avatar').attr('src', '//point.im/avatar/' + commentData.author + '/24'); // Post and comment ID's link $commentTemplate.find('.clearfix .post-id a').attr('href', '//point.im/' + commentData.postId + '#' + commentData.id).text('#' + commentData.postId + '/' + commentData.id) // Adding answer label // @todo i18n .after((commentData.toId != null) ? (' в ответ на
/' + commentData.toId + '') : ''); // Setting action labels and other attributes $commentTemplate.find('.action-labels .reply-label').attr('for', 'reply-' + commentData.postId + '_' + commentData.id); $commentTemplate.find('.action-labels .more-label').attr('for', 'action-' + commentData.postId + '_' + commentData.id); $commentTemplate.find('.post-content input[name="action-radio"]').attr('id', 'action-' + commentData.postId + '_' + commentData.id); // Bookmark link $commentTemplate.find('.action-buttons a.bookmark').attr('href', $('#top-post .info a').attr('href') + commentData.postId + '/b?comment_id=' + commentData.id + '&csrf_token=' + csRfToken); // Reply form $commentTemplate.find('.post-content input.reply-radio').attr('id', 'reply-' + commentData.postId + '_' + commentData.id); $commentTemplate.find('.post-content form.reply-form').attr('action', '/' + commentData.postId); $commentTemplate.find('.post-content form.reply-form textarea[name="text"]').text('@' + commentData.author + ', '); $commentTemplate.find('.post-content form.reply-form input[name="comment_id"]').val(commentData.id); $commentTemplate.find('.post-content form.reply-form input[name="csrf_token"]').val(csRfToken); ///Filling template // Fading out highlight if needed if (commentData.fadeOut) { console.log('Fading out the highlight'); $commentTemplate.children('.pp-highlight').delay(250).fadeOut(20000); } // @todo add indentation indicator support // Hiding $commentTemplate.hide().delay(250).fadeIn(2000); // Triggering callback onCommentCreated($anchor.add($commentTemplate)); }); } /** * Update undread comments count in right panel * * @param {?object} $span jQuery object of unread count */ function update_right_panel_unread_count($span) { var unread_count = $('#comments div.post.unread').length; if (typeof $span === 'undefined') { $span = $('#pp-unread-count'); } if ($span.length > 0) { $span.text(unread_count); } } // Помечаем непрочитанные посты более видимо чем каким-то баджем // Эта часть написана @RainbowSpike function mark_unread_post() { var divs = $(".content-wrap > div.post").css({'padding-left':'2px'}); // массив постов for (var i = 0; i < divs.length; i++) { // обыск постов var spans = $(divs[i]).find(".unread"); // поиск метки непрочитанных комментов if (spans.length > 0) { // если в посте есть непрочитанные комменты... $(divs[i]).css({//...залить пост зеленоватым и скруглить 'background-color': '#EEFFEE', 'border-radius': '10px' }); } } } // Webm function parse_webm(current_options) { $('.post-content a:not(.booru_pic)').each(function(num, obj) { var href = obj.href; var n = null; if (n = href.match(new RegExp('\\.webm(\\?.+)?$', 'i'))) { var player = document.createElement('video'); // Там может быть не vp8+vorbis, но мы этого никак не узнаем $(player).html('').attr('controls', 'controls').css({ 'display': 'block', 'max-width': '95%' }).addClass('parsed-webm-link'); obj.parentElement.insertBefore(player, obj); if (current_options.is('option_embedding_remove_original_link')) { $(obj).hide(); } } }); } // Видео function parse_all_videos(current_options) { $('.post-content a:not(.booru_pic)').each(function(num, obj) { var href = obj.href; var n = null; if (n = href.match(new RegExp('\\.(webm|avi|mp4|mpg|mpeg)(\\?.+)?$', 'i'))) { var player = document.createElement('video'); var mime = video_extension_to_mime(n[1]); $(player).html('').attr('controls', 'controls').css({ 'display': 'block', 'max-width': '95%' }).addClass('parsed-webm-link'); obj.parentElement.insertBefore(player, obj); if (current_options.is('option_embedding_remove_original_link')) { $(obj).hide(); } } }); } function video_extension_to_mime(extension) { switch (extension) { case 'webm':return 'video/webm; codecs="vp8, vorbis'; case 'avi' :return 'video/avi;'; case 'mp4' :return 'video/mp4;'; case 'mpg' :return 'video/mp4;'; case 'mpeg':return 'video/mp4;'; } } // Аудио function parse_all_audios(current_options){ $('.post-content a').each(function(num, obj) { if ($(obj).hasClass('booru_pic')) { return; } var href = obj.href; var n = null; if (n = href.match(new RegExp('^https?:\\/\\/([a-z0-9.-]+)\\/[a-z0-9_\\/.%-]+\\.(mp3|ogg|wav)(\\?.+)?$', 'i'))) { var domain = n[1]; // Проверяем откуда мы грузимся if (domain.match(new RegExp('\\.vk\\.me$', 'i'))){ // Так то ж Контакт! if (typeof(n[3])=='undefined'){ return; } if (!n[3].match('extra\\=', 'i')){ return; } } var player = document.createElement('audio'); var mime = audio_extension_to_mime(n[2]); $(player).html('').attr('controls', 'controls').css({ 'display': 'block', 'max-width': '350px' }).addClass('parsed-audio-link'); obj.parentElement.insertBefore(player, obj); if (current_options.is('option_embedding_remove_original_link')) { $(obj).hide(); } } }); } function audio_extension_to_mime(extension) { switch (extension) { case 'mp3': return 'audio/mpeg'; case 'ogg': return 'audio/ogg; codecs=vorbis'; case 'wav': return 'audio/vnd.wave'; } } /** * Показывает количество рекомендаций и комментаторов у постов */ function set_posts_count_label() { var posts = {}; var ids; $('.content-wrap > div.post').each(function(n, post) { var $post = $(post); var postId = $post.data('id'); posts[postId] = $post; }); ids = Object.keys(posts); $('.content-wrap > div.post .post-id a .cn').addClass('changed_background'); $.ajax('https://api.kanaria.ru/point/get_post_info.php?list=' + encodeURIComponent(ids.join(',')), { dataType: 'json', success: function(data) { ids.forEach(function(id) { var postInfo = data.list[id]; if (postInfo) { posts[id].find('.post-id').after( '
' + ' ' + ' ' + '
' ) posts[id].find('.pp-unique-comments').text(postInfo.count_comment_unique); posts[id].find('.pp-recommendation-count').text(postInfo.count_recommendation); } }); } }); } function parse_pleercom_links(current_options) { $('.post-content a').each(function(num, link) { var $link = $(link); var href = link.href; var matches = href.match(new RegExp('^https?:\\/\\/pleer\\.com\\/tracks\\/([0-9a-z]+)', 'i')); if (matches) { trackHref = 'http://embed.pleer.com/normal/track?id=' + matches[1] + '&t=grey'; $link.before('' + '' + ''); if (current_options.is('option_embedding_remove_original_link')) { $link.remove(); } } }); } // Проставляем теги у постов // @hint В данный момент эта фича используются для NSFW, потом выборку по тегам можно будет использовать много где function create_tag_system() { $('.content-wrap > div.post').each(function() { var tags = $(this).find('div.tags a.tag'); for (var i = 0; i < tags.length; i++) { var tag_name = $(tags[i]).html().toLowerCase(); $(this).addClass('post-tag-' + tag_name); } }); } // Скролл по пробелу function set_space_key_skip_handler() { if ($('#comments').length > 0) { return; } // @todo Свериться с Best-practice биндинга функций. Мб там on или bind $(document.body).keydown(function(e) { // @todo Я хотел по отпусканию кнопки, но там уже скролл срабатывает // проверяем фокус if ($(':focus').length > 0) { return; } var k = event.keyCode; if (k == 32) { space_key_event(); return false; } }); } function space_key_event() { var scroll_current = Math.floor($('body').scrollTop()); var posts = $('.content-wrap > div.post'); for (var i = 0; i < posts.length; i++) { var this_top_px = Math.floor(posts.eq(i).offset().top); if (this_top_px > scroll_current) { $('body').animate({ 'scrollTop': this_top_px }, 200); return; } } } /** * Last draft text * @type {string} */ var draft_last_text = ''; /** * Last draft tags * @type {string} */ var draft_last_tags = ''; /** * Is extension now saving draft * @type {boolean} */ var draft_save_busy = false; /** * Last draft saving time * @type {Date|null} */ var draft_save_last_time = null; /** * Is there any setTimeout'ed handlers * @type {boolean} */ var draft_waiting = false; /** * Restore draft from localStorage */ function draft_restore() { chrome.storage.local.get(['point_draft_text', 'point_draft_tags'], function(items) { if ($('#new-post-form #text-input').val() === '') { $('#new-post-form #text-input').val(items.point_draft_text); draft_last_text = items.point_draft_text; } if ($('#new-post-form #tags-input').val() === '') { $('#new-post-form #tags-input').val(items.point_draft_tags); draft_last_tags = items.point_draft_tags; } }); } /** * Set draft save handler */ function draft_set_save_handler() { $('#text-input, #tags-input').on('keyup', function() { draft_save_check(); // For last keyup if (!draft_waiting) { setTimeout(draft_save_check, 3000); draft_waiting = true; } }); // Adding span indicator $('#new-post-wrap .footnote').append($('')); } /** * Check if we can save the draft now */ function draft_save_check() { if (draft_save_busy) { return; } if (draft_save_last_time !== null) { if ((new Date()).getTime() < draft_save_last_time.getTime() + 3000) { return; } } var current_text = $('#new-post-form #text-input').val(); var current_tags = $('#new-post-form #tags-input').val(); if ((draft_last_text === current_text) && (draft_last_tags === current_tags)) { draft_save_busy = false; return; } draft_save_busy = true; draft_save_last_time = new Date(); // @todo i18n $('#draft-save-status').text(chrome.i18n.getMessage('msg_saving_post_draft')).show(); // Saving current data draft_last_text = current_text; draft_last_tags = current_tags; // Save it using the Chrome extension storage API. chrome.storage.local.set({ point_draft_text: draft_last_text, point_draft_tags: draft_last_tags }, function() { // Notify that we saved. draft_save_busy = false; draft_waiting = false; setTimeout(function() { $('#draft-save-status').fadeOut(1000); }, 1000); }); } // Парсим ссылки на coub function parse_coub_links(current_options) { $('.post-content a').each(function(num, obj) { var href = obj.href; var n = null; if (n = href.match(new RegExp('^https?:\\/\\/coub\\.com\\/view\\/([0-9a-z]+)', 'i'))) { var player = document.createElement('iframe'); var parent_width = $(obj.parentElement).width(); $(player).attr({ 'src': 'https://coub.com/embed/' + n[1] + '?muted=false&autostart=false&originalSize=false&hideTopBar=false&startWithHD=true', 'allowfullscreen': 'true' }).css({ 'max-width': '640px', 'border': 'none', 'width': Math.floor(parent_width * 0.9), 'height': Math.ceil(parent_width * 0.9 * 480 / 640) }).addClass('embeded_video').addClass('embeded_video_' + n[1]); obj.parentElement.insertBefore(player, obj); if (current_options.is('option_embedding_remove_original_link')) { $(obj).hide(); } } }); } // Правим хинт в FancyBox function fancybox_set_smart_hints(){ $('div.post').each(function() { var all_post_images = $(this).find('.postimg'); if (all_post_images.length == 0) { return; } var tags = $(this).find('div.tags a.tag'); var default_hint_text = '';// Дефолтный текст для хинта в FancyBox, если не нашлость другого // Сначала теги for (var i = 0; i < tags.length; i++) { var tag_name = $(tags[i]).html().toLowerCase(); default_hint_text += ' ' + tag_name; } // Потом текст var textcontent = $(this).find('.text-content'); if (textcontent.length > 0) { textcontent = textcontent[0]; for (var i = 0; i < textcontent.childNodes.length; i++) { var current_child_node = textcontent.childNodes[i]; if ((current_child_node.nodeName !== 'P') && (current_child_node.nodeName !== '#text')) { continue; } var a = $(current_child_node).find('a.postimg'); if (a.length > 0) { continue; } var tmp_str = current_child_node.textContent.replace(/(\n(\r)?)/g, ' '); tmp_str = tmp_str.replace("\t", " "); default_hint_text += ' ' + tmp_str; } } // Режем текст default_hint_text = default_hint_text.replace(new RegExp(' {2,}'), ' ').replace(new RegExp(' +$'), '').substr(1); if (default_hint_text.length > 140) { default_hint_text = default_hint_text.substr(0, 140 - 3) + '...'; } // Выставляем дефолтный all_post_images.attr('data-fancybox-title', default_hint_text); // А теперь перебираем по одному все картинки var paragraphs = $(this).find('.post-content > .text > p, .post-content > .text, .text-content > p, .text-content'); paragraphs.each(function() { var nodes = this.childNodes; for (var i = 0; i < nodes.length - 2; i++) { if ($(nodes[i]).hasClass('booru_pic')) { if (nodes[i + 2].nodeName == '#text') { $(nodes[i]).attr('data-fancybox-title', nodes[i + 2].textContent); i += 2; continue; } } } }); }); } /** * Система заметок о пользователях * https://bitbucket.org/skobkin/chrome_point_plus/issue/50/--------------------------- */ // Инициализируем function hints_init_user_system() { chrome.storage.sync.get('point_user_hints', function(items) { if (typeof(items.point_user_hints) == 'undefined') { // Первый запуск системы chrome.storage.sync.set({'point_user_hints': {}}, function() { hints_draw_main_user_hint({}); hints_set_titles_on_users({}); }); } else { // Второй+ запуск системы hints_draw_main_user_hint(items.point_user_hints); hints_set_titles_on_users(items.point_user_hints); } }); } // Рисуем хинт и кнопку под текущим пользователем function hints_draw_main_user_hint(items) { var current_user_name = $('.aside .info h1').text().toLowerCase(); if (current_user_name.length == 0) { return; } var current_user_hint_block = document.createElement('div'); $('.aside .aside-content #counters')[0].parentElement. insertBefore(current_user_hint_block, $('.aside .aside-content #counters')[0]); $(current_user_hint_block).addClass('current-user-hint'); // Рисуем кнопки управления var buttons_block = document.createElement('div'); $(buttons_block).addClass('buttons'). html(''); current_user_hint_block.appendChild(buttons_block); $(buttons_block).find('.edit').on('click', function() { chrome.storage.sync.get('point_user_hints', function(items) { var current_text = ''; if (typeof(items.point_user_hints[current_user_name]) !== 'undefined') { current_text = items.point_user_hints[current_user_name]; } $('.current-user-hint .change_hint_block').slideDown(500); $('.current-user-hint .change_hint_block textarea').val(current_text); }); }); // Рисуем текст var current_text = ''; if (typeof(items[current_user_name]) !== 'undefined') { current_text = items[current_user_name]; } var text_block = document.createElement('div'); $(text_block).addClass('text'); safe_saned_text(current_text, $(text_block)); current_user_hint_block.appendChild(text_block); // Рисуем невидимый блок для управления var change_hint_block = document.createElement('div'); $(change_hint_block).addClass('change_hint_block').hide(). html('' + 'Отмена'); $(change_hint_block).find('.button_save').on('click', function() { $('.current-user-hint .change_hint_block').slideUp(500); var new_text = $('.current-user-hint .change_hint_block textarea').val(); safe_saned_text(new_text, $('.current-user-hint > .text').hide().fadeIn(750)); hints_save_new_hint(current_user_name, new_text); }); $(change_hint_block).find('.button_cancel').on('click', function() { $('.current-user-hint .change_hint_block').slideUp(500); }); current_user_hint_block.appendChild(change_hint_block); } // Nokita Kaze снимает с себя все претензии по этому коду, обращайтесь к фаундеру проекта function safe_saned_text(text, object) { var n = text.split(/\r?\n/); object.text(''); for (var i = 0; i < n.length; i++) { var d = document.createElement('p'); $(d).text(n[i]); object[0].appendChild(d); } } // Рисуем title'ы на всех доступных пользователях, точнее на их аватарках function hints_set_titles_on_users(items) { $('a').each(function() { var href = $(this).attr('href'); if (typeof(href) == 'undefined') { return; } var n = href.match(new RegExp('^https?\\://([0-9a-z-]+)\\.point\\.im/$', 'i')); if (n == null) { return; } var this_user_name = n[1].toLowerCase(); if (typeof(items[this_user_name]) == 'undefined') { return; } $(this).attr({ 'title': items[this_user_name] }); }); } // Сохраняем новый хинт function hints_save_new_hint(username, new_hint) { chrome.storage.sync.get('point_user_hints', function(items) { items.point_user_hints[username] = new_hint; chrome.storage.sync.set({'point_user_hints': items.point_user_hints}); }); } /** * Обновляем кол-во комментариев и непрочитанных новых постов в ленте */ function set_comments_refresh_tick(current_options) { // Проверяем, чтобы были баджи if ($('#main #left-menu #menu-recent .unread').length == 0) { $('#main #left-menu #menu-recent').append(''); } if ($('#main #left-menu #menu-comments .unread').length == 0) { $('#main #left-menu #menu-comments').append(''); } // Ставим тик setInterval(function() { comments_count_refresh_tick(current_options); }, 60000); // Ставим слежение за позицией мыши if (current_options.is('option_other_comments_count_refresh_title')) { $(document). on('mouseenter', function() { set_comments_refresh_clear_title_marks(); }).on('mouseleave', function() { window_focused = false; }); $(window). on('focus', function() { set_comments_refresh_clear_title_marks(); }).on('blur', function() { window_focused = false; }); } } var window_focused = true; // Очищаем [0; 0] function set_comments_refresh_clear_title_marks() { var new_title = document.title.replace(new RegExp('^\\[[0-9]+\\; [0-9]+\\] '), ''); document.title = new_title; window_focused = true; } // Проверка обновления комментариев, обновляется по крону function comments_count_refresh_tick(current_options) { $('#debug_iframe').remove(); var iframe = document.createElement('iframe'); document.body.appendChild(iframe); $(iframe).on('load', function() { var a = $(iframe.contentDocument.body).find('#main #left-menu #menu-recent .unread'); var b = $(iframe.contentDocument.body).find('#main #left-menu #menu-comments .unread'); var count_recent = (a.length == 0) ? 0 : parseInt(a.text()); var count_comments = (b.length == 0) ? 0 : parseInt(b.text()); console.log('Comments: %d, Recent: %d', count_comments, count_recent); if (count_recent > 0) { if (parseInt($('#main #left-menu #menu-recent .unread').text()) != count_recent) { $('#main #left-menu #menu-recent .unread').text(count_recent).show().css({ 'background-color': '#f2ebee', 'color': '#7c3558' }); setTimeout(function() { $('#main #left-menu #menu-recent .unread').css({ 'background-color': '', 'color': '' }); }, 15000); } } else { $('#main #left-menu #menu-recent .unread').text('0').hide(); } if (count_comments > 0) { if (parseInt($('#main #left-menu #menu-comments .unread').text()) != count_comments) { $('#main #left-menu #menu-comments .unread').text(count_comments).show().css({ 'background-color': '#f2ebee', 'color': '#7c3558' }); setTimeout(function() { $('#main #left-menu #menu-comments .unread').css({ 'background-color': '', 'color': '' }); }, 15000); } } else { $('#main #left-menu #menu-comments .unread').text('0').hide(); } 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)) { new_title = '[' + count_recent + '; ' + count_comments + '] ' + new_title; } document.title = new_title; } $('#debug_iframe').remove(); }).attr({ // Из-за Same Origin'а я дёргаю несуществующую страницу на том же домене, чтобы получить баджи и, // в то же время не прочитать новые сообщения в ленте, которые могли появиться, если их написал // этот пользователь 'src': '//' + document.domain + '/?tag=' + Math.random(), 'id': 'debug_iframe' }).css({ 'width': '600px', 'height': '300px' }).hide(); } /** * Встраиваем твиты из Твиттера */ function twitter_tweet_embedding_init() { // Чёрная магия. Выбираемся из манямирка, прихватив с собой пару сраных функций // https://developer.chrome.com/extensions/content_scripts Isolated World var e = document.createElement("script"); e.appendChild(document.createTextNode(twitter_tweet_embedding_wait_for_ready_injected.toString() + twitter_tweet_embedding_parse_links.toString() + 'twitter_tweet_embedding_wait_for_ready_injected();')); document.head.appendChild(e); // Встраиваем скрипт так, как описано в best twitter practice https://dev.twitter.com/web/javascript/loading window.twttr = (function(d, s, id) { var t, js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "https://platform.twitter.com/widgets.js"; fjs.parentNode.insertBefore(js, fjs); return window.twttr || (t = { _e: [], ready: function(f) { t._e.push(f); } }); }(document, "script", "twitter-wjs")); } /** * Проверяем загрузились ли мы. Эта функция запускается из page scope */ function twitter_tweet_embedding_wait_for_ready_injected() { if (typeof(window.twttr) == 'undefined') { setTimeout(twitter_tweet_embedding_wait_for_ready_injected, 100); return; } if (typeof(window.twttr.widgets) == 'undefined') { setTimeout(twitter_tweet_embedding_wait_for_ready_injected, 100); return; } twitter_tweet_embedding_parse_links(); } /** * Парсим все ссылки. Эта функция запускается из page scope */ function twitter_tweet_embedding_parse_links() { // Обрабатываем все твиты var twitter_tweet_count = 0; $('.post-content a:not(.booru_pic)').each(function(num, obj) { var href = obj.href; var n; if (n = href.match(new RegExp('^https?://(www\\.)?twitter\\.com/[^/]+/status/([0-9]+)', 'i'))) { var tweet = document.createElement('div'); $(tweet).attr({ 'id': 'tweet-' + twitter_tweet_count, 'data-tweet-id': n[2] }).addClass('twitter-tweet-embedded'); obj.parentElement.insertBefore(tweet, obj); window.twttr.widgets.createTweet( n[2], tweet, { 'lang': 'ru' } ); twitter_tweet_count++; } }); } /** * Instagram posts * * @param {OptionsManager} options OptionsManager with current options */ function instagram_posts_embedding_init(options) { var regex = new RegExp('^https?://(www\\.)?instagram\\.com/p/([\\w-]+)/?', 'i'); $('.post-content a:not(.booru_pic)').each(function(num, link) { var $link = $(link); var href = link.href; var matches = href.match(regex); if (matches) { $.ajax('https://api.instagram.com/oembed?url=' + 'http://instagr.am/p/' + matches[2] + '/', { dataType: 'json', success: function(response) { var $imgLink = $(''); var $img = $(''); $img.attr({ src: response.thumbnail_url, alt: response.title }); $imgLink .addClass('postimg instagram-post-embedded') .attr({ id: 'instagram-' + num, href: 'http://instagram.com/p/' + matches[2] + '/media/?size=l', title: response.title, traget: '_blank', 'data-fancybox-group': (options.is('option_fancybox_bind_images_to_one_flow')) ? 'one_flow_gallery' : '', 'data-fancybox-title': (options.is('option_fancybox_smart_hints')) ? response.title : '' }) .append($img); $link.before($imgLink); if (options.is('option_embedding_remove_original_link')) { $link.remove(); } } }); } }); }