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 |
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 |
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!
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 |
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 |
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 |
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 |
128 |
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 |
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 |
--------------------------------------------------------------------------------