├── images ├── icon.png ├── icon16.png ├── icon19.png └── icon38.png ├── contentScripts ├── systemMessagesContent.js ├── overCapacityContent.js ├── frontPageContent.js ├── snakeContent.js ├── favoritesContent.js ├── notificationsContent.js └── imgurContent.js ├── .gitattributes ├── pages ├── favoriteComments.html ├── popup.html ├── blockedKeywords.html ├── bookmarkedPosts.html ├── favoriteComments.js ├── popup.js ├── options.html ├── postPreview.js ├── blockedKeywords.js ├── options.js └── bookmarkedPosts.js ├── .gitignore ├── README.md ├── manifest.json ├── background.js └── LICENSE.txt /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AaronV-T/imgur-Browsing-Aid/HEAD/images/icon.png -------------------------------------------------------------------------------- /images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AaronV-T/imgur-Browsing-Aid/HEAD/images/icon16.png -------------------------------------------------------------------------------- /images/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AaronV-T/imgur-Browsing-Aid/HEAD/images/icon19.png -------------------------------------------------------------------------------- /images/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AaronV-T/imgur-Browsing-Aid/HEAD/images/icon38.png -------------------------------------------------------------------------------- /contentScripts/systemMessagesContent.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.sendMessage( { messageType: "checkForMessage" } ); //Send message to background script to check for messages. 2 | 3 | chrome.storage.sync.get({ 4 | lastMessage: "", 5 | lastMessageRead: true 6 | }, function(items) { 7 | if (!items.lastMessageRead) { 8 | addSystemNotification(items.lastMessage); 9 | console.log("displaying system message"); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /pages/favoriteComments.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Favorite Comments | imgur Browsing Aid 6 | 10 | 11 | 12 | 13 | 14 |
Loading options, please wait.
15 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | background.js 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imgur-Browsing-Aid 2 | Chrome extension to add much desired functionality to imgur. 3 | 4 | Feature List: 5 | * Bookmark posts locally for private favorites. 6 | * Organize bookmarks and favorites into folders. 7 | * Follow users you like. 8 | * Favorite comments you want to save for later. 9 | * Block users to auto-skip their posts in the gallery. 10 | * Slideshow mode. 11 | * Auto-skip posts you've already viewed. 12 | * Auto-skip posts containing user-defined keywords and subreddits. 13 | * Remove the "via Android" and "via iPhone" links in comments. 14 | * Auto-close the top notification bar. 15 | * Receive notifications on special users' posts. 16 | 17 | 18 | Known issues: 19 | * Additional options not added to post options sometimes. 20 | * Failure to mark posts as viewed sometimes. 21 | * Failure to sync favorites to bookmarks has been reported. 22 | 23 | To-Do List: 24 | * Enable WASD snake game control for tenkeyless / compact keyboards. 25 | * When slideshow mode is active, disable slideshow controls if the user is typing a comment. 26 | * Improve styles of bookmarked posts page. 27 | * Overhaul styles to match imgur's look and feel. 28 | * Improve the options page. 29 | * Break out special-users option into individual users (with ability to add custom). 30 | -------------------------------------------------------------------------------- /pages/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 |
13 |

You can edit settings, unblock, and unfollow users on the options page.

14 |
15 |
View your bookmarked posts.
16 |
View your favorite comments.
17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |

Edit blocked Keywords and Subreddits.

25 |

You can submit feedback, suggestions, and bug reports by clicking here.

26 |

imgur Browsing Aid - Donate - Show Snake Game - Random

27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pages/blockedKeywords.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Blocked Keywords and Subreddits | imgur Browsing Aid 4 | 5 |

imgur Browsing Aid

6 |
Loading, please wait.
7 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | 4 | "name": "imgur Browsing Aid", 5 | "description": "Provides additional features to improve the imgur browsing experience.", 6 | "version": "0.8.1", 7 | 8 | "background": { 9 | "scripts": ["jquery-2.1.4.min.js", "background.js"], 10 | "persistent": false 11 | }, 12 | "browser_action": { 13 | "default_icon": { 14 | "19": "images/icon19.png", 15 | "38": "images/icon38.png" 16 | }, 17 | "default_title": "imgur Browsing Aid", 18 | "default_popup": "pages/popup.html" 19 | }, 20 | "content_scripts": [ 21 | { 22 | "matches": ["*://imgur.com/*"], 23 | "js": ["jquery-2.1.4.min.js", "contentScripts/systemMessagesContent.js", "contentScripts/notificationsContent.js", "contentScripts/overCapacityContent.js", "contentScripts/snakeContent.js"] 24 | }, 25 | { 26 | "matches": ["*://imgur.com/", "*://*.imgur.com/r/*", "*://imgur.com/hot/*", "*://imgur.com/new/*", "*://imgur.com/topic/*"], 27 | "js": ["contentScripts/frontPageContent.js"] 28 | }, 29 | { 30 | "matches": ["*://*.imgur.com/gallery/*", "*://*.imgur.com/*/favorites/*", "*://*.imgur.com/a/*", "*://*.imgur.com/r/*/*", "*://imgur.com/topic/*/*"], 31 | "js": ["contentScripts/imgurContent.js"] 32 | }, 33 | 34 | { 35 | "matches": ["*://*.imgur.com/account/favorites", "*://*.imgur.com/account/favorites/oldest", "*://*.imgur.com/account/favorites/newest"], 36 | "js": ["contentScripts/favoritesContent.js"] 37 | } 38 | ], 39 | "icons": { 40 | "16": "images/icon16.png", 41 | "48": "images/icon.png" 42 | }, 43 | "options_page": "pages/options.html", 44 | "permissions": [ 45 | "activeTab", 46 | "storage", 47 | "tabs" 48 | ] 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /contentScripts/overCapacityContent.js: -------------------------------------------------------------------------------- 1 | $('body').ready(function() { 2 | var h1Elements = document.getElementsByTagName("h1"); 3 | 4 | for (i = 0; i < h1Elements.length; i++) { 5 | if (h1Elements[i].innerHTML == "Imgur is over capacity!") { 6 | loadOverCapacityContent(); //Call function in overCapacityContent.js 7 | return; 8 | } 9 | } 10 | }); 11 | 12 | var overCapacityViews, overCapacityDate; 13 | 14 | //main: Called when an over capacity page is loaded. 15 | function loadOverCapacityContent() { 16 | chrome.storage.sync.get({ 17 | overCapacityPageViews: 0, 18 | overCapacityCountDate: "neverSet", 19 | snakeGameEnabled: true 20 | }, function (items) { 21 | overCapacityViews = items.overCapacityPageViews; 22 | overCapacityDate = items.overCapacityCountDate; 23 | overCapacityViews++; 24 | 25 | if (overCapacityDate == "neverSet") { 26 | var d = new Date(); 27 | 28 | var theMonth = d.getMonth(); 29 | if (theMonth == 0) theMonth = "January"; 30 | else if (theMonth == 1) theMonth = "February"; 31 | else if (theMonth == 2) theMonth = "March"; 32 | else if (theMonth == 3) theMonth = "April"; 33 | else if (theMonth == 4) theMonth = "May"; 34 | else if (theMonth == 5) theMonth = "June"; 35 | else if (theMonth == 6) theMonth = "July"; 36 | else if (theMonth == 7) theMonth = "August"; 37 | else if (theMonth == 8) theMonth = "September"; 38 | else if (theMonth == 9) theMonth = "October"; 39 | else if (theMonth == 10) theMonth = "November"; 40 | else if (theMonth == 11) theMonth = "December"; 41 | 42 | overCapacityDate = d.getDate() + " " + theMonth + " " + d.getFullYear(); 43 | } 44 | console.log("overCapacityDate: " + overCapacityDate); 45 | chrome.storage.sync.set({ 46 | overCapacityPageViews: overCapacityViews, 47 | overCapacityCountDate: overCapacityDate 48 | }, function () { 49 | addNotification("FYI:", "You have seen the over capacity page " + overCapacityViews + " times since " + overCapacityDate + "."); //Call function in notificationsContent.js 50 | }); 51 | 52 | if (snakeGameEnabled && !document.getElementById("snakeGameDiv")) 53 | initializeSnakeGame(); //Call function in snakeContent.js 54 | }); 55 | } -------------------------------------------------------------------------------- /contentScripts/frontPageContent.js: -------------------------------------------------------------------------------- 1 | var markIconsViewed, viewedPosts; 2 | var notPostPage; 3 | 4 | $('body').ready(function() { 5 | if (document.getElementsByClassName("post-container").length == 0) { 6 | notPostPage = true; 7 | frontPageMain(); 8 | } 9 | else 10 | notPostPage = false; 11 | }); 12 | 13 | //Create a MutationObserver to check for changes on the page. 14 | var mutationObserver = new MutationObserver( function(mutations) { 15 | if (!notPostPage) 16 | return; 17 | 18 | for(var i = 0; i < mutations.length; i++){ 19 | var mut = mutations[i]; 20 | for(var j=0; j < mut.addedNodes.length; ++j){ 21 | //console.log(mut.addedNodes[j].className + " ::: " + mut.addedNodes[j].nodeName); 22 | if(mut.addedNodes[j].className === undefined) continue; 23 | else if(mut.addedNodes[j].className === "posts br5" || mut.addedNodes[j].className === "outside-loader") { 24 | addViewedTexts(); 25 | } 26 | } 27 | } 28 | } ); 29 | mutationObserver.observe(document, { subtree: true, childList: true }); 30 | 31 | function frontPageMain() { 32 | console.log("frontPageContent.js"); 33 | chrome.storage.sync.get({ 34 | //Set defaults. 35 | viewedIconsEnabled: true 36 | }, function(items) { 37 | markIconsViewed = items.viewedIconsEnabled; 38 | 39 | if (markIconsViewed) { 40 | chrome.storage.local.get({ 41 | viewedPosts: new Array() 42 | }, function(items2) { 43 | viewedPostsArray = items2.viewedPosts; 44 | 45 | //Give style to our added elements. 46 | var css = ".alreadyViewedIdentifier { position:absolute;z-index:1;top:1px;right:1px;background-color:rgba(0,0,0,0.5);color:white;font-weight:bold;line-height:20px; }"; 47 | var style = document.createElement("style"); 48 | style.appendChild(document.createTextNode(css)); 49 | document.getElementsByTagName('head')[0].appendChild(style); 50 | 51 | addViewedTexts(); 52 | 53 | }); 54 | } 55 | }); 56 | } 57 | 58 | function addViewedTexts() { 59 | var postIcons = document.getElementsByClassName("post"); 60 | for (i = 0; i < postIcons.length; i++) { 61 | if (postIcons[i].getElementsByClassName("alreadyViewedIdentifier").length == 0) { 62 | var postIconID = postIcons[i].getAttribute("id"); 63 | var startIndex = 0; 64 | if (postIconID.indexOf("/gallery/") == 0) 65 | startIndex = 9; 66 | 67 | if (viewedPostsArray.indexOf(postIconID.substring(startIndex, postIconID.length)) > -1) { 68 | var viewedSpan = document.createElement("span"); 69 | viewedSpan.setAttribute("class", "alreadyViewedIdentifier"); 70 | viewedSpan.innerHTML = "Viewed"; 71 | 72 | postIcons[i].appendChild(viewedSpan); 73 | } 74 | } 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /pages/bookmarkedPosts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bookmarked Images | imgur Browsing Aid 6 | 22 | 23 | 24 | 25 | 26 |
Loading bookmarked images, please wait.
27 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /pages/favoriteComments.js: -------------------------------------------------------------------------------- 1 | var favoriteCommentList = new Array(); 2 | 3 | document.addEventListener('DOMContentLoaded', restore_options); 4 | 5 | // Loads options from chrome.storage 6 | function restore_options() { 7 | chrome.storage.sync.get({ 8 | useSynchronizedStorage: false 9 | }, function(items) { 10 | if (items.useSynchronizedStorage) { 11 | chrome.storage.sync.get({ 12 | // Set defaults. 13 | favoriteComments: new Array(), 14 | }, function(items) { 15 | favoriteCommentList = items.favoriteComments; 16 | populateFavoriteCommentList(); 17 | }); 18 | } 19 | else { 20 | chrome.storage.local.get({ 21 | // Set defaults. 22 | favoriteComments: new Array(), 23 | }, function(items) { 24 | favoriteCommentList = items.favoriteComments; 25 | populateFavoriteCommentList(); 26 | }); 27 | } 28 | }); 29 | } 30 | 31 | function populateFavoriteCommentList() { 32 | var listHTML = ""; 33 | 34 | for (i = 0; i < favoriteCommentList.length; i++) 35 | listHTML += 'View Comment' + favoriteCommentList[i].userName + '' + favoriteCommentList[i].text + ''; 36 | 37 | document.getElementById("favoriteCommentTable").innerHTML = listHTML; 38 | 39 | for (i = 0; i < favoriteCommentList.length; i++) { 40 | document.getElementById("remove" + i).addEventListener("click", unfavoriteComment); 41 | } 42 | 43 | document.getElementById('mainDiv').style.display = "inline"; 44 | document.getElementById('loadingDiv').style.display = "none"; 45 | } 46 | 47 | 48 | function unfavoriteComment() { 49 | var url = this.getAttribute("url"); 50 | 51 | chrome.storage.sync.get({ 52 | useSynchronizedStorage: false 53 | }, function(items) { 54 | if (items.useSynchronizedStorage) { 55 | chrome.storage.sync.get({ 56 | //Set defaults. 57 | favoriteComments: new Array() 58 | }, function(items) { 59 | favoriteCommentList = items.favoriteComments; 60 | 61 | var index = -1; 62 | searchLoop: 63 | for (i = 0; i < favoriteCommentList.length; i++) { 64 | if (url === favoriteCommentList[i].url) { 65 | index = i; 66 | break searchLoop; 67 | } 68 | } 69 | if (index > -1) 70 | favoriteCommentList.splice(index, 1); 71 | 72 | chrome.storage.sync.set({ 73 | favoriteComments: favoriteCommentList 74 | }, function() { 75 | //window.location.reload(); 76 | populateFavoriteCommentList(); 77 | }); 78 | }); 79 | } 80 | else { 81 | chrome.storage.local.get({ 82 | //Set defaults. 83 | favoriteComments: new Array() 84 | }, function(items) { 85 | favoriteCommentList = items.favoriteComments; 86 | 87 | var index = -1; 88 | searchLoop: 89 | for (i = 0; i < favoriteCommentList.length; i++) { 90 | if (url === favoriteCommentList[i].url) { 91 | index = i; 92 | break searchLoop; 93 | } 94 | } 95 | if (index > -1) 96 | favoriteCommentList.splice(index, 1); 97 | 98 | chrome.storage.local.set({ 99 | favoriteComments: favoriteCommentList 100 | }, function() { 101 | //window.location.reload(); 102 | populateFavoriteCommentList(); 103 | }); 104 | }); 105 | } 106 | }); 107 | } -------------------------------------------------------------------------------- /pages/popup.js: -------------------------------------------------------------------------------- 1 | //Script injected into popup window. 2 | document.getElementById('donateSpan').addEventListener('click', openDonationPage); 3 | document.getElementById('snakeSpan').addEventListener('click', showSnakeGame); 4 | document.getElementById('openOptions').addEventListener('click', openOptions); 5 | document.getElementById('openBlockedKeywords').addEventListener('click', openBlockedKeywords); 6 | document.getElementById('openFavoriteComments').addEventListener('click', openFavoriteComments); 7 | document.getElementById('openBookmarkedPosts').addEventListener('click', openBookmarkedPosts); 8 | document.getElementById('openFeedback').addEventListener('click', openFeedback); 9 | document.getElementById('randomSpan').addEventListener('click', openRandom); 10 | 11 | var followedUserList = new Array(); 12 | 13 | window.onload = getFollowedUserListAndPopulate(); 14 | 15 | document.getElementById("versionSpan").innerHTML = "(Version: " + chrome.runtime.getManifest().version + ")"; 16 | 17 | function getFollowedUserListAndPopulate() { 18 | 19 | chrome.storage.sync.get({ 20 | useSynchronizedStorage: false 21 | }, function(items) { 22 | if (items.useSynchronizedStorage) { 23 | chrome.storage.sync.get({ 24 | //Set defaults. 25 | followedUsers: new Array() 26 | }, function(items) { 27 | followedUserList = items.followedUsers; 28 | getFollowedUserListAndPopulateHelper(); 29 | }); 30 | } 31 | else { 32 | chrome.storage.local.get({ 33 | //Set defaults. 34 | followedUsers: new Array() 35 | }, function(items) { 36 | followedUserList = items.followedUsers; 37 | getFollowedUserListAndPopulateHelper(); 38 | }); 39 | } 40 | }); 41 | } 42 | 43 | function getFollowedUserListAndPopulateHelper() { 44 | var listHTML; 45 | if (followedUserList.length > 0) { 46 | listHTML = 'Users You Follow:'; 47 | 48 | for (i = 0; i < followedUserList.length; i++) 49 | listHTML += '' + followedUserList[i] + 'Visit Page'; 50 | } 51 | else 52 | listHTML = ""; 53 | 54 | document.getElementById("followedUserTable").innerHTML = listHTML; 55 | 56 | var visitUserLinks = document.getElementsByClassName("visitUserPage"); 57 | for (i = 0; i < visitUserLinks.length; i++) 58 | visitUserLinks[i].addEventListener("click", visitUserPage); 59 | } 60 | 61 | function openBlockedKeywords() { 62 | chrome.tabs.create({ 'url': "chrome-extension://" + chrome.runtime.id + "/pages/blockedKeywords.html" }); 63 | } 64 | 65 | function openDonationPage() { 66 | chrome.tabs.create({ 'url': "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FLE9GSV5HK9WU" }); 67 | } 68 | 69 | function openFavoriteComments() { 70 | chrome.tabs.create({ 'url': "chrome-extension://" + chrome.runtime.id + "/pages/favoriteComments.html" }); 71 | } 72 | 73 | function openBookmarkedPosts() { 74 | chrome.tabs.create({ 'url': "chrome-extension://" + chrome.runtime.id + "/pages/bookmarkedPosts.html" }); 75 | } 76 | 77 | function openFeedback() { 78 | chrome.tabs.create({ 'url': "https://docs.google.com/forms/d/1m9giW20aIkCb1tsWeED4w0v0pec3A1WfrDBzCScxxZA/viewform?usp=send_form" }); 79 | } 80 | 81 | function openOptions() { 82 | chrome.runtime.openOptionsPage(); 83 | } 84 | 85 | function openRandom() { 86 | chrome.tabs.create({ 'url': "http://imgur.com/gallery/random" }); 87 | } 88 | 89 | function showSnakeGame() { 90 | //Send message to selected tab to initializeSnakeGame. 91 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 92 | chrome.tabs.sendMessage(tabs[0].id, {messageType: "initializeSnakeGame"}); 93 | }); 94 | } 95 | 96 | function visitUserPage() { 97 | var userName = this.getAttribute("userName"); 98 | chrome.tabs.create({ url: "http://imgur.com/user/" + userName + "/submitted" }); 99 | } -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { 2 | if (msg.messageType && msg.messageType == "checkForMessage") { 3 | checkForMessage(); 4 | } 5 | }); 6 | 7 | chrome.runtime.onInstalled.addListener(function (details) { 8 | var extensionID = chrome.runtime.id; 9 | 10 | if (extensionID == "bmkkppdpbgfhfcppblpmbbiibeoeledm") { 11 | chrome.storage.sync.get({ 12 | uniqueID: "neverSet" 13 | }, function(items) { 14 | if (items.uniqueID == "neverSet" || items.uniqueID == "developement") { 15 | requestNewUniqueID(); 16 | } 17 | }); 18 | } 19 | else { 20 | chrome.storage.sync.set({ 21 | uniqueID: "developer" 22 | }, function() {}); 23 | } 24 | 25 | if (details.reason == "install") { 26 | chrome.runtime.openOptionsPage(); 27 | 28 | if (extensionID == "bmkkppdpbgfhfcppblpmbbiibeoeledm") { 29 | $.ajax({ 30 | url: 'http://tollski.com/imgur_browsing_aid/index.php', 31 | type: 'post', 32 | data: { 33 | type: "install" 34 | }, 35 | headers: { 36 | 37 | } 38 | }, function() {}); 39 | } 40 | else 41 | console.log(extensionID); 42 | } 43 | else { 44 | console.log(details.reason); 45 | chrome.storage.sync.get({ 46 | useSynchronizedStorage: "neverSet" 47 | }, function(items) { 48 | if (items.useSynchronizedStorage == "neverSet") { 49 | chrome.runtime.openOptionsPage(); 50 | } 51 | }); 52 | } 53 | }); 54 | 55 | function checkForMessage() { 56 | chrome.storage.sync.get({ 57 | lastMessageCheck: 0, 58 | lastMessageID: 0 59 | }, function(items) { 60 | var lastCheck = items.lastMessageCheck; 61 | 62 | var d = new Date(); 63 | var t = d.getTime(); 64 | 65 | if (t - lastCheck > 5400000) { //If time since last message check is greater than 1.5 hours: get message from the site. 66 | chrome.storage.sync.get({ 67 | uniqueID: "neverSet" 68 | }, function(items2) { 69 | if (items2.uniqueID != "neverSet" && items2.uniqueID != "developement") { 70 | $.get("http://tollski.com/imgur_browsing_aid/latestMessage.php", { id: items2.uniqueID }, function(data, status){ 71 | if (status === "success" && data.indexOf(" ") > -1) { 72 | var receivedMessageID = parseInt(data.substring(0, data.indexOf(" "))); 73 | var receivedMessageText = data.substring(data.indexOf(" ") + 1, data.length); 74 | 75 | //alert("data: " + data +". status: " + status + ". receivedMessageID: " + receivedMessageID + ". items.lastMessageID: " + items.lastMessageID); 76 | console.log("receivedMessageID:" + receivedMessageID + ". items.lastMessageID:" + items.lastMessageID + "."); 77 | 78 | if (receivedMessageID > items.lastMessageID) { 79 | console.log("message is new"); 80 | chrome.storage.sync.set({ 81 | lastMessageCheck: t, 82 | lastMessageID: receivedMessageID, 83 | lastMessage: receivedMessageText, 84 | lastMessageRead: false 85 | }, function() {}); 86 | } 87 | else { 88 | console.log("message is old"); 89 | chrome.storage.sync.set({ 90 | lastMessageCheck: t 91 | }, function() {}); 92 | } 93 | } 94 | else 95 | console.log("data: '" + data +"'. status: " + status); 96 | }); 97 | } 98 | else 99 | requestNewUniqueID(); 100 | }); 101 | } 102 | else 103 | console.log("last message check: " + ((t - lastCheck) / 1000 / 60 / 60)); 104 | }); 105 | } 106 | 107 | function requestNewUniqueID() { 108 | $.get("http://tollski.com/imgur_browsing_aid/requestID.php", { type: "newID" }, function(data, status) { 109 | if (status == "success" && data.indexOf("failed") == -1) { 110 | chrome.storage.sync.set({ 111 | uniqueID: data 112 | }, function() { 113 | console.log("uniqueID: " + data); 114 | }); 115 | } 116 | else 117 | console.log("data: '" + data +"'. status: " + status); 118 | 119 | }); 120 | } -------------------------------------------------------------------------------- /pages/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options | imgur Browsing Aid 4 | 5 |

imgur Browsing Aid

6 |
Loading options, please wait.
7 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /pages/postPreview.js: -------------------------------------------------------------------------------- 1 | function initializePostPreview () { 2 | console.log("postpreview"); 3 | var pressedTimes = 0; 4 | var settingsViewAction = 0; 5 | var maxWidth = 35; 6 | var maxHeight = 23; 7 | var percentageSensX = 70; 8 | var percentageSensY = 90; 9 | var heightPercentage = $(window).height() / 100; 10 | var widthPercentage = $(window).width() / 100; 11 | var Ls = $("img"); 12 | var Ll = Ls.length; 13 | var styles = ""; 14 | 15 | console.log("Images grabbed = " + Ll); 16 | //Appends styles 17 | $("head").append(styles); 18 | 19 | //Calculates where imView shuld be placed. "X" 20 | function getMouseX(mouseX) { 21 | console.log(mouseX, $(window).width()); 22 | if (mouseX > widthPercentage * percentageSensX) { 23 | return (mouseX - widthPercentage * 40); 24 | console.log(mouseX - widthPercentage * 40); 25 | } else { 26 | return (mouseX + 10); 27 | } 28 | } 29 | 30 | //Calculates where imView shuld be placed. "Y" 31 | function getMouseY(mouseY) { 32 | console.log(mouseY, $(window).height()); 33 | if (mouseY > heightPercentage * percentageSensY) { 34 | return (mouseY - heightPercentage * 40); 35 | console.log(mouseY - heightPercentage * 40); 36 | } else { 37 | return (mouseY + 10); 38 | } 39 | } 40 | 41 | function appendImgView(mouseY, mouseX, url) { 42 | var imgurStyles = ""; 43 | var ImgView = "
" + imgurStyles + "Could not show current file
"; 44 | $("body").append(ImgView); 45 | }; 46 | 47 | //Appends SettingsView on function call 48 | function appendSettingsView() { 49 | var settingsView = "
Settings
View size
Width:Height:
Edge sensitivity
Width:Height:
"; 50 | $("body").append(settingsView); 51 | $("#settingsView").draggable(); 52 | } 53 | 54 | //detect if "key" is pressed twice 55 | $(document).keydown(function(e) { 56 | if (e.keyCode == 18 && pressedTimes == 1 && settingsViewAction == 0) { 57 | appendSettingsView(); 58 | pressedTimes = 0; 59 | settingsViewAction = 1; 60 | } else if (e.keyCode !== 18) { 61 | pressedTimes = 0; 62 | } else if (settingsViewAction == 1) { 63 | pressedTimes = 0; 64 | } else { 65 | pressedTimes++; 66 | } 67 | }); 68 | 69 | //Saves changed settings 70 | $(document).on("click", "#saveSettings", function() { 71 | var inputMaxWidth = $("#imgViewWidth").val(); 72 | var inputMaxHeight = $("#imgViewHeight").val(); 73 | var inputSneseX = $("#widthPercentage").val(); 74 | var inputSenseY = $("#heightPercentage").val(); 75 | 76 | maxWidth = inputMaxWidth; 77 | maxHeight = inputMaxHeight; 78 | percentageSensX = inputSneseX; 79 | percentageSensY = inputSenseY; 80 | $("#settingsView").remove(); 81 | settingsViewAction = 0; 82 | }); 83 | 84 | //Resets changed settings 85 | $(document).on("click", "#defaultSettings", function() { 86 | maxWidth = 35; 87 | maxHeight = 23; 88 | percentageSensX = 70; 89 | percentageSensY = 90; 90 | $("#settingsView").remove(); 91 | settingsViewAction = 0; 92 | }); 93 | 94 | //Small img to big img filter 95 | $(Ls).mouseover(function(e) { 96 | var url = $(this).attr("src"); 97 | var Array = url.split("."); 98 | var Last = Array.length - 1; 99 | var mouseX = e.pageX; 100 | var mouseY = e.pageY; 101 | console.log("Array = " + url); 102 | var Array = url.split("."); 103 | console.log(url + " | " + Array); 104 | var Meat = Array[2].split(""); 105 | console.log("Original URL: " + url); 106 | console.log("Meat before: " + Meat); 107 | Meat.pop(); 108 | Meat = Meat.join(""); 109 | console.log("Meat after: " + Meat); 110 | Array.splice(2, 1, Meat); 111 | url = Array.join("."); 112 | console.log("New URL: " + url); 113 | 114 | appendImgView(mouseY, mouseX, url); 115 | if (Array[Last] !== "gif") { 116 | console.log("Link is not a image/gif file"); 117 | 118 | console.log("None gif file detected"); 119 | console.log("Original URL: " + url); 120 | 121 | Array.pop(); 122 | Array.push("gif"); 123 | 124 | url = Array.join("."); 125 | console.log("New URL: " + url); 126 | } 127 | }); 128 | 129 | //Removes view on mouseout 130 | $(Ls).mouseout(function() { 131 | $("#imageView_container").remove(); 132 | console.clear(); 133 | }); 134 | } -------------------------------------------------------------------------------- /contentScripts/snakeContent.js: -------------------------------------------------------------------------------- 1 | // The original code for this game was made by following a great tutorial at http://thecodeplayer.com/walkthrough/html5-game-tutorial-make-a-snake-game-using-html5-canvas-jquery 2 | 3 | /*$(document).keydown(function(e){ 4 | if(e.which == "145") { 5 | if (!document.getElementById("snakeGameDiv")) 6 | initializeSnakeGame(); 7 | } 8 | });*/ 9 | 10 | chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { 11 | if (msg.messageType && msg.messageType == "initializeSnakeGame") { 12 | if (!document.getElementById("snakeGameDiv")) 13 | initializeSnakeGame(); 14 | } 15 | }); 16 | 17 | 18 | function initializeSnakeGame() { 19 | console.log("initializing snake game"); 20 | //Create canvas elements. 21 | var canvasDiv = document.createElement("div"); 22 | canvasDiv.setAttribute("id", "snakeGameDiv"); 23 | canvasDiv.setAttribute("style", "z-index:99; position:fixed; bottom:25px; left:50%; margin-left:-225px;"); 24 | 25 | var canvasElement = document.createElement("canvas"); 26 | canvasElement.setAttribute("id", "snakeGameCanvas"); 27 | canvasElement.setAttribute("width", "450"); 28 | canvasElement.setAttribute("height", "450"); 29 | canvasDiv.appendChild(canvasElement); 30 | 31 | var closeCanvasDivButton = document.createElement("span"); 32 | closeCanvasDivButton.innerHTML = "Close"; 33 | closeCanvasDivButton.setAttribute("style", "cursor:pointer; position:absolute; top:1px; right:1px; color:#4E76C9;"); 34 | closeCanvasDivButton.addEventListener("click", closeCanvasDiv); 35 | canvasDiv.appendChild(closeCanvasDivButton); 36 | 37 | var scoresDiv = document.createElement("div"); 38 | scoresDiv.setAttribute("width", "100%"); 39 | scoresDiv.setAttribute("style", "position:absolute; background-color:black; color:white; top:450px; left:0px; width:100%; height:15px;"); 40 | 41 | var playerHighScoreSpan = document.createElement("span"); 42 | playerHighScoreSpan.setAttribute("id", "playerHighScoreSpan"); 43 | playerHighScoreSpan.setAttribute("style", "z-index:100; position:absolute; bottom:0px; left:1px;"); 44 | scoresDiv.appendChild(playerHighScoreSpan); 45 | 46 | var recordHighScoreSpan = document.createElement("span"); 47 | recordHighScoreSpan.setAttribute("id", "recordHighScoreSpan"); 48 | recordHighScoreSpan.setAttribute("style", "z-index:100; position:absolute; bottom:0px; right:1px;"); 49 | recordHighScoreSpan.innerHTML = "All-Time High Score: ????"; 50 | scoresDiv.appendChild(recordHighScoreSpan); 51 | 52 | canvasDiv.appendChild(scoresDiv); 53 | 54 | document.getElementsByTagName("body")[0].appendChild(canvasDiv); 55 | 56 | //Set up local variables. 57 | var canvas = $("#snakeGameCanvas")[0]; 58 | var canvasContext = canvas.getContext("2d"); 59 | var canvasWidth = $("#snakeGameCanvas").width(); 60 | var canvasHeight = $("#snakeGameCanvas").height(); 61 | var cellWidth = 10; 62 | var moveDirection, selectedDirection; 63 | var food; 64 | var score, highScore; 65 | var paused; 66 | var snakeArray; //Array of cells to make up the snake 67 | var updateScreenInterval; 68 | 69 | //Keydown listener for controls. 70 | $(document).keydown(function(e){ 71 | var key = e.which; 72 | 73 | if((key == "37" || key == "100") && moveDirection != "right") //Left arrow or numpad 4. 74 | selectedDirection = "left"; 75 | else if((key == "38" || key == "104") && moveDirection != "down") //Up arrow or numpad 8. 76 | selectedDirection = "up"; 77 | else if((key == "39" || key == "102") && moveDirection != "left") //Right arrow or numpad 6. 78 | selectedDirection = "right"; 79 | else if((key == "40" || key == "101") && moveDirection != "up") //Down arrow or numpad 5. 80 | selectedDirection = "down"; 81 | 82 | if (paused) { // If the game hasn't yet started: ... 83 | if (key == "37" || key == "38" || key == "39" || key == "40" || key == "100" || key == "101" || key == "102" || key == "104") { 84 | $("#snakeInstructionsDiv").remove(); 85 | paused = false; 86 | startGame(); 87 | } 88 | } 89 | }); 90 | 91 | //Get the player's high score from storage. 92 | chrome.storage.sync.get({ 93 | snakeHighScore: 0 94 | }, function (items) { 95 | highScore = items.snakeHighScore; 96 | init(); 97 | }); 98 | 99 | /* 100 | 101 | 102 | 103 | 104 | 105 | */ 106 | 107 | function init() { 108 | selectedDirection = "right"; //Set default direction. 109 | createSnake(); 110 | createFood(); //Now we can see the food particle 111 | score = 0; 112 | document.getElementById("playerHighScoreSpan").innerHTML = "Your High Score: " + highScore; 113 | paused = true; 114 | 115 | if (updateScreenInterval) 116 | clearInterval(updateScreenInterval); 117 | 118 | paint(); 119 | 120 | 121 | var instructionsDiv = document.createElement("div"); 122 | instructionsDiv.setAttribute("id", "snakeInstructionsDiv"); 123 | instructionsDiv.setAttribute("style", "position:absolute; top:50%; width:100%; color:black; text-align:center;"); 124 | 125 | var instructionSpan = document.createElement("span"); 126 | instructionSpan.innerHTML = "Help the imgur snake collect server resources!
To start the game, press any arrow key or numpad key 4/5/6/8."; 127 | //instructionSpan.setAttribute("style", "position:absolute; top:50%; left:50%; margin-left:-125px; color:black;"); 128 | instructionsDiv.appendChild(instructionSpan); 129 | 130 | document.getElementById("snakeGameDiv").appendChild(instructionsDiv); 131 | } 132 | 133 | function startGame() { 134 | //Start interval that will repaint every 60ms. 135 | if (updateScreenInterval) 136 | clearInterval(updateScreenInterval); 137 | updateScreenInterval = setInterval(paint, 60); 138 | } 139 | 140 | function createSnake() { 141 | var length = 5; //Length of the snake 142 | snakeArray = []; //Empty array to start with 143 | for(var i = length-1; i>=0; i--) { 144 | //This will create a horizontal snake starting from the top left 145 | snakeArray.push({x: i, y:0}); 146 | } 147 | } 148 | 149 | function createFood() { 150 | var foodXPosition, foodYPosition; 151 | do { //Assign x and y coordinates for the food. If they collide with the snake, assign new coordinates. Repeat until there is no collision. 152 | foodXPosition = Math.round(Math.random()*(canvasWidth-cellWidth)/cellWidth); //0-44 153 | foodYPosition = Math.round(Math.random()*(canvasHeight-cellWidth)/cellWidth); //0-44 154 | } while (checkCollision(foodXPosition, foodYPosition, snakeArray)); 155 | 156 | food = { 157 | x: foodXPosition, 158 | y: foodYPosition 159 | }; 160 | } 161 | 162 | 163 | function paint() 164 | { 165 | moveDirection = selectedDirection; 166 | 167 | //To avoid the snake trail we need to paint the BG on every frame 168 | //Lets paint the canvas now 169 | canvasContext.fillStyle = "white"; 170 | canvasContext.fillRect(0, 0, canvasWidth, canvasHeight); 171 | canvasContext.strokeStyle = "black"; 172 | canvasContext.strokeRect(0, 0, canvasWidth, canvasHeight); 173 | 174 | //Get the next coordinates of the front of the snake. 175 | var nextXPosition = snakeArray[0].x; 176 | var nextYPosition = snakeArray[0].y; 177 | if (moveDirection == "right") 178 | nextXPosition++; 179 | else if (moveDirection == "left") 180 | nextXPosition--; 181 | else if (moveDirection == "up") 182 | nextYPosition--; 183 | else if (moveDirection == "down") 184 | nextYPosition++; 185 | 186 | //Game over if snake goes out of bounds or hits its own body. 187 | if(nextXPosition == -1 || nextXPosition == canvasWidth/cellWidth || nextYPosition == -1 || nextYPosition == canvasHeight/cellWidth || checkCollision(nextXPosition, nextYPosition, snakeArray)) { 188 | if (score > highScore) { 189 | highScore = score; 190 | chrome.storage.sync.set({ 191 | snakeHighScore: highScore 192 | }, function () { 193 | //in the future send stats 194 | }); 195 | } 196 | 197 | init(); 198 | return; 199 | } 200 | 201 | //Handle food eating. 202 | if(nextXPosition == food.x && nextYPosition == food.y) { //If the new position of the snake's head matches the position of the food: ... 203 | var tail = {x: nextXPosition, y: nextYPosition}; 204 | score++; 205 | //Create new food 206 | createFood(); 207 | } 208 | else { 209 | var tail = snakeArray.pop(); //pops out the last cell 210 | tail.x = nextXPosition; tail.y = nextYPosition; 211 | } 212 | 213 | snakeArray.unshift(tail); //Put back the tail as the first cell. 214 | 215 | //Paint the snake. 216 | for(var i = 0; i < snakeArray.length; i++) { 217 | var c = snakeArray[i]; 218 | paintCell(c.x, c.y, "green"); 219 | } 220 | //Paint the food. 221 | paintCell(food.x, food.y, "blue"); 222 | //Paint the score. 223 | var score_text = "Score: " + score; 224 | canvasContext.fillText(score_text, 5, canvasHeight-5); 225 | } 226 | 227 | function paintCell(x, y, cellColor) { 228 | canvasContext.fillStyle = cellColor;//"blue"; 229 | canvasContext.fillRect(x*cellWidth, y*cellWidth, cellWidth, cellWidth); 230 | canvasContext.strokeStyle = "white"; 231 | canvasContext.strokeRect(x*cellWidth, y*cellWidth, cellWidth, cellWidth); 232 | } 233 | 234 | function checkCollision(x, y, array) { 235 | //This function will check if the provided x/y coordinates exist 236 | //in an array of cells or not 237 | for(var i = 0; i < array.length; i++) 238 | { 239 | if(array[i].x == x && array[i].y == y) 240 | return true; 241 | } 242 | return false; 243 | } 244 | 245 | function closeCanvasDiv() { 246 | console.log("Closing"); 247 | var parentDiv = this.parentNode; 248 | $(parentDiv).remove(); 249 | } 250 | } -------------------------------------------------------------------------------- /contentScripts/favoritesContent.js: -------------------------------------------------------------------------------- 1 | //Check if the page is an "over capacity" error page. 2 | $('body').ready(function() { 3 | var h1Elements = document.getElementsByTagName("h1"); 4 | 5 | for (i = 0; i < h1Elements.length; i++) { 6 | if (h1Elements[i].innerHTML == "Imgur is over capacity!") 7 | return; 8 | } 9 | 10 | favoritesContentMain(); 11 | }); 12 | 13 | var favoritedImagesArray = new Array(); 14 | var syncRunning = false; 15 | var favoriteArrayMaxLength = 45; 16 | var imagesAdded = 0, favoritesFound = 0; 17 | 18 | /* 19 | 20 | 21 | 22 | */ 23 | function favoritesContentMain() { 24 | addSyncButton(); 25 | } 26 | 27 | /* 28 | 29 | 30 | 31 | */ 32 | function addSyncButton() { 33 | var syncButtonDiv = document.createElement("div"); 34 | syncButtonDiv.setAttribute("style", "text-align:center; padding-bottom:25px"); 35 | syncButtonDiv.setAttribute("id", "sync-div"); 36 | 37 | var syncButton = document.createElement("div"); 38 | syncButton.setAttribute("id", "sync-favorites"); 39 | syncButton.innerHTML = "Sync Favorites"; 40 | syncButton.className = "btn btn-action"; 41 | syncButtonDiv.appendChild(syncButton); 42 | 43 | var placementElement = document.getElementById("imagelist"); 44 | placementElement.insertBefore(syncButtonDiv, placementElement.childNodes[0]); 45 | 46 | document.getElementById("sync-favorites").addEventListener("click", scrollAndSync); 47 | } 48 | 49 | function scrollAndSync() { 50 | var scrolling = setInterval( function() { 51 | scrollBy(0,300); 52 | if (document.getElementById("nomore") !== null) { 53 | clearInterval(scrolling); 54 | window.scrollTo(0, 0); 55 | syncFavorites(); 56 | } 57 | }, 25); 58 | } 59 | 60 | function syncFavorites() { 61 | if (syncRunning) 62 | return; 63 | 64 | syncRunning = true; 65 | 66 | chrome.storage.sync.get({ 67 | useSynchronizedStorage: false 68 | }, function(items) { 69 | if (items.useSynchronizedStorage) { //If using Chrome sync for storage is enabled... 70 | chrome.storage.sync.get({ 71 | //Set defaults. 72 | favoritedImages: new Array(), 73 | favoritedImages1: new Array(), 74 | favoritedImages2: new Array(), 75 | favoritedImages3: new Array(), 76 | favoritedImages4: new Array(), 77 | favoritedImages5: new Array(), 78 | favoritedImages6: new Array(), 79 | favoritedImages7: new Array(), 80 | favoritedImages8: new Array(), 81 | favoritedImages9: new Array(), 82 | favoritedImages10: new Array(), 83 | favoritedImages11: new Array(), 84 | favoritedImages12: new Array(), 85 | favoritedImages13: new Array() 86 | }, function(items) { 87 | favoritedImagesArray = items.favoritedImages; 88 | if (items.favoritedImages1.length > 0) 89 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages1); 90 | if (items.favoritedImages2.length > 0) 91 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages2); 92 | if (items.favoritedImages3.length > 0) 93 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages3); 94 | if (items.favoritedImages4.length > 0) 95 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages4); 96 | if (items.favoritedImages5.length > 0) 97 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages5); 98 | if (items.favoritedImages6.length > 0) 99 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages6); 100 | if (items.favoritedImages7.length > 0) 101 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages7); 102 | if (items.favoritedImages8.length > 0) 103 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages8); 104 | if (items.favoritedImages9.length > 0) 105 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages9); 106 | if (items.favoritedImages10.length > 0) 107 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages10); 108 | if (items.favoritedImages11.length > 0) 109 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages11); 110 | if (items.favoritedImages12.length > 0) 111 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages12); 112 | if (items.favoritedImages13.length > 0) 113 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages13); 114 | 115 | syncFavoritesHelper(); 116 | }); 117 | } 118 | else { 119 | chrome.storage.local.get({ 120 | //Set defaults. 121 | favoritedImages: new Array() 122 | }, function(items) { 123 | favoritedImagesArray = items.favoritedImages; 124 | 125 | syncFavoritesHelper(); 126 | }); 127 | } 128 | }); 129 | } 130 | 131 | function syncFavoritesHelper() { 132 | var actualFavoritedImagesArray = new Array(); 133 | 134 | var postElements = document.getElementsByClassName("post"); 135 | for (i = 0; i < postElements.length; i++) { 136 | if (postElements[i].getAttribute("class").indexOf("empty") > -1) continue; 137 | 138 | var titleCutoffIndex = 30; 139 | if (postElements[i].getElementsByClassName("hover")[0].getElementsByTagName("p")[0].innerHTML.length < 30) 140 | titleCutoffIndex = postElements[i].getElementsByClassName("hover")[0].getElementsByTagName("p")[0].innerHTML.length; 141 | 142 | var shortUrlStartIndex = postElements[i].getElementsByTagName("img")[0].getAttribute("src").indexOf(".com/") + 5; 143 | var shortUrlEndIndex = postElements[i].getElementsByTagName("img")[0].getAttribute("src").indexOf(".jpg"); 144 | 145 | var favImg = { 146 | id: postElements[i].getAttribute("id"), 147 | //url: postElements[i].getElementsByTagName("a")[0].getAttribute("href"), 148 | imgSrc: postElements[i].getElementsByTagName("img")[0].getAttribute("src").substring(shortUrlStartIndex, shortUrlEndIndex), 149 | title: postElements[i].getElementsByClassName("hover")[0].getElementsByTagName("p")[0].innerHTML.substring(0, titleCutoffIndex), 150 | directory: "root" 151 | } 152 | actualFavoritedImagesArray.push(favImg); 153 | } 154 | favoritesFound = actualFavoritedImagesArray.length; 155 | 156 | var indicesFound = new Array(); 157 | for (i = 0; i < actualFavoritedImagesArray.length; i++) { 158 | var imgFound = false; 159 | for (j = 0; j < favoritedImagesArray.length; j++) { 160 | if (actualFavoritedImagesArray[i].id == favoritedImagesArray[j].id) { 161 | imgFound = true; 162 | indicesFound.push(j); 163 | break; 164 | } 165 | } 166 | 167 | if (!imgFound) { 168 | favoritedImagesArray.push(actualFavoritedImagesArray[i]); 169 | indicesFound.push(favoritedImagesArray.length - 1); 170 | imagesAdded++; 171 | } 172 | 173 | } 174 | 175 | /*for (i = favoritedImagesArray.length; i >= 0; i--) { Delete images that were saved but are no longer favorited. 176 | if (indicesFound.indexOf(i) == -1) 177 | favoritedImagesArray.splice(i, 1); 178 | }*/ 179 | 180 | console.log("favoritedImagesArray.length: " + favoritedImagesArray.length); 181 | for (i = 0; i < favoritedImagesArray.length; i++) 182 | console.log("favoritedImagesArray has id: " + favoritedImagesArray[i].id); 183 | 184 | chrome.storage.sync.get({ 185 | useSynchronizedStorage: false 186 | }, function(items) { 187 | if (items.useSynchronizedStorage) { //If using Chrome sync for storage is enabled... 188 | chrome.storage.sync.set({ 189 | favoritedImages: favoritedImagesArray.slice(0, favoriteArrayMaxLength), 190 | favoritedImages1: favoritedImagesArray.slice(favoriteArrayMaxLength , 2 * favoriteArrayMaxLength), 191 | favoritedImages2: favoritedImagesArray.slice(2 * favoriteArrayMaxLength , 3 * favoriteArrayMaxLength), 192 | favoritedImages3: favoritedImagesArray.slice(3 * favoriteArrayMaxLength , 4 * favoriteArrayMaxLength), 193 | favoritedImages4: favoritedImagesArray.slice(4 * favoriteArrayMaxLength , 5 * favoriteArrayMaxLength), 194 | favoritedImages5: favoritedImagesArray.slice(5 * favoriteArrayMaxLength , 6 * favoriteArrayMaxLength), 195 | favoritedImages6: favoritedImagesArray.slice(6 * favoriteArrayMaxLength , 7 * favoriteArrayMaxLength), 196 | favoritedImages7: favoritedImagesArray.slice(7 * favoriteArrayMaxLength , 8 * favoriteArrayMaxLength), 197 | favoritedImages8: favoritedImagesArray.slice(8 * favoriteArrayMaxLength , 9 * favoriteArrayMaxLength), 198 | favoritedImages9: favoritedImagesArray.slice(9 * favoriteArrayMaxLength , 10 * favoriteArrayMaxLength), 199 | favoritedImages10: favoritedImagesArray.slice(10 * favoriteArrayMaxLength , 11 * favoriteArrayMaxLength), 200 | favoritedImages11: favoritedImagesArray.slice(11 * favoriteArrayMaxLength , 12 * favoriteArrayMaxLength), 201 | favoritedImages12: favoritedImagesArray.slice(12 * favoriteArrayMaxLength , 13 * favoriteArrayMaxLength), 202 | favoritedImages13: favoritedImagesArray.slice(13 * favoriteArrayMaxLength , 14 * favoriteArrayMaxLength) 203 | }, function() { 204 | syncMessageSetter(chrome.runtime.lastError); 205 | }); 206 | } 207 | else { 208 | chrome.storage.local.set({ 209 | favoritedImages: favoritedImagesArray 210 | }, function() { 211 | syncMessageSetter(chrome.runtime.lastError); 212 | }); 213 | } 214 | }); 215 | } 216 | 217 | function syncMessageSetter(lastError) { 218 | var messageElement = document.createElement("p"); 219 | messageElement.style.paddingTop = "25px"; 220 | 221 | if (lastError) { 222 | console.error("Error syncing: " + chrome.runtime.lastError.message); 223 | messageElement.style.color = "red"; 224 | messageElement.innerHTML = 'Sync failed.'; 225 | } 226 | else { 227 | messageElement.style.color = "#85bf25"; 228 | messageElement.innerHTML = 'Sync successful (' + imagesAdded + ' new images out of ' + favoritesFound +' favorites found). You can organize your bookmarked images via the "iBA"" icon in the top right.'; 229 | 230 | imagesAdded = 0; 231 | favoritesFound = 0; 232 | } 233 | 234 | document.getElementById("sync-div").appendChild(messageElement); 235 | syncRunning = false; 236 | } 237 | -------------------------------------------------------------------------------- /contentScripts/notificationsContent.js: -------------------------------------------------------------------------------- 1 | var activeNotification; 2 | var slideShowMessageBox; 3 | var closeNotificationInterval; 4 | var canDisplayNotifications; 5 | 6 | //Load notifications options from storage. 7 | chrome.storage.sync.get({ 8 | //Set defaults. 9 | notificationsEnabled: true 10 | }, function(items) { 11 | canDisplayNotifications = items.notificationsEnabled; 12 | }); 13 | 14 | 15 | function addNotification(reasonGiven, descriptionGiven) { 16 | if(!canDisplayNotifications) 17 | return; 18 | 19 | closeActiveNotification(); 20 | 21 | var notificationDiv = document.createElement("div"); 22 | notificationDiv.setAttribute("id", "ibaNotification"); 23 | 24 | var msgWidth = (window.innerWidth - 1030) / 2; 25 | if (msgWidth > 200) 26 | msgWidth = 200; 27 | else if (msgWidth < 150) //If the screen is too small: return. 28 | return; 29 | var msgHeight = msgWidth / 2; 30 | 31 | var topPos = 0; 32 | var slideShowMsgBox = document.getElementById("slideShowMessageBox"); 33 | if (slideShowMsgBox) 34 | topPos = slideShowMsgBox.style.height; 35 | 36 | //notificationDiv.setAttribute("style", "z-index:9999;position:fixed;top:" + topPos + ";left:0;height:" + msgHeight + "px;width:" + msgWidth + "px;border:2px solid;background-color:#121212;text-align:center;"); 37 | //notificationDiv.setAttribute("style", "z-index:9999;position: absolute;margin: 0 auto;width:"+msgWidth+"px;transform: translate(-50%);left: 50%;top:15%;border:2px solid;border-color: #2086E0;background-color: #272727;border-radius: .3em;padding: 0.6em;text-align:center;"); 38 | notificationDiv.setAttribute("style", "z-index:9999; position:fixed; margin:0 auto; width:"+msgWidth+"px; left:0; top:" + topPos + "; border:2px solid;border-color: #2086E0;background-color: #272727;border-radius: .3em;padding: 0.6em;text-align:center;"); 39 | 40 | var linebreak1 = document.createElement("br"); 41 | notificationDiv.appendChild(linebreak1); 42 | 43 | var reasonTxt = document.createElement("span"); 44 | reasonTxt.innerHTML = reasonGiven; 45 | notificationDiv.appendChild(reasonTxt); 46 | 47 | var linebreak2 = document.createElement("br"); 48 | notificationDiv.appendChild(linebreak2); 49 | 50 | var descTxt = document.createElement("span"); 51 | descTxt.innerHTML = descriptionGiven; 52 | notificationDiv.appendChild(descTxt); 53 | 54 | var closeNotificationButton = document.createElement("span"); 55 | closeNotificationButton.innerHTML = "Close"; 56 | closeNotificationButton.setAttribute("style", "cursor:pointer;position:absolute;top:.2em;right:.2em;color:#4E76C9;"); 57 | closeNotificationButton.addEventListener("click", closeNotification); 58 | notificationDiv.appendChild(closeNotificationButton); 59 | 60 | var linebreak3 = document.createElement("br"); 61 | notificationDiv.appendChild(linebreak3); 62 | 63 | if (descriptionGiven === "Post Already Viewed") { 64 | var disableButton = document.createElement("span"); 65 | disableButton.innerHTML = "Press 'F9' to disable."; 66 | disableButton.setAttribute("style", "cursor:pointer;color:#4E76C9;"); 67 | disableButton.addEventListener("click", temporarilyStopSkippingViewedPosts); 68 | notificationDiv.appendChild(disableButton); 69 | } 70 | else if (descriptionGiven.indexOf("User is blocked:") == 0 || descriptionGiven.indexOf("Post is from Reddit.") == 0 || descriptionGiven.indexOf("Post from blocked subreddit:") == 0 || descriptionGiven.indexOf("Keyword in title is blocked:") == 0) { 71 | $(descTxt).css("color", "red"); 72 | } 73 | else if (descriptionGiven === "Check the username.") { 74 | $(descTxt).css("color", "green"); 75 | 76 | var disableButton = document.createElement("span"); 77 | disableButton.innerHTML = "Click to disable these notifications."; 78 | disableButton.setAttribute("style", "cursor:pointer;color:#4E76C9;"); 79 | disableButton.addEventListener("click", permanentlyDisableSpecialUsersNotifications); 80 | notificationDiv.appendChild(disableButton); 81 | } 82 | else if (descriptionGiven === "This post was made by the creator of the imgur Browsing Aid extension.") { 83 | $(descTxt).css("color", "green"); 84 | 85 | var disableButton = document.createElement("span"); 86 | disableButton.innerHTML = "Disable These Notifications"; 87 | disableButton.setAttribute("style", "cursor:pointer;color:#4E76C9;"); 88 | disableButton.addEventListener("click", permanentlyDisableTollskiNotifications); 89 | notificationDiv.appendChild(disableButton); 90 | } 91 | 92 | document.getElementsByTagName("body")[0].appendChild(notificationDiv); 93 | activeNotification = document.getElementById("ibaNotification"); 94 | 95 | var notificationBox = document.getElementById("ibaNotification"); 96 | while (($(notificationBox.lastChild).position().top + $(notificationBox.lastChild).height()) > $(notificationBox).innerHeight()) { //While the inside text is vertically overflowing: decrease font-size by 10%. 97 | console.log("Notification text overflow, fixing."); 98 | var oldFontSize = parseInt($(notificationBox).css("font-size")); 99 | var smallFontSize = oldFontSize * 0.9; 100 | $(notificationBox).css("font-size", smallFontSize + "px"); 101 | } 102 | 103 | closeNotificationInterval = setInterval( function() { 104 | closeActiveNotification(); 105 | }, 6500); 106 | } 107 | 108 | function addSlideShowMessageBox() { 109 | if(!canDisplayNotifications) 110 | return; 111 | 112 | if (slideShowMessageBox) 113 | $('#slideShowMessageBox').remove(); 114 | 115 | var msgDiv = document.createElement("div"); 116 | msgDiv.setAttribute("id", "slideShowMessageBox"); 117 | 118 | var msgWidth = (window.innerWidth - 1030) / 2; 119 | if (msgWidth > 200) 120 | msgWidth = 200; 121 | else if (msgWidth < 150) //If the screen is too small: return. 122 | return; 123 | var msgHeight = msgWidth / 2; 124 | 125 | msgDiv.setAttribute("style", "z-index:9999;position:fixed;top:0;left:0;height:" + msgHeight + "px;width:" + msgWidth + "px;border:2px solid;background-color:#121212;"); 126 | //msgDiv.setAttribute("style", "z-index:9999;position: absolute;margin: 0 auto;width:"+msgWidth+"px;transform: translate(-50%);left: 50%;top: 15%;border:2px solid;border-color: #2086E0;background-color: #272727;border-radius: .3em;padding: 0.6em;text-align:center;"); 127 | 128 | var timeTxt = document.createElement("span"); 129 | timeTxt.innerHTML = "Next Post: "; 130 | timeTxt.setAttribute("id", "slideShowNextPostTime"); 131 | msgDiv.appendChild(timeTxt); 132 | 133 | var linebreak1 = document.createElement("br"); 134 | msgDiv.appendChild(linebreak1); 135 | 136 | var pauseTxt = document.createElement("span"); 137 | pauseTxt.innerHTML = "Pause: 'p' or left arrow"; 138 | msgDiv.appendChild(pauseTxt); 139 | 140 | var linebreak2 = document.createElement("br"); 141 | msgDiv.appendChild(linebreak2); 142 | 143 | var unpauseTxt = document.createElement("span"); 144 | unpauseTxt.innerHTML = "Un-Pause: 'p' or right arrow"; 145 | msgDiv.appendChild(unpauseTxt); 146 | 147 | var linebreak3 = document.createElement("br"); 148 | msgDiv.appendChild(linebreak3); 149 | 150 | var stopTxt = document.createElement("span"); 151 | stopTxt.innerHTML = "Stop: 'e'"; 152 | msgDiv.appendChild(stopTxt); 153 | 154 | var closeNotificationButton = document.createElement("span"); 155 | closeNotificationButton.innerHTML = "Close"; 156 | closeNotificationButton.setAttribute("style", "cursor:pointer;position:absolute;top: .2em;right: .2em;color:#4E76C9;"); 157 | closeNotificationButton.setAttribute("class", "closeNotificationButton"); 158 | closeNotificationButton.addEventListener("click", closeNotification); 159 | msgDiv.appendChild(closeNotificationButton); 160 | 161 | document.getElementsByTagName("body")[0].appendChild(msgDiv); 162 | slideShowMessageBox = document.getElementById("slideShowMessageBox"); 163 | } 164 | 165 | function addSystemNotification(notificationText) { 166 | var notificationDiv = document.createElement("div"); 167 | notificationDiv.setAttribute("id", "ibaSystemNotification"); 168 | 169 | var msgWidth = 300; 170 | var msgHeight = msgWidth / 2; 171 | 172 | notificationDiv.setAttribute("style", "z-index:9999;position: fixed;margin: 0 auto;width:"+msgWidth+"px;transform: translate(-50%);left: 50%;top: 15%;border:2px solid;border-color: #2086E0;background-color: #272727;border-radius: .3em;padding: 0.6em;text-align:center;"); 173 | 174 | var titleSpan = document.createElement("span"); 175 | titleSpan.innerHTML = "imgur Browsing Aid"; 176 | notificationDiv.appendChild(titleSpan); 177 | 178 | var linebreak1 = document.createElement("br"); 179 | notificationDiv.appendChild(linebreak1); 180 | 181 | var linebreak2 = document.createElement("br"); 182 | notificationDiv.appendChild(linebreak2); 183 | 184 | var notificationSpan = document.createElement("span"); 185 | notificationSpan.innerHTML = notificationText; 186 | notificationDiv.appendChild(notificationSpan); 187 | 188 | var closeNotificationButton = document.createElement("span"); 189 | closeNotificationButton.innerHTML = "Close"; 190 | closeNotificationButton.setAttribute("style", "cursor:pointer;position:absolute;top: .2em;right: .2em;color:#4E76C9;"); 191 | closeNotificationButton.addEventListener("click", closeSystemMessage); 192 | notificationDiv.appendChild(closeNotificationButton); 193 | 194 | var aElements = notificationDiv.getElementsByTagName("a"); 195 | for ( i = 0; i < aElements.length; i++) { 196 | aElements[i].addEventListener("click", function() { 197 | chrome.storage.sync.set({ 198 | lastMessageRead: true 199 | }, function() {}); 200 | }); 201 | } 202 | 203 | document.getElementsByTagName("body")[0].appendChild(notificationDiv); 204 | } 205 | 206 | 207 | function closeActiveNotification() { 208 | $('#ibaNotification').remove(); 209 | 210 | if (closeNotificationInterval) 211 | clearInterval(closeNotificationInterval); 212 | } 213 | 214 | function closeNotification() { 215 | if (closeNotificationInterval) 216 | clearInterval(closeNotificationInterval); 217 | 218 | var messageBox = this.parentNode; 219 | 220 | $(messageBox).remove(); 221 | } 222 | 223 | function closeSystemMessage() { 224 | chrome.storage.sync.set({ 225 | lastMessageRead: true 226 | }, function() {}); 227 | 228 | var messageBox = this.parentNode; 229 | 230 | $(messageBox).remove(); 231 | } 232 | 233 | function closeSlideShowMessageBox() { 234 | if (slideShowMessageBox) 235 | $('#slideShowMessageBox').remove(); 236 | } 237 | 238 | function updateSlideShowMessage(secondsRemaining) { 239 | if(!canDisplayNotifications) 240 | return; 241 | 242 | var slideShowPostTimeSpan = document.getElementById("slideShowNextPostTime"); 243 | if (slideShowPostTimeSpan) 244 | slideShowPostTimeSpan.innerHTML = "Next Post: " + secondsRemaining; 245 | } -------------------------------------------------------------------------------- /pages/blockedKeywords.js: -------------------------------------------------------------------------------- 1 | var blockedKeywordArray = new Array(); 2 | var blockedSubredditArray = new Array(); 3 | var disableKeywordStatus, disableSubredditStatus; 4 | 5 | document.addEventListener('DOMContentLoaded', restore_options); 6 | document.getElementById('blockAllSubredditsCheckbox').addEventListener('click', blockAllSubredditsCheckboxClicked); 7 | document.getElementById('blockKeywordButton').addEventListener('click', addBlockedKeyword); 8 | document.getElementById('blockSubredditButton').addEventListener('click', addBlockedSubreddit); 9 | 10 | /* 11 | 12 | 13 | 14 | 15 | */ 16 | 17 | // Loads options from chrome.storage 18 | function restore_options() { 19 | chrome.storage.local.get({ 20 | blockedKeywords: new Array(), 21 | blockedSubreddits: new Array(), 22 | blockAllSubreddits: false 23 | }, function(items) { 24 | document.getElementById('blockAllSubredditsCheckbox').checked = items.blockAllSubreddits; 25 | blockedKeywordArray = items.blockedKeywords; 26 | blockedSubredditArray = items.blockedSubreddits; 27 | 28 | populateListsAndSetReady(); 29 | }); 30 | } 31 | 32 | 33 | //populateListsAndSetReady: Calls the functions to display blocked keywords and subreddits, shows the mainDiv. 34 | function populateListsAndSetReady() { 35 | populateBlockedKeywordList(); 36 | populateBlockedSubredditList(); 37 | 38 | document.getElementById('mainDiv').style.display = "inline"; 39 | document.getElementById('loadingDiv').style.display = "none"; 40 | } 41 | 42 | /* 43 | 44 | 45 | 46 | */ 47 | 48 | //addBlockedKeyword: Gets value input by user and adds it to the blockedKeywords array. 49 | function addBlockedKeyword() { 50 | var keywordToBlock = document.getElementById("blockKeywordInput").value; 51 | var result; 52 | 53 | // Blank out the input box. 54 | document.getElementById("blockKeywordInput").value = ""; 55 | 56 | if (typeof (value = addBlockedWord(keywordToBlock, blockedKeywordArray)) == 'undefined') { 57 | // Keyword was added successfully. Save to storage. 58 | chrome.storage.local.set({ 59 | blockedKeywords: blockedKeywordArray 60 | }, function() { 61 | // Rewrite the blocked keyword array to reflect the update. 62 | populateBlockedKeywordList(); 63 | 64 | // Notify the user that they need to reload Imgur for the change to take effect. 65 | updateStatusText("keywordStatus"); 66 | }); 67 | } else if (typeof value == 'number') { 68 | // Keyword already existed in the array. Highlight it and inform the user of what went wrong. 69 | populateBlockedKeywordListHighlight(value); 70 | updateStatusTextCustom("keywordStatus", "That keyword has already been blocked."); 71 | } else { 72 | // An error was encountered. Redraw the array to clear highlights and display the error for the user. 73 | populateBlockedKeywordList(); 74 | updateStatusTextCustom("keywordStatus", value); 75 | } 76 | } 77 | 78 | //addBlockedSubreddit: Gets value input by user and adds it to the blockedSubreddits array. 79 | function addBlockedSubreddit() { 80 | var subredditToBlock = document.getElementById("blockSubredditInput").value; 81 | var index; 82 | 83 | // Blank out the input box. 84 | document.getElementById("blockSubredditInput").value = ""; 85 | 86 | if (typeof (value = addBlockedWord(subredditToBlock, blockedSubredditArray)) == 'undefined') { 87 | // Subreddit was added successfully. Save to storage. 88 | chrome.storage.local.set({ 89 | blockedSubreddits: blockedSubredditArray 90 | }, function() { 91 | // Rewrite the blocked subreddit array to reflect the update. 92 | populateBlockedSubredditList(); 93 | 94 | // Notify the user that they need to reload Imgur for the change to take effect. 95 | updateStatusText("subredditStatus"); 96 | }); 97 | } else if (typeof value == 'number') { 98 | // Subreddit already existed in the array. Highlight it and inform the user of what went wrong. 99 | populateBlockedSubredditListHighlight(value); 100 | updateStatusTextCustom("subredditStatus", "That subreddit has already been blocked."); 101 | } else { 102 | // An error was encountered. Redraw the array to clear highlights and display the error for the user. 103 | populateBlockedSubredditList(); 104 | updateStatusTextCustom("subredditStatus", value); 105 | 106 | } 107 | } 108 | 109 | // Helper function for addBlockedKeyword and addBlockedSubreddit. Checks precondition (length > 0), performs binary search, pushes word if not in array. 110 | // If an error condition was encountered, a string describing the error is returned. 111 | // If the word was found in the array, the index of the word is returned. 112 | // If the word was successfully inserted into the array, nothing is returned. 113 | function addBlockedWord(wordToBlock, blockArray) { 114 | if (wordToBlock.length == 0) 115 | return "You must specify a word to block."; // Error state. 116 | 117 | //Check if keyword is already blocked. Now with binary search to speed up comparisons over large arrays. 118 | var bsMin = 0, bsMax = blockArray.length - 1, bsMid = 0, comparison = 0; 119 | while (bsMax >= bsMin) { 120 | bsMid = Math.floor(bsMin + ((bsMax - bsMin) / 2)); 121 | comparison = blockArray[bsMid].localeCompare(wordToBlock); 122 | if (comparison > 0) 123 | bsMax = bsMid - 1; // Key must be in the lower subset. 124 | else if (comparison < 0) 125 | bsMin = bsMid + 1; // Key must be in the upper subset. 126 | else 127 | return bsMid; // Key has been found. Return its index for highlighting. 128 | } 129 | 130 | if (comparison < 0) 131 | blockArray.splice(bsMid+1, 0, wordToBlock); // Key should be at a greater index than the last tested key. 132 | else 133 | blockArray.splice(bsMid, 0, wordToBlock); // Key should be at the same index as the last tested key. 134 | 135 | return; // Success: Word inserted in array. 136 | } 137 | 138 | //blockAllSubredditsCheckboxClicked: Gets value of blockAllSubredditsCheckbox and saves to storage. 139 | function blockAllSubredditsCheckboxClicked() { 140 | var blockAll = document.getElementById('blockAllSubredditsCheckbox').checked; 141 | 142 | chrome.storage.local.set({ 143 | blockAllSubreddits: blockAll 144 | }, function() { 145 | updateStatusText("subredditStatus"); 146 | }); 147 | } 148 | 149 | //populateBlockedKeywordList: Displays all the blocked keywords and adds buttons to unblock them. 150 | function populateBlockedKeywordList() { 151 | populateBlockedKeywordListHighlight(-1); 152 | } 153 | 154 | //populateBlockedSubredditListHighlight: Displays all the blocked subreddits and adds buttons to unblock them. 155 | function populateBlockedSubredditList() { 156 | populateBlockedSubredditListHighlight(-1); 157 | } 158 | 159 | //populateBlockedKeywordListHighlight: Displays all the blocked keywords and adds buttons to unblock them. Highlights the entry at the given index. 160 | function populateBlockedKeywordListHighlight(index) { 161 | var listHTML = ""; 162 | 163 | for (i = 0; i < blockedKeywordArray.length; i++) { 164 | if (i == index) { 165 | // TODO: Instead of a static highlight, make this a red pulse that fades back to black. 166 | listHTML += '' + blockedKeywordArray[i] + ''; 167 | } else { 168 | listHTML += '' + blockedKeywordArray[i] + ''; 169 | } 170 | } 171 | 172 | document.getElementById("blockedKeywordsTable").innerHTML = listHTML; 173 | 174 | for (i = 0; i < blockedKeywordArray.length; i++) { 175 | document.getElementById("removeKeyword" + i).addEventListener("click", unblockKeyword); 176 | } 177 | } 178 | 179 | //populateBlockedSubredditListHighlight: Displays all the blocked subreddits and adds buttons to unblock them. Highlights the entry at the given index. 180 | function populateBlockedSubredditListHighlight(index) { 181 | var listHTML = ""; 182 | 183 | for (i = 0; i < blockedSubredditArray.length; i++) { 184 | if (i == index) { 185 | // TODO: Instead of a static highlight, make this a red pulse that fades back to black. 186 | listHTML += '' + blockedSubredditArray[i] + ''; 187 | } else { 188 | listHTML += '' + blockedSubredditArray[i] + ''; 189 | } 190 | } 191 | 192 | document.getElementById("blockedSubredditsTable").innerHTML = listHTML; 193 | 194 | for (i = 0; i < blockedSubredditArray.length; i++) { 195 | document.getElementById("removeSubreddit" + i).addEventListener("click", unblockSubreddit); 196 | } 197 | } 198 | 199 | //unblockKeyword: Removes keyword from blockedKeywords array. 200 | function unblockKeyword() { 201 | var keyword = this.getAttribute("keyword"); 202 | console.log("unblocking keyword:" + keyword); 203 | 204 | var index = blockedKeywordArray.indexOf(keyword); 205 | blockedKeywordArray.splice(index, 1); 206 | 207 | chrome.storage.local.set({ 208 | blockedKeywords: blockedKeywordArray 209 | }, function() { 210 | populateBlockedKeywordList(); 211 | updateStatusText("keywordStatus"); 212 | }); 213 | } 214 | 215 | //unblockSubreddit: Removes subreddit from blockedSubreddits array. 216 | function unblockSubreddit() { 217 | var subreddit = this.getAttribute("subreddit"); 218 | console.log("unblocking subreddit:" + subreddit); 219 | 220 | var index = blockedSubredditArray.indexOf(subreddit); 221 | blockedSubredditArray.splice(index, 1); 222 | 223 | chrome.storage.local.set({ 224 | blockedSubreddits: blockedSubredditArray 225 | }, function() { 226 | populateBlockedSubredditList(); 227 | updateStatusText("subredditStatus"); 228 | }); 229 | } 230 | 231 | // Displays the "Please refresh" message in the element with id matching 'field' parameter. 232 | function updateStatusText(field) { 233 | updateStatusTextCustom(field, "Please refresh any open Imgur pages for changes to go into effect."); 234 | } 235 | 236 | // Performs the same function as updateStatusText, but allows custom text to be inserted. 237 | function updateStatusTextCustom(field, customText) { 238 | var status; 239 | 240 | status = document.getElementById(field); 241 | 242 | status.textContent = customText; 243 | 244 | if (field == "keywordStatus") { 245 | if (disableKeywordStatus) 246 | clearTimeout(disableKeywordStatus); 247 | 248 | disableKeywordStatus = setTimeout(function() { status.textContent = ''; }, 3000); 249 | } 250 | else if (type == "subredditStatus") { 251 | if (disableSubredditStatus) 252 | clearTimeout(disableSubredditStatus); 253 | 254 | disableSubredditStatus = setTimeout(function() { status.textContent = ''; }, 3000); 255 | } 256 | } -------------------------------------------------------------------------------- /pages/options.js: -------------------------------------------------------------------------------- 1 | var blockedUserList = new Array(); 2 | var followedUserList = new Array(); 3 | var lastSavedUseSynchronizedStorage; 4 | var moveRunning = false; 5 | 6 | document.addEventListener('DOMContentLoaded', restore_options); 7 | document.getElementById('save').addEventListener('click', save_options); 8 | document.getElementById('clearViewedPostsButton').addEventListener('click', deleteViewedPosts); 9 | 10 | document.getElementById("versionSpan").innerHTML = "(Version " + chrome.runtime.getManifest().version + ")"; 11 | 12 | // Loads options from chrome.storage 13 | function restore_options() { 14 | chrome.storage.sync.get({ //(Main settings are always stored in storage.sync.) 15 | // Set defaults. 16 | promotedSkipEnabled: false, 17 | topBarCloseEnabled: true, 18 | removeViaMobileSpansEnabled: true, 19 | slideShowModeEnabled: true, 20 | slideShowSecondsPerPost: 10, 21 | notificationsEnabled: true, 22 | specialUserNotificationEnabled: true, 23 | tollskiNotificationEnabled: true, 24 | viewedIconsEnabled: true, 25 | skipViewedPostsEnabled: false, 26 | useSynchronizedStorage: "neverSet", 27 | snakeGameEnabled: true 28 | }, function(items) { 29 | document.getElementById('promotedSkipCheckbox').checked = items.promotedSkipEnabled; 30 | document.getElementById('topBarCloseCheckbox').checked = items.topBarCloseEnabled; 31 | document.getElementById('removeViaMobileSpansCheckbox').checked = items.removeViaMobileSpansEnabled; 32 | document.getElementById('synchronizedStorageCheckbox').checked = items.useSynchronizedStorage; 33 | document.getElementById('slideShowModeCheckbox').checked = items.slideShowModeEnabled; 34 | document.getElementById('slideShowPostTimeTextbox').value = items.slideShowSecondsPerPost; 35 | document.getElementById('notificationsCheckbox').checked = items.notificationsEnabled; 36 | document.getElementById('specialUserNotificationCheckbox').checked = items.specialUserNotificationEnabled; 37 | document.getElementById('tollskiNotificationCheckbox').checked = items.tollskiNotificationEnabled; 38 | document.getElementById('viewedIconsCheckbox').checked = items.viewedIconsEnabled; 39 | document.getElementById('skipViewedPostsCheckbox').checked = items.skipViewedPostsEnabled; 40 | document.getElementById('snakeGameCheckbox').checked = items.snakeGameEnabled; 41 | 42 | if (items.useSynchronizedStorage == "neverSet") { //If the user just installed or just updated from < v0.4.0: convert storage to local. 43 | moveStorage(true, false); 44 | 45 | alert("Local storage is being initialized.\n\nYou may press OK at any time to dismiss this message."); 46 | 47 | chrome.storage.sync.set({ 48 | useSynchronizedStorage: false 49 | }, function() { 50 | if (!chrome.runtime.lastError) { 51 | console.log("neverSet, converted.") 52 | setTimeout(function() { 53 | if (!moveRunning) 54 | window.location.reload(); 55 | }, 2000); 56 | } 57 | }); 58 | 59 | return; 60 | } 61 | else //Else: we can assume it is true or false. 62 | lastSavedUseSynchronizedStorage = items.useSynchronizedStorage; 63 | 64 | if (lastSavedUseSynchronizedStorage) { 65 | chrome.storage.sync.get({ 66 | blockedUsers: new Array(), 67 | followedUsers: new Array() 68 | }, function(items) { 69 | populateListsAndSetReady(items.blockedUsers, items.followedUsers); 70 | }); 71 | } 72 | else { 73 | chrome.storage.local.get({ 74 | blockedUsers: new Array(), 75 | followedUsers: new Array() 76 | }, function(items) { 77 | populateListsAndSetReady(items.blockedUsers, items.followedUsers); 78 | }); 79 | } 80 | }); 81 | } 82 | 83 | // Saves options to chrome.storage 84 | function save_options() { 85 | if (moveRunning) 86 | return; 87 | 88 | var promotedSkip = document.getElementById('promotedSkipCheckbox').checked; 89 | var topBarClose = document.getElementById('topBarCloseCheckbox').checked; 90 | var removeViaMobileSpans = document.getElementById('removeViaMobileSpansCheckbox').checked; 91 | var useSync = document.getElementById('synchronizedStorageCheckbox').checked; 92 | var slideShowMode = document.getElementById('slideShowModeCheckbox').checked; 93 | var slideShowPostTime = document.getElementById('slideShowPostTimeTextbox').value; 94 | console.log(slideShowPostTime); 95 | if (!slideShowPostTime || isNaN(slideShowPostTime) || slideShowPostTime < 1 || slideShowPostTime > 999) { //If slideShowPostTime is not a number between 1-3 characters long... 96 | updateStatusText("Not saved. Please enter a whole number between 1 and 999 for the slide show seconds-per-post option.", false); 97 | return; 98 | } 99 | var useNotifications = document.getElementById('notificationsCheckbox').checked; 100 | var specialUserNotify = document.getElementById('specialUserNotificationCheckbox').checked; 101 | var tollskiNotify = document.getElementById('tollskiNotificationCheckbox').checked; 102 | var viewedIcons = document.getElementById('viewedIconsCheckbox').checked; 103 | var skipViewed = document.getElementById('skipViewedPostsCheckbox').checked; 104 | var snakeGame = document.getElementById('snakeGameCheckbox').checked; 105 | 106 | if (useSync != lastSavedUseSynchronizedStorage) { //If the user changed their sync setting... 107 | if (useSync) { //If they selected to use storage.sync: prompt for confirmation. 108 | var confirmMove = confirm("Do you really wish to use Chrome online sync?\n(Bookmarked images and favorite comments may be lost if you have too many.)"); 109 | if (confirmMove) 110 | moveStorage(lastSavedUseSynchronizedStorage, useSync); 111 | else 112 | return; 113 | } 114 | else 115 | moveStorage(lastSavedUseSynchronizedStorage, useSync); 116 | } 117 | 118 | chrome.storage.sync.set({ 119 | promotedSkipEnabled: promotedSkip, 120 | topBarCloseEnabled: topBarClose, 121 | removeViaMobileSpansEnabled: removeViaMobileSpans, 122 | slideShowModeEnabled: slideShowMode, 123 | slideShowSecondsPerPost: slideShowPostTime, 124 | notificationsEnabled: useNotifications, 125 | specialUserNotificationEnabled: specialUserNotify, 126 | tollskiNotificationEnabled: tollskiNotify, 127 | viewedIconsEnabled: viewedIcons, 128 | skipViewedPostsEnabled: skipViewed, 129 | snakeGameEnabled: snakeGame 130 | }, function() { 131 | if (chrome.runtime.lastError) { 132 | updateStatusText("Error: Something went wrong when trying to save.", false); 133 | console.log("chrome.runtime.lastError: " + chrome.runtime.lastError); 134 | } 135 | else { 136 | if (useSync == lastSavedUseSynchronizedStorage) { 137 | //lastSavedUseSynchronizedStorage = useSync; 138 | 139 | updateStatusText("Options saved. Please refresh any open imgur tabs.", true); 140 | } 141 | } 142 | }); 143 | } 144 | 145 | 146 | 147 | 148 | function deleteViewedPosts() { 149 | var confirmDelete = confirm("Do you really want to erase your viewed post history?"); 150 | if (!confirmDelete) 151 | return; 152 | 153 | chrome.storage.local.set({ 154 | viewedPosts: new Array() 155 | }, function() { 156 | updateStatusText("Viewed post history has been deleted.", true); 157 | }); 158 | } 159 | 160 | //moveStorage: Moves blockedUsers, followedUsers, favoriteComments, favoritedImages, and favoritedImagesDirectories to storage.local from storage.sync, or visa versa. 161 | function moveStorage(syncToLocal, newSyncSetting) { 162 | moveRunning = true; 163 | if (syncToLocal) { //Convert from synchronized to local. 164 | chrome.storage.sync.get({ 165 | blockedUsers: new Array(), 166 | followedUsers: new Array(), 167 | favoriteComments: new Array(), 168 | favoritedImages: new Array(), 169 | favoritedImages1: new Array(), 170 | favoritedImages2: new Array(), 171 | favoritedImages3: new Array(), 172 | favoritedImages4: new Array(), 173 | favoritedImages5: new Array(), 174 | favoritedImages6: new Array(), 175 | favoritedImages7: new Array(), 176 | favoritedImages8: new Array(), 177 | favoritedImages9: new Array(), 178 | favoritedImages10: new Array(), 179 | favoritedImages11: new Array(), 180 | favoritedImages12: new Array(), 181 | favoritedImages13: new Array(), 182 | favoritedImagesDirectories: new Array() 183 | }, function(items) { 184 | var favoritedImagesArray = items.favoritedImages; 185 | if (items.favoritedImages1.length > 0) 186 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages1); 187 | if (items.favoritedImages2.length > 0) 188 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages2); 189 | if (items.favoritedImages3.length > 0) 190 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages3); 191 | if (items.favoritedImages4.length > 0) 192 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages4); 193 | if (items.favoritedImages5.length > 0) 194 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages5); 195 | if (items.favoritedImages6.length > 0) 196 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages6); 197 | if (items.favoritedImages7.length > 0) 198 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages7); 199 | if (items.favoritedImages8.length > 0) 200 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages8); 201 | if (items.favoritedImages9.length > 0) 202 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages9); 203 | if (items.favoritedImages10.length > 0) 204 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages10); 205 | if (items.favoritedImages11.length > 0) 206 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages11); 207 | if (items.favoritedImages12.length > 0) 208 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages12); 209 | if (items.favoritedImages13.length > 0) 210 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages13); 211 | 212 | chrome.storage.local.set({ 213 | blockedUsers: items.blockedUsers, 214 | followedUsers: items.followedUsers, 215 | favoriteComments: items.favoriteComments, 216 | favoritedImages: favoritedImagesArray, 217 | favoritedImagesDirectories: items.favoritedImagesDirectories 218 | }, function() { 219 | if (chrome.runtime.lastError) { 220 | console.log("Failed to move storage from Chrome sync to local: " + chrome.runtime.lastError.message); 221 | } 222 | else { 223 | console.log("Storage moved from Chrome sync to local."); 224 | chrome.storage.sync.set({ 225 | useSynchronizedStorage: newSyncSetting 226 | }, function() { 227 | if (chrome.runtime.lastError) { 228 | updateStatusText("Something went wrong when trying to save.", false); 229 | console.log("chrome.runtime.lastError: " + chrome.runtime.lastError); 230 | } 231 | else { 232 | lastSavedUseSynchronizedStorage = newSyncSetting; 233 | 234 | updateStatusText("Options saved. Please refresh any open imgur tabs.", true); 235 | } 236 | }); 237 | } 238 | moveRunning = false; 239 | }); 240 | }); 241 | } 242 | else { //Convert from local to synchronized. 243 | chrome.storage.local.get({ 244 | blockedUsers: new Array(), 245 | followedUsers: new Array(), 246 | favoriteComments: new Array(), 247 | favoritedImages: new Array(), 248 | favoritedImagesDirectories: new Array() 249 | }, function(items) { 250 | var favoritedImagesArray = items.favoritedImages; 251 | favoriteArrayMaxLength = 45; 252 | chrome.storage.sync.set({ 253 | blockedUsers: items.blockedUsers, 254 | followedUsers: items.followedUsers, 255 | favoriteComments: items.favoriteComments, 256 | favoritedImages: favoritedImagesArray.slice(0, favoriteArrayMaxLength), 257 | favoritedImages1: favoritedImagesArray.slice(favoriteArrayMaxLength , 2 * favoriteArrayMaxLength), 258 | favoritedImages2: favoritedImagesArray.slice(2 * favoriteArrayMaxLength , 3 * favoriteArrayMaxLength), 259 | favoritedImages3: favoritedImagesArray.slice(3 * favoriteArrayMaxLength , 4 * favoriteArrayMaxLength), 260 | favoritedImages4: favoritedImagesArray.slice(4 * favoriteArrayMaxLength , 5 * favoriteArrayMaxLength), 261 | favoritedImages5: favoritedImagesArray.slice(5 * favoriteArrayMaxLength , 6 * favoriteArrayMaxLength), 262 | favoritedImages6: favoritedImagesArray.slice(6 * favoriteArrayMaxLength , 7 * favoriteArrayMaxLength), 263 | favoritedImages7: favoritedImagesArray.slice(7 * favoriteArrayMaxLength , 8 * favoriteArrayMaxLength), 264 | favoritedImages8: favoritedImagesArray.slice(8 * favoriteArrayMaxLength , 9 * favoriteArrayMaxLength), 265 | favoritedImages9: favoritedImagesArray.slice(9 * favoriteArrayMaxLength , 10 * favoriteArrayMaxLength), 266 | favoritedImages10: favoritedImagesArray.slice(10 * favoriteArrayMaxLength , 11 * favoriteArrayMaxLength), 267 | favoritedImages11: favoritedImagesArray.slice(11 * favoriteArrayMaxLength , 12 * favoriteArrayMaxLength), 268 | favoritedImages12: favoritedImagesArray.slice(12 * favoriteArrayMaxLength , 13 * favoriteArrayMaxLength), 269 | favoritedImages13: favoritedImagesArray.slice(13 * favoriteArrayMaxLength , 14 * favoriteArrayMaxLength), 270 | favoritedImagesDirectories: items.favoritedImagesDirectories 271 | }, function() { 272 | if (chrome.runtime.lastError) { 273 | console.log("Failed to move storage from local to Chrome sync:" + chrome.runtime.lastError.message); 274 | } 275 | else { 276 | console.log("Storage moved from local to Chrome sync."); 277 | chrome.storage.sync.set({ 278 | useSynchronizedStorage: newSyncSetting 279 | }, function() { 280 | if (chrome.runtime.lastError) { 281 | updateStatusText("Something went wrong when trying to save.", false); 282 | console.log("chrome.runtime.lastError: " + chrome.runtime.lastError); 283 | } 284 | else { 285 | lastSavedUseSynchronizedStorage = newSyncSetting; 286 | 287 | updateStatusText("Options saved. Please refresh any open imgur tabs.", true); 288 | } 289 | }); 290 | } 291 | moveRunning = false; 292 | }); 293 | }); 294 | } 295 | } 296 | 297 | //populateBlockedUserList: Displays all the blocked users. 298 | function populateBlockedUserList() { 299 | var listHTML = ""; 300 | 301 | for (i = 0; i < blockedUserList.length; i++) 302 | listHTML += '' + blockedUserList[i] + ''; 303 | 304 | document.getElementById("blockedUserTable").innerHTML = listHTML; 305 | 306 | for (i = 0; i < blockedUserList.length; i++) { 307 | document.getElementById("remove" + i).addEventListener("click", unblockUser); 308 | } 309 | 310 | } 311 | 312 | //populateFollowedUserList: Displays all the followed users. 313 | function populateFollowedUserList() { 314 | var listHTML = ""; 315 | 316 | for (i = 0; i < followedUserList.length; i++) 317 | listHTML += '' + followedUserList[i] + ''; 318 | 319 | document.getElementById("followedUserTable").innerHTML = listHTML; 320 | 321 | for (i = 0; i < followedUserList.length; i++) { 322 | document.getElementById("removeFollow" + i).addEventListener("click", unfollowUser); 323 | } 324 | } 325 | 326 | //populateListsAndSetReady: Calls the functions to display blocked and followed users, shows the mainDiv. 327 | function populateListsAndSetReady(blockedUsers, followedUsers) { 328 | blockedUserList = blockedUsers; 329 | populateBlockedUserList(); 330 | followedUserList = followedUsers; 331 | populateFollowedUserList(); 332 | 333 | document.getElementById('mainDiv').style.display = "inline"; 334 | document.getElementById('loadingDiv').style.display = "none"; 335 | } 336 | 337 | //unblockUser: Removes a user from the blocked users list. 338 | function unblockUser() { 339 | var userName = this.getAttribute("userName"); 340 | console.log("unblocking " + userName); 341 | 342 | if (lastSavedUseSynchronizedStorage) { 343 | chrome.storage.sync.get({ 344 | //Set defaults. 345 | blockedUsers: new Array() 346 | }, function(items) { 347 | blockedUserList = items.blockedUsers; 348 | unblockUserHelper(userName); 349 | }); 350 | } 351 | else { 352 | chrome.storage.local.get({ 353 | //Set defaults. 354 | blockedUsers: new Array() 355 | }, function(items) { 356 | blockedUserList = items.blockedUsers; 357 | unblockUserHelper(userName); 358 | }); 359 | } 360 | } 361 | 362 | function unblockUserHelper(userName) { 363 | var index = blockedUserList.indexOf(userName); 364 | blockedUserList.splice(index, 1); 365 | 366 | console.log("Still blocked: " + blockedUserList.toString()); 367 | 368 | if (lastSavedUseSynchronizedStorage) { 369 | chrome.storage.sync.set({ 370 | blockedUsers: blockedUserList 371 | }, function() { 372 | populateBlockedUserList(); 373 | }); 374 | } 375 | else { 376 | chrome.storage.local.set({ 377 | blockedUsers: blockedUserList 378 | }, function() { 379 | populateBlockedUserList(); 380 | }); 381 | } 382 | } 383 | 384 | //unfollowUser: Removes a user from the followed users list. 385 | function unfollowUser() { 386 | var userName = this.getAttribute("userName"); 387 | console.log("unfollowing " + userName); 388 | 389 | if (lastSavedUseSynchronizedStorage) { 390 | chrome.storage.sync.get({ 391 | //Set defaults. 392 | followedUsers: new Array() 393 | }, function(items) { 394 | followedUserList = items.followedUsers; 395 | unfollowUserHelper(userName); 396 | }); 397 | } 398 | else { 399 | chrome.storage.local.get({ 400 | //Set defaults. 401 | followedUsers: new Array() 402 | }, function(items) { 403 | followedUserList = items.followedUsers; 404 | unfollowUserHelper(userName); 405 | }); 406 | } 407 | } 408 | 409 | function unfollowUserHelper(userName) { 410 | var index = followedUserList.indexOf(userName); 411 | followedUserList.splice(index, 1); 412 | 413 | console.log("Still followed: " + followedUserList.toString()); 414 | 415 | if (lastSavedUseSynchronizedStorage) { 416 | chrome.storage.sync.set({ 417 | followedUsers: followedUserList 418 | }, function() { 419 | populateFollowedUserList(); 420 | }); 421 | } 422 | else { 423 | chrome.storage.local.set({ 424 | followedUsers: followedUserList 425 | }, function() { 426 | populateFollowedUserList(); 427 | }); 428 | } 429 | } 430 | 431 | function updateStatusText(text, saveSuccessful) { 432 | // Update status to let user know options were saved. 433 | var status = document.getElementById('status'); 434 | status.textContent = text; 435 | 436 | if (saveSuccessful) 437 | status.setAttribute("style", "color:black;"); 438 | else 439 | status.setAttribute("style", "color:red;"); 440 | 441 | setTimeout(function() { 442 | status.textContent = ''; 443 | }, 3000); 444 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /pages/bookmarkedPosts.js: -------------------------------------------------------------------------------- 1 | var favoritedImagesArray = new Array(); 2 | var favoritedImagesDirectoriesArray = new Array(); 3 | var currentDirName; 4 | var favoriteArrayMaxLength = 45; 5 | var dirDivPos; 6 | var imgDeletionConfirmation = true; 7 | var selectedPosts = new Array(), lastClickedPostID = ""; 8 | 9 | document.addEventListener('DOMContentLoaded', restore_options); 10 | document.getElementById('newDirectoryButton').addEventListener('click', createNewDirectory); 11 | document.getElementById('syncButton').addEventListener('click', goToFavorites); 12 | document.getElementById('requireDeleteConfirm').addEventListener('click', updateImgDeletionConfirmation); 13 | 14 | $(window).scroll(function() { 15 | if (dirDivPos === undefined) { 16 | console.log ("dirDivPos undefined"); 17 | return; 18 | } 19 | if($(window).scrollTop() > dirDivPos.top) 20 | $('#directoriesDiv').css('position','fixed').css('top','0').css('left','50%').css('marginLeft','-500px'); 21 | else 22 | $('#directoriesDiv').css('position','static').css('left','').css('marginLeft',''); 23 | }); 24 | 25 | $(function() { //keyup listener 26 | $(window).keyup(function(e) { 27 | if(e.which == 46) { //Delete key 28 | if (selectedPosts.length < 1) 29 | return; 30 | 31 | var ask = confirm('Do you really wish to delete the ' + selectedPosts.length + ' selected posts?'); 32 | if(ask) { 33 | /*for (i = 0; i < selectedPosts.length; i++) 34 | deleteImg(selectedPosts[i], false);*/ 35 | 36 | deleteImg(selectedPosts); 37 | 38 | } 39 | 40 | } 41 | 42 | }); 43 | }); 44 | 45 | // Loads options from chrome.storage 46 | function restore_options() { 47 | chrome.storage.sync.get({ 48 | useSynchronizedStorage: false 49 | }, function(items) { 50 | if (items.useSynchronizedStorage) { //If using Chrome sync for storage is enabled... 51 | chrome.storage.sync.get({ 52 | // Set defaults. 53 | favoritedImages: new Array(), 54 | favoritedImages1: new Array(), 55 | favoritedImages2: new Array(), 56 | favoritedImages3: new Array(), 57 | favoritedImages4: new Array(), 58 | favoritedImages5: new Array(), 59 | favoritedImages6: new Array(), 60 | favoritedImages7: new Array(), 61 | favoritedImages8: new Array(), 62 | favoritedImages9: new Array(), 63 | favoritedImages10: new Array(), 64 | favoritedImages11: new Array(), 65 | favoritedImages12: new Array(), 66 | favoritedImages13: new Array(), 67 | favoritedImagesDirectories: new Array() 68 | }, function(items) { 69 | chrome.storage.sync.getBytesInUse(null, function(bytesInUse) { 70 | var percentInUse = bytesInUse/chrome.storage.sync.QUOTA_BYTES; 71 | 72 | console.log("chrome.storage.sync bytesInUse: " + bytesInUse +". (" + Math.round(percentInUse * 100) + "% of total)"); 73 | }); 74 | chrome.storage.sync.getBytesInUse("favoritedImages", function(bytesInUse) { console.log("favoritedImages bytesInUse: " + bytesInUse); }); 75 | chrome.storage.sync.getBytesInUse("favoritedImages1", function(bytesInUse) { console.log("favoritedImages1 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages1.length); }); 76 | chrome.storage.sync.getBytesInUse("favoritedImages2", function(bytesInUse) { console.log("favoritedImages2 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages2.length); }); 77 | chrome.storage.sync.getBytesInUse("favoritedImages3", function(bytesInUse) { console.log("favoritedImages3 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages3.length); }); 78 | chrome.storage.sync.getBytesInUse("favoritedImages4", function(bytesInUse) { console.log("favoritedImages4 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages4.length); }); 79 | chrome.storage.sync.getBytesInUse("favoritedImages5", function(bytesInUse) { console.log("favoritedImages5 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages5.length); }); 80 | chrome.storage.sync.getBytesInUse("favoritedImages6", function(bytesInUse) { console.log("favoritedImages6 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages6.length); }); 81 | chrome.storage.sync.getBytesInUse("favoritedImages7", function(bytesInUse) { console.log("favoritedImages7 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages7.length); }); 82 | chrome.storage.sync.getBytesInUse("favoritedImages8", function(bytesInUse) { console.log("favoritedImages8 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages8.length); }); 83 | chrome.storage.sync.getBytesInUse("favoritedImages9", function(bytesInUse) { console.log("favoritedImages9 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages9.length); }); 84 | chrome.storage.sync.getBytesInUse("favoritedImages10", function(bytesInUse) { console.log("favoritedImages10 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages10.length); }); 85 | chrome.storage.sync.getBytesInUse("favoritedImages11", function(bytesInUse) { console.log("favoritedImages11 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages11.length); }); 86 | chrome.storage.sync.getBytesInUse("favoritedImages12", function(bytesInUse) { console.log("favoritedImages12 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages12.length); }); 87 | chrome.storage.sync.getBytesInUse("favoritedImages13", function(bytesInUse) { console.log("favoritedImages13 bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages13.length); }); 88 | 89 | favoritedImagesArray = items.favoritedImages; 90 | if (items.favoritedImages1.length > 0) 91 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages1); 92 | if (items.favoritedImages2.length > 0) 93 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages2); 94 | if (items.favoritedImages3.length > 0) 95 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages3); 96 | if (items.favoritedImages4.length > 0) 97 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages4); 98 | if (items.favoritedImages5.length > 0) 99 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages5); 100 | if (items.favoritedImages6.length > 0) 101 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages6); 102 | if (items.favoritedImages7.length > 0) 103 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages7); 104 | if (items.favoritedImages8.length > 0) 105 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages8); 106 | if (items.favoritedImages9.length > 0) 107 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages9); 108 | if (items.favoritedImages10.length > 0) 109 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages10); 110 | if (items.favoritedImages11.length > 0) 111 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages11); 112 | if (items.favoritedImages12.length > 0) 113 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages12); 114 | if (items.favoritedImages13.length > 0) 115 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages13); 116 | 117 | favoritedImagesDirectoriesArray = items.favoritedImagesDirectories; 118 | 119 | console.log("favoritedImagesArray.length: " + favoritedImagesArray.length); 120 | main(); 121 | }); 122 | } 123 | else { 124 | chrome.storage.local.get({ 125 | // Set defaults. 126 | favoritedImages: new Array(), 127 | favoritedImagesDirectories: new Array() 128 | }, function(items) { 129 | chrome.storage.local.getBytesInUse(null, function(bytesInUse) { 130 | var percentInUse = bytesInUse/chrome.storage.local.QUOTA_BYTES; 131 | 132 | console.log("chrome.storage.local bytesInUse: " + bytesInUse +". (" + Math.round(percentInUse * 100) + "% of total)"); 133 | }); 134 | chrome.storage.sync.getBytesInUse("favoritedImages", function(bytesInUse) { console.log("favoritedImages bytesInUse: " + bytesInUse + ". length: " + items.favoritedImages.length); }); 135 | 136 | favoritedImagesArray = items.favoritedImages; 137 | favoritedImagesDirectoriesArray = items.favoritedImagesDirectories; 138 | 139 | main(); 140 | }); 141 | } 142 | }); 143 | } 144 | 145 | function main() { 146 | /*for (i = 0; i < favoritedImagesArray.length; i++) { 147 | if (favoritedImagesArray[i] != null) 148 | console.log("favoritedImagesArray has id: " + favoritedImagesArray[i].id); 149 | }*/ 150 | 151 | setCurrentDirName(); 152 | updateCurrentDirectoryHeader(); 153 | populateDirectories(); 154 | populateImages(); 155 | initializePostPreview(); 156 | 157 | document.getElementById("requireDeleteConfirm").checked = imgDeletionConfirmation; 158 | 159 | document.getElementById('mainDiv').style.display = "inline"; 160 | document.getElementById('loadingDiv').style.display = "none"; 161 | 162 | dirDivPos = $('#directoriesDiv').offset(); 163 | } 164 | 165 | function allowDrop(ev) { 166 | ev.preventDefault(); 167 | } 168 | 169 | function createNewDirectory() { 170 | var newDirectoryName = document.getElementById("newDirectoryName").value; 171 | 172 | if (newDirectoryName.length <= 0) { 173 | document.getElementById("newDirectoryError").innerHTML = "Please enter a folder name."; 174 | return; 175 | } 176 | 177 | cleanedDirectoryName = newDirectoryName.replace(/[^a-zA-Z0-9-_]/g, ''); 178 | 179 | if (newDirectoryName.length != cleanedDirectoryName.length) { 180 | document.getElementById("newDirectoryError").innerHTML = "Please enter a valid folder name. (No special characters or spaces.)"; 181 | return; 182 | } 183 | 184 | for (i = 0; i < favoritedImagesDirectoriesArray.length; i++) { 185 | if (newDirectoryName == favoritedImagesDirectoriesArray[i]) { 186 | document.getElementById("newDirectoryError").innerHTML = "Folder already exists."; 187 | return; 188 | } 189 | } 190 | 191 | if (newDirectoryName == "root") { 192 | document.getElementById("newDirectoryError").innerHTML = "You can't use that folder name."; 193 | return; 194 | } 195 | 196 | favoritedImagesDirectoriesArray.push(newDirectoryName); 197 | favoritedImagesDirectoriesArray.sort(); 198 | 199 | chrome.storage.sync.get({ 200 | useSynchronizedStorage: false 201 | }, function(items) { 202 | if (items.useSynchronizedStorage) { //If using Chrome sync for storage is enabled... 203 | chrome.storage.sync.set({ 204 | favoritedImagesDirectories: favoritedImagesDirectoriesArray 205 | }, function() { 206 | document.getElementById("newDirectoryName").value = ""; 207 | document.getElementById("newDirectoryError").innerHTML = ""; 208 | populateDirectories(); 209 | }); 210 | } 211 | else { 212 | chrome.storage.local.set({ 213 | favoritedImagesDirectories: favoritedImagesDirectoriesArray 214 | }, function() { 215 | document.getElementById("newDirectoryName").value = ""; 216 | document.getElementById("newDirectoryError").innerHTML = ""; 217 | populateDirectories(); 218 | }); 219 | } 220 | }); 221 | } 222 | 223 | function deleteCurrentDirectory() { 224 | if (currentDirName == "root") { 225 | document.getElementById("deleteCurrentDirectoryError").innerHTML = "You can't delete the root folder."; 226 | return; 227 | } 228 | 229 | var isEmpty = true; 230 | for (i = 0; i < favoritedImagesArray.length; i++) { 231 | if (favoritedImagesArray[i].directory == currentDirName) { 232 | isEmpty = false; 233 | break; 234 | } 235 | } 236 | 237 | if (!isEmpty) { 238 | document.getElementById("deleteCurrentDirectoryError").innerHTML = "The folder must be empty before you can delete it."; 239 | return; 240 | } 241 | 242 | var dirIndex = -1; 243 | for (i = 0; i < favoritedImagesDirectoriesArray.length; i++) { 244 | if (currentDirName == favoritedImagesDirectoriesArray[i]) { 245 | dirIndex = i; 246 | break; 247 | } 248 | } 249 | 250 | if (dirIndex == -1) { 251 | document.getElementById("deleteCurrentDirectoryError").innerHTML = "Folder not found."; 252 | } 253 | else { 254 | favoritedImagesDirectoriesArray.splice(dirIndex, 1); 255 | 256 | chrome.storage.sync.get({ 257 | useSynchronizedStorage: false 258 | }, function(items) { 259 | if (items.useSynchronizedStorage) { //If using Chrome sync for storage is enabled... 260 | chrome.storage.sync.set({ 261 | favoritedImagesDirectories: favoritedImagesDirectoriesArray 262 | }, function() { 263 | chrome.tabs.getSelected(null,function(tab) { 264 | chrome.tabs.update(tab.id, { url: "chrome-extension://" + chrome.runtime.id + "/pages/bookmarkedPosts.html" }); 265 | }); 266 | }); 267 | } 268 | else { 269 | chrome.storage.local.set({ 270 | favoritedImagesDirectories: favoritedImagesDirectoriesArray 271 | }, function() { 272 | chrome.tabs.getSelected(null,function(tab) { 273 | chrome.tabs.update(tab.id, { url: "chrome-extension://" + chrome.runtime.id + "/pages/bookmarkedPosts.html" }); 274 | }); 275 | }); 276 | } 277 | }); 278 | 279 | } 280 | } 281 | 282 | function deleteImgClick() { 283 | if (imgDeletionConfirmation) { 284 | var ask = confirm('Do you really wish to delete this image?'); 285 | if(ask) 286 | deleteImg(this.parentNode.parentNode.firstChild.getAttribute("id")); 287 | } 288 | else 289 | deleteImg(this.parentNode.parentNode.firstChild.getAttribute("id")); 290 | } 291 | 292 | function deleteImg(toDelete) { 293 | if (toDelete.constructor === Array) { 294 | for (i = 0; i < toDelete.length; i++) { 295 | for (j = 0; j < favoritedImagesArray.length; j++) { 296 | if (toDelete[i] == favoritedImagesArray[j].id) { 297 | favoritedImagesArray.splice(j, 1); 298 | break; 299 | } 300 | } 301 | } 302 | } 303 | else if (typeof toDelete == "string"){ 304 | for (i = 0; i < favoritedImagesArray.length; i++) { 305 | if (toDelete == favoritedImagesArray[i].id) { 306 | favoritedImagesArray.splice(i, 1); 307 | break; 308 | } 309 | } 310 | } 311 | else { 312 | console.log(typeof toDelete); 313 | return; 314 | } 315 | 316 | chrome.storage.sync.get({ 317 | useSynchronizedStorage: false 318 | }, function(items) { 319 | if (items.useSynchronizedStorage) { //If using Chrome sync for storage is enabled... 320 | chrome.storage.sync.set({ 321 | favoritedImages: favoritedImagesArray.slice(0, favoriteArrayMaxLength), 322 | favoritedImages1: favoritedImagesArray.slice(favoriteArrayMaxLength , 2 * favoriteArrayMaxLength), 323 | favoritedImages2: favoritedImagesArray.slice(2 * favoriteArrayMaxLength , 3 * favoriteArrayMaxLength), 324 | favoritedImages3: favoritedImagesArray.slice(3 * favoriteArrayMaxLength , 4 * favoriteArrayMaxLength), 325 | favoritedImages4: favoritedImagesArray.slice(4 * favoriteArrayMaxLength , 5 * favoriteArrayMaxLength), 326 | favoritedImages5: favoritedImagesArray.slice(5 * favoriteArrayMaxLength , 6 * favoriteArrayMaxLength), 327 | favoritedImages6: favoritedImagesArray.slice(6 * favoriteArrayMaxLength , 7 * favoriteArrayMaxLength), 328 | favoritedImages7: favoritedImagesArray.slice(7 * favoriteArrayMaxLength , 8 * favoriteArrayMaxLength), 329 | favoritedImages8: favoritedImagesArray.slice(8 * favoriteArrayMaxLength , 9 * favoriteArrayMaxLength), 330 | favoritedImages9: favoritedImagesArray.slice(9 * favoriteArrayMaxLength , 10 * favoriteArrayMaxLength), 331 | favoritedImages10: favoritedImagesArray.slice(10 * favoriteArrayMaxLength , 11 * favoriteArrayMaxLength), 332 | favoritedImages11: favoritedImagesArray.slice(11 * favoriteArrayMaxLength , 12 * favoriteArrayMaxLength), 333 | favoritedImages12: favoritedImagesArray.slice(12 * favoriteArrayMaxLength , 13 * favoriteArrayMaxLength), 334 | favoritedImages13: favoritedImagesArray.slice(13 * favoriteArrayMaxLength , 14 * favoriteArrayMaxLength) 335 | }, function() { 336 | populateImages(); 337 | }); 338 | } 339 | else { 340 | chrome.storage.local.set({ 341 | favoritedImages: favoritedImagesArray 342 | }, function() { 343 | populateImages(); 344 | }); 345 | } 346 | }); 347 | } 348 | 349 | function drag(ev) { 350 | ev.dataTransfer.setData("text", ev.target.id); 351 | } 352 | 353 | function drop(ev) { 354 | ev.preventDefault(); 355 | var id = ev.dataTransfer.getData("text"); 356 | console.log(id + " ::: " + ev.target.innerHTML); 357 | 358 | var movedPosts = new Array(); 359 | movedPosts.push(id); 360 | 361 | if (selectedPosts.length > 0) { 362 | if (selectedPosts.indexOf(id) > -1) //The the post being dragged is selected: unselect it. 363 | selectedPosts.splice(selectedPosts.indexOf(id), 1); 364 | 365 | for (i = 0; i < selectedPosts.length; i++) //Add every selected post to movedPosts. 366 | movedPosts.push(selectedPosts[i]); 367 | } 368 | 369 | chrome.storage.sync.get({ 370 | useSynchronizedStorage: false 371 | }, function(items) { 372 | if (items.useSynchronizedStorage) { //If using Chrome sync for storage is enabled... 373 | chrome.storage.sync.get({ 374 | // Set defaults. 375 | favoritedImages: new Array(), 376 | favoritedImages1: new Array(), 377 | favoritedImages2: new Array(), 378 | favoritedImages3: new Array(), 379 | favoritedImages4: new Array(), 380 | favoritedImages5: new Array(), 381 | favoritedImages6: new Array(), 382 | favoritedImages7: new Array(), 383 | favoritedImages8: new Array(), 384 | favoritedImages9: new Array(), 385 | favoritedImages10: new Array(), 386 | favoritedImages11: new Array(), 387 | favoritedImages12: new Array(), 388 | favoritedImages13: new Array() 389 | }, function(items) { 390 | favoritedImagesArray = items.favoritedImages; 391 | if (items.favoritedImages1.length > 0) 392 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages1); 393 | if (items.favoritedImages2.length > 0) 394 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages2); 395 | if (items.favoritedImages3.length > 0) 396 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages3); 397 | if (items.favoritedImages4.length > 0) 398 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages4); 399 | if (items.favoritedImages5.length > 0) 400 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages5); 401 | if (items.favoritedImages6.length > 0) 402 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages6); 403 | if (items.favoritedImages7.length > 0) 404 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages7); 405 | if (items.favoritedImages8.length > 0) 406 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages8); 407 | if (items.favoritedImages9.length > 0) 408 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages9); 409 | if (items.favoritedImages9.length > 0) 410 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages9); 411 | if (items.favoritedImages10.length > 0) 412 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages10); 413 | if (items.favoritedImages11.length > 0) 414 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages11); 415 | if (items.favoritedImages12.length > 0) 416 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages12); 417 | if (items.favoritedImages13.length > 0) 418 | favoritedImagesArray.push.apply(favoritedImagesArray, items.favoritedImages13); 419 | 420 | for (i = 0; i < movedPosts.length; i++) { 421 | for (j = 0; j < favoritedImagesArray.length; j++) { 422 | if (movedPosts[i] == favoritedImagesArray[j].id) { 423 | favoritedImagesArray[j].directory = ev.target.innerHTML; 424 | break; 425 | } 426 | } 427 | } 428 | 429 | chrome.storage.sync.set({ 430 | favoritedImages: favoritedImagesArray.slice(0, favoriteArrayMaxLength), 431 | favoritedImages1: favoritedImagesArray.slice(favoriteArrayMaxLength , 2 * favoriteArrayMaxLength), 432 | favoritedImages2: favoritedImagesArray.slice(2 * favoriteArrayMaxLength , 3 * favoriteArrayMaxLength), 433 | favoritedImages3: favoritedImagesArray.slice(3 * favoriteArrayMaxLength , 4 * favoriteArrayMaxLength), 434 | favoritedImages4: favoritedImagesArray.slice(4 * favoriteArrayMaxLength , 5 * favoriteArrayMaxLength), 435 | favoritedImages5: favoritedImagesArray.slice(5 * favoriteArrayMaxLength , 6 * favoriteArrayMaxLength), 436 | favoritedImages6: favoritedImagesArray.slice(6 * favoriteArrayMaxLength , 7 * favoriteArrayMaxLength), 437 | favoritedImages7: favoritedImagesArray.slice(7 * favoriteArrayMaxLength , 8 * favoriteArrayMaxLength), 438 | favoritedImages8: favoritedImagesArray.slice(8 * favoriteArrayMaxLength , 9 * favoriteArrayMaxLength), 439 | favoritedImages9: favoritedImagesArray.slice(9 * favoriteArrayMaxLength , 10 * favoriteArrayMaxLength), 440 | favoritedImages10: favoritedImagesArray.slice(10 * favoriteArrayMaxLength , 11 * favoriteArrayMaxLength), 441 | favoritedImages11: favoritedImagesArray.slice(11 * favoriteArrayMaxLength , 12 * favoriteArrayMaxLength), 442 | favoritedImages12: favoritedImagesArray.slice(12 * favoriteArrayMaxLength , 13 * favoriteArrayMaxLength), 443 | favoritedImages13: favoritedImagesArray.slice(13 * favoriteArrayMaxLength , 14 * favoriteArrayMaxLength) 444 | }, function() { 445 | //window.location.reload(); 446 | populateImages(); 447 | }); 448 | }); 449 | } 450 | else { 451 | chrome.storage.local.get({ 452 | // Set defaults. 453 | favoritedImages: new Array() 454 | }, function(items) { 455 | favoritedImagesArray = items.favoritedImages; 456 | 457 | for (i = 0; i < movedPosts.length; i++) { 458 | for (j = 0; j < favoritedImagesArray.length; j++) { 459 | if (movedPosts[i] == favoritedImagesArray[j].id) { 460 | favoritedImagesArray[j].directory = ev.target.innerHTML; 461 | break; 462 | } 463 | } 464 | } 465 | 466 | chrome.storage.local.set({ 467 | favoritedImages: favoritedImagesArray 468 | }, function() { 469 | //window.location.reload(); 470 | populateImages(); 471 | }); 472 | }); 473 | } 474 | }); 475 | } 476 | 477 | function goToDirectory() { 478 | var dirName = this.innerHTML; 479 | var href = "chrome-extension://" + chrome.runtime.id + "/pages/bookmarkedPosts.html"; 480 | 481 | if (dirName != "root") 482 | href += "?" + dirName; 483 | 484 | chrome.tabs.getSelected(null,function(tab) { 485 | chrome.tabs.update(tab.id, { url: href }); 486 | }); 487 | } 488 | 489 | function goToFavorites() { 490 | chrome.tabs.getSelected(null,function(tab) { 491 | chrome.tabs.update(tab.id, { url: "http://imgur.com/account/favorites" }); 492 | }); 493 | } 494 | 495 | function goToPost() { 496 | chrome.tabs.create({ 'url': "http://imgur.com/account/favorites/" + this.getAttribute("postID") }); 497 | } 498 | 499 | function highlightSelectedPosts() { 500 | var favImgElements = document.getElementsByClassName("favoriteImage"); 501 | 502 | for (i = 0; i < favImgElements.length; i++) { 503 | if (selectedPosts.indexOf(favImgElements[i].getAttribute("id")) > -1) 504 | $(favImgElements[i]).css("border", "2px solid #ffd700"); 505 | else 506 | $(favImgElements[i]).css("border", "2px solid #434343"); 507 | } 508 | 509 | } 510 | 511 | function populateDirectories() { 512 | var tableHTML = 'Folders'; 513 | tableHTML += 'root'; 514 | var colMax = 8; 515 | var colCount = 1; 516 | for (i = 0; i < favoritedImagesDirectoriesArray.length; i++) { 517 | if (favoritedImagesDirectoriesArray[i] == "root") continue; 518 | if (colCount == colMax){ 519 | tableHTML += ''; 520 | colCount = 0; 521 | } 522 | 523 | if (colCount == 0) 524 | tableHTML += ''; 525 | 526 | tableHTML += '' + favoritedImagesDirectoriesArray[i] + ''; 527 | colCount++; 528 | } 529 | tableHTML += ''; 530 | 531 | document.getElementById("directoriesTable").innerHTML = tableHTML; 532 | 533 | var goToDirectoryButtons = document.getElementsByClassName("goToDirectory"); 534 | for (i = 0; i < goToDirectoryButtons.length; i++) { 535 | goToDirectoryButtons[i].addEventListener("click", goToDirectory); 536 | goToDirectoryButtons[i].addEventListener("dragover", function(event) { allowDrop(event); }); 537 | goToDirectoryButtons[i].addEventListener("drop", function(event) { drop(event); }); 538 | } 539 | 540 | } 541 | 542 | function populateImages() { 543 | var postCount = 0; 544 | 545 | $('.imgDiv').remove(); 546 | selectedPosts = new Array(); 547 | document.getElementById("selectedPostCount").innerHTML = "Currently Selected Posts: " + selectedPosts.length; 548 | 549 | 550 | var colCount = 0; 551 | for (i = 0; i < favoritedImagesArray.length; i++) { 552 | if (favoritedImagesArray[i] == null) { 553 | // TODO: Tell them how to submit a bug report. 554 | console.log("favoritedImagesArray[" + i + "] was null. Please submit a bug report with this information."); 555 | continue; 556 | } 557 | if (favoritedImagesArray[i].directory == currentDirName) { 558 | var imgDiv = document.createElement("div"); 559 | imgDiv.setAttribute("class", "imgDiv"); 560 | if (colCount == 4) { 561 | imgDiv.setAttribute("style", "padding-bottom:14.5px;float:left;"); 562 | colCount = 0; 563 | } 564 | else { 565 | imgDiv.setAttribute("style", "padding-bottom:14.5px;padding-right:9.5px;float:left;"); 566 | colCount++; 567 | } 568 | 569 | var img = document.createElement("img"); 570 | img.setAttribute("style", "width:180px;height:180px;"); 571 | 572 | if (favoritedImagesArray[i].imgSrc.indexOf("http://i.imgur.com") > -1) //For images synced with extension versions < 0.3.3 573 | img.setAttribute("src", favoritedImagesArray[i].imgSrc); 574 | else 575 | img.setAttribute("src", "http://i.imgur.com/" + favoritedImagesArray[i].imgSrc + ".jpg"); 576 | img.setAttribute("id", favoritedImagesArray[i].id); 577 | 578 | if (favoritedImagesArray[i].title.length < 30) 579 | img.setAttribute("title", favoritedImagesArray[i].title); 580 | else 581 | img.setAttribute("title", favoritedImagesArray[i].title + "..."); 582 | 583 | img.setAttribute("class", "favoriteImage"); 584 | img.setAttribute("draggable", "true"); 585 | 586 | var imgControlsDiv = document.createElement("div"); 587 | imgControlsDiv.setAttribute("style", "text-align: center;") 588 | var viewImgSpan = document.createElement("span"); 589 | viewImgSpan.setAttribute("class", "viewImg"); 590 | viewImgSpan.setAttribute("style", "margin-right:10px;"); 591 | viewImgSpan.setAttribute("postID", favoritedImagesArray[i].id); 592 | viewImgSpan.innerHTML = "View"; 593 | viewImgSpan.addEventListener("click", goToPost); 594 | var deleteImgSpan = document.createElement("span"); 595 | deleteImgSpan.setAttribute("class", "deleteImg"); 596 | deleteImgSpan.innerHTML = "Delete"; 597 | 598 | imgControlsDiv.appendChild(viewImgSpan); 599 | imgControlsDiv.appendChild(deleteImgSpan); 600 | 601 | imgDiv.appendChild(img); 602 | imgDiv.appendChild(imgControlsDiv); 603 | 604 | var placementElement = document.getElementById("imagesDiv"); 605 | placementElement.appendChild(imgDiv); 606 | 607 | postCount++; 608 | } 609 | 610 | document.getElementById("currentDirectoryPostCount").innerHTML = "Images: " + postCount; 611 | } 612 | 613 | var favImgs = document.getElementsByClassName("favoriteImage"); 614 | for (i = 0; i < favImgs.length; i++) { 615 | favImgs[i].addEventListener("click", function(event) { postClicked(event, this.getAttribute("id")); }); 616 | favImgs[i].addEventListener("dragstart", drag); 617 | } 618 | 619 | var deleteImgs = document.getElementsByClassName("deleteImg"); 620 | for (i = 0; i < deleteImgs.length; i++) { 621 | deleteImgs[i].addEventListener("click", deleteImgClick); 622 | } 623 | } 624 | 625 | function postClicked(ev, postID) { 626 | if (ev.ctrlKey) { //If the control key is being held: ... 627 | if (selectedPosts.indexOf(postID) > -1) //If the post is already selected: unselect it. 628 | selectedPosts.splice(selectedPosts.indexOf(postID), 1); 629 | else //If the post is not selected: select it. 630 | selectedPosts.push(postID); 631 | 632 | lastClickedPostID = postID; 633 | } 634 | else if (ev.shiftKey) { 635 | selectedPosts = new Array(); 636 | var favImgElements = document.getElementsByClassName("favoriteImage"); 637 | 638 | 639 | var lastClickedPostIndex, postIndex; 640 | for (i = 0; i < favImgElements.length; i++) { 641 | if (favImgElements[i].getAttribute("id") == lastClickedPostID) 642 | lastClickedPostIndex = i; 643 | if (favImgElements[i].getAttribute("id") == postID) 644 | postIndex = i; 645 | 646 | } 647 | 648 | var startID, endID; 649 | if (lastClickedPostIndex < postIndex) { 650 | startID = lastClickedPostID; 651 | endID = postID; 652 | } 653 | else { 654 | startID = postID; 655 | endID = lastClickedPostID; 656 | } 657 | 658 | var addToSelected = false; 659 | for (i = 0; i < favImgElements.length; i++) { 660 | if (favImgElements[i].getAttribute("id") == startID) 661 | addToSelected = true; 662 | 663 | if (addToSelected) 664 | selectedPosts.push(favImgElements[i].getAttribute("id")); 665 | 666 | if (favImgElements[i].getAttribute("id") == endID) 667 | addToSelected = false; 668 | } 669 | } 670 | else { //Else: Make the clicked post the only selected post. 671 | selectedPosts = new Array(); 672 | selectedPosts.push(postID); 673 | lastClickedPostID = postID; 674 | } 675 | 676 | highlightSelectedPosts(); 677 | document.getElementById("selectedPostCount").innerHTML = "Currently Selected Posts: " + selectedPosts.length; 678 | } 679 | 680 | function setCurrentDirName() { 681 | if (window.location.href.lastIndexOf("?") == -1) 682 | currentDirName = ""; 683 | else 684 | currentDirName = window.location.href.substring(window.location.href.lastIndexOf("?") + 1, window.location.href.length); 685 | 686 | if (currentDirName === undefined || currentDirName.length == 0) 687 | currentDirName = "root"; 688 | } 689 | 690 | function updateCurrentDirectoryHeader() { 691 | document.getElementById("currentDirectoryHeader").innerHTML = "Folder: " + currentDirName; 692 | 693 | if (currentDirName != "root") { 694 | var deleteCurrentDirectorySpan = document.getElementById("deleteCurrentDirectory"); 695 | deleteCurrentDirectorySpan.innerHTML = "(Click here to delete this folder.)"; 696 | deleteCurrentDirectorySpan.addEventListener('click', deleteCurrentDirectory); 697 | } 698 | } 699 | 700 | function updateImgDeletionConfirmation() { 701 | imgDeletionConfirmation = document.getElementById("requireDeleteConfirm").checked; 702 | } -------------------------------------------------------------------------------- /contentScripts/imgurContent.js: -------------------------------------------------------------------------------- 1 | //Check if the page is an "over capacity" error page. 2 | $('body').ready(function() { 3 | var h1Elements = document.getElementsByTagName("h1"); 4 | 5 | for (i = 0; i < h1Elements.length; i++) { 6 | if (h1Elements[i].innerHTML == "Imgur is over capacity!") 7 | return; 8 | } 9 | 10 | imgurContentMain(); 11 | }); 12 | 13 | var skipPromoted, closeTopBar, removeViaMobileSpans, canSlideShow, slideShowTime, blockedUserList, followedUserList, favoriteCommentList; 14 | var notifyOnSpecialUsers, notifyOnTollski, markIconsViewed, skipViewed, viewedPostsArray; 15 | var blockReddit, blockedKeywordsArray, blockedSubredditsArray 16 | var postUser, postID; 17 | var rightTrueLeftFalse = true; 18 | var lastCommentUpdateTime = 0, lastCommentUpdateSkipped = false; 19 | var slideShowInterval, slideShowRunning = false, slideShowPaused = false, slideShowSecondsRemaining; 20 | var isFirstPostAfterPageLoad; 21 | var clickingBecauseSkipping = false; 22 | 23 | //Create a MutationObserver to check for changes on the page. 24 | var mutationObserver = new MutationObserver( function(mutations) { 25 | for(var i = 0; i < mutations.length; i++){ 26 | var mut = mutations[i]; 27 | for(var j=0; j < mut.addedNodes.length; ++j){ 28 | //console.log(mut.addedNodes[j].className + " ::: " + mut.addedNodes[j].nodeName); 29 | if(mut.addedNodes[j].className === undefined) continue; 30 | else if(mut.addedNodes[j].className.indexOf("humanMsg") >-1 ) { 31 | if (isFirstPostAfterPageLoad) 32 | isFirstPostAfterPageLoad = false; 33 | setTimeout(function() { 34 | onNewPost(); 35 | }, 10); 36 | //The following node classNames all change once per new post: humanMsg, point-info left bold, views-info left 37 | } 38 | else if((mut.addedNodes[j].className.indexOf("comment") > -1 || mut.addedNodes[j].className.indexOf("children") > -1) && mut.addedNodes[j].className != "favorite-comment") 39 | onCommentsLoaded(); 40 | } 41 | } 42 | } ); 43 | mutationObserver.observe(document, { subtree: true, childList: true }); 44 | 45 | //Add an event listener so that our "block user" and "follow user" buttons can communicate with us. **Old method of listening, may change to add click event listener to the buttons directly.** 46 | window.addEventListener("message", function(event) { 47 | if (event.source != window) // Only accept messages from ourself. 48 | return; 49 | 50 | if (event.data.type && (event.data.type == "FROM_PAGE")) { 51 | if (event.data.text.indexOf("block") == 0 && event.data.text.indexOf("user:") > -1) { 52 | var startIndex = event.data.text.indexOf("user:") + 5; 53 | var userName = event.data.text.substring(startIndex, event.data.text.length); 54 | blockUser(userName); 55 | } 56 | else if (event.data.text.indexOf("follow") == 0 && event.data.text.indexOf("user:") > -1) { 57 | var startIndex = event.data.text.indexOf("user:") + 5; 58 | var userName = event.data.text.substring(startIndex, event.data.text.length); 59 | followUser(userName); 60 | } 61 | } 62 | }, false); 63 | 64 | $(function() { //Keydown listener 65 | $(window).keydown(function(e) { 66 | if(e.which == 37) { //Left arrow key 67 | movedBack(); 68 | } 69 | else if (e.which == 39) { //Right arrow key 70 | movedForward(); 71 | } 72 | else if (e.which == 69) { //'e' key 73 | if (slideShowRunning) 74 | slideShowStop(); 75 | } 76 | else if (e.which == 80) { //'p' key 77 | if (slideShowRunning) 78 | slideShowPauseToggle(); 79 | } 80 | else if (e.which == 120) { //'F9' key 81 | if (window.location.href.indexOf("imgur.com/account/favorites/") > -1) { //Don't skip already viewed images when browsing your own favorites list. 82 | addNotification("Notification:", "Skipping of viewed posts not available when browsing your own favorites."); 83 | return; 84 | } 85 | 86 | if (skipViewed) 87 | addNotification("Notification:", "Skipping of viewed posts has been temporarily disabled. Press 'F9' to re-enable."); //Call function in notificationsContent.js 88 | else 89 | addNotification("Notification:", "Skipping of viewed posts has been temporarily enabled. Press 'F9' to disable."); //Call function in notificationsContent.js 90 | 91 | skipViewed = !skipViewed; 92 | } 93 | }); 94 | }); 95 | 96 | 97 | /* 98 | 99 | 100 | 101 | */ 102 | 103 | //imgurContentMain: Load options from storage and call member functions. 104 | function imgurContentMain() { 105 | //Load options from storage, close top bar, add the button to block users, and call the onNewPost function. 106 | chrome.storage.sync.get({ 107 | //Set defaults. 108 | promotedSkipEnabled: false, 109 | topBarCloseEnabled: true, 110 | removeViaMobileSpansEnabled: true, 111 | slideShowModeEnabled: true, 112 | slideShowSecondsPerPost: 10, 113 | specialUserNotificationEnabled: true, 114 | tollskiNotificationEnabled: true, 115 | viewedIconsEnabled: true, 116 | skipViewedPostsEnabled: false 117 | }, function(items) { 118 | skipPromoted = items.promotedSkipEnabled; 119 | closeTopBar = items.topBarCloseEnabled; 120 | removeViaMobileSpans = items.removeViaMobileSpansEnabled; 121 | canSlideShow = items.slideShowModeEnabled; 122 | slideShowTime = items.slideShowSecondsPerPost; 123 | notifyOnSpecialUsers = items.specialUserNotificationEnabled; 124 | notifyOnTollski = items.tollskiNotificationEnabled; 125 | markIconsViewed = items.viewedIconsEnabled; 126 | skipViewed = items.skipViewedPostsEnabled; 127 | 128 | chrome.storage.local.get({ 129 | blockAllSubreddits: false, 130 | blockedKeywords: new Array(), 131 | blockedSubreddits: new Array(), 132 | viewedPosts: new Array() 133 | }, function(items2) { 134 | blockReddit = items2.blockAllSubreddits; 135 | blockedKeywordsArray = items2.blockedKeywords; 136 | blockedSubredditsArray = items2.blockedSubreddits; 137 | viewedPostsArray = items2.viewedPosts; 138 | 139 | chrome.storage.local.getBytesInUse("viewedPosts", function(bytesInUse) { console.log("viewedPosts bytesInUse: " + bytesInUse + ". length: " + items2.viewedPosts.length); }); 140 | 141 | if (closeTopBar) 142 | checkForTopBarAndClose(); 143 | 144 | /*addBookmarkButton(); 145 | addFollowButton(); 146 | addBlockButton(); 147 | if (canSlideShow) 148 | addToggleSlideShowButton(); 149 | if (skipViewed) 150 | addViewedTexts();*/ 151 | 152 | //Give style to our added buttons and other elements. 153 | var buttonHoverCss = ".addedPostOptionDiv:hover { background-color:#E8E7E6; } .favorite-comment:hover { background-color:#E8E7E6; } .alreadyViewedIdentifier { position:absolute;z-index:1;top:1px;right:1px;background-color:rgba(0,0,0,0.5);color:white;font-weight:bold; }"; 154 | var style = document.createElement("style"); 155 | style.appendChild(document.createTextNode(buttonHoverCss)); 156 | document.getElementsByTagName('head')[0].appendChild(style); 157 | 158 | isFirstPostAfterPageLoad = true; 159 | onNewPost(); 160 | 161 | document.getElementsByClassName("btn btn-action navNext")[0].addEventListener("click", movedForward); 162 | document.getElementsByClassName("btn navPrev icon icon-arrow-left")[0].addEventListener("click", movedBack); 163 | document.getElementById("side-gallery").addEventListener("click", sideGalleryClicked); //If a thumbnail was clicked: treat it like the user moved back in the gallery. 164 | 165 | var checkCount = 0; 166 | var checkThumbnails = setInterval(function() { //Check if the thumbnails have loaded once every 500ms (max 60 checks). If they have loaded: add the viewed icons. 167 | console.log("checking"); 168 | var sgItems = document.getElementsByClassName("sg-item grid"); 169 | 170 | if (sgItems.length > 0) { 171 | clearInterval(checkThumbnails); 172 | addViewedTexts(); 173 | } 174 | else if (checkCount >= 60) 175 | clearInterval(checkThumnails); 176 | else 177 | checkCount++; 178 | }, 500); 179 | }); 180 | }); 181 | } 182 | 183 | //onCommentsLoaded: Called when comments are loaded or a change is detected in the comments. Calls comment member functions. 184 | function onCommentsLoaded() { 185 | var d = new Date(); 186 | var currTime = d.getTime(); 187 | //console.log(currTime - lastCommentUpdateTime); 188 | if (currTime - lastCommentUpdateTime > 500) { 189 | if (removeViaMobileSpans) 190 | removeViaElements(); 191 | 192 | addFavoriteCommentButtons(); 193 | 194 | lastCommentUpdateTime = currTime; 195 | //lastCommentUpdateSkipped = false; 196 | } 197 | //else 198 | //lastCommentUpdateSkipped = true; 199 | } 200 | 201 | //onNewPost: Called when a new post is viewed. 202 | function onNewPost() { 203 | var postSkipped = false; 204 | 205 | if (skipPromoted && !postSkipped) 206 | postSkipped = checkIfPromotedPost(); 207 | 208 | if(!postSkipped) { 209 | var postUserElement = document.getElementsByClassName("post-account")[0]; 210 | if (postUserElement !== undefined) 211 | postUser = postUserElement.innerHTML; 212 | else 213 | postUser = ""; 214 | 215 | var currentURL = window.location.href; 216 | 217 | var startIndex = -1; 218 | if (currentURL.indexOf("imgur.com/gallery/") > -1) 219 | startIndex = currentURL.indexOf("imgur.com/gallery/") + 18; 220 | else if (currentURL.indexOf("/favorites/") > -1) 221 | startIndex = currentURL.indexOf("/favorites/") + 11; 222 | else if (currentURL.indexOf("imgur.com/a/") > -1) 223 | startIndex = currentURL.indexOf("imgur.com/a/") + 12; 224 | else if (currentURL.indexOf("imgur.com/r/") > -1 || currentURL.indexOf("imgur.com/topic/") > -1) { 225 | startIndex = currentURL.lastIndexOf("/") + 1; 226 | } 227 | 228 | var lastIndex = currentURL.length; 229 | if (currentURL.substring(startIndex, currentURL.length).indexOf("/") > -1) 230 | lastIndex = currentURL.substring(startIndex, currentURL.length).indexOf("/"); 231 | 232 | if (startIndex > -1) { 233 | postID = currentURL.substring(startIndex, lastIndex); 234 | 235 | if (postID.length < 5 || postID.length > 7) 236 | postID = "unknown"; 237 | } 238 | else 239 | postID = "unknown"; 240 | 241 | if (rightTrueLeftFalse && !isFirstPostAfterPageLoad) {//If the user is moving forward in the gallery: check to see if post should be skipped, then continue to onNewPost2 (from within the functions). 242 | postSkipped = checkForBlockedKeywords(); 243 | 244 | if (!postSkipped && postUser.length == 0 && document.getElementsByClassName("post-title-meta")[0].innerHTML.indexOf("reddit.com") > -1) 245 | postSkipped = checkForBlockedSubreddits(); 246 | 247 | if (!postSkipped) 248 | checkForBlockedUsers(); 249 | else 250 | onNewPost2(postSkipped); 251 | } 252 | else //If the user is moving back in the gallery: don't bother skipping the post, just continue to onNewPost2. 253 | onNewPost2(postSkipped); 254 | } 255 | } 256 | 257 | //onNewPost2: Continuation of onNewPost, called by checkForBlockedUsers when it has finished. 258 | function onNewPost2(postSkipped) { 259 | if (!postSkipped && skipViewed && !isFirstPostAfterPageLoad && rightTrueLeftFalse) 260 | postSkipped = checkIfViewedPost(); 261 | 262 | 263 | addBookmarkButton(); 264 | addFollowButton(); 265 | addBlockButton(); 266 | if (canSlideShow) 267 | addToggleSlideShowButton(); 268 | if (markIconsViewed && !isFirstPostAfterPageLoad) 269 | addViewedTexts(); 270 | 271 | if (!postSkipped) { 272 | if (postID !== "unknown") { 273 | if (viewedPostsArray.indexOf(postID) == -1) { 274 | if (viewedPostsArray.length >= 20000) 275 | viewedPostsArray.shift(); //Remove first element of the array. 276 | 277 | viewedPostsArray.push(postID); 278 | 279 | chrome.storage.local.set({ 280 | viewedPosts: viewedPostsArray 281 | }, function() {}); 282 | } 283 | } 284 | } 285 | 286 | if (!postSkipped) 287 | checkForSpecialUsers(); 288 | 289 | onCommentsLoaded(); 290 | } 291 | 292 | /* 293 | 294 | 295 | 296 | */ 297 | 298 | //addBlockButton: Adds block user button to post options. 299 | function addBlockButton() { 300 | //var blockPosterDiv = document.createElement("div"); 301 | var blockPosterElem = document.createElement("li"); 302 | blockPosterElem.setAttribute("style", "text-align:center"); 303 | blockPosterElem.setAttribute("id", "block-poster"); 304 | blockPosterElem.setAttribute("class", "addedPostOptionDiv"); 305 | 306 | var textNode = document.createTextNode("block user"); 307 | blockPosterElem.appendChild(textNode); 308 | //document.getElementById("options-btn").getElementsByClassName("options")[0].appendChild(blockPosterDiv); 309 | document.getElementsByClassName("post-action-options-items")[0].appendChild(blockPosterElem); 310 | 311 | document.getElementById("block-poster").addEventListener("click", function() { 312 | window.postMessage({ type: "FROM_PAGE", text: "block user:" + postUser }, "*"); 313 | }, false); 314 | } 315 | 316 | //addBookmarkButton: Adds bookmark post button to post options. 317 | function addBookmarkButton() { 318 | //var bookmarkPostDiv = document.createElement("div"); 319 | var bookmarkPostElement = document.createElement("li"); 320 | bookmarkPostElement.setAttribute("style", "text-align:center;"); 321 | bookmarkPostElement.setAttribute("id", "bookmark-post"); 322 | bookmarkPostElement.setAttribute("class", "addedPostOptionDiv"); 323 | 324 | var textNode = document.createTextNode("bookmark post"); 325 | bookmarkPostElement.appendChild(textNode); 326 | //document.getElementById("options-btn").getElementsByClassName("options")[0].appendChild(bookmarkPostDiv); 327 | document.getElementsByClassName("post-action-options-items")[0].appendChild(bookmarkPostElement); 328 | 329 | bookmarkPostElement.addEventListener('click', bookmarkPost); 330 | } 331 | 332 | //addFavoriteCommentButtons: Removes any existing favorite comment buttons and adds a favorite comment button to each visible comment. 333 | function addFavoriteCommentButtons() { 334 | var existingFavoriteButtons = document.getElementsByClassName("favorite-comment"); 335 | for (i = 0; i < existingFavoriteButtons.length; i++) 336 | $('.favorite-comment').remove(); 337 | 338 | //console.log("adding comment buttons"); 339 | var commentOptionsButtons = document.getElementsByClassName("caption-toolbar edit-button like-combobox-but-not "); 340 | for (i = 0; i < commentOptionsButtons.length; i++) { 341 | var favoriteCommentDiv = document.createElement("div"); 342 | favoriteCommentDiv.setAttribute("class", "favorite-comment"); 343 | favoriteCommentDiv.setAttribute("style", "text-align:left;padding-left:10px;;"); 344 | var textNode = document.createTextNode("favorite"); 345 | favoriteCommentDiv.appendChild(textNode); 346 | //console.log("added favorite comment button"); 347 | commentOptionsButtons[i].getElementsByClassName("options")[0].firstChild.appendChild(favoriteCommentDiv); 348 | } 349 | 350 | var favoriteCommentDivs = document.getElementsByClassName("favorite-comment"); 351 | for (i = 0; i < favoriteCommentDivs.length; i++) 352 | favoriteCommentDivs[i].addEventListener("click", favoriteComment); 353 | } 354 | 355 | //addFollowButton: Adds follow user button to post options. 356 | function addFollowButton() { 357 | //var followPosterDiv = document.createElement("div"); 358 | var followPosterElem = document.createElement("li"); 359 | followPosterElem.setAttribute("style", "text-align:center;"); 360 | followPosterElem.setAttribute("id", "follow-poster"); 361 | followPosterElem.setAttribute("class", "addedPostOptionDiv"); 362 | 363 | var textNode = document.createTextNode("follow user"); 364 | followPosterElem.appendChild(textNode); 365 | //document.getElementById("options-btn").getElementsByClassName("options")[0].appendChild(followPosterDiv); 366 | document.getElementsByClassName("post-action-options-items")[0].appendChild(followPosterElem); 367 | 368 | document.getElementById("follow-poster").addEventListener("click", function() { 369 | window.postMessage({ type: "FROM_PAGE", text: "follow user:" + postUser }, "*"); 370 | }, false); 371 | } 372 | 373 | //addToggleSlideShowButton: Adds slide show toggle button to post options. 374 | function addToggleSlideShowButton() { 375 | //var slideShowToggleDiv = document.createElement("div"); 376 | var slideShowToggleElem = document.createElement("li"); 377 | slideShowToggleElem.setAttribute("style", "text-align:center;"); 378 | slideShowToggleElem.setAttribute("id", "follow-poster"); 379 | slideShowToggleElem.setAttribute("class", "addedPostOptionDiv"); 380 | 381 | var textNode = document.createTextNode("toggle slideshow"); 382 | slideShowToggleElem.appendChild(textNode); 383 | //document.getElementById("options-btn").getElementsByClassName("options")[0].appendChild(slideShowToggleDiv); 384 | document.getElementsByClassName("post-action-options-items")[0].appendChild(slideShowToggleElem); 385 | 386 | slideShowToggleElem.addEventListener("click", slideShowToggle); 387 | } 388 | 389 | 390 | function addViewedTexts() { 391 | if (window.location.href.indexOf("imgur.com/account/favorites/") > -1) //Don't add viewed spans on your own favorites list thumbnails. 392 | return; 393 | 394 | var postThumbnails = document.getElementsByClassName("sg-item grid"); 395 | for (i = 0; i < postThumbnails.length; i++) { 396 | if (postThumbnails[i].getElementsByClassName("alreadyViewedIdentifier").length == 0) { 397 | var postIconID = postThumbnails[i].getAttribute("href"); 398 | var startIndex = 1; 399 | if (postIconID.indexOf("/a/") == 0) 400 | startIndex = 3; 401 | 402 | if (viewedPostsArray.indexOf(postThumbnails[i].getAttribute("href").substring(startIndex, postIconID.length)) > -1) { 403 | var viewedSpan = document.createElement("span"); 404 | viewedSpan.setAttribute("class", "alreadyViewedIdentifier"); 405 | viewedSpan.innerHTML = "Viewed"; 406 | 407 | postThumbnails[i].appendChild(viewedSpan); 408 | 409 | if (postThumbnails[i].getElementsByClassName("sg-item-num-images").length > 0) //If the thumbnail has an image-number icon: move it down. 410 | $(postThumbnails[i].getElementsByClassName("sg-item-num-images")[0]).css("top", "24px"); 411 | } 412 | } 413 | } 414 | } 415 | 416 | //blockUser: Adds user to blocked user list and then skips current post. 417 | function blockUser(userName) { 418 | if (userName === "") { 419 | console.log("No username detected, unable to block."); 420 | return; 421 | } 422 | 423 | console.log("blocking " + userName); 424 | chrome.storage.sync.get({ 425 | useSynchronizedStorage: false 426 | }, function(items) { 427 | if (items.useSynchronizedStorage) { 428 | chrome.storage.sync.get({ 429 | //Set defaults. 430 | blockedUsers: new Array() 431 | }, function(items) { 432 | blockedUserList = items.blockedUsers; 433 | 434 | blockedUserList.push(userName); 435 | 436 | chrome.storage.sync.set({ 437 | blockedUsers: blockedUserList 438 | }, function() { 439 | skipPost(); 440 | }); 441 | }); 442 | } 443 | else { 444 | chrome.storage.local.get({ 445 | //Set defaults. 446 | blockedUsers: new Array() 447 | }, function(items) { 448 | blockedUserList = items.blockedUsers; 449 | 450 | blockedUserList.push(userName); 451 | 452 | chrome.storage.local.set({ 453 | blockedUsers: blockedUserList 454 | }, function() { 455 | skipPost(); 456 | }); 457 | }); 458 | } 459 | }); 460 | } 461 | 462 | //bookmarkPost: Adds post to bookmarked posts(favoritedImages). 463 | function bookmarkPost() { 464 | if (postID === "unknown") { 465 | alert("Oops, I wasn't able to get the post ID. Please sumbit a bug report with the URL of this page."); 466 | return; 467 | } 468 | 469 | var bookmarkedArrayMaxLength = 45; 470 | 471 | var titleCutoffIndex = 30; 472 | if (document.getElementsByClassName("post-title font-opensans-bold")[0] < 30) 473 | titleCutoffIndex = document.getElementsByClassName("post-title font-opensans-bold")[0].innerHTML.length; 474 | 475 | 476 | var shortUrlStartIndex = document.getElementsByClassName("sg-item selected grid")[0].getAttribute("style").indexOf(".com/") + 5; 477 | var shortUrlEndIndex = document.getElementsByClassName("sg-item selected grid")[0].getAttribute("style").indexOf(".jpg"); 478 | 479 | 480 | var bookmarkedImg = { 481 | id: postID, //document.getElementsByClassName("post-image-container")[0].getAttribute("id"), 482 | imgSrc: document.getElementsByClassName("sg-item selected grid")[0].getAttribute("style").substring(shortUrlStartIndex, shortUrlEndIndex), 483 | title: document.getElementsByClassName("post-title")[0].innerHTML.substring(0, titleCutoffIndex), 484 | directory: "root" 485 | } 486 | 487 | chrome.storage.sync.get({ 488 | useSynchronizedStorage: false 489 | }, function(items) { 490 | if (items.useSynchronizedStorage) { //If the they have selected to use Chrome sync for storage... 491 | chrome.storage.sync.get({ 492 | //Set defaults. 493 | favoritedImages: new Array(), 494 | favoritedImages1: new Array(), 495 | favoritedImages2: new Array(), 496 | favoritedImages3: new Array(), 497 | favoritedImages4: new Array(), 498 | favoritedImages5: new Array(), 499 | favoritedImages6: new Array(), 500 | favoritedImages7: new Array(), 501 | favoritedImages8: new Array(), 502 | favoritedImages9: new Array(), 503 | favoritedImages10: new Array(), 504 | favoritedImages11: new Array(), 505 | favoritedImages12: new Array(), 506 | favoritedImages13: new Array() 507 | }, function(items) { 508 | var bookmarkedImagesArray = items.favoritedImages; 509 | if (items.favoritedImages1.length > 0) 510 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages1); 511 | if (items.favoritedImages2.length > 0) 512 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages2); 513 | if (items.favoritedImages3.length > 0) 514 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages3); 515 | if (items.favoritedImages4.length > 0) 516 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages4); 517 | if (items.favoritedImages5.length > 0) 518 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages5); 519 | if (items.favoritedImages6.length > 0) 520 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages6); 521 | if (items.favoritedImages7.length > 0) 522 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages7); 523 | if (items.favoritedImages8.length > 0) 524 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages8); 525 | if (items.favoritedImages9.length > 0) 526 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages9); 527 | if (items.favoritedImages10.length > 0) 528 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages10); 529 | if (items.favoritedImages11.length > 0) 530 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages11); 531 | if (items.favoritedImages12.length > 0) 532 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages12); 533 | if (items.favoritedImages13.length > 0) 534 | bookmarkedImagesArray.push.apply(bookmarkedImagesArray, items.favoritedImages13); 535 | 536 | //If the user already has this post bookmarked: return. 537 | for (i = 0; i < bookmarkedImagesArray.length; i++) { 538 | if (bookmarkedImagesArray[i].id == bookmarkedImg.id) { 539 | alert("You already have bookmarked this post."); 540 | return; 541 | } 542 | } 543 | 544 | bookmarkedImagesArray.unshift(bookmarkedImg); //Add the post to the beginning of bookmarkedImagesArray. 545 | 546 | chrome.storage.sync.set({ 547 | favoritedImages: bookmarkedImagesArray.slice(0, bookmarkedArrayMaxLength), 548 | favoritedImages1: bookmarkedImagesArray.slice(bookmarkedArrayMaxLength , 2 * bookmarkedArrayMaxLength), 549 | favoritedImages2: bookmarkedImagesArray.slice(2 * bookmarkedArrayMaxLength , 3 * bookmarkedArrayMaxLength), 550 | favoritedImages3: bookmarkedImagesArray.slice(3 * bookmarkedArrayMaxLength , 4 * bookmarkedArrayMaxLength), 551 | favoritedImages4: bookmarkedImagesArray.slice(4 * bookmarkedArrayMaxLength , 5 * bookmarkedArrayMaxLength), 552 | favoritedImages5: bookmarkedImagesArray.slice(5 * bookmarkedArrayMaxLength , 6 * bookmarkedArrayMaxLength), 553 | favoritedImages6: bookmarkedImagesArray.slice(6 * bookmarkedArrayMaxLength , 7 * bookmarkedArrayMaxLength), 554 | favoritedImages7: bookmarkedImagesArray.slice(7 * bookmarkedArrayMaxLength , 8 * bookmarkedArrayMaxLength), 555 | favoritedImages8: bookmarkedImagesArray.slice(8 * bookmarkedArrayMaxLength , 9 * bookmarkedArrayMaxLength), 556 | favoritedImages9: bookmarkedImagesArray.slice(9 * bookmarkedArrayMaxLength , 10 * bookmarkedArrayMaxLength), 557 | favoritedImages10: bookmarkedImagesArray.slice(10 * bookmarkedArrayMaxLength , 11 * bookmarkedArrayMaxLength), 558 | favoritedImages11: bookmarkedImagesArray.slice(11 * bookmarkedArrayMaxLength , 12 * bookmarkedArrayMaxLength), 559 | favoritedImages12: bookmarkedImagesArray.slice(12 * bookmarkedArrayMaxLength , 13 * bookmarkedArrayMaxLength), 560 | favoritedImages13: bookmarkedImagesArray.slice(13 * bookmarkedArrayMaxLength , 14 * bookmarkedArrayMaxLength) 561 | }, function() { 562 | if (!chrome.runtime.lastError) 563 | console.log("post bookmarked: " + postID); 564 | }); 565 | }); 566 | } 567 | else { 568 | chrome.storage.local.get({ 569 | //Set defaults. 570 | favoritedImages: new Array() 571 | }, function(items) { 572 | var bookmarkedImagesArray = items.favoritedImages; 573 | 574 | //If the user already has this post bookmarked: return. 575 | for (i = 0; i < bookmarkedImagesArray.length; i++) { 576 | if (bookmarkedImagesArray[i].id == bookmarkedImg.id) { 577 | alert("You already have bookmarked this post."); 578 | return; 579 | } 580 | } 581 | 582 | bookmarkedImagesArray.unshift(bookmarkedImg); //Add the post to the beginning of bookmarkedImagesArray. 583 | 584 | chrome.storage.local.set({ 585 | favoritedImages: bookmarkedImagesArray 586 | }, function() { 587 | if (!chrome.runtime.lastError) 588 | console.log("post bookmarked: " + postID); 589 | }); 590 | }); 591 | } 592 | }); 593 | } 594 | 595 | function checkForBlockedKeywords() { 596 | var postTitle = document.getElementsByClassName("post-title")[0].innerHTML.toLowerCase(); 597 | 598 | for (i = 0; i < blockedKeywordsArray.length; i++) { 599 | if (postTitle.indexOf(blockedKeywordsArray[i].toLowerCase()) > -1) { 600 | console.log("***Post's title contains blocked keyword (" + blockedKeywordsArray[i] + "), skipping.***"); 601 | 602 | if (blockedKeywordsArray[i].length > 16) 603 | addNotification("Previous Post Skipped:", "Keyword in title is blocked: (" + blockedKeywordsArray[i].substring(0, 16) + "...)"); 604 | else 605 | addNotification("Previous Post Skipped:", "Keyword in title is blocked: (" + blockedKeywordsArray[i] + ")"); 606 | 607 | onNewPost2(true); 608 | skipPost(); 609 | return true; 610 | } 611 | } 612 | //Don't call onNewPost2 here because it will be done in either checkForBlockedSubreddits or checkForBlockedUsers. 613 | return false; 614 | 615 | } 616 | 617 | function checkForBlockedSubreddits() { 618 | if (blockReddit) { 619 | console.log("***Post's title is from Reddit, skipping.***"); 620 | 621 | addNotification("Previous Post Skipped:", "Post is from Reddit."); 622 | 623 | onNewPost2(true); 624 | skipPost(); 625 | return true; 626 | } 627 | 628 | var redditURL = document.getElementsByClassName("post-title-meta")[0].getElementsByTagName("a")[0].getAttribute("href").toLowerCase(); 629 | redditURL = redditURL.substr(redditURL.indexOf("reddit.com/r/") + 13, redditURL.length); 630 | var subredditName = redditURL.substr(0, redditURL.indexOf("/")); 631 | console.log("subredditName: " + subredditName); 632 | 633 | for (i = 0; i < blockedSubredditsArray.length; i++) { 634 | if (subredditName === blockedSubredditsArray[i].toLowerCase()) { 635 | console.log("***Post's title is from blocked subreddit(" + blockedSubredditsArray[i] + "), skipping.***"); 636 | 637 | if (blockedSubredditsArray[i].length > 16) 638 | addNotification("Previous Post Skipped:", "Post from blocked subreddit: (" + blockedSubredditsArray[i].substring(0, 16) + "...)"); 639 | else 640 | addNotification("Previous Post Skipped:", "Post from blocked subreddit: (" + blockedSubredditsArray[i] + ")"); 641 | 642 | onNewPost2(true); 643 | skipPost(); 644 | return true; 645 | } 646 | } 647 | //Don't call onNewPost2 here because it will be done in checkForBlockedUsers. 648 | return false; 649 | } 650 | 651 | //checkForBlockedUsers: Checks if post creator is blocks, skips post if user is blocked. 652 | function checkForBlockedUsers() { 653 | console.log("Checking if user(" + postUser + ") is blocked."); 654 | chrome.storage.sync.get({ 655 | useSynchronizedStorage: false 656 | }, function(items) { 657 | if (items.useSynchronizedStorage) { //If the they have selected to use Chrome sync for storage... 658 | chrome.storage.sync.get({ 659 | //Set defaults. 660 | blockedUsers: new Array() 661 | }, function(items) { 662 | blockedUserList = items.blockedUsers; 663 | 664 | for (i = 0; i < blockedUserList.length; i++) { 665 | if (blockedUserList[i].toLowerCase() === postUser.toLowerCase()) { 666 | console.log("***Post's creator (" + blockedUserList[i] + ") has been blocked, skipping.***"); 667 | 668 | if (blockedUserList[i].length > 16) 669 | addNotification("Previous Post Skipped:", "User is blocked: (" + blockedUserList[i].substring(0, 16) + "...)"); 670 | else 671 | addNotification("Previous Post Skipped:", "User is blocked: (" + blockedUserList[i] + ")"); 672 | 673 | onNewPost2(true); 674 | skipPost(); 675 | return;//break; 676 | } 677 | } 678 | onNewPost2(false); 679 | }); 680 | } 681 | else { 682 | chrome.storage.local.get({ 683 | //Set defaults. 684 | blockedUsers: new Array() 685 | }, function(items) { 686 | blockedUserList = items.blockedUsers; 687 | 688 | for (i = 0; i < blockedUserList.length; i++) { 689 | if (blockedUserList[i].toLowerCase() === postUser.toLowerCase()) { 690 | console.log("***Post's creator (" + blockedUserList[i] + ") has been blocked, skipping.***"); 691 | 692 | if (blockedUserList[i].length > 16) 693 | addNotification("Previous Post Skipped:", "User is blocked: (" + blockedUserList[i].substring(0, 16) + "...)"); 694 | else 695 | addNotification("Previous Post Skipped:", "User is blocked: (" + blockedUserList[i] + ")"); 696 | 697 | onNewPost2(true); 698 | skipPost(); 699 | return;//break; 700 | } 701 | } 702 | onNewPost2(false); 703 | }); 704 | } 705 | }); 706 | } 707 | 708 | //checkForSpecialUsers: Checks if the post's creator is a "special" user, notifies if true. 709 | function checkForSpecialUsers() { 710 | if (notifyOnSpecialUsers) { 711 | if (postUser === "ANewBadlyPhotoshoppedPhotoofMichaelCeraEveryday") 712 | addNotification("Tip:", "Check the username."); //Call function in notificationsContent.js 713 | } 714 | 715 | if (notifyOnTollski && postUser.indexOf("Tollski") == 0 && postUser.length == 7) 716 | addNotification("Tip:", "This post was made by the creator of the imgur Browsing Aid extension."); //Call function in notificationsContent.js 717 | } 718 | 719 | //checkForTopBarAndClose: If notifications bar is open, close it. 720 | function checkForTopBarAndClose() { 721 | var closeButtons = document.getElementsByClassName("cta-close icon-x"); 722 | if (closeButtons.length > 0) { 723 | closeButtons[0].click(); 724 | console.log("Top bar detected and closed."); 725 | } 726 | } 727 | 728 | //checkIfPromotedPost: If this is a promoted post, skip it. 729 | function checkIfPromotedPost() { 730 | if (document.getElementsByClassName("promoted-tag").length > 0) { 731 | console.log("***Promoted post, skipping.***"); 732 | skipPost(); 733 | return true; 734 | } 735 | else 736 | return false; 737 | } 738 | 739 | //checkIfViewedPost: Checks if this post has already been viewed, skips the post if it has. 740 | function checkIfViewedPost() { 741 | /*if (window.location.href.indexOf("imgur.com/gallery/") == -1) //If we are not in the gallery: return. 742 | return;*/ 743 | if (window.location.href.indexOf("imgur.com/account/favorites/") > -1) //Don't skip already viewed images when browsing your own favorites list. 744 | return; 745 | 746 | for (i = 0; i < viewedPostsArray.length; i++){ 747 | if (postID === viewedPostsArray[i]) { 748 | console.log("Skipping post (Already Viewed): " + postID); 749 | addNotification("Previous Post Skipped:", "Post Already Viewed"); 750 | skipPost(); 751 | return true; 752 | } 753 | } 754 | return false; 755 | } 756 | 757 | //favoriteComment: Adds comment to favoriteComments. 758 | function favoriteComment() { 759 | var superParent = this.parentNode.parentNode.parentNode.parentNode.parentNode; 760 | 761 | var commentText = ""; 762 | for (i = 0; i < superParent.childNodes[1].childNodes.length; i++) //Add the innerHTML of each childNode to commentText. 763 | commentText += superParent.childNodes[1].childNodes[i].innerHTML; 764 | 765 | console.log("https://imgur.com" + superParent.getElementsByClassName("item permalink-caption-link")[0].getAttribute("href")); 766 | console.log(superParent.getElementsByClassName("author")[0].children[0].innerHTML); 767 | console.log(commentText); 768 | 769 | var comment = { 770 | url: "https://imgur.com" + superParent.getElementsByClassName("item permalink-caption-link")[0].getAttribute("href"), 771 | userName: superParent.getElementsByClassName("author")[0].children[0].innerHTML, 772 | text: commentText 773 | }; 774 | 775 | chrome.storage.sync.get({ 776 | useSynchronizedStorage: false 777 | }, function(items) { 778 | if (items.useSynchronizedStorage) { //If the they have selected to use Chrome sync for storage... 779 | chrome.storage.sync.get({ 780 | //Set defaults. 781 | favoriteComments: new Array() 782 | }, function(items) { 783 | favoriteCommentList = items.favoriteComments; 784 | 785 | favoriteCommentList.push(comment); 786 | 787 | chrome.storage.sync.set({ 788 | favoriteComments: favoriteCommentList 789 | }, function() { 790 | superParent.getElementsByClassName("caption-toolbar edit-button like-combobox-but-not opened")[0].setAttribute("class", "caption-toolbar edit-button like-combobox-but-not "); 791 | }); 792 | }); 793 | } 794 | else { 795 | chrome.storage.local.get({ 796 | //Set defaults. 797 | favoriteComments: new Array() 798 | }, function(items) { 799 | favoriteCommentList = items.favoriteComments; 800 | 801 | favoriteCommentList.push(comment); 802 | 803 | chrome.storage.local.set({ 804 | favoriteComments: favoriteCommentList 805 | }, function() { 806 | superParent.getElementsByClassName("caption-toolbar edit-button like-combobox-but-not opened")[0].setAttribute("class", "caption-toolbar edit-button like-combobox-but-not "); 807 | }); 808 | }); 809 | } 810 | }); 811 | 812 | } 813 | 814 | //followUser: Adds user to followed user list. 815 | function followUser(userName) { 816 | if (userName === "") { 817 | console.log("No username detected, unable to follow."); 818 | return; 819 | } 820 | 821 | chrome.storage.sync.get({ 822 | useSynchronizedStorage: false 823 | }, function(items) { 824 | if (items.useSynchronizedStorage) { //If the they have selected to use Chrome sync for storage... 825 | chrome.storage.sync.get({ 826 | //Set defaults. 827 | followedUsers: new Array() 828 | }, function(items) { 829 | followedUserList = items.followedUsers; 830 | 831 | if ($.inArray(userName, followedUserList) > -1) 832 | console.log(userName + " already followed."); 833 | else { 834 | followedUserList.push(userName); 835 | console.log("following " + userName); 836 | 837 | chrome.storage.sync.set({ 838 | followedUsers: followedUserList 839 | }, function() {}); 840 | } 841 | }); 842 | } 843 | else { 844 | chrome.storage.local.get({ 845 | //Set defaults. 846 | followedUsers: new Array() 847 | }, function(items) { 848 | followedUserList = items.followedUsers; 849 | 850 | if ($.inArray(userName, followedUserList) > -1) 851 | console.log(userName + " already followed."); 852 | else { 853 | followedUserList.push(userName); 854 | console.log("following " + userName); 855 | 856 | chrome.storage.local.set({ 857 | followedUsers: followedUserList 858 | }, function() {}); 859 | } 860 | }); 861 | } 862 | }); 863 | } 864 | 865 | function movedBack() { 866 | rightTrueLeftFalse = false; 867 | if (slideShowRunning && !slideShowPaused) { 868 | slideShowSecondsRemaining = slideShowTime; 869 | updateSlideShowMessage(slideShowSecondsRemaining); 870 | slideShowPauseToggle(); 871 | } 872 | } 873 | 874 | function movedForward() { 875 | rightTrueLeftFalse = true; 876 | if (slideShowRunning) { 877 | slideShowSecondsRemaining = slideShowTime; 878 | updateSlideShowMessage(slideShowSecondsRemaining); 879 | if (slideShowPaused) 880 | slideShowPauseToggle(); 881 | } 882 | } 883 | 884 | //permanentlyDisableSpecialUsersNotifications: Sets the option to notify on special users to false. 885 | function permanentlyDisableSpecialUsersNotifications() { 886 | notifyOnSpecialUsers = false; 887 | 888 | chrome.storage.sync.set({ 889 | specialUserNotificationEnabled: notifyOnSpecialUsers 890 | }, function() { 891 | if (!chrome.runtime.lastError) 892 | addNotification("Notification:", "You have disabled notifications for special users."); 893 | }); 894 | } 895 | 896 | //permanentlyDisableSpecialUsersNotifications: Sets the option to notify on special users to false. 897 | function permanentlyDisableTollskiNotifications() { 898 | notifyOnTollski = false; 899 | 900 | chrome.storage.sync.set({ 901 | tollskiNotificationEnabled: notifyOnTollski 902 | }, function() { 903 | if (!chrome.runtime.lastError) 904 | addNotification("Notification:", "You have disabled notifications for Tollski."); 905 | }); 906 | } 907 | 908 | //removeViaElements: Removes "via Android" and "via iPhone" links next to comment author names. 909 | function removeViaElements() { 910 | //Not working everytime, what do we have to wait for? 911 | var viaClassElements = document.getElementsByClassName("via"); 912 | var origLength = viaClassElements.length; 913 | 914 | //console.log("starting removal: " + origLength); 915 | for (i = origLength - 1; i >=0; i--) { 916 | //console.log(i + " " + origLength + " removing via: " + viaClassElements[0].parentNode.firstChild.innerHTML); 917 | viaClassElements[i].parentNode.removeChild(viaClassElements[i]); 918 | } 919 | 920 | } 921 | 922 | //sideGalleryClicked: Runs when a thumbnail in the side gallery has been clicked. Determines if we need to move forward or backward in the gallery. 923 | function sideGalleryClicked() { 924 | if (clickingBecauseSkipping) { 925 | clickingBecauseSkipping = false; 926 | movedForward(); 927 | } 928 | else 929 | movedBack(); 930 | } 931 | 932 | //skipPost: Skips current post. 933 | function skipPost() { 934 | if (rightTrueLeftFalse){ 935 | //Variables for debugging. 936 | var postsSkipped = 1; //Variable to count how many posts will be skipped. 937 | var postIDsSkipped = postID; //Track the IDs skipped. 938 | 939 | if (skipViewed) { //If skipping viewed posts is enabled: find the next non-viewed/non-downvoted post and click it. 940 | var sgItems = document.getElementsByClassName("sg-item grid"); 941 | var foundCurrentSgItem = false, foundNextNonViewed = false; 942 | for (i = 0; i < sgItems.length; i++) { 943 | //console.log("searching sg item"); 944 | if (!foundCurrentSgItem) { 945 | if (sgItems[i].className == "sg-item selected grid") 946 | foundCurrentSgItem = true; 947 | } 948 | else { 949 | if (sgItems[i].getElementsByClassName("alreadyViewedIdentifier").length == 0 && sgItems[i].getElementsByClassName("sg-item-vote icon-downvote").length == 0) { //If the thumbnail hasn't already been viewed and hasn't been downvoted: ... 950 | //console.log("found next non-viewed post"); 951 | foundNextNonViewed = true; 952 | clickingBecauseSkipping = true; 953 | sgItems[i].click(); 954 | break; 955 | } 956 | else { 957 | postsSkipped++; 958 | var startIndex; 959 | if (sgItems[i].getAttribute("href").indexOf("/a/") == 0) 960 | startIndex = 3; 961 | else 962 | startIndex = 1; 963 | 964 | postIDsSkipped += ", " + sgItems[i].getAttribute("href").substring(startIndex, sgItems[i].getAttribute("href").length); 965 | } 966 | } 967 | } 968 | 969 | if (!foundNextNonViewed) {//If no suitable non-viewed post was found: click the last element. 970 | console.log("No non-viewed posts found, going to last thumbnail in side gallery."); 971 | sgItems[sgItems.length - 1].click(); 972 | } 973 | } 974 | else //If skipping viewed posts is disabled: click the next button. 975 | document.getElementsByClassName("btn btn-action navNext")[0].click(); 976 | 977 | console.log("Posts skipped: " + postsSkipped + ". (IDs: " + postIDsSkipped +")"); 978 | } 979 | else 980 | document.getElementsByClassName("btn navPrev icon icon-arrow-left")[0].click(); 981 | } 982 | 983 | function slideShowPauseToggle() { 984 | if (slideShowInterval && slideShowRunning) { 985 | if (slideShowPaused) { 986 | slideShowStart(true); 987 | slideShowPaused = false; 988 | } 989 | else { 990 | clearInterval(slideShowInterval); 991 | slideShowPaused = true; 992 | } 993 | } 994 | } 995 | 996 | function slideShowStart(unpausing) { 997 | if (canSlideShow) { 998 | if (!unpausing) { 999 | slideShowRunning = true; 1000 | addSlideShowMessageBox(); 1001 | slideShowSecondsRemaining = slideShowTime; 1002 | updateSlideShowMessage(slideShowSecondsRemaining); 1003 | } 1004 | 1005 | slideShowInterval = setInterval( function() { 1006 | if (slideShowSecondsRemaining <= 0) { 1007 | document.getElementsByClassName("btn btn-action navNext")[0].click(); 1008 | slideShowSecondsRemaining = slideShowTime; 1009 | } 1010 | else 1011 | slideShowSecondsRemaining--; 1012 | updateSlideShowMessage(slideShowSecondsRemaining); //Call function in notificationsContent.js 1013 | }, 1000); 1014 | } 1015 | } 1016 | 1017 | function slideShowStop() { 1018 | if (slideShowInterval) { 1019 | clearInterval(slideShowInterval); 1020 | closeSlideShowMessageBox(); //Call function in notificationsContent.js 1021 | slideShowPaused = false; 1022 | console.log("Slide show stopped."); 1023 | } 1024 | slideShowRunning = false; 1025 | } 1026 | 1027 | function slideShowToggle() { 1028 | if (slideShowRunning) 1029 | slideShowStop(); 1030 | else 1031 | slideShowStart(false); 1032 | } 1033 | 1034 | function temporarilyStopSkippingViewedPosts() { 1035 | skipViewed = false; 1036 | addNotification("Notification:", "Skipping of viewed posts has been temporarily disabled. Press 'F9' to re-enable."); 1037 | } --------------------------------------------------------------------------------