├── .gitignore ├── CODE_OF_CONDUCT.md ├── README.md ├── activity-stream ├── fxa.html ├── mofo-eoy-2017.html ├── newsletter-subscribe.html ├── send-to-device-card.html ├── send-to-device.html ├── simple-snippet.html └── simple-video-snippet.html ├── campaigns ├── 10th-anniversary-video │ ├── 10th-anniversary-video-no-share.html │ └── 10th-anniversary-video.html ├── 10th-anniversary │ ├── 10th-anniversary-flare1.png │ ├── 10th-anniversary-flare2.png │ ├── 10th-anniversary-flare3.png │ ├── 10th-anniversary-heart1.png │ ├── 10th-anniversary-heart2.png │ ├── 10th-anniversary-no-share.html │ ├── 10th-anniversary.html │ └── README.md ├── android-push-play-shop │ ├── README.md │ ├── phone-icon.png │ ├── play │ │ ├── snippet-play-fromParticle.html │ │ └── snippet-play.html │ ├── push │ │ ├── snippet-push-fromParticle.html │ │ └── snippet-push.html │ └── shop │ │ ├── snippet-shop-fromParticle.html │ │ └── snippet-shop.html ├── hello │ ├── README.md │ ├── animation-snippet-cdn.html │ ├── animation-snippet-embedded.html │ └── simple-snippet.html ├── humble-bundle │ ├── ftl.html │ ├── humble-carts.html │ └── vox-snippet.html ├── mass-surveillance-snippet │ └── snippet.html ├── mobile │ ├── mobile-snippet-widget-200.html │ ├── mobile-snippet-widget-qr.html │ └── mobile-snippet-widget.html ├── mofo-eoy-2014 │ ├── deliverable │ │ └── snippet-embeddable.html │ └── deliverables │ │ └── eoy2-deliverable.html ├── mofo-eoy-2015 │ └── snippet.html ├── mofo-eoy-2016 │ └── snippet.html ├── mofo-spectacular-1-eoy-2015 │ └── snippet.html ├── mofo-spectacular-2-eoy-2015 │ └── snippet.html ├── mofo-spectacular-3-eoy-2015 │ └── snippet.html ├── net-neutrality-comments │ └── snippet.html ├── pocket │ ├── pocket_1.html │ ├── pocket_2.html │ └── simple.html ├── private-browsing │ ├── logo-swap.html │ └── simple.html ├── sms-android │ ├── android-email-sms-configure.html │ └── android-email-sms.html ├── sopa │ ├── .gitignore │ ├── README.md │ ├── build │ │ └── .gitignore │ ├── content.html │ ├── css │ │ ├── .gitignore │ │ └── styles.css │ ├── fabfile.py │ ├── images │ │ ├── .gitignore │ │ ├── bg.png │ │ ├── icon.png │ │ └── stop_censorship.png │ ├── requirements.txt │ ├── scripts │ │ ├── .gitignore │ │ └── code.js │ └── snippet_template.html ├── thank-you │ └── snippet.html └── windows-10 │ └── default-browser-large-cta.html ├── generic-templates ├── addon_install_snippet.html ├── fxos-logo-animation │ ├── fox-animation.png │ ├── fxos-logo-animation-old.html │ └── fxos-logo-animation.html ├── heartbeat-survey.html ├── logo-swap-with-share.html ├── newsletter-signup-snippet │ └── snippet.html ├── simple-snippet.html └── video-snippets │ ├── share-over-search-bar.html │ └── simple-over-search-bar.html ├── legacy ├── beta-share-snippet │ ├── .gitignore │ ├── README.md │ ├── build │ │ └── .gitignore │ ├── content.html │ ├── css │ │ ├── .gitignore │ │ └── styles.css │ ├── fabfile.py │ ├── images │ │ ├── .gitignore │ │ ├── facebook.png │ │ ├── firefox_beta.png │ │ └── twitter.png │ ├── requirements.txt │ ├── scripts │ │ ├── .gitignore │ │ └── popup.js │ └── snippet_template.html ├── blank-snippet │ ├── .gitignore │ ├── README.md │ ├── build │ │ └── .gitignore │ ├── content.html │ ├── css │ │ └── .gitignore │ ├── fabfile.py │ ├── images │ │ └── .gitignore │ ├── requirements.txt │ ├── scripts │ │ ├── .gitignore │ │ └── blank.js │ └── snippet_template.html ├── flicks-2012-video │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── content.html │ ├── fabfile.py │ ├── images │ │ ├── .gitkeep │ │ ├── close.png │ │ ├── facebook.png │ │ ├── flicks.png │ │ ├── play.png │ │ ├── replay.png │ │ ├── share.png │ │ ├── share_white.png │ │ └── twitter.png │ ├── requirements.txt │ ├── script.js │ └── styles.less ├── july2012 │ ├── README.md │ ├── images │ │ ├── cauldron.png │ │ ├── close.png │ │ ├── flags │ │ │ ├── 40x50_Argentina.png │ │ │ ├── 40x50_Brazil.png │ │ │ ├── 40x50_China.png │ │ │ ├── 40x50_FFlogo.png │ │ │ ├── 40x50_France.png │ │ │ ├── 40x50_Germany.png │ │ │ ├── 40x50_India.png │ │ │ ├── 40x50_Indonesia.png │ │ │ ├── 40x50_Italy.png │ │ │ ├── 40x50_Japan.png │ │ │ ├── 40x50_Mexico.png │ │ │ ├── 40x50_Phillipines.png │ │ │ ├── 40x50_PlayIcon.png │ │ │ ├── 40x50_Russia.png │ │ │ ├── 40x50_Spain.png │ │ │ ├── 40x50_Taiwan.png │ │ │ ├── 40x50_UK.png │ │ │ └── icons-base64.txt │ │ ├── flame-bits.png │ │ ├── frame-five.png │ │ ├── frame-four.png │ │ ├── frame-one.png │ │ ├── frame-three.png │ │ └── frame-two.png │ ├── snippet-fromParticle.html │ ├── snippet-persona.html │ └── snippet-video.html ├── jumping-fox-game │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── crafty.js │ ├── game.js │ ├── index.html │ ├── scripts │ │ ├── compile.py │ │ └── replace_script_tags.py │ └── sprites.png ├── logo-swap-about-accounts-links.html ├── persona-switcher │ ├── README.md │ ├── about-home-persona-switcher.html │ └── snippet.html ├── pianno-snippet │ ├── .gitignore │ ├── README.md │ ├── content.html │ ├── css │ │ └── styles.css │ ├── fabfile.py │ ├── sampledata.html │ ├── scripts │ │ └── code.js │ └── snippet_template.html └── split-snippet │ ├── README.md │ └── snippet.html ├── standard-css ├── README.md └── legacy-css.html └── standard-js ├── README.md └── snippet.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Participation Guidelines 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette guidelines. 4 | For more details, please read the 5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 6 | 7 | ## How to Report 8 | For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page. 9 | 10 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # about:home Snippets 2 | 3 | This repo contains code for standard and interactive snippets that we share 4 | on the about:home page in Firefox pre version 56. 5 | 6 | ## License 7 | 8 | Any copyright is dedicated to the Public Domain. 9 | http://creativecommons.org/publicdomain/zero/1.0/ 10 | -------------------------------------------------------------------------------- /activity-stream/fxa.html: -------------------------------------------------------------------------------- 1 | {# 2 | Activity Stream snippet for FxA sign up/sign in. 3 | 4 | Variables: 5 | 6 | @scene1_icon: image, optional - Snippet icon. 64x64px. SVG or PNG preferred. 7 | @scene1_button_label: text - Text for the button next to main text that opens the email form. 8 | @scene1_button_background_color: hash, optional - Button background color. Default #D7D7DB. 9 | @scene1_button_color: hash, optional - Button text color. Default #0C0C0D. 10 | @scene1_text: text - Text for scene1/initial view of the snippet. 11 | @scene1_title: text, optional - Title displayed before scene1_text. 12 | @scene1_title_icon: image, optional - Title icon. 16x16px. SVG or PNG preferred. Grayscale. 13 | 14 | @scene2_text: text - Text for scene2/form view. 15 | @scene2_title: text, optional - Title displayed before scene2_text. 16 | @scene2_email_placeholder_text: text, optional - Placeholder text for email field. Default 'YOUR EMAIL HERE'. 17 | @scene2_button_label: text, optional - Text for form submit button. Default 'Sign Me Up'. 18 | @scene2_dismiss_button_text: text, optional - Text for dismiss button in footer of form/scene2. Default 'Dismiss'. 19 | 20 | @utm_campaign: text, optional - Value to pass through to GA as utm_campaign. 21 | @utm_term: text, optional - Value to pass through to GA as utm_term. 22 | #} 23 | 222 | 223 |
224 |
225 |
226 | {% if scene1_icon %} 227 | snippet icon 228 | {% endif %} 229 | 230 |
231 | {% if scene1_title %} 232 |

{{ scene1_title }}

233 | {% endif %} 234 |

{{ scene1_text|safe }}

235 |
236 | 237 | 238 | 239 | 240 |
241 |
242 | 243 | 280 |
281 | 282 | 322 | -------------------------------------------------------------------------------- /activity-stream/simple-snippet.html: -------------------------------------------------------------------------------- 1 | {# 2 | Simple Snippet for Activity Stream with button option. 3 | 4 | Variables: 5 | 6 | @icon: image, optional - Snippet icon. 64x64px. SVG or PNG preferred. 7 | @button_label: text, optional - Text for a button next to main snippet text that links to button_url. Requires button_url. 8 | @button_url: text, optional - A url, button_label links to this. 9 | @button_background_color: hash, optional - Button background color. Default #D7D7DB. 10 | @button_color: hash, optional - Button text color. Default #0C0C0D. 11 | @text: text - Text of snippet. 12 | @title: text, optional - Snippet title displayed above snippet text. 13 | @title_icon: image, optional - Title icon. 16x16px. SVG or PNG preferred. Grayscale. 14 | 15 | @tall: checkbox, optional - Fundraising only, increases height to roughly 120px. 16 | #} 17 | 108 | 109 |
110 | {% if icon %} 111 | snippet icon 112 | {% endif %} 113 | 114 |
115 | {% if title %} 116 |

{{ title }}

117 | {% endif %} 118 |

{{ text|safe }}

119 |
120 | 121 | {% if button_label and button_url %} 122 | {{ button_label }} 123 | {% endif %} 124 | 125 | 127 |
128 | -------------------------------------------------------------------------------- /activity-stream/simple-video-snippet.html: -------------------------------------------------------------------------------- 1 | {# 2 | Activity Stream snippet for simple video display. 3 | 4 | Variables: 5 | 6 | @scene1_icon: image, optional - Snippet icon. 64x64px. SVG or PNG preferred. 7 | @scene1_button_label: text - Text for the button next to main text that displays the video. Default 'Watch'. 8 | @scene1_button_background_color: hash, optional - Button background color. Default #D7D7DB. 9 | @scene1_button_color: hash, optional - Button text color. Default #0C0C0D. 10 | @scene1_text: text - Text for scene1/initial view of the snippet. 11 | @scene1_title: text, optional - Title displayed before scene1_text. 12 | 13 | @close_video_button_text: text, optional - Text for video modal close button in footer of scene2. Default 'Done'. 14 | 15 | @video_url: text - URL to .webm version of the video. Must be .webm format! 16 | #} 17 | 162 | 163 |
164 |
165 |
166 | {% if scene1_icon %} 167 | snippet icon 168 | {% endif %} 169 | 170 |
171 | {% if scene1_title %} 172 |

{{ scene1_title }}

173 | {% endif %} 174 |

{{ scene1_text|safe }}

175 |
176 | 177 | 178 | 179 | 180 |
181 |
182 | 183 | 198 |
199 | 200 | 237 | -------------------------------------------------------------------------------- /campaigns/10th-anniversary/10th-anniversary-flare1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/10th-anniversary/10th-anniversary-flare1.png -------------------------------------------------------------------------------- /campaigns/10th-anniversary/10th-anniversary-flare2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/10th-anniversary/10th-anniversary-flare2.png -------------------------------------------------------------------------------- /campaigns/10th-anniversary/10th-anniversary-flare3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/10th-anniversary/10th-anniversary-flare3.png -------------------------------------------------------------------------------- /campaigns/10th-anniversary/10th-anniversary-heart1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/10th-anniversary/10th-anniversary-heart1.png -------------------------------------------------------------------------------- /campaigns/10th-anniversary/10th-anniversary-heart2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/10th-anniversary/10th-anniversary-heart2.png -------------------------------------------------------------------------------- /campaigns/10th-anniversary/README.md: -------------------------------------------------------------------------------- 1 | # 10th Anniversary Snippet Template 2 | 3 | This template was made for the 10th anniversary celebration on November 10th, 4 | 2014. 5 | -------------------------------------------------------------------------------- /campaigns/android-push-play-shop/README.md: -------------------------------------------------------------------------------- 1 | # about:home Snippets for Android SMS campaign 2 | 3 | This campaign promotes Firefox for Android. There are three snippets, 4 | each with a different animated sequence. 5 | 6 | * "Push" - The android appears as a small icon. When activated, he 7 | vanishes in a puff of smoke and reappears much larger next to the logo. 8 | The android turns and squeezes the logo down to size and appears to push it 9 | into a mobile phone that grows from behind the logo. The android then turns 10 | back to face the viewer, and with another puff of smoke goes back to his 11 | former size and position as an icon. 12 | 13 | * "Play" - The android peeks from behind the search field. On activation, 14 | he leaps up and off the top of the screen, pulling down a mobile phone. 15 | The logo then shrinks down to appear on the phone's screen as the 16 | android passes behind the phone, leaning out to wave at the viewer. 17 | 18 | * "Shop" - The android peeks from behind the search field. On activation, 19 | he pops up and turns to lift a shopping bag (bearing the Google 20 | Playlogo) from behind the search field. The Firefox logo lowers into the bag 21 | and a mobile phone (showing the logo) rises from the bag to take its place. 22 | The shopping bag lowers out of view as the android passes behind the phone 23 | to wave at the viewer. 24 | 25 | The CSS animation was done by Particle (particularplace.com), and their original, 26 | unminified code is also included with each snippet for reference. 27 | 28 | For the en-US locale, the link leads to a web page where a user can enter 29 | his or her mobile phone number and a link to the Google Play store will be 30 | sent to their phone automatically. Because this SMS service is currently 31 | only available in the US, snippets for other locales link directly to the 32 | Google Play store. 33 | 34 | # Localized Strings 35 | 36 | ## For English locales: 37 | 38 | ### Push: 39 | Fast. Smart. Safe. Put Firefox on your Android phone. 40 | 41 | ### Play: 42 | Fast. Smart. Safe. It's never been easier to put Firefox on your Android phone. 43 | 44 | ### Shop: 45 | Fast. Smart. Safe. Get the mobile browser that's got your back. 46 | 47 | 48 | ## All other locales use the same text for all three snippets 49 | 50 | ### es-ES 51 | Rápido. Inteligente. Seguro. Obtén el navegador para dispositivos móviles que te protege. Obtén Firefox para Android. 52 | 53 | ### de 54 | Schnell. Intelligent. Sicher. Holen Sie sich den mobilen Browser, der Sie beschützt. 55 | 56 | ### it 57 | Veloce. Intelligente. Sicuro. Installa il browser mobile che si preoccupa solo di te. 58 | 59 | ### ru 60 | Быстрый. Умный. Безопасный. Установите мобильный браузер, надёжно прикрывающий вашу спину. 61 | 62 | ### cs 63 | Rychlý. Chytrý. Bezpečný. Získejte mobilní prohlížeč co vám kryje záda. 64 | 65 | ### ko 66 | 빠르고. 똑똑하고. 안전한. 새로운 모바일 브라우저가 돌아왔습니다. 67 | 68 | ### fr 69 | Rapide. Sûr. Malin. Adoptez le navigateur mobile qui assure vos arrières. 70 | 71 | ### nl 72 | Snel. Slim. Veilig. Kies de mobiele browser die u beschermt. 73 | 74 | ### pt-BR 75 | Rápido. Inteligente. Seguro. Use o navegador que se preocupa com você. 76 | 77 | ### pl 78 | Szybka. Innowacyjna. Bezpieczna. Pobierz przeglądarkę, która jest po Twojej stronie. 79 | 80 | ### nb-NO 81 | Rask. Smart. Sikker. Last ned den mobile nettleseren som passer på deg. 82 | 83 | ## License 84 | 85 | Any copyright is dedicated to the Public Domain. 86 | http://creativecommons.org/publicdomain/zero/1.0/ 87 | -------------------------------------------------------------------------------- /campaigns/android-push-play-shop/phone-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/android-push-play-shop/phone-icon.png -------------------------------------------------------------------------------- /campaigns/hello/README.md: -------------------------------------------------------------------------------- 1 | animation-snippet-cdn.html and animation-snippet-embedded.html are the 2 | same with the only difference being that the first serves the animation 3 | over cdn and the second embeds it into the snippet using a variable. 4 | We shipped the later. 5 | -------------------------------------------------------------------------------- /campaigns/hello/animation-snippet-cdn.html: -------------------------------------------------------------------------------- 1 | 3 |
4 | 49 | 50 |
51 |

{{ text|safe }}

52 | 53 | {{ buttonLabel|safe }} 54 | 55 |
56 |
57 | 58 | 275 | -------------------------------------------------------------------------------- /campaigns/hello/animation-snippet-embedded.html: -------------------------------------------------------------------------------- 1 | 3 |
4 | 51 | 52 |
53 |

{{ text|safe }}

54 | 55 | {{ buttonLabel|safe }} 56 | 57 |
58 |
59 | 60 | 270 | -------------------------------------------------------------------------------- /campaigns/hello/simple-snippet.html: -------------------------------------------------------------------------------- 1 | 3 | 4 |
5 | 6 | 7 | 8 |

{{ text|safe }}

9 | 10 | 215 |
216 | -------------------------------------------------------------------------------- /campaigns/mofo-eoy-2014/deliverable/snippet-embeddable.html: -------------------------------------------------------------------------------- 1 |
2 | 139 | 140 |

{{ text|safe }}

141 | 142 |
143 | 144 | 145 | 146 |
147 | 148 | 149 | 150 | 209 |
210 | -------------------------------------------------------------------------------- /campaigns/mofo-eoy-2014/deliverables/eoy2-deliverable.html: -------------------------------------------------------------------------------- 1 |
2 | 143 | 144 |
145 |
146 | 147 |
148 |
149 |

{{ text|safe }}

150 | 151 |
152 |
153 |
{{ selectAmount|safe }}
154 | 155 |
156 | 157 | 158 | 159 |
160 |
161 | 162 |
163 |
{{ paymentMethod|safe }}
164 | 165 | 173 |
174 |
175 | 176 | 179 |
180 |
181 | 182 | 281 |
282 | -------------------------------------------------------------------------------- /campaigns/private-browsing/simple.html: -------------------------------------------------------------------------------- 1 | 65 | 66 |
67 | {% if blockable %} 68 |
69 |
70 | {% endif %} 71 | {% if blockable or clickable %} 72 |
73 |
74 | {% endif %} 75 | 76 | 77 | 78 |

{{ text|safe }}

79 |
80 | 81 | 147 | -------------------------------------------------------------------------------- /campaigns/sopa/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | !build/.gitignore 3 | *~ 4 | *.pyc 5 | .snippetconfig 6 | *.pyc 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /campaigns/sopa/README.md: -------------------------------------------------------------------------------- 1 | # SOPA Blackout Snippet 2 | 3 | This is the blackout snippet we used to black out the about:home page for 4 | every Firefox user on January 18th. 5 | 6 | See the 7 | [Snippet Development Template](https://github.com/Osmose/snippet-dev-template) 8 | for info on how to work on this. 9 | -------------------------------------------------------------------------------- /campaigns/sopa/build/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/sopa/build/.gitignore -------------------------------------------------------------------------------- /campaigns/sopa/content.html: -------------------------------------------------------------------------------- 1 |

Mozilla is joining the virtual strike against Internet censorship. Help us fight SOPA/PIPA - take action today!

2 | 3 |
4 | 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /campaigns/sopa/css/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/sopa/css/.gitignore -------------------------------------------------------------------------------- /campaigns/sopa/css/styles.css: -------------------------------------------------------------------------------- 1 | #doom_container { 2 | display: none; 3 | } 4 | 5 | #brandStart { 6 | position: relative; 7 | } 8 | 9 | #black_bar_of_doom { 10 | position: absolute; 11 | left: -moz-calc(50% - 113px); 12 | top: -moz-calc(47% - 16px); 13 | -moz-transform: rotate(-5deg); 14 | } 15 | 16 | body { 17 | -moz-transition: 1s linear; 18 | } 19 | 20 | body.dark { 21 | background: #181818; 22 | } 23 | 24 | body.dark #searchText { 25 | background: #181818; 26 | color: #BBB; 27 | } 28 | 29 | body.dark #contentContainer { 30 | background: none; 31 | } 32 | 33 | body.dark a { 34 | color: #990000; 35 | } 36 | 37 | body.dark #snippets, 38 | body.dark #snippets:hover, 39 | body.dark #snippets:hover:active { 40 | color: #BBB; 41 | background: none; 42 | } 43 | -------------------------------------------------------------------------------- /campaigns/sopa/fabfile.py: -------------------------------------------------------------------------------- 1 | # TODO: Determine how to organize code 2 | # TODO: Figure out a better way to edit the DB 3 | 4 | import base64 5 | import ConfigParser 6 | import os 7 | import pystache 8 | import select 9 | import sqlite3 10 | 11 | from fabric.decorators import task 12 | from glob import glob 13 | from os.path import isfile 14 | 15 | BUILD_DIR = 'build' 16 | BUILD_JS_FILE = BUILD_DIR + '/compiled.min.js' 17 | BUILD_CSS_FILE = BUILD_DIR + '/compiled.css' 18 | BUILD_CONTENT_FILE = BUILD_DIR + '/compiled.html' 19 | BUILD_OUT_FILE = BUILD_DIR + '/snippet.html' 20 | 21 | SCRIPTS_DIR = 'scripts' 22 | CSS_DIR = 'css' 23 | IMAGES_DIR = 'images' 24 | 25 | SNIPPET_TEMPLATE_FILE = 'snippet_template.html' 26 | SNIPPET_CONTENT_FILE = 'content.html' 27 | 28 | config = ConfigParser.ConfigParser() 29 | config.read('.snippetconfig') 30 | database_present = config.has_section('Database') 31 | 32 | 33 | @task 34 | def monitor_build_push(): 35 | """ 36 | Monitors the current directory for changes and pushes when they happen 37 | """ 38 | 39 | monitor = DirectoryMonitor('./') 40 | print "Monitoring for changes..." 41 | 42 | while True: 43 | if monitor.is_directory_changed(): 44 | print "Change detected, pushing..." 45 | build_all_push() 46 | 47 | 48 | class DirectoryMonitor: 49 | def __init__(self, path): 50 | directories = os.walk(path) 51 | 52 | self.kitems = [] 53 | self.kq = select.kqueue() 54 | for d in directories: 55 | # Ignore .git and the like 56 | # TODO: Handle embedded dot directories 57 | if d[0].startswith('./.'): 58 | continue 59 | 60 | # Setup kqueue for monitoring 61 | directory = os.open(d[0], os.O_RDONLY) 62 | ke = select.kevent(directory, filter=select.KQ_FILTER_VNODE, 63 | flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE | 64 | select.KQ_EV_CLEAR, 65 | fflags=select.KQ_NOTE_DELETE | 66 | select.KQ_NOTE_WRITE) 67 | self.kq.control([ke], 0, None) 68 | self.kitems.append((ke, directory)) 69 | 70 | def __del__(self): 71 | for (ke, directory) in self.kitems: 72 | directory.close() 73 | 74 | def is_directory_changed(self): 75 | for (ke, directory) in self.kitems: 76 | raised_events = self.kq.control([ke], 1, None) 77 | for event in raised_events: 78 | if event.fflags & (select.KQ_NOTE_DELETE | 79 | select.KQ_NOTE_WRITE): 80 | return True 81 | 82 | return False 83 | 84 | 85 | @task 86 | def build_all_push(): 87 | build_all() 88 | push_to_db() 89 | 90 | 91 | @task 92 | def push_to_db(): 93 | """ 94 | Checks for database configuration info and pushes the last built snippet 95 | to the specified database 96 | """ 97 | 98 | if (database_present): 99 | with open(BUILD_OUT_FILE, 'r') as snippet: 100 | conn = sqlite3.connect(config.get('Database', 'db_path')) 101 | conn.execute(""" 102 | UPDATE homesnippets_snippet 103 | SET body=? 104 | WHERE id=? 105 | """, (snippet.read(), config.get('Database', 'snippet_id'))) 106 | conn.commit() 107 | conn.close() 108 | 109 | 110 | @task 111 | def db_setup(): 112 | """Setup database details and create snippet to push updates to.""" 113 | 114 | if not config.has_section('Database'): 115 | config.add_section('Database') 116 | 117 | db_path = raw_input('Enter the absolute path to the sqlite ' 118 | 'database file: ') 119 | 120 | while not _test_sqlite3_db(db_path): 121 | db_path = raw_input('Error validating database. Enter absolute path' 122 | ' to database file (blank to quit setup): ') 123 | if not db_path: 124 | return 125 | 126 | config.set('Database', 'db_path', db_path) 127 | 128 | # Set up snippet to push to 129 | conn = sqlite3.connect(db_path) 130 | 131 | # Create Snippet 132 | conn.execute(""" 133 | INSERT INTO homesnippets_clientmatchrule (description, exclude, 134 | created, modified) 135 | VALUES ('Matches Anything', 0, datetime('now'), datetime('now')) 136 | """) 137 | client_rule_id = _get_last_insert_rowid(conn) 138 | 139 | # Create client rule 140 | conn.execute(""" 141 | INSERT INTO homesnippets_snippet (name, body, disabled, preview, 142 | created, modified) 143 | VALUES (?, '', 0, 0, datetime('now'), datetime('now')) 144 | """, ('Autogenerated Snippet',)) 145 | snippet_id = _get_last_insert_rowid(conn) 146 | 147 | # Associate snippet with rule 148 | conn.execute(""" 149 | INSERT INTO homesnippets_snippet_client_match_rules 150 | (snippet_id, clientmatchrule_id) 151 | VALUES (?, ?) 152 | """, (snippet_id, client_rule_id)) 153 | 154 | conn.commit() 155 | conn.close() 156 | 157 | config.set('Database', 'snippet_id', snippet_id) 158 | config.set('Database', 'client_rule_id', client_rule_id) 159 | 160 | # TODO: Handle failure better 161 | with open('.snippetconfig', 'w') as f: 162 | config.write(f) 163 | 164 | 165 | def _get_last_insert_rowid(conn): 166 | cursor = conn.execute('SELECT last_insert_rowid()') 167 | result = cursor.fetchone() 168 | if result is not None: 169 | return result[0] 170 | else: 171 | return None 172 | 173 | 174 | def _test_sqlite3_db(db_path): 175 | """Very basic test for validity of database.""" 176 | 177 | # Check for file existance and if it's a sqlite3 db 178 | if isfile(db_path): 179 | try: 180 | conn = sqlite3.connect(db_path) 181 | 182 | # TODO: If we really care, do a more thorough check 183 | # If it has the homesnippets_snippet table we're content 184 | tables = [r[0] for r in conn.execute(""" 185 | SELECT name FROM sqlite_master 186 | WHERE type='table' 187 | """).fetchall()] 188 | conn.close() 189 | 190 | if 'homesnippets_snippet' in tables: 191 | return True 192 | except sqlite3.DatabaseError: 193 | pass 194 | 195 | return False 196 | 197 | 198 | @task 199 | def build_all(): 200 | combine_js() 201 | combine_css() 202 | build_content() 203 | build_snippet() 204 | 205 | 206 | @task 207 | def combine_js(): 208 | """Combines every .js file in the SCRIPTS_DIR into one script.""" 209 | 210 | _combine_files(SCRIPTS_DIR + '/*.js', BUILD_JS_FILE) 211 | 212 | 213 | @task 214 | def combine_css(): 215 | """Combines every .css file in the CSS_DIR into one file.""" 216 | 217 | _combine_files(CSS_DIR + '/*.css', BUILD_CSS_FILE) 218 | 219 | 220 | def _combine_files(glob_mask, combined_file_name): 221 | """Combines all files that match glob_mask into one file.""" 222 | 223 | files = [] 224 | for file in glob(glob_mask): 225 | with open(file, 'r') as f: 226 | files.append(f.read()) 227 | 228 | with open(combined_file_name, 'w') as f: 229 | f.write('\n'.join(files)) 230 | 231 | 232 | @task 233 | def build_content(): 234 | with open(BUILD_CONTENT_FILE, 'w') as f: 235 | f.write(ContentView().render()) 236 | 237 | 238 | @task 239 | def build_snippet(): 240 | """ 241 | Combines the compiled JS, CSS, and content into the template and outputs 242 | the result. 243 | """ 244 | template = SnippetView({ 245 | 'css': BUILD_CSS_FILE, 246 | 'js': BUILD_JS_FILE, 247 | 'content': BUILD_CONTENT_FILE 248 | }) 249 | 250 | with open(BUILD_OUT_FILE, 'w') as output: 251 | output.write(template.render()) 252 | 253 | 254 | class SnippetView(pystache.View): 255 | template_file = SNIPPET_TEMPLATE_FILE 256 | 257 | def __init__(self, filenames): 258 | super(SnippetView, self).__init__() 259 | self._filenames = filenames 260 | 261 | def __getattr__(self, item): 262 | try: 263 | return self._loadfile(item) 264 | except KeyError: 265 | raise AttributeError 266 | 267 | def _loadfile(self, key): 268 | with open(self._filenames[key], 'r') as f: 269 | return f.read() 270 | 271 | 272 | class ContentView(pystache.View): 273 | template_file = SNIPPET_CONTENT_FILE 274 | 275 | def base64img(self, text=None): 276 | return self._base64img 277 | 278 | def _base64img(self, text=''): 279 | filename = text.strip() 280 | if filename.endswith('png'): 281 | mimetype = 'image/png' 282 | elif filename.endswith(('jpg', 'jpeg')): 283 | mimetype = 'image/jpeg' 284 | else: 285 | return '' 286 | 287 | with open(IMAGES_DIR + '/' + filename, 'r') as f: 288 | data = base64.encodestring(f.read()) 289 | 290 | return 'data:%s;base64,%s' % (mimetype, data) 291 | -------------------------------------------------------------------------------- /campaigns/sopa/images/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/sopa/images/.gitignore -------------------------------------------------------------------------------- /campaigns/sopa/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/sopa/images/bg.png -------------------------------------------------------------------------------- /campaigns/sopa/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/sopa/images/icon.png -------------------------------------------------------------------------------- /campaigns/sopa/images/stop_censorship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/sopa/images/stop_censorship.png -------------------------------------------------------------------------------- /campaigns/sopa/requirements.txt: -------------------------------------------------------------------------------- 1 | Fabric==1.1.1 2 | pystache==0.3.1 3 | -------------------------------------------------------------------------------- /campaigns/sopa/scripts/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/campaigns/sopa/scripts/.gitignore -------------------------------------------------------------------------------- /campaigns/sopa/scripts/code.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var brand_start = document.getElementById('brandStart'), 3 | doom_container = document.getElementById('doom_container'), 4 | bar = document.getElementById('black_bar_of_doom'); 5 | 6 | 7 | var date = new Date(), 8 | gmt = date.getTime() + (date.getTimezoneOffset() * 60), 9 | est = gmt - (5 * 60 * 60), 10 | end = new Date('Wed, 18 Jan 2012 20:00:00 EST').getTime(); 11 | 12 | if (est < end) { 13 | doom_container.removeChild(bar); 14 | brand_start.appendChild(bar); 15 | document.body.className = 'dark'; 16 | } 17 | })(); 18 | -------------------------------------------------------------------------------- /campaigns/sopa/snippet_template.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | {{& content}} 6 | 11 |
12 | -------------------------------------------------------------------------------- /campaigns/thank-you/snippet.html: -------------------------------------------------------------------------------- 1 | {# 2 | Spectacular thank you snippet with link and confetti. Firefox 45.0 and up only. 3 | 4 | Variables: 5 | 6 | @header_image: Required, data uri of an svg. 7 | @header_image_height: Optional, number, defaults to 104. 8 | @header_alt: Required, text describing the header image. 9 | @text: main text - Text of snippet. 10 | @text_color: Optional, defaults to #FFFFFF. 11 | @button_text: Required, text for button. 12 | @link_href: Required, button link location. 13 | @background: Required, color hash, background color. 14 | @animation: Text, Optional, defaults to "dynamic", can also use "static". 15 | 16 | #} 17 | 99 |
100 | {% if header_image %} 101 | {{ header_alt }} 102 | {% elif header_alt %} 103 |
{{ header_alt }}
104 | {% endif %} 105 |

{{ text|safe }}

106 | {{ button_text }} 107 |
108 | 109 | 110 | 260 | -------------------------------------------------------------------------------- /generic-templates/addon_install_snippet.html: -------------------------------------------------------------------------------- 1 | 24 |
25 | 26 |

{{ text|safe }}

27 | Add to Firefox 28 | 29 |
30 | 47 | -------------------------------------------------------------------------------- /generic-templates/fxos-logo-animation/fox-animation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/generic-templates/fxos-logo-animation/fox-animation.png -------------------------------------------------------------------------------- /generic-templates/fxos-logo-animation/fxos-logo-animation.html: -------------------------------------------------------------------------------- 1 |
2 | 64 | 65 |
66 | {% if logo_url %}{% endif %} 67 | 68 |
69 | 70 |
71 |
72 | 73 | {% if icon_url %}{% endif %} 74 | 75 | {% if icon_url %}{% endif %} 76 |

{{ text|safe }}

77 | 78 | 102 |
103 | -------------------------------------------------------------------------------- /generic-templates/heartbeat-survey.html: -------------------------------------------------------------------------------- 1 | {# 2 | Snippet for prompting users with a UITour survey 3 | 4 | Variables: 5 | 6 | @message - small text - Survey message text 7 | @thankyouMessage - small text - Thanks message text shown after the user 8 | interacts with the prompt 9 | @engagementURL - URL - URL to open in a new tab after the user interacts with 10 | the prompt 11 | @engagementButtonLabel - small text - If blank, show a 5-star rating in the 12 | prompt, otherwise show a button with this text 13 | @learnMoreURL - URL - URL to open when the Learn More link is clicked 14 | @learnMoreLabel - small text - Label for the Learn More link 15 | 16 | Must target versions with mozUITour. 17 | 18 | #} 19 |
20 | 104 | -------------------------------------------------------------------------------- /generic-templates/logo-swap-with-share.html: -------------------------------------------------------------------------------- 1 | 125 |
126 |
127 |
128 |
129 | {{ text|safe }} 130 | {{ postShareMessage|safe }} 131 |
132 | 136 |
137 |
138 | 234 | -------------------------------------------------------------------------------- /generic-templates/simple-snippet.html: -------------------------------------------------------------------------------- 1 | {# 2 | Simple and Logo Swap Snippet with Block, Link Button and Click 3 | 4 | Variables: 5 | 6 | @block_button_text - small text - Text to display while hovering over opt out button. Default 'Remove this' 7 | @blockable: checkbox - Check to allow user to block this snippet. 8 | @clickable: checkbox - Check to allow snippet to be clickable 9 | @rtl: checkbox - If checked change text direction to support RTL languages 10 | @icon: image - Snippet icon. 64x64px. SVG or PNG preferred. 11 | @icon_url: text - URL linked from icon and whole snippet when snippet is clickable. (optional / required when snippet is clickable) 12 | @link_logo: checkbox - Check to make replacement logo clickable. 13 | @replacement_logo: image - Optional. Replace logo. 14 | @button_label: Optional. Text for a button next to main snippet text that links to icon_url. Requires icon_url. 15 | @text: main text - Text of snippet. 16 | @logo_height: small_text - Logo height. Defaults to 192px 17 | @logo_width: small_text - Logo width. Defaults to 192px 18 | 19 | #} 20 | 146 | {% if clickable %} 147 | 148 | {% endif %} 149 |
150 | {% if blockable or clickable %} 151 |
152 | {% endif %} 153 |
154 | {% if rtl %} 155 | {% if button_label and icon_url %} 156 | 159 | {% endif %} 160 | {% else %} 161 |
162 | {% if icon_url %} 163 | 164 | {% endif %} 165 | 166 | {% if icon_url %} 167 | 168 | {% endif %} 169 |
170 | {% endif %} 171 | 172 |

{{ text|safe }}

173 | 174 | {% if rtl %} 175 |
176 | {% if icon_url %} 177 | 178 | {% endif %} 179 | 180 | {% if icon_url %} 181 | 182 | {% endif %} 183 |
184 | {% else %} 185 | {% if button_label and icon_url %} 186 |
187 | {{ button_label }} 188 |
189 | {% endif %} 190 | {% endif %} 191 |
192 | {% if blockable or clickable %} 193 |
194 | {% endif %} 195 | 196 | {% if blockable %} 197 | 199 | {% endif %} 200 |
201 | {% if clickable %} 202 | 203 | {% endif %} 204 | 280 | -------------------------------------------------------------------------------- /generic-templates/video-snippets/simple-over-search-bar.html: -------------------------------------------------------------------------------- 1 | {# 2 | Snippet with Video over search bar 3 | 4 | Variables: 5 | 6 | @icon - image - snippet icon. works with 40x50px and with 64x64px 7 | @message - main text - Main snippet text 8 | @video_poster - image - Must have the same dimensions as video 9 | @video_url - small text - URL to video. WebM. Height 192px. Width up to 470px 10 | 11 | #} 12 | 120 | 121 |
122 |
123 |
124 | 125 | 126 |
127 |
129 |
130 | 131 |
132 |
133 | 134 |

{{ message|safe }}

135 |
136 |
137 | 138 | 218 | -------------------------------------------------------------------------------- /legacy/beta-share-snippet/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | !build/.gitignore 3 | *~ 4 | *.pyc 5 | .snippetconfig 6 | *.pyc 7 | -------------------------------------------------------------------------------- /legacy/beta-share-snippet/README.md: -------------------------------------------------------------------------------- 1 | # Beta Share Snippet 2 | 3 | This snippet shows a Facebook and Twitter share button on the right side of the 4 | snippet. 5 | 6 | See the 7 | [Snippet Development Template](https://github.com/Osmose/snippet-dev-template) 8 | for info on how to work on this. -------------------------------------------------------------------------------- /legacy/beta-share-snippet/build/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/beta-share-snippet/build/.gitignore -------------------------------------------------------------------------------- /legacy/beta-share-snippet/content.html: -------------------------------------------------------------------------------- 1 | 2 |

3 |

19 |
Thanks for using Firefox Beta to help make Firefox more awesome. Now invite your friends to give it a try.
20 |

21 | -------------------------------------------------------------------------------- /legacy/beta-share-snippet/css/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/beta-share-snippet/css/.gitignore -------------------------------------------------------------------------------- /legacy/beta-share-snippet/css/styles.css: -------------------------------------------------------------------------------- 1 | .share-buttons { 2 | border-left: 1px dotted #999; 3 | float: right; 4 | list-style-type: none; 5 | margin: -7px 0 0; 6 | padding-left: 10px; 7 | padding-right: 20px; 8 | } 9 | 10 | .share-buttons img { 11 | vertical-align: middle; 12 | } -------------------------------------------------------------------------------- /legacy/beta-share-snippet/fabfile.py: -------------------------------------------------------------------------------- 1 | # TODO: Determine how to organize code 2 | # TODO: Figure out a better way to edit the DB 3 | 4 | import base64 5 | import ConfigParser 6 | import os 7 | import pystache 8 | import select 9 | import sqlite3 10 | 11 | from fabric.decorators import task 12 | from glob import glob 13 | from os.path import isfile 14 | 15 | BUILD_DIR = 'build' 16 | BUILD_JS_FILE = BUILD_DIR + '/compiled.min.js' 17 | BUILD_CSS_FILE = BUILD_DIR + '/compiled.css' 18 | BUILD_CONTENT_FILE = BUILD_DIR + '/compiled.html' 19 | BUILD_OUT_FILE = BUILD_DIR + '/snippet.html' 20 | 21 | SCRIPTS_DIR = 'scripts' 22 | CSS_DIR = 'css' 23 | IMAGES_DIR = 'images' 24 | 25 | SNIPPET_TEMPLATE_FILE = 'snippet_template.html' 26 | SNIPPET_CONTENT_FILE = 'content.html' 27 | 28 | config = ConfigParser.ConfigParser() 29 | config.read('.snippetconfig') 30 | database_present = config.has_section('Database') 31 | 32 | 33 | @task 34 | def monitor_build_push(): 35 | """ 36 | Monitors the current directory for changes and pushes when they happen 37 | """ 38 | 39 | monitor = DirectoryMonitor('./') 40 | print "Monitoring for changes..." 41 | 42 | while True: 43 | if monitor.is_directory_changed(): 44 | print "Change detected, pushing..." 45 | build_all_push() 46 | 47 | 48 | class DirectoryMonitor: 49 | def __init__(self, path): 50 | directories = os.walk(path) 51 | 52 | self.kitems = [] 53 | self.kq = select.kqueue() 54 | for d in directories: 55 | # Ignore .git and the like 56 | # TODO: Handle embedded dot directories 57 | if d[0].startswith('./.'): 58 | continue 59 | 60 | # Setup kqueue for monitoring 61 | directory = os.open(d[0], os.O_RDONLY) 62 | ke = select.kevent(directory, filter=select.KQ_FILTER_VNODE, 63 | flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE | 64 | select.KQ_EV_CLEAR, 65 | fflags=select.KQ_NOTE_DELETE | 66 | select.KQ_NOTE_WRITE) 67 | self.kq.control([ke], 0, None) 68 | self.kitems.append((ke, directory)) 69 | 70 | def __del__(self): 71 | for (ke, directory) in self.kitems: 72 | directory.close() 73 | 74 | def is_directory_changed(self): 75 | for (ke, directory) in self.kitems: 76 | raised_events = self.kq.control([ke], 1, None) 77 | for event in raised_events: 78 | if event.fflags & (select.KQ_NOTE_DELETE | 79 | select.KQ_NOTE_WRITE): 80 | return True 81 | 82 | return False 83 | 84 | 85 | @task 86 | def build_all_push(): 87 | build_all() 88 | push_to_db() 89 | 90 | 91 | @task 92 | def push_to_db(): 93 | """ 94 | Checks for database configuration info and pushes the last built snippet 95 | to the specified database 96 | """ 97 | 98 | if (database_present): 99 | with open(BUILD_OUT_FILE, 'r') as snippet: 100 | conn = sqlite3.connect(config.get('Database', 'db_path')) 101 | conn.execute(""" 102 | UPDATE homesnippets_snippet 103 | SET body=? 104 | WHERE id=? 105 | """, (snippet.read(), config.get('Database', 'snippet_id'))) 106 | conn.commit() 107 | conn.close() 108 | 109 | 110 | @task 111 | def db_setup(): 112 | """Setup database details and create snippet to push updates to.""" 113 | 114 | if not config.has_section('Database'): 115 | config.add_section('Database') 116 | 117 | db_path = raw_input('Enter the absolute path to the sqlite ' 118 | 'database file: ') 119 | 120 | while not _test_sqlite3_db(db_path): 121 | db_path = raw_input('Error validating database. Enter absolute path' 122 | ' to database file (blank to quit setup): ') 123 | if not db_path: 124 | return 125 | 126 | config.set('Database', 'db_path', db_path) 127 | 128 | # Set up snippet to push to 129 | conn = sqlite3.connect(db_path) 130 | 131 | # Create Snippet 132 | conn.execute(""" 133 | INSERT INTO homesnippets_clientmatchrule (description, exclude, 134 | created, modified) 135 | VALUES ('Matches Anything', 0, datetime('now'), datetime('now')) 136 | """) 137 | client_rule_id = _get_last_insert_rowid(conn) 138 | 139 | # Create client rule 140 | conn.execute(""" 141 | INSERT INTO homesnippets_snippet (name, body, disabled, preview, 142 | created, modified) 143 | VALUES (?, '', 0, 0, datetime('now'), datetime('now')) 144 | """, ('Autogenerated Snippet',)) 145 | snippet_id = _get_last_insert_rowid(conn) 146 | 147 | # Associate snippet with rule 148 | conn.execute(""" 149 | INSERT INTO homesnippets_snippet_client_match_rules 150 | (snippet_id, clientmatchrule_id) 151 | VALUES (?, ?) 152 | """, (snippet_id, client_rule_id)) 153 | 154 | conn.commit() 155 | conn.close() 156 | 157 | config.set('Database', 'snippet_id', snippet_id) 158 | config.set('Database', 'client_rule_id', client_rule_id) 159 | 160 | # TODO: Handle failure better 161 | with open('.snippetconfig', 'w') as f: 162 | config.write(f) 163 | 164 | 165 | def _get_last_insert_rowid(conn): 166 | cursor = conn.execute('SELECT last_insert_rowid()') 167 | result = cursor.fetchone() 168 | if result is not None: 169 | return result[0] 170 | else: 171 | return None 172 | 173 | 174 | def _test_sqlite3_db(db_path): 175 | """Very basic test for validity of database.""" 176 | 177 | # Check for file existance and if it's a sqlite3 db 178 | if isfile(db_path): 179 | try: 180 | conn = sqlite3.connect(db_path) 181 | 182 | # TODO: If we really care, do a more thorough check 183 | # If it has the homesnippets_snippet table we're content 184 | tables = [r[0] for r in conn.execute(""" 185 | SELECT name FROM sqlite_master 186 | WHERE type='table' 187 | """).fetchall()] 188 | conn.close() 189 | 190 | if 'homesnippets_snippet' in tables: 191 | return True 192 | except sqlite3.DatabaseError: 193 | pass 194 | 195 | return False 196 | 197 | 198 | @task 199 | def build_all(): 200 | combine_js() 201 | combine_css() 202 | build_content() 203 | build_snippet() 204 | 205 | 206 | @task 207 | def combine_js(): 208 | """Combines every .js file in the SCRIPTS_DIR into one script.""" 209 | 210 | _combine_files(SCRIPTS_DIR + '/*.js', BUILD_JS_FILE) 211 | 212 | 213 | @task 214 | def combine_css(): 215 | """Combines every .css file in the CSS_DIR into one file.""" 216 | 217 | _combine_files(CSS_DIR + '/*.css', BUILD_CSS_FILE) 218 | 219 | 220 | def _combine_files(glob_mask, combined_file_name): 221 | """Combines all files that match glob_mask into one file.""" 222 | 223 | files = [] 224 | for file in glob(glob_mask): 225 | with open(file, 'r') as f: 226 | files.append(f.read()) 227 | 228 | with open(combined_file_name, 'w') as f: 229 | f.write('\n'.join(files)) 230 | 231 | 232 | @task 233 | def build_content(): 234 | with open(BUILD_CONTENT_FILE, 'w') as f: 235 | f.write(ContentView().render()) 236 | 237 | 238 | @task 239 | def build_snippet(): 240 | """ 241 | Combines the compiled JS, CSS, and content into the template and outputs 242 | the result. 243 | """ 244 | template = SnippetView({ 245 | 'css': BUILD_CSS_FILE, 246 | 'js': BUILD_JS_FILE, 247 | 'content': BUILD_CONTENT_FILE 248 | }) 249 | 250 | with open(BUILD_OUT_FILE, 'w') as output: 251 | output.write(template.render()) 252 | 253 | 254 | class SnippetView(pystache.View): 255 | template_file = SNIPPET_TEMPLATE_FILE 256 | 257 | def __init__(self, filenames): 258 | super(SnippetView, self).__init__() 259 | self._filenames = filenames 260 | 261 | def __getattr__(self, item): 262 | try: 263 | return self._loadfile(item) 264 | except KeyError: 265 | raise AttributeError 266 | 267 | def _loadfile(self, key): 268 | with open(self._filenames[key], 'r') as f: 269 | return f.read() 270 | 271 | 272 | class ContentView(pystache.View): 273 | template_file = SNIPPET_CONTENT_FILE 274 | 275 | def base64img(self, text=None): 276 | return self._base64img 277 | 278 | def _base64img(self, text=''): 279 | filename = text.strip() 280 | if filename.endswith('png'): 281 | mimetype = 'image/png' 282 | elif filename.endswith(('jpg', 'jpeg')): 283 | mimetype = 'image/jpeg' 284 | else: 285 | return '' 286 | 287 | with open(IMAGES_DIR + '/' + filename, 'r') as f: 288 | data = base64.encodestring(f.read()) 289 | 290 | return 'data:%s;base64,%s' % (mimetype, data) 291 | -------------------------------------------------------------------------------- /legacy/beta-share-snippet/images/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/beta-share-snippet/images/.gitignore -------------------------------------------------------------------------------- /legacy/beta-share-snippet/images/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/beta-share-snippet/images/facebook.png -------------------------------------------------------------------------------- /legacy/beta-share-snippet/images/firefox_beta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/beta-share-snippet/images/firefox_beta.png -------------------------------------------------------------------------------- /legacy/beta-share-snippet/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/beta-share-snippet/images/twitter.png -------------------------------------------------------------------------------- /legacy/beta-share-snippet/requirements.txt: -------------------------------------------------------------------------------- 1 | Fabric==1.1.1 2 | pystache==0.3.1 3 | -------------------------------------------------------------------------------- /legacy/beta-share-snippet/scripts/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/beta-share-snippet/scripts/.gitignore -------------------------------------------------------------------------------- /legacy/beta-share-snippet/scripts/popup.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | function popup_onclick(e) { 3 | e.preventDefault(); 4 | var new_window = window.open(this.href, 'share', 'height=300, width=600'); 5 | if (window.focus) { 6 | new_window.focus(); 7 | } 8 | } 9 | 10 | var snippet = document.getElementById('beta-share-snippet'); 11 | snippet.addEventListener('show_snippet', function(e) { 12 | var links = document.querySelectorAll('a.popup'); 13 | for (var k = 0; k < links.length; k++) { 14 | var link = links[k]; 15 | link.addEventListener('click', popup_onclick, true); 16 | } 17 | }); 18 | })(); 19 | -------------------------------------------------------------------------------- /legacy/beta-share-snippet/snippet_template.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | {{& content}} 6 | 11 |
12 | -------------------------------------------------------------------------------- /legacy/blank-snippet/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | !build/.gitignore 3 | *~ 4 | *.pyc 5 | .snippetconfig 6 | *.pyc 7 | -------------------------------------------------------------------------------- /legacy/blank-snippet/README.md: -------------------------------------------------------------------------------- 1 | # Blank Snippet 2 | 3 | This snippet, when displayed, blanks out the snippet box so that it is not 4 | shown to the user. This apparently increases conversion rates for other 5 | snippets. 6 | 7 | See the 8 | [Snippet Development Template](https://github.com/Osmose/snippet-dev-template) 9 | for info on how to work on this. 10 | -------------------------------------------------------------------------------- /legacy/blank-snippet/build/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/blank-snippet/build/.gitignore -------------------------------------------------------------------------------- /legacy/blank-snippet/content.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/blank-snippet/content.html -------------------------------------------------------------------------------- /legacy/blank-snippet/css/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/blank-snippet/css/.gitignore -------------------------------------------------------------------------------- /legacy/blank-snippet/fabfile.py: -------------------------------------------------------------------------------- 1 | # TODO: Determine how to organize code 2 | # TODO: Figure out a better way to edit the DB 3 | 4 | import base64 5 | import ConfigParser 6 | import os 7 | import pystache 8 | import select 9 | import sqlite3 10 | 11 | from fabric.decorators import task 12 | from glob import glob 13 | from os.path import isfile 14 | 15 | BUILD_DIR = 'build' 16 | BUILD_JS_FILE = BUILD_DIR + '/compiled.min.js' 17 | BUILD_CSS_FILE = BUILD_DIR + '/compiled.css' 18 | BUILD_CONTENT_FILE = BUILD_DIR + '/compiled.html' 19 | BUILD_OUT_FILE = BUILD_DIR + '/snippet.html' 20 | 21 | SCRIPTS_DIR = 'scripts' 22 | CSS_DIR = 'css' 23 | IMAGES_DIR = 'images' 24 | 25 | SNIPPET_TEMPLATE_FILE = 'snippet_template.html' 26 | SNIPPET_CONTENT_FILE = 'content.html' 27 | 28 | config = ConfigParser.ConfigParser() 29 | config.read('.snippetconfig') 30 | database_present = config.has_section('Database') 31 | 32 | 33 | @task 34 | def monitor_build_push(): 35 | """ 36 | Monitors the current directory for changes and pushes when they happen 37 | """ 38 | 39 | monitor = DirectoryMonitor('./') 40 | print "Monitoring for changes..." 41 | 42 | while True: 43 | if monitor.is_directory_changed(): 44 | print "Change detected, pushing..." 45 | build_all_push() 46 | 47 | 48 | class DirectoryMonitor: 49 | def __init__(self, path): 50 | directories = os.walk(path) 51 | 52 | self.kitems = [] 53 | self.kq = select.kqueue() 54 | for d in directories: 55 | # Ignore .git and the like 56 | # TODO: Handle embedded dot directories 57 | if d[0].startswith('./.'): 58 | continue 59 | 60 | # Setup kqueue for monitoring 61 | directory = os.open(d[0], os.O_RDONLY) 62 | ke = select.kevent(directory, filter=select.KQ_FILTER_VNODE, 63 | flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE | 64 | select.KQ_EV_CLEAR, 65 | fflags=select.KQ_NOTE_DELETE | 66 | select.KQ_NOTE_WRITE) 67 | self.kq.control([ke], 0, None) 68 | self.kitems.append((ke, directory)) 69 | 70 | def __del__(self): 71 | for (ke, directory) in self.kitems: 72 | directory.close() 73 | 74 | def is_directory_changed(self): 75 | for (ke, directory) in self.kitems: 76 | raised_events = self.kq.control([ke], 1, None) 77 | for event in raised_events: 78 | if event.fflags & (select.KQ_NOTE_DELETE | 79 | select.KQ_NOTE_WRITE): 80 | return True 81 | 82 | return False 83 | 84 | 85 | @task 86 | def build_all_push(): 87 | build_all() 88 | push_to_db() 89 | 90 | 91 | @task 92 | def push_to_db(): 93 | """ 94 | Checks for database configuration info and pushes the last built snippet 95 | to the specified database 96 | """ 97 | 98 | if (database_present): 99 | with open(BUILD_OUT_FILE, 'r') as snippet: 100 | conn = sqlite3.connect(config.get('Database', 'db_path')) 101 | conn.execute(""" 102 | UPDATE homesnippets_snippet 103 | SET body=? 104 | WHERE id=? 105 | """, (snippet.read(), config.get('Database', 'snippet_id'))) 106 | conn.commit() 107 | conn.close() 108 | 109 | 110 | @task 111 | def db_setup(): 112 | """Setup database details and create snippet to push updates to.""" 113 | 114 | if not config.has_section('Database'): 115 | config.add_section('Database') 116 | 117 | db_path = raw_input('Enter the absolute path to the sqlite ' 118 | 'database file: ') 119 | 120 | while not _test_sqlite3_db(db_path): 121 | db_path = raw_input('Error validating database. Enter absolute path' 122 | ' to database file (blank to quit setup): ') 123 | if not db_path: 124 | return 125 | 126 | config.set('Database', 'db_path', db_path) 127 | 128 | # Set up snippet to push to 129 | conn = sqlite3.connect(db_path) 130 | 131 | # Create Snippet 132 | conn.execute(""" 133 | INSERT INTO homesnippets_clientmatchrule (description, exclude, 134 | created, modified) 135 | VALUES ('Matches Anything', 0, datetime('now'), datetime('now')) 136 | """) 137 | client_rule_id = _get_last_insert_rowid(conn) 138 | 139 | # Create client rule 140 | conn.execute(""" 141 | INSERT INTO homesnippets_snippet (name, body, disabled, preview, 142 | created, modified) 143 | VALUES (?, '', 0, 0, datetime('now'), datetime('now')) 144 | """, ('Autogenerated Snippet',)) 145 | snippet_id = _get_last_insert_rowid(conn) 146 | 147 | # Associate snippet with rule 148 | conn.execute(""" 149 | INSERT INTO homesnippets_snippet_client_match_rules 150 | (snippet_id, clientmatchrule_id) 151 | VALUES (?, ?) 152 | """, (snippet_id, client_rule_id)) 153 | 154 | conn.commit() 155 | conn.close() 156 | 157 | config.set('Database', 'snippet_id', snippet_id) 158 | config.set('Database', 'client_rule_id', client_rule_id) 159 | 160 | # TODO: Handle failure better 161 | with open('.snippetconfig', 'w') as f: 162 | config.write(f) 163 | 164 | 165 | def _get_last_insert_rowid(conn): 166 | cursor = conn.execute('SELECT last_insert_rowid()') 167 | result = cursor.fetchone() 168 | if result is not None: 169 | return result[0] 170 | else: 171 | return None 172 | 173 | 174 | def _test_sqlite3_db(db_path): 175 | """Very basic test for validity of database.""" 176 | 177 | # Check for file existance and if it's a sqlite3 db 178 | if isfile(db_path): 179 | try: 180 | conn = sqlite3.connect(db_path) 181 | 182 | # TODO: If we really care, do a more thorough check 183 | # If it has the homesnippets_snippet table we're content 184 | tables = [r[0] for r in conn.execute(""" 185 | SELECT name FROM sqlite_master 186 | WHERE type='table' 187 | """).fetchall()] 188 | conn.close() 189 | 190 | if 'homesnippets_snippet' in tables: 191 | return True 192 | except sqlite3.DatabaseError: 193 | pass 194 | 195 | return False 196 | 197 | 198 | @task 199 | def build_all(): 200 | combine_js() 201 | combine_css() 202 | build_content() 203 | build_snippet() 204 | 205 | 206 | @task 207 | def combine_js(): 208 | """Combines every .js file in the SCRIPTS_DIR into one script.""" 209 | 210 | _combine_files(SCRIPTS_DIR + '/*.js', BUILD_JS_FILE) 211 | 212 | 213 | @task 214 | def combine_css(): 215 | """Combines every .css file in the CSS_DIR into one file.""" 216 | 217 | _combine_files(CSS_DIR + '/*.css', BUILD_CSS_FILE) 218 | 219 | 220 | def _combine_files(glob_mask, combined_file_name): 221 | """Combines all files that match glob_mask into one file.""" 222 | 223 | files = [] 224 | for file in glob(glob_mask): 225 | with open(file, 'r') as f: 226 | files.append(f.read()) 227 | 228 | with open(combined_file_name, 'w') as f: 229 | f.write('\n'.join(files)) 230 | 231 | 232 | @task 233 | def build_content(): 234 | with open(BUILD_CONTENT_FILE, 'w') as f: 235 | f.write(ContentView().render()) 236 | 237 | 238 | @task 239 | def build_snippet(): 240 | """ 241 | Combines the compiled JS, CSS, and content into the template and outputs 242 | the result. 243 | """ 244 | template = SnippetView({ 245 | 'css': BUILD_CSS_FILE, 246 | 'js': BUILD_JS_FILE, 247 | 'content': BUILD_CONTENT_FILE 248 | }) 249 | 250 | with open(BUILD_OUT_FILE, 'w') as output: 251 | output.write(template.render()) 252 | 253 | 254 | class SnippetView(pystache.View): 255 | template_file = SNIPPET_TEMPLATE_FILE 256 | 257 | def __init__(self, filenames): 258 | super(SnippetView, self).__init__() 259 | self._filenames = filenames 260 | 261 | def __getattr__(self, item): 262 | try: 263 | return self._loadfile(item) 264 | except KeyError: 265 | raise AttributeError 266 | 267 | def _loadfile(self, key): 268 | with open(self._filenames[key], 'r') as f: 269 | return f.read() 270 | 271 | 272 | class ContentView(pystache.View): 273 | template_file = SNIPPET_CONTENT_FILE 274 | 275 | def base64img(self, text=None): 276 | return self._base64img 277 | 278 | def _base64img(self, text=''): 279 | filename = text.strip() 280 | if filename.endswith('png'): 281 | mimetype = 'image/png' 282 | elif filename.endswith(('jpg', 'jpeg')): 283 | mimetype = 'image/jpeg' 284 | else: 285 | return '' 286 | 287 | with open(IMAGES_DIR + '/' + filename, 'r') as f: 288 | data = base64.encodestring(f.read()) 289 | 290 | return 'data:%s;base64,%s' % (mimetype, data) 291 | -------------------------------------------------------------------------------- /legacy/blank-snippet/images/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/blank-snippet/images/.gitignore -------------------------------------------------------------------------------- /legacy/blank-snippet/requirements.txt: -------------------------------------------------------------------------------- 1 | Fabric==1.1.1 2 | pystache==0.3.1 3 | -------------------------------------------------------------------------------- /legacy/blank-snippet/scripts/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/blank-snippet/scripts/.gitignore -------------------------------------------------------------------------------- /legacy/blank-snippet/scripts/blank.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var snippet = document.getElementById('blankSnippet'); 3 | snippet.addEventListener('show_snippet', function(e) { 4 | document.getElementById('snippets').style.display = 'none'; 5 | document.getElementById('contentContainer').style.backgroundImage = 'none'; 6 | }); 7 | })(); 8 | -------------------------------------------------------------------------------- /legacy/blank-snippet/snippet_template.html: -------------------------------------------------------------------------------- 1 | 6 |
7 | -------------------------------------------------------------------------------- /legacy/flicks-2012-video/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | !build/.gitignore 3 | *~ 4 | *.pyc 5 | .snippetconfig 6 | *.pyc 7 | build.html 8 | -------------------------------------------------------------------------------- /legacy/flicks-2012-video/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Michael Kelly 2012 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /legacy/flicks-2012-video/README.md: -------------------------------------------------------------------------------- 1 | # Flicks 2012 Video Snippet 2 | 3 | Snippet to promote the winners of the 2011/2012 Flicks contest and the upcoming 4 | 2013 contest. 5 | 6 | See the 7 | [Snippet Development Template](https://github.com/Osmose/snippet-dev-template) 8 | for info on how to work on this. 9 | -------------------------------------------------------------------------------- /legacy/flicks-2012-video/content.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 7 | 8 |
9 | 10 |

11 | What if companies could track you offline like they do online? 12 | Watch this winning video from Firefox 13 | Flicks for the answer. 14 |

15 |
16 | 17 | 22 |
23 | -------------------------------------------------------------------------------- /legacy/flicks-2012-video/fabfile.py: -------------------------------------------------------------------------------- 1 | # TODO: Figure out a better way to edit the DB 2 | 3 | import base64 4 | import ConfigParser 5 | import os 6 | import time 7 | from os.path import isfile 8 | from subprocess import CalledProcessError, check_output 9 | 10 | import sqlite3 11 | from fabric.decorators import task 12 | from jinja2 import Environment, FileSystemLoader 13 | from slimit import minify 14 | from watchdog.events import PatternMatchingEventHandler 15 | from watchdog.observers import Observer 16 | 17 | 18 | BUILD_OUT_FILE = 'build.html' 19 | SNIPPET_CONTENT_FILE = 'content.html' 20 | JS_FILE = 'script.js' 21 | CSS_FILE = 'styles.css' 22 | LESS_FILE = 'styles.less' 23 | 24 | LESS_BIN = os.environ.get('LESS_BIN', 'lessc') 25 | 26 | IGNORE_PATTERNS = (BUILD_OUT_FILE, '.gitignore', 'fabfile.py', 'README.md', 27 | 'requirements.txt', 'LICENSE') 28 | IGNORE_PATTERNS = ['*{0}'.format(filename) for filename in IGNORE_PATTERNS] 29 | 30 | config = ConfigParser.ConfigParser() 31 | config.read('.snippetconfig') 32 | database_present = config.has_section('Database') 33 | 34 | 35 | class MonitorBuildPushEventHandler(PatternMatchingEventHandler): 36 | def on_any_event(self, event): 37 | """Runs the build_push_all task when any filesystem event occurs.""" 38 | print "Files have changed, pushing..." 39 | build() 40 | push() 41 | 42 | 43 | env = Environment(autoescape=True, loader=FileSystemLoader('./')) 44 | 45 | 46 | def base64img(filename): 47 | if filename.endswith('png'): 48 | mimetype = 'image/png' 49 | elif filename.endswith(('jpg', 'jpeg')): 50 | mimetype = 'image/jpeg' 51 | else: 52 | return '' 53 | 54 | with open(filename, 'r') as f: 55 | data = base64.encodestring(f.read()) 56 | return 'data:%s;base64,%s' % (mimetype, data) 57 | env.globals['base64img'] = base64img 58 | 59 | 60 | @task 61 | def monitor(): 62 | """ 63 | Monitors the current directory for changes and pushes when they happen. 64 | """ 65 | observer = Observer() 66 | handler = MonitorBuildPushEventHandler(ignore_patterns=IGNORE_PATTERNS) 67 | observer.schedule(handler, '.', recursive=True) 68 | print "Monitoring for changes..." 69 | observer.start() 70 | try: 71 | while True: 72 | time.sleep(1) 73 | except KeyboardInterrupt: 74 | observer.stop() 75 | observer.join() 76 | 77 | 78 | @task 79 | def push(): 80 | """ 81 | Checks for database configuration info and pushes the last built snippet 82 | to the specified database 83 | """ 84 | 85 | if (database_present): 86 | with open(BUILD_OUT_FILE, 'r') as snippet: 87 | conn = sqlite3.connect(config.get('Database', 'db_path')) 88 | conn.execute(""" 89 | UPDATE homesnippets_snippet 90 | SET body=? 91 | WHERE id=? 92 | """, (snippet.read(), config.get('Database', 'snippet_id'))) 93 | conn.commit() 94 | conn.close() 95 | 96 | 97 | @task 98 | def db_setup(): 99 | """Setup database details and create snippet to push updates to.""" 100 | 101 | if not config.has_section('Database'): 102 | config.add_section('Database') 103 | 104 | if 'HOMESNIPPETS_DATABASE' in os.environ: 105 | print ('Using path from HOMESNIPPETS_DATABASE: {0}' 106 | .format(os.environ['HOMESNIPPETS_DATABASE'])) 107 | db_path = os.environ['HOMESNIPPETS_DATABASE'] 108 | else: 109 | db_path = raw_input('Enter the absolute path to the sqlite ' 110 | 'database file: ') 111 | 112 | while not _test_sqlite3_db(db_path): 113 | db_path = raw_input('Error validating database. Enter absolute path' 114 | ' to database file (blank to quit setup): ') 115 | if not db_path: 116 | return 117 | 118 | config.set('Database', 'db_path', db_path) 119 | 120 | # Get name to use for snippet. 121 | name = raw_input('Please enter the product name you will use to view this ' 122 | 'snippet (i.e. flicks_video):') 123 | 124 | # Set up snippet to push to 125 | conn = sqlite3.connect(db_path) 126 | 127 | # Create client rule 128 | conn.execute(""" 129 | INSERT INTO homesnippets_clientmatchrule (description, name, exclude, 130 | created, modified) 131 | VALUES (?, ?, 0, datetime('now'), datetime('now')) 132 | """, ['Name: {0}'.format(name), name]) 133 | client_rule_id = _get_last_insert_rowid(conn) 134 | 135 | # Create snippet 136 | conn.execute(""" 137 | INSERT INTO homesnippets_snippet (name, body, disabled, preview, 138 | created, modified) 139 | VALUES (?, '', 0, 0, datetime('now'), datetime('now')) 140 | """, (name,)) 141 | snippet_id = _get_last_insert_rowid(conn) 142 | 143 | # Associate snippet with rule 144 | conn.execute(""" 145 | INSERT INTO homesnippets_snippet_client_match_rules 146 | (snippet_id, clientmatchrule_id) 147 | VALUES (?, ?) 148 | """, (snippet_id, client_rule_id)) 149 | 150 | conn.commit() 151 | conn.close() 152 | 153 | config.set('Database', 'snippet_id', snippet_id) 154 | config.set('Database', 'client_rule_id', client_rule_id) 155 | 156 | # TODO: Handle failure better 157 | with open('.snippetconfig', 'w') as f: 158 | config.write(f) 159 | print '' 160 | 161 | 162 | def _get_last_insert_rowid(conn): 163 | cursor = conn.execute('SELECT last_insert_rowid()') 164 | result = cursor.fetchone() 165 | if result is not None: 166 | return result[0] 167 | else: 168 | return None 169 | 170 | 171 | def _test_sqlite3_db(db_path): 172 | """Very basic test for validity of database.""" 173 | 174 | # Check for file existance and if it's a sqlite3 db 175 | if isfile(db_path): 176 | try: 177 | conn = sqlite3.connect(db_path) 178 | 179 | # TODO: If we really care, do a more thorough check 180 | # If it has the homesnippets_snippet table we're content 181 | tables = [r[0] for r in conn.execute(""" 182 | SELECT name FROM sqlite_master 183 | WHERE type='table' 184 | """).fetchall()] 185 | conn.close() 186 | 187 | if 'homesnippets_snippet' in tables: 188 | return True 189 | except sqlite3.DatabaseError: 190 | pass 191 | 192 | return False 193 | 194 | 195 | @task 196 | def build(): 197 | """Builds the snippet.""" 198 | # Use the LESS file over the CSS file if it exists. 199 | css = '' 200 | if os.path.isfile(LESS_FILE): 201 | args = [LESS_BIN, '-x', LESS_FILE] 202 | try: 203 | css = check_output(args) 204 | except CalledProcessError, e: 205 | print 'Error compiling %s with command `%s`:' % (filename, args) 206 | print e.output 207 | print 'File will be ignored.' 208 | elif os.path.isfile(CSS_FILE): 209 | with open(CSS_FILE, 'r') as f: 210 | css = f.read() 211 | 212 | js = '' 213 | if os.path.isfile(JS_FILE): 214 | with open(JS_FILE, 'r') as f: 215 | js = minify(f.read()) 216 | 217 | template = env.get_template(SNIPPET_CONTENT_FILE) 218 | 219 | with open(BUILD_OUT_FILE, 'w') as output: 220 | output.write(template.render({ 221 | 'css': css, 222 | 'js': js 223 | })) 224 | -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/.gitkeep -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/close.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/facebook.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/flicks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/flicks.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/play.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/replay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/replay.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/share.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/share_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/share_white.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/flicks-2012-video/images/twitter.png -------------------------------------------------------------------------------- /legacy/flicks-2012-video/requirements.txt: -------------------------------------------------------------------------------- 1 | Fabric>=1.1.1 2 | pystache>=0.3.1 3 | watchdog -------------------------------------------------------------------------------- /legacy/flicks-2012-video/script.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function VideoShareOverlay(video, shareURL, options) { 5 | this.video = video; 6 | this.shareURL = shareURL; 7 | this.ended = false; 8 | 9 | // Store strings (for l10n handyness). 10 | this.strings = { 11 | share: 'Share', 12 | resume: 'Resume', 13 | replay: 'Replay', 14 | tweet: 'Tweet', 15 | twitterShare: '' 16 | }; 17 | if (options.strings) { 18 | this.strings = this.util.extend(this.strings, options.strings); 19 | } 20 | 21 | // Build HTML for the overlay. 22 | // TODO: Do this smarter. 23 | var container = document.createElement('div'); 24 | var content = []; 25 | 26 | content.push('
'); 27 | content.push(''); 28 | content.push(''); 29 | content.push('
'); 30 | content.push('
'); 31 | if (options.externalLink) { 32 | content.push(''); 33 | content.push(options.externalLink.label); 34 | content.push(''); 35 | } 36 | content.push(''); 40 | content.push(''); 41 | content.push(''); 42 | content.push('
'); 43 | content.push('
'); 44 | content.push('
'); 45 | 46 | container.innerHTML = content.join('\n'); 47 | 48 | // Convenient element references! 49 | this.videoOverlay = container.querySelector('.video-overlay'); 50 | this.closeButton = container.querySelector('.close'); 51 | this.shareButton = container.querySelector('.share'); 52 | this.shareScreen = container.querySelector('.shareScreen'); 53 | this.resumeButton = container.querySelector('.resume'); 54 | this.facebookShare = container.querySelector('.facebook'); 55 | this.twitterShare = container.querySelector('.twitter'); 56 | 57 | if (options.hidden) { 58 | this.setPlayerState('hidden'); 59 | } 60 | 61 | // Replace the video with the overlay and insert it into the overlay. 62 | video.parentNode.insertBefore(container, video); 63 | video.parentNode.removeChild(video); 64 | this.videoOverlay.appendChild(video); 65 | 66 | // Bind event handlers 67 | this.handleEvent(video, 'play', 'onPlay'); 68 | this.handleEvent(video, 'ended', 'onEnded'); 69 | this.handleEvent(this.closeButton, 'click', 'onClickClose'); 70 | this.handleEvent(this.shareButton, 'click', 'onClickShare'); 71 | this.handleEvent(this.resumeButton, 'click', 'onClickResume'); 72 | this.handleEvent(this.facebookShare, 'click', 'onClickSocial'); 73 | this.handleEvent(this.twitterShare, 'click', 'onClickSocial'); 74 | } 75 | 76 | VideoShareOverlay.prototype = { 77 | // Set a method on this object as the event handler. 78 | handleEvent: function(obj, eventName, handlerName) { 79 | var self = this; 80 | obj.addEventListener(eventName, function(e) { 81 | self[handlerName](e); 82 | }); 83 | }, 84 | 85 | setPlayerState: function(state) { 86 | this.util.removeClass(this.videoOverlay, 'visible', 'hidden'); 87 | this.util.addClass(this.videoOverlay, state); 88 | }, 89 | 90 | setShareState: function(state) { 91 | this.util.removeClass(this.videoOverlay, 'share-visible', 92 | 'share-hidden'); 93 | this.util.addClass(this.videoOverlay, 'share-' + state); 94 | }, 95 | 96 | hide: function() { 97 | this.setPlayerState('hidden'); 98 | this.video.pause(); 99 | }, 100 | 101 | show: function() { 102 | this.setPlayerState('visible'); 103 | }, 104 | 105 | hideShare: function() { 106 | this.setShareState('hidden'); 107 | }, 108 | 109 | showShare: function() { 110 | this.setShareState('visible'); 111 | this.video.pause(); 112 | }, 113 | 114 | onPlay: function(e) { 115 | e.preventDefault(); 116 | this.util.addClass(this.videoOverlay, 'started'); 117 | }, 118 | 119 | onEnded: function(e) { 120 | e.preventDefault(); 121 | this.util.addClass(this.resumeButton, 'replay'); 122 | this.resumeButton.innerHTML = this.strings.replay; 123 | this.ended = true; 124 | this.showShare(); 125 | }, 126 | 127 | onClickClose: function(e) { 128 | e.preventDefault(); 129 | this.hide(); 130 | }, 131 | 132 | onClickShare: function(e) { 133 | e.preventDefault(); 134 | this.video.pause(); 135 | 136 | 137 | this.util.removeClass(this.resumeButton, 'replay'); 138 | this.resumeButton.innerHTML = this.strings.resume; 139 | this.showShare(); 140 | }, 141 | 142 | onClickResume: function(e) { 143 | e.preventDefault(); 144 | if (this.ended) { 145 | this.ended = false; 146 | this.video.currentTime = 0; 147 | } 148 | 149 | this.hideShare(); 150 | this.video.play(); 151 | }, 152 | 153 | onClickSocial: function(e) { 154 | e.preventDefault(); 155 | var link = e.target; 156 | window.open(link.href, 'share-' + link.className, 'toolbar=0,' + 157 | 'status=0,width=600,height=400').focus(); 158 | }, 159 | 160 | util: { 161 | buildTwitterURL: function(shareURL, message) { 162 | return ('https://twitter.com/share?url=' + 163 | encodeURIComponent(shareURL) + '&text=' + 164 | encodeURIComponent(message)); 165 | }, 166 | 167 | buildFacebookURL: function(shareURL) { 168 | return ('https://facebook.com/sharer.php?u=' + 169 | encodeURIComponent(shareURL)); 170 | }, 171 | 172 | extend: function(obj) { 173 | var sources = Array.prototype.slice.call(arguments, 1); 174 | for (var k = 0; k < sources.length; k++) { 175 | var source = sources[k]; 176 | for (var prop in source) { 177 | if (source.hasOwnProperty(prop)) { 178 | obj[prop] = source[prop]; 179 | } 180 | } 181 | } 182 | return obj; 183 | }, 184 | 185 | addClass: function(el, klass) { 186 | var className = ' ' + el.className + ' '; 187 | if (className.indexOf(' ' + klass + ' ') === -1) { 188 | el.className += ' ' + klass; 189 | } 190 | }, 191 | 192 | removeClass: function(el) { 193 | var oldClasses = el.className.split(/\s+/); 194 | var newClasses = []; 195 | var removeClasses = Array.prototype.slice.call(arguments, 1); 196 | for (var k = 0; k < oldClasses.length; k++) { 197 | if (removeClasses.indexOf(oldClasses[k]) === -1) { 198 | newClasses.push(oldClasses[k]); 199 | } 200 | } 201 | el.className = newClasses.join(' '); 202 | } 203 | } 204 | }; 205 | 206 | var snippet = document.querySelector('#flicks-2012-snippet'); 207 | var video = snippet.querySelector('video'); 208 | var showVideoLink = snippet.querySelector('.show-video'); 209 | 210 | var shareOverlay = new VideoShareOverlay(video, 'http://mzl.la/JSGZHP', { 211 | hidden: true, 212 | externalLink: { 213 | href: 'https://firefoxflicks.mozilla.org', 214 | label: 'Visit firefoxflicks.org' 215 | }, 216 | strings: { 217 | shareLabel: 'Share', 218 | shareScreenPrompt: 'Share', 219 | resume: 'Resume', 220 | replay: 'Replay', 221 | twitterShare: 'What if companies tracked you offline like they do online? This winning #Firefox Flicks video has the answer. Via @Firefox' 222 | } 223 | }); 224 | 225 | // Trigger animation when show video link is clicked. 226 | showVideoLink.addEventListener('click', function(e) { 227 | e.preventDefault(); 228 | shareOverlay.show(); 229 | }, false); 230 | })(); 231 | -------------------------------------------------------------------------------- /legacy/july2012/README.md: -------------------------------------------------------------------------------- 1 | # about:home Snippets for July 2012 campaign 2 | 3 | This promotional campaign happened to coincide with an international sporting event. 4 | 5 | There are two snippets. One features a video highlighting the international, multilingual 6 | nature of Firefox. The other promotes a collection of international flag personas. 7 | 8 | Localized strings can be found at http://l10n.mozilla-community.org/~pascalc/langchecker/?action=translate&file=olympics.lang 9 | 10 | The CSS animation was done by Particle (particularplace.com), and their original, unminified 11 | code is included here as well. 12 | 13 | ## License 14 | 15 | Any copyright is dedicated to the Public Domain. 16 | http://creativecommons.org/publicdomain/zero/1.0/ 17 | -------------------------------------------------------------------------------- /legacy/july2012/images/cauldron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/cauldron.png -------------------------------------------------------------------------------- /legacy/july2012/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/close.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Argentina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Argentina.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Brazil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Brazil.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_China.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_China.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_FFlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_FFlogo.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_France.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_France.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Germany.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Germany.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_India.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_India.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Indonesia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Indonesia.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Italy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Italy.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Japan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Japan.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Mexico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Mexico.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Phillipines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Phillipines.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_PlayIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_PlayIcon.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Russia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Russia.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Spain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Spain.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_Taiwan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_Taiwan.png -------------------------------------------------------------------------------- /legacy/july2012/images/flags/40x50_UK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flags/40x50_UK.png -------------------------------------------------------------------------------- /legacy/july2012/images/flame-bits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/flame-bits.png -------------------------------------------------------------------------------- /legacy/july2012/images/frame-five.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/frame-five.png -------------------------------------------------------------------------------- /legacy/july2012/images/frame-four.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/frame-four.png -------------------------------------------------------------------------------- /legacy/july2012/images/frame-one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/frame-one.png -------------------------------------------------------------------------------- /legacy/july2012/images/frame-three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/frame-three.png -------------------------------------------------------------------------------- /legacy/july2012/images/frame-two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/july2012/images/frame-two.png -------------------------------------------------------------------------------- /legacy/jumping-fox-game/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | tmp/ 3 | -------------------------------------------------------------------------------- /legacy/jumping-fox-game/Makefile: -------------------------------------------------------------------------------- 1 | # folders 2 | BIN = bin/ 3 | TMP = tmp/ 4 | 5 | # files 6 | PROG = $(BIN)index.html 7 | INDEXIN = index.html 8 | IMAGEJSOUT = $(TMP)images.js 9 | SPRITE = sprites.png 10 | CRAFTYSRC = crafty.js 11 | GAMESRC = game.js 12 | JSOUT = $(TMP)compiled.js 13 | IMGTMP = $(TMP)encoded.txt 14 | IMGOUT = $(TMP)encoded_.txt 15 | 16 | all : folders $(PROG) 17 | 18 | folders : 19 | [ -d $(BIN) ] || mkdir $(BIN) 20 | [ -d $(TMP) ] || mkdir $(TMP) 21 | 22 | $(PROG) : $(INDEXIN) $(JSOUT) 23 | ./scripts/replace_script_tags.py $(INDEXIN) $(JSOUT) > $(PROG) 24 | 25 | # minify and concatenate js files 26 | $(JSOUT) : $(CRAFTYSRC) $(IMAGEJSOUT) $(GAMESRC) 27 | ./scripts/compile.py $(CRAFTYSRC) > $(JSOUT) 28 | cat $(IMAGEJSOUT) >> $(JSOUT) 29 | ./scripts/compile.py $(GAMESRC) >> $(JSOUT) 30 | 31 | # encode image to base64 and include it in a js file 32 | $(IMAGEJSOUT) : $(SPRITE) 33 | base64 $(SPRITE) > $(IMGTMP) 34 | awk '$$1=$$1' ORS='' $(IMGTMP) > $(IMGOUT) 35 | echo "var img = new Image();" > $(IMAGEJSOUT) 36 | echo "img.src = \"data:image/png;base64,`cat $(IMGOUT)`\";" >> $(IMAGEJSOUT) 37 | echo "img.alt = '';" >> $(IMAGEJSOUT) 38 | echo "Crafty.assets['$(SPRITE)'] = img;" >> $(IMAGEJSOUT) 39 | 40 | clean : 41 | rm -rf $(BIN)* 42 | rm -rf $(TMP)* 43 | -------------------------------------------------------------------------------- /legacy/jumping-fox-game/README.md: -------------------------------------------------------------------------------- 1 | # about:home Jumping Fox Game Snippet 2 | 3 | Snippet for the Firefox about:home page that let you play with a fox. Jump over enemies, catch stars and make a lot of points! 4 | 5 | ## Development 6 | 7 | * Set up [home-snippets-server][] and install [home-snippets-switcher][]. 8 | * Open a terminal. 9 | * `git clone git://github.com/mozilla/about-home-jumping-fox-game.git` 10 | * `cd about-home-jumping-fox-game` 11 | * `make` 12 | * Paste the contents of `./bin/index.html` into a new snippet via the home-snippets-server admin interface. 13 | * If you started the home-snippets-server with `python manage.py runserver` the admin interface is located at . 14 | * In the `about-home-jumping-fox-game` directory, run the command `python -m SimpleHTTPServer 3033` 15 | * This runs a web server in the current directory on port 3033. If you want to use a different port, you will have to change the command as well as changing the iframe link in the snippet code. 16 | * Navigate to `about:home` and make sure you point the home-snippets-switcher to `http://localhost:8000` 17 | 18 | [home-snippets-server]: https://github.com/lmorchard/home-snippets-server 19 | [home-snippets-switcher]: https://github.com/lmorchard/home-snippets-switcher 20 | -------------------------------------------------------------------------------- /legacy/jumping-fox-game/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Game Snippet 6 | 7 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /legacy/jumping-fox-game/scripts/compile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import httplib, urllib, re, sys 4 | 5 | file_number = len(sys.argv) 6 | data = '' 7 | headers = { "Content-type": "application/x-www-form-urlencoded" } 8 | conn = httplib.HTTPConnection('closure-compiler.appspot.com') 9 | 10 | for i in xrange(1, file_number): 11 | js_file = open(sys.argv[i]) 12 | content = js_file.read() 13 | 14 | # Define the parameters for the POST request and encode them in 15 | # a URL-safe format. 16 | 17 | params = urllib.urlencode([ 18 | ('js_code', content), 19 | ('compilation_level', 'WHITESPACE_ONLY'), 20 | ('output_format', 'text'), 21 | ('output_info', 'compiled_code'), 22 | ]) 23 | 24 | # Always use the following value for the Content-type header. 25 | conn.request('POST', '/compile', params, headers) 26 | response = conn.getresponse() 27 | res = response.read() 28 | resNoSpace = re.sub(r'[\s]*', '', res) 29 | if not resNoSpace: 30 | res = content 31 | data = " ".join((data, res)) 32 | 33 | print data 34 | conn.close 35 | -------------------------------------------------------------------------------- /legacy/jumping-fox-game/scripts/replace_script_tags.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import re, sys 4 | 5 | if len(sys.argv) < 2: 6 | print 'More args needed.' 7 | exit 8 | 9 | inputFile = open(sys.argv[1]) 10 | scriptFile = open(sys.argv[2]) 11 | data = inputFile.read() 12 | scriptContent = scriptFile.read() 13 | 14 | data = re.sub(r'', '', data) 15 | data = re.sub(r'[\s]*', ''.join(('')), data) 16 | 17 | print data 18 | -------------------------------------------------------------------------------- /legacy/jumping-fox-game/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mozmeao/snippets/2054899350590adcb3c0b0a341c782b0e2f81d0b/legacy/jumping-fox-game/sprites.png -------------------------------------------------------------------------------- /legacy/logo-swap-about-accounts-links.html: -------------------------------------------------------------------------------- 1 | <-- Archived. Do not use. about:accounts links to not need special templates anymore. --> 2 | 16 |
17 | 18 | 19 | 20 |

{{ text|safe }}

21 |
22 | 79 | -------------------------------------------------------------------------------- /legacy/persona-switcher/README.md: -------------------------------------------------------------------------------- 1 | # about:home Persona Switcher Snippet 2 | 3 | Snippet for the Firefox about:home page that showcases personas and allows users to preview and install the personas directly from the about:home page. 4 | 5 | ## Development 6 | 7 | * Set up [home-snippets-server][] and install [home-snippets-switcher][]. 8 | * Open a terminal. 9 | * `git clone git://github.com/mozilla/about-home-persona-switcher.git` 10 | * `cd about-home-persona-switcher` 11 | * Paste the contents of `./snippet.html` into a new snippet via the home-snippets-server admin interface. 12 | * If you started the home-snippets-server with `python manage.py runserver` the admin interface is located at . 13 | * In the `about-home-persona-switcher` directory, run the command `python -m SimpleHTTPServer 3033` 14 | * This runs a web server in the current directory on port 3033. If you want to use a different port, you will have to change the command as well as changing the iframe link in the snippet code. 15 | * Navigate to `about:home` and make sure you point the home-snippets-switcher to `http://localhost:8000` 16 | 17 | [home-snippets-server]: https://github.com/lmorchard/home-snippets-server 18 | [home-snippets-switcher]: https://github.com/lmorchard/home-snippets-switcher 19 | -------------------------------------------------------------------------------- /legacy/persona-switcher/snippet.html: -------------------------------------------------------------------------------- 1 |
2 | 16 | 17 |
18 | -------------------------------------------------------------------------------- /legacy/pianno-snippet/.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | !build/.gitignore 3 | *~ 4 | *.pyc 5 | .snippetconfig 6 | *.pyc 7 | -------------------------------------------------------------------------------- /legacy/pianno-snippet/README.md: -------------------------------------------------------------------------------- 1 | # about:home Piano Snippet 2 | 3 | Snippet that lets Firefox users play an HTML5-powered piano on the about:home 4 | page. -------------------------------------------------------------------------------- /legacy/pianno-snippet/content.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /legacy/pianno-snippet/css/styles.css: -------------------------------------------------------------------------------- 1 | #piano_snippet_iframe { 2 | display: none; 3 | } 4 | 5 | #piano_controls { 6 | display: none; 7 | } -------------------------------------------------------------------------------- /legacy/pianno-snippet/fabfile.py: -------------------------------------------------------------------------------- 1 | # TODO: Determine how to organize code 2 | # TODO: Figure out a better way to edit the DB 3 | 4 | import ConfigParser 5 | import os 6 | import select 7 | import sqlite3 8 | 9 | from fabric.decorators import task 10 | from glob import glob 11 | from os.path import isfile 12 | from string import Template 13 | 14 | BUILD_DIR = 'build' 15 | BUILD_JS_FILE = BUILD_DIR + '/compiled.min.js' 16 | BUILD_CSS_FILE = BUILD_DIR + '/compiled.css' 17 | BUILD_OUT_FILE = BUILD_DIR + '/snippet.html' 18 | 19 | SCRIPTS_DIR = 'scripts' 20 | CSS_DIR = 'css' 21 | 22 | SNIPPET_TEMPLATE_FILE = 'snippet_template.html' 23 | SNIPPET_CONTENT_FILE = 'content.html' 24 | 25 | config = ConfigParser.ConfigParser() 26 | config.read('.snippetconfig') 27 | database_present = config.has_section('Database') 28 | 29 | 30 | @task 31 | def monitor_build_push(): 32 | """ 33 | Monitors the current directory for changes and pushes when they happen 34 | """ 35 | 36 | monitor = DirectoryMonitor('./') 37 | print "Monitoring for changes..." 38 | 39 | while True: 40 | if monitor.is_directory_changed(): 41 | print "Change detected, pushing..." 42 | build_all_push() 43 | 44 | 45 | class DirectoryMonitor: 46 | def __init__(self, path): 47 | directories = os.walk(path) 48 | 49 | self.kitems = [] 50 | self.kq = select.kqueue() 51 | for d in directories: 52 | # Ignore .git and the like 53 | # TODO: Handle embedded dot directories 54 | if d[0].startswith('./.'): 55 | continue 56 | 57 | # Setup kqueue for monitoring 58 | directory = os.open(d[0], os.O_RDONLY) 59 | ke = select.kevent(directory, filter=select.KQ_FILTER_VNODE, 60 | flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE | 61 | select.KQ_EV_CLEAR, 62 | fflags=select.KQ_NOTE_DELETE | 63 | select.KQ_NOTE_WRITE) 64 | self.kq.control([ke], 0, None) 65 | self.kitems.append((ke, directory)) 66 | 67 | def __del__(self): 68 | for (ke, directory) in self.kitems: 69 | directory.close() 70 | 71 | def is_directory_changed(self): 72 | for (ke, directory) in self.kitems: 73 | raised_events = self.kq.control([ke], 1, None) 74 | for event in raised_events: 75 | if event.fflags & (select.KQ_NOTE_DELETE | 76 | select.KQ_NOTE_WRITE): 77 | return True 78 | 79 | return False 80 | 81 | 82 | @task 83 | def build_all_push(): 84 | build_all() 85 | push_to_db() 86 | 87 | 88 | @task 89 | def push_to_db(): 90 | """ 91 | Checks for database configuration info and pushes the last built snippet 92 | to the specified database 93 | """ 94 | 95 | if (database_present): 96 | with open(BUILD_OUT_FILE, 'r') as snippet: 97 | conn = sqlite3.connect(config.get('Database', 'db_path')) 98 | conn.execute(""" 99 | UPDATE homesnippets_snippet 100 | SET body=? 101 | WHERE id=? 102 | """, (snippet.read(), config.get('Database', 'snippet_id'))) 103 | conn.commit() 104 | conn.close() 105 | 106 | 107 | @task 108 | def db_setup(): 109 | """Setup database details and create snippet to push updates to.""" 110 | 111 | if not config.has_section('Database'): 112 | config.add_section('Database') 113 | 114 | db_path = raw_input('Enter the absolute path to the sqlite ' 115 | 'database file: ') 116 | 117 | while not _test_sqlite3_db(db_path): 118 | db_path = raw_input('Error validating database. Enter absolute path' 119 | ' to database file (blank to quit setup): ') 120 | if not db_path: 121 | return 122 | 123 | config.set('Database', 'db_path', db_path) 124 | 125 | # Set up snippet to push to 126 | conn = sqlite3.connect(db_path) 127 | 128 | # Create Snippet 129 | conn.execute(""" 130 | INSERT INTO homesnippets_clientmatchrule (description, exclude, 131 | created, modified) 132 | VALUES ('Matches Anything', 0, datetime('now'), datetime('now')) 133 | """) 134 | client_rule_id = _get_last_insert_rowid(conn) 135 | 136 | # Create client rule 137 | conn.execute(""" 138 | INSERT INTO homesnippets_snippet (name, body, disabled, preview, 139 | created, modified) 140 | VALUES (?, '', 0, 0, datetime('now'), datetime('now')) 141 | """, ('Autogenerated Snippet',)) 142 | snippet_id = _get_last_insert_rowid(conn) 143 | 144 | # Associate snippet with rule 145 | conn.execute(""" 146 | INSERT INTO homesnippets_snippet_client_match_rules 147 | (snippet_id, clientmatchrule_id) 148 | VALUES (?, ?) 149 | """, (snippet_id, client_rule_id)) 150 | 151 | conn.commit() 152 | conn.close() 153 | 154 | config.set('Database', 'snippet_id', snippet_id) 155 | config.set('Database', 'client_rule_id', client_rule_id) 156 | 157 | # TODO: Handle failure better 158 | with open('.snippetconfig', 'w') as f: 159 | config.write(f) 160 | 161 | 162 | def _get_last_insert_rowid(conn): 163 | cursor = conn.execute('SELECT last_insert_rowid()') 164 | result = cursor.fetchone() 165 | if result is not None: 166 | return result[0] 167 | else: 168 | return None 169 | 170 | 171 | def _test_sqlite3_db(db_path): 172 | """Very basic test for validity of database.""" 173 | 174 | # Check for file existance and if it's a sqlite3 db 175 | if isfile(db_path): 176 | try: 177 | conn = sqlite3.connect(db_path) 178 | 179 | # TODO: If we really care, do a more thorough check 180 | # If it has the homesnippets_snippet table we're content 181 | tables = [r[0] for r in conn.execute(""" 182 | SELECT name FROM sqlite_master 183 | WHERE type='table' 184 | """).fetchall()] 185 | conn.close() 186 | 187 | if 'homesnippets_snippet' in tables: 188 | return True 189 | except sqlite3.DatabaseError: 190 | pass 191 | 192 | return False 193 | 194 | 195 | @task 196 | def build_all(): 197 | combine_js() 198 | combine_css() 199 | build_snippet() 200 | 201 | 202 | @task 203 | def combine_js(): 204 | """Combines every .js file in the SCRIPTS_DIR into one script.""" 205 | 206 | _combine_files(SCRIPTS_DIR + '/*.js', BUILD_JS_FILE) 207 | 208 | 209 | @task 210 | def combine_css(): 211 | """Combines every .css file in the CSS_DIR into one file.""" 212 | 213 | _combine_files(CSS_DIR + '/*.css', BUILD_CSS_FILE) 214 | 215 | 216 | def _combine_files(glob_mask, combined_file_name): 217 | """Combines all files that match glob_mask into one file.""" 218 | 219 | files = [] 220 | for file in glob(glob_mask): 221 | with open(file, 'r') as f: 222 | files.append(f.read()) 223 | 224 | with open(combined_file_name, 'w') as f: 225 | f.write('\n'.join(files)) 226 | 227 | 228 | @task 229 | def build_snippet(): 230 | """ 231 | Combines the compiled JS, CSS, and content into the template and outputs 232 | the result. 233 | """ 234 | 235 | js_file = open(BUILD_JS_FILE, 'r') 236 | css_file = open(BUILD_CSS_FILE, 'r') 237 | template_file = open(SNIPPET_TEMPLATE_FILE, 'r') 238 | content_file = open(SNIPPET_CONTENT_FILE, 'r') 239 | 240 | template = Template(template_file.read()) 241 | compiled = template.substitute({ 242 | 'css': css_file.read(), 243 | 'js': js_file.read(), 244 | 'content': content_file.read() 245 | }) 246 | 247 | content_file.close() 248 | template_file.close() 249 | css_file.close() 250 | js_file.close() 251 | 252 | output_file = open(BUILD_OUT_FILE, 'w') 253 | output_file.write(compiled) 254 | output_file.close() 255 | -------------------------------------------------------------------------------- /legacy/pianno-snippet/scripts/code.js: -------------------------------------------------------------------------------- 1 | var iframe = document.getElementById("piano_snippet_iframe"); 2 | (function() { 3 | var textbox = document.getElementById("searchText"), 4 | recording_url = document.getElementById("recording_url"), 5 | start_record_button = document.getElementById("record_button"), 6 | stop_record_button = document.getElementById("stop_record_button"), 7 | playback_button = document.getElementById("playback_button"), 8 | enable_button = document.getElementById('enable_piano'), 9 | piano_controls = document.getElementById('piano_controls'), 10 | 11 | channels = {}, 12 | recordingBuffer = [], 13 | is_recording = false, 14 | delay_start = 0, 15 | 16 | keymap = { 17 | 65: 'c', // a 18 | 87: 'cs', // w 19 | 83: 'd', // s 20 | 69: 'eb', // e 21 | 68: 'e', // d 22 | 70: 'f', // f 23 | 84: 'fs', // t 24 | 71: 'g', // g 25 | 89: 'gs', // y 26 | 72: 'a', // h 27 | 85: 'bb', // u 28 | 74: 'b', // j 29 | }; 30 | 31 | function getCurrentTime() { 32 | return (new Date()).getTime(); 33 | } 34 | 35 | function receiveAudioData(e) { 36 | loadAudioData(JSON.parse(e.data)); 37 | } 38 | 39 | function loadAudioData(data) { 40 | for (note in data) { 41 | channels[note] = new Audio("data:audio/ogg;base64," + data[note]); 42 | } 43 | } 44 | 45 | function keyDownCallback(e) { 46 | if (e.keyCode in keymap) { 47 | var key_str = keymap[e.keyCode]; 48 | playNote(key_str); 49 | } 50 | } 51 | 52 | function playNote(note) { 53 | var key = channels[note]; 54 | key.pause(); 55 | key.currentTime = 0; 56 | key.play(); 57 | 58 | if (is_recording) { 59 | var cur_time = (new Date()).getTime(); 60 | recordingBuffer.push(cur_time - delay_start); 61 | delay_start = cur_time; 62 | recordingBuffer.push(note); 63 | } 64 | } 65 | 66 | function startRecording() { 67 | is_recording = true; 68 | recordingBuffer = []; 69 | delay_start = (new Date()).getTime(); 70 | } 71 | 72 | function stopRecording() { 73 | is_recording = false; 74 | recording_url.value = recordingBuffer.join(";"); 75 | } 76 | 77 | function playbackCallback() { 78 | playbackRecording(recording_url.value.split(";")); 79 | } 80 | 81 | function playbackRecording(rec_actions) { 82 | if (rec_actions.length > 1) { 83 | var delay = rec_actions.shift(); 84 | var note = rec_actions.shift(); 85 | var last_event = getCurrentTime();; 86 | 87 | var playback_interval = setInterval(function() { 88 | var current_time = getCurrentTime(); 89 | if (current_time - last_event > delay) { 90 | playNote(note); 91 | last_event = current_time; 92 | 93 | if (rec_actions.length > 1) { 94 | delay = rec_actions.shift(); 95 | note = rec_actions.shift(); 96 | } else { 97 | clearInterval(playback_interval); 98 | } 99 | } 100 | }, 15); 101 | } 102 | } 103 | 104 | enable_button.addEventListener('click', function() { 105 | window.addEventListener('keydown', keyDownCallback, false); 106 | piano_controls.style.display = 'block'; 107 | enable_button.style.display = 'none'; 108 | }, false); 109 | 110 | window.addEventListener('message', receiveAudioData, false); 111 | start_record_button.addEventListener('click', startRecording, false); 112 | stop_record_button.addEventListener('click', stopRecording, false); 113 | playback_button.addEventListener('click', playbackCallback, false); 114 | })(); -------------------------------------------------------------------------------- /legacy/pianno-snippet/snippet_template.html: -------------------------------------------------------------------------------- 1 |
2 | 5 | $content 6 | 11 |
12 | -------------------------------------------------------------------------------- /legacy/split-snippet/README.md: -------------------------------------------------------------------------------- 1 | # Split Snippet 2 | 3 | The split snippet is a snippet that has a normal snippet and an alternative 4 | snippet. Most of the time the normal snippet is the only one seen, but there is 5 | a chance that in it's place the alternative snippet will be shown instead. 6 | 7 | The alternative snippet only has a chance to show when the split snippet is 8 | chosen by the random snippet choice that normally happens on about home. If, for 9 | example, there are 4 snippets available and the alternative snippet has a 10% 10 | chance of being seen, the alternative snippet will be seen 25% * 10% = 2.5% of 11 | the time, while the normal snippet will be seen 25% - 2.5% = 22.5% of the time. 12 | The other 3 snippets will all be seen 25% of the time as usual. 13 | -------------------------------------------------------------------------------- /standard-css/README.md: -------------------------------------------------------------------------------- 1 | # Standard CSS Snippet 2 | 3 | This snippet is delivered to all users and defines basic styling for all 4 | snippets. 5 | 6 | See [the snippets service repository](https://github.com/mozilla/snippets-service/blob/master/snippets/base/templates/base/includes/snippet_css.html) for the latest version. 7 | -------------------------------------------------------------------------------- /standard-css/legacy-css.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /standard-js/README.md: -------------------------------------------------------------------------------- 1 | # Standard Snippet JS 2 | 3 | This is the Javascript that is always sent by the snippets service. It's main 4 | purpose is to randomly choose a snippet and display it to the user. 5 | 6 | See also [the snippets service repository](https://github.com/mozilla/snippets-service/blob/master/snippets/base/templates/base/includes/snippet_js.html) for the latest version. 7 | -------------------------------------------------------------------------------- /standard-js/snippet.html: -------------------------------------------------------------------------------- 1 | // Go to https://github.com/mozilla/snippets-service/blob/master/snippets/base/templates/base/includes/snippet_js.html 2 | --------------------------------------------------------------------------------