Skip to content

Instantly share code, notes, and snippets.

@quietlynn
Created January 18, 2012 15:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quietlynn/1633597 to your computer and use it in GitHub Desktop.
Save quietlynn/1633597 to your computer and use it in GitHub Desktop.
Google+ Post Censorship => Censor the words in your post.
/*
Google+ Post Censorship => Censor the words in your post.
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 <http://www.gnu.org/licenses/>.
*/
// ==UserScript==
// @name Google+ Post Censorship
// @namespace http://project.quietmusic.org/j/
// @description Censor the words in your post.
// @match https://plus.google.com/*
// ==/UserScript==
function doClick(target) {
var e;
e = document.createEvent("MouseEvents");
e.initEvent("mousedown", true, true);
target.dispatchEvent(e);
e = document.createEvent("MouseEvents");
e.initEvent("click", true, true);
target.dispatchEvent(e);
e = document.createEvent("MouseEvents");
e.initEvent("mouseup", true, true);
target.dispatchEvent(e);
return target;
};
function doKeypress(target) {
var e = document.createEvent("KeyboardEvent");
e.initEvent("keypress", true, true, window, 0, 0, 0, 0, 0, "e".charCodeAt(0));
target.dispatchEvent(e);
return target;
};
var urlPrefix = "http://sopastrike.com/#?/censor/";
var censorChar = "█";
var censorCharCode = censorChar.charCodeAt(0);
var censorWord = function (len) {
return Array(len + 1).join(censorChar);
}
var uncensorText = function(e) {
if(!e) e = event;
e.preventDefault();
var span = e.target;
span.parentElement.replaceChild(document.createTextNode(span.title), span);
};
var onCensorButtonClick = function (e) {
if(!e) e = event;
e.preventDefault();
var sel = document.getSelection();
if(sel.anchorNode == sel.focusNode && sel.anchorNode instanceof Text) {
var start = sel.anchorOffset;
var end = sel.focusOffset;
if(start == end) return;
if(start > end) {
var t = start;
start = end;
end = t;
}
var txt = sel.anchorNode;
var post = txt.textContent;
var beforeText = document.createTextNode(post.substr(0, start));
var span = document.createElement("span");
span.textContent = censorWord(end - start);
span.setAttribute("title", post.substring(start, end));
span.setAttribute("contenteditable", "false");
span.setAttribute("tabindex", "-1");
span.setAttribute("censored", "true");
span.addEventListener("contextmenu", uncensorText, false);
var p = txt.parentElement;
txt.nodeValue = post.substr(end);
p.insertBefore(beforeText, txt);
p.insertBefore(span, txt);
if(!p.getAttribute("censored")) {
p.setAttribute("censored", "true");
var onShareButtonMousedown = function(e) {
if(!e) e = event;
e.preventDefault();
e.target.removeEventListener("mousedown", onShareButtonMousedown, false);
p.removeAttribute("censored");
var spans = p.querySelectorAll("span[censored='true']");
var uncensored = new Array();
for(var i = 0; i < spans.length; i++) {
uncensored.push(encodeURIComponent(spans[i].title));
}
var uri = urlPrefix + uncensored.join("/");
addUncensoredLink(uri);
};
document.querySelector(".e-U-me-Qf").addEventListener("mousedown", onShareButtonMousedown, false);
}
}
};
var addUncensoredLink = function (uri) {
var insertTo = document.querySelector(".k-Qf-e-fa");
//This will fail for unknown reasons:
//insertTo.addEventListener('DOMNodeInserted', onMediaInserted, false);
doClick(document.querySelector(".e-ja-p.e-ja-p-C"));
var intMedia = setInterval(function() {
var urlBox = insertTo.querySelector(".Nf");
if(urlBox) {
clearInterval(intMedia);
urlBox.value = uri;
doKeypress(urlBox);
var addButton = document.querySelector(".jhqR7");
var i = setInterval(function() {
if(addButton.getAttribute("aria-disabled") == "false") {
clearInterval(i);
doClick(addButton);
}
}, 100);
}
}, 100);
};
function checkElement(ele) {
if(!ele.classList) return;
var linkButton = ele;
if(!ele.classList.contains("e-ja-p") || !ele.classList.contains("e-ja-p-C")) {
linkButton = ele.querySelector(".e-ja-p.e-ja-p-C");
if(!linkButton) return;
}
if(ele.querySelector(".ext-censor-button")) return;
var button = document.createElement("button");
button.setAttribute("role", "button");
button.setAttribute("class", "e-ja-p ext-censor-button");
button.setAttribute("title", "Censor");
button.textContent = censorChar + censorChar;
button.setAttribute("style", "border: none; top: -10px; position: relative; padding: 0; margin-right: 8px;");
button.addEventListener("click", onCensorButtonClick, false);
linkButton.parentElement.appendChild(button);
}
//checkElement(document.body);
function uncensorPost(a) {
var content = a.parentElement.parentElement.parentElement.parentElement.querySelector(".rXnUBd");
var uncensored = a.href.substr(urlPrefix.length).split("/");
var uncensoredPos = 0;
var result = document.evaluate(".//text()", content, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for(var i = 0; i < result.snapshotLength; i++) {
var text = result.snapshotItem(i);
var match = null;
var pos = -1;
var str = null;
while((pos = (str = text.nodeValue).indexOf(censorChar)) >= 0) {
if(uncensoredPos > uncensored.length) return;
var end = pos + 1;
while(str.charCodeAt(end) == censorCharCode) end++;
var p = text.parentNode;
if(pos > 0) {
var beforeText = document.createTextNode(str.substr(0, pos));
p.insertBefore(beforeText, text);
}
text.nodeValue = str.substr(end);
var span = document.createElement("span");
span.textContent = decodeURIComponent(uncensored[uncensoredPos]);
span.setAttribute("style", "background: black;");
p.insertBefore(span, text);
uncensoredPos++;
}
}
}
function checkPosts(ele) {
var censoredPosts = ele.querySelectorAll("a[href^='" + urlPrefix + "']");
for(var i=0;i<censoredPosts.length;i++) uncensorPost(censoredPosts[i]);
}
document.body.addEventListener('DOMNodeInserted', function(e) {
if(!e) e = event;
if(!e.target.classList) return;
checkElement(e.target);
checkPosts(e.target);
}, false);
checkPosts(document.body);
@quietlynn
Copy link
Author

使用方法:
安装后 G+ 发贴框右下角会增加 『██』按钮。
先选中你想要涂黑的文字,然后点击『██』按钮,即可将这些文字涂黑。
鼠标悬停可以确认原文,右键点击则可以还原。
涂黑文字后,点击发贴按钮并不会立即发贴,而是会添加一个链接。
这个链接中包含了被涂黑的内容,所以不建议去除该链接。除非你不希望别人查看原始内容。
如果觉得链接的图片和说明很烦,可以去除,但链接本身不能移除。
当链接添加完成后,再次点击发贴按钮即可发送。

@quietlynn
Copy link
Author

还原方法:
首先必须确认那个帖子包含一个到 SOPA Strike 的链接。
安装这个脚本后,选中被涂黑的文本,即可看到原来的文本。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment