Compress initial commit
|
@ -0,0 +1,27 @@
|
|||
*.swp
|
||||
*~
|
||||
dist
|
||||
.DS_Store
|
||||
*.bak
|
||||
*.webm
|
||||
*.mov
|
||||
*.avi
|
||||
*.ogg
|
||||
*.ogv
|
||||
*.oga
|
||||
*.mp4
|
||||
*.wav
|
||||
*.mp3
|
||||
*.sqlite
|
||||
node_modules
|
||||
cornfield/view
|
||||
css/butter.ui.css
|
||||
css/transitions.css
|
||||
css/embed-shell.css
|
||||
cornfield/config/runtime.json
|
||||
cornfield/config/versions.json
|
||||
docs
|
||||
css/embed.css
|
||||
templates/assets/plugins/wikipedia/popcorn.wikipedia.css
|
||||
templates/assets/css/jquery-ui/jquery.ui.butter.css
|
||||
src/ui/webmakernav/webmakernav.css
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "external/popcorn-js"]
|
||||
path = external/popcorn-js
|
||||
url = git://github.com/mozilla/popcorn-js.git
|
||||
[submodule "external/html5-lint"]
|
||||
path = external/html5-lint
|
||||
url = git://github.com/mozilla/html5-lint.git
|
|
@ -0,0 +1,65 @@
|
|||
{
|
||||
// Environments
|
||||
"browser" : true,
|
||||
"devel": true,
|
||||
"node" : true,
|
||||
"nonstandard": true,
|
||||
"predef": [
|
||||
"Popcorn",
|
||||
"requirejs",
|
||||
"require",
|
||||
"define"
|
||||
],
|
||||
|
||||
// Enforcing
|
||||
//"bitwise": true,
|
||||
//"camelcase": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"forin": true,
|
||||
"immed": true,
|
||||
//"indent": 2,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": true,
|
||||
"nonew": true,
|
||||
//"plusplus": true,
|
||||
//"quotmark": true,
|
||||
//"regexp": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"strict": false,
|
||||
"trailing": true,
|
||||
//"maxparams": 4,
|
||||
//"maxdepth": 3,
|
||||
//"maxstatements": 4,
|
||||
//"maxcomplexity": 5,
|
||||
|
||||
// Relaxing
|
||||
//"asi": true,
|
||||
//"boss": true,
|
||||
//"debug": true,
|
||||
//"eqnull": true,
|
||||
"es5" : true,
|
||||
//"esnext": true,
|
||||
//"evil": true,
|
||||
//"expr": true,
|
||||
//"funcscope": true,
|
||||
"globalstrict": true
|
||||
//"iterator": true,
|
||||
//"lastsemic": true,
|
||||
//"laxbreak": true,
|
||||
//"laxcomma": true,
|
||||
//"loopfunc": true,
|
||||
//"multistr": true,
|
||||
//"onecase": true,
|
||||
//"proto": true,
|
||||
//"regexdash": true,
|
||||
//"scripturl": true,
|
||||
//"smarttabs": true,
|
||||
//"shadow": true,
|
||||
//"sub": true
|
||||
//"supernew": true,
|
||||
//"validthis": true,
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
||||
before_script: node make check
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.mozilla.org#popcorn"
|
||||
on_success: change
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2011, 2012 Mozilla Foundation
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
|
@ -0,0 +1,3 @@
|
|||
/*! This Source Code Form is subject to the terms of the MIT license
|
||||
* If a copy of the MIT license was not distributed with this file, you can
|
||||
* obtain one at http://www.mozillapopcorn.org/butter-license.txt */
|
|
@ -0,0 +1,278 @@
|
|||
Butter
|
||||
======
|
||||
|
||||
An SDK for authoring Popcorn projects.
|
||||
|
||||
Supported Platforms
|
||||
-------------------
|
||||
|
||||
We're writing Butter so that it runs in modern, HTML5 compatible browsers. For version 1.0, we're targeting modern HTML5 desktop browsers. In the current version we are supporting:
|
||||
|
||||
### Desktop:
|
||||
* Chrome stable
|
||||
* Firefox stable
|
||||
* Internet Explorer 9+
|
||||
* Safari stable
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* node v0.8 or higher
|
||||
* npm (comes with node v0.8 installer)
|
||||
* mongodb v2.0.8 or higher
|
||||
* A working build environment:
|
||||
* Mac OS X - Xcode or Command Line Tools package
|
||||
* Windows - Python 2.5+ and Visual Studio 2010 (C++ Express edition works fine)
|
||||
* Linux - build-essential package on Debian/Ubuntu, or the equivalent for your distro
|
||||
|
||||
Environment Setup
|
||||
-----------------
|
||||
|
||||
1. `git clone --recursive https://github.com/mozilla/butter.git`
|
||||
2. `cd butter`
|
||||
3. `npm install`
|
||||
|
||||
Running Butter in development mode
|
||||
----------------------------------
|
||||
|
||||
1. Run `node make server`.
|
||||
2. Navigate to [http://localhost:8888/](http://localhost:8888/) in your favourite browser.
|
||||
|
||||
If you want to change the bind IP or port check the Configuration section below.
|
||||
|
||||
Packaging and Distributing Butter
|
||||
--------------------------------
|
||||
|
||||
Running `node make deploy` will compile all the necessary files into the `dist/` folder.
|
||||
Run `NODE_ENV=production node app.js` in the `dist/cornfield` directory in order to run the server in production mode.
|
||||
|
||||
Cornfield
|
||||
---------
|
||||
|
||||
Cornfield is PopcornMaker's back-end server system, designed to serve content to users, store their ongoing work, and publish what they've done.
|
||||
|
||||
### Storage
|
||||
|
||||
There are two types of storage Cornfield needs to run:
|
||||
|
||||
* A database: To store user project data, a database is required. Cornfield uses the `Sequelize` middleware, so multiple database options are available. You are responsible for setting up and maintaining a PostgreSQL or MySQL database enrivonment if you choose to use either, so make sure a user has access to a database called `popcorn` for cornfield to run correctly.
|
||||
|
||||
* A data-blob store: To store published projects, Cornfield can use the filesystem, or Amazon's S3. See the configuration options below for setting up this feature for your environment.
|
||||
|
||||
|
||||
### Configuration
|
||||
|
||||
There are several configuration files in cornfield/config/ that control how cornfield works.
|
||||
They are applied in order from most general to most specific to present one configuration
|
||||
to the server:
|
||||
|
||||
1. default.json
|
||||
2. _hostname_.json
|
||||
3. _environment_.json
|
||||
4. _hostname_-_environment_.json
|
||||
5. runtime.json
|
||||
|
||||
_hostname_ and _environment_ are variable:
|
||||
|
||||
* _hostname_ - The hostname of the machine. Defaults to the output of `hostname` on the cli.
|
||||
* _environment_ - The value of the `NODE_ENV` environment variable. Defaults to `development`.
|
||||
|
||||
To change the cornfield configuration for your deployment of Butter, it's best to create a
|
||||
new file called _hostname_-_environment_.json that overrides the cornfield defaults.
|
||||
|
||||
#### Configuration Options
|
||||
|
||||
- `server` settings for the cornfield server
|
||||
- `bindIP` the IP or hostname to use for the server (e.g., localhost).
|
||||
- `bindPort` the Port number to use for the server (e.g., 8888). If using a port number lower than 1024, the server will have to be run as root.
|
||||
- `logger` settings for server logging
|
||||
- `format` the logging format to use. Possible values include: default, short, tiny, dev.
|
||||
- `session` settings for user sessions
|
||||
- `secret` the sessions secret (i.e., some long string)
|
||||
- `duration` the session's duration (e.g., 2419200000)
|
||||
- `staticMiddleware` settings for cornfield Connect middleware
|
||||
- `maxAge` the max age of static assests
|
||||
- `dirs` settings for various directories, paths, hostnames
|
||||
- `wwwRoot` the server's WWW root directory (e.g., `../`)
|
||||
- `templates` the location of templates (e.g., `../templates`)
|
||||
- `appHostname` the hostname URL for the application, usually the same as `server.bindIP` and `server.bindPort` (e.g., `http://localhost:8888`)
|
||||
- `embedHostname` <i>[optional]</i> the hostname URL where published embed documents are stored, if different from `dirs.appHostname` (e.g., `http://s3.amazonaws.com/your-bucket`)
|
||||
- `templates` list of templates to serve. The format is as follows:
|
||||
`<template-name>`: `{{templateBase}}<path/to/template/config.json>`. The `{{templateBase}}` string will be replaced by the value in `dirs.templates` (e.g., "basic": "{{templateBase}}basic/config.json")
|
||||
|
||||
- `exportedAssets` list of scripts to include in exported assets. These are things like popcorn.js or other scripts that your exported projects depend upon in order to run.
|
||||
|
||||
- `additionalStaticRoots` list of additional roots to use.
|
||||
|
||||
- `database` database configuration options
|
||||
- `database` the database name. Used by mysql and postgresql
|
||||
- `username` the username to use when connecting to the database. Used by mysql and postgresql
|
||||
- `password` the password for the username. Used by mysql and postgresql
|
||||
- `options` additional sequelize options. Please see the [sequelize manual](http://www.sequelizejs.com/#usage-options) for the complete listing.
|
||||
- `dialect` the sql dialect of the database. Default is `mysql`, must be one of `mysql`, `sqlite`, or `postgresql`
|
||||
- `storage` the storage engine for sqlite. Default is `:memory:`, an in-memory db, must be a string representing a file path or `:memory:`
|
||||
- `logging` function to print sql queries to console. Default is `console.log`, must be a function or `false`
|
||||
- `host` hostname of the mysql or postgresql server. Default is `localhost`
|
||||
- `port` port of the mysql or postgresql server. Default is `3306`
|
||||
- `pool` connection pooling options for mysql and postgresql. Default is none
|
||||
- `maxConnections` - maximum number of connections open in the pool
|
||||
- `maxIdleTime` - maximum time in seconds to leave an idle connection open in the pool
|
||||
|
||||
- `publishStore` a `fileStore` used to publish project HTML files (see `fileStore` below for details)
|
||||
|
||||
- `feedbackStore` a `fileStore` used to publish feedback from the user as JSON (see `fileStore` below for details)
|
||||
|
||||
- `crashStore` a `fileStore` used to publish crash reports from the user as JSON (see `fileStore` below for details)
|
||||
|
||||
The `fileStore` type is used to setup a backend for storing data:
|
||||
|
||||
- `type` the type of file store to use. Possible values include `local` (i.e., local file system) and `s3` (i.e., Amazon S3)
|
||||
- `options` options for the file store, which depends on the type chosen.
|
||||
- local options
|
||||
- `root` the root directory under which all exported files are placed (e.g., `./view`)
|
||||
- `namePrefix` <i>[optional]</i> the path prefix to add to any filenames passed to the local file store. For example, if using "v" all filenames will become "v/<key>"
|
||||
- `nameSuffix` <i>[optional]</i> the filename suffix to use for all filenames (e.g., ".html")
|
||||
- s3 options
|
||||
- `key` the AWS S3 key to use for authentication
|
||||
- `secret` the AWS S3 secret to use for authentication
|
||||
- `bucket` the AWS S3 bucket name to use for storing key/value pairs
|
||||
- `namePrefix` <i>[optional]</i> the prefix to add to any key names passed to the s3 file store. For example, if using "v" all keys will become "v/<key>"
|
||||
- `nameSuffix` <i>[optional]</i> the suffix to add to any key names passed to the s3 file store. For example, if using ".json" all keys will end in ".json"
|
||||
- `contentType` <i>[optional]</i> the mime type to use for data written to S3. If none given `text/plain` is used.
|
||||
|
||||
### Sample production config
|
||||
|
||||
`alice-production.json:`
|
||||
|
||||
This sample config uses a mix of the local file system as well as Amazon S3 for storage.
|
||||
|
||||
```javascript
|
||||
{
|
||||
"server" : {
|
||||
"bindIP" : "0.0.0.0",
|
||||
"bindPort" : "80"
|
||||
},
|
||||
"logger" : {
|
||||
"format" : "default"
|
||||
},
|
||||
"session" : {
|
||||
"secret": "1721f7a15316469fa4a9-5117d0d20e9f"
|
||||
},
|
||||
"staticMiddleware": {
|
||||
"maxAge": "3600000"
|
||||
},
|
||||
"dirs": {
|
||||
"appHostname": "http://example.org",
|
||||
"embedHostname": "http://s3.amazonaws.com/my-bucket"
|
||||
},
|
||||
"publishStore": {
|
||||
"type": "s3",
|
||||
"options": {
|
||||
"namePrefix": "v",
|
||||
"key": "my-s3-key",
|
||||
"secret": "my-s3-secret",
|
||||
"contentType": "text/html"
|
||||
}
|
||||
},
|
||||
"feedbackStore": {
|
||||
"type": "local",
|
||||
"options": {
|
||||
"root": "./view",
|
||||
"namePrefix": "feedback",
|
||||
"nameSuffix": ".json"
|
||||
}
|
||||
},
|
||||
"crashStore": {
|
||||
"type": "local",
|
||||
"options": {
|
||||
"root": "./view",
|
||||
"namePrefix": "crash",
|
||||
"nameSuffix": ".json"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
Before contributing a new patch be sure to run the following:
|
||||
|
||||
* Run `node make check` to lint butter
|
||||
* Run `node make server` and navigate to `http://localhost:8888/test` to run the browser tests
|
||||
|
||||
If you are contributing changes to cornfield, make sure you run the cornfield tests from the butter root directory this command:
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
|
||||
Cornfield will attempt to run tests for using a mysql backend, but they will not run if mysql is not set up properly. To ensure that they run, use the `DB_HOST`, `DB_DATABASE`, `DB_USERNAME`, and `DB_PASSWORD` environment variables to tell the tests which host, database, username, and password to use respectively. If `DB_HOST` is left blank, `localhost` is assumed.
|
||||
|
||||
Getting Involved
|
||||
----------------
|
||||
|
||||
* Chat with the Popcorn community on irc.mozilla.org in the [#popcorn](irc://irc.mozilla.org/popcorn) channel. The developers hang out here on a daily basis.
|
||||
* We also have a [mailing list](https://mail.mozilla.org/listinfo/community-popcorn) that you can subscribe to.
|
||||
* File bugs and feature requests on our [issue tracker](https://webmademovies.lighthouseapp.com/projects/65733-butter/).
|
||||
* The latest code can be found on our [Github repository](https://github.com/mozilla/butter/).
|
||||
* If you'd like to contribute code, file a ticket on our issue tracker, and link to it from your Github pull request.
|
||||
|
||||
Contributing Design
|
||||
-------------------
|
||||
|
||||
### Where to find/drop files
|
||||
|
||||
Our design files are organized on dropbox, at this link:
|
||||
https://www.dropbox.com/sh/7vm2rvw3axvkp0k/Tk4MKH4nZe
|
||||
You can ask Kate ( k88hudson on IRC or Twitter ) to be added as a collaborator if you want to drop your files in here.
|
||||
|
||||
### File System
|
||||
* References: screen shots and other reference work from the webmaker project or HTML5 ecosystem
|
||||
* Wireframes: documents about the functionality/interaction/description of features
|
||||
* Visual Comps: UI mock-ups and style guide
|
||||
|
||||
### Working with lighthouse
|
||||
When someone assigns you a ticket, it will show up in your lighthouse queue with a status of `ui-comps-requested` or `assigned`.
|
||||
|
||||
If you want someone to review or give feedback on your work, the best thing to do is:
|
||||
* Put a link to your files in the ticket ( on our dropbox or somewhere externally )
|
||||
* Change the status of the ticket to `peer-review-requested` or `feedback-requested`, and choose a member of the team to be responsible.
|
||||
|
||||
Contributing Code
|
||||
-----------------
|
||||
|
||||
### Working with Lighthouse
|
||||
All of our code changes to Butter are documented in tickets, and go through two levels of peer-review. If you are interested in working on a ticket chose one from the [list of open tickets](https://webmademovies.lighthouseapp.com/projects/65733-popcorn-maker/milestones/current), ping any of the developers on IRC, and they will assign it to you.
|
||||
|
||||
### Working with branches and making a pull-request
|
||||
|
||||
* Each ticket is a separate branch, usually named after the ticket number. IE `t1234`
|
||||
* All commit messages must include the ticket number. IE `Bug 1234 - Fixed a thing` or `[t1234] Fixed a thing`
|
||||
* Before submitting a pull request, make sure you have rebased against the latest revision of master.
|
||||
|
||||
### Getting review
|
||||
All code changes in butter have to go through two levels of peer review. This improves the integrity of our code, and everyone goes through the process, from casual contributors to our most senior developers.
|
||||
|
||||
1. After you have made a pull-request, post the link (e.g. https://github.com/mozilla/butter/pull/662) in the corresponding ticket.
|
||||
2. Set the status of the ticket to `peer-review requested`, and choose someone to review your code. If you're not sure who should review your code, ask in #popcorn on IRC.
|
||||
3. After you get a review, you will see (1) comments in the diff in your pull-request and (2) comments in lighthouse. Keep an eye on the ticket to see when your review is done.
|
||||
4. Complete the changes that were requested, or if you disagree or need more information, comment in the pull-request or lighthouse. Commit and push up.
|
||||
5. After your review passes, your reviewer will pass the ticket on to `super-review-requested`. You will likely have more changes after that review.
|
||||
6. After your final round of changes, your ticket will change to `review-looks-good`. Hurrah! Ask someone to help you merge your code into master.
|
||||
|
||||
### Landing (for those with commit rights to github.com/mozilla/butter)
|
||||
Once code has been reviewed (PR+ and SR+), and you want to land it, you need to follow our rebase strategy. Don't use Github's "Merge pull request". Instead, please do the following:
|
||||
|
||||
1. `git checkout master`
|
||||
2. `git pull mozilla master` This assumes your remote to Mozilla's butter is called mozilla
|
||||
3. `git checkout mybranch`
|
||||
4. `git rebase -i master` Squash your commits here, where it makes sense
|
||||
5. Make sure everything still works in Butter at this point
|
||||
6. `git push origin mybranch --force`
|
||||
7. `git checkout master`
|
||||
8. `git merge mybranch --ff-only` No need for a commit message, as we're not doing a merge commit
|
||||
9. `git push mozilla master`
|
||||
10. Paste URL to commits in ticket, and mark it as "Staged"
|
||||
|
||||
We use this landing strategy in order to make backing-out failed commits easier.
|
|
@ -0,0 +1,253 @@
|
|||
0.3 Release, "Breakfast Club" - April 10, 2012
|
||||
|
||||
609 Add configuration that includes all plugins
|
||||
604 [Meta] Install 0.3 on mozillapopcorn.org/edge
|
||||
634 Need a way to set options on Popcorn
|
||||
639 Create music video template
|
||||
653 Saving doesn't work twice.
|
||||
652 Simple URL replacement in Cornfield
|
||||
650 Fix publish path
|
||||
648 Dialogs need relative paths
|
||||
647 Fix media element loading edgecase
|
||||
646 Give editors own comm lib
|
||||
643 Make cornfield's root file-serve path configurable
|
||||
637 Fix positioning of butter-media-highlight
|
||||
622 cornfield server should run by default, not simple node server
|
||||
641 Editor module should auto-add editors from config
|
||||
642 Update Popcorn submodule
|
||||
596 replace Layla as default video
|
||||
631 In-editor update of trackevent does not update the corresponding view
|
||||
621 Server needs mongoose to run
|
||||
626 Firefox textbox elements don't have proper height in dialogs
|
||||
557 Fix import in test/selenium/testcases_tracks.py
|
||||
616 Fix UI/Asset directory structure
|
||||
598 Ability to turn Logger off
|
||||
431 Common CSS for Dialogs
|
||||
615 Remove cornfield/publish.js from repo
|
||||
601 Test template exclude browser ID on publish
|
||||
610 Fix inline-block inconsistency with Google Chrome on header buttons
|
||||
611 Fix final lint errors
|
||||
597 Published projects don't work
|
||||
594 Bring cornfield tests back up to par
|
||||
603 Turn off Media UI when butter.ui is disabled
|
||||
600 src/core/trackevents.js is accessing butter when it doesn't exist
|
||||
602 Make export button yellow like the others
|
||||
320 Ability to import/export popcorn code per track
|
||||
605 Export buttons aren't enabled
|
||||
330 Implement publish project UI
|
||||
466 Save indicator
|
||||
563 Remove popcorn_outer.png
|
||||
536 UI for specifying/changing timeline media
|
||||
534 Name your project
|
||||
535 Implement load project uI
|
||||
537 Make Popcorn Maker header functional
|
||||
585 Header behavior tweaks
|
||||
584 After importing a project, trackevents aren't clickable.
|
||||
402 Plugin tray UI needs to be brought up to par
|
||||
529 Scrubber position resets to 0 if you attempt to drag it from the far right
|
||||
458 Protect from invalid times in trackevents
|
||||
436 have butter.io.cornfield write out a script tag to load BrowserID if it's not loaded
|
||||
358 Add tooltip to unreadable trackevent title
|
||||
579 Events are added 1 frame too early
|
||||
569 PopcornWrapper breaks tests
|
||||
583 Fix readme to indicate that --recursive clone is needed
|
||||
364 Change HTML Generation to use Double quotes rather than single
|
||||
242 generatePopcornString needs to pass options to Popcorn object
|
||||
543 "When the tray shows anything other than the timeline, ""Add Popcorn"" should be ""Done""
|
||||
581 have we removed the ability to delete a track?
|
||||
365 HTML Generation Moves Video Containing Element to Different Spot on Page
|
||||
544 Add Track button
|
||||
510 Remove reference to secretrobotron's github account
|
||||
462 Phantom tracks when moving an event over a droppable target
|
||||
276 in/out should indicate what they are measuring
|
||||
539 Vertical scroll in timeline area with mousewheel
|
||||
524 Refactor Media/Track/TrackEvent structure to be more light-weight
|
||||
457 Dynamically load popcorn players on-demand
|
||||
252 Don't let a user commit a blank field for timeline media change
|
||||
494 Pasting video URL should not fail when no HTTP
|
||||
437 Port all keyboard shortcuts from Popcorn Maker .1 into Butter
|
||||
467 Elegant load for tray
|
||||
482 clearProject should probably remove all tracks + trackEvents as well
|
||||
495 At the end of the timeline, play should restart video
|
||||
525 "Amalgamate ""cancel"" and ""ok"" buttons in default editor"
|
||||
530 DragNDrop on Media elements is broken
|
||||
460 "Create and implement UI for ""Add Popcorn"" button"
|
||||
552 importButter not recognizing event types/info
|
||||
489 default editor breaks with youtube player
|
||||
421 Fix linting errors
|
||||
329 Up/Down arrows should move to next/prev event
|
||||
514 resizing track events does not update start or end time
|
||||
432 Track events can't lose focus
|
||||
243 Create a rudimentary testing process
|
||||
443 Butter should always reliably load
|
||||
538 Confirm that single press of esc key dismisses event editors
|
||||
271 Weird design bug in chrome
|
||||
498 Tests fail first pass through on Chrome
|
||||
441 Scubber Line Behaviour erratic.
|
||||
553 `node make` doesn't work
|
||||
500 Start using selenium
|
||||
231 Replace Makefiles with shelljs
|
||||
492 Timebar canvas is too large
|
||||
301 Use the require order plugin
|
||||
527 Remove plugin addition from template.js
|
||||
485 trackevent timing buggy
|
||||
526 Tests broken as a result of merge
|
||||
506 Remove jquery and jquery-ui
|
||||
218 bodyReady crashes on SVG elements
|
||||
502 util/time doesn't have license header
|
||||
516 Fix tests after DragNDrop broke them
|
||||
481 uncaught typeError in Chrome only
|
||||
461 Move editor dialogues to tray, create quick edit flow
|
||||
505 Replace $sortable
|
||||
94 Dragging the scrubber/a track event along the timeline does not force the timeline to scroll
|
||||
490 Zooming doesn't move the scrubber
|
||||
477 Dragging Footnote in template.html to the edge of track 2 causes it to disappear
|
||||
455 "Stop target from ""blinking"" if mouse is dragging something"
|
||||
342 We should roll out our own drag & drop
|
||||
404 Clean up start-up and organization of Butter
|
||||
262 Object has no method 'slider' issue still around
|
||||
314 Changes to track list UI
|
||||
133 "Make ""standard target"" default target"
|
||||
493 If a track event is double clicked and the editor is already opened, focus the editor.
|
||||
474 Update Popcorn.js to v1.2
|
||||
408 Attempt to clean up timeline module
|
||||
487 "Use ""on"" instead of ""listen"" for Popcorn interface"
|
||||
480 Get rid of Butter instancing
|
||||
488 Remove CSS checking in plugin module
|
||||
348 Fix module order dependency
|
||||
429 Style Guide for Source
|
||||
352 Performance when zooming/moving around on timeline is slow with numerous trackevents
|
||||
132 Footnote data stays in workspace preview too long
|
||||
130 """Subtitle-container"" is confusing"
|
||||
45 resizing page UI problem
|
||||
131 Export>Preview not working
|
||||
107 google maps exception in butter
|
||||
105 adding tracks doesn't fire timeupdate on youtube
|
||||
121 Image plugin broken on experimental branch
|
||||
134 Youtube doesn't export/preview
|
||||
104 Clicking New Project should re-open the start dialog
|
||||
102 Hide youtube's native flash controls and annotations by default
|
||||
96 Scrubber doesn't reset when time is reset
|
||||
139 You should be able to set the project title when you create it
|
||||
106 Youtube seek bar fires play
|
||||
127 Selection needs to be turned off for Chrome
|
||||
140 Track events broken in chrome
|
||||
64 Reassign track representation for manual track -> DOM assignment
|
||||
112 image and webpage refresh issue
|
||||
72 Show one object in preview window
|
||||
71 DOM Object database for tracks
|
||||
70 Enable the user of arbitrary player plugins
|
||||
63 Implement timeline using CSS
|
||||
118 Review - Import, Export, Load, Save, CSS, Player Plugins, DOM Database, Preview Isolation
|
||||
109 Wordriver plug-in start doesn't fire
|
||||
69 Click & Drag plugins to create events
|
||||
67 Project Details
|
||||
85 what to do on a refresh
|
||||
84 Remove butter.html
|
||||
97 $popcorn is undefined when resizing window
|
||||
92 Update AUTHORS
|
||||
90 Changing url for media needs to actually change the media
|
||||
66 Help Button
|
||||
88 Video continues to play when red timeline bar is held
|
||||
68 Remove accordion
|
||||
17 Play/Pause should be controllable with the space bar.
|
||||
35 Focus on one command at a time in preview pane
|
||||
18 Better handles on the timeline to grab each instance of a plugin
|
||||
49 UI Revamp
|
||||
36 Youtube support in Butter?
|
||||
22 Multiple timelines per plugin
|
||||
|
||||
0.2 Release, "Ghostbusters" - March 1, 2012
|
||||
|
||||
337 Ability to login/save/load from a cornfield server
|
||||
390 Setting trackEvent out time > video duration causes issues
|
||||
268 Fade in of modal dialogues far too slow
|
||||
332 Ensure all player types work
|
||||
427 Better UX for highlighting elements
|
||||
446 Warning when closing a window dialog manually
|
||||
428 Change per-file licenses
|
||||
395 Butter readme should include info on submodules
|
||||
454 Flash target on click, not hover
|
||||
438 Tray UI should be no bigger than is necessary to accomodate 4 tracks
|
||||
256 Timecodes should round to 3 decimal places
|
||||
449 <style> needs to be removed for getHTML
|
||||
444 Rogue Track Events appear after moving a track event
|
||||
452 Template has unneeded html elements
|
||||
375 Push butter up to mozilla's github account
|
||||
451 Hovering over new track event does not blink it's default target
|
||||
391 Creating a new trackEvent should provide a default target
|
||||
448 Target should blink once when a track event is created
|
||||
298 Have templates show their ID in the editor view
|
||||
447 unit tests have errors
|
||||
401 Timeline tracks allow track events to be position at -0.01 seconds
|
||||
211 previewer should provide a getHTML function
|
||||
440 Scrolling Horizontally does not move the vertical scrollbar
|
||||
277 We lost different colours for plugins
|
||||
388 Track Editor UI
|
||||
416 Red "X" for deleting tracks
|
||||
248 Need to close editor windows
|
||||
420 Dialog module cleanup
|
||||
413 Clicking on handle makes it jump forward
|
||||
425 Polling scrubber spins too often at start
|
||||
319 Ability to have a UI cue for currently edited element
|
||||
423 Shouldn't be able to re-order tracks from within trackliner.
|
||||
424 Zoombar is broken (exception)
|
||||
280 "Media element" is confusing name for a target
|
||||
392 importProject is slightly broken
|
||||
418 Get rid of old and busted scraper code
|
||||
366 Move code for making targets droppable into core/target
|
||||
410 Change all occurrences of const to var
|
||||
389 Calling preview explicitly shouldn't be necessary
|
||||
351 Timeline scrolling should be triggered by mouse wheel
|
||||
384 Test template file should not create default trackEvents or too many tracks
|
||||
409 Dragging scrubber is off by some factor of the timelines duration
|
||||
255 When collapsing timeline, playhead and play button should remain
|
||||
411 spacebar for play/pause missing from new tray
|
||||
405 Remove css that causes timeline media div to grow/shrink
|
||||
237 Ability to seek
|
||||
289 Mute button doesn't mute.
|
||||
372 Default editor needs a better home
|
||||
399 Track Event Selection
|
||||
381 Add Tracks UI segment
|
||||
368 Target object's id should reflect the element's id
|
||||
397 Add play/pause and mute buttons.
|
||||
335 Click on timeline to move playhead
|
||||
254 Much confusion re: "Apply" and "OK"
|
||||
400 Moving the playhead/scrubber while playing should mimic HTML5 behaviour
|
||||
382 Right-click on slider doesn't let go on mouse up
|
||||
186 Event editor should update when track events are moved
|
||||
370 Click on scrollbars to move timeline
|
||||
386 I cloned the latest Butter repo - no events appear on timeline
|
||||
234 EventEditor chops "http:" off of webpage plugin src.
|
||||
266 plugins should default to a target, not media element
|
||||
305 Timeline changes from editors are slow to update in Chrome
|
||||
294 Error checking only works when creating new project
|
||||
275 Hard to use apostrophes
|
||||
283 In edit track dialogue, buttons are weird
|
||||
270 edge grabbers for events should be larger and more obvious
|
||||
349 Extra default editor
|
||||
257 Add .DS_Store to .gitignore
|
||||
369 Draggable issues in Chrome
|
||||
377 Fix Failing Core Tests
|
||||
376 Upgrade libs
|
||||
367 getTarget should be changed to match getMedia
|
||||
378 Timeline zooming still causing resize issue in Chrome
|
||||
239 Escape key should dismiss dialog windows
|
||||
334 Add helper to event draggables
|
||||
374 Dialog module has some poor naming conventions
|
||||
311 Make zoom match timeline style
|
||||
26 Timeline should be zoomable
|
||||
86 hitting enter to accept plugin/track changes
|
||||
350 core/media.js should access Popcorn directly
|
||||
192 Editor dialogs should be non-modal
|
||||
331 Crash on loading editor for certain plugins (base.manifest)
|
||||
345 Get playhead to follow currentTime of video
|
||||
346 Editors to use dialog module (and work at all)
|
||||
236 Fix Failing Core Tests
|
||||
264 Ugly scrollbars on timeline
|
||||
333 Target-droppable events
|
||||
336 Currentime looping causes video jitter
|
||||
235 We need better names for track.js/trackevent.js
|
||||
282 Editor dialogues should be draggable
|
||||
263 Passing no Arguments into butter.getMedia throws an Exception
|
||||
216 When butter finds data-butter="media", should check if target is a <video>
|
|
@ -0,0 +1,333 @@
|
|||
/*jshint eqeqeq:false */
|
||||
console.log( __dirname );
|
||||
|
||||
// Given foo/ return foo
|
||||
function stripSlash( path ) {
|
||||
return path.replace( /\/$/, '' );
|
||||
}
|
||||
|
||||
var express = require('express'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
jade = require('jade'),
|
||||
app = express.createServer(),
|
||||
clientSessions = require('client-sessions'),
|
||||
lessMiddleware = require('less-middleware'),
|
||||
CONFIG = require('config'),
|
||||
User = require( './lib/user' )( CONFIG.database ),
|
||||
filter = require( './lib/filter' )( User.isDBOnline ),
|
||||
sanitizer = require( './lib/sanitizer' ),
|
||||
FileStore = require('./lib/file-store.js'),
|
||||
stores = {},
|
||||
TEMPLATES_DIR = CONFIG.dirs.templates,
|
||||
APP_HOSTNAME = stripSlash( CONFIG.dirs.appHostname ),
|
||||
// If a separate hostname is given for embed, use it, otherwise use app's hostname
|
||||
EMBED_HOSTNAME = CONFIG.dirs.embedHostname ? stripSlash( CONFIG.dirs.embedHostname ) : APP_HOSTNAME,
|
||||
EMBED_SUFFIX = '_',
|
||||
WWW_ROOT = path.resolve( CONFIG.dirs.wwwRoot || path.join( __dirname, ".." ) ),
|
||||
VALID_TEMPLATES = CONFIG.templates,
|
||||
EXPORT_ASSETS = CONFIG.exportAssets;
|
||||
|
||||
var templateConfigs = {};
|
||||
|
||||
function readTemplateConfig( templateName, templatedPath ) {
|
||||
var configPath = templatedPath.replace( '{{templateBase}}', TEMPLATES_DIR + '/' );
|
||||
fs.readFile( configPath, 'utf8', function( err, conf ) {
|
||||
var configPathBase = configPath.substring( 0, configPath.lastIndexOf( '/' ) );
|
||||
conf = JSON.parse( conf );
|
||||
conf.template = configPathBase + '/' + conf.template;
|
||||
templateConfigs[ templateName ] = conf;
|
||||
});
|
||||
}
|
||||
|
||||
// parse configs ahead of any action that has to happen with them
|
||||
for ( var templateName in VALID_TEMPLATES ) {
|
||||
if ( VALID_TEMPLATES.hasOwnProperty( templateName ) ) {
|
||||
readTemplateConfig( templateName, VALID_TEMPLATES[ templateName ] );
|
||||
}
|
||||
}
|
||||
|
||||
console.log( "Templates Dir:", TEMPLATES_DIR );
|
||||
|
||||
app.configure( 'development', function() {
|
||||
app.use( lessMiddleware( WWW_ROOT ));
|
||||
CONFIG.additionalStaticRoots.forEach( function( dir ) {
|
||||
app.use( express.static( dir ) );
|
||||
});
|
||||
});
|
||||
|
||||
function setupStore( config ) {
|
||||
var store = FileStore.create( config.type, config.options );
|
||||
if( store.requiresFileSystem ) {
|
||||
app.use( express.static( store.root, JSON.parse( JSON.stringify( CONFIG.staticMiddleware ) ) ) );
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
app.configure( function() {
|
||||
app.use( express.logger( CONFIG.logger ) )
|
||||
.use( express.static( WWW_ROOT, JSON.parse( JSON.stringify( CONFIG.staticMiddleware ) ) ) )
|
||||
.use( express.bodyParser() )
|
||||
.use( clientSessions( CONFIG.session ) )
|
||||
.use( express.csrf() )
|
||||
/* Show Zeus who's boss
|
||||
* This only affects requests under /api and /persona, not static files
|
||||
* because the static file writes the response header before we hit this middleware
|
||||
*/
|
||||
.use( function( req, res, next ) {
|
||||
res.header( 'Cache-Control', 'no-store' );
|
||||
return next();
|
||||
})
|
||||
.set('view options', {layout: false});
|
||||
|
||||
// File Store types and options come from JSON config file.
|
||||
stores.publish = setupStore( CONFIG.publishStore );
|
||||
stores.crash = setupStore( CONFIG.crashStore );
|
||||
stores.feedback = setupStore( CONFIG.feedbackStore );
|
||||
});
|
||||
|
||||
require( 'express-persona' )( app, {
|
||||
audience: CONFIG.dirs.appHostname
|
||||
});
|
||||
require('./routes')( app, User, filter, sanitizer, stores, EMBED_SUFFIX );
|
||||
|
||||
function writeEmbedShell( path, url, data, callback ) {
|
||||
if( !writeEmbedShell.templateFn ) {
|
||||
writeEmbedShell.templateFn = jade.compile( fs.readFileSync( 'views/embed-shell.jade', 'utf8' ),
|
||||
{ filename: 'embed-shell.jade', pretty: true } );
|
||||
}
|
||||
|
||||
stores.publish.write( path, writeEmbedShell.templateFn( data ), callback );
|
||||
}
|
||||
|
||||
function writeEmbed( path, url, data, callback ) {
|
||||
if( !writeEmbed.templateFn ) {
|
||||
writeEmbed.templateFn = jade.compile( fs.readFileSync( 'views/embed.jade', 'utf8' ),
|
||||
{ filename: 'embed.jade', pretty: true } );
|
||||
}
|
||||
|
||||
stores.publish.write( path, writeEmbed.templateFn( data ), callback );
|
||||
}
|
||||
|
||||
app.post( '/api/publish/:id',
|
||||
filter.isLoggedIn, filter.isStorageAvailable, filter.isXHR,
|
||||
function publishRoute( req, res ) {
|
||||
|
||||
var email = req.session.email,
|
||||
id = parseInt( req.params.id, 10 );
|
||||
|
||||
if ( isNaN( id ) ) {
|
||||
res.json( { error: "ID was not a number" }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
User.findProject( email, id, function( err, project ) {
|
||||
if ( err ) {
|
||||
res.json( { error: err }, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !project ) {
|
||||
res.json( { error: 'project not found' }, 404);
|
||||
return;
|
||||
}
|
||||
|
||||
var i = 0,
|
||||
template = project.template;
|
||||
|
||||
if( !( template && VALID_TEMPLATES[ template ] ) ) {
|
||||
res.json({ error: 'template not found' }, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
var projectData = JSON.parse( project.data, sanitizer.escapeHTMLinJSON ),
|
||||
templateConfig = templateConfigs[ template ],
|
||||
templateFile = templateConfig.template,
|
||||
baseHref;
|
||||
|
||||
fs.readFile( templateFile, 'utf8', function( err, data ){
|
||||
if ( err ) {
|
||||
res.json( { error: 'error reading template file' }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
var headEndTagIndex,
|
||||
bodyEndTagIndex,
|
||||
externalAssetsString = '',
|
||||
popcornString = '',
|
||||
currentMedia,
|
||||
currentTrack,
|
||||
currentTrackEvent,
|
||||
mediaPopcornOptions,
|
||||
templateURL,
|
||||
baseString,
|
||||
headStartTagIndex,
|
||||
templateScripts,
|
||||
startString,
|
||||
numSources,
|
||||
j, k, len;
|
||||
|
||||
templateURL = templateFile.substring( templateFile.indexOf( '/templates' ), templateFile.lastIndexOf( '/' ) );
|
||||
baseHref = APP_HOSTNAME + templateURL + "/";
|
||||
baseString = '\n <base href="' + baseHref + '"/>';
|
||||
|
||||
// look for script tags with data-butter-exclude in particular (e.g. butter's js script)
|
||||
data = data.replace( /\s*<script[\.\/='":_\-\w\s]*data-butter-exclude[\.\/='":_\-\w\s]*><\/script>/g, '' );
|
||||
|
||||
// Adding to cut out the actual head tag
|
||||
headStartTagIndex = data.indexOf( '<head>' ) + 6;
|
||||
headEndTagIndex = data.indexOf( '</head>' );
|
||||
bodyEndTagIndex = data.indexOf( '</body>' );
|
||||
|
||||
templateScripts = data.substring( headStartTagIndex, headEndTagIndex );
|
||||
startString = data.substring( 0, headStartTagIndex );
|
||||
|
||||
externalAssetsString += '\n';
|
||||
for ( i = 0; i < EXPORT_ASSETS.length; ++i ) {
|
||||
externalAssetsString += ' <script src="' + path.relative( path.dirname( templateFile ), EXPORT_ASSETS[ i ] ) + '"></script>\n';
|
||||
}
|
||||
|
||||
// If the template has custom plugins defined in it's config, add them to our exported page
|
||||
if ( templateConfig.plugin && templateConfig.plugin.plugins ) {
|
||||
var plugins = templateConfig.plugin.plugins;
|
||||
for ( i = 0, len = plugins.length; i < len; i++ ) {
|
||||
externalAssetsString += '\n <script src="' + APP_HOSTNAME + '/' + plugins[ i ].path.split( '{{baseDir}}' ).pop() + '"></script>';
|
||||
}
|
||||
externalAssetsString += '\n';
|
||||
}
|
||||
|
||||
popcornString += '<script>';
|
||||
|
||||
for ( i = 0; i < projectData.media.length; ++i ) {
|
||||
var mediaUrls,
|
||||
mediaUrlsString = '[ "';
|
||||
|
||||
currentMedia = projectData.media[ i ];
|
||||
// We expect a string (one url) or an array of url strings.
|
||||
// Turn a single url into an array of 1 string.
|
||||
mediaUrls = typeof currentMedia.url === "string" ? [ currentMedia.url ] : currentMedia.url;
|
||||
mediaPopcornOptions = currentMedia.popcornOptions || {};
|
||||
// Force the Popcorn instance we generate to have an ID we can query.
|
||||
mediaPopcornOptions.id = "Butter-Generated";
|
||||
|
||||
numSources = mediaUrls.length;
|
||||
|
||||
for ( k = 0; k < numSources - 1; k++ ) {
|
||||
mediaUrlsString += mediaUrls[ k ] + '" , "';
|
||||
}
|
||||
mediaUrlsString += mediaUrls[ numSources - 1 ] + '" ]';
|
||||
|
||||
popcornString += '\n(function(){';
|
||||
popcornString += '\nvar popcorn = Popcorn.smart("#' + currentMedia.target + '", ' +
|
||||
mediaUrlsString + ', ' + JSON.stringify( mediaPopcornOptions ) + ');';
|
||||
for ( j = 0; j < currentMedia.tracks.length; ++ j ) {
|
||||
currentTrack = currentMedia.tracks[ j ];
|
||||
for ( k = 0; k < currentTrack.trackEvents.length; ++k ) {
|
||||
currentTrackEvent = currentTrack.trackEvents[ k ];
|
||||
popcornString += '\npopcorn.' + currentTrackEvent.type + '(';
|
||||
popcornString += JSON.stringify( currentTrackEvent.popcornOptions, null, 2 );
|
||||
popcornString += ');';
|
||||
}
|
||||
}
|
||||
|
||||
popcornString += '}());\n';
|
||||
}
|
||||
popcornString += '</script>\n';
|
||||
|
||||
data = startString + baseString + templateScripts + externalAssetsString +
|
||||
data.substring( headEndTagIndex, bodyEndTagIndex ) +
|
||||
popcornString + data.substring( bodyEndTagIndex );
|
||||
|
||||
// Convert 1234567890 => "kf12oi"
|
||||
var idBase36 = id.toString( 36 ),
|
||||
publishUrl = EMBED_HOSTNAME + '/' + stores.publish.expand( idBase36 ),
|
||||
iframeUrl = EMBED_HOSTNAME + '/' + stores.publish.expand( idBase36 + EMBED_SUFFIX );
|
||||
|
||||
function finished( err ) {
|
||||
if ( err ) {
|
||||
res.json({ error: 'internal server error' }, 500);
|
||||
} else {
|
||||
res.json({ error: 'okay', publishUrl: publishUrl, iframeUrl: iframeUrl });
|
||||
}
|
||||
}
|
||||
|
||||
function publishEmbedShell() {
|
||||
// Write out embed shell HTML
|
||||
writeEmbedShell( idBase36, publishUrl,
|
||||
{
|
||||
author: project.author,
|
||||
projectName: project.name,
|
||||
embedShellSrc: publishUrl,
|
||||
embedSrc: iframeUrl,
|
||||
baseHref: APP_HOSTNAME
|
||||
},
|
||||
finished );
|
||||
}
|
||||
|
||||
// This is a query string-only URL because of the <base> tag
|
||||
var remixUrl = "?savedDataUrl=/api/remix/" + project.id,
|
||||
mediaUrl = projectData.media[ 0 ].url,
|
||||
attribURL = Array.isArray( mediaUrl ) ? mediaUrl[ 0 ] : mediaUrl;
|
||||
|
||||
writeEmbed( idBase36 + EMBED_SUFFIX, iframeUrl,
|
||||
{
|
||||
id: id,
|
||||
author: project.author,
|
||||
title: project.name,
|
||||
mediaSrc: attribURL,
|
||||
embedShellSrc: publishUrl,
|
||||
baseHref: baseHref,
|
||||
remixUrl: remixUrl,
|
||||
templateScripts: templateScripts,
|
||||
externalAssets: externalAssetsString,
|
||||
// XXX: need a better way to wrap function, DOM needs to be ready
|
||||
popcorn: popcornString.replace( /^\(function\(\)\{/m, "Popcorn( function(){" )
|
||||
.replace( /\}\(\)\);$/m, "});" )
|
||||
},
|
||||
publishEmbedShell );
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.get( '/dashboard', filter.isStorageAvailable, function( req, res ) {
|
||||
var email = req.session.email;
|
||||
|
||||
if ( !email ) {
|
||||
res.render( 'dashboard-unauthorized.jade' );
|
||||
return;
|
||||
}
|
||||
|
||||
User.findAllProjects( email, function( err, docs ) {
|
||||
var userProjects = [];
|
||||
|
||||
docs.forEach( function( project ) {
|
||||
if ( project.template && VALID_TEMPLATES[ project.template ] ) {
|
||||
userProjects.push({
|
||||
// make sure _id is a string. saw some strange double-quotes on output otherwise
|
||||
_id: String(project.id),
|
||||
name: sanitizer.escapeHTML( project.name ),
|
||||
template: project.template,
|
||||
href: path.relative( WWW_ROOT, templateConfigs[ project.template ].template ) +
|
||||
"?savedDataUrl=/api/project/" + project.id
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
res.render( 'dashboard.jade', {
|
||||
user: {
|
||||
csrf: req.session._csrf,
|
||||
email: email
|
||||
},
|
||||
projects: userProjects
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
var port = process.env.PORT || CONFIG.server.bindPort;
|
||||
|
||||
app.listen(port, CONFIG.server.bindIP, function() {
|
||||
var addy = app.address();
|
||||
console.log('HTTP Server started on http://' + CONFIG.server.bindIP + ':' + addy.port);
|
||||
console.log('Press Ctrl+C to stop');
|
||||
});
|
|
@ -0,0 +1,81 @@
|
|||
{
|
||||
"server" : {
|
||||
"bindIP" : "localhost",
|
||||
"bindPort" : "8888"
|
||||
},
|
||||
"logger" : {
|
||||
"format" : "dev"
|
||||
},
|
||||
"session" : {
|
||||
"secret": "thisisareallyreallylongsecrettoencryptcookies",
|
||||
"duration": 2419200000
|
||||
},
|
||||
"staticMiddleware": {
|
||||
"maxAge": "0"
|
||||
},
|
||||
"dirs": {
|
||||
"wwwRoot": "../",
|
||||
"templates": "../templates",
|
||||
"appHostname": "http://localhost:8888"
|
||||
},
|
||||
"publishStore": {
|
||||
"type": "local",
|
||||
"options": {
|
||||
"root": "./view",
|
||||
"namePrefix": "v",
|
||||
"nameSuffix": ".html"
|
||||
}
|
||||
},
|
||||
"feedbackStore": {
|
||||
"type": "local",
|
||||
"options": {
|
||||
"root": "./view",
|
||||
"namePrefix": "feedback",
|
||||
"nameSuffix": ".json"
|
||||
}
|
||||
},
|
||||
"crashStore": {
|
||||
"type": "local",
|
||||
"options": {
|
||||
"root": "./view",
|
||||
"namePrefix": "crash",
|
||||
"nameSuffix": ".json"
|
||||
}
|
||||
},
|
||||
"templates": {
|
||||
"basic": "{{templateBase}}basic/config.json"
|
||||
},
|
||||
"exportAssets": [
|
||||
"../external/popcorn-js/ie8/popcorn.ie8.js",
|
||||
"../external/popcorn-js/popcorn.js",
|
||||
"../external/popcorn-js/wrappers/common/popcorn._MediaElementProto.js",
|
||||
"../external/popcorn-js/wrappers/html5/popcorn.HTMLMediaElement.js",
|
||||
"../external/popcorn-js/wrappers/null/popcorn.HTMLNullVideoElement.js",
|
||||
"../external/popcorn-js/wrappers/soundcloud/popcorn.HTMLSoundCloudAudioElement.js",
|
||||
"../external/popcorn-js/wrappers/vimeo/popcorn.HTMLVimeoVideoElement.js",
|
||||
"../external/popcorn-js/wrappers/youtube/popcorn.HTMLYouTubeVideoElement.js",
|
||||
"../external/popcorn-js/modules/player/popcorn.player.js",
|
||||
"../external/popcorn-js/players/youtube/popcorn.youtube.js",
|
||||
"../external/popcorn-js/players/vimeo/popcorn.vimeo.js",
|
||||
"../external/popcorn-js/players/soundcloud/popcorn.soundcloud.js",
|
||||
"../templates/assets/plugins/text/popcorn.text.js",
|
||||
"../templates/assets/plugins/popup/popcorn.popup.js",
|
||||
"../templates/assets/plugins/googlemap/popcorn.googlemap.js",
|
||||
"../templates/assets/plugins/twitter/popcorn.twitter.js",
|
||||
"../templates/assets/plugins/image/popcorn.image.js",
|
||||
"../templates/assets/plugins/loopPlugin/popcorn.loopPlugin.js",
|
||||
"../templates/assets/plugins/skip/popcorn.skip.js",
|
||||
"../templates/assets/plugins/pausePlugin/popcorn.pausePlugin.js",
|
||||
"../templates/assets/plugins/wikipedia/popcorn.wikipedia.js"
|
||||
],
|
||||
"database": {
|
||||
"database": "popcorn",
|
||||
"username": null,
|
||||
"password": null,
|
||||
"options": {
|
||||
"logging": false,
|
||||
"dialect": "sqlite",
|
||||
"storage": "popcorn.sqlite"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"additionalStaticRoots": [
|
||||
"../public"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"dirs": {
|
||||
"wwwRoot": "../public",
|
||||
"templates": "../public/templates"
|
||||
},
|
||||
"exportAssets": [
|
||||
"../external/popcorn-js/popcorn.js"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
var fs = require( 'fs' ),
|
||||
knox = require( 'knox' ),
|
||||
Path = require( 'path' );
|
||||
|
||||
// Make sure the dir exists, and its parent. Create if not.
|
||||
function ensurePathExistsSync( path ) {
|
||||
var parent = Path.dirname( path );
|
||||
|
||||
// Build paths above too, if not present. Check for relative or absolute paths
|
||||
if ( parent !== "." && parent !== "/" ) {
|
||||
ensurePathExistsSync( parent );
|
||||
}
|
||||
|
||||
if ( !fs.existsSync( path ) ) {
|
||||
fs.mkdirSync( path );
|
||||
}
|
||||
}
|
||||
|
||||
var BaseFileStore = {
|
||||
|
||||
// By default, we use no prefix/suffix unless user-supplied.
|
||||
namePrefix: '',
|
||||
nameSuffix: '',
|
||||
|
||||
// If we have a root directory, we need to work with the FS
|
||||
get requiresFileSystem() {
|
||||
return !!this.root;
|
||||
},
|
||||
|
||||
// Expand a name to include the namePrefix
|
||||
expand: function( name ) {
|
||||
// Make sure name is a string, since non-strings are ignored by join
|
||||
name = name + '';
|
||||
return Path.join( this.namePrefix, name ) + this.nameSuffix;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* LocalFileStore - stores data in local file system using root dir
|
||||
*/
|
||||
function LocalFileStore( options ) {
|
||||
// A root path for all filenames
|
||||
if( !options.root ) {
|
||||
throw 'LocalFileStore Error: expected root';
|
||||
}
|
||||
this.root = options.root;
|
||||
|
||||
// An optional prefix for all filenames. Will be joined with /
|
||||
// For example: filename=foo namePrefix=v becomes v/foo
|
||||
if( options.namePrefix ) {
|
||||
this.namePrefix = options.namePrefix;
|
||||
}
|
||||
ensurePathExistsSync( Path.join( this.root, this.namePrefix ) );
|
||||
|
||||
// An optional suffix for all filenames. Will be joined directly
|
||||
// For example: filename=foo nameSuffix=.html becomes foo.html
|
||||
if( options.nameSuffix ) {
|
||||
this.nameSuffix = options.nameSuffix;
|
||||
}
|
||||
}
|
||||
|
||||
LocalFileStore.prototype = Object.create( BaseFileStore );
|
||||
|
||||
LocalFileStore.prototype.write = function( path, data, callback ) {
|
||||
path = Path.join( this.root, this.expand( path ) );
|
||||
ensurePathExistsSync( Path.dirname( path ) );
|
||||
|
||||
fs.writeFile( path, data, function( err ) {
|
||||
if (err) {
|
||||
callback( err );
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
LocalFileStore.prototype.remove = function( path, callback ) {
|
||||
path = Path.join( this.root, this.expand( path ) );
|
||||
fs.unlink( path, callback );
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* S3FileStore - store data using Amazon S3
|
||||
*/
|
||||
function S3FileStore( options ) {
|
||||
// Amazon S3 credentials for accessing a bucket
|
||||
this.client = knox.createClient({
|
||||
key: options.key,
|
||||
secret: options.secret,
|
||||
bucket: options.bucket
|
||||
});
|
||||
|
||||
// An optional prefix for all keys. Will be joined with /
|
||||
// For example: key=foo namePrefix=v becomes v/foo
|
||||
if( options.namePrefix ) {
|
||||
this.namePrefix = options.namePrefix;
|
||||
}
|
||||
|
||||
// An optional suffix for all filenames. Will be joined directly
|
||||
// For example: filename=foo nameSuffix=.html becomes foo.html
|
||||
if( options.nameSuffix ) {
|
||||
this.nameSuffix = options.nameSuffix;
|
||||
}
|
||||
|
||||
// An optional mime type for the files to be written. Defaults to
|
||||
// text/plain if none given.
|
||||
this.contentType = options.contentType || 'text/plain';
|
||||
}
|
||||
|
||||
S3FileStore.prototype = Object.create( BaseFileStore );
|
||||
|
||||
S3FileStore.prototype.write = function( key, data, callback ) {
|
||||
this.client.put( this.expand( key ), {
|
||||
'x-amz-acl': 'public-read',
|
||||
'Content-Length': data.length,
|
||||
'Content-Type': this.contentType
|
||||
})
|
||||
.on( 'response', function( res ) {
|
||||
if( res.statusCode === 200 ) {
|
||||
callback();
|
||||
} else {
|
||||
callback( res.statusCode );
|
||||
}
|
||||
})
|
||||
.end( data );
|
||||
};
|
||||
|
||||
S3FileStore.prototype.remove = function( key, callback ) {
|
||||
this.client.del( this.expand( key ) )
|
||||
.on( 'response', function( res ) {
|
||||
if( res.statusCode === 200 ) {
|
||||
callback();
|
||||
} else {
|
||||
callback( res.statusCode );
|
||||
}
|
||||
})
|
||||
.end();
|
||||
};
|
||||
|
||||
|
||||
var FileStores = {
|
||||
'S3': S3FileStore,
|
||||
'LOCAL': LocalFileStore
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
// Pass a type (one of 'local' or 's3') to build a FileStore object.
|
||||
create: function( type, options ) {
|
||||
options = options || {};
|
||||
|
||||
var Constructor = FileStores[ type.toUpperCase() ];
|
||||
if( !Constructor ) {
|
||||
throw 'Unknown FileStore type: ' + type;
|
||||
}
|
||||
|
||||
return new Constructor( options );
|
||||
}
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
'use strict';
|
||||
|
||||
var dbCheckFn, filters;
|
||||
|
||||
filters = {
|
||||
isLoggedIn: function( req, res, next ) {
|
||||
if ( req.session.email ) {
|
||||
next();
|
||||
} else {
|
||||
res.json({
|
||||
error: 'unauthorized'
|
||||
}, 403 );
|
||||
}
|
||||
},
|
||||
isStorageAvailable: function( req, res, next ) {
|
||||
if ( dbCheckFn() ) {
|
||||
next();
|
||||
} else {
|
||||
res.json({
|
||||
error: 'storage service is not running'
|
||||
}, 500 );
|
||||
}
|
||||
},
|
||||
isXHR: function( req, res, next ) {
|
||||
if ( req.header( 'X-Requested-With' ) === 'XMLHttpRequest' ) {
|
||||
next();
|
||||
} else {
|
||||
res.json({
|
||||
error: 'X-Requested-With is not set to XMLHttpRequest'
|
||||
}, 412 );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = function ctor( fn ) {
|
||||
dbCheckFn = fn;
|
||||
return filters;
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = function(sequelize, DataTypes) {
|
||||
return sequelize.define( "Project", {
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true
|
||||
},
|
||||
data: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false
|
||||
},
|
||||
email: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
validate: {
|
||||
isEmail: true
|
||||
}
|
||||
},
|
||||
name: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
validate: {
|
||||
isAlphanumeric: true
|
||||
}
|
||||
},
|
||||
author: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
template: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false,
|
||||
validate: {
|
||||
isAlphanumeric: true
|
||||
}
|
||||
},
|
||||
// The original version of Butter that was used when project
|
||||
// was first created. This will usually be the same as
|
||||
// latestButterVersion, but could be different (i.e., a newer
|
||||
// version of Butter was used to edit a project), and gives
|
||||
// some insight into what was used originally, in case of
|
||||
// breaking changes.
|
||||
originalButterVersion: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
// The latest version of Butter that was used to save the project.
|
||||
latestButterVersion: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: false
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
var sanitizer = {
|
||||
// From https://github.com/mozilla/zamboni/blob/a4b32033/media/js/mkt/utils.js#L15
|
||||
escapeHTML: function escapeHTML( s ) {
|
||||
if ( s && typeof s === "string" ) {
|
||||
s = s.replace( /&/g, '&' ).replace( />/g, '>' ).replace( /</g, '<' )
|
||||
.replace( /'/g, ''' ).replace( /"/g, '"' );
|
||||
}
|
||||
|
||||
return s;
|
||||
},
|
||||
escapeHTMLinJSON: function escapeHTMLinJSON( key, value ) {
|
||||
if ( typeof value === "string" ) {
|
||||
return sanitizer.escapeHTML( value );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = sanitizer;
|
|
@ -0,0 +1,144 @@
|
|||
"use strict";
|
||||
|
||||
function defaultDBReadyFunction( err ) {
|
||||
if ( err ) {
|
||||
err = Array.isArray( err ) ? err[ 0 ] : err;
|
||||
console.warn( "lib/user.js: DB setup error\n", err.number ? err.number : '[No Error Number]', err.message );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function( config, dbReadyFn ) {
|
||||
config = config || {};
|
||||
|
||||
dbReadyFn = dbReadyFn || defaultDBReadyFunction;
|
||||
|
||||
var username = config.username || "";
|
||||
var password = config.password || "";
|
||||
|
||||
var dbOnline = false,
|
||||
Sequelize = require( "sequelize" ),
|
||||
sequelize = new Sequelize( config.database, username, password, config.options ),
|
||||
Project = sequelize.import( __dirname + "/models/project" ),
|
||||
versions;
|
||||
|
||||
// travis-ci doesn't create this file when running `npm test` so we need a workaround
|
||||
try {
|
||||
versions = require( "../config/versions.json" );
|
||||
} catch (ex) {
|
||||
versions = {
|
||||
butter: "travis-ci"
|
||||
};
|
||||
}
|
||||
sequelize.sync().complete(function( err ) {
|
||||
if ( !err ) {
|
||||
dbOnline = true;
|
||||
}
|
||||
|
||||
dbReadyFn( err );
|
||||
});
|
||||
|
||||
return {
|
||||
getSequelizeInstance: function(){
|
||||
return sequelize;
|
||||
},
|
||||
|
||||
createProject: function( email, data, callback ) {
|
||||
if ( !email || !data ) {
|
||||
callback( "not enough parameters to update" );
|
||||
return;
|
||||
}
|
||||
|
||||
var project = Project.build({
|
||||
data: JSON.stringify( data.data ),
|
||||
email: email,
|
||||
name: data.name,
|
||||
author: data.author || "",
|
||||
template: data.template,
|
||||
originalButterVersion: versions.butter,
|
||||
latestButterVersion: versions.butter
|
||||
});
|
||||
|
||||
project.save().complete(function( err, result ) {
|
||||
callback( err, result );
|
||||
});
|
||||
},
|
||||
deleteProject: function( email, pid, callback ) {
|
||||
if ( !email || !pid ) {
|
||||
callback( "not enough parameters to delete" );
|
||||
return;
|
||||
}
|
||||
|
||||
Project.find( { where: { email: email, id: pid } } )
|
||||
.success(function( project ) {
|
||||
if ( project ) {
|
||||
project.destroy().complete( function( err ) {
|
||||
callback( err );
|
||||
});
|
||||
} else {
|
||||
callback( "the project has already been deleted" );
|
||||
}
|
||||
})
|
||||
.error(function( error ) {
|
||||
callback( error );
|
||||
});
|
||||
},
|
||||
findAllProjects: function findAllProjects( email, callback ) {
|
||||
if ( !email ) {
|
||||
callback( "not enough parameters to search" );
|
||||
return;
|
||||
}
|
||||
|
||||
Project.findAll( { where: { email: email } } ).complete( function( err, projects ) {
|
||||
callback( err, projects );
|
||||
});
|
||||
},
|
||||
findProject: function findProject( email, pid, callback ) {
|
||||
if ( !email || !pid ) {
|
||||
callback( "not enough parameters to search" );
|
||||
return;
|
||||
}
|
||||
|
||||
Project.find( { where: { email: email, id: pid } } ).complete( function( err, project ) {
|
||||
callback( err, project );
|
||||
});
|
||||
},
|
||||
findById: function findById( pid, callback ) {
|
||||
if ( !pid ) {
|
||||
callback( "not enough parameters for search" );
|
||||
return;
|
||||
}
|
||||
|
||||
Project.find({ where: { id: pid } } ).complete( function( err, project ) {
|
||||
callback( err, project );
|
||||
});
|
||||
|
||||
},
|
||||
isDBOnline: function isDBOnline() {
|
||||
return dbOnline;
|
||||
},
|
||||
updateProject: function updateProject( email, pid, data, callback ) {
|
||||
if ( !email || !pid || !data ) {
|
||||
callback( "not enough parameters to update" );
|
||||
return;
|
||||
}
|
||||
|
||||
Project.find( { where: { email: email, id: pid } } )
|
||||
.success(function( project ) {
|
||||
project.updateAttributes({
|
||||
data: JSON.stringify( data.data ),
|
||||
email: email,
|
||||
name: data.name,
|
||||
author: data.author || "",
|
||||
template: data.template,
|
||||
latestButterVersion: versions.butter
|
||||
})
|
||||
.complete( function(err, result) {
|
||||
callback( err, result );
|
||||
});
|
||||
})
|
||||
.error(function( error ) {
|
||||
callback( error );
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,197 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = function routesCtor( app, User, filter, sanitizer, stores, EMBED_SUFFIX ) {
|
||||
|
||||
var uuid = require( "node-uuid" ),
|
||||
// Keep track of whether this is production or development
|
||||
deploymentType = app.settings.env === "production" ? "production" : "development";
|
||||
|
||||
app.get( '/api/whoami', filter.isXHR, function( req, res ) {
|
||||
var email = req.session.email;
|
||||
|
||||
if (email) {
|
||||
res.json({
|
||||
status: "okay",
|
||||
csrf: req.session._csrf,
|
||||
email: email,
|
||||
name: email,
|
||||
username: email
|
||||
});
|
||||
} else {
|
||||
res.json({
|
||||
error: 'unauthorized',
|
||||
csrf: req.session._csrf,
|
||||
}, 403 );
|
||||
}
|
||||
});
|
||||
|
||||
app.get( '/api/project/:id?',
|
||||
filter.isLoggedIn, filter.isStorageAvailable, filter.isXHR,
|
||||
function( req, res ) {
|
||||
|
||||
User.findProject( req.session.email, req.params.id, function( err, doc ) {
|
||||
if ( err ) {
|
||||
res.json( { error: err }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !doc ) {
|
||||
res.json( { error: "project not found" }, 404 );
|
||||
return;
|
||||
}
|
||||
|
||||
var projectJSON = JSON.parse( doc.data );
|
||||
projectJSON.name = doc.name;
|
||||
projectJSON.projectID = doc.id;
|
||||
projectJSON.author = doc.author;
|
||||
projectJSON.template = doc.template;
|
||||
res.json( projectJSON );
|
||||
});
|
||||
});
|
||||
|
||||
app.post( '/api/delete/:id?',
|
||||
filter.isLoggedIn, filter.isStorageAvailable, filter.isXHR,
|
||||
function( req, res ) {
|
||||
|
||||
var id = parseInt( req.params.id, 10 );
|
||||
|
||||
if ( isNaN( id ) ) {
|
||||
res.json( { error: "ID was not a number" }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
User.deleteProject( req.session.email, req.params.id, function( err ) {
|
||||
if ( err ) {
|
||||
res.json( { error: 'project not found' }, 404 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete published projects, too
|
||||
var embedShell = id.toString( 36 ),
|
||||
embedDoc = embedShell + EMBED_SUFFIX;
|
||||
|
||||
stores.publish.remove( embedShell, function( e ) {
|
||||
if( e ) {
|
||||
res.json( { error: 'unable to remove file: ' + embedShell }, 500 );
|
||||
return;
|
||||
}
|
||||
stores.publish.remove( embedDoc, function( e ) {
|
||||
if( e ) {
|
||||
res.json( { error: 'unable to remove file: ' + embedDoc }, 500 );
|
||||
return;
|
||||
}
|
||||
res.json( { error: 'okay' }, 200 );
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.post( '/api/project/:id?',
|
||||
filter.isLoggedIn, filter.isStorageAvailable, filter.isXHR,
|
||||
function( req, res ) {
|
||||
|
||||
if ( req.body.id ) {
|
||||
User.updateProject( req.session.email, req.body.id, req.body, function( err, doc ) {
|
||||
if ( err ) {
|
||||
res.json( { error: err }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
res.json( { error: 'okay', project: doc } );
|
||||
});
|
||||
} else {
|
||||
User.createProject( req.session.email, req.body, function( err, doc ) {
|
||||
if ( err ) {
|
||||
res.json( { error: err }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Send back the newly added row's ID
|
||||
res.json( { error: 'okay', projectId: doc.id } );
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// We have a separate remix API for unsecured and sanitized access to projects
|
||||
app.get( '/api/remix/:id',
|
||||
filter.isStorageAvailable, filter.isXHR,
|
||||
function( req, res ) {
|
||||
|
||||
User.findById( req.params.id, function( err, project ) {
|
||||
if ( err ) {
|
||||
res.json( { error: err }, 500 );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !project ) {
|
||||
res.json( { error: 'project not found' }, 404 );
|
||||
return;
|
||||
}
|
||||
|
||||
var projectJSON = JSON.parse( project.data, sanitizer.escapeHTMLinJSON );
|
||||
projectJSON.name = "Remix of " + sanitizer.escapeHTML( project.name );
|
||||
projectJSON.template = sanitizer.escapeHTML( project.template );
|
||||
|
||||
res.json( projectJSON );
|
||||
});
|
||||
});
|
||||
|
||||
function formatDate( d ) {
|
||||
// YYYY-MM-DD
|
||||
d = d || new Date();
|
||||
|
||||
function pad( n ) {
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
return ( d.getUTCFullYear() + '-' +
|
||||
pad( d.getUTCMonth() + 1 ) + '-' +
|
||||
pad( d.getUTCDate() ) );
|
||||
}
|
||||
|
||||
function generateUniqueName( keys ) {
|
||||
// Generate a unique name, with formatting to support analysis later on.
|
||||
// The format is:
|
||||
// <key1>=<value1>/<key2>=<value2>/<key..>=<value..>/<unique blob name>
|
||||
// For example:
|
||||
// dt=2012-05-31T20:00/deployment=production/64432AE8-7132-4C01-BD5E-AE49BC343CC8
|
||||
|
||||
// Serialize keys array
|
||||
var keysString = '';
|
||||
keys.forEach( function( key ) {
|
||||
keysString += key.name + '=' + key.value + '/';
|
||||
});
|
||||
keysString = keysString.replace( /\/$/, '' );
|
||||
|
||||
return keysString + '/' + uuid.v4();
|
||||
}
|
||||
|
||||
function storeData( req, res, store ) {
|
||||
var s = '';
|
||||
|
||||
req.addListener( 'data', function( data ) {
|
||||
s += data;
|
||||
});
|
||||
|
||||
req.addListener( 'end', function() {
|
||||
var name = generateUniqueName([
|
||||
{ name: 'dt', value: formatDate() },
|
||||
{ name: 'deployment', value: deploymentType }
|
||||
]);
|
||||
store.write( name, s, function() {
|
||||
res.writeHead( 200, { 'content-type': 'text/plain' } );
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Store crash reports
|
||||
app.post( '/crash', function( req, res ) {
|
||||
storeData( req, res, stores.crash );
|
||||
});
|
||||
|
||||
// Store feedback reports
|
||||
app.post( '/feedback', function( req, res ) {
|
||||
storeData( req, res, stores.feedback );
|
||||
});
|
||||
|
||||
};
|
|
@ -0,0 +1,119 @@
|
|||
var test = require("tap").test;
|
||||
|
||||
var filter = require( "../lib/filter" );
|
||||
|
||||
test( "isLoggedIn filter allow", function( t ) {
|
||||
t.plan( 1 );
|
||||
|
||||
var mockReq = { session: { email: "test.example.org" } },
|
||||
mockRes = { json: function() {
|
||||
t.ok( false, "this should not be called when session email is set" );
|
||||
}},
|
||||
mockNext = function() {
|
||||
t.ok( true, "next() was called when session was set" );
|
||||
};
|
||||
|
||||
filter().isLoggedIn( mockReq, mockRes, mockNext );
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test( "isLoggedIn filter deny", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockReq = { session: {} },
|
||||
mockRes = { json: function( data, statusCode ) {
|
||||
t.deepEqual(data,
|
||||
{ error: "unauthorized" },
|
||||
"error should be unauthorized" );
|
||||
t.equal( statusCode, 403, "status should be 403 unauthorized" );
|
||||
}},
|
||||
mockNext = function() {
|
||||
t.ok( false, "next() should not be called when session email is null" );
|
||||
};
|
||||
|
||||
filter().isLoggedIn( mockReq, mockRes, mockNext );
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test( "isStorageAvailable filter allow", function( t ) {
|
||||
t.plan( 1 );
|
||||
|
||||
var mockRes = { json: function() {
|
||||
t.ok( false, "this should not be called when storage is available" );
|
||||
}},
|
||||
mockNext = function() {
|
||||
t.ok( true, "next() was called when storage was available" );
|
||||
};
|
||||
|
||||
filter(function() {
|
||||
return true;
|
||||
}).isStorageAvailable( null, mockRes, mockNext );
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test( "isStorageAvailable filter deny", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockRes = { json: function( data, statusCode ) {
|
||||
t.deepEqual(data,
|
||||
{ error: "storage service is not running" },
|
||||
"error should be storage service is not running" );
|
||||
t.equal( statusCode, 500, "status should be 500 server error" );
|
||||
}},
|
||||
mockNext = function() {
|
||||
t.ok( false, "next() should not be called when storage is not available" );
|
||||
};
|
||||
|
||||
filter(function() {
|
||||
return false;
|
||||
}).isStorageAvailable( null, mockRes, mockNext );
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test( "isXHR filter allow", function( t ) {
|
||||
t.plan( 1 );
|
||||
|
||||
var mockReq = { header: function( key ) {
|
||||
if ( key === "X-Requested-With" ) {
|
||||
return "XMLHttpRequest";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}},
|
||||
mockRes = { json: function() {
|
||||
t.ok( false, "this should not be called when X-Requested-With is set" );
|
||||
}},
|
||||
mockNext = function() {
|
||||
t.ok( true, "next() was called when X-Requested-With was set" );
|
||||
};
|
||||
|
||||
filter().isXHR( mockReq, mockRes, mockNext );
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test( "isLoggedIn filter deny", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockReq = { header: function( key ) {
|
||||
return "";
|
||||
}},
|
||||
mockRes = { json: function( data, statusCode ) {
|
||||
t.deepEqual(data,
|
||||
{ error: "X-Requested-With is not set to XMLHttpRequest" },
|
||||
"error should be X-Requested-With is not set to XMLHttpRequest" );
|
||||
t.equal( statusCode, 412, "status should be 412 unauthorized" );
|
||||
}},
|
||||
mockNext = function() {
|
||||
t.ok( false, "next() should not be called when X-Requested-With is null" );
|
||||
};
|
||||
|
||||
filter().isXHR( mockReq, mockRes, mockNext );
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
var test = require("tap").test;
|
||||
|
||||
var sanitizer = require( "../lib/sanitizer" );
|
||||
|
||||
test( "String sanitization", function( t ) {
|
||||
t.equal( sanitizer.escapeHTML( "hello world" ),
|
||||
"hello world",
|
||||
"no sanitization needed" );
|
||||
|
||||
t.equal( sanitizer.escapeHTML( "<script>alert()</script>" ),
|
||||
"<script>alert()</script>",
|
||||
"sanitize less than and greater than" );
|
||||
|
||||
t.equal( sanitizer.escapeHTML( "bill & ted" ),
|
||||
"bill & ted",
|
||||
"sanitize ampersand" );
|
||||
|
||||
t.equal( sanitizer.escapeHTML( "'\"" ),
|
||||
"'"",
|
||||
"sanitize single and double quotes" );
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
test( "JSON sanitization", function( t ) {
|
||||
t.deepEqual(JSON.parse('{"hello":"world"}', sanitizer.escapeHTMLinJSON ),
|
||||
{ hello: "world" },
|
||||
"no sanitization needed" );
|
||||
|
||||
t.deepEqual(JSON.parse('{"test":"<script>alert()</script>"}', sanitizer.escapeHTMLinJSON ),
|
||||
{ test: "<script>alert()</script>" },
|
||||
"sanitize less than and greater than" );
|
||||
|
||||
t.deepEqual(JSON.parse('{"test":"bill & ted"}', sanitizer.escapeHTMLinJSON ),
|
||||
{ test: "bill & ted" },
|
||||
"sanitize ampersand" );
|
||||
|
||||
t.deepEqual(JSON.parse('{"test":"\'\\""}', sanitizer.escapeHTMLinJSON ),
|
||||
{ test: "'"" },
|
||||
"sanitize single and double quotes" );
|
||||
|
||||
t.deepEqual(JSON.parse('{"testing\'\\"alert()": "uh oh" }', sanitizer.escapeHTMLinJSON ),
|
||||
{ "testing'\"alert()": "uh oh" },
|
||||
"key names are not sanitized" );
|
||||
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,126 @@
|
|||
var test = require( "tap" ).test,
|
||||
userLibrary = require( "../lib/user" ),
|
||||
Sequelize = require( "sequelize" );
|
||||
|
||||
var DB_USERNAME = process.env.DB_USERNAME || "popcorntest";
|
||||
var DB_DATABASE = process.env.DB_DATABASE || "popcorntest";
|
||||
var DB_PASSWORD = process.env.DB_PASSWORD || "";
|
||||
var DB_HOST = process.env.DB_HOST;
|
||||
|
||||
var mockEmail = "test@example.org",
|
||||
mockData = {
|
||||
data: {
|
||||
test: "Hey Test Values"
|
||||
},
|
||||
email: mockEmail,
|
||||
name: "Test User",
|
||||
author: "Test User",
|
||||
template: "basic"
|
||||
};
|
||||
|
||||
var configWithPool = {
|
||||
database: DB_DATABASE,
|
||||
username: DB_USERNAME,
|
||||
password: DB_PASSWORD,
|
||||
options: {
|
||||
host: DB_HOST,
|
||||
dialect: "mysql",
|
||||
logging: false,
|
||||
pool: {
|
||||
maxConnections: 5,
|
||||
maxIdleTime: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var configWithoutPool = {
|
||||
database: DB_DATABASE,
|
||||
username: DB_USERNAME,
|
||||
password: DB_PASSWORD,
|
||||
options: {
|
||||
host: DB_HOST,
|
||||
dialect: "mysql",
|
||||
logging: false
|
||||
}
|
||||
};
|
||||
|
||||
function Waiter( numItems, onCompleted, onCancelled ) {
|
||||
var _callbacks = [],
|
||||
_usedCallbacked = 0,
|
||||
_cancelled = false;
|
||||
|
||||
this.wait = function( callback ) {
|
||||
_callbacks.push( callback );
|
||||
return function() {
|
||||
if ( ++_usedCallbacked === _callbacks.length ) {
|
||||
for ( var i = 0; i < _callbacks.length; ++i ) {
|
||||
if ( !_cancelled ) {
|
||||
_callbacks[ i ].apply( this, arguments );
|
||||
if ( _cancelled ) {
|
||||
onCancelled();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
this.cancel = function() {
|
||||
_cancelled = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
test( "mysql db pooling", function( t ) {
|
||||
var poolingUser, nonPoolingUser;
|
||||
|
||||
var waiter = new Waiter( 2,
|
||||
function(){
|
||||
var projectWaiter = new Waiter( 2,
|
||||
function() {
|
||||
t.end();
|
||||
},
|
||||
function() {
|
||||
t.end();
|
||||
});
|
||||
|
||||
poolingUser.createProject( mockEmail, mockData, projectWaiter.wait( function( err, project ) {
|
||||
t.ok( !err, "Pooling project created" );
|
||||
if ( err ) {
|
||||
projectWaiter.cancel();
|
||||
}
|
||||
}));
|
||||
nonPoolingUser.createProject( mockEmail, mockData, projectWaiter.wait( function( err, project ) {
|
||||
t.ok( !err, "Non-pooling project created" );
|
||||
if ( err ) {
|
||||
projectWaiter.cancel();
|
||||
}
|
||||
}));
|
||||
},
|
||||
function() {
|
||||
t.comment( "\nWARNING: MySQL tests did NOT run.\n" +
|
||||
"Make sure that the mysql server is running and a user '" + DB_USERNAME + "' exists with no password for the '" + DB_DATABASE + "' database." );
|
||||
// Just to leave room in comments.
|
||||
t.comment( "" );
|
||||
t.end();
|
||||
});
|
||||
|
||||
poolingUser = userLibrary( configWithPool, waiter.wait( function( err ) {
|
||||
if ( err ) {
|
||||
waiter.cancel();
|
||||
return;
|
||||
}
|
||||
t.ok( poolingUser.getSequelizeInstance().connectorManager.pool, "Pool exists" );
|
||||
}));
|
||||
|
||||
nonPoolingUser = userLibrary( configWithoutPool, waiter.wait( function( err ) {
|
||||
if ( err ) {
|
||||
waiter.cancel();
|
||||
return;
|
||||
}
|
||||
t.ok( !nonPoolingUser.getSequelizeInstance().connectorManager.pool, "No pool exists" );
|
||||
}));
|
||||
|
||||
});
|
|
@ -0,0 +1,293 @@
|
|||
var test = require( "tap" ).test,
|
||||
user,
|
||||
mockEmail = "test@example.org",
|
||||
mockData = {
|
||||
data: {
|
||||
test: "Hey Test Values"
|
||||
},
|
||||
email: mockEmail,
|
||||
name: "Test User",
|
||||
author: "Test User",
|
||||
template: "basic"
|
||||
},
|
||||
id,
|
||||
callback;
|
||||
|
||||
test( "sqlite db setup with incorrect pool params", function( t ) {
|
||||
var poolUser = require( "../lib/user" )({
|
||||
database: "popcorn",
|
||||
options: {
|
||||
dialect: "sqlite",
|
||||
storage: ":memory:",
|
||||
logging: false,
|
||||
pool: {
|
||||
maxConnections: 5,
|
||||
maxIdleTime: 1
|
||||
}
|
||||
}
|
||||
}, function( err ) {
|
||||
t.ok( !poolUser.getSequelizeInstance().connectorManager.pool, "No pool exists" );
|
||||
t.ok( !err, "User created with sqlite db and ignored pool param" );
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test( "sqlite db setup", function( t ) {
|
||||
user = require( "../lib/user" )({
|
||||
database: "popcorn",
|
||||
options: {
|
||||
dialect: "sqlite",
|
||||
storage: ":memory:",
|
||||
logging: false
|
||||
}
|
||||
}, function( err ) {
|
||||
t.ok( !err, "User created with sqlite db" );
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test( "createProject valid parameters", function( t ) {
|
||||
t.plan( 6 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
// Store ID for later tests
|
||||
id = project.id;
|
||||
|
||||
t.ok( project, "Project has data" );
|
||||
t.equal( project.data, JSON.stringify( mockData.data ), "Properly Set Data of Project" );
|
||||
t.equal( project.email, mockData.email, "Properly Set Email of Project" );
|
||||
t.equal( project.name, mockData.name, "Properly Set Name of Project" );
|
||||
t.equal( project.author, mockData.author, "Properly Set Author of Project" );
|
||||
t.equal( project.template, mockData.template, "Properly Set Template of Project" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.createProject( mockEmail, mockData, mockCallback );
|
||||
});
|
||||
|
||||
test( "createProject invalid parameters - Project Data", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to update", "Reported expected error message" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.createProject( mockEmail, null, mockCallback );
|
||||
});
|
||||
|
||||
test( "createProject invalid parameters - Email", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to update", "Reported expected error message for creation" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.createProject( null, mockData, mockCallback );
|
||||
});
|
||||
|
||||
test( "deleteProject invalid parameters - Project ID", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to delete", "Reported expected error message for delete" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.deleteProject( mockEmail, null, mockCallback );
|
||||
});
|
||||
|
||||
test( "deleteProject invalid parameters - Email", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to delete", "Reported expected error message for delete" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.deleteProject( null, id, mockCallback );
|
||||
});
|
||||
|
||||
test( "deleteProject valid parameters", function( t ) {
|
||||
t.plan( 1 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
var deleteCallback = function( err ) {
|
||||
t.false( err, "No error was passed back. Project successfully removed." );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.deleteProject( mockEmail, project.id, deleteCallback );
|
||||
};
|
||||
|
||||
user.createProject( mockEmail, mockData, mockCallback );
|
||||
});
|
||||
|
||||
test( "findAllProjects valid parameters", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, docs ) {
|
||||
t.ok( Array.isArray( docs ), "Returned an array of projects" );
|
||||
t.ok( docs, "Successfully returned all projects for " + mockEmail );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.findAllProjects( mockEmail, mockCallback );
|
||||
});
|
||||
|
||||
test( "findAllProjects invalid parameters", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, docs ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to search", "Reported expected error message for retrieving all projects" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.findAllProjects( null, mockCallback );
|
||||
});
|
||||
|
||||
test( "findById valid parameters", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( project, "Successfully received a project" );
|
||||
t.deepEqual( project.id, id, "ID of retrieved project matches." );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.findById( id, mockCallback );
|
||||
});
|
||||
|
||||
test( "findById invalid parameters", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters for search", "Reported expected error message for retrieving by ID" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.findById( null, mockCallback );
|
||||
});
|
||||
|
||||
test( "findProject valid parameters", function( t ) {
|
||||
t.plan( 7 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( project, "Project was retrieved" );
|
||||
t.deepEqual( project.id, id, "Project has correct id" );
|
||||
t.equal( project.data, JSON.stringify( mockData.data ), "Properly Set Data of Project" );
|
||||
t.equal( project.email, mockData.email, "Properly Set Email of Project" );
|
||||
t.equal( project.name, mockData.name, "Properly Set Name of Project" );
|
||||
t.equal( project.author, mockData.author, "Properly Set Author of Project" );
|
||||
t.equal( project.template, mockData.template, "Properly Set Template of Project" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.findProject( mockEmail, id, mockCallback );
|
||||
});
|
||||
|
||||
test( "findProject invalid parameters - Project ID", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to search", "Reported expected error message for project retrieval" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.findProject( mockEmail, null, mockCallback );
|
||||
});
|
||||
|
||||
test( "findProject invalid parameters - Email", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to search", "Reported expected error message for project retrieval" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.findProject( null, id, mockCallback );
|
||||
});
|
||||
|
||||
test( "updateProject valid parameters", function( t ) {
|
||||
t.plan( 4 );
|
||||
|
||||
var updateData = {
|
||||
data: {
|
||||
test: "NEW TEXT"
|
||||
},
|
||||
name: "Test Userd",
|
||||
author: "Test Userd",
|
||||
template: "advanced"
|
||||
},
|
||||
mockCallback = function( err, project ) {
|
||||
t.equal( project.data, JSON.stringify( updateData.data ), "Properly updated Data of Project" );
|
||||
t.equal( project.name, updateData.name, "Properly updated Name of Project" );
|
||||
t.equal( project.author, updateData.author, "Properly updated Author of Project" );
|
||||
t.equal( project.template, updateData.template, "Properly updated Template of Project" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.updateProject( mockEmail, id, updateData, mockCallback );
|
||||
});
|
||||
|
||||
test( "updateProject invalid parameters - Project Data", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to update", "Reported expected error message for project updating" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.updateProject( mockEmail, id, null, mockCallback );
|
||||
});
|
||||
|
||||
test( "updateProject invalid parameters - Project ID", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to update", "Reported expected error message for project updating" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.updateProject( mockEmail, null, mockData, mockCallback );
|
||||
});
|
||||
|
||||
test( "updateProject invalid parameters - Email", function( t ) {
|
||||
t.plan( 2 );
|
||||
|
||||
var mockCallback = function( err, project ) {
|
||||
t.ok( err, "Successfully received an error with invalid parameters" );
|
||||
t.equal( err, "not enough parameters to update", "Reported expected error message for project updating" );
|
||||
|
||||
t.end();
|
||||
};
|
||||
|
||||
user.updateProject( null, id, mockData, mockCallback );
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
function mockFilter(req, res, next) {
|
||||
next();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isLoggedIn: mockFilter,
|
||||
isStorageAvailable: mockFilter,
|
||||
isXHR: mockFilter
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
escapeHTML: function escapeHTML( s ) {
|
||||
return s;
|
||||
},
|
||||
escapeHTMLinJSON: function escapeHTMLinJSON( key, value ) {
|
||||
return value;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
module.exports = function(data) {
|
||||
data = data || {};
|
||||
|
||||
return function(req, res, next) {
|
||||
req.session = {};
|
||||
|
||||
Object.keys(data).forEach(function(key) {
|
||||
req.session[key] = data[key];
|
||||
});
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
publish: {
|
||||
remove: function(path, callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,88 @@
|
|||
function generateMockData(id) {
|
||||
id = id || parseInt( Math.random()*10000, 10 );
|
||||
|
||||
return {
|
||||
id: id,
|
||||
data: JSON.stringify({
|
||||
hello: "world",
|
||||
adventure: "bill & ted's"
|
||||
}),
|
||||
email: "test@example.org",
|
||||
name: "My Mock Project",
|
||||
author: "Test User",
|
||||
template: "basic"
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function() {
|
||||
return {
|
||||
error: false,
|
||||
doc: true,
|
||||
generateMockData: generateMockData,
|
||||
findProject: function(email, id, callback) {
|
||||
if (this.error) {
|
||||
callback("mock error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.doc) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, generateMockData(id));
|
||||
},
|
||||
deleteProject: function(email, id, callback) {
|
||||
if (this.error) {
|
||||
callback("mock error");
|
||||
return;
|
||||
}
|
||||
|
||||
callback();
|
||||
},
|
||||
findById: function(id, callback) {
|
||||
if (this.error) {
|
||||
callback("mock error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.doc) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, generateMockData(id));
|
||||
},
|
||||
createProject: function(email, data, callback) {
|
||||
if (this.error) {
|
||||
callback("mock error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.data) {
|
||||
callback("not enough parameters to update");
|
||||
return;
|
||||
}
|
||||
|
||||
data.id = parseInt( Math.random()*10000, 10 );
|
||||
data.data = JSON.stringify( data.data );
|
||||
|
||||
callback(null, data);
|
||||
},
|
||||
updateProject: function(email, id, data, callback) {
|
||||
if (this.error) {
|
||||
callback("mock error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.doc) {
|
||||
callback("project id not found");
|
||||
return;
|
||||
}
|
||||
|
||||
data.data = JSON.stringify( data.data );
|
||||
|
||||
callback(null, data);
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,303 @@
|
|||
var test = require("tap").test,
|
||||
request = require("supertest");
|
||||
|
||||
var mockEmail = "test@example.org",
|
||||
mockSession = require("./mock.session"),
|
||||
mockUser = require("./mock.user")(),
|
||||
mockFilter = require("./mock.filter"),
|
||||
mockSanitizer = require("./mock.sanitizer"),
|
||||
mockStore = require("./mock.store");
|
||||
|
||||
var express = require("express");
|
||||
var app = express.createServer();
|
||||
|
||||
app.use(mockSession({
|
||||
email: mockEmail,
|
||||
_csrf: "FDaS435D2z"
|
||||
}))
|
||||
.use(express.bodyParser());
|
||||
|
||||
require("../routes")(app, mockUser, mockFilter, mockSanitizer, mockStore);
|
||||
|
||||
test("whoami API valid", function(t) {
|
||||
request(app)
|
||||
.get("/api/whoami")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 200, "status code is 200");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.deepEqual(res.body, {
|
||||
status: "okay",
|
||||
email: mockEmail,
|
||||
name: mockEmail,
|
||||
username: mockEmail,
|
||||
csrf: "FDaS435D2z"
|
||||
}, "response should have 5 attributes");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("project data get with error", function(t) {
|
||||
mockUser.error = true;
|
||||
mockUser.doc = false;
|
||||
|
||||
request(app)
|
||||
.get("/api/project/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 500, "status code is 500");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.ok(res.body.error, "json contains an error");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("project data get not found", function(t) {
|
||||
mockUser.error = false;
|
||||
mockUser.doc = false;
|
||||
|
||||
request(app)
|
||||
.get("/api/project/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 404, "status code is 404");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.ok(res.body.error, "json contains an error");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("project data get valid", function(t) {
|
||||
mockUser.error = false;
|
||||
mockUser.doc = true;
|
||||
|
||||
request(app)
|
||||
.get("/api/project/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 200, "status code is 200");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
|
||||
// This is very obtuse...
|
||||
var mockData = mockUser.generateMockData(1234);
|
||||
mockData.data = JSON.parse(mockData.data);
|
||||
mockData.data.name = mockData.name;
|
||||
mockData.data.projectID = mockData.id;
|
||||
mockData.data.author = mockData.author;
|
||||
mockData.data.template = mockData.template;
|
||||
mockData = mockData.data;
|
||||
t.deepEqual(res.body, mockData, "saved data is equal");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("delete project not found", function(t) {
|
||||
mockUser.error = true;
|
||||
|
||||
request(app)
|
||||
.post("/api/delete/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 404, "status code is 404");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.ok(res.body.error, "json contains an error");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("delete project found", function(t) {
|
||||
mockUser.error = false;
|
||||
|
||||
request(app)
|
||||
.post("/api/delete/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 200, "status code is 200");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
// wtf was I think when returning error is a good thing?
|
||||
t.equal(res.body.error, "okay", "json returns okay");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
/*******************
|
||||
* DANGER ZONE *
|
||||
* HERE BE DRAGONS *
|
||||
*******************/
|
||||
|
||||
test("create project with error", function(t) {
|
||||
mockUser.error = true;
|
||||
|
||||
var mockData = mockUser.generateMockData(1234);
|
||||
delete mockData.id;
|
||||
|
||||
request(app)
|
||||
.post("/api/project/1234")
|
||||
.send(mockData)
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 500, "status code is 500");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.equal(res.body.error, "mock error", "error message is correct");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("create project with no data", function(t) {
|
||||
mockUser.error = false;
|
||||
|
||||
var mockData = mockUser.generateMockData(1234);
|
||||
delete mockData.id;
|
||||
delete mockData.data;
|
||||
|
||||
request(app)
|
||||
.post("/api/project/1234")
|
||||
.send(mockData)
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 500, "status code is 500");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.equal(res.body.error, "not enough parameters to update", "error message is correct");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("create project valid", function(t) {
|
||||
mockUser.error = false;
|
||||
|
||||
var mockData = mockUser.generateMockData();
|
||||
mockData.data = JSON.parse(mockData.data);
|
||||
delete mockData.id;
|
||||
|
||||
request(app)
|
||||
.post("/api/project/1234")
|
||||
.send(mockData)
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 200, "status code is 200");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.equal(res.body.error, "okay", "status is okay");
|
||||
t.ok(res.body.projectId, "id is present");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("update project with error", function(t) {
|
||||
mockUser.error = true;
|
||||
mockUser.doc = true;
|
||||
|
||||
var mockData = mockUser.generateMockData(1234);
|
||||
mockData.data = JSON.parse(mockData.data);
|
||||
mockData.id = mockData.id;
|
||||
|
||||
request(app)
|
||||
.post("/api/project/1234")
|
||||
.send(mockData)
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 500, "status code is 500");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.ok(res.body.error, "mock error");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("update project with no matching id", function(t) {
|
||||
mockUser.error = false;
|
||||
mockUser.doc = false;
|
||||
|
||||
var mockData = mockUser.generateMockData(1234);
|
||||
mockData.data = JSON.parse(mockData.data);
|
||||
mockData.id = mockData.id;
|
||||
|
||||
request(app)
|
||||
.post("/api/project/1234")
|
||||
.send(mockData)
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 500, "status code is 500");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.ok(res.body.error, "project id not found");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("update project valid", function(t) {
|
||||
mockUser.error = false;
|
||||
mockUser.doc = true;
|
||||
|
||||
var mockData = mockUser.generateMockData(1234);
|
||||
mockData.data = JSON.parse(mockData.data);
|
||||
mockData.id = mockData.id;
|
||||
|
||||
request(app)
|
||||
.post("/api/project/1234")
|
||||
.send(mockData)
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 200, "status code is 200");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.equal(res.body.error, "okay", "status is okay");
|
||||
mockData.data = JSON.stringify(mockData.data);
|
||||
t.deepEqual(res.body.project, mockData, "saved data is equal");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test("remix project with error", function(t) {
|
||||
mockUser.error = true;
|
||||
mockUser.doc = false;
|
||||
|
||||
request(app)
|
||||
.get("/api/remix/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 500, "status code is 500");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.ok(res.body.error, "json contains an error");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("remix project with no doc", function(t) {
|
||||
mockUser.error = false;
|
||||
mockUser.doc = false;
|
||||
|
||||
request(app)
|
||||
.get("/api/remix/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 404, "status code is 404");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
t.ok(res.body.error, "json contains an error");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("remix project valid", function(t) {
|
||||
mockUser.error = false;
|
||||
mockUser.doc = true;
|
||||
|
||||
request(app)
|
||||
.get("/api/remix/1234")
|
||||
.end(function(err, res) {
|
||||
t.equal(res.statusCode, 200, "status code is 200");
|
||||
t.equal(res.type, "application/json", "response type is json");
|
||||
|
||||
// This is very obtuse...
|
||||
var mockData = mockUser.generateMockData(1234);
|
||||
mockData.data = JSON.parse(mockData.data);
|
||||
mockData.data.name = "Remix of " + mockData.name;
|
||||
mockData.data.template = "basic";
|
||||
mockData = mockData.data;
|
||||
t.deepEqual(res.body, mockData, "saved data is equal");
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test("clean up server connections", function(t) {
|
||||
app.close();
|
||||
t.end();
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
doctype 5
|
||||
html
|
||||
head
|
||||
title Dashboard
|
||||
style
|
||||
body {
|
||||
font-family: "Open Sans", "Helvetica Neue", sans-serif;
|
||||
background: #3D3F44;
|
||||
color: #EEE;
|
||||
width: 650px;
|
||||
margin: 0 auto;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
img {
|
||||
width: 650px;
|
||||
}
|
||||
body
|
||||
h1 Sorry...
|
||||
img(src="/struggling-dino.gif")
|
||||
p Please login before attempting to view your dashboard.
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
doctype 5
|
||||
html
|
||||
head
|
||||
title Dashboard
|
||||
link(rel='stylesheet',href='../css/butter.ui.css')
|
||||
script
|
||||
(function(){
|
||||
var currentDeletionId;
|
||||
|
||||
function setDeletionHeaderState( state, projectName ) {
|
||||
var header = document.querySelector( 'div.butter-delete-confirmation' ),
|
||||
nameSpan = header.querySelector( 'span' ),
|
||||
table = document.querySelector( 'table' );
|
||||
|
||||
if ( !state ) {
|
||||
//avoid shim problems completely
|
||||
header.className = 'butter-delete-confirmation';
|
||||
table.className = '';
|
||||
}
|
||||
else {
|
||||
nameSpan.innerHTML = projectName;
|
||||
|
||||
//avoid shim problems completely
|
||||
header.className = 'butter-delete-confirmation open';
|
||||
table.className = 'confirm-delete';
|
||||
}
|
||||
}
|
||||
|
||||
function createDeleteHandler( deleteElement ) {
|
||||
var projectId = deleteElement.getAttribute( 'data-project-id' ),
|
||||
projectName = deleteElement.getAttribute( 'data-project-name' );
|
||||
|
||||
deleteElement.addEventListener( 'click', function( e ) {
|
||||
setDeletionHeaderState( true, projectName );
|
||||
currentDeletionId = projectId;
|
||||
}, false );
|
||||
}
|
||||
|
||||
document.addEventListener( 'DOMContentLoaded', function( e ) {
|
||||
var deleteButtons = document.querySelectorAll( 'td > a.butter-delete-button' ),
|
||||
i = deleteButtons ? deleteButtons.length : 0,
|
||||
noButton = document.querySelector( 'div.butter-delete-confirmation > button.no' ),
|
||||
yesButton = document.querySelector( 'div.butter-delete-confirmation > button.yes' );
|
||||
|
||||
noButton.addEventListener( 'click', function( e ) {
|
||||
setDeletionHeaderState( false );
|
||||
currentDeletionId = null;
|
||||
}, false );
|
||||
|
||||
yesButton.addEventListener( 'click', function( e ) {
|
||||
var req,
|
||||
row;
|
||||
if ( currentDeletionId ) {
|
||||
req = new XMLHttpRequest();
|
||||
req.open( 'POST', '/api/delete/' + currentDeletionId, false );
|
||||
req.setRequestHeader( "X-Requested-With", "XMLHttpRequest" );
|
||||
req.setRequestHeader( "x-csrf-token", document.getElementById( "csrf" ).value );
|
||||
row = document.querySelector( 'tr[data-project-id="' + currentDeletionId + '"]' );
|
||||
currentDeletionId = null;
|
||||
req.send( null );
|
||||
if ( req.status == 200 ) {
|
||||
row.parentNode.removeChild( row );
|
||||
}
|
||||
setDeletionHeaderState( false );
|
||||
}
|
||||
}, false );
|
||||
|
||||
while ( i-- ) {
|
||||
createDeleteHandler( deleteButtons[ i ] );
|
||||
}
|
||||
}, false );
|
||||
}());
|
||||
style
|
||||
body {
|
||||
font-family: "Open Sans", "Helvetica Neue", sans-serif;
|
||||
background: #3D3F44;
|
||||
color: #888;
|
||||
width: 650px;
|
||||
margin: 0 auto;
|
||||
font-size: .9em;
|
||||
overflow: scroll;
|
||||
}
|
||||
.butter-logo {
|
||||
background: url( "logo-words.png" ) no-repeat;
|
||||
}
|
||||
table, th, tr, td {
|
||||
border: none;
|
||||
border-spacing: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: 350px;
|
||||
}
|
||||
table {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 40px;
|
||||
-moz-transition: margin-top 0.3s;
|
||||
-webkit-transition: margin-top 0.3s;
|
||||
-ms-transition: margin-top 0.3s;
|
||||
-o-transition: margin-top 0.3s;
|
||||
transition: margin-top 0.3s;
|
||||
}
|
||||
table.confirm-delete {
|
||||
margin-top: 45px;
|
||||
}
|
||||
th {
|
||||
text-align: left;
|
||||
color: #EEE;
|
||||
border-bottom: 1px solid #222;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
td, th {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
td a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
}
|
||||
td a:hover {
|
||||
text-decoration: underline;
|
||||
color: #fff;
|
||||
}
|
||||
td:first-child {
|
||||
width: 350px;
|
||||
}
|
||||
td:first-child:hover {
|
||||
background: rgb(255,239,158);
|
||||
-webkit-transition: .2s all;
|
||||
-moz-transition: .2s all;
|
||||
-ms-transition: .2s all;
|
||||
-o-transition: .2s all;
|
||||
transition: .2s all;
|
||||
}
|
||||
td:first-child:hover a {
|
||||
color: #242428;
|
||||
}
|
||||
td:nth-child(2) {
|
||||
width: 300px;
|
||||
}
|
||||
tr:nth-child(odd) {
|
||||
background: rgba(0,0,0,.3);
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background: rgba(0,0,0,.4);
|
||||
}
|
||||
|
||||
.butter-projects-title {
|
||||
display: block;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
color: #EEE;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.butter-projects-title:hover {
|
||||
color: #FFF;
|
||||
}
|
||||
.butter-delete-confirmation {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 51px;
|
||||
background: rgb(241,218,54); /* Old browsers */
|
||||
background: -moz-linear-gradient(top, rgba(241,218,54,1) 0%, rgba(252,239,118,1) 100%); /* FF3.6+ */
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(241,218,54,1)), color-stop(100%,rgba(252,239,118,1))); /* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(top, rgba(241,218,54,1) 0%,rgba(252,239,118,1) 100%); /* Chrome10+,Safari5.1+ */
|
||||
background: -o-linear-gradient(top, rgba(241,218,54,1) 0%,rgba(252,239,118,1) 100%); /* Opera 11.10+ */
|
||||
background: -ms-linear-gradient(top, rgba(241,218,54,1) 0%,rgba(252,239,118,1) 100%); /* IE10+ */
|
||||
background: linear-gradient(top, rgba(241,218,54,1) 0%,rgba(252,239,118,1) 100%); /* W3C */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f1da36', endColorstr='#fcef76',GradientType=0 ); /* IE6-9 */
|
||||
-moz-transition: all 0.3s;
|
||||
-webkit-transition: all 0.3s;
|
||||
-ms-transition: all 0.3s;
|
||||
-o-transition: all 0.3s;
|
||||
transition: all 0.3s;
|
||||
padding: 0px;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
height: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.butter-delete-confirmation span {
|
||||
max-width: 200px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.butter-delete-confirmation.open {
|
||||
height: 20px;
|
||||
padding: 8px;
|
||||
}
|
||||
body.butter-header-spacing
|
||||
div#butter-header
|
||||
div.butter-header-inner
|
||||
div.butter-logo
|
||||
span.butter-name My Dashboard –
|
||||
= user.email
|
||||
div.butter-delete-confirmation
|
||||
| Are you sure you want to delete "
|
||||
span.project-name
|
||||
| "?
|
||||
button.yes Yes
|
||||
button.no No
|
||||
|
||||
table
|
||||
tr
|
||||
th Project Title
|
||||
th Template
|
||||
th
|
||||
each project in projects
|
||||
tr(data-project-id=project._id)
|
||||
td
|
||||
a(href= project.href).butter-projects-title
|
||||
= project.name
|
||||
td
|
||||
= project.template
|
||||
td
|
||||
a(href= "#", data-project-id=project._id, data-project-name=project.name).butter-delete-button
|
||||
| Delete
|
||||
input(id="csrf", type="hidden", value=user.csrf)
|
|
@ -0,0 +1,22 @@
|
|||
!!! 5
|
||||
html
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
meta(http-equiv='X-UA-Compatible', content='IE=edge,chrome=1')
|
||||
meta(name='author', content='#{author}')
|
||||
meta(name='title', content='#{projectName}')
|
||||
meta(name='og:title', content='#{projectName}')
|
||||
meta(name='og:type', content='video.other')
|
||||
meta(name='og:url', content='#{embedShellSrc}')
|
||||
meta(name='og:image', content='#{baseHref}/resources/logo/popcorn.png')
|
||||
meta(name='og:image:type', content='image/png')
|
||||
meta(name='og:image:width', content='33')
|
||||
meta(name='og:image:width', content='50')
|
||||
meta(name='og:description', content='This was created with Popcorn Maker - part of the Mozilla Webmaker initiative')
|
||||
meta(name='og:site_name', content='https://webmaker.org')
|
||||
meta(name='description', content='This was created with Popcorn Maker - part of the Mozilla Webmaker initiative')
|
||||
title #{projectName} - Popcorn Maker
|
||||
meta(name='viewport', content='width=device-width')
|
||||
link(rel='stylesheet', href='#{baseHref}/css/embed-shell.css')
|
||||
body
|
||||
iframe(src='#{embedSrc}', width='1280', height='745', frameborder='0', mozallowfullscreen='mozallowfullscreen', webkitallowfullscreen='webkitallowfullscreen', allowfullscreen='allowfullscreen')
|
|
@ -0,0 +1,98 @@
|
|||
!!! 5
|
||||
html(lang='en')
|
||||
head
|
||||
base(href='#{baseHref}')
|
||||
!{templateScripts}
|
||||
!{externalAssets}
|
||||
!{popcorn}
|
||||
link(rel='stylesheet', href='/css/embed.css')
|
||||
link(rel='stylesheet', href="/css/controls.css")
|
||||
// This is the embed, the actual content is at the following URL
|
||||
link(rel='cannonical', href='#{embedShellSrc}')
|
||||
style
|
||||
@-o-viewport { width: device-width; }
|
||||
@-moz-viewport { width: device-width; }
|
||||
@-ms-viewport { width: device-width; }
|
||||
@-webkit-viewport { width: device-width; }
|
||||
@viewport { width: device-width; }
|
||||
script(src='/src/embed.js')
|
||||
body.embed
|
||||
#container.container
|
||||
#video-container.video
|
||||
#video
|
||||
#controls-big-play-button
|
||||
#post-roll.embed-overlay(style='display: none;')
|
||||
.post-roll-inner
|
||||
a(href='#').embed-logo
|
||||
.embed-project
|
||||
div
|
||||
.mozpopcorn Mozilla Popcorn
|
||||
.embed-title #{title}
|
||||
.embed-author #{author}
|
||||
.post-roll-description
|
||||
| This was created with Mozilla Popcorn.
|
||||
br
|
||||
a(href='/', target='_blank') Create a project like this!
|
||||
ul.embed-nav.post-roll-options
|
||||
li
|
||||
a#replay-post
|
||||
span Replay
|
||||
li
|
||||
a(href='#{remixUrl}', target='_blank')#remix-post
|
||||
span Remix
|
||||
li
|
||||
a#share-post
|
||||
span Share
|
||||
#share.embed-overlay(style='display: none;')
|
||||
.share-inner
|
||||
a#share-close X
|
||||
a.embed-logo
|
||||
.embed-project
|
||||
div
|
||||
.mozpopcorn Mozilla Popcorn
|
||||
.embed-title #{title}
|
||||
.embed-author #{author}
|
||||
#share-options.share-options
|
||||
fieldset
|
||||
label URL
|
||||
input#share-url.share-ul(type='url')
|
||||
ul.embed-nav.share-buttons
|
||||
li
|
||||
a#replay-share(href='#') Twitter
|
||||
li
|
||||
a#share-share(href='#') Google+
|
||||
fieldset
|
||||
label Embed
|
||||
textarea#share-iframe
|
||||
iframe
|
||||
.share-size
|
||||
div.size-options
|
||||
a.small.option(href='#')
|
||||
span.icon
|
||||
span.size Small
|
||||
span.dimensions 560x358
|
||||
a.medium.option.current(href='#')
|
||||
span.icon
|
||||
span.size Medium
|
||||
span.dimensions 640x403
|
||||
a.large.option(href='#')
|
||||
span.icon
|
||||
span.size Large
|
||||
span.dimensions 853x523
|
||||
a.xlarge.option(href='#')
|
||||
span.icon
|
||||
span.size X-Large
|
||||
span.dimensions 1280x763
|
||||
#attribution-info.attribution-info
|
||||
#attribution-logo.attribution-logo
|
||||
span.attribution-text Credits
|
||||
#attribution-details.attribution-details
|
||||
span.attribution-close
|
||||
div.attribution-mopop mozilla Popcorn
|
||||
div.attribution-title #{title}
|
||||
if author
|
||||
div.attribution-author #{author}
|
||||
div.attribution-media
|
||||
span.media-icon
|
||||
a.attribution-media-src(href='#{mediaSrc}', target='_blank') #{mediaSrc}
|
||||
#controls.controls
|
|
@ -0,0 +1,26 @@
|
|||
/* This Source Code Form is subject to the terms of the MIT license
|
||||
* If a copy of the MIT license was not distributed with this file, you can
|
||||
* obtain one at http://www.mozillapopcorn.org/butter-license.txt */
|
||||
|
||||
@import "globals";
|
||||
@import "webfonts";
|
||||
@import "normalize";
|
||||
@import "utilities";
|
||||
|
||||
@import "common";
|
||||
|
||||
@import "ui-states";
|
||||
@import "buttons";
|
||||
@import "dialog";
|
||||
|
||||
@import "media-editor";
|
||||
@import "editors";
|
||||
|
||||
@import "header";
|
||||
@import "tray";
|
||||
@import "tray-status-bar";
|
||||
@import "tray-timeline";
|
||||
|
||||
@import "plugin-module";
|
||||
@import "share-editor";
|
||||
@import "super-scrollbar";
|
|
@ -0,0 +1,570 @@
|
|||
/*********************************************************
|
||||
* BUTTONS
|
||||
*/
|
||||
|
||||
@_btnLineHeight: 14px;
|
||||
@_btnTotalHeight: 35px; // It turns out that the total height of our buttons is 35px.
|
||||
|
||||
// Base
|
||||
.butter-btn {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
line-height: @_btnTotalHeight - 2; //borders
|
||||
padding: 0 10px;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
border: 1px solid @baseLight;
|
||||
background: @baseLight;
|
||||
color: @baseText;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
// Disabled states
|
||||
.butter-btn-slide-out {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
.butter-btn {
|
||||
float: left;
|
||||
.transition( all 0.2s ease-in );
|
||||
}
|
||||
.butter-disabled {
|
||||
margin-top: -@_btnTotalHeight;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.butter-btn.butter-disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
// Colors
|
||||
.btn-light {
|
||||
background: @baseLight;
|
||||
color: @baseText;
|
||||
border: 1px solid darken( @baseLight, 20% );
|
||||
border-top-color: darken( @baseLight, 15% );
|
||||
border-bottom-color: darken( @baseLight, 25% );
|
||||
box-shadow: inset 0 1px 0 lighten( @baseLight, 10% );
|
||||
.box-sizing( border-box );
|
||||
&:hover {
|
||||
color: darken( @baseText, 10% );
|
||||
}
|
||||
}
|
||||
|
||||
.btn-green {
|
||||
background: @green;
|
||||
color: #FFF;
|
||||
border: 1px solid darken( @green, 15% );
|
||||
border-top-color: darken( @green, 10% );
|
||||
border-bottom-color: darken( @green, 20% );
|
||||
box-shadow: inset 0 1px 0 lighten( @green, 10% );
|
||||
&:hover {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-red {
|
||||
background: #D3473C;
|
||||
color: #FFF;
|
||||
border: 1px solid #A32630;
|
||||
box-shadow: inset 0 1px 0 lighten( #D3473C, 10% );
|
||||
}
|
||||
|
||||
// Button group
|
||||
.btn-group {
|
||||
display: inline-block;
|
||||
a, button {
|
||||
margin-left: -5px;
|
||||
border-right-width: 0;
|
||||
}
|
||||
.butter-btn:first-of-type {
|
||||
margin-left: 0;
|
||||
border-radius: 2px 0 0 2px;
|
||||
}
|
||||
.butter-btn:last-of-type {
|
||||
border-radius: 0 2px 2px 0;
|
||||
border-right-width: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Media Icons
|
||||
*/
|
||||
|
||||
.media-icon {
|
||||
position: relative;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
background: url( "../resources/media-icons.png" ) no-repeat;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
&.html5-icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
&.youtube-icon {
|
||||
background-position: -16px 0;
|
||||
}
|
||||
&.vimeo-icon {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
&.soundcloud-icon {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Icons
|
||||
*/
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
background-image: url("../resources/glyphicons-halflings-alt.png");
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-left: -4px;
|
||||
margin-right: 4px;
|
||||
line-height: @_btnLineHeight;
|
||||
background-repeat: no-repeat;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
.icon-only {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.icon-grear-sign {
|
||||
background-position: -240px 0;
|
||||
}
|
||||
.icon-white {
|
||||
background-image: url("../resources/glyphicons-halflings-white.png");
|
||||
}
|
||||
.icon-glass {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.icon-music {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
.icon-search {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
.icon-envelope {
|
||||
background-position: -72px 0;
|
||||
}
|
||||
.icon-heart {
|
||||
background-position: -96px 0;
|
||||
}
|
||||
.icon-star {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
.icon-star-empty {
|
||||
background-position: -144px 0;
|
||||
}
|
||||
.icon-user {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
.icon-film {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
.icon-th-large {
|
||||
background-position: -216px 0;
|
||||
}
|
||||
.icon-th {
|
||||
background-position: -240px 0;
|
||||
}
|
||||
.icon-th-list {
|
||||
background-position: -264px 0;
|
||||
}
|
||||
.icon-ok {
|
||||
background-position: -288px 0;
|
||||
}
|
||||
.icon-remove {
|
||||
background-position: -312px 0;
|
||||
}
|
||||
.icon-x,
|
||||
.icon-close {
|
||||
background-position: -432px -24px;
|
||||
}
|
||||
.icon-zoom-in {
|
||||
background-position: -336px 0;
|
||||
}
|
||||
.icon-zoom-out {
|
||||
background-position: -360px 0;
|
||||
}
|
||||
.icon-off {
|
||||
background-position: -384px 0;
|
||||
}
|
||||
.icon-signal {
|
||||
background-position: -408px 0;
|
||||
}
|
||||
.icon-cog {
|
||||
background-position: -432px 0;
|
||||
}
|
||||
.icon-trash {
|
||||
background-position: -456px 0;
|
||||
}
|
||||
.icon-home {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
.icon-file {
|
||||
background-position: -24px -24px;
|
||||
}
|
||||
.icon-time {
|
||||
background-position: -48px -24px;
|
||||
}
|
||||
.icon-road {
|
||||
background-position: -72px -24px;
|
||||
}
|
||||
.icon-download-alt {
|
||||
background-position: -96px -24px;
|
||||
}
|
||||
.icon-download {
|
||||
background-position: -120px -24px;
|
||||
}
|
||||
.icon-upload {
|
||||
background-position: -144px -24px;
|
||||
}
|
||||
.icon-inbox {
|
||||
background-position: -168px -24px;
|
||||
}
|
||||
.icon-play-circle {
|
||||
background-position: -192px -24px;
|
||||
}
|
||||
.icon-repeat {
|
||||
background-position: -216px -24px;
|
||||
}
|
||||
.icon-refresh {
|
||||
background-position: -240px -24px;
|
||||
}
|
||||
.icon-list-alt {
|
||||
background-position: -264px -24px;
|
||||
}
|
||||
.icon-lock {
|
||||
background-position: -287px -24px;
|
||||
}
|
||||
.icon-flag {
|
||||
background-position: -312px -24px;
|
||||
}
|
||||
.icon-headphones {
|
||||
background-position: -336px -24px;
|
||||
}
|
||||
.icon-volume-off {
|
||||
background-position: -360px -24px;
|
||||
}
|
||||
.icon-volume-down {
|
||||
background-position: -384px -24px;
|
||||
}
|
||||
.icon-volume-up {
|
||||
background-position: -408px -24px;
|
||||
}
|
||||
.icon-grabhandle {
|
||||
background-position: -456px -24px;
|
||||
}
|
||||
.icon-tag {
|
||||
background-position: 0 -48px;
|
||||
}
|
||||
.icon-tags {
|
||||
background-position: -25px -48px;
|
||||
}
|
||||
.icon-book {
|
||||
background-position: -48px -48px;
|
||||
}
|
||||
.icon-bookmark {
|
||||
background-position: -72px -48px;
|
||||
}
|
||||
.icon-print {
|
||||
background-position: -96px -48px;
|
||||
}
|
||||
.icon-camera {
|
||||
background-position: -120px -48px;
|
||||
}
|
||||
.icon-font {
|
||||
background-position: -144px -48px;
|
||||
}
|
||||
.icon-bold {
|
||||
background-position: -167px -48px;
|
||||
}
|
||||
.icon-italic {
|
||||
background-position: -192px -48px;
|
||||
}
|
||||
.icon-text-height {
|
||||
background-position: -216px -48px;
|
||||
}
|
||||
.icon-text-width {
|
||||
background-position: -240px -48px;
|
||||
}
|
||||
.icon-align-left {
|
||||
background-position: -264px -48px;
|
||||
}
|
||||
.icon-align-center {
|
||||
background-position: -288px -48px;
|
||||
}
|
||||
.icon-align-right {
|
||||
background-position: -312px -48px;
|
||||
}
|
||||
.icon-align-justify {
|
||||
background-position: -336px -48px;
|
||||
}
|
||||
.icon-list {
|
||||
background-position: -360px -48px;
|
||||
}
|
||||
.icon-indent-left {
|
||||
background-position: -384px -48px;
|
||||
}
|
||||
.icon-indent-right {
|
||||
background-position: -408px -48px;
|
||||
}
|
||||
.icon-facetime-video {
|
||||
background-position: -432px -48px;
|
||||
}
|
||||
.icon-picture {
|
||||
background-position: -456px -48px;
|
||||
}
|
||||
.icon-pencil {
|
||||
background-position: 0 -72px;
|
||||
}
|
||||
.icon-map-marker {
|
||||
background-position: -24px -72px;
|
||||
}
|
||||
.icon-adjust {
|
||||
background-position: -48px -72px;
|
||||
}
|
||||
.icon-tint {
|
||||
background-position: -72px -72px;
|
||||
}
|
||||
.icon-edit {
|
||||
background-position: -96px -72px;
|
||||
}
|
||||
.icon-share {
|
||||
background-position: -120px -72px;
|
||||
}
|
||||
.icon-check {
|
||||
background-position: -144px -72px;
|
||||
}
|
||||
.icon-move {
|
||||
background-position: -168px -72px;
|
||||
}
|
||||
.icon-step-backward {
|
||||
background-position: -192px -72px;
|
||||
}
|
||||
.icon-fast-backward {
|
||||
background-position: -216px -72px;
|
||||
}
|
||||
.icon-backward {
|
||||
background-position: -240px -72px;
|
||||
}
|
||||
.icon-play {
|
||||
background-position: -264px -72px;
|
||||
}
|
||||
.icon-pause {
|
||||
background-position: -288px -72px;
|
||||
}
|
||||
.icon-stop {
|
||||
background-position: -312px -72px;
|
||||
}
|
||||
.icon-forward {
|
||||
background-position: -336px -72px;
|
||||
}
|
||||
.icon-fast-forward {
|
||||
background-position: -360px -72px;
|
||||
}
|
||||
.icon-step-forward {
|
||||
background-position: -384px -72px;
|
||||
}
|
||||
.icon-eject {
|
||||
background-position: -408px -72px;
|
||||
}
|
||||
.icon-chevron-left {
|
||||
background-position: -432px -72px;
|
||||
}
|
||||
.icon-chevron-right {
|
||||
background-position: -456px -72px;
|
||||
}
|
||||
.icon-plus-sign {
|
||||
background-position: 0 -96px;
|
||||
}
|
||||
.icon-minus-sign {
|
||||
background-position: -24px -96px;
|
||||
}
|
||||
.icon-remove-sign {
|
||||
background-position: -48px -96px;
|
||||
}
|
||||
.icon-ok-sign {
|
||||
background-position: -72px -96px;
|
||||
}
|
||||
.icon-question-sign {
|
||||
background-position: -96px -96px;
|
||||
}
|
||||
.icon-info-sign {
|
||||
background-position: -120px -96px;
|
||||
}
|
||||
.icon-screenshot {
|
||||
background-position: -144px -96px;
|
||||
}
|
||||
.icon-remove-circle {
|
||||
background-position: -168px -96px;
|
||||
}
|
||||
.icon-ok-circle {
|
||||
background-position: -192px -96px;
|
||||
}
|
||||
.icon-ban-circle {
|
||||
background-position: -216px -96px;
|
||||
}
|
||||
.icon-arrow-left {
|
||||
background-position: -240px -96px;
|
||||
}
|
||||
.icon-arrow-right {
|
||||
background-position: -264px -96px;
|
||||
}
|
||||
.icon-arrow-up {
|
||||
background-position: -289px -96px;
|
||||
}
|
||||
.icon-arrow-down {
|
||||
background-position: -312px -96px;
|
||||
}
|
||||
.icon-share-alt {
|
||||
background-position: -336px -96px;
|
||||
}
|
||||
.icon-resize-full {
|
||||
background-position: -360px -96px;
|
||||
}
|
||||
.icon-resize-small {
|
||||
background-position: -384px -96px;
|
||||
}
|
||||
.icon-plus {
|
||||
background-position: -408px -96px;
|
||||
}
|
||||
.icon-minus {
|
||||
background-position: -433px -96px;
|
||||
}
|
||||
.icon-asterisk {
|
||||
background-position: -456px -96px;
|
||||
}
|
||||
.icon-exclamation-sign {
|
||||
background-position: 0 -120px;
|
||||
}
|
||||
.icon-downtick {
|
||||
margin-left: 0;
|
||||
background-position: -24px -120px;
|
||||
}
|
||||
.icon-leaf {
|
||||
background-position: -48px -120px;
|
||||
}
|
||||
.icon-fire {
|
||||
background-position: -72px -120px;
|
||||
}
|
||||
.icon-eye-open {
|
||||
background-position: -96px -120px;
|
||||
}
|
||||
.icon-eye-close {
|
||||
background-position: -120px -120px;
|
||||
}
|
||||
.icon-warning-sign {
|
||||
background-position: -144px -120px;
|
||||
}
|
||||
.icon-plane {
|
||||
background-position: -168px -120px;
|
||||
}
|
||||
.icon-calendar {
|
||||
background-position: -192px -120px;
|
||||
}
|
||||
.icon-random {
|
||||
background-position: -216px -120px;
|
||||
}
|
||||
.icon-comment {
|
||||
background-position: -240px -120px;
|
||||
}
|
||||
.icon-magnet {
|
||||
background-position: -264px -120px;
|
||||
}
|
||||
.icon-chevron-up {
|
||||
background-position: -288px -120px;
|
||||
}
|
||||
.icon-chevron-down {
|
||||
background-position: -313px -119px;
|
||||
}
|
||||
.icon-retweet {
|
||||
background-position: -336px -120px;
|
||||
}
|
||||
.icon-shopping-cart {
|
||||
background-position: -360px -120px;
|
||||
}
|
||||
.icon-folder-close {
|
||||
background-position: -384px -120px;
|
||||
}
|
||||
.icon-folder-open {
|
||||
background-position: -408px -120px;
|
||||
}
|
||||
.icon-resize-vertical {
|
||||
background-position: -432px -119px;
|
||||
}
|
||||
.icon-resize-horizontal {
|
||||
background-position: -456px -118px;
|
||||
}
|
||||
.icon-hdd {
|
||||
background-position: 0 -144px;
|
||||
}
|
||||
.icon-bullhorn {
|
||||
background-position: -24px -144px;
|
||||
}
|
||||
.icon-bell {
|
||||
background-position: -48px -144px;
|
||||
}
|
||||
.icon-certificate {
|
||||
background-position: -72px -144px;
|
||||
}
|
||||
.icon-thumbs-up {
|
||||
background-position: -96px -144px;
|
||||
}
|
||||
.icon-thumbs-down {
|
||||
background-position: -120px -144px;
|
||||
}
|
||||
.icon-hand-right {
|
||||
background-position: -144px -144px;
|
||||
}
|
||||
.icon-hand-left {
|
||||
background-position: -168px -144px;
|
||||
}
|
||||
.icon-hand-up {
|
||||
background-position: -192px -144px;
|
||||
}
|
||||
.icon-hand-down {
|
||||
background-position: -216px -144px;
|
||||
}
|
||||
.icon-circle-arrow-right {
|
||||
background-position: -240px -144px;
|
||||
}
|
||||
.icon-circle-arrow-left {
|
||||
background-position: -264px -144px;
|
||||
}
|
||||
.icon-circle-arrow-up {
|
||||
background-position: -288px -144px;
|
||||
}
|
||||
.icon-circle-arrow-down {
|
||||
background-position: -312px -144px;
|
||||
}
|
||||
.icon-globe {
|
||||
background-position: -336px -144px;
|
||||
}
|
||||
.icon-wrench {
|
||||
background-position: -360px -144px;
|
||||
}
|
||||
.icon-tasks {
|
||||
background-position: -384px -144px;
|
||||
}
|
||||
.icon-filter {
|
||||
background-position: -408px -144px;
|
||||
}
|
||||
.icon-briefcase {
|
||||
background-position: -432px -144px;
|
||||
}
|
||||
.icon-fullscreen {
|
||||
background-position: -456px -144px;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*********************************************************
|
||||
* Base Styles
|
||||
*/
|
||||
|
||||
body {
|
||||
background: @baseStage;
|
||||
overflow: hidden;
|
||||
}
|
|
@ -0,0 +1,273 @@
|
|||
/* @override
|
||||
http://ocupopdev.com/popcorn-embed/css/controls.css */
|
||||
|
||||
.controls {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
border: 1px solid #d5d6d5;
|
||||
height: 41px;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.controls-hide {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#butter-controls {
|
||||
color: #F8FDE2;
|
||||
position: relative;
|
||||
height: 22px;
|
||||
width: 100%;
|
||||
display: block;
|
||||
background:white;
|
||||
}
|
||||
|
||||
/* Big Button */
|
||||
|
||||
#controls-big-play-button {
|
||||
display: none;
|
||||
width: 57px;
|
||||
height: 66px;
|
||||
background: url(../resources/controls/icon_play.png) no-repeat;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -33px;
|
||||
margin-left: -26px;
|
||||
z-index: 9999;
|
||||
cursor: pointer;
|
||||
}
|
||||
#controls-big-play-button.controls-ready {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#butter-controls.controls-active {
|
||||
/* active happens on mouse over and is reverted to default on mouse out */
|
||||
display: block;
|
||||
}
|
||||
|
||||
#butter-controls.controls-ready/*, #controls-big-play-button.controls-ready*/ {
|
||||
/* ready happens when the template is exported, and not while in the editor */
|
||||
/* remove this if you want the big play button and active to show controls */
|
||||
display: block;
|
||||
}
|
||||
|
||||
#controls-big-play-button.controls-ready {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.controls-left {
|
||||
height: 22px;
|
||||
position: absolute;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
.controls-middle {
|
||||
margin-top: 0;
|
||||
height: 41px;
|
||||
position: absolute;
|
||||
left: 185px;
|
||||
right: 215px;
|
||||
padding-right: 20px;
|
||||
border-right: 1px solid #d5d6d5;
|
||||
}
|
||||
|
||||
.controls-right {
|
||||
padding-top: 0;
|
||||
height: 41px;
|
||||
position: absolute;
|
||||
width: 108px;
|
||||
right: 45px;
|
||||
background: #f2f2f2;
|
||||
border-right: 1px solid #d5d6d5;
|
||||
border-left: 1px solid #d5d6d5;
|
||||
}
|
||||
|
||||
#controls-timebar {
|
||||
position: absolute;
|
||||
background: #e4e4e4;
|
||||
height: 15px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 12px;
|
||||
margin-right: 12px;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#controls-progressbar {
|
||||
height: 100%;
|
||||
background: #1eb771;
|
||||
position: absolute;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* Time */
|
||||
|
||||
.time {
|
||||
position: absolute;
|
||||
left: 43px;
|
||||
height: 27px;
|
||||
background: url(../resources/controls/controls_time_arrowL.gif) no-repeat left top, url(../resources/controls/controls_time_arrowR.gif) right top no-repeat;
|
||||
background-color: #f2f2f2;
|
||||
font-size: 12px;
|
||||
line-height: 1em;
|
||||
padding-top: 14px;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
color: #58595b;
|
||||
}
|
||||
|
||||
#controls-currenttime {
|
||||
color: #1eb771;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
left: auto;
|
||||
right: auto;
|
||||
font-size: 12px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
#controls-duration {
|
||||
left: auto;
|
||||
right: auto;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
|
||||
/* Volume */
|
||||
|
||||
#controls-volume-container {
|
||||
position: absolute;
|
||||
right: 165px;
|
||||
width: 38px;
|
||||
}
|
||||
|
||||
#controls-volume {
|
||||
position: absolute;
|
||||
background: #e4e4e4;
|
||||
height: 15px;
|
||||
left: 7px;
|
||||
right: 0;
|
||||
top: 12px;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#controls-volume-progressbar {
|
||||
height: 100%;
|
||||
background: #1eb771;
|
||||
position: absolute;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#controls-volume-scrubber {
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
background: #EEE;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#controls-volume-scrubber:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 15px;
|
||||
border-radius: 15px;
|
||||
background: #EEE;
|
||||
top: -2px;
|
||||
left: -5px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
#controls-play {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
background: #1eb771 url(../resources/controls/controls_icon_playPause.png) no-repeat;
|
||||
padding: 0;
|
||||
border-radius: 3px;
|
||||
margin-top: 7px;
|
||||
margin-left: 7px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#controls-mute {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-image: url(../resources/glyphicons-halflings.png);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
left: -8px;
|
||||
top: 12px;
|
||||
}
|
||||
|
||||
.controls-btn {
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.controls-playing {
|
||||
background-position: center -15px !important;
|
||||
}
|
||||
|
||||
.controls-paused {
|
||||
background-position: center 10px !important;
|
||||
|
||||
}
|
||||
|
||||
.controls-muted {
|
||||
background-position: -360px -24px;
|
||||
}
|
||||
|
||||
.controls-unmuted {
|
||||
background-position: -384px -24px;
|
||||
}
|
||||
|
||||
.controls-right div {
|
||||
background: #cecfcf url(../resources/controls/controls_icons.png) no-repeat;
|
||||
margin-top: 6px;
|
||||
margin-left: 6px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 3px;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.controls-right div:hover {
|
||||
background-color: #1eb771;
|
||||
}
|
||||
|
||||
#controls-share {
|
||||
background-position: -27px -2px;
|
||||
}
|
||||
|
||||
#controls-remix {
|
||||
background-position: -61px -2px;
|
||||
}
|
||||
|
||||
#controls-fullscreen {
|
||||
background-position: 7px -2px;
|
||||
}
|
||||
|
||||
#controls-logo {
|
||||
width: 45px;
|
||||
height: 42px;
|
||||
background: url(../resources/controls/controls_icons.png) no-repeat -85px 2px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
cursor: pointer;
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
/*********************************************************
|
||||
* DIALOGS
|
||||
*/
|
||||
|
||||
@_overlayOpacity: 0.75; // How dark is the overlay?
|
||||
@_dialogWidth: 600px; // Width of dialog
|
||||
@_dialogPadding: 25px; // Inner padding
|
||||
@_dialogTopMargin: 100px; // How far should the dialog be from the top of the window?
|
||||
|
||||
.butter-modal-overlay {
|
||||
z-index: @MODAL_Z_INDEX;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
&.fade-in {
|
||||
opacity: 1;
|
||||
.transition( opacity 0.3s );
|
||||
}
|
||||
&.butter-modal-overlay-dark-bg {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba( 0, 0, 0, @_overlayOpacity );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.butter-dialog {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
color: @baseText;
|
||||
position: relative;
|
||||
width: @_dialogWidth;
|
||||
padding: @_dialogPadding;
|
||||
margin: @_dialogTopMargin auto;
|
||||
background: #FFF;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 10px 10px -10px #000;
|
||||
.box-sizing( border-box );
|
||||
|
||||
&.small {
|
||||
width: 330px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-dialog-title {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.butter-form {
|
||||
margin-bottom: 10px;
|
||||
textarea {
|
||||
padding: 10px;
|
||||
min-height: 150px;
|
||||
}
|
||||
}
|
||||
.butter-dialog-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.butter-feedback-form {
|
||||
padding: 0;
|
||||
background: lighten( #EEE, 3% );
|
||||
font-size: 13px;
|
||||
.butter-dialog-title {
|
||||
border-bottom: 1px solid #CCC;
|
||||
.gradient( "vertical", #FFF, #EEE );
|
||||
box-shadow: 0 1px #FFF;
|
||||
border-radius: 3px 3px 0 0;
|
||||
padding: 10px 35px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
margin: 0;
|
||||
.icon-info-sign {
|
||||
opacity: 0.2;
|
||||
margin: 3px 0 0 3px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
p {
|
||||
font-weight: normal;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
.butter-logo {
|
||||
position: absolute;
|
||||
top: -35px;
|
||||
left: -25px;
|
||||
width: 50px;
|
||||
}
|
||||
.butter-form {
|
||||
padding: 8px 0;
|
||||
label {
|
||||
position: relative;
|
||||
padding-left: 60px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
textarea {
|
||||
font-size: 11px;
|
||||
font-family: menlo, mono;
|
||||
box-shadow: 0 1px 0 #FFF;
|
||||
&:focus {
|
||||
box-shadow: inset 0 2px 4px -2px #CCC,
|
||||
0 1px 0 #FFF;
|
||||
border-color: #AAA;
|
||||
.transition( all 0.5s ease );
|
||||
}
|
||||
}
|
||||
}
|
||||
strong {
|
||||
color: @red;
|
||||
}
|
||||
.butter-btn {
|
||||
font-weight: 700;
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ticket-icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
background: url( "/resources/icons/ticket.png" ) top center no-repeat;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* First-run
|
||||
*/
|
||||
|
||||
.first-run {
|
||||
.butter-editor-area {
|
||||
z-index: @MODAL_Z_INDEX + 1;
|
||||
}
|
||||
.butter-modal-container {
|
||||
position: relative;
|
||||
z-index: @MODAL_Z_INDEX + 1;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-first-run-dialog {
|
||||
position: fixed;
|
||||
right: 360px;
|
||||
top: 80px;
|
||||
-moz-animation: bounce 1s infinite;
|
||||
-webkit-animation: bounce 1s infinite;
|
||||
-o-animation: bounce 1s infinite;
|
||||
animation: bounce 1s infinite;
|
||||
|
||||
.butter-logo {
|
||||
top: -15px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.triangle( "right", 20px, @baseLight, 1px, #CCC );
|
||||
|
||||
.butter-dialog-title {
|
||||
padding: 10px 0 10px 50px;
|
||||
}
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.overlay-highlight {
|
||||
z-index: @MODAL_Z_INDEX + 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.butter-tooltip.tooltip-popup,
|
||||
.butter-tooltip.tooltip-media {
|
||||
background: #F8EDAB;
|
||||
h3 {
|
||||
margin: 0 0 5px 0;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&:after {
|
||||
border-bottom-color: #F8EDAB;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-tooltip.tooltip-popup {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.butter-tooltip.tooltip-media {
|
||||
width: 150px;
|
||||
margin-left: -75px;
|
||||
.center-div {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes bounce {
|
||||
0% { right: 360px; }
|
||||
50% { right: 345px; }
|
||||
100% { right: 360px; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes bounce {
|
||||
0% { right: 360px; }
|
||||
50% { right: 345px; }
|
||||
100% { right: 360px; }
|
||||
}
|
||||
|
||||
@-o-keyframes bounce {
|
||||
0% { right: 360px; }
|
||||
50% { right: 345px; }
|
||||
100% { right: 360px; }
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0% { right: 360px; }
|
||||
50% { right: 345px; }
|
||||
100% { right: 360px; }
|
||||
}
|
|
@ -0,0 +1,567 @@
|
|||
/*********************************************************
|
||||
* EDITORS
|
||||
*/
|
||||
@_editorHeaderHeight: 45px;
|
||||
@_editorHeaderBorder: 5px;
|
||||
@_editorTitle: 50px;
|
||||
@_editorTabs: 30px;
|
||||
@_editorScrollbarWidth: 15px;
|
||||
|
||||
/*********************************************************
|
||||
* Editor Header
|
||||
*/
|
||||
|
||||
.butter-editor-header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: -1px;
|
||||
border-bottom: @_editorHeaderBorder solid @green;
|
||||
height: @_editorHeaderHeight;
|
||||
background: @baseDark;
|
||||
|
||||
> ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
.clearfix();
|
||||
|
||||
> li {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
} // .butter-editor-header
|
||||
|
||||
.butter-editor-header .butter-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #FFF;
|
||||
font-size: 14px;
|
||||
padding: 0 10px;
|
||||
border-radius: 0;
|
||||
height: @_editorHeaderHeight;
|
||||
line-height: @_editorHeaderHeight;
|
||||
>.icon {
|
||||
margin-top: 1px;
|
||||
margin-left: 0;
|
||||
margin-right: 2px;
|
||||
}
|
||||
&.butter-active {
|
||||
background: @green;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-editor-close-btn {
|
||||
position: fixed;
|
||||
top: @HEADER_SPACING;
|
||||
right: 0;
|
||||
z-index: @HEADER_Z_INDEX + 1;
|
||||
&.toggled .icon {
|
||||
background-image: url("../resources/glyphicons-halflings.png");
|
||||
background-position: -432px -72px; /* from icon-chevron-right */
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Main Editor Area
|
||||
*/
|
||||
|
||||
.butter-editor-area {
|
||||
|
||||
position: fixed;
|
||||
z-index: @EDITOR_Z_INDEX;
|
||||
top: @HEADER_SPACING;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: @EDITOR_WIDTH;
|
||||
background: @baseLight;
|
||||
.transition( right 0.35s );
|
||||
border-left: 1px solid @baseLightOutline;
|
||||
|
||||
&.minimized {
|
||||
right: -@EDITOR_WIDTH - 2;
|
||||
}
|
||||
|
||||
// Tabs, breadcrumbs
|
||||
.butter-editor {
|
||||
color: @baseText;
|
||||
font-size: 13px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
.butter-editor-tabs {
|
||||
padding: 0 20px;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
height: @_editorTabs;
|
||||
> li {
|
||||
float: left;
|
||||
margin-right: 3px;
|
||||
margin-top: -1px;
|
||||
|
||||
a:hover {
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
.butter-btn {
|
||||
background: lighten( @baseLightOutline, 10% );
|
||||
border-radius: 0;
|
||||
border: 1px solid @baseLightOutline;
|
||||
&.butter-active {
|
||||
background: #FFF;
|
||||
border-top-color: #FFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1, .butter-breadcrumbs { // Breadcrumbs
|
||||
color: @green;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
text-transform: capitalize;
|
||||
height: @_editorTitle;
|
||||
line-height: @_editorTitle;
|
||||
margin: 0;
|
||||
padding: 0 20px;
|
||||
background: #FFF;
|
||||
border-bottom: 1px solid @baseLightOutline;
|
||||
.box-sizing( border-box );
|
||||
.butter-breadcrumbs-back {
|
||||
opacity: 0.6;
|
||||
position: relative;
|
||||
padding-right: 15px;
|
||||
margin-right: 15px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
border-right: 1px solid @baseLightOutline;
|
||||
.triangle( "right", 5px, #FFF, 1px, @baseLightOutline );
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.close-btn {
|
||||
position: relative;
|
||||
float: right;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
line-height: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Tabs
|
||||
.editor-tabs {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
border-radius: 5px;
|
||||
|
||||
> button {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// States
|
||||
|
||||
.display-off {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.butter-editor-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
// Errors
|
||||
.error-message-container {
|
||||
.transition( height 0.35s, margin 0.35s, padding 0.35s );
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
color: #D93B21;
|
||||
visibility: hidden;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.error-message-container.open {
|
||||
padding: 10px 20px;
|
||||
padding-right: 15px; //scrollbars
|
||||
background: #F0DDDD;
|
||||
}
|
||||
|
||||
// Spacing
|
||||
.butter-editor-spacing {
|
||||
padding-right: @EDITOR_WIDTH;
|
||||
}
|
||||
|
||||
.butter-editor-spacing.editor-minimized {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.butter-editor-content {
|
||||
position: absolute;
|
||||
top: @_editorHeaderHeight + @_editorHeaderBorder;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.butter-editor-body {
|
||||
position: absolute;
|
||||
top: @_editorTitle;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.butter-editor-body.butter-tabs-spacing {
|
||||
top: @_editorTitle + @_editorTabs;
|
||||
}
|
||||
|
||||
// Scrollbars
|
||||
.scrollbar-outer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: @_editorScrollbarWidth;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.allow-scrollbar {
|
||||
.butter-scroll-bar.butter-scroll-bar-v {
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
width: 10px;
|
||||
bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
} //editor area
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Editor UI styles
|
||||
*/
|
||||
|
||||
@_editorInnerWidth: 286px;
|
||||
@_editorTextIndent: 40px;
|
||||
@_editorInputHeight: 32px;
|
||||
|
||||
.butter-form {
|
||||
|
||||
// Container building blocks
|
||||
.trackevent-property,
|
||||
.trackevent-warning,
|
||||
fieldset {
|
||||
border: none;
|
||||
margin: 10px 20px;
|
||||
padding: 0;
|
||||
.clearfix();
|
||||
}
|
||||
|
||||
.trackevent-warning {
|
||||
background: darken( @baseLight, 10% );
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
// Label
|
||||
label.property-name,
|
||||
label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.editor-section-header {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
// Inputs
|
||||
select,
|
||||
input,
|
||||
textarea {
|
||||
height: @_editorInputHeight;
|
||||
width: 100%;
|
||||
padding: 6px;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid @baseLightOutline;
|
||||
border-top-color: darken( @baseLightOutline, 10% );
|
||||
border-radius: 2px;
|
||||
.box-sizing( border-box );
|
||||
&:-moz-placeholder {
|
||||
color: #AAA;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: 1px solid @green;
|
||||
.transition( border 0.25s ease );
|
||||
}
|
||||
}
|
||||
|
||||
// Textareas
|
||||
textarea {
|
||||
height: 100px;
|
||||
line-height: 1.3;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
// Radios
|
||||
.butter-form-radio,
|
||||
.butter-form-checkbox {
|
||||
line-height: 1.3em;
|
||||
padding-left: @_editorTextIndent;
|
||||
padding-top: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
float: left;
|
||||
vertical-align: text-top;
|
||||
width: 12px;
|
||||
height: 13px;
|
||||
margin-left: -@_editorTextIndent + 2;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
|
||||
input[type="checkbox"] {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
// Error/Invalid
|
||||
input:invalid,
|
||||
textarea:invalid,
|
||||
input:invalid + .butter-unit {
|
||||
border-color: @red;
|
||||
}
|
||||
|
||||
|
||||
// Units
|
||||
.butter-form-append {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
.clearfix();
|
||||
>input {
|
||||
height: @_editorInputHeight;
|
||||
float: left;
|
||||
border-radius: 2px 0 0 2px;
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-unit {
|
||||
height: @_editorInputHeight - 2;
|
||||
position: absolute;
|
||||
right: -2px;
|
||||
bottom: 5px;
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
font-size: 10px;
|
||||
line-height: @_editorInputHeight;
|
||||
padding: 0 5px;
|
||||
min-width: 16px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
background-color: @baseLight;
|
||||
color: #777;
|
||||
border: 1px solid @baseLightOutline;
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
// Inline form styles
|
||||
|
||||
.butter-form-inline.form-single {
|
||||
.clearfix();
|
||||
label {
|
||||
.box-sizing( border-box );
|
||||
width: 80px;
|
||||
float: left;
|
||||
padding: 0;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
> input, textarea, select {
|
||||
float: left;
|
||||
margin-left: 5px;
|
||||
width: @_editorInnerWidth - 85;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-form-inline.form-half{
|
||||
.butter-form-radio,
|
||||
.butter-form-checkbox {
|
||||
.box-sizing( border-box );
|
||||
width: @_editorInnerWidth / 2;
|
||||
float: left;
|
||||
}
|
||||
> input,
|
||||
> select,
|
||||
.butter-form-append {
|
||||
&:last-child {
|
||||
margin-left: 10px;
|
||||
}
|
||||
position: relative;
|
||||
width: @_editorInnerWidth / 2 - 10;
|
||||
float: left;
|
||||
> input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code, pre {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
} // Fieldset
|
||||
|
||||
/*********************************************************
|
||||
* Scrollbars
|
||||
*/
|
||||
|
||||
.butter-scroll-bar {
|
||||
position: absolute;
|
||||
background: darken( @baseLight, 30% );
|
||||
box-shadow: 0 0 1px rgba( 0, 0, 0, 0.3 );
|
||||
border-radius: 15px;
|
||||
.selectable( none );
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.butter-scroll-handle {
|
||||
height: 8px;
|
||||
top: 1px;
|
||||
position: absolute;
|
||||
background: darken( @baseLight, 10% );
|
||||
border-radius: 15px;
|
||||
&:hover,
|
||||
&.butter-scollbar-active {
|
||||
background: darken( @baseLight, 50% );
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-scroll-bar-v {
|
||||
.butter-scroll-handle {
|
||||
width: 8px;
|
||||
left: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Tooltip
|
||||
*/
|
||||
|
||||
* {
|
||||
&:hover > .butter-tooltip:not(.tooltip-no-hover) {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
.transition( opacity 0.3s ease 0.5s );
|
||||
}
|
||||
}
|
||||
|
||||
.butter-tooltip {
|
||||
@_tooltipWidth: 110px;
|
||||
&.tooltip-on {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
.transition( opacity 0.3s ease 0.5s );
|
||||
}
|
||||
&.tooltip-no-transition-on {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
&.tooltip-error {
|
||||
color: red;
|
||||
}
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-top: -7px;
|
||||
margin-left: -@_tooltipWidth / 2;
|
||||
z-index: @MODAL_Z_INDEX;
|
||||
width: @_tooltipWidth;
|
||||
padding: 10px;
|
||||
background: #FFF;
|
||||
text-shadow: none;
|
||||
color: #555;
|
||||
line-height: 15px;
|
||||
font-size: 11px;
|
||||
.box-sizing( border-box );
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
border: 1px solid #CCC;
|
||||
box-shadow: 0 5px 6px -5px rgba( 0, 0, 0, .3 );
|
||||
pointer-events: none; /* csslint-ignore: better for browsers that support it, not critical for those that don't */
|
||||
.transition( opacity 0.3s ease 0 );
|
||||
|
||||
&:after,
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-bottom: 5px solid #FFF;
|
||||
}
|
||||
&:after {
|
||||
z-index: @MODAL_Z_INDEX + 1;
|
||||
}
|
||||
&:before {
|
||||
top: -6px;
|
||||
border-bottom: 5px solid #CCC;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-no-top-margin {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Draggable/Resizable
|
||||
*/
|
||||
|
||||
.editor-disable-pointer-events {
|
||||
pointer-events: none; /* csslint-ignore: better for browsers that support it, not critical for those that don't */
|
||||
}
|
||||
|
||||
.editor-drag-handle {
|
||||
-webkit-transition: opacity .3s ease;
|
||||
-moz-transition: opacity .3s ease;
|
||||
-ms-transition: opacity .3s ease;
|
||||
-o-transition: opacity .3s ease;
|
||||
transition: opacity .3s ease;
|
||||
|
||||
opacity: 0.4;
|
||||
z-index: 5000;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
@controlsHeight: 43px;
|
||||
@small: 560px;
|
||||
@medium: 640px;
|
||||
@large: 853px;
|
||||
@xlarge: 1280px;
|
||||
|
||||
.height-width( @width ) {
|
||||
width: @width;
|
||||
height: (.5625 * @width ) + @controlsHeight;
|
||||
}
|
||||
|
||||
iframe {
|
||||
display: block;
|
||||
margin: 60px auto;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and ( max-width: @medium ) {
|
||||
iframe {
|
||||
.height-width( @small );
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and ( min-width: @medium ) {
|
||||
iframe {
|
||||
.height-width( @medium );
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and ( min-width: @large ) {
|
||||
iframe {
|
||||
.height-width( @large );
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and ( min-width: @xlarge ) {
|
||||
iframe {
|
||||
.height-width( @xlarge );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,813 @@
|
|||
// GLOBALS
|
||||
.transition(@transition1) {
|
||||
-webkit-transition: @transition1;
|
||||
-moz-transition: @transition1;
|
||||
-o-transition: @transition1;
|
||||
-ms-transition: @transition1;
|
||||
transition: @transition1;
|
||||
}
|
||||
|
||||
@creditsLogoSize: 25px;
|
||||
@creditsZindex: 100000000000000;
|
||||
@red: #CB3E21;
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: #F8FDE2;
|
||||
font-weight: 300;
|
||||
font-size: 14px;
|
||||
font-family: "Helvetica Neue", sans-serif;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
#controls-big-play-button {
|
||||
width: 57px;
|
||||
height: 66px;
|
||||
background: url( "../resources/controls/icon_play.png" ) no-repeat;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -33px;
|
||||
margin-left: -26px;
|
||||
z-index: 9999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.embed {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-bottom: 56.25%;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.video > div video,
|
||||
.video > div iframe,
|
||||
.video > object,
|
||||
.embed-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.embed-overlay {
|
||||
background: rgba( 255, 255, 255, 0.95 );
|
||||
color: #676867;
|
||||
}
|
||||
|
||||
.embed-nav {
|
||||
@_embedIconsSize: 50px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
> li {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
> a {
|
||||
display: block;
|
||||
padding-top: @_embedIconsSize;
|
||||
width: @_embedIconsSize;
|
||||
text-decoration: none;
|
||||
color: #EEE;
|
||||
text-align: center;
|
||||
opacity: 0.7;
|
||||
.transition( opacity .3s ease);
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Credits
|
||||
*/
|
||||
|
||||
.attribution-info {
|
||||
font-family: "Meta", "Open Sans", "Helvetica Neue", sans-serif;
|
||||
z-index: @creditsZindex;
|
||||
}
|
||||
|
||||
.attribution-logo {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
width: @creditsLogoSize;
|
||||
height: @creditsLogoSize;
|
||||
border-radius: @creditsLogoSize;
|
||||
text-align: center;
|
||||
background-color: @red;
|
||||
color: #FFF;
|
||||
z-index: 1;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
.transition( all 0.1s ease );
|
||||
&:before {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
font-size: 30px;
|
||||
font-family: Georgia, serif;
|
||||
content: '\0201c';
|
||||
}
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
.attribution-text {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
// "Credits"
|
||||
.attribution-text {
|
||||
position: absolute;
|
||||
height: @creditsLogoSize;
|
||||
line-height: @creditsLogoSize;
|
||||
left: @creditsLogoSize + 6;
|
||||
visibility: hidden;
|
||||
text-shadow: 0 0 5px rgba( 0, 0, 0, 0.3 );
|
||||
.transition( all 0.1s ease );
|
||||
}
|
||||
|
||||
@media only screen and ( min-width: @large ) {
|
||||
.attribution-logo {
|
||||
width: @creditsLogoSize + 5;
|
||||
height: @creditsLogoSize + 5;
|
||||
border-radius: @creditsLogoSize + 5;
|
||||
&:before { font-size: 40px; }
|
||||
}
|
||||
.attribution-text {
|
||||
left: @creditsLogoSize + 14;
|
||||
line-height: @creditsLogoSize + 5;
|
||||
}
|
||||
}
|
||||
|
||||
.attribution-details {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-left: 3.5em;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
background: rgba( 255, 255, 255, 0.9 );
|
||||
color: black;
|
||||
border-bottom: 1px solid rgba( 0, 0, 0, 0.2 );
|
||||
font-size: 16px;
|
||||
.transition( opacity .1s ease );
|
||||
}
|
||||
// Adjust font size for other sizes
|
||||
@media only screen and ( min-width: @medium ) {
|
||||
.attribution-details {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
@media only screen and ( min-width: @large ) {
|
||||
.attribution-details {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.attribution-mopop {
|
||||
color: @red;
|
||||
font-size: 0.9em;
|
||||
font-weight: 700;
|
||||
}
|
||||
.attribution-title {
|
||||
font-size: 1.3em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.attribution-author {
|
||||
font-style: italic;
|
||||
}
|
||||
.attribution-media {
|
||||
margin-top: 0.5em;
|
||||
font-size: 0.8em;
|
||||
&:before {
|
||||
display: block;
|
||||
float: left;
|
||||
content: "Media";
|
||||
text-transform: uppercase;
|
||||
font-size: 0.8em;
|
||||
font-weight: 700;
|
||||
margin-right: 2em;
|
||||
}
|
||||
.media-btn {
|
||||
float: left;
|
||||
}
|
||||
.attribution-media-src {
|
||||
float: left;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
color: #555;
|
||||
max-width: 70%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
// The x in the top right corner
|
||||
.attribution-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 8px;
|
||||
font-weight: 700;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CREDITS STATES
|
||||
|
||||
// State: default
|
||||
// hide credits panel
|
||||
.attribution-details {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
// State: attribution-on
|
||||
// when the logo is clicked, show the credits
|
||||
.attribution-on {
|
||||
.attribution-logo {
|
||||
opacity: 1;
|
||||
.attribution-text {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
.attribution-details {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Icons for credits
|
||||
*/
|
||||
|
||||
.media-icon {
|
||||
position: relative;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 2px;
|
||||
background: url( "../resources/media-icons.png" ) no-repeat;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
&.html5-icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
&.youtube-icon {
|
||||
background-position: -16px 0;
|
||||
}
|
||||
&.vimeo-icon {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
&.soundcloud-icon {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.attribution-close {
|
||||
background-image: url("../resources/glyphicons-halflings-alt.png");
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-position: -432px -24px;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
SHARED STYLES BETWEEN POSTROLL AND SHARE STATES */
|
||||
|
||||
#post-roll,
|
||||
#share {
|
||||
font-family: "Meta", "Open Sans", "Helvetica Neue", sans-serif;
|
||||
text-shadow: 1px 1px 0 rgba( 255, 255, 255, 0.4 );
|
||||
font-size: 1.5em;
|
||||
line-height: 1.4em;
|
||||
color: #676867;
|
||||
|
||||
a {
|
||||
color: #676867;
|
||||
}
|
||||
|
||||
.post-roll-inner, .share-inner {
|
||||
position: relative;
|
||||
padding: 10%;
|
||||
font-family: "Meta", "Open Sans", "Helvetica Neue", sans-serif;
|
||||
text-shadow: 1px 1px 0 rgba( 255, 255, 255, 0.4 );
|
||||
}
|
||||
|
||||
.embed-project,
|
||||
.share-options {
|
||||
margin-left: 30%;
|
||||
margin-top: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.mozpopcorn {
|
||||
color: #D53B2A;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.embed-logo {
|
||||
float: left;
|
||||
background: url( "../resources/controls/postroll_logo.png" ) 0 0 no-repeat;
|
||||
width: 30%;
|
||||
background-size: 100%;
|
||||
max-width: 231px;
|
||||
height: 388px;
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
margin-top: -5%;
|
||||
}
|
||||
|
||||
.embed-title {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: #676867;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.embed-author {
|
||||
margin-bottom: 1em;
|
||||
color: #676867;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* POST ROLL
|
||||
*/
|
||||
|
||||
|
||||
#post-roll {
|
||||
|
||||
.post-roll-description {
|
||||
color: #676867;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.embed-nav > li > a {
|
||||
background: rgba( 0, 0, 0, 0.3 ) url( "../resources/controls/controls_icons.png" ) no-repeat;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
border-radius: 7px;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
}
|
||||
|
||||
.embed-nav > li > a span {
|
||||
color: #676867;
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#replay-post {
|
||||
background-position: 9px -28px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#replay-post:hover {
|
||||
background-color: #2BB673;
|
||||
}
|
||||
|
||||
#remix-post {
|
||||
background-position: 9px -78px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#remix-post:hover {
|
||||
background-color: #002839;
|
||||
}
|
||||
|
||||
#share-post {
|
||||
background-position: 9px -123px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#share-post:hover {
|
||||
background-color: #D53B2A;
|
||||
}
|
||||
|
||||
} // post-roll
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* SHARE
|
||||
*/
|
||||
|
||||
#share {
|
||||
|
||||
.embed-nav {
|
||||
@_shareIconsSize: 80px;
|
||||
|
||||
> li {
|
||||
width: @_shareIconsSize;
|
||||
height: @_shareIconsSize / 2;
|
||||
}
|
||||
}
|
||||
|
||||
#share-close {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
font-size: 16px;
|
||||
text-decoration: none;
|
||||
background: rgba( 0, 0, 0, 0.3 );
|
||||
text-shadow: 1px 1px 0 rgba( 0, 0, 0, 0.2 );
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding-top: 6px;
|
||||
line-height: 1em;
|
||||
width: 28px;
|
||||
height: 23px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#share-close:hover {
|
||||
background: #1eb771;
|
||||
}
|
||||
|
||||
.share-options input,
|
||||
.share-options textarea {
|
||||
font-size: 12px;
|
||||
resize: none;
|
||||
width: 70%;
|
||||
padding: 10px;
|
||||
float: left;
|
||||
border-radius: 2px;
|
||||
background: white;
|
||||
border: 1px solid #d5d6d5;
|
||||
&:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 1px #2BB673;
|
||||
}
|
||||
}
|
||||
|
||||
.share-options textarea {
|
||||
height: 90px;
|
||||
font-family: menlo, monospace;
|
||||
}
|
||||
|
||||
.share-options fieldset {
|
||||
border: none;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.share-options label {
|
||||
display: block;
|
||||
padding-bottom: 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.share-buttons {
|
||||
float: left;
|
||||
margin: 0;
|
||||
margin-left: 20px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.share-buttons > li > a {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.share-size {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
line-height: 1em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.size-options {
|
||||
background: #ababab;
|
||||
border-radius: 5px;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
width: 113px;
|
||||
|
||||
a {
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
text-shadow: 1px 1px 0 rgba( 0, 0, 0, 0.2 );
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid rgba( 255, 255, 255, 0.3 );
|
||||
padding: 3px 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
a:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background:#1EB771;
|
||||
}
|
||||
|
||||
a.current {
|
||||
display: block;
|
||||
background: url( "../resources/controls/embed_size_sprite.png" ) no-repeat 90px 15px;
|
||||
}
|
||||
|
||||
a.current:hover {
|
||||
display: block;
|
||||
background: #1EB771;
|
||||
}
|
||||
|
||||
a:first-child:hover {
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
}
|
||||
|
||||
a:last-child:hover {
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
span.icon {
|
||||
background: url( "../resources/controls/embed_size_sprite.png" ) no-repeat;
|
||||
width: 36px;
|
||||
height: 29px;
|
||||
margin: 0 3px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
span.size{
|
||||
font-weight: bold;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
span.dimensions {
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
.small .icon {
|
||||
background-position: center -14px;
|
||||
}
|
||||
|
||||
.medium .icon {
|
||||
background-position: center -52px;
|
||||
}
|
||||
|
||||
.large .icon {
|
||||
background-position: center -91px;
|
||||
}
|
||||
|
||||
.xlarge .icon {
|
||||
background-position: center -131px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.size-options:hover a {
|
||||
display: block;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.size-options:hover a.current {
|
||||
background: url( "../resources/controls/embed_size_sprite.png" ) no-repeat 88px -162px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* MEDIA QUERIES
|
||||
*/
|
||||
|
||||
@small: 560px;
|
||||
@medium: 640px;
|
||||
@large: 853px;
|
||||
@xlarge: 1280px;
|
||||
|
||||
@media only screen and ( max-width: @large ) {
|
||||
|
||||
#post-roll, #share {
|
||||
|
||||
.embed-logo {
|
||||
width: 20%;
|
||||
background-size: 100%;
|
||||
margin-left: 10%;
|
||||
margin-top: 0;
|
||||
height: 255px;
|
||||
}
|
||||
|
||||
.embed-author {
|
||||
margin-bottom: 1em;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.post-roll-inner, .share-inner {
|
||||
left: 0;
|
||||
width: 80%;
|
||||
padding: 5%;
|
||||
top: 10%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#post-roll .post-roll-description {
|
||||
font-size: 16px;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
#share {
|
||||
|
||||
.share-options {
|
||||
|
||||
input {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
padding: 3px 0;
|
||||
min-width: 0;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 110px;
|
||||
width: 70%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 70%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
float: left;
|
||||
width: 20%;
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.share-size {
|
||||
float: none;
|
||||
margin-left: 97%;
|
||||
width: 100%;
|
||||
|
||||
.size-options {
|
||||
bottom: -35px;
|
||||
}
|
||||
}
|
||||
|
||||
.share-size label {
|
||||
float: left;
|
||||
width: 20%;
|
||||
padding-top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and ( max-width: @small ) {
|
||||
|
||||
#post-roll, #share {
|
||||
|
||||
font-size: 13px;
|
||||
|
||||
.embed-title {
|
||||
margin-bottom: 3px;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.mozpopcorn {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.embed-author {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.embed-logo {
|
||||
width: 20%;
|
||||
margin-left: 20px;
|
||||
margin-top: 0;
|
||||
height: 175px;
|
||||
}
|
||||
|
||||
.embed-project {
|
||||
margin-top: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.post-roll-inner, .share-inner {
|
||||
width: 90%;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.post-roll-description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#share {
|
||||
|
||||
.embed-logo {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.embed-project, .share-options {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.share-options {
|
||||
|
||||
fieldset {
|
||||
padding: 3px 0;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 90px;
|
||||
width: 70%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 70%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
float: left;
|
||||
width: 20%;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.share-size {
|
||||
float: none;
|
||||
width: 100%;
|
||||
margin-top: 115px;
|
||||
margin-left: 20%;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.embed-info {
|
||||
|
||||
.embed-logo-small {
|
||||
width: 63px;
|
||||
height: 63px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.mozpop {
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
.embed-title {
|
||||
font-size: 1.3em;
|
||||
|
||||
}
|
||||
|
||||
.embed-author {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.embed-details {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#play {
|
||||
width: 40px;
|
||||
background-size: 100%;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
// SPACING
|
||||
@WEBMAKERNAV_SPACING: 28px;
|
||||
@PRIMARYHEADER_SPACING: 62px;
|
||||
@HEADER_SPACING: @WEBMAKERNAV_SPACING + @PRIMARYHEADER_SPACING;
|
||||
@TRAY_HEIGHT: 220px;
|
||||
@TRAY_SPACING: @TRAY_HEIGHT - 10;
|
||||
@TRAY_SPACING_MINIMIZED: 35px;
|
||||
@TABZILLA_HEIGHT: 210px;
|
||||
|
||||
// Z INDEXES
|
||||
@BASE_Z_INDEX: 100000000;
|
||||
@HEADER_Z_INDEX: @BASE_Z_INDEX + 10;
|
||||
@TRAY_Z_INDEX: @BASE_Z_INDEX + 1;
|
||||
@EDITOR_Z_INDEX: @BASE_Z_INDEX + 1;
|
||||
@MODAL_Z_INDEX: @BASE_Z_INDEX + 100;
|
||||
|
||||
// EDITOR
|
||||
@EDITOR_WIDTH: 350px;
|
||||
|
||||
// COLORS
|
||||
@COLOR_SELECTION: #FEF49C;
|
||||
@baseDark: #052938;
|
||||
@baseLight: #F4F5F5;
|
||||
@baseStage: #E7EDF0;
|
||||
@green: #3FB58E;
|
||||
@greyGreen: #c2c6b3;
|
||||
@red: #CB3E21;
|
||||
@baseLightOutline: #CCC;
|
||||
@baseText: #555;
|
||||
@editorOutline: #CCC;
|
||||
@midGrey: #D9DDDD;
|
||||
@darkGrey: #3A3C3C;
|
||||
|
||||
// MIXINS
|
||||
.selectable(@param) {
|
||||
-webkit-touch-callout: @param;
|
||||
-webkit-user-select: @param;
|
||||
-moz-user-select: @param;
|
||||
-ms-user-select: @param;
|
||||
user-select: @param;
|
||||
}
|
||||
|
||||
// GRADIENTS
|
||||
// Usage:
|
||||
// .gradient( "vertical", red, blue ); -> Creates a gradient from top = red to bottom = blue.
|
||||
// .gradient( "horizonal", red, blue ); -> Creates a gradient from left = red to right = blue.
|
||||
// .gradient( "vertical", red, blue, true ); -> Creates a gradient with a solid-color fallback. This is
|
||||
// necessary for IE9 when the container has a border-radius of 2+
|
||||
|
||||
._gradient( @color1, @color2, @startLoc, @endLoc, @from, @to, @ieFallback: false, @ieGradientType: 0 ) when ( @ieFallback ) {
|
||||
// Internal mixin for generating gradients when there are rounded corners
|
||||
background: @color1;
|
||||
background: -webkit-gradient( linear, @startLoc, @endLoc, color-stop( @from, @color1 ), color-stop( @to, @color2 ) );
|
||||
background: -webkit-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: -moz-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: -ms-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: -o-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: linear-gradient( @startLoc, @color1 );
|
||||
}
|
||||
|
||||
._gradient( @color1, @color2, @startLoc, @endLoc, @from, @to, @ieFallback: false, @ieGradientType: 0 ) when not ( @ieFallback ) {
|
||||
// Internal mixin for generating gradients when there are no rounded corners
|
||||
filter: e( %( "progid:DXImageTransform.Microsoft.Gradient(startColorstr='%d', endColorstr='%d', GradientType=%d)", @color1, @color2, @ieGradientType ) );
|
||||
background: -webkit-gradient( linear, @startLoc, @endLoc, color-stop( @from, @color1 ), color-stop( @to, @color2 ) );
|
||||
background: -webkit-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: -moz-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: -ms-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: -o-linear-gradient( @startLoc, @color1 @from, @color2 @to );
|
||||
background: linear-gradient( @startLoc, @color1 );
|
||||
}
|
||||
|
||||
.gradient( "vertical", @color1, @color2, @fallback: false ) {
|
||||
._gradient( @color1, @color2, top, bottom, 0%, 100%, @fallback, 0 );
|
||||
}
|
||||
|
||||
.gradient( "horizontal", @color1, @color2, @fallback: false ) {
|
||||
._gradient( @color1, @color2, left, right, 0%, 100%, @fallback, 1 );
|
||||
}
|
||||
|
||||
.gradient( "center top", @color1, @color2, @fallback: false ) {
|
||||
._gradient( @color1, @color2, left, right, 0%, 100%, @fallback, 1 );
|
||||
}
|
||||
|
||||
.transition(@transition1) {
|
||||
-webkit-transition: @transition1;
|
||||
-moz-transition: @transition1;
|
||||
-o-transition: @transition1;
|
||||
-ms-transition: @transition1;
|
||||
transition: @transition1;
|
||||
}
|
||||
.transition(@transition1, @transition2) {
|
||||
-webkit-transition: @transition1, @transition2;
|
||||
-moz-transition: @transition1, @transition2;
|
||||
-o-transition: @transition1, @transition2;
|
||||
-ms-transition: @transition1, @transition2;
|
||||
transition: @transition1, @transition2;
|
||||
}
|
||||
.transition(@transition1, @transition2, @transition3) {
|
||||
-webkit-transition: @transition1, @transition2, @transition3;
|
||||
-moz-transition: @transition1, @transition2, @transition3;
|
||||
-o-transition: @transition1, @transition2, @transition3;
|
||||
-ms-transition: @transition1, @transition2, @transition3;
|
||||
transition: @transition1, @transition2, @transition3;
|
||||
}
|
||||
.animation( @animation ) {
|
||||
-webkit-animation: @animation;
|
||||
-moz-animation: @animation;
|
||||
-o-animation: @animation;
|
||||
-ms-animation: @animation;
|
||||
}
|
||||
.transform( @transformation ) {
|
||||
-webkit-transform: @transformation;
|
||||
-moz-transform: @transformation;
|
||||
-o-transform: @transformation;
|
||||
-ms-transform: @transformation;
|
||||
transform: @transformation;
|
||||
}
|
||||
.transform-origin( @transformation ) {
|
||||
-webkit-transform-origin: @transformation;
|
||||
-moz-transform-origin: @transformation;
|
||||
-o-transform-origin: @transformation;
|
||||
-ms-transform-origin: @transformation;
|
||||
transform-origin: @transformation;
|
||||
}
|
||||
|
||||
.transformAnimation(@startProperty, @endProperty) {
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: @startProperty;
|
||||
transform: @startProperty;
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: @endProperty;
|
||||
transform: @endProperty;
|
||||
}
|
||||
}
|
||||
@-moz-keyframes spin {
|
||||
0% {
|
||||
-moz-transform: @startProperty;
|
||||
transform: @startProperty;
|
||||
}
|
||||
100% {
|
||||
-moz-transform: @endProperty;
|
||||
transform: @endProperty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.boxOrient(@direction) {
|
||||
-webkit-box-orient: @direction;
|
||||
-moz-box-orient: @direction;
|
||||
-ms-box-orient: @direction;
|
||||
box-orient: @direction;
|
||||
}
|
||||
.boxAlign(@property) {
|
||||
-webkit-box-align: @property;
|
||||
-moz-box-align: @property;
|
||||
-ms-box-align: @property;
|
||||
box-align: @property;
|
||||
}
|
||||
.box-sizing( @property ) {
|
||||
// https://developer.mozilla.org/En/CSS/Box-sizing
|
||||
-webkit-box-sizing: @property; // Chrome 10-
|
||||
-moz-box-sizing: @property;
|
||||
-ms-box-sizing: @property; // IE 8+
|
||||
box-sizing: @property; // Opera, Safari 5.1+, Chrome 10+
|
||||
}
|
||||
|
||||
// *********************************************************
|
||||
// POSITIONING
|
||||
//
|
||||
|
||||
.clearfix() {
|
||||
*zoom: 1;
|
||||
&:before,
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
&:after { clear: both; }
|
||||
}
|
||||
|
||||
.triangle( "right", @size, @color, @borderSize, @borderColor ) {
|
||||
&:after, &:before {
|
||||
left: 100%;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none; /* csslint-ignore */
|
||||
}
|
||||
&:after {
|
||||
border-left-color: @color;
|
||||
border-width: @size;
|
||||
top: 50%;
|
||||
margin-top: -@size;
|
||||
}
|
||||
&:before {
|
||||
border-left-color: @borderColor;
|
||||
border-width: @size + @borderSize + 1;
|
||||
top: 50%;
|
||||
margin-top: -( @size + @borderSize + 1 );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*********************************************************
|
||||
* HEADER
|
||||
*/
|
||||
@_logoWidth: 180px;
|
||||
|
||||
// Used to position absolute elements in the middle of our header bar area
|
||||
@HEADER_ALIGN_MIDDLE: 2.7;
|
||||
|
||||
// Adds room to template to account for header
|
||||
.butter-header-spacing {
|
||||
padding-top: @HEADER_SPACING;
|
||||
}
|
||||
|
||||
.butter-editor-spacing.editor-minimized {
|
||||
.butter-header {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-header {
|
||||
z-index: @HEADER_Z_INDEX;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: @HEADER_SPACING;
|
||||
.transition( all .2s ease-in-out );
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Primary white nav bar
|
||||
*/
|
||||
|
||||
.butter-header-primary {
|
||||
position: relative;
|
||||
background: #FFF;
|
||||
color: lighten( @baseText, 10% );
|
||||
text-shadow: 0 1px 0 #FFF;
|
||||
font-size: 0.95em;
|
||||
border-bottom: 1px solid darken( @editorOutline, 10% );
|
||||
box-shadow: 0 -1px 10px 0 rgba( 0, 0, 0, 0.1 );
|
||||
.clearfix();
|
||||
}
|
||||
|
||||
.butter-logo {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 30px;
|
||||
height: 100px;
|
||||
width: @_logoWidth;
|
||||
background: url( "../resources/logo.png" ) no-repeat;
|
||||
}
|
||||
|
||||
.butter-nav {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-left: @_logoWidth + 50;
|
||||
list-style: none;
|
||||
height: @PRIMARYHEADER_SPACING;
|
||||
line-height: @PRIMARYHEADER_SPACING;
|
||||
> li {
|
||||
float: left;
|
||||
padding: 0 20px;
|
||||
&.butter-breadcrumbs {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin-right: 10px;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
border-right: 1px solid @baseLightOutline;
|
||||
.triangle( "right", 5px, #FFF, 1px, @baseLightOutline );
|
||||
}
|
||||
&.butter-project-title {
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: @green;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#tabzilla {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: @HEADER_Z_INDEX + 100;
|
||||
}
|
||||
|
||||
#tabzilla-panel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: @MODAL_Z_INDEX;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Buttons
|
||||
*/
|
||||
|
||||
.butter-header {
|
||||
.butter-btn {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-project-title > input {
|
||||
font-size: 14px;
|
||||
border: 1px solid @green;
|
||||
border-radius: 2px;
|
||||
padding: 5px;
|
||||
color: @green;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-project-title {
|
||||
max-width: 35%;
|
||||
min-width: 8%;
|
||||
height: 100%;
|
||||
|
||||
a {
|
||||
&.butter-project-name {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
opacity: 0.4;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
right: 0;
|
||||
top: @PRIMARYHEADER_SPACING / @HEADER_ALIGN_MIDDLE;
|
||||
}
|
||||
&:hover .icon {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-login-project-info {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.butter-login-project-info > ul {
|
||||
position: absolute;
|
||||
top: 48px;
|
||||
left: 28px;
|
||||
width: 175px;
|
||||
border-top: 0;
|
||||
border-radius: 0 0 2px 2px;
|
||||
box-shadow: 0 10px 15px -5px rgba( 0, 0, 0, 0.6 );
|
||||
padding: 0;
|
||||
background: #FFF;
|
||||
z-index: @MODAL_Z_INDEX;
|
||||
li {
|
||||
border-top: 1px solid @baseLight;
|
||||
list-style: none;
|
||||
font-size: 10px;
|
||||
line-height: 35px;
|
||||
margin: 0;
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
&:last-child {
|
||||
border-radius: 0 0 2px 2px;
|
||||
}
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: @baseText;
|
||||
display: block;
|
||||
padding: 0 20px;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: @green;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#main {
|
||||
min-width: 300px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.content-div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 3px solid #000;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#main, .content-div {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.container-div {
|
||||
float: left;
|
||||
text-align: center;
|
||||
font-family: helvetica;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
video {
|
||||
position: relative;
|
||||
top: 30px;
|
||||
}
|
||||
|
||||
#manual-test {
|
||||
clear: both;
|
||||
padding-top: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 5px;
|
||||
padding: 0.25em 0.75em 0.2em;
|
||||
display: inline-block;
|
||||
color: #000000;
|
||||
font-size: 1.142em;
|
||||
border: 0 none;
|
||||
border-radius: 0.2em 0.2em 0.2em 0.2em;
|
||||
box-shadow: 1px 1px rgba(0, 0, 0, 0.25);
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*********************************************************
|
||||
* MEDIA EDITOR
|
||||
*/
|
||||
|
||||
.media-editor {
|
||||
|
||||
.fl-right {
|
||||
margin-top: 8px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.media-editor-inner-wrapper { // Textarea wrappers
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-bottom: 5px;
|
||||
&:hover .delete-media-btn {
|
||||
right: 2px;
|
||||
}
|
||||
textarea {
|
||||
font-size: 12px;
|
||||
font-family: monaco, monospace;
|
||||
}
|
||||
}
|
||||
|
||||
.alt-media-wrapper {
|
||||
textarea {
|
||||
height: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
.alt-media-wrapper-inner {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.alternate-media-label { // When alternate media are displayed
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-top: 20px;
|
||||
&:hover {
|
||||
color: #000;
|
||||
}
|
||||
>.icon-x {
|
||||
float: right;
|
||||
opacity: 0.5;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.alternates-hidden { // When alternate media are hidden
|
||||
.butter-btn-slide-out {
|
||||
float: left;
|
||||
}
|
||||
.alternate-media-label {
|
||||
font-size: 12px;
|
||||
float: right;
|
||||
margin: 0;
|
||||
>.icon-x {
|
||||
display: none;
|
||||
}
|
||||
&:after {
|
||||
content: "...";
|
||||
}
|
||||
}
|
||||
.alt-media-wrapper,
|
||||
.add-alternate-media-source-btn,
|
||||
.add-alternate-media-source-desc {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.delete-media-btn {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: -20px;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
.transition( right 0.2s ease );
|
||||
}
|
||||
|
||||
.error {
|
||||
border: 1px inset #ff0000;
|
||||
}
|
||||
|
||||
.media-error-message {
|
||||
color: #ff0000;
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.media-loading-spinner {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
left: 10px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
display: inline-block;
|
||||
background-image: url("../resources/spinny.gif");
|
||||
&.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* NORMALIZATION
|
||||
* A lot of this is from normalize.css and HTML5 Boilerplate, docs for which can be found at h5bp.com/css
|
||||
*/
|
||||
|
||||
/*********************************************************
|
||||
* HTML5 display
|
||||
*/
|
||||
|
||||
// Corrects html5 display definitions in IE9
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
// Forces controls to display in modern browsers
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
// IE9 doesn't support the new HTML5 hidden attribute
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Links
|
||||
*/
|
||||
|
||||
// Addresses `outline` inconsistency between Chrome and other browsers.
|
||||
a:focus {
|
||||
outline: thin dotted;
|
||||
}
|
||||
|
||||
// Improves readability when focused and also mouse hovered in all browsers.
|
||||
// See people.opera.com/patrickl/experiments/keyboard/test
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Typography
|
||||
*/
|
||||
|
||||
// Prevent iOS text size adjust on device orientation change, without disabling user zoom: h5bp.com/g
|
||||
html {
|
||||
font-size: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
// Normalize fonts
|
||||
html,
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: "Open Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
hr {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
border-top: 1px solid #CCC;
|
||||
margin: 1em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Redeclare monospace font family: h5bp.com/j
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: "menlo", monospace, serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
// Improve readability of pre-formatted text
|
||||
pre {
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
// Superscripts and subscripts: h5bp.com/k;
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Selection
|
||||
*/
|
||||
|
||||
::-moz-selection {
|
||||
background: @COLOR_SELECTION;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: @COLOR_SELECTION;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Images
|
||||
*/
|
||||
|
||||
// Removes border when inside `a` element for IE9
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
// Corrects overflow displayed oddly in IE9.
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Margins not present in IE9
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Forms
|
||||
*/
|
||||
|
||||
// Normalize spacing
|
||||
fieldset {
|
||||
border: 1px solid #C0C0C0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
// Corrects color not being inherited in IE9
|
||||
legend {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// 1. Corrects font size not being inherited in all browsers.
|
||||
// 2. Addresses margins set differently in Chrome
|
||||
// 3. Improves appearance and consistency in all browsers.
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-size: 100%; //1
|
||||
margin: 0; //2
|
||||
vertical-align: baseline; //3
|
||||
}
|
||||
|
||||
|
||||
// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls.
|
||||
// 2. Corrects inability to style clickable `input` types in iOS.
|
||||
// 3. Improves usability and consistency of cursor style between image-type `input` and others.
|
||||
button,
|
||||
html input[type="button"], //1
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* csslint-ignore: (2) */
|
||||
cursor: pointer; //3
|
||||
}
|
||||
|
||||
// Reset default cursor for disabled elements.
|
||||
button[disabled],
|
||||
input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
// 1. Addresses box sizing set to content-box in IE9.
|
||||
// 2. Removes excess padding in IE9.
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; //1
|
||||
padding: 0; //2
|
||||
}
|
||||
|
||||
// 1. Addresses `appearance` set to `searchfield` in S5, Chrome.
|
||||
// 2. Addresses `box-sizing` set to `border-box` in S5, Chrome (include `-moz` to future-proof).
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* csslint-ignore: (1) */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; //2
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
// Removes inner padding and search cancel button in S5, Chrome on OS X.
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none; /* csslint-ignore */
|
||||
}
|
||||
|
||||
// 1. Removes default vertical scrollbar in IE9.
|
||||
// 2. Improves readability and alignment in all browsers.
|
||||
textarea {
|
||||
overflow: auto; //1
|
||||
vertical-align: top; //2
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Tables
|
||||
*/
|
||||
|
||||
// Remove most spacing between table cells.
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Iframes
|
||||
*/
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
//This is the list of plugins that appears after clickling the "Popcorn" Button
|
||||
.plugin-list-editor .plugin-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.butter-plugin-tile {
|
||||
text-transform: capitalize;
|
||||
position: relative;
|
||||
background: #FFF;
|
||||
box-shadow: 1px 5px 2px -3px rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #CCC;
|
||||
border-radius: 2px;
|
||||
border-top-color: #E3E3E3;
|
||||
border-bottom-color: #BDBDBD;
|
||||
color: #555;
|
||||
font-size: 13px;
|
||||
line-height: 24px;
|
||||
cursor: move;
|
||||
padding: 8px;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
left: -2px;
|
||||
top: -2px;
|
||||
box-shadow: 4px 4px 0 -2px rgba( 0, 0, 0, .3 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.butter-plugin-icon {
|
||||
background: url( "../resources/default-icon.png" ) center no-repeat;
|
||||
display: block;
|
||||
float: left;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
//This is the css for the editor that is opened when clicking the "Share" Button
|
||||
.butter-editor-area {
|
||||
.share-editor {
|
||||
|
||||
.sub-container {
|
||||
>p {
|
||||
padding-right: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fade-container {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.butter-project-author {
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
.butter-project-author-update {
|
||||
width: 66px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 20px;
|
||||
|
||||
>p {
|
||||
margin: 0 0 10px 5px;
|
||||
font-size: 14px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.big {
|
||||
font-size: 16.25px;
|
||||
}
|
||||
|
||||
>label {
|
||||
font-size: 13px;
|
||||
display: block;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
>textarea {
|
||||
min-height: 100px;
|
||||
line-height: 1.25;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
>div {
|
||||
text-transform: capitalize;
|
||||
position: relative;
|
||||
background: #FFF;
|
||||
box-shadow: inset 0 1px 0 0 white, inset 1px 0 0 0 white, inset -1px 0 0 0 white, inset 0 -1px 0 0 white, 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid #CCC;
|
||||
border-radius: 2px;
|
||||
border-top-color: #E3E3E3;
|
||||
border-bottom-color: #BDBDBD;
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
margin-right: 5px;
|
||||
line-height: 25px;
|
||||
cursor: move;
|
||||
padding: 10px;
|
||||
|
||||
&:hover {
|
||||
left: -2px;
|
||||
top: -2px;
|
||||
box-shadow: 4px 4px 0 -2px rgba( 0, 0, 0, .3 );
|
||||
}
|
||||
|
||||
}
|
||||
div {
|
||||
>span {
|
||||
&.icon {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-size: 30px;
|
||||
background-repeat: no-repeat;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
@_superScrollbarHeight: 32px;
|
||||
|
||||
#butter-super-scrollbar-outer-container {
|
||||
position: relative;
|
||||
left: -@_trackHandleWidth;
|
||||
|
||||
.butter-super-scrollbar-zoom-slider {
|
||||
position: absolute;
|
||||
width: 94px;
|
||||
height: 6px;
|
||||
z-index: 2;
|
||||
|
||||
> .butter-super-scrollbar-zoom-handle {
|
||||
top: -6px;
|
||||
position: absolute;
|
||||
height: 16px;
|
||||
width: 6px;
|
||||
left: 50%;
|
||||
line-height: 100%;
|
||||
cursor: pointer;
|
||||
background: #EEE;
|
||||
border: 1px solid #999;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-super-scrollbar-zoom-slider-container {
|
||||
position: absolute;
|
||||
background: #EEE;
|
||||
border: 1px solid #999;
|
||||
width: 100px;
|
||||
height: 6px;
|
||||
border-radius: 6px;
|
||||
left: 12px;
|
||||
top: 13px;
|
||||
z-index: 2;
|
||||
|
||||
> .tick {
|
||||
height: 6px;
|
||||
width: 1px;
|
||||
float: left;
|
||||
border-left: 1px solid #CCC;
|
||||
}
|
||||
> .tick:first-child {
|
||||
margin-left: 1px;
|
||||
}
|
||||
> .tick:nth-child( 2 ) {
|
||||
margin-left: 2px;
|
||||
}
|
||||
> .tick:nth-child( 3 ) {
|
||||
margin-left: 4px;
|
||||
}
|
||||
> .tick:nth-child( 4 ) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
> .tick:nth-child( 5 ) {
|
||||
margin-left: 16px;
|
||||
}
|
||||
> .tick:nth-child( 6 ) {
|
||||
margin-left: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#butter-super-scrollbar-inner-container {
|
||||
background: darken( @baseLight, 3% );
|
||||
height: @_superScrollbarHeight;
|
||||
position: absolute;
|
||||
left: @_trackHandleWidth;
|
||||
width: 100%;
|
||||
right: -7px;
|
||||
bottom: -@_superScrollbarHeight;
|
||||
border: 1px solid @baseLightOutline;
|
||||
margin-right: 5px;
|
||||
top: 0;
|
||||
box-shadow: inset 2px 0 5px -2px rgba( 0, 0, 0, 0.2 );
|
||||
}
|
||||
|
||||
#butter-super-scrollbar-visuals {
|
||||
margin-top: 7px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#butter-super-scrollbar-viewport {
|
||||
.gradient( "vertical", fade( #FFF, 65% ), fade( #FFF, 20% ), true );
|
||||
cursor: move;
|
||||
height: 28px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
min-width: 5px;
|
||||
&.viewport-transition {
|
||||
.transition( left 0.1s linear, right 0.1s linear );
|
||||
}
|
||||
&:before {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
bottom: -3px;
|
||||
left: -3px;
|
||||
display: block;
|
||||
border: 4px solid #FFF;
|
||||
z-index: 1;
|
||||
box-shadow: 0 2px 2px 0 rgba( 0, 0, 0, 0.2 ) inset, 0 0 0 1px @baseLightOutline;
|
||||
}
|
||||
}
|
||||
|
||||
.butter-super-scrollbar-trackevent {
|
||||
background: rgba( 0, 0, 0, 0.4 );
|
||||
height: 3px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.butter-super-scrollbar-handle {
|
||||
background: #41BB92;
|
||||
display: block;
|
||||
height: 18px;
|
||||
margin-top: -9px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 6px;
|
||||
border: 1px solid @green;
|
||||
box-shadow: 0 2px 3px -2px;
|
||||
z-index: 1;
|
||||
cursor: ew-resize;
|
||||
|
||||
&:before { // The little center grip on the handle
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
bottom: 2px;
|
||||
left: 2px;
|
||||
width: 2px;
|
||||
background: darken( @green, 10% );
|
||||
}
|
||||
|
||||
.butter-super-arrow { // The green arrows
|
||||
content: "";
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
background-image: url( "../resources/glyphicons-halflings-green.png" );
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
top: 2px;
|
||||
.transition( all 0.1s ease );
|
||||
}
|
||||
}
|
||||
|
||||
#butter-super-scrollbar-handle-left {
|
||||
left: -8px;
|
||||
.butter-super-arrow {
|
||||
left: 0;
|
||||
background-position: -240px -96px;
|
||||
}
|
||||
}
|
||||
|
||||
#butter-super-scrollbar-handle-right {
|
||||
right: -10px;
|
||||
.butter-super-arrow {
|
||||
right: 0;
|
||||
background-position: -264px -96px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Arrows - hover states
|
||||
// This allows the arrows to animate.
|
||||
#butter-super-scrollbar-viewport:hover {
|
||||
.butter-super-arrow {
|
||||
opacity: 0.5;
|
||||
}
|
||||
#butter-super-scrollbar-handle-left .butter-super-arrow {
|
||||
left: 10px;
|
||||
}
|
||||
#butter-super-scrollbar-handle-right .butter-super-arrow {
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
// Arrows - minimum size states
|
||||
// At 50px wide, force the arrows to the outside
|
||||
#butter-super-scrollbar-container.super-scrollbar-small:hover {
|
||||
#butter-super-scrollbar-handle-left .butter-super-arrow {
|
||||
left: -16px;
|
||||
}
|
||||
#butter-super-scrollbar-handle-right .butter-super-arrow {
|
||||
right: -16px;
|
||||
}
|
||||
}
|
||||
|
||||
// The little red scrubber
|
||||
#buter-super-scrollbar-scrubber {
|
||||
background: none repeat scroll 0 0 @red;
|
||||
bottom: 0;
|
||||
cursor: move;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 1px;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/* This Source Code Form is subject to the terms of the MIT license
|
||||
* If a copy of the MIT license was not distributed with this file, you can
|
||||
* obtain one at http://www.mozillapopcorn.org/butter-license.txt */
|
||||
/*
|
||||
*/
|
||||
@import "globals";
|
||||
|
||||
/*********************************************************
|
||||
* Base transition styles
|
||||
*/
|
||||
.transition-state( @property, @off, @on ) {
|
||||
.transition( @property 0.3s ease, visibility 0.3s ease );
|
||||
visibility: ~`"visible;\n @{property}: @{on}"`;
|
||||
&.off{
|
||||
visibility: ~`"hidden;\n @{property}: @{off} !important"`;
|
||||
}
|
||||
}
|
||||
|
||||
// Basic transitions
|
||||
.popcorn-fade {
|
||||
.transition-state( opacity, 0, 1 );
|
||||
}
|
||||
|
||||
.popcorn-none {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.popcorn-none.off {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.popcorn-slide-up {
|
||||
.transition-state( margin-top, 100%, 0 );
|
||||
}
|
||||
|
||||
.popcorn-slide-down {
|
||||
.transition-state( margin-top, -100%, 0 );
|
||||
}
|
||||
|
||||
.popcorn-pop {
|
||||
visibility: hidden;
|
||||
.transform( scale( 0, 0 ) );
|
||||
.transform-origin( center );
|
||||
}
|
||||
.popcorn-pop.on{
|
||||
visibility: visible;
|
||||
.transform( scale( 1, 1 ) );
|
||||
.animation( pop .2s 1 ease-out );
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Keyframe Animations
|
||||
*/
|
||||
|
||||
@-webkit-keyframes pop {
|
||||
0% {-webkit-transform: scale( 0, 0 ); transform: scale( 0, 0 ); }
|
||||
75% {-webkit-transform: scale( 1.6, 1.6 ); transform: scale( 1.6, 1.6 ); }
|
||||
100% {-webkit-transform: scale( 1, 1 ); transform: scale( 1, 1 ); }
|
||||
}
|
||||
@-moz-keyframes pop {
|
||||
0% {-moz-transform: scale( 0, 0 ); transform: scale( 0, 0 ); }
|
||||
75% {-moz-transform: scale( 1.6, 1.6 ); transform: scale( 1.6, 1.6 ); }
|
||||
100% {-moz-transform: scale( 1, 1); transform: scale( 1, 1 ); }
|
||||
}
|
||||
@-o-keyframes pop {
|
||||
0% {-o-transform: scale( 0, 0 ); transform: scale( 0, 0 ); }
|
||||
75% {-o-transform: scale( 1.6, 1.6 ); transform: scale( 1.6, 1.6 ); }
|
||||
100% {-o-transform: scale( 1, 1 ); transform: scale( 1.0, 1.0 ); }
|
||||
}
|
||||
@keyframes pop {
|
||||
0% {transform: scale( 0, 0 ); }
|
||||
75% {transform: scale( 1.6, 1.6 ); }
|
||||
100% {transform: scale( 1, 1 ); }
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/*********************************************************
|
||||
* TRAY STATUS
|
||||
*/
|
||||
@_butterStatusHeight: 45px;
|
||||
@_mediaStatusContainerHeight: @_butterStatusHeight;
|
||||
@_playButtonHeight: 26px;
|
||||
@_scrubberBarHeight: 8px;
|
||||
@_scrubberHandleHeight: 10px;
|
||||
@_traySideWidth: 129px;
|
||||
@_timebarRight: 27px;
|
||||
|
||||
/*********************************************************
|
||||
* Butter Status Area - The top bar in the tray
|
||||
*/
|
||||
|
||||
.butter-status-area {
|
||||
position: absolute;
|
||||
height: @_butterStatusHeight;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
.selectable( none );
|
||||
}
|
||||
|
||||
.media-status-container {
|
||||
position: relative;
|
||||
height: @_mediaStatusContainerHeight;
|
||||
background: #FFF;
|
||||
border-top: 1px solid @baseLightOutline;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Time bar - The horizontal line where the scrubber is
|
||||
*/
|
||||
|
||||
.time-bar {
|
||||
position: absolute;
|
||||
left: @_traySideWidth;
|
||||
top: ( @_mediaStatusContainerHeight - @_scrubberBarHeight ) / 2;
|
||||
right: @_timebarRight;
|
||||
height: ( @_mediaStatusContainerHeight / 2 ) + ( @_scrubberBarHeight / 2 );
|
||||
}
|
||||
|
||||
// Time ticks
|
||||
.time-bar-canvas-container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: @_scrubberBarHeight;
|
||||
height: ( @_mediaStatusContainerHeight / 2 ) - ( @_scrubberBarHeight / 2 );
|
||||
overflow: hidden;
|
||||
right: 0;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.time-bar-scrubber-container {
|
||||
background: fade( @baseDark, 20% );
|
||||
border-bottom: 1px solid #FFF;
|
||||
z-index: @TRAY_Z_INDEX + 10;
|
||||
border-radius: 15px;
|
||||
position: absolute;
|
||||
.selectable( none );
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
height: @_scrubberBarHeight;
|
||||
.fill-bar {
|
||||
background: @green;
|
||||
border-radius: 15px;
|
||||
height: @_scrubberBarHeight;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.time-bar-scrubber-line {
|
||||
position: absolute;
|
||||
top: @_scrubberHandleHeight + 3px;
|
||||
left: 4px;
|
||||
width: 2px;
|
||||
height: 150px;
|
||||
cursor: pointer;
|
||||
z-index: @TRAY_Z_INDEX + 9;
|
||||
background: fade( @red, 50% );
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -3px;
|
||||
left: -2px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 6px;
|
||||
background-color: @red;
|
||||
}
|
||||
}
|
||||
|
||||
.time-bar-scrubber-node {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: 3px solid #FFF;
|
||||
background: @green;
|
||||
width: @_scrubberHandleHeight;
|
||||
height: @_scrubberHandleHeight;
|
||||
border-radius: @_scrubberHandleHeight;
|
||||
margin-left: -@_scrubberHandleHeight / 2;
|
||||
margin-top: -@_scrubberHandleHeight / 2;
|
||||
box-shadow: 0 2px 3px rgba( 0, 0, 0, 0.8 );
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Tooltip that show the time when you hover over/drag the scrubber
|
||||
.butter-time-tooltip {
|
||||
@_tooltipHeight: 30px;
|
||||
@_tooltipWidth: 70px;
|
||||
width: @_tooltipWidth;
|
||||
margin-left: -@_tooltipWidth / 2;
|
||||
padding: @_tooltipHeight / 3;
|
||||
font-size: 11px;
|
||||
line-height: @_tooltipHeight / 3;
|
||||
top: -( @_tooltipHeight + 4px );
|
||||
height: @_tooltipHeight;
|
||||
&.tooltip-on {
|
||||
.transition( all 0.1s ease 0 );
|
||||
}
|
||||
&:after, &:before{
|
||||
top: 100%;
|
||||
border-bottom: none;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-top: 5px solid #FFF;
|
||||
}
|
||||
&:before {
|
||||
top: 100%;
|
||||
border-bottom: none;
|
||||
border-top: 5px solid #CCC;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Status container - Play button, time code at the top left of the tray.
|
||||
*/
|
||||
|
||||
.status-container {
|
||||
position: absolute;
|
||||
width: @_traySideWidth;
|
||||
height: @_butterStatusHeight;
|
||||
line-height: @_butterStatusHeight;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.time-container {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
input {
|
||||
background: transparent;
|
||||
color: @baseText;
|
||||
border: none;
|
||||
width: 60px;
|
||||
font-size: 10px;
|
||||
font-family: menlo, monospace;
|
||||
&:focus {
|
||||
.selectable( text );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-button {
|
||||
width: @_playButtonHeight;
|
||||
height: @_playButtonHeight;
|
||||
line-height: @_playButtonHeight;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
background: @green;
|
||||
&:active {
|
||||
background-color: lighten( @green, 10% );
|
||||
}
|
||||
}
|
||||
|
||||
.play-button-container {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
float: left;
|
||||
width: @_playButtonHeight + 13px;
|
||||
background: lighten( @baseLight, 5% );
|
||||
border-right: 1px solid @baseLightOutline;
|
||||
.triangle( "right", 4px, #FFF, 1px, @baseLightOutline );
|
||||
.status-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 5px;
|
||||
margin-top: -@_playButtonHeight / 2;
|
||||
border-bottom: 1px solid #FFF;
|
||||
}
|
||||
.icon {
|
||||
margin-top: 3px;
|
||||
}
|
||||
.status-button[data-state="true"] > .icon {
|
||||
background-position: -288px -72px;
|
||||
}
|
||||
}
|
||||
|
||||
.mute-button-container {
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
left: @_traySideWidth - 23px;
|
||||
|
||||
.status-button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: none;
|
||||
.icon {
|
||||
background-image: url( "../resources/glyphicons-halflings.png" );
|
||||
}
|
||||
&[data-state="true"] .icon {
|
||||
background-position: -360px -24px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
/*********************************************************
|
||||
* TRAY TIMELINE
|
||||
*/
|
||||
@_trackEventHeight: 27px;
|
||||
@_trackHeight: @_trackEventHeight + 3;
|
||||
@_mediaContainerHeight: 140px;
|
||||
@_trackContainerSpacing: 0;
|
||||
@_trackHandleWidth: 129px;
|
||||
|
||||
@_trackEventColor: #FFF;
|
||||
|
||||
// Main timeline section
|
||||
.butter-timeline-area {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
border-top: 1px solid @baseLightOutline;
|
||||
}
|
||||
|
||||
// butter-timeline-area-inner
|
||||
.butter-timeline {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: @_timebarRight;
|
||||
z-index: @TRAY_Z_INDEX + 1;
|
||||
}
|
||||
// inside .butter-timeline
|
||||
.media-instance {
|
||||
height: 100%;
|
||||
padding-left: @_trackHandleWidth;
|
||||
position: relative;
|
||||
.selectable( none );
|
||||
.transition( top 0.5s );
|
||||
.butter-scroll-bar-v {
|
||||
right: -18px;
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
//inside .media-instance
|
||||
.media-container {
|
||||
position: relative;
|
||||
top: @_trackContainerSpacing;
|
||||
height: @_mediaContainerHeight;
|
||||
}
|
||||
|
||||
.tracks-container-wrapper {
|
||||
background: @baseLight;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
border-left: 1px solid @baseLightOutline;
|
||||
border-right: 1px solid @baseLightOutline;
|
||||
box-shadow: inset 0 0 5px 0 rgba( 0, 0, 0, 0.2 );
|
||||
}
|
||||
|
||||
.tracks-container {
|
||||
padding-bottom: @_trackHeight; //must have padding to account for add popcorn button
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Track
|
||||
*/
|
||||
.butter-track {
|
||||
width: 100%;
|
||||
height: @_trackHeight;
|
||||
position: relative;
|
||||
border-bottom: 1px dashed @baseLightOutline;
|
||||
|
||||
.track-title {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 50%;
|
||||
}
|
||||
&.draggable-hover {
|
||||
//box-shadow: inset 0 0 0 2px @green;
|
||||
background: fade( #FFF, 80% );
|
||||
}
|
||||
|
||||
&.butter-track-ghost {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Track Event
|
||||
*/
|
||||
.butter-track-event {
|
||||
.selectable( none );
|
||||
background: @_trackEventColor;
|
||||
box-shadow: 1px 5px 2px -3px rgba( 0, 0, 0, 0.1 );
|
||||
border: 1px solid #CCC;
|
||||
border-radius: 4px;
|
||||
border-top-color: #E3E3E3;
|
||||
border-bottom-color: #BDBDBD;
|
||||
cursor: move;
|
||||
display: block;
|
||||
height: @_trackEventHeight;
|
||||
padding: 1px 0;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
|
||||
&[selected="true"] {
|
||||
border-color: @green;
|
||||
box-shadow: 1px 5px 2px -3px rgba( 0, 0, 0, 0.2 );
|
||||
}
|
||||
|
||||
.butter-track-event-info {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
left: 35px;
|
||||
line-height: 25px;
|
||||
color: @baseText;
|
||||
}
|
||||
.butter-track-event-icon {
|
||||
position: absolute;
|
||||
height: 25px;
|
||||
width: 30px;
|
||||
background-size: 20px;
|
||||
background-image: url( "../resources/default-icon.png" );
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.handle {
|
||||
position: absolute;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
top: 5px;
|
||||
opacity: 0;
|
||||
background: @_trackEventColor;
|
||||
.transition( all 0.1s ease );
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
background-image: url( "../resources/glyphicons-halflings-green.png" );
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
.left-handle {
|
||||
left: 10px;
|
||||
cursor: w-resize;
|
||||
cursor: ew-resize;
|
||||
&:after {
|
||||
background-position: -240px -96px;
|
||||
left: 2px;
|
||||
}
|
||||
}
|
||||
.right-handle {
|
||||
right: 10px;
|
||||
cursor: e-resize;
|
||||
cursor: ew-resize;
|
||||
&:after {
|
||||
background-position: -264px -96px;
|
||||
right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.butter-resizable {
|
||||
.handle {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.left-handle {
|
||||
left: 0;
|
||||
}
|
||||
.right-handle {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.trackevent-small {
|
||||
overflow: visible;
|
||||
.handle {
|
||||
background: none;
|
||||
}
|
||||
.butter-track-event-info {
|
||||
left: 0;
|
||||
}
|
||||
.left-handle {
|
||||
left: -16px;
|
||||
&:after {
|
||||
left: -2px;
|
||||
}
|
||||
}
|
||||
.right-handle {
|
||||
right: -16px;
|
||||
&:after {
|
||||
right: -2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.butter-track-event-ghost {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
* Track Handle Container - Left-hand side panel
|
||||
*/
|
||||
|
||||
.track-handle-container {
|
||||
position: absolute;
|
||||
width: @_trackHandleWidth;
|
||||
left: 0;
|
||||
top: @_trackContainerSpacing;
|
||||
bottom: 1px;
|
||||
border-bottom: 1px solid lighten( @baseLightOutline, 5% );
|
||||
overflow: hidden;
|
||||
background: @baseLight;
|
||||
}
|
||||
|
||||
.handle-list {
|
||||
position: relative;
|
||||
padding-bottom: @_trackHeight;
|
||||
}
|
||||
|
||||
.track-handle {
|
||||
border: none;
|
||||
border-bottom: 1px solid darken( @baseLight, 25% );
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
height: @_trackHeight;
|
||||
background: @baseLight;
|
||||
position: relative;
|
||||
line-height: @_trackHeight;
|
||||
overflow: hidden;
|
||||
box-shadow: inset 0 1px #FFF;
|
||||
.title {
|
||||
padding-left: 22px;
|
||||
font-size: 11px;
|
||||
color: @baseText;
|
||||
}
|
||||
&:first-of-type {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.menu {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
.transition( width 0.1s );
|
||||
opacity: 0.3;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.delete {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 8px;
|
||||
background-image: url( "../resources/glyphicons-halflings.png" );
|
||||
background-position: -456px 0;
|
||||
cursor: pointer;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
&:hover .menu {
|
||||
width: 15px;
|
||||
}
|
||||
&:hover .track-handle-icon {
|
||||
border-color: #000;
|
||||
&:after {
|
||||
border-bottom-color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.track-handle-icon {
|
||||
border: 0 solid darken( @baseLightOutline, 10% );
|
||||
box-shadow: inset 0 1px 0 #FFF, 0 1px 0 #FFF;
|
||||
position: absolute;
|
||||
top: 9px;
|
||||
right: 10px;
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 9px;
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
&:after {
|
||||
box-shadow: 0 1px 0 #FFF;
|
||||
border-bottom: 1px solid darken( @baseLightOutline, 10% );
|
||||
content: " ";
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.add-track {
|
||||
padding: 0;
|
||||
font-size: 11px;
|
||||
position: absolute;
|
||||
right: 9px;
|
||||
width: 20px;
|
||||
font-weight: 700;
|
||||
margin-left: 10px;
|
||||
margin-top: 14px; // This is a crappy work-around because the height of this is getting set in javascript
|
||||
}
|
||||
|
||||
// Drag and dropping track handles
|
||||
.placeholder {
|
||||
width: 95px;
|
||||
box-shadow: inset 0 1px 0 #999, 0 0 1px #AAA;
|
||||
background: transparent;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*********************************************************
|
||||
* TRAY
|
||||
*/
|
||||
|
||||
// Adds room to bottom of template for tray
|
||||
.butter-tray-spacing {
|
||||
padding-bottom: @TRAY_SPACING;
|
||||
.transition( padding-bottom 0.5s );
|
||||
}
|
||||
|
||||
.butter-tray-spacing.tray-minimized {
|
||||
padding-bottom: @TRAY_SPACING_MINIMIZED;
|
||||
}
|
||||
|
||||
.butter-editor-spacing.editor-minimized .butter-tray {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.butter-tray {
|
||||
background: #FFF;
|
||||
position: fixed;
|
||||
z-index: @TRAY_Z_INDEX;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: @EDITOR_WIDTH;
|
||||
height: @TRAY_HEIGHT;
|
||||
.selectable( none );
|
||||
.transition( bottom 0.35s, right 0.35s );
|
||||
|
||||
* {
|
||||
.selectable( none );
|
||||
}
|
||||
|
||||
&.minimized {
|
||||
bottom: -@TRAY_HEIGHT + @_butterStatusHeight;
|
||||
}
|
||||
|
||||
.butter-toggle-button {
|
||||
top: 15px;
|
||||
right: 6px;
|
||||
z-index: @TRAY_Z_INDEX + 10;
|
||||
}
|
||||
|
||||
// This is the list of plugins in "my events"
|
||||
.butter-timeline-area {
|
||||
position: relative;
|
||||
height: 160px;
|
||||
top: @_butterStatusHeight;
|
||||
}
|
||||
|
||||
// This is the container for the spinning popcorn logo on the right side of the tray
|
||||
.butter-loading-container {
|
||||
position: absolute;
|
||||
z-index: @TRAY_Z_INDEX + 1;
|
||||
right: 10px;
|
||||
top: 3px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.fadable {
|
||||
//TO-DO: This should be moved into a general UI kit
|
||||
.transition( opacity 0.5s );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/*********************************************************
|
||||
* UTILITIES
|
||||
*/
|
||||
|
||||
.butter-image-preload {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
opacity: 0;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*********************************************************
|
||||
* WEB FONTS
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('../resources/fonts/opensans-bold-webfont.woff') format('woff'),
|
||||
url('../resources/fonts/opensans-bold-webfont.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('../resources/fonts/opensans-bolditalic-webfont.woff') format('woff'),
|
||||
url('../resources/fonts/opensans-bolditalic-webfont.ttf') format('truetype');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('../resources/fonts/opensans-regular-webfont.woff') format('woff'),
|
||||
url('../resources/fonts/opensans-regular-webfont.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
src: url('../resources/fonts/opensans-italic-webfont.woff') format('woff'),
|
||||
url('../resources/fonts/opensans-italic-webfont.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Meta';
|
||||
src: url('http://www.mozilla.org/img/fonts/MetaWebPro-Bold.eot');
|
||||
src: local('?'), url('http://www.mozilla.org/img/fonts/MetaWebPro-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<!-- This Source Code Form is subject to the terms of the MIT license
|
||||
If a copy of the MIT license was not distributed with this file, you can
|
||||
obtain one at http://www.mozillapopcorn.org/butter-license.txt -->
|
||||
|
||||
<div class="butter-editor default-editor allow-scrollbar">
|
||||
<h1>Google Maps Editor</h1>
|
||||
<div class="butter-editor-body scrollbar-container">
|
||||
<div class="editor-options-wrapper scrollbar-outer">
|
||||
<div class="editor-options scrollbar-inner">
|
||||
<div class="error-message-container">
|
||||
<div class="error-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,209 @@
|
|||
/*global google*/
|
||||
/* This Source Code Form is subject to the terms of the MIT license
|
||||
* If a copy of the MIT license was not distributed with this file, you can
|
||||
* obtain one at http://www.mozillapopcorn.org/butter-license.txt */
|
||||
|
||||
( function( Butter ) {
|
||||
|
||||
Butter.Editor.register( "googlemap", "load!{{baseDir}}editors/googlemap-editor.html",
|
||||
function( rootElement, butter, compiledLayout ) {
|
||||
|
||||
var _this = this;
|
||||
|
||||
var _rootElement = rootElement,
|
||||
_trackEvent,
|
||||
_popcornEventMapReference,
|
||||
_butter;
|
||||
|
||||
/**
|
||||
* Member: getMapFromTrackEvent
|
||||
*
|
||||
* Retrieves a handle to the map associated with the trackevent.
|
||||
*/
|
||||
function getMapFromTrackEvent() {
|
||||
if ( !_trackEvent.popcornTrackEvent._map ) {
|
||||
_trackEvent.popcornTrackEvent.onmaploaded = function( options, map ){
|
||||
_popcornEventMapReference = map;
|
||||
};
|
||||
}
|
||||
else {
|
||||
_popcornEventMapReference = _trackEvent.popcornTrackEvent._map;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Member: setup
|
||||
*
|
||||
* Sets up the content of this editor
|
||||
*
|
||||
* @param {TrackEvent} trackEvent: The TrackEvent being edited
|
||||
*/
|
||||
function setup( trackEvent ){
|
||||
_trackEvent = trackEvent;
|
||||
|
||||
var pluginOptions = {},
|
||||
ignoreKeys = [
|
||||
"target",
|
||||
"start",
|
||||
"end"
|
||||
],
|
||||
optionsContainer = _rootElement.querySelector( ".editor-options" );
|
||||
|
||||
function callback( elementType, element, trackEvent, name ) {
|
||||
pluginOptions[ name ] = {
|
||||
element: element,
|
||||
trackEvent: trackEvent,
|
||||
elementType: elementType
|
||||
};
|
||||
}
|
||||
|
||||
function attachHandlers() {
|
||||
var key,
|
||||
option,
|
||||
pitchObject,
|
||||
headingObject,
|
||||
currentMapType;
|
||||
|
||||
function toggleStreetView() {
|
||||
pitchObject.element.parentNode.style.display = "block";
|
||||
headingObject.element.parentNode.style.display = "block";
|
||||
_this.scrollbar.update();
|
||||
}
|
||||
|
||||
function toggleMaps() {
|
||||
pitchObject.element.parentNode.style.display = "none";
|
||||
headingObject.element.parentNode.style.display = "none";
|
||||
_this.scrollbar.update();
|
||||
}
|
||||
|
||||
function attachTypeHandler( option ) {
|
||||
option.element.addEventListener( "change", function( e ) {
|
||||
var elementVal = e.target.value,
|
||||
updateOptions = {},
|
||||
target;
|
||||
|
||||
if ( elementVal === "STREETVIEW" ) {
|
||||
toggleStreetView();
|
||||
} else {
|
||||
toggleMaps();
|
||||
}
|
||||
|
||||
updateOptions.type = elementVal;
|
||||
option.trackEvent.update( updateOptions );
|
||||
|
||||
// Attempt to make the trackEvent's target blink
|
||||
target = _butter.getTargetByType( "elementID", option.trackEvent.popcornOptions.target );
|
||||
if ( target ) {
|
||||
target.view.blink();
|
||||
} else {
|
||||
_butter.currentMedia.view.blink();
|
||||
}
|
||||
}, false );
|
||||
}
|
||||
|
||||
function attachFullscreenHandler( option ) {
|
||||
option.element.addEventListener( "click", function( e ) {
|
||||
var srcElement = e.target,
|
||||
updateOptions = {},
|
||||
manifestOpts = trackEvent.manifest.options;
|
||||
|
||||
if ( srcElement.checked ) {
|
||||
updateOptions = {
|
||||
height: 100,
|
||||
width: 100,
|
||||
left: 0,
|
||||
top: 0,
|
||||
fullscreen: true
|
||||
};
|
||||
|
||||
} else {
|
||||
updateOptions = {
|
||||
height: manifestOpts.height[ "default" ],
|
||||
width: manifestOpts.width[ "default" ],
|
||||
left: manifestOpts.left[ "default" ],
|
||||
top: manifestOpts.top[ "default" ],
|
||||
fullscreen: false
|
||||
};
|
||||
}
|
||||
|
||||
trackEvent.update( updateOptions );
|
||||
}, false );
|
||||
}
|
||||
|
||||
for ( key in pluginOptions ) {
|
||||
if ( pluginOptions.hasOwnProperty( key ) ) {
|
||||
option = pluginOptions[ key ];
|
||||
|
||||
if ( key === "type" ) {
|
||||
pitchObject = pluginOptions.pitch;
|
||||
headingObject = pluginOptions.heading;
|
||||
currentMapType = option.trackEvent.popcornOptions.type;
|
||||
|
||||
if ( currentMapType === "STREETVIEW" ) {
|
||||
toggleStreetView();
|
||||
} else {
|
||||
toggleMaps();
|
||||
}
|
||||
|
||||
attachTypeHandler( option );
|
||||
} else if ( option.elementType === "select" && key !== "type" ) {
|
||||
_this.attachSelectChangeHandler( option.element, option.trackEvent, key, _this.updateTrackEventSafe );
|
||||
} else if ( key === "fullscreen" ) {
|
||||
attachFullscreenHandler( option );
|
||||
} else if ( option.elementType === "input" ) {
|
||||
_this.attachInputChangeHandler( option.element, option.trackEvent, key, _this.updateTrackEventSafe );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optionsContainer.appendChild( _this.createStartEndInputs( trackEvent, _this.updateTrackEventSafe ) );
|
||||
|
||||
_this.createPropertiesFromManifest({
|
||||
trackEvent: trackEvent,
|
||||
callback: callback,
|
||||
basicContainer: optionsContainer,
|
||||
ignoreManifestKeys: ignoreKeys
|
||||
});
|
||||
|
||||
attachHandlers();
|
||||
|
||||
_this.updatePropertiesFromManifest( trackEvent );
|
||||
_this.scrollbar.update();
|
||||
|
||||
_this.setTrackEventUpdateErrorCallback( _this.setErrorState );
|
||||
|
||||
}
|
||||
|
||||
// Extend this object to become a BaseEditor
|
||||
Butter.Editor.TrackEventEditor.extend( _this, butter, rootElement, {
|
||||
open: function( parentElement, trackEvent ) {
|
||||
var popcorn = butter.currentMedia.popcorn.popcorn;
|
||||
|
||||
_butter = butter;
|
||||
// Update properties when TrackEvent is updated
|
||||
trackEvent.listen( "trackeventupdated", function ( e ) {
|
||||
_this.updatePropertiesFromManifest( e.target );
|
||||
_this.setErrorState( false );
|
||||
|
||||
// Now we REALLY know that we can try setting up listeners
|
||||
popcorn.on( "googlemaps-loaded", function() {
|
||||
popcorn.off( "googlemaps-loaded" );
|
||||
getMapFromTrackEvent();
|
||||
});
|
||||
});
|
||||
|
||||
// Now we REALLY know that we can try setting up listeners
|
||||
popcorn.on( "googlemaps-loaded", function() {
|
||||
popcorn.off( "googlemaps-loaded" );
|
||||
getMapFromTrackEvent();
|
||||
});
|
||||
|
||||
setup( trackEvent );
|
||||
|
||||
},
|
||||
close: function() {
|
||||
}
|
||||
});
|
||||
});
|
||||
}( window.Butter ));
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 401f80981f905cd42f0317fdfb7472de614bc1ac
|
|
@ -0,0 +1 @@
|
|||
Subproject commit fa07a4bb76ba92df075fd2e6c387c5ea425d3fd5
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
RequireJS 2.0.4 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
var requirejs,require,define;
|
||||
(function(Y){function x(b){return J.call(b)==="[object Function]"}function G(b){return J.call(b)==="[object Array]"}function q(b,c){if(b){var e;for(e=0;e<b.length;e+=1)if(b[e]&&c(b[e],e,b))break}}function N(b,c){if(b){var e;for(e=b.length-1;e>-1;e-=1)if(b[e]&&c(b[e],e,b))break}}function y(b,c){for(var e in b)if(b.hasOwnProperty(e)&&c(b[e],e))break}function K(b,c,e,i){c&&y(c,function(c,j){if(e||!b.hasOwnProperty(j))i&&typeof c!=="string"?(b[j]||(b[j]={}),K(b[j],c,e,i)):b[j]=c});return b}function s(b,
|
||||
c){return function(){return c.apply(b,arguments)}}function Z(b){if(!b)return b;var c=Y;q(b.split("."),function(b){c=c[b]});return c}function $(b,c,e){return function(){var i=fa.call(arguments,0),g;if(e&&x(g=i[i.length-1]))g.__requireJsBuild=!0;i.push(c);return b.apply(null,i)}}function aa(b,c,e){q([["toUrl"],["undef"],["defined","requireDefined"],["specified","requireSpecified"]],function(i){var g=i[1]||i[0];b[i[0]]=c?$(c[g],e):function(){var b=z[O];return b[g].apply(b,arguments)}})}function H(b,
|
||||
c,e,i){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=i;if(e)c.originalError=e;return c}function ga(){if(I&&I.readyState==="interactive")return I;N(document.getElementsByTagName("script"),function(b){if(b.readyState==="interactive")return I=b});return I}var ha=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ia=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,ba=/\.js$/,ja=/^\.\//,J=Object.prototype.toString,A=Array.prototype,fa=A.slice,ka=A.splice,w=!!(typeof window!==
|
||||
"undefined"&&navigator&&document),ca=!w&&typeof importScripts!=="undefined",la=w&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,O="_",S=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",z={},p={},P=[],L=!1,j,t,C,u,D,I,E,da,ea;if(typeof define==="undefined"){if(typeof requirejs!=="undefined"){if(x(requirejs))return;p=requirejs;requirejs=void 0}typeof require!=="undefined"&&!x(require)&&(p=require,require=void 0);j=requirejs=function(b,c,e,i){var g=O,r;!G(b)&&
|
||||
typeof b!=="string"&&(r=b,G(c)?(b=c,c=e,e=i):b=[]);if(r&&r.context)g=r.context;(i=z[g])||(i=z[g]=j.s.newContext(g));r&&i.configure(r);return i.require(b,c,e)};j.config=function(b){return j(b)};require||(require=j);j.version="2.0.4";j.jsExtRegExp=/^\/|:|\?|\.js$/;j.isBrowser=w;A=j.s={contexts:z,newContext:function(b){function c(a,d,o){var l=d&&d.split("/"),f=l,b=k.map,c=b&&b["*"],e,g,h;if(a&&a.charAt(0)===".")if(d){f=k.pkgs[d]?l=[d]:l.slice(0,l.length-1);d=a=f.concat(a.split("/"));for(f=0;d[f];f+=
|
||||
1)if(e=d[f],e===".")d.splice(f,1),f-=1;else if(e==="..")if(f===1&&(d[2]===".."||d[0]===".."))break;else f>0&&(d.splice(f-1,2),f-=2);f=k.pkgs[d=a[0]];a=a.join("/");f&&a===d+"/"+f.main&&(a=d)}else a.indexOf("./")===0&&(a=a.substring(2));if(o&&(l||c)&&b){d=a.split("/");for(f=d.length;f>0;f-=1){g=d.slice(0,f).join("/");if(l)for(e=l.length;e>0;e-=1)if(o=b[l.slice(0,e).join("/")])if(o=o[g]){h=o;break}!h&&c&&c[g]&&(h=c[g]);if(h){d.splice(0,f,h);a=d.join("/");break}}}return a}function e(a){w&&q(document.getElementsByTagName("script"),
|
||||
function(d){if(d.getAttribute("data-requiremodule")===a&&d.getAttribute("data-requirecontext")===h.contextName)return d.parentNode.removeChild(d),!0})}function i(a){var d=k.paths[a];if(d&&G(d)&&d.length>1)return e(a),d.shift(),h.undef(a),h.require([a]),!0}function g(a,d,o,b){var f=a?a.indexOf("!"):-1,v=null,e=d?d.name:null,g=a,i=!0,j="",k,m;a||(i=!1,a="_@r"+(N+=1));f!==-1&&(v=a.substring(0,f),a=a.substring(f+1,a.length));v&&(v=c(v,e,b),m=n[v]);a&&(v?j=m&&m.normalize?m.normalize(a,function(a){return c(a,
|
||||
e,b)}):c(a,e,b):(j=c(a,e,b),k=h.nameToUrl(j)));a=v&&!m&&!o?"_unnormalized"+(O+=1):"";return{prefix:v,name:j,parentMap:d,unnormalized:!!a,url:k,originalName:g,isDefine:i,id:(v?v+"!"+j:j)+a}}function r(a){var d=a.id,o=m[d];o||(o=m[d]=new h.Module(a));return o}function p(a,d,o){var b=a.id,f=m[b];if(n.hasOwnProperty(b)&&(!f||f.defineEmitComplete))d==="defined"&&o(n[b]);else r(a).on(d,o)}function B(a,d){var b=a.requireModules,l=!1;if(d)d(a);else if(q(b,function(d){if(d=m[d])d.error=a,d.events.error&&(l=
|
||||
!0,d.emit("error",a))}),!l)j.onError(a)}function u(){P.length&&(ka.apply(F,[F.length-1,0].concat(P)),P=[])}function t(a,d,b){a=a&&a.map;d=$(b||h.require,a,d);aa(d,h,a);d.isBrowser=w;return d}function z(a){delete m[a];q(M,function(d,b){if(d.map.id===a)return M.splice(b,1),d.defined||(h.waitCount-=1),!0})}function A(a,d){var b=a.map.id,l=a.depMaps,f;if(a.inited){if(d[b])return a;d[b]=!0;q(l,function(a){if(a=m[a.id])return!a.inited||!a.enabled?(f=null,delete d[b],!0):f=A(a,K({},d))});return f}}function C(a,
|
||||
d,b){var l=a.map.id,f=a.depMaps;if(a.inited&&a.map.isDefine){if(d[l])return n[l];d[l]=a;q(f,function(f){var f=f.id,c=m[f];!Q[f]&&c&&(!c.inited||!c.enabled?b[l]=!0:(c=C(c,d,b),b[f]||a.defineDepById(f,c)))});a.check(!0);return n[l]}}function D(a){a.check()}function E(){var a=k.waitSeconds*1E3,d=a&&h.startTime+a<(new Date).getTime(),b=[],l=!1,f=!0,c,g,j;if(!T){T=!0;y(m,function(a){c=a.map;g=c.id;if(a.enabled&&!a.error)if(!a.inited&&d)i(g)?l=j=!0:(b.push(g),e(g));else if(!a.inited&&a.fetched&&c.isDefine&&
|
||||
(l=!0,!c.prefix))return f=!1});if(d&&b.length)return a=H("timeout","Load timeout for modules: "+b,null,b),a.contextName=h.contextName,B(a);f&&(q(M,function(a){if(!a.defined){var a=A(a,{}),d={};a&&(C(a,d,{}),y(d,D))}}),y(m,D));if((!d||j)&&l)if((w||ca)&&!U)U=setTimeout(function(){U=0;E()},50);T=!1}}function V(a){r(g(a[0],null,!0)).init(a[1],a[2])}function J(a){var a=a.currentTarget||a.srcElement,d=h.onScriptLoad;a.detachEvent&&!S?a.detachEvent("onreadystatechange",d):a.removeEventListener("load",d,
|
||||
!1);d=h.onScriptError;a.detachEvent&&!S||a.removeEventListener("error",d,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}var k={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{}},m={},W={},F=[],n={},R={},N=1,O=1,M=[],T,X,h,Q,U;Q={require:function(a){return t(a)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports=n[a.map.id]={}},module:function(a){return a.module={id:a.map.id,uri:a.map.url,config:function(){return k.config&&k.config[a.map.id]||{}},exports:n[a.map.id]}}};
|
||||
X=function(a){this.events=W[a.id]||{};this.map=a;this.shim=k.shim[a.id];this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};X.prototype={init:function(a,d,b,l){l=l||{};if(!this.inited){this.factory=d;if(b)this.on("error",b);else this.events.error&&(b=s(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.depMaps.rjsSkipMap=a.rjsSkipMap;this.errback=b;this.inited=!0;this.ignore=l.ignore;l.enabled||this.enabled?this.enable():this.check()}},defineDepById:function(a,
|
||||
d){var b;q(this.depMaps,function(d,f){if(d.id===a)return b=f,!0});return this.defineDep(b,d)},defineDep:function(a,d){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=d)},fetch:function(){if(!this.fetched){this.fetched=!0;h.startTime=(new Date).getTime();var a=this.map;if(this.shim)t(this,!0)(this.shim.deps||[],s(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=this.map.url;R[a]||
|
||||
(R[a]=!0,h.load(this.map.id,a))},check:function(a){if(this.enabled&&!this.enabling){var d=this.map.id,b=this.depExports,c=this.exports,f=this.factory,e;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(this.depCount<1&&!this.defined){if(x(f)){if(this.events.error)try{c=h.execCb(d,f,b,c)}catch(g){e=g}else c=h.execCb(d,f,b,c);if(this.map.isDefine)if((b=this.module)&&b.exports!==void 0&&b.exports!==this.exports)c=b.exports;else if(c===void 0&&this.usingExports)c=
|
||||
this.exports;if(e)return e.requireMap=this.map,e.requireModules=[this.map.id],e.requireType="define",B(this.error=e)}else c=f;this.exports=c;if(this.map.isDefine&&!this.ignore&&(n[d]=c,j.onResourceLoad))j.onResourceLoad(h,this.map,this.depMaps);delete m[d];this.defined=!0;h.waitCount-=1;h.waitCount===0&&(M=[])}this.defining=!1;if(!a&&this.defined&&!this.defineEmitted)this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0}}else this.fetch()}},callPlugin:function(){var a=
|
||||
this.map,d=a.id,b=g(a.prefix,null,!1,!0);p(b,"defined",s(this,function(b){var f=this.map.name,e=this.map.parentMap?this.map.parentMap.name:null;if(this.map.unnormalized){if(b.normalize&&(f=b.normalize(f,function(a){return c(a,e,!0)})||""),b=g(a.prefix+"!"+f,this.map.parentMap,!1,!0),p(b,"defined",s(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),b=m[b.id]){if(this.events.error)b.on("error",s(this,function(a){this.emit("error",a)}));b.enable()}}else f=s(this,function(a){this.init([],
|
||||
function(){return a},null,{enabled:!0})}),f.error=s(this,function(a){this.inited=!0;this.error=a;a.requireModules=[d];y(m,function(a){a.map.id.indexOf(d+"_unnormalized")===0&&z(a.map.id)});B(a)}),f.fromText=function(a,d){var b=L;b&&(L=!1);r(g(a));j.exec(d);b&&(L=!0);h.completeLoad(a)},b.load(a.name,t(a.parentMap,!0,function(a,d){a.rjsSkipMap=!0;return h.require(a,d)}),f,k)}));h.enable(b,this);this.pluginMaps[b.id]=b},enable:function(){this.enabled=!0;if(!this.waitPushed)M.push(this),h.waitCount+=
|
||||
1,this.waitPushed=!0;this.enabling=!0;q(this.depMaps,s(this,function(a,d){var b,c;if(typeof a==="string"){a=g(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.depMaps.rjsSkipMap);this.depMaps[d]=a;if(b=Q[a.id]){this.depExports[d]=b(this);return}this.depCount+=1;p(a,"defined",s(this,function(a){this.defineDep(d,a);this.check()}));this.errback&&p(a,"error",this.errback)}b=a.id;c=m[b];!Q[b]&&c&&!c.enabled&&h.enable(a,this)}));y(this.pluginMaps,s(this,function(a){var b=m[a.id];b&&!b.enabled&&
|
||||
h.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){q(this.events[a],function(a){a(b)});a==="error"&&delete this.events[a]}};return h={config:k,contextName:b,registry:m,defined:n,urlFetched:R,waitCount:0,defQueue:F,Module:X,makeModuleMap:g,configure:function(a){a.baseUrl&&a.baseUrl.charAt(a.baseUrl.length-1)!=="/"&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e=k.paths,f=k.map;K(k,a,!0);k.paths=K(e,a.paths,!0);if(a.map)k.map=
|
||||
K(f||{},a.map,!0,!0);if(a.shim)y(a.shim,function(a,b){G(a)&&(a={deps:a});if(a.exports&&!a.exports.__buildReady)a.exports=h.makeShimExports(a.exports);c[b]=a}),k.shim=c;if(a.packages)q(a.packages,function(a){a=typeof a==="string"?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ba,"")}}),k.pkgs=b;y(m,function(a,b){a.map=g(b)});if(a.deps||a.callback)h.require(a.deps||[],a.callback)},makeShimExports:function(a){var b;return typeof a==="string"?
|
||||
(b=function(){return Z(a)},b.exports=a,b):function(){return a.apply(Y,arguments)}},requireDefined:function(a,b){var c=g(a,b,!1,!0).id;return n.hasOwnProperty(c)},requireSpecified:function(a,b){a=g(a,b,!1,!0).id;return n.hasOwnProperty(a)||m.hasOwnProperty(a)},require:function(a,d,c,e){var f;if(typeof a==="string"){if(x(d))return B(H("requireargs","Invalid require call"),c);if(j.get)return j.get(h,a,d);a=g(a,d,!1,!0);a=a.id;return!n.hasOwnProperty(a)?B(H("notloaded",'Module name "'+a+'" has not been loaded yet for context: '+
|
||||
b)):n[a]}c&&!x(c)&&(e=c,c=void 0);d&&!x(d)&&(e=d,d=void 0);for(u();F.length;)if(f=F.shift(),f[0]===null)return B(H("mismatch","Mismatched anonymous define() module: "+f[f.length-1]));else V(f);r(g(null,e)).init(a,d,c,{enabled:!0});E();return h.require},undef:function(a){var b=g(a,null,!0),c=m[a];delete n[a];delete R[b.url];delete W[a];if(c){if(c.events.defined)W[a]=c.events;z(a)}},enable:function(a){m[a.id]&&r(a).enable()},completeLoad:function(a){var b=k.shim[a]||{},c=b.exports&&b.exports.exports,
|
||||
e,f;for(u();F.length;){f=F.shift();if(f[0]===null){f[0]=a;if(e)break;e=!0}else f[0]===a&&(e=!0);V(f)}f=m[a];if(!e&&!n[a]&&f&&!f.inited)if(k.enforceDefine&&(!c||!Z(c)))if(i(a))return;else return B(H("nodefine","No define call for "+a,null,[a]));else V([a,b.deps||[],b.exports]);E()},toUrl:function(a,b){var e=a.lastIndexOf("."),g=null;e!==-1&&(g=a.substring(e,a.length),a=a.substring(0,e));return h.nameToUrl(c(a,b&&b.id,!0),g)},nameToUrl:function(a,b){var c,e,f,g,h,i;if(j.jsExtRegExp.test(a))g=a+(b||
|
||||
"");else{c=k.paths;e=k.pkgs;g=a.split("/");for(h=g.length;h>0;h-=1)if(i=g.slice(0,h).join("/"),f=e[i],i=c[i]){G(i)&&(i=i[0]);g.splice(0,h,i);break}else if(f){c=a===f.name?f.location+"/"+f.main:f.location;g.splice(0,h,c);break}g=g.join("/")+(b||".js");g=(g.charAt(0)==="/"||g.match(/^[\w\+\.\-]+:/)?"":k.baseUrl)+g}return k.urlArgs?g+((g.indexOf("?")===-1?"?":"&")+k.urlArgs):g},load:function(a,b){j.load(h,a,b)},execCb:function(a,b,c,e){return b.apply(e,c)},onScriptLoad:function(a){if(a.type==="load"||
|
||||
la.test((a.currentTarget||a.srcElement).readyState))I=null,a=J(a),h.completeLoad(a.id)},onScriptError:function(a){var b=J(a);if(!i(b.id))return B(H("scripterror","Script error",a,[b.id]))}}}};j({});aa(j);if(w&&(t=A.head=document.getElementsByTagName("head")[0],C=document.getElementsByTagName("base")[0]))t=A.head=C.parentNode;j.onError=function(b){throw b;};j.load=function(b,c,e){var i=b&&b.config||{},g;if(w)return g=i.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),
|
||||
g.type=i.scriptType||"text/javascript",g.charset="utf-8",g.async=!0,g.setAttribute("data-requirecontext",b.contextName),g.setAttribute("data-requiremodule",c),g.attachEvent&&!(g.attachEvent.toString&&g.attachEvent.toString().indexOf("[native code")<0)&&!S?(L=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1)),g.src=e,E=g,C?t.insertBefore(g,C):t.appendChild(g),E=null,g;else ca&&(importScripts(e),b.completeLoad(c))};
|
||||
w&&N(document.getElementsByTagName("script"),function(b){if(!t)t=b.parentNode;if(u=b.getAttribute("data-main")){if(!p.baseUrl)D=u.split("/"),da=D.pop(),ea=D.length?D.join("/")+"/":"./",p.baseUrl=ea,u=da;u=u.replace(ba,"");p.deps=p.deps?p.deps.concat(u):[u];return!0}});define=function(b,c,e){var i,g;typeof b!=="string"&&(e=c,c=b,b=null);G(c)||(e=c,c=[]);!c.length&&x(e)&&e.length&&(e.toString().replace(ha,"").replace(ia,function(b,e){c.push(e)}),c=(e.length===1?["require"]:["require","exports","module"]).concat(c));
|
||||
if(L&&(i=E||ga()))b||(b=i.getAttribute("data-requiremodule")),g=z[i.getAttribute("data-requirecontext")];(g?g.defQueue:P).push([b,c,e])};define.amd={jQuery:!0};j.exec=function(b){return eval(b)};j(p)}})(this);
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
RequireJS text 2.0.1 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/requirejs/text for details
|
||||
*/
|
||||
define(["module"],function(e){"use strict";var t=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"],n=/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,r=/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,i=typeof location!="undefined"&&location.href,s=i&&location.protocol&&location.protocol.replace(/\:/,""),o=i&&location.hostname,u=i&&(location.port||undefined),a=[],f=e.config&&e.config()||{},l,c;return l={version:"2.0.1",strip:function(e){if(e){e=e.replace(n,"");var t=e.match(r);t&&(e=t[1])}else e="";return e},jsEscape:function(e){return e.replace(/(['\\])/g,"\\$1").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r").replace(/[\u2028]/g,"\\u2028").replace(/[\u2029]/g,"\\u2029")},createXhr:f.createXhr||function(){var e,n,r;if(typeof XMLHttpRequest!="undefined")return new XMLHttpRequest;if(typeof ActiveXObject!="undefined")for(n=0;n<3;n+=1){r=t[n];try{e=new ActiveXObject(r)}catch(i){}if(e){t=[r];break}}return e},parseName:function(e){var t=!1,n=e.indexOf("."),r=e.substring(0,n),i=e.substring(n+1,e.length);return n=i.indexOf("!"),n!==-1&&(t=i.substring(n+1,i.length),t=t==="strip",i=i.substring(0,n)),{moduleName:r,ext:i,strip:t}},xdRegExp:/^((\w+)\:)?\/\/([^\/\\]+)/,useXhr:function(e,t,n,r){var i=l.xdRegExp.exec(e),s,o,u;return i?(s=i[2],o=i[3],o=o.split(":"),u=o[1],o=o[0],(!s||s===t)&&(!o||o.toLowerCase()===n.toLowerCase())&&(!u&&!o||u===r)):!0},finishLoad:function(e,t,n,r){n=t?l.strip(n):n,f.isBuild&&(a[e]=n),r(n)},load:function(e,t,n,r){if(r.isBuild&&!r.inlineText){n();return}f.isBuild=r.isBuild;var a=l.parseName(e),c=a.moduleName+"."+a.ext,h=t.toUrl(c),p=f.useXhr||l.useXhr;!i||p(h,s,o,u)?l.get(h,function(t){l.finishLoad(e,a.strip,t,n)},function(e){n.error&&n.error(e)}):t([c],function(e){l.finishLoad(a.moduleName+"."+a.ext,a.strip,e,n)})},write:function(e,t,n,r){if(a.hasOwnProperty(t)){var i=l.jsEscape(a[t]);n.asModule(e+"!"+t,"define(function () { return '"+i+"';});\n")}},writeFile:function(e,t,n,r,i){var s=l.parseName(t),o=s.moduleName+"."+s.ext,u=n.toUrl(s.moduleName+"."+s.ext)+".js";l.load(o,n,function(t){var n=function(e){return r(u,e)};n.asModule=function(e,t){return r.asModule(e,u,t)},l.write(e,o,n,i)},i)}},typeof process!="undefined"&&process.versions&&!!process.versions.node?(c=require.nodeRequire("fs"),l.get=function(e,t){var n=c.readFileSync(e,"utf8");n.indexOf("\ufeff")===0&&(n=n.substring(1)),t(n)}):l.createXhr()?l.get=function(e,t,n){var r=l.createXhr();r.open("GET",e,!0),f.onXhr&&f.onXhr(r,e),r.onreadystatechange=function(i){var s,o;r.readyState===4&&(s=r.status,s>399&&s<600?(o=new Error(e+" HTTP status: "+s),o.xhr=r,n(o)):t(r.responseText))},r.send(null)}:typeof Packages!="undefined"&&(l.get=function(e,t){var n="utf-8",r=new java.io.File(e),i=java.lang.System.getProperty("line.separator"),s=new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(r),n)),o,u,a="";try{o=new java.lang.StringBuffer,u=s.readLine(),u&&u.length()&&u.charAt(0)===65279&&(u=u.substring(1)),o.append(u);while((u=s.readLine())!==null)o.append(i),o.append(u);a=String(o.toString())}finally{s.close()}t(a)}),l})
|
|
@ -0,0 +1,511 @@
|
|||
/*global cat,cd,cp,env,exec,echo,find,ls,mkdir,mv,pwd,rm,sed,target*/
|
||||
|
||||
var path = require( "path" ),
|
||||
spawn = require('child_process').spawn,
|
||||
normalize = function( p ){ return '"' + path.normalize( p ) + '"'; },
|
||||
join = path.join,
|
||||
// Make Windows happy, use `node <path>`
|
||||
nodeExec = function( p ){ return 'node "' + p + '"'; },
|
||||
pythonExec = function( p ){ return 'python "' + p + '"'; },
|
||||
SLICE = Array.prototype.slice,
|
||||
|
||||
JSLINT = nodeExec( normalize( "./node_modules/jshint/bin/hint" ) ),
|
||||
HTML5LINT = pythonExec( normalize( "./external/html5-lint/html5check.py" ) ),
|
||||
CSSLINT = nodeExec( normalize( "./node_modules/csslint/cli.js" ) ),
|
||||
UGLIFY = nodeExec( normalize( "./node_modules/uglify-js/bin/uglifyjs" ) ),
|
||||
RJS = nodeExec( normalize( "./node_modules/requirejs/bin/r.js" ) ),
|
||||
LESS = nodeExec( normalize( "./node_modules/less/bin/lessc" ) ),
|
||||
|
||||
SRC_DIR = 'src',
|
||||
EDITORS_DIR = 'editors',
|
||||
TEMPLATES_DIR = 'templates',
|
||||
DIST_DIR = 'dist',
|
||||
CSS_DIR = 'css',
|
||||
CORNFIELD_DIR = 'cornfield',
|
||||
PUBLIC_DIR = 'public',
|
||||
|
||||
DEFAULT_CONFIG = './src/default-config',
|
||||
|
||||
BUTTER_LESS_FILE = join( CSS_DIR, "butter.ui.less" ),
|
||||
BUTTER_CSS_FILE_COMMENT = "/* THIS FILE WAS GENERATED BY A TOOL, DO NOT EDIT. SEE .less FILE IN css/ */",
|
||||
BUTTER_CSS_FILE = join( CSS_DIR, "/butter.ui.css" ),
|
||||
BUTTER_TRANSITIONS_LESS_FILE = join( CSS_DIR, "transitions.less" ),
|
||||
BUTTER_TRANSITIONS_CSS_FILE = join( CSS_DIR, "/transitions.css" ),
|
||||
|
||||
BUTTERED_POPCORN = join( DIST_DIR, '/buttered-popcorn.js' ),
|
||||
|
||||
// We store version info about Popcorn and Butter when we deploy
|
||||
VERSIONS_CONFIG = join( CORNFIELD_DIR, 'config', 'versions.json' );
|
||||
|
||||
require('shelljs/make');
|
||||
|
||||
// Get the git repo version info for a given repo root dir
|
||||
function gitDescribe( repoRoot ) {
|
||||
var cwd = pwd();
|
||||
cd( repoRoot );
|
||||
var version = exec( 'git describe',
|
||||
{ silent: true } ).output.replace( /\r?\n/m, '' );
|
||||
cd( cwd );
|
||||
return version;
|
||||
}
|
||||
|
||||
// Write a version.json file for cornfield to use when saving data
|
||||
function publishVersionInfo( versionConfig ) {
|
||||
var defaultConfig = require( DEFAULT_CONFIG ),
|
||||
popcornDir = defaultConfig.dirs[ 'popcorn-js' ].replace( '{{baseDir}}', './' ),
|
||||
butterDir = '.';
|
||||
|
||||
JSON.stringify({
|
||||
date: (new Date()).toJSON(),
|
||||
version: env.VERSION || 'development',
|
||||
popcorn: gitDescribe( popcornDir ),
|
||||
butter: gitDescribe( butterDir )
|
||||
}, null, 2 ).to( versionConfig );
|
||||
}
|
||||
|
||||
// To supress CSS warnings/errors for a particular line, end the line
|
||||
// with a comment indicating you want CSS Lint to ignore this line's
|
||||
// error(s). Here are some examples:
|
||||
//
|
||||
// -webkit-appearance: button; /* csslint-ignore */
|
||||
// -webkit-appearance: button; /*csslint-ignore*/
|
||||
// -webkit-appearance: button; /* csslint-ignore: This is being done because of iOS ... */
|
||||
function checkCSSFile( filename, warnings, errors ) {
|
||||
var fileLines = cat( filename ).split( /\r?\n/ ),
|
||||
ignoreLines = "",
|
||||
// Look for: "blah blah blah /* csslint-ignore */" or
|
||||
// "blah blah /*csslint-ignore: this is my reason*/"
|
||||
ignoreRegex = /\/\*\s*csslint-ignore[^*]*\*\/$/,
|
||||
// Errors look like: "css/butter.ui.css: line 186, col 3, Error..."
|
||||
lineRegex = /\: line (\d+),/;
|
||||
|
||||
// Build a map of lines to ignore: "|14||27|" means ignore lines 14 and 27
|
||||
for( var i=0; i < fileLines.length; i++ ){
|
||||
if( ignoreRegex.test( fileLines[ i ] ) ) {
|
||||
ignoreLines += "|" + i + "|";
|
||||
}
|
||||
}
|
||||
|
||||
// Run CSSLint across the file, check for errors/warnings and ignore if
|
||||
// they are ones we know about from above.
|
||||
exec(CSSLINT +
|
||||
' --warnings=' + warnings +
|
||||
' --errors=' + errors +
|
||||
' --quiet --format=compact' +
|
||||
' ' + filename, { silent: true } ).output.split( /\r?\n/ )
|
||||
.forEach( function( line ) {
|
||||
if( !line ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Some warnings don't refer to a line, e.g.
|
||||
// "css/butter.ui.css: Warning - Too many floats (10)..."
|
||||
var matches = line.match( lineRegex ),
|
||||
lineNumber = matches ? matches[ 1 ] : null;
|
||||
|
||||
if( !!lineNumber ) {
|
||||
if( ignoreLines.indexOf( "|" + lineNumber + "|" ) === -1 ) {
|
||||
echo( line );
|
||||
}
|
||||
} else {
|
||||
echo( line );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkCSS( dir ) {
|
||||
// see cli.js --list-rules.
|
||||
var warnings = [
|
||||
// "important",
|
||||
// "adjoining-classes",
|
||||
// "duplicate-background-images",
|
||||
// "qualified-headings",
|
||||
// "fallback-colors",
|
||||
// "empty-rules",
|
||||
// "shorthand",
|
||||
// "overqualified-elements",
|
||||
// "import",
|
||||
// "regex-selectors",
|
||||
// "rules-count",
|
||||
// "font-sizes",
|
||||
// "universal-selector",
|
||||
// "unqualified-attributes",
|
||||
"zero-units"
|
||||
].join(",");
|
||||
|
||||
var errors = [
|
||||
"known-properties",
|
||||
"compatible-vendor-prefixes",
|
||||
"display-property-grouping",
|
||||
"duplicate-properties",
|
||||
"errors",
|
||||
"gradients",
|
||||
"font-faces",
|
||||
//"floats",
|
||||
"vendor-prefix"
|
||||
].join(",");
|
||||
|
||||
|
||||
var files = ls( dir );
|
||||
files.forEach( function( filename ) {
|
||||
filename = join( dir, filename );
|
||||
if( /\.css$/.test( filename ) ) {
|
||||
checkCSSFile( filename, warnings, errors );
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function checkJS(){
|
||||
// Takes a string or an array of strings referring to directories.
|
||||
var dirs = SLICE.call( arguments );
|
||||
|
||||
// Get all js and json files in dirs
|
||||
var files = "";
|
||||
[ /\.js$/, /\.json$/ ].forEach( function( regexp ){
|
||||
files += find( dirs ).filter( function( file ) {
|
||||
return file.match( regexp );
|
||||
}).join(' ') + ' ';
|
||||
});
|
||||
|
||||
// jshint with non-errors plus linting of json files
|
||||
exec(JSLINT + ' ' + files + ' --show-non-errors --extra-ext json');
|
||||
}
|
||||
|
||||
var desc = {
|
||||
check: 'Lint CSS, HTML, and JS',
|
||||
css: 'Build LESS files to CSS',
|
||||
deploy: 'Build Butter suitable for production',
|
||||
server: 'Run the development server'
|
||||
};
|
||||
|
||||
target.all = function() {
|
||||
echo('Please specify a target. Available targets:');
|
||||
Object.keys(target).sort().filter(function(t) {
|
||||
return t !== "all";
|
||||
}).forEach(function(t) {
|
||||
echo(' ' + t + ' - ' + desc[t]);
|
||||
});
|
||||
};
|
||||
|
||||
function clean() {
|
||||
rm('-fr', DIST_DIR);
|
||||
mkdir('-p', DIST_DIR);
|
||||
}
|
||||
|
||||
function checkHTMLFile( filename, ignoreList ) {
|
||||
var printedHeader = false,
|
||||
printFooter = false;
|
||||
|
||||
var out = exec( HTML5LINT + " -h " + filename, { silent: true } ).output;
|
||||
|
||||
if ( out ) {
|
||||
out = out.replace( "There were errors. (Tried in the text/html mode.)\n", "", "m" );
|
||||
|
||||
// Break the set of errors apart, and inspect each for
|
||||
// matches in our ignoreList. If not something we should
|
||||
// ignore, print each error.
|
||||
out.split( "\n\n" ).forEach( function( error ) {
|
||||
if ( !error.length ) {
|
||||
return;
|
||||
}
|
||||
var i = ignoreList.length,
|
||||
ignore;
|
||||
while ( i-- ) {
|
||||
ignore = ignoreList[ i ];
|
||||
// If the error string matches the ignore string, make sure
|
||||
// there isn't also a conditional when() function. If there is
|
||||
// check that too.
|
||||
if ( error.indexOf( ignore.text ) > -1 ) {
|
||||
if ( ignore.when ) {
|
||||
if ( ignore.when( filename ) ) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !printedHeader ) {
|
||||
echo( "HTML5 Lint Issues for file: " + filename + "\n" );
|
||||
printedHeader = true;
|
||||
printFooter = true;
|
||||
}
|
||||
echo( error + "\n" );
|
||||
});
|
||||
|
||||
if ( printFooter ) {
|
||||
echo( "\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkHTML() {
|
||||
// Poor-man's HTML Doc vs. Fragment check
|
||||
function isHTMLFragment( filename ) {
|
||||
return !( /<html[^>]*\>/m ).test( cat( filename ) );
|
||||
}
|
||||
|
||||
// List of errors/warnings to ignore, some with a conditional
|
||||
// to only ignore when some condition is true.
|
||||
var ignoreList = [
|
||||
{
|
||||
// Don't warn on valid docs
|
||||
text: "The document is valid HTML5 + ARIA + SVG 1.1 + MathML 2.0 (subject to the utter previewness of this service)."
|
||||
},
|
||||
{
|
||||
text: "Error: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.",
|
||||
when: isHTMLFragment
|
||||
},
|
||||
{
|
||||
text: "Error: Element “head” is missing a required instance of child element “title”.",
|
||||
when: isHTMLFragment
|
||||
},
|
||||
{
|
||||
text: "Error: Bad value “X-UA-Compatible” for attribute “http-equiv” on element “meta”."
|
||||
},
|
||||
{
|
||||
text: "Warning: The character encoding of the document was not declared."
|
||||
},
|
||||
{
|
||||
// Let <style> be in fragments.
|
||||
text: "Error: Element “style” not allowed as child of element “body” in this context. (Suppressing further errors from this subtree.)",
|
||||
when: isHTMLFragment
|
||||
}
|
||||
];
|
||||
|
||||
find([
|
||||
EDITORS_DIR,
|
||||
PUBLIC_DIR,
|
||||
join( SRC_DIR, "dialog", "dialogs" ),
|
||||
join( SRC_DIR, "layouts" ),
|
||||
join( SRC_DIR, "editor" ),
|
||||
join( SRC_DIR, "ui", "webmakernav" ),
|
||||
TEMPLATES_DIR ] ).filter( function( file ) {
|
||||
return file.match( /\.html$/ );
|
||||
}).forEach( function( filename ) {
|
||||
checkHTMLFile( filename, ignoreList );
|
||||
});
|
||||
}
|
||||
|
||||
function lessToCSS( options ){
|
||||
var compress = !!options.compress,
|
||||
lessFile = options.lessFile,
|
||||
cssFile = options.cssFile;
|
||||
|
||||
var args = compress ? " --yui-compress " : " ",
|
||||
result = exec(LESS + args + lessFile, {silent:true});
|
||||
|
||||
if( result.code === 0 ){
|
||||
var css = BUTTER_CSS_FILE_COMMENT + "\n\n" + result.output;
|
||||
css.to( cssFile );
|
||||
} else {
|
||||
echo( result.output );
|
||||
}
|
||||
}
|
||||
|
||||
function buildCSS(compress) {
|
||||
lessToCSS({
|
||||
lessFile: BUTTER_LESS_FILE,
|
||||
cssFile: BUTTER_CSS_FILE,
|
||||
compress: compress
|
||||
});
|
||||
|
||||
lessToCSS({
|
||||
lessFile: BUTTER_TRANSITIONS_LESS_FILE,
|
||||
cssFile: BUTTER_TRANSITIONS_CSS_FILE,
|
||||
compress: compress
|
||||
});
|
||||
|
||||
lessToCSS({
|
||||
lessFile: "templates/assets/plugins/wikipedia/popcorn.wikipedia.less",
|
||||
cssFile: "templates/assets/plugins/wikipedia/popcorn.wikipedia.css",
|
||||
compress: compress
|
||||
});
|
||||
|
||||
lessToCSS({
|
||||
lessFile: "templates/assets/css/jquery-ui/jquery.ui.butter.less",
|
||||
cssFile: "templates/assets/css/jquery-ui/jquery.ui.butter.css",
|
||||
compress: compress
|
||||
});
|
||||
|
||||
lessToCSS({
|
||||
lessFile: "src/ui/webmakernav/webmakernav.less",
|
||||
cssFile: "src/ui/webmakernav/webmakernav.css",
|
||||
compress: compress
|
||||
});
|
||||
|
||||
lessToCSS({
|
||||
lessFile: "css/embed.less",
|
||||
cssFile: "css/embed.css",
|
||||
compress: compress
|
||||
});
|
||||
|
||||
lessToCSS({
|
||||
lessFile: "css/embed-shell.less",
|
||||
cssFile: "css/embed-shell.css",
|
||||
compress: compress
|
||||
});
|
||||
}
|
||||
|
||||
target.check = function() {
|
||||
checkJS( 'make.js', SRC_DIR, EDITORS_DIR, CORNFIELD_DIR, TEMPLATES_DIR );
|
||||
buildCSS();
|
||||
checkCSS( CSS_DIR, TEMPLATES_DIR );
|
||||
checkHTML();
|
||||
};
|
||||
|
||||
function stampVersion( version, filename ){
|
||||
// Stamp embed.version with supplied version, or git info
|
||||
version = version || gitDescribe( "." );
|
||||
sed( '-i', '@VERSION@', version, filename );
|
||||
}
|
||||
|
||||
target.css = function() {
|
||||
buildCSS();
|
||||
};
|
||||
|
||||
function buildJS( version, compress ){
|
||||
var doCompress = compress ? "" : "optimize=none";
|
||||
var result = "";
|
||||
|
||||
result = exec(RJS + ' -o tools/build.js ' + doCompress, {silent: true});
|
||||
if (!!result.code) {
|
||||
echo(result.output);
|
||||
}
|
||||
stampVersion( version, 'dist/src/butter.js' );
|
||||
|
||||
result = exec(RJS + ' -o tools/embed.js ' + doCompress, {silent: true});
|
||||
if (!!result.code) {
|
||||
echo(result.output);
|
||||
}
|
||||
stampVersion( version, 'dist/src/embed.js' );
|
||||
}
|
||||
|
||||
target.server = function() {
|
||||
echo('### Serving butter');
|
||||
|
||||
// Write-out version info regarding Butter and Popcorn so cornfield knows what it's serving.
|
||||
publishVersionInfo( VERSIONS_CONFIG );
|
||||
|
||||
cd( CORNFIELD_DIR );
|
||||
|
||||
// Use child_process.spawn here for a long-running server process
|
||||
// (replaces `exec('node app.js', { async: true });`).
|
||||
var server = spawn( 'node', [ 'app.js' ] );
|
||||
|
||||
// Mostly stolen from http://nodejs.org/docs/v0.3.5/api/child_processes.html#child_process.spawn
|
||||
server.stdout.on( 'data', function( data ) {
|
||||
process.stdout.write( data );
|
||||
});
|
||||
|
||||
server.stderr.on( 'data', function( data ) {
|
||||
process.stderr.write( "" + data );
|
||||
});
|
||||
|
||||
server.on( 'exit', function( code ) {
|
||||
console.log( 'server process exited with code ' + code );
|
||||
});
|
||||
};
|
||||
|
||||
function butteredPopcorn() {
|
||||
var defaultConfig = require( DEFAULT_CONFIG ),
|
||||
popcornDir = defaultConfig.dirs['popcorn-js'].replace( '{{baseDir}}', './' ),
|
||||
popcornFiles = [];
|
||||
|
||||
// Popcorn License Header
|
||||
popcornFiles.push( popcornDir + '/LICENSE_HEADER' );
|
||||
|
||||
// classList shim
|
||||
popcornFiles.push( './tools/classlist-shim.js' );
|
||||
|
||||
// popcorn IE8 shim
|
||||
popcornFiles.push( popcornDir + '/ie8/popcorn.ie8.js' );
|
||||
|
||||
// popcorn.js
|
||||
popcornFiles.push( popcornDir + '/popcorn.js' );
|
||||
|
||||
// plugins
|
||||
if ( defaultConfig.plugin && defaultConfig.plugin.plugins ) {
|
||||
defaultConfig.plugin.plugins.forEach( function( plugin ){
|
||||
popcornFiles.push( plugin.path.replace( '{{baseDir}}', './' ) );
|
||||
});
|
||||
}
|
||||
|
||||
// wrapper base prototype
|
||||
popcornFiles.push( popcornDir + '/wrappers/common/popcorn._MediaElementProto.js' );
|
||||
|
||||
// wrappers
|
||||
if ( defaultConfig.wrapper && defaultConfig.wrapper.wrappers ) {
|
||||
defaultConfig.wrapper.wrappers.forEach( function( wrapper ){
|
||||
popcornFiles.push( wrapper.path.replace( '{{baseDir}}', './' ) );
|
||||
});
|
||||
}
|
||||
|
||||
// module for baseplayer
|
||||
popcornFiles.push( popcornDir + '/modules/player/popcorn.player.js' );
|
||||
|
||||
// players
|
||||
if ( defaultConfig.player && defaultConfig.player.players ) {
|
||||
defaultConfig.player.players.forEach( function( player ){
|
||||
popcornFiles.push( player.path.replace( '{{baseDir}}', './' ) );
|
||||
});
|
||||
}
|
||||
|
||||
// Stamp Popcorn.version with the git commit sha we are using
|
||||
var popcornVersion = gitDescribe( popcornDir );
|
||||
|
||||
// Write out dist/buttered-popcorn.js
|
||||
cat( popcornFiles ).to( BUTTERED_POPCORN );
|
||||
sed('-i', '@VERSION', popcornVersion, BUTTERED_POPCORN);
|
||||
}
|
||||
|
||||
target.deploy = function(){
|
||||
echo('### Making deployable versions of butter, embed, popcorn, etc. in dist/ (use UNMINIFIED=1 for unminified)');
|
||||
|
||||
// To get unminified butter.js, use the UNMINIFIED env variable:
|
||||
// $ UNMINIFIED=1 node make deploy
|
||||
var compress = env.UNMINIFIED !== "1",
|
||||
version = env.VERSION;
|
||||
|
||||
clean();
|
||||
|
||||
buildJS( version, compress );
|
||||
buildCSS( compress );
|
||||
butteredPopcorn();
|
||||
|
||||
// We'll mirror src/butter.js and src/embed.js to mimic exploded install
|
||||
mkdir('-p', './dist/src');
|
||||
|
||||
// Copy other assets over
|
||||
mkdir( join( DIST_DIR, 'css' ) );
|
||||
cp('css/*.css', join( DIST_DIR, 'css' ) );
|
||||
cp('-R', 'editors', DIST_DIR);
|
||||
cp('-R', 'resources', DIST_DIR);
|
||||
cp('-R', 'templates', DIST_DIR);
|
||||
cp('-R', 'cornfield', DIST_DIR);
|
||||
cp('package.json', 'README.md', DIST_DIR);
|
||||
|
||||
// Export will need a version of popcorn.js where the templates expect it
|
||||
// at dist/external/popcorn-js/popcorn.js
|
||||
if ( compress ) {
|
||||
exec( UGLIFY + ' --output ' + BUTTERED_POPCORN + ' ' + BUTTERED_POPCORN );
|
||||
}
|
||||
mkdir( '-p', 'dist/external/popcorn-js/' );
|
||||
mv( BUTTERED_POPCORN, './dist/external/popcorn-js/popcorn.js' );
|
||||
|
||||
// Move everything into the public folder
|
||||
cp( '-R', 'public', DIST_DIR );
|
||||
mv([ 'dist/css', 'dist/editors', 'dist/external', 'dist/resources', 'dist/src', 'dist/templates' ], 'dist/public/' );
|
||||
|
||||
// Write-out version info regarding Butter and Popcorn so cornfield knows what it's serving.
|
||||
publishVersionInfo( join( DIST_DIR, VERSIONS_CONFIG ) );
|
||||
|
||||
// Create a tar archive
|
||||
var tarName = 'butter-' + gitDescribe( '.' ) + '.tar';
|
||||
exec( 'tar -cyf "' + tarName + '" dist' );
|
||||
mv( tarName, 'dist' );
|
||||
|
||||
// It's important to use the production config
|
||||
echo( 'Run cornfield with `NODE_ENV=production node app.js`' );
|
||||
};
|
|
@ -0,0 +1,265 @@
|
|||
{
|
||||
"name": "butter",
|
||||
"version": "0.9.0",
|
||||
"dependencies": {
|
||||
"shelljs": {
|
||||
"version": "0.0.6"
|
||||
},
|
||||
"jshint": {
|
||||
"version": "0.6.2",
|
||||
"dependencies": {
|
||||
"argsparser": {
|
||||
"version": "0.0.6"
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "0.0.5",
|
||||
"dependencies": {
|
||||
"lru-cache": {
|
||||
"version": "1.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"requirejs": {
|
||||
"version": "2.0.6"
|
||||
},
|
||||
"express": {
|
||||
"version": "2.5.11",
|
||||
"dependencies": {
|
||||
"connect": {
|
||||
"version": "1.9.2",
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "0.5.1"
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.2.7"
|
||||
},
|
||||
"formidable": {
|
||||
"version": "1.0.11"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.2.4"
|
||||
},
|
||||
"qs": {
|
||||
"version": "0.4.2"
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jade": {
|
||||
"version": "0.27.2",
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "0.6.1"
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"express-persona": {
|
||||
"version": "0.0.6"
|
||||
},
|
||||
"config": {
|
||||
"version": "0.4.16",
|
||||
"dependencies": {
|
||||
"js-yaml": {
|
||||
"version": "0.3.7"
|
||||
},
|
||||
"coffee-script": {
|
||||
"version": "1.3.3"
|
||||
},
|
||||
"vows": {
|
||||
"version": "0.6.4",
|
||||
"dependencies": {
|
||||
"eyes": {
|
||||
"version": "0.1.8"
|
||||
},
|
||||
"diff": {
|
||||
"version": "1.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "2.1.5"
|
||||
},
|
||||
"sequelize": {
|
||||
"version": "1.5.0",
|
||||
"dependencies": {
|
||||
"mysql": {
|
||||
"version": "0.9.6",
|
||||
"dependencies": {
|
||||
"hashish": {
|
||||
"version": "0.0.4",
|
||||
"dependencies": {
|
||||
"traverse": {
|
||||
"version": "0.6.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.2.4"
|
||||
},
|
||||
"underscore.string": {
|
||||
"version": "2.0.0"
|
||||
},
|
||||
"lingo": {
|
||||
"version": "0.0.5"
|
||||
},
|
||||
"validator": {
|
||||
"version": "0.3.9"
|
||||
},
|
||||
"moment": {
|
||||
"version": "1.1.1"
|
||||
},
|
||||
"commander": {
|
||||
"version": "0.6.1"
|
||||
},
|
||||
"generic-pool": {
|
||||
"version": "1.0.9"
|
||||
}
|
||||
}
|
||||
},
|
||||
"client-sessions": {
|
||||
"version": "0.0.9",
|
||||
"dependencies": {
|
||||
"cookies": {
|
||||
"version": "0.1.7",
|
||||
"from": "https://github.com/benadida/cookies/tarball/d2f0f0b3"
|
||||
},
|
||||
"node-proxy": {
|
||||
"version": "0.6.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"csslint": {
|
||||
"version": "0.9.9"
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "1.3.3"
|
||||
},
|
||||
"less": {
|
||||
"version": "1.3.0"
|
||||
},
|
||||
"less-middleware": {
|
||||
"version": "0.1.7",
|
||||
"dependencies": {
|
||||
"mkdirp": {
|
||||
"version": "0.3.4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"knox": {
|
||||
"version": "0.3.1",
|
||||
"dependencies": {
|
||||
"mime": {
|
||||
"version": "1.2.7"
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-uuid": {
|
||||
"version": "1.3.3"
|
||||
},
|
||||
"supertest": {
|
||||
"version": "0.3.1",
|
||||
"dependencies": {
|
||||
"superagent": {
|
||||
"version": "0.9.5",
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "0.4.2"
|
||||
},
|
||||
"formidable": {
|
||||
"version": "1.0.9"
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.2.5"
|
||||
},
|
||||
"emitter-component": {
|
||||
"version": "0.0.5"
|
||||
},
|
||||
"cookiejar": {
|
||||
"version": "1.3.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"methods": {
|
||||
"version": "0.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tap": {
|
||||
"version": "0.3.1",
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"yamlish": {
|
||||
"version": "0.0.5"
|
||||
},
|
||||
"slide": {
|
||||
"version": "1.1.3"
|
||||
},
|
||||
"runforcover": {
|
||||
"version": "0.0.2",
|
||||
"dependencies": {
|
||||
"bunker": {
|
||||
"version": "0.1.2",
|
||||
"dependencies": {
|
||||
"burrito": {
|
||||
"version": "0.2.12",
|
||||
"dependencies": {
|
||||
"traverse": {
|
||||
"version": "0.5.2"
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "1.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"nopt": {
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"abbrev": {
|
||||
"version": "1.0.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.3.4"
|
||||
},
|
||||
"difflet": {
|
||||
"version": "0.2.3",
|
||||
"dependencies": {
|
||||
"traverse": {
|
||||
"version": "0.6.3"
|
||||
},
|
||||
"charm": {
|
||||
"version": "0.0.8"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deep-equal": {
|
||||
"version": "0.0.0"
|
||||
},
|
||||
"buffer-equal": {
|
||||
"version": "0.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
{
|
||||
"name": "butter",
|
||||
"version": "0.9.0",
|
||||
"author": "The Mozilla Popcorn Team <dev-popcorn@lists.mozilla.org>",
|
||||
"description": "The Popcorn authoring tool",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Brett Gaylor",
|
||||
"email": "brett@mozillafoundation.org "
|
||||
},
|
||||
{
|
||||
"name": "Bobby Richter",
|
||||
"email": "secretrobotron@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "David Seifried",
|
||||
"email": "david.c.seifried@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Christopher De Cairos",
|
||||
"email": "chris@chrisdecairos.ca"
|
||||
},
|
||||
{
|
||||
"name": "Matthew Schranz",
|
||||
"email": "schranz.m@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jon Buckley",
|
||||
"email": "jon@jbuckley.ca"
|
||||
},
|
||||
{
|
||||
"name": "Scott Downe",
|
||||
"email": "scott.downe@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Mohammed Buttu",
|
||||
"email": "mohammedbuttu@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Kate Hudson",
|
||||
"email": "katehudsondesign@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Ben Moskowitz",
|
||||
"email": "benrito@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "David Humphrey",
|
||||
"email": "david.humphrey@senecacollege.ca"
|
||||
},
|
||||
{
|
||||
"name": "Jeremy Banks",
|
||||
"email": "jeremy@jeremybanks.ca"
|
||||
},
|
||||
{
|
||||
"name": "Brian Chirls",
|
||||
"email": "brian@chirls.com"
|
||||
},
|
||||
{
|
||||
"name": "James Burke",
|
||||
"email": "jrburke@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Robert Stanica",
|
||||
"email": "robertstanica@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Chris Appleton",
|
||||
"email": "christopher@mozillafoundation.org"
|
||||
},
|
||||
{
|
||||
"name": "Cory Shaw",
|
||||
"email": "c@ocupop.com"
|
||||
},
|
||||
{
|
||||
"name": "Michael Nieling",
|
||||
"email": "m@ocupop.com"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mozilla/butter.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"shelljs": "0.0.6",
|
||||
"jshint": "0.6.2",
|
||||
"requirejs": "2.0.6",
|
||||
"express": "2.5.11",
|
||||
"jade": "0.27.2",
|
||||
"express-persona": "~0.0.6",
|
||||
"config": "0.4.16",
|
||||
"sqlite3": "~2.1.5",
|
||||
"sequelize": "~1.5.0",
|
||||
"client-sessions": "0.0.9",
|
||||
"csslint": "0.9.9",
|
||||
"uglify-js": "1.3.3",
|
||||
"less": "1.3.0",
|
||||
"less-middleware": "~0.1.7",
|
||||
"knox": "0.3.1",
|
||||
"node-uuid": "1.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tap": "~0.3.1",
|
||||
"supertest": "~0.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./node_modules/.bin/tap cornfield/test/*.test.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engine": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
}
|
После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1,227 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-US" dir="ltr" class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mozilla Popcorn</title>
|
||||
<link rel="stylesheet" href="media/css/sandstone.css">
|
||||
<link rel="stylesheet" href="media/css/page.css">
|
||||
<link href="//www.mozilla.org/tabzilla/media/css/tabzilla.css" rel="stylesheet">
|
||||
<!--[if lt IE 9]>
|
||||
<script src="/media/js/html5shiv.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body id="home">
|
||||
<script type="text/javascript">
|
||||
document.documentElement.className = document.documentElement.className.replace(/\bno-js\b/, '');
|
||||
</script>
|
||||
<div id="outer-wrapper">
|
||||
<div id="wrapper">
|
||||
<section id="header">
|
||||
<header id="masthead">
|
||||
<div class="row">
|
||||
<div class="span10">
|
||||
<div class="logo">
|
||||
<a href="/en-US/">
|
||||
<img src="/popcornlogo-small.png" alt="Mozilla Popcorn">
|
||||
</a>
|
||||
</div>
|
||||
<a href="http://www.mozilla.org/" id="tabzilla">Mozilla</a>
|
||||
<nav id="nav-main" role="navigation">
|
||||
<ul>
|
||||
<li class="home"><a href="/">Home</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="container divider">
|
||||
<div class="row">
|
||||
<div class="hero-unit span6">
|
||||
<hgroup class="large">
|
||||
<h2>Video beyond the box</h2>
|
||||
<h1>Popcorn Maker</h1>
|
||||
</hgroup>
|
||||
<p>
|
||||
Popcorn Maker makes it easy to enhance, remix and share web video. Use your web browser to combine video and audio with content from the rest of the web — from text, links and maps to pictures and live feeds.
|
||||
</p>
|
||||
<p>
|
||||
Use Popcorn Maker to create your own interactive newscasts, pop-up videos, multimedia reports, fan videos, guided web tours and more. Remix your favorite videos on YouTube or sounds on SoundCloud, add your own comments and links, or drag and drop in content from across the web.
|
||||
</p>
|
||||
<p>
|
||||
The result is a whole new way to tell stories on the web, with videos that are dynamic, full of links, and unique each time you watch them. It's video beyond the box.
|
||||
</p>
|
||||
<p class="intro-bar">
|
||||
<a class="button-blue start" href="/templates/basic">Start from scratch</a>
|
||||
<em>or</em>
|
||||
<a class="button start" href="#">Take a tutorial</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<video controls preload="none" width="344" height="232"
|
||||
poster="media/img/poster.png">
|
||||
<source src="http://videos.mozilla.org/serv/webmademovies/popcornsite.webm" type="video/webm">
|
||||
<source src="http://videos.mozilla.org/serv/webmademovies/popcornsite.mp4" type="video/mp4">
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span10">
|
||||
<h2>Remix and explore these great projects made with Popcorn Maker:</h2>
|
||||
|
||||
<div id="projects" class="carousel">
|
||||
<a class="control left"><span>prev</span></a>
|
||||
<a class="control right"><span>next</span></a>
|
||||
<div class="carousel-items">
|
||||
<ul>
|
||||
<li>
|
||||
<div class="thumbnail">
|
||||
<a href="/templates/basic/?savedDataUrl=tour.json">
|
||||
<img src="http://placehold.it/240x147" alt="">
|
||||
</a>
|
||||
<div class="caption">
|
||||
<p>by Mozilla</p>
|
||||
<h5 class="title"><a href="/templates/basic/?savedDataUrl=tour.json">Neighbourhood Tour</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="thumbnail">
|
||||
<a href="/templates/basic/?savedDataUrl=tour.json">
|
||||
<img src="http://placehold.it/240x147" alt="">
|
||||
</a>
|
||||
<div class="caption">
|
||||
<p>by Mozilla</p>
|
||||
<h5 class="title"><a href="/templates/basic/?savedDataUrl=soundscape.json">Soundscape</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div class="thumbnail">
|
||||
<a href="/templates/basic/?savedDataUrl=meme.json">
|
||||
<img src="http://placehold.it/240x147" alt="">
|
||||
</a>
|
||||
<div class="caption">
|
||||
<p>by Mozilla</p>
|
||||
<h5 class="title"><a href="/templates/basic/?savedDataUrl=meme.json">Video Meme</a></h5>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<a class="more" href="#">See all projects...</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="span10">
|
||||
<ul class="thumbnails">
|
||||
<li class="span3 threeColumn">
|
||||
<div class="action">
|
||||
<a href="http://popcornjs.org">
|
||||
<img src="http://placehold.it/147x147" alt="">
|
||||
</a>
|
||||
<div class="caption">
|
||||
<h5 class="title">
|
||||
<a href="http://popcornjs.org">Create advanced experiences with Popcorn.js</a>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="span3 threeColumn">
|
||||
<div class="action">
|
||||
<a href="http://blog.mozilla.org/popcorn/">
|
||||
<img src="http://placehold.it/147x147" alt="">
|
||||
</a>
|
||||
<div class="caption">
|
||||
<h5 class="title">
|
||||
<a href="http://blog.mozilla.org/popcorn/">Read the Popcorn Blog</a>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="span3 threeColumn">
|
||||
<div class="action">
|
||||
<a href="http://yeswecanhas.com/files/2008/02/bammacat.jpg">
|
||||
<img src="http://placehold.it/147x147" alt="">
|
||||
</a>
|
||||
<div class="caption">
|
||||
<h5 class="title">
|
||||
<a href="http://yeswecanhas.com/files/2008/02/bammacat.jpg">Some sort of get involved link here</a>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="page-bottom">
|
||||
<footer id="colophon">
|
||||
<div class="row">
|
||||
<div class="span2">
|
||||
<h2><img src="/media/img/footer-logo.png" alt="Mozilla Webmaker"></h2>
|
||||
</div>
|
||||
|
||||
<nav class="span2">
|
||||
<h3>About</h3>
|
||||
<ul>
|
||||
<li><a href="mailto:mozparty@mozilla.org">Contact Us</a></li>
|
||||
<li><a href="//www.mozilla.org/en-US/privacy-policy">Privacy Policy</a></li>
|
||||
<li><a href="//www.mozilla.org/en-US/about/legal.html">Legal Notices</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<nav class="span2">
|
||||
<h3>Connect with us</h3>
|
||||
<ul>
|
||||
<li><a href="http://twitter.com/mozilla/">Twitter</a></li>
|
||||
<li><a href="https://www.facebook.com/mozilla/">Facebook</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<nav class="span2">
|
||||
<h3>Make something</h3>
|
||||
<ul>
|
||||
<li><a href="#">Projects</a></li>
|
||||
<li><a href="https://webmaker.org/tools/">Tools</a></li>
|
||||
<li><a href="https://webmaker.org/events/">Events</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<nav class="span2">
|
||||
<h3>Support our work</h3>
|
||||
<ul>
|
||||
<li><a href="https://donate.mozilla.org/page/contribute/join-mozilla?source=join_link">Donate</a></li>
|
||||
<li><a href="https://mozillalabs.com/en-US/">Contribute</a></li>
|
||||
<li><a href="https://donate.mozilla.org/page/contribute/firefoxtshirt">Buy a t-shirt</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="//www.mozilla.org/media/js/libs/jquery-1.7.1.min.js"></script>
|
||||
<script src="//www.mozilla.org/tabzilla/media/js/tabzilla.js"></script>
|
||||
<script src="media/js/jcarousellite_1.0.1.min.js"></script>
|
||||
<script>
|
||||
$(function(){
|
||||
$('#projects .carousel-items').jCarouselLite({
|
||||
btnNext: '.right',
|
||||
btnPrev: '.left',
|
||||
circular: true,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
После Ширина: | Высота: | Размер: 6.1 KiB |
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
Webpage Maker Styles
|
||||
================================
|
||||
Global styles and classes
|
||||
*/
|
||||
|
||||
body {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.threeColumn {
|
||||
margin-left: 47px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-size: 36px;
|
||||
color: rgb(109, 110, 113);
|
||||
font-weight: 100;
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-size: 16px;
|
||||
color: rgb(109, 110, 113);
|
||||
font-weight: 500;
|
||||
line-height: 23px
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: "Open Sans",sans-serif;
|
||||
font-size: 13px;
|
||||
color: rgb(147, 149, 152);
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.hero-unit h2 {
|
||||
text-transform: lowercase;
|
||||
font-style: italic;
|
||||
line-height: 50px;
|
||||
font-family: "Open Sans Light", sans-serif;
|
||||
}
|
||||
|
||||
.hero-unit h1 {
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a.top,
|
||||
a.top:link,
|
||||
a.top:visited,
|
||||
a.top:hover,
|
||||
a.top:active {
|
||||
color: #666;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
a.top:before {
|
||||
content: "⇧ ";
|
||||
}
|
||||
|
||||
.more {
|
||||
float: right;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.large,
|
||||
.large h1 {
|
||||
font-size: 58px;
|
||||
}
|
||||
|
||||
/*
|
||||
Global styles and classes
|
||||
================================
|
||||
Layout styles
|
||||
*/
|
||||
|
||||
#outer-wrapper {
|
||||
border-top: 1px;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
background: #F9F9F9 url("/media/img/bg-stone.png") repeat-x 0 70px;
|
||||
padding-bottom: 0;
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#test-ribbon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#tabzilla-panel {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#header {
|
||||
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .5);
|
||||
-moz-box-shadow: 0 0 5px rgba(0,0,0,.5);
|
||||
-ms-box-shadow: 0 0 5px rgba(0,0,0,.5);
|
||||
-o-box-shadow: 0 0 5px rgba(0,0,0,.5);
|
||||
box-shadow: 0 0 5px
|
||||
rgba(0, 0, 0, .5);
|
||||
background: #FFF;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#masthead {
|
||||
margin-bottom: 90px;
|
||||
}
|
||||
|
||||
#masthead .row {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-size: 2.2em;
|
||||
font-weight: 200;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.logo a,
|
||||
.logo a:link,
|
||||
.logo a:visited,
|
||||
.logo a:hover,
|
||||
.logo a:active
|
||||
{
|
||||
color: #4d4d4d;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
margin-right: 20px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.logo img {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
#masthead nav {
|
||||
float: none;
|
||||
}
|
||||
|
||||
#masthead nav ul li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#nav-main a:hover,
|
||||
#nav-main a:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#nav-main ul {
|
||||
height: 70px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#masthead #nav-main li a {
|
||||
-webkit-transition: all .25s linear 0s;
|
||||
-moz-transition: all .25s linear 0s;
|
||||
-ms-transition: all .25s linear 0s;
|
||||
-o-transition: all .25s linear 0s;
|
||||
transition: all .25s linear 0s;
|
||||
display: block;
|
||||
min-width: 70px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
margin: 0 0 0 -1px;
|
||||
padding: 0 15px;
|
||||
float: left;
|
||||
text-align: center;
|
||||
border: solid #E1E2E3;
|
||||
border-width: 0 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#nav-main li a:hover {
|
||||
background: rgba(28,144,193,0.1);
|
||||
}
|
||||
|
||||
#home #nav-main .home a {
|
||||
background: #4199D6;
|
||||
color: #FFF;
|
||||
border: none;
|
||||
margin-right: 1px;
|
||||
text-shadow: -1px -1px #347DB0;
|
||||
}
|
||||
|
||||
#home #nav-main .home a:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
border: solid transparent;
|
||||
border-width: 25px 50px 0 50px;
|
||||
border-top-color: #4199D6;
|
||||
}
|
||||
|
||||
#page-bottom {
|
||||
background-color: #fff;
|
||||
border-top: solid 1px #E1E2E3;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
#colophon {
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
#colophon h2 {
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: 100;
|
||||
color: #999;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
#colophon h3 {
|
||||
color: #999;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
#colophon a,
|
||||
#colophon a:link,
|
||||
#colophon a:visited,
|
||||
#colophon a:hover,
|
||||
#colophon a:active {
|
||||
color: #27AAE1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*
|
||||
Layout styles
|
||||
================================
|
||||
Home styles
|
||||
*/
|
||||
|
||||
#home .caption p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.thumbnail img {
|
||||
width: 240px;
|
||||
height: 147px;
|
||||
border: 6px solid white;
|
||||
-webkit-box-shadow: 0 2px 2px 3px rgba(0, 0, 0, 0.1);
|
||||
-moz-box-shadow: 0 2px 2px 3px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2px 2px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.thumbnails {
|
||||
margin-left: -24px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.action {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
Home styles
|
||||
================================
|
||||
Carousel styles
|
||||
*/
|
||||
|
||||
.carousel {
|
||||
position: relative;
|
||||
}
|
||||
.carousel li {
|
||||
margin: 0 10px;
|
||||
}
|
||||
.carousel .control {
|
||||
position: absolute;
|
||||
top: 70px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: url(/media/img/slider-arrows.png) no-repeat;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
.carousel .control span {
|
||||
visibility: hidden;
|
||||
}
|
||||
.carousel .left {
|
||||
left: 0;
|
||||
background-position: 0 0;
|
||||
}
|
||||
.carousel .left:hover {
|
||||
background-position: 0 -50px;
|
||||
}
|
||||
.carousel .left:active {
|
||||
background-position: 0 -100px;
|
||||
}
|
||||
.carousel .right {
|
||||
right: 0;
|
||||
background-position: -50px 0;
|
||||
}
|
||||
.carousel .right:hover {
|
||||
background-position: -50px -50px;
|
||||
}
|
||||
.carousel .right:active {
|
||||
background-position: -50px -100px;
|
||||
}
|
||||
.carousel .carousel-items {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.no-js .carousel .control {
|
||||
display: none;
|
||||
}
|
||||
.no-js .carousel ul {
|
||||
list-style: none;
|
||||
margin-left: -24px;
|
||||
}
|
||||
.no-js .carousel li {
|
||||
float: left;
|
||||
margin-left: 47px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Carousel styles
|
||||
================================
|
||||
*/
|
|
@ -0,0 +1,496 @@
|
|||
/*
|
||||
* Based on bootstrap, Copyright 2012 Twitter, Inc
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
html,
|
||||
body,
|
||||
div,
|
||||
span,
|
||||
object,
|
||||
iframe,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
a,
|
||||
abbr,
|
||||
address,
|
||||
cite,
|
||||
code,
|
||||
del,
|
||||
dfn,
|
||||
em,
|
||||
img,
|
||||
ins,
|
||||
kbd,
|
||||
q,
|
||||
samp,
|
||||
small,
|
||||
strong,
|
||||
sub,
|
||||
sup,
|
||||
var,
|
||||
b,
|
||||
i,
|
||||
hr,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
ol,
|
||||
ul,
|
||||
li,
|
||||
fieldset,
|
||||
form,
|
||||
label,
|
||||
legend,
|
||||
table,
|
||||
caption,
|
||||
tbody,
|
||||
tfoot,
|
||||
thead,
|
||||
tr,
|
||||
th,
|
||||
td,
|
||||
article,
|
||||
aside,
|
||||
canvas,
|
||||
details,
|
||||
figure,
|
||||
figcaption,
|
||||
hgroup,
|
||||
menu,
|
||||
footer,
|
||||
header,
|
||||
nav,
|
||||
section,
|
||||
summary,
|
||||
time,
|
||||
mark,
|
||||
audio,
|
||||
video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
article,
|
||||
aside,
|
||||
canvas,
|
||||
figure,
|
||||
figure img,
|
||||
figcaption,
|
||||
hgroup,
|
||||
footer,
|
||||
header,
|
||||
nav,
|
||||
section,
|
||||
audio,
|
||||
video {
|
||||
display: block;
|
||||
}
|
||||
a img {
|
||||
border: 0;
|
||||
}
|
||||
/* {{{ Basic Colors, Text, Links */
|
||||
html {
|
||||
background: #fff;
|
||||
}
|
||||
body {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
color: #333333;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.button, .button:link, .button:visited {
|
||||
-moz-transition -webkit-transition -o-transition -ms-transition transition: all 0.25s linear 0s;
|
||||
background-color: #659324;
|
||||
background-image: -moz-linear-gradient(#81BC2E, #659324);
|
||||
background-repeat: repeat-x;
|
||||
border: 0 none;
|
||||
border-radius: 0.25em 0.25em 0.25em 0.25em;
|
||||
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.1), 0 -2px 0 0 rgba(0, 0, 0, 0.2) inset;
|
||||
color: #FFFFFF;
|
||||
display: inline-block;
|
||||
font-family: 'OpenSansRegular',sans-serif;
|
||||
font-size: 14px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
padding: 0 24px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.button:hover, .button:link:hover, .button:visited:hover {
|
||||
-moz-transition -webkit-transition -o-transition -ms-transition transition: all 0.25s linear 0s;
|
||||
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.1), 0 -2px 0 0 rgba(0, 0, 0, 0.2) inset, 0 12px 24px 2px #83C822 inset;
|
||||
color: #FFFFFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button:active, .button:link:active, .button:visited:active {
|
||||
-moz-transition -webkit-transition -o-transition -ms-transition transition: all 0.25s linear 0s;
|
||||
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2) inset, 0 12px 24px 6px rgba(0, 0, 0, 0.2) inset, 0 0 2px 2px rgba(0, 0, 0, 0.2) inset;
|
||||
color: #FFFFFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button-blue, .button-blue:link, .button-blue:visited {
|
||||
-moz-transition -webkit-transition -o-transition -ms-transition transition: all 0.25s linear 0s;
|
||||
background-color: #276195;
|
||||
background-image: -moz-linear-gradient(#3C88CC, #276195);
|
||||
background-repeat: repeat-x;
|
||||
border: 0 none;
|
||||
border-radius: 0.25em 0.25em 0.25em 0.25em;
|
||||
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.1), 0 -2px 0 0 rgba(0, 0, 0, 0.2) inset;
|
||||
color: #FFFFFF;
|
||||
display: inline-block;
|
||||
font-family: 'OpenSansRegular',sans-serif;
|
||||
font-size: 14px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
padding: 0 24px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.button-blue:hover, .button-blue:link:hover, .button-blue:visited:hover {
|
||||
-moz-transition -webkit-transition -o-transition -ms-transition transition: all 0.25s linear 0s;
|
||||
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.1), 0 -2px 0 0 rgba(0, 0, 0, 0.2) inset, 0 12px 24px 2px #83C822 inset;
|
||||
color: #FFFFFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button-blue:active, .button-blue:link:active, .button-blue:visited:active {
|
||||
-moz-transition -webkit-transition -o-transition -ms-transition transition: all 0.25s linear 0s;
|
||||
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2) inset, 0 12px 24px 6px rgba(0, 0, 0, 0.2) inset, 0 0 2px 2px rgba(0, 0, 0, 0.2) inset;
|
||||
color: #FFFFFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button-blue small, .button-blue:link small, .button-blue:visited small {
|
||||
display: block;
|
||||
}
|
||||
.button-blue:hover, .button-blue:link:hover, .button-blue:visited:hover {
|
||||
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.1), 0 -2px 0 0 rgba(0, 0, 0, 0.2) inset, 0 12px 24px 2px #3089D8 inset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#outer-wrapper {
|
||||
border-top: 2px solid #fff;
|
||||
}
|
||||
#wrapper {
|
||||
background: #f9f9f9 url(/media/img/bg-stone.png) 0 0 repeat-x;
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
a {
|
||||
color: #2983c8;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover,
|
||||
a:active {
|
||||
color: #20679e;
|
||||
text-decoration: underline;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
.huge,
|
||||
.large {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 100;
|
||||
display: block;
|
||||
margin: 0 0 12px 0;
|
||||
line-height: 100%;
|
||||
text-shadow: 0px 1px 0px rgba(255, 255, 255, 0.75);
|
||||
color: #484848;
|
||||
}
|
||||
.huge,
|
||||
.huge h1 {
|
||||
font-size: 108px;
|
||||
letter-spacing: -4px;
|
||||
line-height: 100%;
|
||||
}
|
||||
.large,
|
||||
.large h1 {
|
||||
font-size: 72px;
|
||||
letter-spacing: -3px;
|
||||
line-height: 100%;
|
||||
}
|
||||
h1,
|
||||
.huge h2,
|
||||
.large h2,
|
||||
.billboard h2 {
|
||||
font-size: 48px;
|
||||
letter-spacing: -2px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 32px;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 28px;
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
h4 {
|
||||
font-size: 24px;
|
||||
letter-spacing: -0.25px;
|
||||
}
|
||||
h5 {
|
||||
font-size: 16px;
|
||||
}
|
||||
h6 {
|
||||
font-size: 14px;
|
||||
}
|
||||
hgroup h1,
|
||||
hgroup h2,
|
||||
hgroup h3,
|
||||
hgroup h4,
|
||||
hgroup h5,
|
||||
hgroup h6 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
dl,
|
||||
hgroup {
|
||||
margin: 0 0 24px 0;
|
||||
}
|
||||
li {
|
||||
margin-left: 24px;
|
||||
}
|
||||
/* }}} */
|
||||
/* {{{ Layout */
|
||||
.row {
|
||||
margin-left: -24px;
|
||||
zoom: 1;
|
||||
}
|
||||
.row:after {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
clear: both;
|
||||
content: ".";
|
||||
}
|
||||
[class*="span"] {
|
||||
float: left;
|
||||
margin-left: 24px;
|
||||
}
|
||||
.span1 {
|
||||
width: 68px;
|
||||
}
|
||||
.span2 {
|
||||
width: 160px;
|
||||
}
|
||||
.span3 {
|
||||
width: 252px;
|
||||
}
|
||||
.span4 {
|
||||
width: 344px;
|
||||
}
|
||||
.span5 {
|
||||
width: 436px;
|
||||
}
|
||||
.span6 {
|
||||
width: 528px;
|
||||
}
|
||||
.span7 {
|
||||
width: 620px;
|
||||
}
|
||||
.span8 {
|
||||
width: 712px;
|
||||
}
|
||||
.span9 {
|
||||
width: 804px;
|
||||
}
|
||||
.span10 {
|
||||
width: 896px;
|
||||
}
|
||||
.span11 {
|
||||
width: 988px;
|
||||
}
|
||||
.span12,
|
||||
.container {
|
||||
width: 1080px;
|
||||
}
|
||||
.offset1 {
|
||||
margin-left: 116px;
|
||||
}
|
||||
.offset2 {
|
||||
margin-left: 208px;
|
||||
}
|
||||
.offset3 {
|
||||
margin-left: 300px;
|
||||
}
|
||||
.offset4 {
|
||||
margin-left: 392px;
|
||||
}
|
||||
.offset5 {
|
||||
margin-left: 484px;
|
||||
}
|
||||
.offset6 {
|
||||
margin-left: 576px;
|
||||
}
|
||||
.offset7 {
|
||||
margin-left: 668px;
|
||||
}
|
||||
.offset8 {
|
||||
margin-left: 760px;
|
||||
}
|
||||
.offset9 {
|
||||
margin-left: 852px;
|
||||
}
|
||||
.offset10 {
|
||||
margin-left: 944px;
|
||||
}
|
||||
.offset11 {
|
||||
margin-left: 1036px;
|
||||
}
|
||||
#main-content,
|
||||
#main-feature {
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
.main-column {
|
||||
float: left;
|
||||
margin-left: 24px;
|
||||
width: 528px;
|
||||
}
|
||||
.sidebar {
|
||||
float: left;
|
||||
margin-left: 24px;
|
||||
width: 160px;
|
||||
margin-left: 208px;
|
||||
}
|
||||
.divider.container,
|
||||
.divider {
|
||||
border-bottom: 1px dotted #d6d6d6;
|
||||
padding-bottom: 48px;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
.divider-last.container,
|
||||
.divider-last {
|
||||
border-bottom: 0;
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
/* }}} */
|
||||
/* {{{ Less Framework Grid */
|
||||
/* Default Layout: 992px.
|
||||
Gutters: 24px.
|
||||
Outer margins: 48px.
|
||||
Leftover space for scrollbars @1024px: 32px.
|
||||
-------------------------------------------------------------------------------
|
||||
cols 1 2 3 4 5 6 7 8 9 10
|
||||
px 68 160 252 344 436 528 620 712 804 896 */
|
||||
#masthead,
|
||||
#main-feature,
|
||||
#main-content,
|
||||
#colophon,
|
||||
.billboard,
|
||||
.container {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
padding-left: 48px;
|
||||
padding-right: 48px;
|
||||
position: relative;
|
||||
width: 896px;
|
||||
zoom: 1;
|
||||
}
|
||||
#masthead:after,
|
||||
#main-feature:after,
|
||||
#main-content:after,
|
||||
#colophon:after,
|
||||
.billboard:after,
|
||||
.container:after {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
clear: both;
|
||||
content: ".";
|
||||
}
|
||||
/* }}} */
|
||||
/* {{{ Header Nav */
|
||||
#masthead h2 {
|
||||
padding: 48px 0 36px 0;
|
||||
margin: 0;
|
||||
}
|
||||
#masthead nav {
|
||||
float: right;
|
||||
margin-right: 16px;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
#masthead nav ol li,
|
||||
#masthead nav ul li {
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
*zoom: 1;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
}
|
||||
#masthead nav ol li a,
|
||||
#masthead nav ul li a,
|
||||
#masthead nav ol li b,
|
||||
#masthead nav ul li b {
|
||||
display: inline-block;
|
||||
padding: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
#masthead nav ol li a,
|
||||
#masthead nav ul li a,
|
||||
#masthead nav ol li a:link,
|
||||
#masthead nav ul li a:link,
|
||||
#masthead nav ol li a:visited,
|
||||
#masthead nav ul li a:visited {
|
||||
color: #484848;
|
||||
}
|
||||
/* }}} */
|
||||
/* {{{ Header Breadcrumbs */
|
||||
#masthead nav.breadcrumbs {
|
||||
padding: 12px 0;
|
||||
float: none;
|
||||
padding: 12px 0;
|
||||
}
|
||||
#masthead nav.breadcrumbs a,
|
||||
#masthead nav.breadcrumbs span {
|
||||
margin-right: .5em;
|
||||
margin-left: .5em;
|
||||
}
|
||||
#masthead nav.breadcrumbs a:first-child,
|
||||
#masthead nav.breadcrumbs span:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
/* }}} */
|
||||
/* {{{ Footer */
|
||||
#colophon {
|
||||
color: #bbbbbb;
|
||||
padding: 48px 0;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
}
|
||||
#colophon a,
|
||||
#colophon a:link,
|
||||
#colophon a:visited {
|
||||
color: #2983c8;
|
||||
}
|
||||
#colophon a:hover,
|
||||
#colophon a:active {
|
||||
color: #20679e;
|
||||
}
|
||||
#colophon nav {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
#colophon nav ol li,
|
||||
#colophon nav ul li {
|
||||
list-style-type: none;
|
||||
margin: 0 0 2px 0;
|
||||
}
|
||||
/* }}} */
|
После Ширина: | Высота: | Размер: 7.2 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 115 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
|
@ -0,0 +1,4 @@
|
|||
(function(g,b){function k(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function l(a){var c={},f=a.createElement,b=a.createDocumentFragment,d=b();a.createElement=function(a){if(!e.shivMethods)return f(a);var b;b=c[a]?c[a].cloneNode():m.test(a)?(c[a]=f(a)).cloneNode():f(a);return b.canHaveChildren&&!n.test(a)?d.appendChild(b):b};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+k().join().replace(/\w+/g,function(a){f(a);
|
||||
d.createElement(a);return'c("'+a+'")'})+");return n}")(e,d)}function h(a){var c;if(a.documentShived)return a;if(e.shivCSS&&!i){c=a.createElement("p");var b=a.getElementsByTagName("head")[0]||a.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}</style>";c=!!b.insertBefore(c.lastChild,b.firstChild)}j||(c=!l(a));if(c)a.documentShived=c;return a}var d=g.html5||{},n=/^<|^(?:button|form|map|select|textarea|object|iframe|option|optgroup)$/i,
|
||||
m=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,i,j;(function(){var a=b.createElement("a");a.innerHTML="<xyz></xyz>";i="hidden"in a;if(!(a=1==a.childNodes.length))a:{try{b.createElement("a")}catch(c){a=!0;break a}a=b.createDocumentFragment();a="undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}j=
|
||||
a})();var e={elements:d.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:!1!==d.shivCSS,shivMethods:!1!==d.shivMethods,type:"default",shivDocument:h};g.html5=e;h(b)})(this,document);
|
|
@ -0,0 +1 @@
|
|||
(function($){$.fn.jCarouselLite=function(o){o=$.extend({btnPrev:null,btnNext:null,btnGo:null,mouseWheel:false,auto:null,speed:200,easing:null,vertical:false,circular:true,visible:3,start:0,scroll:1,beforeStart:null,afterEnd:null},o||{});return this.each(function(){var b=false,animCss=o.vertical?"top":"left",sizeCss=o.vertical?"height":"width";var c=$(this),ul=$("ul",c),tLi=$("li",ul),tl=tLi.size(),v=o.visible;if(o.circular){ul.prepend(tLi.slice(tl-v-1+1).clone()).append(tLi.slice(0,v).clone());o.start+=v}var f=$("li",ul),itemLength=f.size(),curr=o.start;c.css("visibility","visible");f.css({overflow:"hidden",float:o.vertical?"none":"left"});ul.css({margin:"0",padding:"0",position:"relative","list-style-type":"none","z-index":"1"});c.css({overflow:"hidden",position:"relative","z-index":"2",left:"0px"});var g=o.vertical?height(f):width(f);var h=g*itemLength;var j=g*v;f.css({width:f.width(),height:f.height()});ul.css(sizeCss,h+"px").css(animCss,-(curr*g));c.css(sizeCss,j+"px");if(o.btnPrev)$(o.btnPrev).click(function(){return go(curr-o.scroll)});if(o.btnNext)$(o.btnNext).click(function(){return go(curr+o.scroll)});if(o.btnGo)$.each(o.btnGo,function(i,a){$(a).click(function(){return go(o.circular?o.visible+i:i)})});if(o.mouseWheel&&c.mousewheel)c.mousewheel(function(e,d){return d>0?go(curr-o.scroll):go(curr+o.scroll)});if(o.auto)setInterval(function(){go(curr+o.scroll)},o.auto+o.speed);function vis(){return f.slice(curr).slice(0,v)};function go(a){if(!b){if(o.beforeStart)o.beforeStart.call(this,vis());if(o.circular){if(a<=o.start-v-1){ul.css(animCss,-((itemLength-(v*2))*g)+"px");curr=a==o.start-v-1?itemLength-(v*2)-1:itemLength-(v*2)-o.scroll}else if(a>=itemLength-v+1){ul.css(animCss,-((v)*g)+"px");curr=a==itemLength-v+1?v+1:v+o.scroll}else curr=a}else{if(a<0||a>itemLength-v)return;else curr=a}b=true;ul.animate(animCss=="left"?{left:-(curr*g)}:{top:-(curr*g)},o.speed,o.easing,function(){if(o.afterEnd)o.afterEnd.call(this,vis());b=false});if(!o.circular){$(o.btnPrev+","+o.btnNext).removeClass("disabled");$((curr-o.scroll<0&&o.btnPrev)||(curr+o.scroll>itemLength-v&&o.btnNext)||[]).addClass("disabled")}}return false}})};function css(a,b){return parseInt($.css(a[0],b))||0};function width(a){return a[0].offsetWidth+css(a,'marginLeft')+css(a,'marginRight')};function height(a){return a[0].offsetHeight+css(a,'marginTop')+css(a,'marginBottom')}})(jQuery);
|
После Ширина: | Высота: | Размер: 7.0 KiB |
После Ширина: | Высота: | Размер: 749 KiB |
После Ширина: | Высота: | Размер: 297 B |
После Ширина: | Высота: | Размер: 24 KiB |
После Ширина: | Высота: | Размер: 1009 B |
После Ширина: | Высота: | Размер: 18 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 14 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 425 B |