├── Gemfile ├── .pairs ├── public ├── images │ ├── badge.png │ ├── logo-132.png │ └── logo-200.png ├── stylesheets │ └── stop_censorship.css └── javascripts │ ├── stop_censorship.js │ └── cloudflare.js ├── Rakefile ├── cloudflare.md ├── spec └── javascripts │ ├── support │ ├── jasmine_config.rb │ ├── jasmine_runner.rb │ └── jasmine.yml │ ├── helpers │ └── SpecHelper.js │ └── stop_censorship_spec.js ├── Gemfile.lock ├── UNLICENSE ├── Readme.md ├── cloudflare.json └── index.html /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | gem "jasmine" 4 | -------------------------------------------------------------------------------- /.pairs: -------------------------------------------------------------------------------- 1 | pairs: 2 | ms: Michael Sofaer; michael 3 | cj: Chris Joel; chris 4 | email: 5 | prefix: pair 6 | domain: cloudflare.com 7 | -------------------------------------------------------------------------------- /public/images/badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fightforthefuture/internet_defense_league_cloud_flare/HEAD/public/images/badge.png -------------------------------------------------------------------------------- /public/images/logo-132.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fightforthefuture/internet_defense_league_cloud_flare/HEAD/public/images/logo-132.png -------------------------------------------------------------------------------- /public/images/logo-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fightforthefuture/internet_defense_league_cloud_flare/HEAD/public/images/logo-200.png -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | task :default => [:jasmine] 2 | 3 | 4 | begin 5 | require 'rubygems' 6 | require 'jasmine' 7 | load 'jasmine/tasks/jasmine.rake' 8 | rescue LoadError 9 | task :jasmine do 10 | abort "Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine" 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /cloudflare.md: -------------------------------------------------------------------------------- 1 | #Defend the Internet 2 | 3 | This app lets you join the sites willing to band together to defend the internet 4 | from damaging legislation. 5 | 6 | You turn it on, and when there's an action, your site will automatically be a part of it. 7 | 8 | This file does not allow 9 | -------------------------------------------------------------------------------- /spec/javascripts/support/jasmine_config.rb: -------------------------------------------------------------------------------- 1 | module Jasmine 2 | class Config 3 | 4 | # Add your overrides or custom config code here 5 | 6 | end 7 | end 8 | 9 | 10 | # Note - this is necessary for rspec2, which has removed the backtrace 11 | module Jasmine 12 | class SpecBuilder 13 | def declare_spec(parent, spec) 14 | me = self 15 | example_name = spec["name"] 16 | @spec_ids << spec["id"] 17 | backtrace = @example_locations[parent.description + " " + example_name] 18 | parent.it example_name, {} do 19 | me.report_spec(spec["id"]) 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/javascripts/helpers/SpecHelper.js: -------------------------------------------------------------------------------- 1 | beforeEach(function() { 2 | this.sopa = null; 3 | var self = this; 4 | 5 | var promise = CloudFlare.require(["stop_censorship","cloudflare/jquery1.7", "cloudflare/user"], 6 | function(stop_censorship, $, user){ 7 | self.sopa = stop_censorship; 8 | self.user = user 9 | window.$ = $ 10 | } 11 | ) 12 | 13 | waitsFor(function(){ 14 | return this.sopa !== null; 15 | }) 16 | }); 17 | 18 | afterEach(function(){ 19 | this.user.setCookie("__cfduid", "") 20 | this.user.setCookie("cf_sopa", "") 21 | $(".sopa_badge").remove() 22 | this.sopa.config.cookie = null 23 | }) 24 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | childprocess (0.2.3) 5 | ffi (~> 1.0.6) 6 | diff-lcs (1.1.3) 7 | ffi (1.0.11) 8 | jasmine (1.1.2) 9 | jasmine-core (>= 1.1.0) 10 | rack (>= 1.1) 11 | rspec (>= 1.3.1) 12 | selenium-webdriver (>= 0.1.3) 13 | jasmine-core (1.1.0) 14 | multi_json (1.0.4) 15 | rack (1.3.5) 16 | rspec (2.7.0) 17 | rspec-core (~> 2.7.0) 18 | rspec-expectations (~> 2.7.0) 19 | rspec-mocks (~> 2.7.0) 20 | rspec-core (2.7.1) 21 | rspec-expectations (2.7.0) 22 | diff-lcs (~> 1.1.2) 23 | rspec-mocks (2.7.0) 24 | rubyzip (0.9.5) 25 | selenium-webdriver (2.15.0) 26 | childprocess (>= 0.2.1) 27 | ffi (~> 1.0.9) 28 | multi_json (~> 1.0.4) 29 | rubyzip 30 | 31 | PLATFORMS 32 | ruby 33 | 34 | DEPENDENCIES 35 | jasmine 36 | -------------------------------------------------------------------------------- /spec/javascripts/support/jasmine_runner.rb: -------------------------------------------------------------------------------- 1 | $:.unshift(ENV['JASMINE_GEM_PATH']) if ENV['JASMINE_GEM_PATH'] # for gem testing purposes 2 | 3 | require 'rubygems' 4 | require 'jasmine' 5 | jasmine_config_overrides = File.expand_path(File.join(File.dirname(__FILE__), 'jasmine_config.rb')) 6 | require jasmine_config_overrides if File.exist?(jasmine_config_overrides) 7 | if Jasmine::Dependencies.rspec2? 8 | require 'rspec' 9 | else 10 | require 'spec' 11 | end 12 | 13 | jasmine_config = Jasmine::Config.new 14 | spec_builder = Jasmine::SpecBuilder.new(jasmine_config) 15 | 16 | should_stop = false 17 | 18 | if Jasmine::Dependencies.rspec2? 19 | RSpec.configuration.after(:suite) do 20 | spec_builder.stop if should_stop 21 | end 22 | else 23 | Spec::Runner.configure do |config| 24 | config.after(:suite) do 25 | spec_builder.stop if should_stop 26 | end 27 | end 28 | end 29 | 30 | spec_builder.start 31 | should_stop = true 32 | spec_builder.declare_suites 33 | -------------------------------------------------------------------------------- /UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | #SOPA 2 | 3 | We don't like it. 4 | 5 | ##What you can do 6 | 7 | Put your site on CloudFlare and then add the Stop Censorship application 8 | 9 | ###What if I'm not on CloudFlare? 10 | 11 | To test it out, use the bookmarklet on the main app page: 12 | 13 | http://mikesofaer.github.com/stop_censorship 14 | 15 | If you want to support the efforts to stop American censorship, add this to your page: 16 | 17 | ```html 18 | 19 | 20 | 35 | ``` 36 | 37 | ## Contributing 38 | 39 | This is public domain software. Submitting a patch involves releasing your patch to the public domain 40 | 41 | -------------------------------------------------------------------------------- /spec/javascripts/support/jasmine.yml: -------------------------------------------------------------------------------- 1 | # src_files 2 | # 3 | # Return an array of filepaths relative to src_dir to include before jasmine specs. 4 | # Default: [] 5 | # 6 | # EXAMPLE: 7 | # 8 | # src_files: 9 | # - lib/source1.js 10 | # - lib/source2.js 11 | # - dist/**/*.js 12 | # 13 | src_files: 14 | - public/javascripts/cloudflare.js 15 | - public/javascripts/**/*.js 16 | 17 | # stylesheets 18 | # 19 | # Return an array of stylesheet filepaths relative to src_dir to include before jasmine specs. 20 | # Default: [] 21 | # 22 | # EXAMPLE: 23 | # 24 | # stylesheets: 25 | # - css/style.css 26 | # - stylesheets/*.css 27 | # 28 | stylesheets: 29 | 30 | # helpers 31 | # 32 | # Return an array of filepaths relative to spec_dir to include before jasmine specs. 33 | # Default: ["helpers/**/*.js"] 34 | # 35 | # EXAMPLE: 36 | # 37 | # helpers: 38 | # - helpers/**/*.js 39 | # 40 | helpers: 41 | 42 | # spec_files 43 | # 44 | # Return an array of filepaths relative to spec_dir to include. 45 | # Default: ["**/*[sS]pec.js"] 46 | # 47 | # EXAMPLE: 48 | # 49 | # spec_files: 50 | # - **/*[sS]pec.js 51 | # 52 | spec_files: 53 | 54 | # src_dir 55 | # 56 | # Source directory path. Your src_files must be returned relative to this path. Will use root if left blank. 57 | # Default: project root 58 | # 59 | # EXAMPLE: 60 | # 61 | # src_dir: public 62 | # 63 | src_dir: 64 | 65 | # spec_dir 66 | # 67 | # Spec directory path. Your spec_files must be returned relative to this path. 68 | # Default: spec/javascripts 69 | # 70 | # EXAMPLE: 71 | # 72 | # spec_dir: spec/javascripts 73 | # 74 | spec_dir: 75 | -------------------------------------------------------------------------------- /public/stylesheets/stop_censorship.css: -------------------------------------------------------------------------------- 1 | body span.sopafied { 2 | display: inline !important; 3 | position: relative !important; 4 | text-decoration: none !important; 5 | color: #000 !important; 6 | text-shadow: none !important; 7 | background: #000 !important; 8 | cursor: pointer !important; 9 | margin: 0 !important; 10 | padding: 0 !important; 11 | line-height: inherit !important; 12 | } 13 | 14 | .sopa_badge { 15 | background: transparent; 16 | cursor: pointer; 17 | text-decoration: none; 18 | position: fixed; 19 | z-index: 100000; 20 | } 21 | 22 | .sopa_badge.cfcensorship_right { 23 | top: 25px; 24 | right: -63px; 25 | -webkit-transform: rotate(45deg); 26 | -moz-transform: rotate(45deg); 27 | -o-transform: rotate(45deg); 28 | -ms-transform: rotate(45deg); 29 | } 30 | 31 | .sopa_badge.cfcensorship_left { 32 | top: 25px; 33 | left: -63px; 34 | -webkit-transform:rotate(-45deg); 35 | -moz-transform:rotate(-45deg); 36 | -o-transform:rotate(-45deg); 37 | -ms-transform:rotate(-45deg); 38 | } 39 | 40 | .sopa_badge.cfcensorship_left.ie { 41 | top: 0px; 42 | right: 20px; 43 | } 44 | 45 | .sopa_badge.cfcensorship_right.ie { 46 | top: 0px; 47 | left: 20px; 48 | } 49 | 50 | .sopa_popup .senator_info { 51 | display: block; 52 | position: relative; 53 | padding: 8px; 54 | margin: 8px; 55 | border: 1px solid #e0e0e0; 56 | background: #f0f0f0; 57 | color: #808080; 58 | font-weight: 300; 59 | } 60 | .sopa_popup button { 61 | margin-top: 10px; 62 | padding: 3px; 63 | } 64 | .sopa_popup h2 { 65 | font-size: 20px; 66 | font-weight: 800; 67 | } 68 | 69 | .sopa_popup p { 70 | font-size: 14px; 71 | font-weight: 500; 72 | } 73 | 74 | .sopa_popup { 75 | font-family: 'Helvetica Neue', Arial, sans-serif !important; 76 | text-align: center; 77 | } 78 | 79 | #hyLiteDlg { 80 | border-radius: 4px; 81 | -webkit-border-radius: 4px; 82 | -moz-border-radius: 4px; 83 | -o-border-radius: 4px; 84 | -ms-border-radius: 4px; 85 | } 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /cloudflare.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Internet Defense League", 3 | "description": "Together we will make the bad guys regret their badness and from them reclaim our tubes.", 4 | "keywords" : [ 5 | "anti-censorship" 6 | ], 7 | "version": "0.0.1", 8 | "contributors": [ 9 | { 10 | "name" : "Michael Sofaer", 11 | "email" : "michael@cloudflare.com" 12 | }, 13 | { 14 | "name" : "Chris Joel", 15 | "email" : "chris@cloudflare.com" 16 | } 17 | ], 18 | "repository" : { 19 | "type" : "git", 20 | "url" : "https://github.com/fightforthefuture/internet_defense_league.git" 21 | }, 22 | "main" : "./public/javascripts/stop_censorship.js", 23 | "dependencies" : { 24 | "jquery" : "~1.7" 25 | }, 26 | "licenses" : [ 27 | { 28 | "type": "tos", 29 | "url": "http://unlicense.org" 30 | } 31 | ], 32 | "implements" : "AMD", 33 | "scripts" : { 34 | }, 35 | "config" : { 36 | "assets" : { 37 | "logos" : { 38 | "200px": "./public/images/logo-200.png", 39 | "132px": "./public/images/logo-132.png" 40 | } 41 | }, 42 | "payment": {}, 43 | "details": { 44 | "Category": "Anti-Censorship", 45 | "Language": "English", 46 | "Restrictions": "None", 47 | "Supporting": "americancensorship.org", 48 | "Script Injection": "" 49 | }, 50 | "interface": [ 51 | { 52 | "name": "Badge Position", 53 | "id": "position_x", 54 | "required": true, 55 | "description": "which side of the screen should your badge be displayed on?", 56 | "type": "select", 57 | "options": [ 58 | { 59 | "label": "Top Right", 60 | "value": "right" 61 | }, 62 | { 63 | "label": "Top Left", 64 | "value": "left" 65 | } 66 | ] 67 | }, 68 | { 69 | "id": "handle", 70 | "name": "Twitter Username", 71 | "description": "Enter your Twitter username to include it in the suggested tweet (optional). If there is no Twitter username, your site URL will be included instead.", 72 | "type": "string" 73 | }, 74 | { 75 | "id": "persistent", 76 | "name": "Persistence", 77 | "description": "Text is blacked out on first visit only. If you would like this to happen on every visit, switch to the Persistent mode.", 78 | "type": "select", 79 | "options": [ 80 | { 81 | "label": "First visit only", 82 | "value": false 83 | }, 84 | { 85 | "label": "Every visit", 86 | "value": true 87 | } 88 | ] 89 | } 90 | 91 | ] 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /spec/javascripts/stop_censorship_spec.js: -------------------------------------------------------------------------------- 1 | describe("#targetSelector", function() { 2 | it("should default to something reasonable", function(){ 3 | expect(this.sopa.config.selector).toBe("header, h1, h2, h3, p, li, span, em") 4 | }) 5 | it("should be configurable", function(){ 6 | this.sopa.config.selector = "p, h2" 7 | expect(this.sopa.config.selector).toBe("p, h2") 8 | }) 9 | }); 10 | 11 | describe("#sopafy", function(){ 12 | beforeEach(function(){ 13 | spyOn(this.sopa, "inspirationalDialog") 14 | this.page = $(""); 15 | this.target = $("
Hello I am a target for censorship.
This anchor should not be censored!") 16 | this.page.append(this.target) 17 | this.sopa.config.cookie = "__cfduid" 18 | }) 19 | describe("when there is a CDN cookie, and no censorship cookie", function(){ 20 | beforeEach(function(){ 21 | this.user.setCookie("__cfduid", "something") 22 | this.user.setCookie("cf_sopa", "") 23 | this.target.sopafy() 24 | this.sopa_wrappers = $("span.sopafied", this.target) 25 | }) 26 | it("should wrap some of the text in span tags", function(){ 27 | expect(this.sopa_wrappers.text()).toBe("Hellotargetcensorship") 28 | expect(this.target.text()).toBe("Hello I am a target for censorship. This anchor should not be censored!") 29 | }) 30 | it("should open a dialog when a span is clicked", function() { 31 | /*var spanWrapper = this.target.find('span.sopafied').eq(0); 32 | 33 | spanWrapper.click(); 34 | 35 | var dialog = this.page.find('.sopa_popup'); 36 | 37 | console.info(this.page); 38 | 39 | expect(dialog.length).toBe(1);*/ 40 | 41 | // This won't work unless we have a DOM 42 | 43 | }) 44 | it("should fire a inspirationalDialog when clicked", function(){ 45 | $(this.sopa_wrappers[0]).click(); 46 | expect(this.sopa.inspirationalDialog).toHaveBeenCalled(); 47 | }) 48 | it("should set a censorship cookie", function(){ 49 | expect(this.user.getCookie("cf_sopa")).toBe("true") 50 | }) 51 | it("should create a reminder badge", function(){ 52 | expect($(".sopa_badge").length).toBe(1); 53 | }) 54 | it("should create a reminder badge only once", function(){ 55 | this.target.sopafy() 56 | expect($(".sopa_badge").length).toBe(1); 57 | }) 58 | 59 | 60 | it("should not wrap text in an achor", function() { 61 | var sopaElementsInAnchor = this.target.eq(1).find('.sopafied') 62 | console.info(this.target); 63 | 64 | expect(sopaElementsInAnchor.length).toBe(0) 65 | }) 66 | 67 | }) 68 | describe("when there isn't a CDN cookie", function(){ 69 | beforeEach(function(){ 70 | this.target.sopafy() 71 | this.sopa_wrappers = $("span.sopafied", this.target) 72 | }) 73 | it("should not wrap the text in anchor tags", function(){ 74 | expect(this.sopa_wrappers.text()).toBe("") 75 | expect(this.target.text()).toBe("Hello I am a target for censorship. This anchor should not be censored!") 76 | }) 77 | it("should create a reminder badge", function(){ 78 | expect($(".sopa_badge").length).toBe(1); 79 | }) 80 | }) 81 | describe("when there is a censorship cookie", function(){ 82 | beforeEach(function(){ 83 | this.user.setCookie("__cfduid", "something") 84 | this.user.setCookie("cf_sopa", "true") 85 | }) 86 | describe("and persistent mode is not on", function(){ 87 | beforeEach(function(){ 88 | this.target.sopafy() 89 | this.sopa_wrappers = $("span.sopafied", this.target) 90 | }) 91 | it("should not wrap the text in anchor tags", function(){ 92 | expect(this.sopa_wrappers.text()).toBe("") 93 | expect(this.target.text()).toBe("Hello I am a target for censorship. This anchor should not be censored!") 94 | }) 95 | it("should create a reminder badge", function(){ 96 | expect($(".sopa_badge").length).toBe(1); 97 | }) 98 | }) 99 | describe("and persistent mode is on", function(){ 100 | beforeEach(function(){ 101 | this.sopa.config.persistent = true 102 | this.target.sopafy() 103 | this.sopa_wrappers = $("span.sopafied", this.target) 104 | }) 105 | it("should wrap the text in anchor tags", function(){ 106 | expect(this.sopa_wrappers.text()).toBe("Hellotargetcensorship") 107 | expect(this.target.text()).toBe("Hello I am a target for censorship. This anchor should not be censored!") 108 | }) 109 | it("should create a reminder badge", function(){ 110 | expect($(".sopa_badge").length).toBe(1); 111 | }) 112 | }) 113 | 114 | }) 115 | }) 116 | 117 | describe("inspirationalDialog", function(){ 118 | beforeEach(function(){ 119 | spyOn($, "liteDialog"); 120 | this.target = $("Hello I am a target for censorship.") 121 | $("#jasmine_content").html(this.target) 122 | }) 123 | it("should create a dialog", function(){ 124 | this.sopa.inspirationalDialog(); 125 | expect($.liteDialog).toHaveBeenCalled(); 126 | }) 127 | it("should create a reminder badge", function(){ 128 | this.sopa.inspirationalDialog(); 129 | expect($(".sopa_badge").length).toBe(1); 130 | }) 131 | describe("when not in persistent mode", function(){ 132 | it("should unsopafy the page", function(){ 133 | this.sopa.config.persistent = false 134 | this.sopa.inspirationalDialog() 135 | expect($("#jasmine_content span.sopafied").length).toBe(0) 136 | expect($("#jasmine_content").text()).toBe("Hello I am a target for censorship.") 137 | }) 138 | }) 139 | describe("when in persistent mode", function(){ 140 | it("should unsopafy the page", function(){ 141 | this.sopa.config.persistent = true 142 | this.sopa.inspirationalDialog() 143 | console.info($("#jasmine_content span.sopafied")) 144 | expect($("#jasmine_content span.sopafied").length).toBe(1) 145 | expect($("#jasmine_content").text()).toBe("Hello I am a target for censorship.") 146 | }) 147 | }) 148 | }) 149 | 150 | describe("protestContent", function(){ 151 | describe("default", function(){ 152 | beforeEach(function(){ 153 | this.sopa.config.twitterHandle = "handle" 154 | this.content = this.sopa.protestContent(); 155 | }) 156 | it("should have a call to action", function(){ 157 | expect(this.content.text()).toContain("Help Protect Freedom.") 158 | }) 159 | xit("should have the twitter handle", function(){ 160 | expect(this.content.text()).toContain("handle") 161 | }) 162 | it("should have a dropdown list of senators", function(){ 163 | expect(this.content.text()).not.toContain("907-456-0233") 164 | this.content.find("select").val("AK").change() 165 | expect(this.content.text()).toContain("907-456-0233") 166 | }) 167 | it("should have a button to restore the bars", function(){ 168 | spyOn(this.user, "setCookie") 169 | spyOn($.fn, "sopafy") 170 | $(this.content.find(".recensor")).click() 171 | expect(this.user.setCookie.calls[0].args).toEqual(["cf_sopa", ""]) 172 | expect($.fn.sopafy).toHaveBeenCalled() 173 | }) 174 | it("should have a link to the PIPA video", function(){ 175 | expect(this.content.html()).toContain("http://fightforthefuture.org/pipa") 176 | }) 177 | 178 | }) 179 | }) 180 | 181 | describe("badge", function(){ 182 | beforeEach(function(){ 183 | this.badge = this.sopa.badge() 184 | }) 185 | it("should open the dialog", function(){ 186 | spyOn(this.sopa, "inspirationalDialog") 187 | this.badge.click() 188 | expect(this.sopa.inspirationalDialog).toHaveBeenCalled() 189 | }) 190 | }) 191 | 192 | describe("styleSheet", function(){ 193 | beforeEach(function(){ 194 | this.styleSheet = this.sopa.styleSheet() 195 | $("head").append(this.styleSheet) 196 | }) 197 | describe("badge", function(){ 198 | beforeEach(function(){ 199 | this.badge = this.sopa.badge() 200 | $("#jasmine_content").append(this.badge) 201 | }) 202 | /*it("should have high z-index", function(){ 203 | expect(this.badge.css("z-index")).toBe("100000") 204 | })*/ 205 | }) 206 | afterEach(function(){ 207 | this.styleSheet.remove() 208 | }) 209 | }) 210 | 211 | describe("tweetWindow", function(){ 212 | beforeEach(function(){ 213 | spyOn(window, "open") 214 | this.sopa.tweetWindow({ 215 | text: "te>xt", 216 | url: "url", 217 | hashtag: "hashtag" 218 | }) 219 | this.tweet = window.open.calls[0].args[0] 220 | }) 221 | it("should have the right text", function(){ 222 | expect(this.tweet).toContain("text=te%3Ext") 223 | }) 224 | it("should have the right url", function(){ 225 | expect(this.tweet).toContain("url=url") 226 | }) 227 | it("should have the right hashtag", function(){ 228 | expect(this.tweet).toContain("hashtags=hashtag") 229 | }) 230 | it("should have the right via", function(){ 231 | expect(this.tweet).toContain("via=cloudflare") 232 | }) 233 | }) 234 | -------------------------------------------------------------------------------- /public/javascripts/stop_censorship.js: -------------------------------------------------------------------------------- 1 | CloudFlare.define( 2 | "stop_censorship", 3 | ["cloudflare/jquery1.7", "cloudflare/user", "cloudflare/dom", "cloudflare/path", "cloudflare/console", "stop_censorship/config"], 4 | function($, user, dom, path, console, _config) { 5 | 6 | var SopaProtest = function SopaProtest(config){ 7 | var self=this 8 | self.config = config 9 | if (config.onCloudflare) { 10 | self.cookie = "__cfduid" 11 | } 12 | } 13 | 14 | var cdnPath = "//ajax.cloudflare.com/cdn-cgi/nexp/"; 15 | 16 | var config = $.extend({ 17 | selector : "header, h1, h2, h3, p, li, span, em", 18 | position_x : "right", 19 | onCloudflare : false, 20 | regex : '.{5}' 21 | }, _config) 22 | 23 | config.regex = new RegExp(config.regex) 24 | 25 | var sopaProtest = new SopaProtest(config) 26 | 27 | //jquery.liteDialog 28 | ;(function(a){var p="hyLite";function c(e){e.keyCode===27&&a.liteDialog("hide")}var d={init:function(e){var b={html:"",modal:!1,shadow:"#000",shadowRadius:"25px",background:"#FFF",color:"#000",width:"300px",padding:"10px",zIndex:9000};e&&a.extend(b,e);a("#"+p+"Shdw").length===0&&a("
").hide().css({height:a(document).height(),width:a(document).width()}).appendTo(document.body);a("#"+p+"Dlg").length===0&&a("
").hide().appendTo(document.body); a("#"+p+"Shdw").css({background:b.shadow,'z-index':b.zIndex}).fadeTo("fast",0.4);a("#"+p+"Dlg").html(b.html).width(b.width).css({"box-shadow":"0px 0px "+b.shadowRadius+" "+b.shadow,"-moz-box-shadow":"0px 0px "+b.shadowRadius+" "+b.shadow,"-webkit-box-shadow":"0px 0px "+b.shadowRadius+" "+b.shadow,color:b.color,background:b.background,padding:b.padding,top:(a(window).height()-a("#"+p+"Dlg").outerHeight())/2+a(window).scrollTop(),left:(a(window).width()-a("#"+p+"Dlg").outerWidth())/2+a(window).scrollLeft(),'z-index':b.zIndex}).fadeIn(); b.modal?(a("#"+p+"Shdw, #"+p+"Dlg").unbind(),a(document).unbind("keyup",c)):(a("#"+p+"Shdw, #"+p+"Dlg").click(function(){a.liteDialog("hide")}),a(document).keyup(c))},hide:function(){a("#"+p+"Shdw, #"+p+"Dlg").fadeOut()}};a.liteDialog=a.fn.liteDialog=function(a){return d[a]?d[a].apply(this,Array.prototype.slice.call(arguments,1)):typeof a==="object"||!a?d.init.apply(this,arguments):d.init.apply(this,[{html:a}])}})($); 29 | 30 | 31 | $.extend(SopaProtest.prototype, { 32 | badge : function(){ 33 | var self = this, 34 | side = /^right$|^left$/i.test(self.config.position_x) ? self.config.position_x.toLowerCase() : 'right'; 35 | 36 | return $("") 37 | .bind("click", function(){ self.inspirationalDialog() }) 38 | }, 39 | placeBadge : function(){ 40 | if(!$("body").find(".sopa_badge").length) { 41 | $("body").append(this.badge()) 42 | } 43 | }, 44 | 45 | tweetWindow : function(options) { 46 | window.open( 47 | "https://twitter.com/intent/tweet?original_referer=http%3A%2F%2Fcloudflare.com"+ 48 | "&text="+encodeURIComponent(options.text)+ 49 | "&url="+encodeURIComponent(options.url)+ 50 | "&hashtags="+encodeURIComponent(options.hashtag)+ 51 | "&via=cloudflare", 52 | "_blank", 53 | "height=450,left=445,personalbar=0,resiable=1,scrollbars=1,toolbar=0,top=225,width=550" 54 | ); 55 | }, 56 | 57 | senatorDropdown: function(){ 58 | var senators =[["AK","Lisa Murkowski","907-456-0233"],["AK","Mark Begich","907-271-5915"],["AL","Jefferson Sessions","334-244-7017"],["AL","Richard Shelby","205-759-5047"],["AR","John Boozman","479-725-0400"],["AR","Mark Pryor","501-324-6336"],["AZ","Jon Kyl","602-840-1891"],["AZ","John McCain","602-952-2410"],["CA","Barbara Boxer","510-286-8537"],["CA","Dianne Feinstein","415-393-0707"],["CO","Michael Bennet","303-455-7600"],["CO","Mark Udall","303-650-7820"],["CT","Richard Blumenthal","860-258-6940"],["CT","Joseph Lieberman","860-549-8463"],["DE","Thomas Carper","302-573-6291"],["DE","Chris Coons","302-573-6345"],["FL","Bill Nelson","407-872-7161"],["FL","Marco Rubio","305-418-8553"],["GA","C. Saxby Chambliss","770-763-9090"],["GA","John Isakson","770-661-0999"],["HI","Daniel Akaka","808-522-8970"],["HI","Daniel Inouye","808-541-2542"],["IA","Charles Grassley","515-288-1145"],["IA","Thomas Harkin","515-284-4574"],["ID","Michael Crapo","208-334-1776"],["ID","James Risch","208-342-7985"],["IL","Richard Durbin","312-353-4952"],["IL","Mark Kirk","312-886-3506"],["IN","Daniel Coats","317-554-0750"],["IN","Richard Lugar","317-226-5555"],["KS","Pat Roberts","913-451-9343"],["KY","Mitch McConnell","502-582-6304"],["KY","Rob Portman","361-576-1231"],["LA","Mary Landrieu","225-389-0395"],["LA","David Vitter","337-262-6898"],["MA","Scott Brown","617-565-3170"],["MA","John Kerry","617-565-8519"],["MD","Barbara Mikulski","410-962-4510"],["ME","Susan Collins","207-945-0417"],["ME","Olympia Snowe","207-874-0883"],["MI","Carl Levin","313-226-6020"],["MI","Debbie Stabenow","517-203-1760"],["MN","Al Franken","651-221-1016"],["MN","Amy Klobuchar","612-727-5220"],["MO","Roy Blunt","816-471-7141"],["MO","Claire McCaskill","816-421-1639"],["MS","Thad Cochran","601-965-4459"],["MS","Roger Wicker","601-965-4644"],["MT","Max Baucus","406-657-6790"],["MT","Jon Tester","406-449-5401"],["NC","Richard Burr","910-251-1058"],["NC","Kay Hagan","336-333-5311"],["ND","Kent Conrad","701-258-4648"],["ND","John Hoeven","701-250-4618"],["NE","Mike Johanns","308-632-6032"],["NE","E. Benjamin Nelson","402-441-4600"],["NH","Kelly Ayotte","603-622-7979"],["NH","Jeanne Shaheen","603-647-7500"],["NJ","Frank Lautenberg","973-639-8700"],["NJ","Robert Menendez","973-645-3030"],["NM","Jeff Bingaman","505-346-6601"],["NM","Tom Udall","505-346-6791"],["NV","Dean Heller","775-686-5770"],["NV","Harry Reid","702-388-5020"],["NY","Kirsten Gillibrand","212-688-6262"],["NY","Charles Schumer","212-486-4430"],["OH","Sherrod Brown","216-522-7272"],["OK","James Inhofe","918-748-5111"],["OK","Tom Coburn","918-581-7651"],["OR","Jeffery Merkley","503-326-3386"],["PA","Robert Casey","570-941-0930"],["PA","Pat Toomey","610-434-1444"],["RI","John Reed","401-943-3100"],["RI","Sheldon Whitehouse","401-453-5294"],["SC","Jim DeMint","864-233-5366"],["SC","Lindsey Graham","864-250-1417"],["SD","Tim Johnson","414-276-7282"],["SD","John Thune","605-334-9596"],["TN","Lamar Alexander","615-736-5129"],["TN","Bob Corker","423-756-2757"],["TX","John Cornyn","512-469-6034"],["TX","Kay Hutchison","214-361-3500"],["UT","Orrin Hatch","801-524-4380"],["UT","Mike Lee","801-524-5933"],["VA","Mark Warner","804-775-2314"],["VA","James Webb","804-771-2221"],["VT","Patrick Leahy","802-863-2525"],["VT","Bernard Sanders","802-862-0697"],["WA","Patty Murray","206-553-5545"],["WI","Ron Johnson","605-332-8896"],["WI","Herbert Kohl","414-297-4451"],["WV","Joe Manchin","304-342-5855"],["WV","John Rockefeller","304-347-5372"],["WY","John Barrasso","307-261-6413"],["WY","Michael Enzi","307-682-6268"]] 59 | var senatorsByState = {} 60 | $.each(senators, function(i, senator){ 61 | var state = $.trim(senator[0]); 62 | 63 | senatorsByState[state] = senatorsByState[state] || []; 64 | senatorsByState[state].push(senator.slice(1)); 65 | 66 | }) 67 | var target = $("
") 68 | var dropdown = $("