/* Google+ Conditional Fuu => Automatically reply posts on certain conditions. Copyright (C) 2012 Jingqin Lynn This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ // ==UserScript== // @name Google+ Conditional Fuu // @namespace http://project.quietmusic.org/j/ // @description Automatically reply posts on certain conditions. // @match https://plus.google.com/* // ==/UserScript== (function() { //Use the element to detect Google+ main page. var base = document.querySelector('base'); if (!base) return; if (!base.href.match(/^https:\/\/plus\.google\.com(\/u\/\d+)?\/?/)) return; //Chrome V8 don't support unsafeWindow. Time for a hack. if (window == unsafeWindow) { var span = document.createElement('span'); span.setAttribute('onclick', 'return window;'); unsafeWindow = span.onclick(); } //For shorter code. var win = unsafeWindow; win.ext = win.ext || {}; if (win.ext.condFuu) { return; } else { win.ext.condFuu = {}; } var main = function($) { var getLocale = function() { var lang = { 'en': { 'fuuDefaultValue' : 'Fuu', 'input_cond_xpath' : 'Please input the XPath expression for the posts to be auto-replyed.', 'input_reply_value' : 'Please input the text of the reply:' }, 'zh-hans': { 'fuuDefaultValue' : '呼', 'input_cond_xpath' : '请输入自动回复时,贴子需要满足的条件(XPath 表达式):', 'input_reply_value' : '请输入自动回复的文本:' }, }; //alias for languages lang['zh-cn'] = lang['zh-hans']; lang['zh-sg'] = lang['zh-hans']; lang['zh-tw'] = lang['zh-hant']; lang['zh-hk'] = lang['zh-hant']; lang['zh'] = lang['zh-hans']; //fallback lang[''] = lang['en']; //general fallback var langCode = localStorage.getItem('cond-fuu-lang') || $.gplus.getLangCode(); var loc = lang[langCode]; if(!loc) { loc = lang[langCode.substr(0,2)]; if(!loc) { loc = lang['']; } } return loc; }; var fuuOnPost = function (post) { var fuuComplete = function() { post.stopDynamicSelect(handler); $('.ext-fuu-button').attr('data-ext-fuu-ed', 'true'); }; var handler = post.dynamicSelect('.g-z-e-Ia-df', function(ed) { fuu(ed, post, fuuComplete); }); $.gplus.doClick($('.rBJ4nd', post)[0]); }; //Add fuu-text to the editor and then submit the reply. var fuu = function (ed, post, callback) { if(ed.children.length == 0) { var onNodeInserted = function(e) { if(!e) e = event; ed.removeEventListener('DOMNodeInserted', onNodeInserted, false); fuu(ed, post, callback); } ed.addEventListener('DOMNodeInserted', onNodeInserted, false); return; } if(ed.children[0].tagName == 'DIV') { if(callback) callback(); var handler = $(ed).dynamicSelect('iframe', function (frame) { $(ed).stopDynamicSelect(handler); //The content in the frame is changing, and DOMNodeInserted won't work. //Use setInterval as a workaround. var it = setInterval(function() { if(frame.contentDocument.body.classList.contains('editable')) { clearInterval(it); fuu(frame.contentDocument.body, post); } }, 100); }); return; } if(callback) callback(); //ed.ownerDocument.body.scrollIntoView(ed); ed.textContent = localStorage.getItem('cond-fuu-text') || loc['fuuDefaultValue']; //"Input" something to enable the submit button. $.gplus.doKeypress(ed); var submit = $('.b-a-ga', post); if(submit.attr('aria-disabled') != 'true') { $.gplus.doClick(submit[0]); } else { //Webkit don't support DOMAttrModified. //Use setInterval as workaround. //Todo: use DOMAttrModified on supported browsers such as Firefox. var it = setInterval(function() { if(submit.attr('aria-disabled') != 'true') { clearInterval(it); $.gplus.doClick(submit[0]); }; }, 100); } return true; }; var showSettingUI = function (e) { var fuuText = localStorage.getItem('cond-fuu-text') || loc['fuuDefaultValue']; localStorage.setItem('cond-fuu-text', prompt(loc['input_reply_value'], fuuText) || fuuText); var fuuXPath = localStorage.getItem('cond-fuu-xpath') || 'false()'; localStorage.setItem('cond-fuu-xpath', prompt(loc['input_cond_xpath'], fuuXPath) || fuuXPath); localStorage.setItem('cond-fuu-lastPost', new Date()); if (e) e.preventDefault(); }; //Init var loc = getLocale(); //Match any new posts $(document.body).dynamicSelect('.Te', function(post) { post = $(post); var handler = post.dynamicSelect('.k-Qf-C-RySO6d.UzyZPb', function (postLink) { var title = postLink.getAttribute('title'); if (title != "Timestamp") { post.stopDynamicSelect(handler); var time = new Date(title); var lastTime = new Date(localStorage.getItem('cond-fuu-lastPost')); if (time && time > lastTime && post.xpath(localStorage.getItem('cond-fuu-xpath') || 'false()', 'boolean')) { localStorage.setItem('cond-fuu-lastPost', time); post.attr('data-ext-cond-fuu', 'matched'); fuuOnPost(post); } } }); }); $(document.body).dynamicSelect('.afEYIc', function(button) { $(button).on('contextmenu', showSettingUI); }); }; if(win.ext.toolkitReady) { main(win.jQuery); } else { win.ext.toolkitCallback = win.ext.toolkitCallback || []; win.ext.toolkitCallback.push(main); } })();