Skip to content
This repository was archived by the owner on Mar 26, 2021. It is now read-only.

Commit 87cbba8

Browse files
author
Nicole Borrelli
committed
Improved blocking code
- Added ability to block for multiple reasons - Added ability to remove blocks (by selecting the command from the menu again) - Sub-menu is built dynamically. Yay! ...every time... boo.
1 parent f2cc06a commit 87cbba8

File tree

5 files changed

+202
-43
lines changed

5 files changed

+202
-43
lines changed

README.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ Safety Duck
22

33
Safety Duck is a Firefox extension that allows for the tagging of images that may cause various "triggers", and hides them when they are references on a web page.
44

5-
It actually allows tagging of images with the "personal" reason currently, but no way to untag, or to tag for any other reason.
5+
Supports a "dynamic" list of rules/channels/reasons for an image to be blocked. This is currently coded into the safetyduck object as an array, but is easily changed to read the data from elsewhere.
6+
When an image is blocked for a reason/channel, the name is checked in the popup menu.
7+
Images can be blocked for multiple reasons and will be displayed once all the reasons are removed.
68

79
TODO:
8-
Have the blocking be reversible.
9-
Have the sub-menu checkbox get checked for each reason the image is blocked.
10-
If an image is no longer blocked for any reason, show it again.
11-
12-
After this it gets tricky...
10+
Decide on terminology... >_> And then refactor some of the code to be consistent
11+
Build the preferences interface so that channels can be added there.
12+
Include a way to "watch" channels, so that images can be flagged but still visible.
1313
Build a way to have local + remote blacklists.
1414
Build a local whitelist(?) for images blocked remotely that the user wants to see.

chrome/content/ff-overlay.js

Lines changed: 153 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm");
55
safetyduck.addBlock = function(url, category) {
66
// Check to see if the url is in the list already
77
var entry = this.mHashMap[url];
8-
if (entry == null || !isArray(entry)) {
8+
if (entry == null || !Array.isArray(entry)) {
99
// If it's not an array, or doesn't exist at all, make sure it does
1010
entry = [];
1111
}
@@ -16,6 +16,30 @@ safetyduck.addBlock = function(url, category) {
1616
this.mHashMap[url] = entry;
1717
};
1818

19+
safetyduck.removeBlock = function(img, category) {
20+
// Get the url
21+
var url = img.getAttribute("safetyduck-original-src");
22+
23+
// Check to see if the url is in the list already
24+
var entry = this.mHashMap[url];
25+
if (entry == null || !Array.isArray(entry)) {
26+
// If it's not an array, or doesn't exist at all, make sure it does
27+
this.mHashMap[url] = [];
28+
29+
// If it's empty though, this can't be removed...
30+
return;
31+
}
32+
33+
// Find the index & remove it
34+
var catIndex = entry.indexOf(category);
35+
if (catIndex >= 0) {
36+
entry.splice(catIndex, 1);
37+
}
38+
39+
// And remove the attribute from the object itself
40+
img.setAttribute(safetyduck.channelNameToAttribute(category), "false");
41+
};
42+
1943
safetyduck.loadBlacklist = function(source) {
2044
// Save "this"
2145
var thisSafetyDuck = this;
@@ -76,14 +100,112 @@ safetyduck.onFirefoxUnload = function(event) {
76100
}
77101

78102
safetyduck.showFirefoxContextMenu = function(event) {
79-
// show or hide the menuitem based on what the context menu is on
80-
document.getElementById("safetyduck-menu").hidden = !gContextMenu.onImage;
103+
// helpful short name
104+
const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
105+
106+
// show or hide the menuitem based on what the context menu is on
107+
if (!gContextMenu.onImage) {
108+
// Not an image, hide and exit
109+
document.getElementById("safetyduck-menu").hidden = true;
110+
return;
111+
}
112+
113+
// On an image, show the item
114+
document.getElementById("safetyduck-menu").hidden = false;
115+
116+
// The image the context menu is for
117+
var contextImage = document.popupNode;
118+
119+
// Get the menu
120+
var subMenuRoot = document.getElementById("safetyduck-popup");
121+
122+
// Clear it
123+
while (subMenuRoot.hasChildNodes()) {
124+
subMenuRoot.removeChild(subMenuRoot.firstChild);
125+
}
126+
127+
// Build the menu
128+
var channels = safetyduck.channels();
129+
var channel = channels.next();
130+
while (channel != null) {
131+
// Build a child element and set attributes
132+
var child = document.createElementNS(XUL_NAMESPACE, "menuitem");
133+
child.setAttribute("type", "checkbox");
134+
135+
// Since text-transform is currently broken for XUL files (Bug 101800) do that transform here
136+
var channelLabel = channel.toLowerCase().replace(/^(.)|\s(.)/g, function($1) { return $1.toUpperCase(); });
137+
child.setAttribute("label", channelLabel);
138+
139+
// Is this image blocked for this reason?
140+
var attr = safetyduck.channelNameToAttribute(channel);
141+
var value = contextImage.getAttribute(attr);
142+
child.setAttribute("checked", (value == "true"));
143+
144+
// Attach the command
145+
child.addEventListener("command", function(cmd) { safetyduck.onMenuItemCommand(cmd.target.label.toLowerCase()); }, true);
146+
147+
// Add it to the list
148+
subMenuRoot.appendChild(child);
149+
150+
// Next
151+
channel = channels.next();
152+
}
81153
};
82154

155+
safetyduck.showImage = function(img) {
156+
// Is the image blocked?
157+
if (img.src != "chrome://safetyduck/content/images/blank.png") {
158+
// No?
159+
return;
160+
}
161+
162+
// Get the original image url
163+
var originalSrc = img.getAttribute("safetyduck-original-src");
164+
if (originalSrc == null || originalSrc.length == 0) {
165+
// ???
166+
return;
167+
}
168+
169+
// Are there additional reasons for this image to be blocked?
170+
if (safetyduck.isBlocked(originalSrc)) {
171+
// Yes, don't show it
172+
Log("Image '" + originalSrc + "' is still blocked for: '" + JSON.stringify(safetyduck.mHashMap[originalSrc]));
173+
return;
174+
}
175+
176+
// Save the height and width
177+
var height = img.height;
178+
var width = img.width;
179+
180+
// Replace the image and reset the height & width
181+
img.src = originalSrc;
182+
img.width = width;
183+
img.height = height;
184+
}
185+
83186
safetyduck.replaceImage = function(img) {
84-
// Fetch the original URL and save it in the object for later
85-
img.safetyduck = {};
86-
img.safetyduck.src = img.src;
187+
// Save meta data to the img object as attributes
188+
var originalSrc = img.getAttribute("safetyduck-original-src");
189+
if (originalSrc == null || originalSrc.length == 0) {
190+
// Save the original source only... not the src to the image used as filler
191+
img.setAttribute("safetyduck-original-src", img.src);
192+
193+
// Set the variable so it can be useful now
194+
originalSrc = img.src;
195+
}
196+
197+
// Get the reasons why the image is blocked
198+
var reasons = safetyduck.getBlocks(originalSrc);
199+
if (reasons.length == 0) {
200+
// Image isn't blocked?
201+
return;
202+
}
203+
204+
// Add block reasons
205+
for (var [key, value] in Iterator(reasons)) {
206+
img.setAttribute(safetyduck.channelNameToAttribute(value), "true");
207+
Log("Add block for: " + safetyduck.channelNameToAttribute(value))
208+
}
87209

88210
// Save the height and width
89211
var height = img.height;
@@ -107,17 +229,39 @@ safetyduck.onPageLoad = function(loadEvent) {
107229
var anImg = docImages[i];
108230

109231
// Blocked?
232+
Log("Check for block on: " + anImg.src);
110233
if (safetyduck.isBlocked(anImg.src)) {
111234
// Hide it
235+
Log("Image blocked: " + anImg.src);
112236
safetyduck.replaceImage(anImg);
113237
}
114238
}
115239
}
116240

117241
safetyduck.onMenuItemCommand = function(category) {
118-
// document.popupNode is the image element that was clicked
119-
this.addBlock(document.popupNode.src, category);
120-
this.replaceImage(document.popupNode);
242+
// The image
243+
var contextImage = document.popupNode;
244+
// And it's url
245+
var imageSrc = contextImage.src;
246+
247+
// Is it blocked already?
248+
if (contextImage.getAttribute("safetyduck-original-src") != null) {
249+
// Yes. So, don't use this url, use the original source
250+
imageSrc = contextImage.getAttribute("safetyduck-original-src");
251+
}
252+
253+
Log("Command on '" + imageSrc + "' => :" + category + ":");
254+
255+
// Is the item being blocked or unblocked?
256+
if (safetyduck.isBlockedFor(imageSrc, category)) {
257+
// Unblock the image (for this reason)
258+
this.removeBlock(contextImage, category);
259+
this.showImage(contextImage);
260+
} else {
261+
// Block the image
262+
this.addBlock(imageSrc, category);
263+
this.replaceImage(contextImage);
264+
}
121265
}
122266

123267

chrome/content/ff-overlay.xul

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<?xml-stylesheet href="chrome://safetyduck/skin/overlay.css" type="text/css"?>
3+
34
<!DOCTYPE overlay SYSTEM "chrome://safetyduck/locale/overlay.dtd">
45
<overlay id="safetyduck-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
5-
<script src="overlay.js"/>
6-
<script src="ff-overlay.js"/>
7-
6+
<script src="overlay.js" type="application/javascript;version=1.8" />
7+
<script src="ff-overlay.js" type="application/javascript;version=1.8" />
8+
89
<stringbundleset id="stringbundleset">
910
<stringbundle id="safetyduck-strings" src="chrome://safetyduck/locale/overlay.properties"/>
1011
</stringbundleset>
1112

1213
<popup id="contentAreaContextMenu">
1314
<menu id="safetyduck-menu"
14-
insertafter="context-stop"
15+
insertafter="context-viewimageinfo"
1516
label="&safetyduckContext.label;"
1617
accesskey="&safetyduckContext.accesskey;">
1718
<menupopup id="safetyduck-popup">
18-
<menuitem label="&safetyduckContext.label.personal;" type="checkbox" oncommand="safetyduck.onMenuItemCommand('personal')"/>
1919
</menupopup>
2020
</menu>
2121
</popup>

chrome/content/overlay.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1+
function Log(msg) {
2+
var aConsoleService = Components.classes["@mozilla.org/consoleservice;1"].
3+
getService(Components.interfaces.nsIConsoleService);
4+
aConsoleService.logStringMessage(msg);
5+
}
6+
17
var safetyduck = {
28
// Object to be used for tracking images to replace in the DOM
39
mHashMap : {},
410

11+
// List of "channels" - should be built from preferences
12+
mChannels : [ "death", "personal" ],
13+
14+
channels : function() {
15+
for (var [key, value] in Iterator(safetyduck.mChannels)) {
16+
yield value;
17+
}
18+
yield null;
19+
},
20+
521
onLoad: function() {
622
// initialization code
723
this.initialized = true;
@@ -16,7 +32,24 @@ var safetyduck = {
1632

1733
isBlocked: function(url) {
1834
// Simple check to see if the url is in the list of blocked items
19-
return (url in this.mHashMap);
35+
return (url in this.mHashMap && this.mHashMap[url].length > 0);
36+
},
37+
38+
isBlockedFor: function(url, category) {
39+
return (this.isBlocked(url) ? this.mHashMap[url].indexOf(category) >= 0 : false);
40+
},
41+
42+
getBlocks: function(url) {
43+
return (this.isBlocked(url)) ? this.mHashMap[url] : [];
44+
},
45+
46+
/**
47+
* Converts a blocked channel name to a attribute name
48+
* @param name The name of the channel (ex: "injured wings")
49+
* @return The attribute name (ex: safetyduck-block-injured-wings)
50+
*/
51+
channelNameToAttribute : function(name) {
52+
return "safetyduck-block-" + name.toLowerCase().replace(/ /g,'-');
2053
}
2154
};
2255

chrome/skin/overlay.css

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,4 @@
1-
/* This is just an example. You shouldn't do this. */
2-
#safetyduck-hello
3-
{
4-
color: red ! important;
5-
}
6-
#safetyduck-toolbar-button
7-
{
8-
list-style-image: url("chrome://safetyduck/skin/toolbar-button.png");
9-
-moz-image-region: rect(0px 24px 24px 0px);
10-
}
11-
#safetyduck-toolbar-button:hover
12-
{
13-
-moz-image-region: rect(24px 24px 48px 0px);
14-
}
15-
[iconsize="small"] #safetyduck-toolbar-button
16-
{
17-
-moz-image-region: rect( 0px 40px 16px 24px);
18-
}
19-
[iconsize="small"] #safetyduck-toolbar-button:hover
20-
{
21-
-moz-image-region: rect(24px 40px 40px 24px);
22-
}
1+
#safetyduck-popup menuitem {
2+
-moz-appearance: none;
3+
text-transform: capitalize;
4+
}

0 commit comments

Comments
 (0)