├── Deanimator.safariextension ├── Info.plist ├── Settings.plist ├── deanimator.js └── global.html ├── LICENSE └── readme.mdown /Deanimator.safariextension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Author 6 | Mat Sadler 7 | CFBundleDisplayName 8 | Deanimator 9 | CFBundleIdentifier 10 | com.github.matsadler.deanimator 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleShortVersionString 14 | 0.3.0 15 | CFBundleVersion 16 | 0.3.0 17 | Chrome 18 | 19 | Global Page 20 | global.html 21 | 22 | Content 23 | 24 | Scripts 25 | 26 | Start 27 | 28 | deanimator.js 29 | 30 | 31 | 32 | Description 33 | Stop animated GIFs. 34 | ExtensionInfoDictionaryVersion 35 | 1.0 36 | Permissions 37 | 38 | Website Access 39 | 40 | Include Secure Pages 41 | 42 | Level 43 | All 44 | 45 | 46 | Update Manifest URL 47 | http://matsadler.github.com/deanimator/updates.plist 48 | Website 49 | http://github.com/matsadler/deanimator 50 | 51 | 52 | -------------------------------------------------------------------------------- /Deanimator.safariextension/Settings.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DefaultValue 7 | 8 | Key 9 | applyToAll 10 | Title 11 | Apply to all images 12 | Type 13 | CheckBox 14 | 15 | 16 | DefaultValue 17 | 18 | Key 19 | applyToBackgroundImages 20 | Title 21 | Apply to background images 22 | Type 23 | CheckBox 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Deanimator.safariextension/deanimator.js: -------------------------------------------------------------------------------- 1 | var ImagesByURL = { 2 | hash: {}, 3 | add: function (url, image) { 4 | var store = (this.hash[url] || (this.hash[url] = [])); 5 | if (store.indexOf(image) < 0) { 6 | store.push(image); 7 | } 8 | return image; 9 | }, 10 | remove: function (url) { 11 | var value = this.hash[url]; 12 | delete this.hash[url]; 13 | return value || []; 14 | }, 15 | include: function (url) { 16 | return this.hash.hasOwnProperty(url); 17 | } 18 | }; 19 | 20 | function deanimate(images) { 21 | [].slice.call(images).forEach(function (image) { 22 | if (!ImagesByURL.include(image.src)) { 23 | safari.self.tab.dispatchMessage("toDataURL", image.src); 24 | } 25 | ImagesByURL.add(image.src, image); 26 | }); 27 | } 28 | 29 | 30 | function deanimateBackground(elements) { 31 | [].slice.call(elements).forEach(function (element) { 32 | var style = window.getComputedStyle(element, null), 33 | match = style.backgroundImage.match(/^url\((.*)\)$/), 34 | url = match ? match[1] : null; 35 | if (url) { 36 | if (!ImagesByURL.include(url)) { 37 | safari.self.tab.dispatchMessage("toDataURL", url); 38 | } 39 | ImagesByURL.add(url, element); 40 | } 41 | }); 42 | } 43 | 44 | var Responders = { 45 | imageAsDataURL: function (event) { 46 | var message = event.message, images = ImagesByURL.remove(message.url); 47 | images.forEach(function (image) { 48 | if (image.src === message.url) { 49 | image.src = message.dataURL; 50 | } 51 | }); 52 | images.forEach(function (image) { 53 | var style = window.getComputedStyle(image, null); 54 | if (style.backgroundImage === "url(" + message.url + ")") { 55 | image.style.backgroundImage = "url(" + message.dataURL + ")"; 56 | } 57 | }); 58 | }, 59 | applyToBackgroundImages: function (event) { 60 | deanimateBackground(document.querySelectorAll("*")); 61 | } 62 | }; 63 | 64 | safari.self.addEventListener("message", function (event) { 65 | var responder = Responders[event.name]; 66 | if (responder) { 67 | responder(event); 68 | } 69 | }); 70 | 71 | window.addEventListener("DOMContentLoaded", function (event) { 72 | deanimate(document.images); 73 | }); 74 | 75 | window.addEventListener("load", function (event) { 76 | safari.self.tab.dispatchMessage("applyToBackgroundImages"); 77 | }); 78 | 79 | window.addEventListener("DOMNodeInserted", function (event) { 80 | if (event.target.tagName === "IMG") { 81 | deanimate([event.target]); 82 | } else if (event.target.getElementsByTagName) { 83 | deanimate(event.target.getElementsByTagName("img")); 84 | } 85 | }); -------------------------------------------------------------------------------- /Deanimator.safariextension/global.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | global 5 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2018 Matthew Sadler. 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /readme.mdown: -------------------------------------------------------------------------------- 1 | # Deanimator # 2 | 3 | Safari extension to stop/disable animated GIFs. 4 | 5 | [Download](http://github.com/downloads/matsadler/deanimator/Deanimator-0.3.0.safariextz) --------------------------------------------------------------------------------