From 08da6c3f848bf673610d8fd4e98ee43aff385574 Mon Sep 17 00:00:00 2001 From: Pirhoo Date: Sun, 9 Nov 2014 15:52:46 +0100 Subject: [PATCH] Hello world --- .bowerrc | 3 + .editorconfig | 13 + .gitignore | 5 + .jshintrc | 25 + .yo-rc.json | 40 + bower.json | 19 + gulp/build.js | 116 +++ gulp/e2e-tests.js | 36 + gulp/proxy.js | 65 ++ gulp/server.js | 58 ++ gulp/unit-tests.js | 31 + gulp/watch.js | 10 + gulp/wiredep.js | 23 + gulpfile.js | 9 + package.json | 44 + src/404.html | 157 ++++ src/app/bootstrap.loader.less | 51 ++ src/app/bootstrap.variables.less | 860 ++++++++++++++++++ src/app/index.js | 24 + src/app/index.less | 5 + src/app/main/main.controller.js | 48 + src/app/main/main.html | 118 +++ src/app/main/main.less | 97 ++ src/app/view/view.controller.js | 6 + src/app/view/view.html | 5 + src/app/view/view.less | 9 + src/assets/examples.json | 9 + src/assets/images/editor-bg.png | Bin 0 -> 33159 bytes .../scaffolder/scaffolder.controller.js | 26 + .../scaffolder/scaffolder.directive.js | 13 + src/components/scaffolder/scaffolder.html | 8 + src/components/scaffolder/scaffolder.less | 42 + src/favicon.ico | Bin 0 -> 4286 bytes src/index.html | 64 ++ test/e2e/main.js | 9 + test/karma.conf.js | 28 + test/protractor.conf.js | 21 + test/unit/main.js | 12 + 38 files changed, 2109 insertions(+) create mode 100644 .bowerrc create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 .yo-rc.json create mode 100644 bower.json create mode 100644 gulp/build.js create mode 100644 gulp/e2e-tests.js create mode 100644 gulp/proxy.js create mode 100644 gulp/server.js create mode 100644 gulp/unit-tests.js create mode 100644 gulp/watch.js create mode 100644 gulp/wiredep.js create mode 100644 gulpfile.js create mode 100644 package.json create mode 100644 src/404.html create mode 100644 src/app/bootstrap.loader.less create mode 100644 src/app/bootstrap.variables.less create mode 100644 src/app/index.js create mode 100644 src/app/index.less create mode 100644 src/app/main/main.controller.js create mode 100644 src/app/main/main.html create mode 100644 src/app/main/main.less create mode 100644 src/app/view/view.controller.js create mode 100644 src/app/view/view.html create mode 100644 src/app/view/view.less create mode 100644 src/assets/examples.json create mode 100644 src/assets/images/editor-bg.png create mode 100644 src/components/scaffolder/scaffolder.controller.js create mode 100644 src/components/scaffolder/scaffolder.directive.js create mode 100644 src/components/scaffolder/scaffolder.html create mode 100644 src/components/scaffolder/scaffolder.less create mode 100644 src/favicon.ico create mode 100644 src/index.html create mode 100644 test/e2e/main.js create mode 100644 test/karma.conf.js create mode 100644 test/protractor.conf.js create mode 100644 test/unit/main.js diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..69fad35 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "bower_components" +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e717f5e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a22a458 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +dist +.tmp +.sass-cache +bower_components diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..ad9dfcc --- /dev/null +++ b/.jshintrc @@ -0,0 +1,25 @@ +{ + "node": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": true, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "white": true, + "validthis": true, + "globals": { + "angular": false + } +} diff --git a/.yo-rc.json b/.yo-rc.json new file mode 100644 index 0000000..7767142 --- /dev/null +++ b/.yo-rc.json @@ -0,0 +1,40 @@ +{ + "generator-gulp-angular": { + "props": { + "angularVersion": "1.3.x", + "angularModules": [ + { + "name": "angular-sanitize", + "module": "ngSanitize", + "version": "1.3.x" + } + ], + "jQuery": { + "name": "jquery", + "version": "2.x.x" + }, + "resource": { + "name": null, + "version": "1.3.x", + "module": null + }, + "router": { + "name": "angular-ui-router", + "version": "0.2.x", + "module": "ui.router" + }, + "ui": { + "name": "bootstrap", + "version": "3.2.x", + "key": "bootstrap" + }, + "cssPreprocessor": { + "key": "less", + "extension": "less", + "npm": { + "gulp-less": "^1.3.3" + } + } + } + } +} \ No newline at end of file diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..27fb1d9 --- /dev/null +++ b/bower.json @@ -0,0 +1,19 @@ +{ + "name": "iframeScaffolder", + "version": "0.0.0", + "dependencies": { + "modernizr": "2.8.x", + "angular": "1.3.x", + "jquery": "2.x.x", + "angular-sanitize": "1.3.x", + "angular-ui-router": "0.2.x", + "bootstrap": "3.3.x", + "angular-zeroclipboard": "~0.3.2" + }, + "devDependencies": { + "angular-mocks": "1.3.x" + }, + "resolutions": { + "angular": "1.3.x" + } +} diff --git a/gulp/build.js b/gulp/build.js new file mode 100644 index 0000000..2d27262 --- /dev/null +++ b/gulp/build.js @@ -0,0 +1,116 @@ +'use strict'; + +var gulp = require('gulp'); + +var $ = require('gulp-load-plugins')({ + pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] +}); + +function handleError(err) { + console.error(err.toString()); + this.emit('end'); +} + +gulp.task('styles', ['wiredep'], function () { + return gulp.src('src/{app,components}/**/*.less') + .pipe($.less({ + paths: [ + 'src/bower_components', + 'src/app', + 'src/components' + ] + })) + .on('error', handleError) + .pipe($.autoprefixer('last 1 version')) + .pipe(gulp.dest('.tmp')) + .pipe($.size()); +}); + +gulp.task('scripts', function () { + return gulp.src('src/{app,components}/**/*.js') + .pipe($.jshint()) + .pipe($.jshint.reporter('jshint-stylish')) + .pipe($.size()); +}); + +gulp.task('partials', function () { + return gulp.src('src/{app,components}/**/*.html') + .pipe($.minifyHtml({ + empty: true, + spare: true, + quotes: true + })) + .pipe($.ngHtml2js({ + moduleName: 'iframeLayout' + })) + .pipe(gulp.dest('.tmp')) + .pipe($.size()); +}); + +gulp.task('html', ['styles', 'scripts', 'partials'], function () { + var htmlFilter = $.filter('*.html'); + var jsFilter = $.filter('**/*.js'); + var cssFilter = $.filter('**/*.css'); + var assets; + + return gulp.src('src/*.html') + .pipe($.inject(gulp.src('.tmp/{app,components}/**/*.js'), { + read: false, + starttag: '', + addRootSlash: false, + addPrefix: '../' + })) + .pipe(assets = $.useref.assets()) + .pipe($.rev()) + .pipe(jsFilter) + .pipe($.ngAnnotate()) + .pipe($.uglify({preserveComments: $.uglifySaveLicense})) + .pipe(jsFilter.restore()) + .pipe(cssFilter) + .pipe($.replace('bower_components/bootstrap/fonts','fonts')) + .pipe($.csso()) + .pipe(cssFilter.restore()) + .pipe(assets.restore()) + .pipe($.useref()) + .pipe($.revReplace()) + .pipe(htmlFilter) + .pipe($.minifyHtml({ + empty: true, + spare: true, + quotes: true + })) + .pipe(htmlFilter.restore()) + .pipe(gulp.dest('dist')) + .pipe($.size()); +}); + +gulp.task('images', function () { + return gulp.src('src/assets/images/**/*') + .pipe($.cache($.imagemin({ + optimizationLevel: 3, + progressive: true, + interlaced: true + }))) + .pipe(gulp.dest('dist/assets/images')) + .pipe($.size()); +}); + +gulp.task('fonts', function () { + return gulp.src($.mainBowerFiles()) + .pipe($.filter('**/*.{eot,svg,ttf,woff}')) + .pipe($.flatten()) + .pipe(gulp.dest('dist/fonts')) + .pipe($.size()); +}); + +gulp.task('misc', function () { + return gulp.src('src/**/*.ico') + .pipe(gulp.dest('dist')) + .pipe($.size()); +}); + +gulp.task('clean', function (done) { + $.del(['.tmp', 'dist'], done); +}); + +gulp.task('build', ['html', 'images', 'fonts', 'misc']); diff --git a/gulp/e2e-tests.js b/gulp/e2e-tests.js new file mode 100644 index 0000000..b5bb951 --- /dev/null +++ b/gulp/e2e-tests.js @@ -0,0 +1,36 @@ +'use strict'; + +var gulp = require('gulp'); + +var $ = require('gulp-load-plugins')(); + +var browserSync = require('browser-sync'); + +// Downloads the selenium webdriver +gulp.task('webdriver-update', $.protractor.webdriver_update); + +gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); + +gulp.task('protractor-only', ['webdriver-update', 'wiredep'], function (done) { + var testFiles = [ + 'test/e2e/**/*.js' + ]; + + gulp.src(testFiles) + .pipe($.protractor.protractor({ + configFile: 'test/protractor.conf.js', + })) + .on('error', function (err) { + // Make sure failed tests cause gulp to exit non-zero + throw err; + }) + .on('end', function () { + // Close browser sync server + browserSync.exit(); + done(); + }); +}); + +gulp.task('protractor', ['serve:e2e', 'protractor-only']); +gulp.task('protractor:src', ['serve:e2e', 'protractor-only']); +gulp.task('protractor:dist', ['serve:e2e-dist', 'protractor-only']); diff --git a/gulp/proxy.js b/gulp/proxy.js new file mode 100644 index 0000000..2fcd734 --- /dev/null +++ b/gulp/proxy.js @@ -0,0 +1,65 @@ + /*jshint unused:false */ + +/*************** + + This file allow to configure a proxy system plugged into BrowserSync + in order to redirect backend requests while still serving and watching + files from the web project + + IMPORTANT: The proxy is disabled by default. + + If you want to enable it, watch at the configuration options and finally + change the `module.exports` at the end of the file + +***************/ + +'use strict'; + +var httpProxy = require('http-proxy'); +var chalk = require('chalk'); + +/* + * Location of your backend server + */ +var proxyTarget = 'http://server/context/'; + +var proxy = httpProxy.createProxyServer({ + target: proxyTarget +}); + +proxy.on('error', function(error, req, res) { + res.writeHead(500, { + 'Content-Type': 'text/plain' + }); + + console.error(chalk.red('[Proxy]'), error); +}); + +/* + * The proxy middleware is an Express middleware added to BrowserSync to + * handle backend request and proxy them to your backend. + */ +function proxyMiddleware(req, res, next) { + /* + * This test is the switch of each request to determine if the request is + * for a static file to be handled by BrowserSync or a backend request to proxy. + * + * The existing test is a standard check on the files extensions but it may fail + * for your needs. If you can, you could also check on a context in the url which + * may be more reliable but can't be generic. + */ + if (/\.(html|css|js|png|jpg|jpeg|gif|ico|xml|rss|txt|eot|svg|ttf|woff|cur)(\?((r|v|rel|rev)=[\-\.\w]*)?)?$/.test(req.url)) { + next(); + } else { + proxy.web(req, res); + } +} + +/* + * This is where you activate or not your proxy. + * + * The first line activate if and the second one ignored it + */ + +//module.exports = [proxyMiddleware]; +module.exports = []; diff --git a/gulp/server.js b/gulp/server.js new file mode 100644 index 0000000..a1d9481 --- /dev/null +++ b/gulp/server.js @@ -0,0 +1,58 @@ +'use strict'; + +var gulp = require('gulp'); + +var util = require('util'); + +var browserSync = require('browser-sync'); + +var middleware = require('./proxy'); + +function browserSyncInit(baseDir, files, browser) { + browser = browser === undefined ? 'default' : browser; + + var routes = null; + if(baseDir === 'src' || (util.isArray(baseDir) && baseDir.indexOf('src') !== -1)) { + routes = { + // Should be '/bower_components': '../bower_components' + // Waiting for https://github.com/shakyShane/browser-sync/issues/308 + '/bower_components': 'bower_components' + }; + } + + browserSync.instance = browserSync.init(files, { + startPath: '/index.html', + server: { + baseDir: baseDir, + middleware: middleware, + routes: routes + }, + browser: browser + }); + +} + +gulp.task('serve', ['watch'], function () { + browserSyncInit([ + 'src', + '.tmp' + ], [ + '.tmp/{app,components}/**/*.css', + 'src/assets/images/**/*', + 'src/*.html', + 'src/{app,components}/**/*.html', + 'src/{app,components}/**/*.js' + ]); +}); + +gulp.task('serve:dist', ['build'], function () { + browserSyncInit('dist'); +}); + +gulp.task('serve:e2e', function () { + browserSyncInit(['src', '.tmp'], null, []); +}); + +gulp.task('serve:e2e-dist', ['watch'], function () { + browserSyncInit('dist', null, []); +}); diff --git a/gulp/unit-tests.js b/gulp/unit-tests.js new file mode 100644 index 0000000..b3918da --- /dev/null +++ b/gulp/unit-tests.js @@ -0,0 +1,31 @@ +'use strict'; + +var gulp = require('gulp'); + +var $ = require('gulp-load-plugins')(); + +var wiredep = require('wiredep'); + +gulp.task('test', function() { + var bowerDeps = wiredep({ + directory: 'bower_components', + exclude: ['bootstrap-sass-official'], + dependencies: true, + devDependencies: true + }); + + var testFiles = bowerDeps.js.concat([ + 'src/{app,components}/**/*.js', + 'test/unit/**/*.js' + ]); + + return gulp.src(testFiles) + .pipe($.karma({ + configFile: 'test/karma.conf.js', + action: 'run' + })) + .on('error', function(err) { + // Make sure failed tests cause gulp to exit non-zero + throw err; + }); +}); diff --git a/gulp/watch.js b/gulp/watch.js new file mode 100644 index 0000000..6780331 --- /dev/null +++ b/gulp/watch.js @@ -0,0 +1,10 @@ +'use strict'; + +var gulp = require('gulp'); + +gulp.task('watch', ['styles'] ,function () { + gulp.watch('src/{app,components}/**/*.less', ['styles']); + gulp.watch('src/{app,components}/**/*.js', ['scripts']); + gulp.watch('src/assets/images/**/*', ['images']); + gulp.watch('bower.json', ['wiredep']); +}); diff --git a/gulp/wiredep.js b/gulp/wiredep.js new file mode 100644 index 0000000..5935769 --- /dev/null +++ b/gulp/wiredep.js @@ -0,0 +1,23 @@ +'use strict'; + +var gulp = require('gulp'); + +// inject bower components +gulp.task('wiredep', function () { + var wiredep = require('wiredep').stream; + + gulp.src('src/{app,components}/*.scss') + .pipe(wiredep({ + directory: 'bower_components', + ignorePath: /^\/|\.\.\// + })) + .pipe(gulp.dest('src')); + + gulp.src('src/*.html') + .pipe(wiredep({ + directory: 'bower_components', + exclude: ['bootstrap'], + ignorePath: /^\/|\.\.\// + })) + .pipe(gulp.dest('src')); +}); diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..9670cf3 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,9 @@ +'use strict'; + +var gulp = require('gulp'); + +require('require-dir')('./gulp'); + +gulp.task('default', ['clean'], function () { + gulp.start('build'); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..54b2f5d --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "iframeScaffolder", + "version": "0.0.0", + "dependencies": {}, + "devDependencies": { + "gulp": "^3.8.0", + "gulp-autoprefixer": "^0.0.6", + "gulp-cache": "^0.2.0", + "del": "^0.1.3", + "gulp-csso": "^0.2.6", + "gulp-filter": "^1.0.0", + "gulp-flatten": "^0.0.2", + "gulp-imagemin": "^1.0.0", + "gulp-jshint": "^1.8.0", + "gulp-load-plugins": "^0.6.0", + "gulp-size": "^1.1.0", + "gulp-uglify": "^1.0.0", + "gulp-useref": "^1.0.0", + "gulp-ng-annotate": "^0.3.0", + "gulp-replace": "^0.4.0", + "gulp-rev": "^1.1.0", + "gulp-rev-replace": "^0.3.0", + "gulp-ng-html2js": "^0.1.6", + "gulp-minify-html": "^0.1.3", + "gulp-inject": "^1.0.0", + "gulp-protractor": "^0.0.11", + "gulp-karma": "^0.0.4", + "main-bower-files": "^2.0.0", + "jshint-stylish": "^0.4.0", + "wiredep": "^1.8.5", + "karma-jasmine": "^0.1.5", + "karma-phantomjs-launcher": "^0.1.4", + "require-dir": "^0.1.0", + "browser-sync": "^1.3.6", + "http-proxy": "^1.3.0", + "chalk": "^0.4.0", + "protractor": "^1.1.1", + "uglify-save-license": "^0.4.1", + "gulp-less": "^1.3.3" + }, + "engines": { + "node": ">=0.10.0" + } +} diff --git a/src/404.html b/src/404.html new file mode 100644 index 0000000..fdace4a --- /dev/null +++ b/src/404.html @@ -0,0 +1,157 @@ + + + + + Page Not Found :( + + + +
+

Not found :(

+

Sorry, but the page you were trying to view does not exist.

+

It looks like this was the result of either:

+ + + +
+ + diff --git a/src/app/bootstrap.loader.less b/src/app/bootstrap.loader.less new file mode 100644 index 0000000..e802e56 --- /dev/null +++ b/src/app/bootstrap.loader.less @@ -0,0 +1,51 @@ +// Core variables and mixins +@import "bootstrap.variables.less"; +@import "../../bower_components/bootstrap/less/mixins.less"; + +// Reset and dependencies +@import "../../bower_components/bootstrap/less/normalize.less"; +@import "../../bower_components/bootstrap/less/print.less"; +@import "../../bower_components/bootstrap/less/glyphicons.less"; + +// Core CSS +@import "../../bower_components/bootstrap/less/scaffolding.less"; +@import "../../bower_components/bootstrap/less/type.less"; +@import "../../bower_components/bootstrap/less/code.less"; +@import "../../bower_components/bootstrap/less/grid.less"; +@import "../../bower_components/bootstrap/less/tables.less"; +@import "../../bower_components/bootstrap/less/forms.less"; +@import "../../bower_components/bootstrap/less/buttons.less"; + +// Components +@import "../../bower_components/bootstrap/less/component-animations.less"; +@import "../../bower_components/bootstrap/less/dropdowns.less"; +@import "../../bower_components/bootstrap/less/button-groups.less"; +@import "../../bower_components/bootstrap/less/input-groups.less"; +@import "../../bower_components/bootstrap/less/navs.less"; +@import "../../bower_components/bootstrap/less/navbar.less"; +@import "../../bower_components/bootstrap/less/breadcrumbs.less"; +@import "../../bower_components/bootstrap/less/pagination.less"; +@import "../../bower_components/bootstrap/less/pager.less"; +@import "../../bower_components/bootstrap/less/labels.less"; +@import "../../bower_components/bootstrap/less/badges.less"; +@import "../../bower_components/bootstrap/less/jumbotron.less"; +@import "../../bower_components/bootstrap/less/thumbnails.less"; +@import "../../bower_components/bootstrap/less/alerts.less"; +@import "../../bower_components/bootstrap/less/progress-bars.less"; +@import "../../bower_components/bootstrap/less/media.less"; +@import "../../bower_components/bootstrap/less/list-group.less"; +@import "../../bower_components/bootstrap/less/panels.less"; +@import "../../bower_components/bootstrap/less/responsive-embed.less"; +@import "../../bower_components/bootstrap/less/wells.less"; +@import "../../bower_components/bootstrap/less/close.less"; + +// Components w/ JavaScript +@import "../../bower_components/bootstrap/less/modals.less"; +@import "../../bower_components/bootstrap/less/tooltip.less"; +@import "../../bower_components/bootstrap/less/popovers.less"; +@import "../../bower_components/bootstrap/less/carousel.less"; + +// Utility classes +@import "../../bower_components/bootstrap/less/utilities.less"; +@import "../../bower_components/bootstrap/less/responsive-utilities.less"; + diff --git a/src/app/bootstrap.variables.less b/src/app/bootstrap.variables.less new file mode 100644 index 0000000..b0aac68 --- /dev/null +++ b/src/app/bootstrap.variables.less @@ -0,0 +1,860 @@ +// +// Variables +// -------------------------------------------------- +@import url(http://fonts.googleapis.com/css?family=Lato:400,300,700); +// +// Variables +// -------------------------------------------------- + + +//== Colors +// +//## Gray and brand colors for use across Bootstrap. + +@gray-base: #000; +@gray-darker: lighten(@gray-base, 13.5%); // #222 +@gray-dark: lighten(@gray-base, 20%); // #333 +@gray: lighten(@gray-base, 33.5%); // #555 +@gray-light: lighten(@gray-base, 46.7%); // #777 +@gray-lighter: lighten(@gray-base, 93.5%); // #eee + +@brand-primary: #53BF6B; +@brand-success: #5cb85c; +@brand-info: #5bc0de; +@brand-warning: #f0ad4e; +@brand-danger: #d9534f; + + +//== Scaffolding +// +//## Settings for some of the most global styles. + +//** Background color for ``. +@body-bg: @gray-lighter; +//** Global text color on ``. +@text-color: @gray-dark; + +//** Global textual link color. +@link-color: @brand-primary; +//** Link hover color set via `darken()` function. +@link-hover-color: darken(@link-color, 15%); +//** Link hover decoration. +@link-hover-decoration: underline; + + +//== Typography +// +//## Font, line-height, and color for body text, headings, and more. + +@font-family-sans-serif: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; +@font-family-serif: Georgia, "Times New Roman", Times, serif; +//** Default monospace fonts for ``, ``, and `
`.
+@font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
+@font-family-base:        @font-family-sans-serif;
+
+@font-size-base:          14px;
+@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px
+@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px
+
+@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px
+@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px
+@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px
+@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px
+@font-size-h5:            @font-size-base;
+@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+@line-height-base:        1.428571429; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px
+
+//** By default, this inherits from the ``.
+@headings-font-family:    @font-family-sans-serif;
+@headings-font-weight:    500;
+@headings-line-height:    1.1;
+@headings-color:          inherit;
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+@icon-font-path:          '/bower_components/bootstrap/fonts/';
+//** File name for all font files.
+@icon-font-name:          "glyphicons-halflings-regular";
+//** Element ID within SVG icon file.
+@icon-font-svg-id:        "glyphicons_halflingsregular";
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+@padding-base-vertical:     6px;
+@padding-base-horizontal:   12px;
+
+@padding-large-vertical:    10px;
+@padding-large-horizontal:  16px;
+
+@padding-small-vertical:    5px;
+@padding-small-horizontal:  10px;
+
+@padding-xs-vertical:       1px;
+@padding-xs-horizontal:     5px;
+
+@line-height-large:         1.33;
+@line-height-small:         1.5;
+
+@border-radius-base:        2px;
+@border-radius-large:       3px;
+@border-radius-small:       1.5px;
+
+//** Global color for active items (e.g., navs or dropdowns).
+@component-active-color:    #fff;
+//** Global background color for active items (e.g., navs or dropdowns).
+@component-active-bg:       @brand-primary;
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+@caret-width-base:          4px;
+//** Carets increase slightly in size for larger components.
+@caret-width-large:         5px;
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for ``s and ``s.
+@table-cell-padding:            8px;
+//** Padding for cells in `.table-condensed`.
+@table-condensed-cell-padding:  5px;
+
+//** Default background color used for all tables.
+@table-bg:                      transparent;
+//** Background color used for `.table-striped`.
+@table-bg-accent:               #f9f9f9;
+//** Background color used for `.table-hover`.
+@table-bg-hover:                #f5f5f5;
+@table-bg-active:               @table-bg-hover;
+
+//** Border color for table and cell borders.
+@table-border-color:            #ddd;
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+@btn-font-weight:                normal;
+
+@btn-default-color:              #333;
+@btn-default-bg:                 #fff;
+@btn-default-border:             #ccc;
+
+@btn-primary-color:              #fff;
+@btn-primary-bg:                 @brand-primary;
+@btn-primary-border:             darken(@btn-primary-bg, 5%);
+
+@btn-success-color:              #fff;
+@btn-success-bg:                 @brand-success;
+@btn-success-border:             darken(@btn-success-bg, 5%);
+
+@btn-info-color:                 #fff;
+@btn-info-bg:                    @brand-info;
+@btn-info-border:                darken(@btn-info-bg, 5%);
+
+@btn-warning-color:              #fff;
+@btn-warning-bg:                 @brand-warning;
+@btn-warning-border:             darken(@btn-warning-bg, 5%);
+
+@btn-danger-color:               #fff;
+@btn-danger-bg:                  @brand-danger;
+@btn-danger-border:              darken(@btn-danger-bg, 5%);
+
+@btn-link-disabled-color:        @gray-light;
+
+
+//== Forms
+//
+//##
+
+//** `` background color
+@input-bg:                       #fff;
+//** `` background color
+@input-bg-disabled:              @gray-lighter;
+
+//** Text color for ``s
+@input-color:                    @gray;
+//** `` border color
+@input-border:                   #ccc;
+
+// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4
+//** Default `.form-control` border radius
+@input-border-radius:            @border-radius-base;
+//** Large `.form-control` border radius
+@input-border-radius-large:      @border-radius-large;
+//** Small `.form-control` border radius
+@input-border-radius-small:      @border-radius-small;
+
+//** Border color for inputs on focus
+@input-border-focus:             #66afe9;
+
+//** Placeholder text color
+@input-color-placeholder:        #999;
+
+//** Default `.form-control` height
+@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);
+//** Large `.form-control` height
+@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
+//** Small `.form-control` height
+@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
+
+@legend-color:                   @gray-dark;
+@legend-border-color:            #e5e5e5;
+
+//** Background color for textual input addons
+@input-group-addon-bg:           @gray-lighter;
+//** Border color for textual input addons
+@input-group-addon-border-color: @input-border;
+
+//** Disabled cursor for form controls and buttons.
+@cursor-disabled:                not-allowed;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+@dropdown-bg:                    #fff;
+//** Dropdown menu `border-color`.
+@dropdown-border:                rgba(0,0,0,.15);
+//** Dropdown menu `border-color` **for IE8**.
+@dropdown-fallback-border:       #ccc;
+//** Divider color for between dropdown items.
+@dropdown-divider-bg:            #e5e5e5;
+
+//** Dropdown link text color.
+@dropdown-link-color:            @gray-dark;
+//** Hover color for dropdown links.
+@dropdown-link-hover-color:      darken(@gray-dark, 5%);
+//** Hover background for dropdown links.
+@dropdown-link-hover-bg:         #f5f5f5;
+
+//** Active dropdown menu item text color.
+@dropdown-link-active-color:     @component-active-color;
+//** Active dropdown menu item background color.
+@dropdown-link-active-bg:        @component-active-bg;
+
+//** Disabled dropdown menu item background color.
+@dropdown-link-disabled-color:   @gray-light;
+
+//** Text color for headers within dropdown menus.
+@dropdown-header-color:          @gray-light;
+
+//** Deprecated `@dropdown-caret-color` as of v3.1.0
+@dropdown-caret-color:           #000;
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+@zindex-navbar:            1000;
+@zindex-dropdown:          1000;
+@zindex-popover:           1060;
+@zindex-tooltip:           1070;
+@zindex-navbar-fixed:      1030;
+@zindex-modal:             1040;
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `@screen-xs` as of v3.0.1
+@screen-xs:                  480px;
+//** Deprecated `@screen-xs-min` as of v3.2.0
+@screen-xs-min:              @screen-xs;
+//** Deprecated `@screen-phone` as of v3.0.1
+@screen-phone:               @screen-xs-min;
+
+// Small screen / tablet
+//** Deprecated `@screen-sm` as of v3.0.1
+@screen-sm:                  768px;
+@screen-sm-min:              @screen-sm;
+//** Deprecated `@screen-tablet` as of v3.0.1
+@screen-tablet:              @screen-sm-min;
+
+// Medium screen / desktop
+//** Deprecated `@screen-md` as of v3.0.1
+@screen-md:                  992px;
+@screen-md-min:              @screen-md;
+//** Deprecated `@screen-desktop` as of v3.0.1
+@screen-desktop:             @screen-md-min;
+
+// Large screen / wide desktop
+//** Deprecated `@screen-lg` as of v3.0.1
+@screen-lg:                  1200px;
+@screen-lg-min:              @screen-lg;
+//** Deprecated `@screen-lg-desktop` as of v3.0.1
+@screen-lg-desktop:          @screen-lg-min;
+
+// So media queries don't overlap when required, provide a maximum
+@screen-xs-max:              (@screen-sm-min - 1);
+@screen-sm-max:              (@screen-md-min - 1);
+@screen-md-max:              (@screen-lg-min - 1);
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+@grid-columns:              12;
+//** Padding between columns. Gets divided in half for the left and right.
+@grid-gutter-width:         30px;
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+@grid-float-breakpoint:     @screen-sm-min;
+//** Point at which the navbar begins collapsing.
+@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+@container-tablet:             (720px + @grid-gutter-width);
+//** For `@screen-sm-min` and up.
+@container-sm:                 @container-tablet;
+
+// Medium screen / desktop
+@container-desktop:            (940px + @grid-gutter-width);
+//** For `@screen-md-min` and up.
+@container-md:                 @container-desktop;
+
+// Large screen / wide desktop
+@container-large-desktop:      (1140px + @grid-gutter-width);
+//** For `@screen-lg-min` and up.
+@container-lg:                 @container-large-desktop;
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+@navbar-height:                    50px;
+@navbar-margin-bottom:             @line-height-computed;
+@navbar-border-radius:             @border-radius-base;
+@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));
+@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);
+@navbar-collapse-max-height:       340px;
+
+@navbar-default-color:             #777;
+@navbar-default-bg:                #f8f8f8;
+@navbar-default-border:            darken(@navbar-default-bg, 6.5%);
+
+// Navbar links
+@navbar-default-link-color:                #777;
+@navbar-default-link-hover-color:          #333;
+@navbar-default-link-hover-bg:             transparent;
+@navbar-default-link-active-color:         #555;
+@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);
+@navbar-default-link-disabled-color:       #ccc;
+@navbar-default-link-disabled-bg:          transparent;
+
+// Navbar brand label
+@navbar-default-brand-color:               @navbar-default-link-color;
+@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);
+@navbar-default-brand-hover-bg:            transparent;
+
+// Navbar toggle
+@navbar-default-toggle-hover-bg:           #ddd;
+@navbar-default-toggle-icon-bar-bg:        #888;
+@navbar-default-toggle-border-color:       #ddd;
+
+
+// Inverted navbar
+// Reset inverted navbar basics
+@navbar-inverse-color:                      lighten(@gray-light, 15%);
+@navbar-inverse-bg:                         #222;
+@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);
+
+// Inverted navbar links
+@navbar-inverse-link-color:                 lighten(@gray-light, 15%);
+@navbar-inverse-link-hover-color:           #fff;
+@navbar-inverse-link-hover-bg:              transparent;
+@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;
+@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);
+@navbar-inverse-link-disabled-color:        #444;
+@navbar-inverse-link-disabled-bg:           transparent;
+
+// Inverted navbar brand label
+@navbar-inverse-brand-color:                @navbar-inverse-link-color;
+@navbar-inverse-brand-hover-color:          #fff;
+@navbar-inverse-brand-hover-bg:             transparent;
+
+// Inverted navbar toggle
+@navbar-inverse-toggle-hover-bg:            #333;
+@navbar-inverse-toggle-icon-bar-bg:         #fff;
+@navbar-inverse-toggle-border-color:        #333;
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+@nav-link-padding:                          10px 15px;
+@nav-link-hover-bg:                         @gray-lighter;
+
+@nav-disabled-link-color:                   @gray-light;
+@nav-disabled-link-hover-color:             @gray-light;
+
+//== Tabs
+@nav-tabs-border-color:                     #ddd;
+
+@nav-tabs-link-hover-border-color:          @gray-lighter;
+
+@nav-tabs-active-link-hover-bg:             @body-bg;
+@nav-tabs-active-link-hover-color:          @gray;
+@nav-tabs-active-link-hover-border-color:   #ddd;
+
+@nav-tabs-justified-link-border-color:            #ddd;
+@nav-tabs-justified-active-link-border-color:     @body-bg;
+
+//== Pills
+@nav-pills-border-radius:                   @border-radius-base;
+@nav-pills-active-link-hover-bg:            @component-active-bg;
+@nav-pills-active-link-hover-color:         @component-active-color;
+
+
+//== Pagination
+//
+//##
+
+@pagination-color:                     @link-color;
+@pagination-bg:                        #fff;
+@pagination-border:                    #ddd;
+
+@pagination-hover-color:               @link-hover-color;
+@pagination-hover-bg:                  @gray-lighter;
+@pagination-hover-border:              #ddd;
+
+@pagination-active-color:              #fff;
+@pagination-active-bg:                 @brand-primary;
+@pagination-active-border:             @brand-primary;
+
+@pagination-disabled-color:            @gray-light;
+@pagination-disabled-bg:               #fff;
+@pagination-disabled-border:           #ddd;
+
+
+//== Pager
+//
+//##
+
+@pager-bg:                             @pagination-bg;
+@pager-border:                         @pagination-border;
+@pager-border-radius:                  15px;
+
+@pager-hover-bg:                       @pagination-hover-bg;
+
+@pager-active-bg:                      @pagination-active-bg;
+@pager-active-color:                   @pagination-active-color;
+
+@pager-disabled-color:                 @pagination-disabled-color;
+
+
+//== Jumbotron
+//
+//##
+
+@jumbotron-padding:              30px;
+@jumbotron-color:                inherit;
+@jumbotron-bg:                   @gray-lighter;
+@jumbotron-heading-color:        inherit;
+@jumbotron-font-size:            ceil((@font-size-base * 1.5));
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+@state-success-text:             #3c763d;
+@state-success-bg:               #dff0d8;
+@state-success-border:           darken(spin(@state-success-bg, -10), 5%);
+
+@state-info-text:                #31708f;
+@state-info-bg:                  #d9edf7;
+@state-info-border:              darken(spin(@state-info-bg, -10), 7%);
+
+@state-warning-text:             #8a6d3b;
+@state-warning-bg:               #fcf8e3;
+@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);
+
+@state-danger-text:              #a94442;
+@state-danger-bg:                #f2dede;
+@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+@tooltip-max-width:           200px;
+//** Tooltip text color
+@tooltip-color:               #fff;
+//** Tooltip background color
+@tooltip-bg:                  #000;
+@tooltip-opacity:             .9;
+
+//** Tooltip arrow width
+@tooltip-arrow-width:         5px;
+//** Tooltip arrow color
+@tooltip-arrow-color:         @tooltip-bg;
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+@popover-bg:                          #fff;
+//** Popover maximum width
+@popover-max-width:                   276px;
+//** Popover border color
+@popover-border-color:                rgba(0,0,0,.2);
+//** Popover fallback border color
+@popover-fallback-border-color:       #ccc;
+
+//** Popover title background color
+@popover-title-bg:                    darken(@popover-bg, 3%);
+
+//** Popover arrow width
+@popover-arrow-width:                 10px;
+//** Popover arrow color
+@popover-arrow-color:                 @popover-bg;
+
+//** Popover outer arrow width
+@popover-arrow-outer-width:           (@popover-arrow-width + 1);
+//** Popover outer arrow color
+@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);
+//** Popover outer arrow fallback color
+@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+@label-default-bg:            @gray-light;
+//** Primary label background color
+@label-primary-bg:            @brand-primary;
+//** Success label background color
+@label-success-bg:            @brand-success;
+//** Info label background color
+@label-info-bg:               @brand-info;
+//** Warning label background color
+@label-warning-bg:            @brand-warning;
+//** Danger label background color
+@label-danger-bg:             @brand-danger;
+
+//** Default label text color
+@label-color:                 #fff;
+//** Default text color of a linked label
+@label-link-hover-color:      #fff;
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+@modal-inner-padding:         15px;
+
+//** Padding applied to the modal title
+@modal-title-padding:         15px;
+//** Modal title line-height
+@modal-title-line-height:     @line-height-base;
+
+//** Background color of modal content area
+@modal-content-bg:                             #fff;
+//** Modal content border color
+@modal-content-border-color:                   rgba(0,0,0,.2);
+//** Modal content border color **for IE8**
+@modal-content-fallback-border-color:          #999;
+
+//** Modal backdrop background color
+@modal-backdrop-bg:           #000;
+//** Modal backdrop opacity
+@modal-backdrop-opacity:      .5;
+//** Modal header border color
+@modal-header-border-color:   #e5e5e5;
+//** Modal footer border color
+@modal-footer-border-color:   @modal-header-border-color;
+
+@modal-lg:                    900px;
+@modal-md:                    600px;
+@modal-sm:                    300px;
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+@alert-padding:               15px;
+@alert-border-radius:         @border-radius-base;
+@alert-link-font-weight:      bold;
+
+@alert-success-bg:            @state-success-bg;
+@alert-success-text:          @state-success-text;
+@alert-success-border:        @state-success-border;
+
+@alert-info-bg:               @state-info-bg;
+@alert-info-text:             @state-info-text;
+@alert-info-border:           @state-info-border;
+
+@alert-warning-bg:            @state-warning-bg;
+@alert-warning-text:          @state-warning-text;
+@alert-warning-border:        @state-warning-border;
+
+@alert-danger-bg:             @state-danger-bg;
+@alert-danger-text:           @state-danger-text;
+@alert-danger-border:         @state-danger-border;
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+@progress-bg:                 #f5f5f5;
+//** Progress bar text color
+@progress-bar-color:          #fff;
+//** Variable for setting rounded corners on progress bar.
+@progress-border-radius:      @border-radius-base;
+
+//** Default progress bar color
+@progress-bar-bg:             @brand-primary;
+//** Success progress bar color
+@progress-bar-success-bg:     @brand-success;
+//** Warning progress bar color
+@progress-bar-warning-bg:     @brand-warning;
+//** Danger progress bar color
+@progress-bar-danger-bg:      @brand-danger;
+//** Info progress bar color
+@progress-bar-info-bg:        @brand-info;
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+@list-group-bg:                 #fff;
+//** `.list-group-item` border color
+@list-group-border:             #ddd;
+//** List group border radius
+@list-group-border-radius:      @border-radius-base;
+
+//** Background color of single list items on hover
+@list-group-hover-bg:           #f5f5f5;
+//** Text color of active list items
+@list-group-active-color:       @component-active-color;
+//** Background color of active list items
+@list-group-active-bg:          @component-active-bg;
+//** Border color of active list elements
+@list-group-active-border:      @list-group-active-bg;
+//** Text color for content within active list items
+@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);
+
+//** Text color of disabled list items
+@list-group-disabled-color:      @gray-light;
+//** Background color of disabled list items
+@list-group-disabled-bg:         @gray-lighter;
+//** Text color for content within disabled list items
+@list-group-disabled-text-color: @list-group-disabled-color;
+
+@list-group-link-color:         #555;
+@list-group-link-hover-color:   @list-group-link-color;
+@list-group-link-heading-color: #333;
+
+
+//== Panels
+//
+//##
+
+@panel-bg:                    #fff;
+@panel-body-padding:          15px;
+@panel-heading-padding:       10px 15px;
+@panel-footer-padding:        @panel-heading-padding;
+@panel-border-radius:         @border-radius-base;
+
+//** Border color for elements within panels
+@panel-inner-border:          #ddd;
+@panel-footer-bg:             #f5f5f5;
+
+@panel-default-text:          @gray-dark;
+@panel-default-border:        #ddd;
+@panel-default-heading-bg:    #f5f5f5;
+
+@panel-primary-text:          #fff;
+@panel-primary-border:        @brand-primary;
+@panel-primary-heading-bg:    @brand-primary;
+
+@panel-success-text:          @state-success-text;
+@panel-success-border:        @state-success-border;
+@panel-success-heading-bg:    @state-success-bg;
+
+@panel-info-text:             @state-info-text;
+@panel-info-border:           @state-info-border;
+@panel-info-heading-bg:       @state-info-bg;
+
+@panel-warning-text:          @state-warning-text;
+@panel-warning-border:        @state-warning-border;
+@panel-warning-heading-bg:    @state-warning-bg;
+
+@panel-danger-text:           @state-danger-text;
+@panel-danger-border:         @state-danger-border;
+@panel-danger-heading-bg:     @state-danger-bg;
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+@thumbnail-padding:           4px;
+//** Thumbnail background color
+@thumbnail-bg:                @body-bg;
+//** Thumbnail border color
+@thumbnail-border:            #ddd;
+//** Thumbnail border radius
+@thumbnail-border-radius:     @border-radius-base;
+
+//** Custom text color for thumbnail captions
+@thumbnail-caption-color:     @text-color;
+//** Padding around the thumbnail caption
+@thumbnail-caption-padding:   9px;
+
+
+//== Wells
+//
+//##
+
+@well-bg:                     #f5f5f5;
+@well-border:                 darken(@well-bg, 7%);
+
+
+//== Badges
+//
+//##
+
+@badge-color:                 #fff;
+//** Linked badge text color on hover
+@badge-link-hover-color:      #fff;
+@badge-bg:                    @gray-light;
+
+//** Badge text color in active nav link
+@badge-active-color:          @link-color;
+//** Badge background color in active nav link
+@badge-active-bg:             #fff;
+
+@badge-font-weight:           bold;
+@badge-line-height:           1;
+@badge-border-radius:         10px;
+
+
+//== Breadcrumbs
+//
+//##
+
+@breadcrumb-padding-vertical:   8px;
+@breadcrumb-padding-horizontal: 15px;
+//** Breadcrumb background color
+@breadcrumb-bg:                 #f5f5f5;
+//** Breadcrumb text color
+@breadcrumb-color:              #ccc;
+//** Text color of current page in the breadcrumb
+@breadcrumb-active-color:       @gray-light;
+//** Textual separator for between breadcrumb elements
+@breadcrumb-separator:          "/";
+
+
+//== Carousel
+//
+//##
+
+@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);
+
+@carousel-control-color:                      #fff;
+@carousel-control-width:                      15%;
+@carousel-control-opacity:                    .5;
+@carousel-control-font-size:                  20px;
+
+@carousel-indicator-active-bg:                #fff;
+@carousel-indicator-border-color:             #fff;
+
+@carousel-caption-color:                      #fff;
+
+
+//== Close
+//
+//##
+
+@close-font-weight:           bold;
+@close-color:                 #000;
+@close-text-shadow:           0 1px 0 #fff;
+
+
+//== Code
+//
+//##
+
+@code-color:                  #c7254e;
+@code-bg:                     #f9f2f4;
+
+@kbd-color:                   #fff;
+@kbd-bg:                      #333;
+
+@pre-bg:                      #f5f5f5;
+@pre-color:                   @gray-dark;
+@pre-border-color:            #ccc;
+@pre-scrollable-max-height:   340px;
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+@component-offset-horizontal: 180px;
+//** Text muted color
+@text-muted:                  @gray-light;
+//** Abbreviations and acronyms border color
+@abbr-border-color:           @gray-light;
+//** Headings small color
+@headings-small-color:        @gray-light;
+//** Blockquote small color
+@blockquote-small-color:      @gray-light;
+//** Blockquote font size
+@blockquote-font-size:        (@font-size-base * 1.25);
+//** Blockquote border color
+@blockquote-border-color:     @gray-lighter;
+//** Page header border color
+@page-header-border-color:    @gray-lighter;
+//** Width of horizontal description list titles
+@dl-horizontal-offset:        @component-offset-horizontal;
+//** Horizontal line color.
+@hr-border:                   @gray-lighter;
diff --git a/src/app/index.js b/src/app/index.js
new file mode 100644
index 0000000..7e3e1f9
--- /dev/null
+++ b/src/app/index.js
@@ -0,0 +1,24 @@
+'use strict';
+
+angular.module('iframeScaffolder', ['ngSanitize', 'ui.router', 'zeroclipboard'])
+  .config(function ($stateProvider, $urlRouterProvider, $sceProvider, uiZeroclipConfigProvider) {
+    $stateProvider
+      .state('home', {
+        url: '/',
+        templateUrl: 'app/main/main.html',
+        controller: 'MainCtrl'
+      })
+      .state('view', {
+        url: '/view?urls&layout',
+        templateUrl: 'app/view/view.html',
+        controller: 'ViewCtrl',
+      });
+
+    $urlRouterProvider.otherwise('/');
+    $sceProvider.enabled(false);
+    // config ZeroClipboard
+    uiZeroclipConfigProvider.setZcConf({
+      swfPath: 'bower_components/zeroclipboard/dist/ZeroClipboard.swf'
+    });
+  })
+;
diff --git a/src/app/index.less b/src/app/index.less
new file mode 100644
index 0000000..5d0f7bc
--- /dev/null
+++ b/src/app/index.less
@@ -0,0 +1,5 @@
+@import "bootstrap.loader.less";
+// Internal
+@import "main/main.less";
+@import "view/view.less";
+@import "../components/scaffolder/scaffolder.less";
diff --git a/src/app/main/main.controller.js b/src/app/main/main.controller.js
new file mode 100644
index 0000000..45bba93
--- /dev/null
+++ b/src/app/main/main.controller.js
@@ -0,0 +1,48 @@
+'use strict';
+
+angular.module('iframeScaffolder').controller('MainCtrl', function ($scope, $state, $http) {
+
+  $scope.layout   = "head";
+  $scope.urls     = [];
+  $scope.width    = 600;
+  $scope.height   = 450;
+  $scope.examples = []
+  // Get sample datasets
+  $http.get("assets/examples.json").success(function(data) {
+    $scope.examples = data;
+  });
+
+  $scope.addUrl = function() {
+    // Avoid adding null value
+    if(!$scope.newUrl) return
+    // Add the url to the list
+    $scope.urls.push($scope.newUrl);
+    // Reset form value
+    $scope.newUrl = null;
+  };
+
+  $scope.removeUrl = function(index) {
+    $scope.urls.splice(index, 1);
+  };
+
+  $scope.getViewUrl = function() {
+    var params = {
+      urls: $scope.urls.join(","),
+      layout: $scope.layout
+    };
+    return $state.href('view', params, {absolute: true});
+  };
+
+  $scope.getViewIframe = function() {
+    var url = $scope.getViewUrl(),
+      width = $scope.width || 600,
+     height = $scope.height || 450;
+    return ''
+  };
+
+  $scope.pickExample = function() {
+    var example = $scope.examples[Math.floor(Math.random() * $scope.examples.length)];
+    angular.extend($scope, angular.copy(example));
+  };
+
+});
diff --git a/src/app/main/main.html b/src/app/main/main.html
new file mode 100644
index 0000000..2abe9b2
--- /dev/null
+++ b/src/app/main/main.html
@@ -0,0 +1,118 @@
+
+
+

Iframe Scaffolder

+

This tool helps you to quickly build a mosaic of iframes.

+
+
+
+
+
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ Choose a layout
+ How iframes are arranged +
+
+ + + +
+
+
+
+
+
+

+ + Export the iframe +

+

+ +

+
+
Change the size 
+
+ + x + +
+
+
+
+
+
+ + + +
+ Hi, I'm @pirhoo.
+ I hope you enjoy this open source tool. +
+
+
+
+
+
+
+
+

+ Add your iframe's URL on the panel to preview the mosaic here. +

+

+ + See an example. + + {{example}} +

+
+
+
+
+ + + + + + +
+
+
+ +
+
+
+
+
diff --git a/src/app/main/main.less b/src/app/main/main.less new file mode 100644 index 0000000..05743f1 --- /dev/null +++ b/src/app/main/main.less @@ -0,0 +1,97 @@ +@import "../bootstrap.variables.less"; +@import "../../../bower_components/bootstrap/less/mixins.less"; + +.introduction { + padding:20px 0; + margin-bottom:20px; + background: white; +} + +.editor { + + position:relative; + counter-reset: step; + + &__credits { + margin-top:40px; + } + + &__step { + position:relative; + counter-increment:step; + + &__label { + position:absolute; + bottom:0; + top:0; + right:100%; + color:white; + width:15px; + line-height: 20px; + text-align: center; + background: @brand-primary; + border-radius:@panel-border-radius 0 0 @panel-border-radius; + + &:after { + position:absolute; + top:50%; + left:50%; + content:counter(step); + .translate(-50%, -50%); + } + } + + &__url { + white-space: nowrap; + overflow: hidden; + position: relative; + + &__actions { + position:relative; + background: white; + .box-shadow(0 0 10px 10px white); + } + } + + &__actions { + position:absolute; + top:0; + left:0; + } + + & &__size { + display:inline-block; + width:65px; + } + } + + &__preview { + position: relative; + background:url("/assets/images/editor-bg.png") black 0 0; + + &__scaffolder { + margin:20px; + height: 500px; + background:#fff; + .box-shadow(0 0 10px 0 fade(black, 20)); + } + + &__empty-alert { + position:absolute; + top:0; + left:0; + bottom:0; + right:0; + z-index: 100; + background: fade(#fff, 60); + + &__message { + position:absolute; + top:50%; + left:50%; + text-align: center; + .translate(-50%, -50%); + } + } + } +} diff --git a/src/app/view/view.controller.js b/src/app/view/view.controller.js new file mode 100644 index 0000000..f7c9317 --- /dev/null +++ b/src/app/view/view.controller.js @@ -0,0 +1,6 @@ +'use strict'; + +angular.module('iframeScaffolder').controller('ViewCtrl', function ($scope, $stateParams) { + $scope.layout = $stateParams.layout + $scope.urls = $stateParams.urls.split(",") +}); diff --git a/src/app/view/view.html b/src/app/view/view.html new file mode 100644 index 0000000..d49cb29 --- /dev/null +++ b/src/app/view/view.html @@ -0,0 +1,5 @@ +
+
+ +
+
diff --git a/src/app/view/view.less b/src/app/view/view.less new file mode 100644 index 0000000..756bf75 --- /dev/null +++ b/src/app/view/view.less @@ -0,0 +1,9 @@ +.view { + &__scaffolder { + position:absolute; + top:0; + left:0; + right:0; + bottom:0; + } +} diff --git a/src/assets/examples.json b/src/assets/examples.json new file mode 100644 index 0000000..63d0477 --- /dev/null +++ b/src/assets/examples.json @@ -0,0 +1,9 @@ +[ + { + "urls": [ + "http://charts-datawrapper.s3.amazonaws.com/tcGKU/index.html?rev=91", + "http://charts-datawrapper.s3.amazonaws.com/CzstV/index.html?rev=39" + ], + "layout": "horizontal" + } +] diff --git a/src/assets/images/editor-bg.png b/src/assets/images/editor-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..ba6365e5511c83383c6cd5fd86fbb0c61bc342ff GIT binary patch literal 33159 zcmWifcOY9|8^>$buDwcY1&L9!MNxZGV((F#wkpyVjjC0$i9YC7dpG)bUP&!3PygSTNKK%brp*BD@VtU@u8*bFr;Q*MOY@Ne8>=QC!^UVvu|(<! z$49c&o~R>+Gr!lyFRmnsu*!lE^7uk80h(|Z`m9olI$_$wtsevA>a{CG5YXSTGQj61 z9u$^!8~6!70jrQErB*SZtKNxVMoGSKsapwbFbZ;_3ojLjs_rubg6&cOjzdL39!mpu z6KT?=ukCtXiRrD;Z4CxBHW*%u>+?QXj04UsG@isn7e*#%2_-h!ej)teCxKGt7PqLS6;YQg!C?JvgK zecc6CPGu_*9=tp!uRpqZHF4i)SQl%hT6Ns=3!yn@~AT zjifHIvN!MP={jxh2<(z7o(i^`+q9L47ORJu(td@iui>)e-(nsD9GzI8;;e-Q;yyTV zmh^nB4zkL6uBLr-SSCxO7dH7CdgwN)Bl1m!`qI`cDu2peWBcGH(WQ}gXlR6j2Q zCo1JJtEVYWiYDKrYyh<^@5e!h5RQ{3{~e4z=LZbkxB~)=Gv(li9{Otqs+Rb7)>z8A zPZA0H3(R3BUR7U@tc4SM-+r^}dZiSyF)I)rFp<3G@p^8+D_bFtr^iM)Nh?8;-Td*DZ~$8)NErAI5lvz6kr; zP`W=>2`$7QpT}9bm~fQHThP6fFd~`=^2&oObXe+~)N$+JwM1zmuO%wU$B|dryN*@k zDwh_WOqv}O3nOzF2RB5Z-j%Y~ax=lI@Sn2W6v3@m`owxnDG)tn2mTA#I)J0kv{-$v zmuOQ;-gD1>4NT;FFLP;4Rnv*(LaXNW8eY!;`3$GVo&Z*0U~AeBivE3}JVVuHamG7O zSTg!v1m|$q`mnv!cJPwt(F&nMTLgeT420F^cT>EvrrI2Bv(pw~8a<<}EAD|Z?SX)e z7z?rIw}lDE4qOY&R18-6TY-x*rvc3oz0S+f zUE&(fuft$6uW)(AUN7NDp+s*^Fraq|q;*;5i;k;tO=`zhL+E`MM~?pp#3u!9QJAQd zCb59%NCXA)PtZY#F&}9B#@HS7NNZfNMSrRw^Jnprk-YG%noj3)Aw;^~e`SsYh8hp^Wt*LBhM702jYX zafwM`e;f7wqf^7j;l6T=$yp|9AElMu3=#SSJh-8x>&T~ICJ_p9j35)XuS7T4XP5e` zsffg#+Urec@OIQXz)MvebUt5*uoQGuzj6|+b@9R0qrw%Se5(~CBv~)?Gx-=D_FdHx zkqq((acTlTAOo6hRwJagcIRzkme^63TBd5tGsan+dw7h0ZC~UtdlbUsQ)@ATi%|R0j@6ed)^MrCFZp_t$>tf5ZiyA*u@S+i0L;WR+q_A)HZSzrPbkkyxX;-a$k1PrOqOXyyG3l;-TvYz|T~E16y1(I)zT?aa z;-mdteNE;MW~t=BZT0rpH= z)-?&xK^Yz;wGXu`9p)}BRdpkqy9%BHg&NVmH{*A>AIzL_&4L4$V=@TSN~Elnm*|BTtuLdUzd* zyAF063-cx|4ONAZ`=FT7wV~7P5CVzTcj0 z&58Qh`o8<#6m;$y%#uj!@Cb&1Rz(o-qhv^BA7*Lvw67Z)w!f!MI`}1aSl@?*ouXr^ zt*JVs?c%Nw0tJ2Tu#W=srJ|3ZF_oj$B-9$jmx`k3heV84QxcBiE8{y!`gk<-{(fv1 zEP_C3gjiF3h+edwJW)`kL&)hmaa$+;uoFh|(!mZ@#cvHN?`sn)jyH?fhRBfIBiQK% z6^)Hm4(q1kAeElxcqq*r^pLoB7EgHb;XbQ1(!jpf%SZVHWw$ENV3l|z!y>FM&`J6u zTFfW{^q+RxpZW%WC?aIyC(!I4WdJOEjA?Az+vN-UYN@Vp)uF2TIAGPH?cU`tDw;-F z17>kXrmFnvLCN`yL2tQ3uBtA+xnLLv=91iVx~n(yy38r0AiPH6HaW49wD?IN%B~4F zqCK%N*L9rGY$C|L#h(e#(W#wwe~aRu`NS)(oaB-|i$kR-Ybfc0*PPhD2Wv*fAVnrm zmy$p`vjN3LU%fo<9?gFD^ZflDhtt^q9ly=T!iZbhDT|7tS1|qd_i!S`-Pta_CM?&D z;nVh``7DHa&1h2HMv*BSQ4I2+OiC*WAyxozKlK`(VK&lzbenV{6m5IKyX^?gyvn*ELx3g^cKJ@iRBh=DMJ=jLV*60vT3#GfDap zv$*m@F^`8H*CeOv$eygZ5;Tr5cH+2l8Gi z8LjmW92q+r0yf!ap{UaMTVer$A{=tXO`s9f4umi~8Ix}^Y~Jai0s$YAV}Vh;Ml&C) z*5CPf+v!o=KXtTD{-gKVB3^tve>Rp#i9Em1&Hs=6adpJM3uJEE0pTg(>c@AlX?47* z7ayDcx%SbU0%*0jI=}W&50#MUx=O3lNGqxQe`_*ACXbbUsF*xf88OC#@&|F1Jj zS`8B-=TgG~6U$-R(2+DUhyn+8xR?bh%c|cYaqv}Iq}5+8Ojeovtz=d6WJGeF`9h2c zsJ+p%m;x$rw`EqJs<5el@E>g3FivaOft8Wl?{WHTpWD~xcoQ!a1~nqzf8EA+YGhfe zn(yogkI&LE$9o6x1sPo6nv-V1-J}iyYM5Ms>}!F|@gb%g1j;e=wxu^X4Pj%h)xLSS z2|7vHNo0vpF(t7I#@Jn#;jwwprXy|?#BrE#&%LGN{8k6zlb!UiJ^q|OwXkkOZrN)e zS)tzll$fpA3}Ez@cL;6gG1Dp602|7_imYjTW&wXO$=1l%Wzt>ZC1xajidF`twED%r zT;lwm*&wPO_NsU0}z7;RY2JqPr54{NdI2JCd9eU7ogP!eK6a+;xJEYqs~o z%G9C^dEeQ71euM)ycJ~bK;B2^!Oa4S+;rym;i_-FmKe1Pfg$e+L@MWH^`OCDfpCiy z35mzorsUNWo4LmXn2fxWbts+8ubr&W=_`2}Y;Ry!l<4x&Z680@NZDf$7~FpzZ%ldx z73aWFTA$AT##_Dwe8ts7FH8!y_7m5a_r1TtZNvdCMjXs!2>peo=n)516+`#_+Afk= zPnNcQ*+psjw%!>OnPI@~&b}Y(^}q4#+6nr;9O}XW^nc5TW9h}ch>H0B?o~18lwQLd zb?=pcLGRoc9RijWJZE11jJRv0nPr9AVa}K0_0b`w8@tI4O*_1~ZrgQzj|}m#eLjA% zz)IfJ0J5|-*mdu@XAdg%;rNtkamT4(&N47`=;QqSTneuZ{`~O^tE#9I8M>m-NaMYt z`AQGTOr<5;ncko#$}xOy8nH3Tp5qi-&!6Bel+UBY5@BE2<|9xekb94J!75HQB5tlg zoNuYGyMR;hLk>%?4Qv1V`d4e3-+o{w(&<>3Z`h|)Q?5Go6T0lH!kbo9w=sbO3dpFqEpVTrYbUIi|;o~KqT(u%AD(w zBLu$|0#PV8gq#)KMrX2_8&jgDY%1eLA$DwpM{SYfqUW{lZ;8~3G%QdLX#lAfr zr!2eh!=WK?eOu4I=_jgD=A%v14HjofQ6@uTMWk9G=ArV{?3XTF z@V}HZidQjaDEBCYfL~Mc4k1Gh%?H;;$Y5v)V3|?YkQfO)5O;wmk}1S$-6`Mu zzl2-)b@sJsHZO5D4-7t{iZ1EJJBZ1@1AmRI(M_2oCGro*YdQV-8_MObMPnHDVnZLtBrrwu#F5tiztn*LF z1mcm-j5X0guWbXMcM?~0E=_R(=^jB^E!5p=YLEGQEl(u26lKA$!K_0Vk=%6Uf#F0J zWyckdXOt(&@RG6^92+Mh*zfa@Oc>|ff;w`A;e9{*T?&l7vddYvb-~yQIIHnZ4E%03 zzdP(PE=jP6=iyos)sMR<;`QWflzNTZQzEst_Ei!Si`%CXWkFe>H(zAF-jtfXYAc52 zcx?zNHfgod!fU4^@biIpe4$kyTdDle<@m+vhll2X$1kPS<@Yas;?{Spri5B~*?1`b zZdm7^lp&$*nh|p#keT3=n5X_BDyH$ynW9Cgk^=lXkGDV7MIy<@%-`g=O1?0JSOMdn zJ1aav?AgiL)BVu9Pm=pBs26 z32%w^@Cn8nEddYKHfrgVG`_p!w{Tr9P^Unc7A6q%JRa%;Zb6un2=6uH+g|c>ja#p) zaVlhM{liMq>1TUYobG#W_hKOi+-c)9S<$CjJJ(wJ^?ix0u|dc?D7hMxY?R5pGI9G` z9&L)t`tsUNJ+|EvOA5o#gKBS0Er;B$OFQs*Xg{v9UA?f(zd9M!Q<^`4L$&+?;*GSY zEl%JHOOWbzzs|H{yw$K=+jLeK0sH(Nj|R^>XQO8o6E!`*KDb3U_7rZni;RoCij0u6 z} zOg5qC176r5HmIDR-ywDq_Jv$ZH>`qa;>vo6nvFr6G-VR#lhUO|zsfQFdozf2V8!F=MJ5z)`?J|$D_tn3P0 zlO1mbSd|))bauI_-sJV&6+qI8) z6?&EL#?C}eMmKIFjWuG6{hImkqzB)l)?cN`A6n0^IMy7m7Phw_M3o{((jeOD& zzg)fq$muma(@0)8fs#E1J0m;4{=O@>KP4-7M6#0>04p}R(!p;E1bAch&K&!iTk-;X zqsA}(cM~h^zL+Fs!nN5xyWot*KU8T36kZZ{Dhbtg)FFPyKMp#@8NA7#bY`TCe)4B) zG@I6#<8V0WSXGCjb2SIMzG#v3U-|f=|qnYvYH$!bkx*Zl~s;GkXS5 zocG(XBimqqnl(3O;knerULhUau)uExjj&tx>rcDI>D^-y15cS82JDX7!q15bQx7cJI+A`=fFYeV<-C_Z=}tUh`8N+$`o z9e1j|VZMQf(xeEbDEAb42n(z1gmps+9&ufeQ)Cx4mKI5gxLQedk0&?AZxMAO$n~)5 zcwgdr$kjurvNr`fK+_i$F!6maybtv(<6Z;F<3$zL)qI1p1oNfIp$5ni1k>4v86v}C z?pGo)qu8Nhj1Nkt^0)$~tT%Ytc>Kq{=tx?;@|Y%~Dyce@(bMw-ny{jX5_Rzq46>W5 zjo*m(rWK%%U|S)Cr(_D$iO=d;-J>_Npw_AQZj6fpeM+(Ci)^*8He_Oe-K5s1dV#Fb zo#5T3SNN@i1H;FNKyk7AIqI7DJ_+Kb9NDMo4Z^mPKdDz5myEgl(o2Pbt_)Wqwsu*s zbJy-lTXH=LUqm^9tUVZ_ug3Z3+aMvNba%SsmRiuh^l95)R@*ucpqgHZ_?K`g&R#54 zgGW4=drJ8CoZl+qU|>{XT+{-H`{r@+0J4`utfSY2O-+Ms&IRR%qkM}sGMcc7 z&lVO0w!_9z7@v=s2ylV(6u5sb^EyqDq%Wldt?UA%yrU&6J#XZwf%M*o2QG=ZC?rCv z>1E>r035Z6cn|lbIa27j6ZcL-g0E)Vw7a#Ze!!)q0~aQ7`T}+w<&48!?NPJS70_+d zXRJriq{x(IU}?@L$}`(M9csv5cb^V1b%kgEunS#vwB*m-kS4slA@!r1y{%hl1MII8Xy%Dc6mF@6C4% z|D>E^&t+sZ_E`WDaymguDKV|RR(po?l^x;rX%bLn+a*Re5_}9axt%Bvme$+ECkS zWgdh1Kn7j+`W@tx9#jt}DaHJ_k=ei4FQ0KnfpIClX}@Tb{Mt+DFUzOcffbS3>RdzT z!h6e|YX_cz#^8ZWPSCDELBr>@pnE3Fit2hTCOkkEn76BZ_(D4>WkBVXrLX~+8gwU* zNvYGt%A`C!+6SL6t>ms5eGI(h3kX6e>+J-{p7ecMQFDlroH{-b1xpoaW~(FQ2e|uw z^;0dRGwL#3Z2Xs22o!aC2Sm9mU1_50nj)5j3v4d{XSXvnwnXl<+YN> zP)m7OxX11`wYW}gR^;1>64~qs1P8Q0Z)WX(my#^ftodj{PkZti&qbQ{zj>0fP}8aU zTenz8WKZ5!cB+J)jZtsV#3QTcNg_@WFeBpIPuxyx+I-d|5}G6-T-Yd0ZDs6V*aS66 znu>tqu-3>hi;JwOf%-}Ie3ZD&B2VDDU<^d=xmwt7beGZNLFv0^T0v7>I&e2ikRIbK zaIl}Je0q=fz{kAG$30lF-ja#r9JCNuUF|7tCLLUl+JUR9f2+_8j}_9%>Hl`(*V<=I z0V71ei%RJ@)iNt^e1s{l^e5a6>D!P9@leykqvLwRMdD@K)bI4T7H<4{w2iHMW8?02 zu;V1?SXzS9&Rb;SDr(o;C>knPsFgmol6yNsub>4mG=<~AH|j4t=<64Xsol|1AHn1T zaOT-9O|$T;+b2zpdQsR2GFU(&iD9gmI#gQf&86 zfE>QBg}L!{wgM+FP(qqop`hBibo)xjlm{zBOLv=+b1#&!I3xUlpo#r;{OF2ZLvmP! zgY}RRIQGa~sgG;GXjiqTNeX#k8oE_~5{Z>pHX1urv>o`Zj|1^<<^K$)e<@qz{D;O% z{8#uB6U5)Mv1!VYL)oUQ2bDV40G_0(tt}$EI8D+R4GiO;kTQL{O*|)L?wOZr$qH|H zSx;S~HSKx@Zm4ffbfz}Yzzu(7l9AS{Iu-6aX&S@T;&=V}BG=)FFq=}PL9Gy`iQV}x53ih0Ox0wh->0OV7P_z<2h5s zy5v)eJ{h&Pw2gBQ*&?C`k06!xA&1agSZQzk5)`whjZZioy}#cPQT>Y+^N8>!?s?(= zE@fL=7Z)9w6Ll!-aGG=p*}_7q`>^OMheTY_X(Ozg~tOfOSia-x`E%IR=|`hX+mT3R{LUObvQ9@ zp#KQjOiMw}5{S%`_LjBrX+s1F>Q5bZLFY2CmNOvE0 zw41nT?SaL?I+1J8fBo0YL%KUVY55=A=r6}hhkZ!AJ|1>D+65)W^i{c3o!cbvc_={>$MFA5fP@-@RVd6n)WHD47dSAUwBvICpcNDX_K`r}!&h z=CZRKOyVKG<~N%lZ(`ojoeH}U`>fgMN4w;XKJ!#B zL!~)Q>ZZoUAhzbTN&pboa?;s3)0RbF``eOYdCc_x>%5&j4jv2TMAkR#WZg+NF71p^#>eT zK~vEoe16YqmyU&vgVd9awm7D8aAOzXy^nD7mnB`<-xRW(DLt4ov{4o)wR;fpX6t2234zy2c-Sdp5$TAO?N!vjymU7U zr(&vRt4T#i!Y$3D=2|U83f?tE_^NRllm<&Kn~SOiIaXtZCJZv9BA#fg&G1VO;|oU{ zD&#fx_l5geEMce2#ft&UcQ;Dh0gu_ch_!6!9fnz_QYY<|H~J{WW*1E}8$RT;uXQAj*FUyZ)m@Q8Zoe#Xqo#>mvCtBc|I>Q za(7tps$#YFNTuHhabR|tMOI|5NPyd>`igZ69GANy9s5KZ9_3V$J=4X67`#D}Dy8}L zKkBCx*};{sC77h!TV*lsVPkS;uY&x-kiven3~QFsr3Z6qZT5oC!J%D^2VMESTfzaB z@9cTfv1b;tP1Cx|hKvUGp(L2M5%*eKlh|5{_4U4@D#(+X*_yPh1+KOZrrX;@19|IS z6QODDpWu+9Dw3p&>0gi1K-K`i6xP46suvBD8m^sQmYOM|t>Pq$tezHv*@^=1q?XBY zBVSqLr&q%ks=Gc}0xOXFt*T1~rc9NNfRqc}P`v_H$(0Bkps0Xut`0*KcNPt_x}4f) zeb;yn+R1)zsAe|6EoeBa&4Uqx>U9~I?W%te z5WR6a&y!F)4vF78>(_HX%Zo;jX`KjdN1SPRfaMlGjJ84F8QbAc=AL)W>p%X#1@ES|-dBPrB1JBW%GB|KhRi5o`J%IGds5E_lKPDjZjnW?^vK@6 zoAPqSb-mC5-qk>4k&MG!zRuPz5&fnXJiL-AXxW@@^Ft>d>G<`YSpLtSL4w(=m87(g z`8Hh~&_$}wVgDY1!r;VM{346dGSOeUI~G&PIm@g3%oJee6r2~ghNbi1TK-mJWSYnQ z2j#5MVc~KXI1nhWeK97i+1BQtiH=cnww>*}jxjP(K*7km(#6k1jgysv!~h!FO?U&7 zluM-2t2Qa4k*oim{6}VRtSzL&ouXV%q+H6?Sn@R6#iv$$gmw!XOq87-X7+kH9Yd<% zd7yHQ<64z>Wk)L&BtZcI_d|=@{J3nhe#+9cOkcUhr9LjUt!R2(lm(AVbhEvHETl-- z+T(fcRi3Ds1n|)`$L@LTSf+@20U$axc(W)Ts(uvlW-su8jN4!|aMI4Y3J~q4ozKn) zcMua1D6szUc1dIfv>4g1qYn0e64S!Q!miSj>2tE0ulnaE*^?(cj$h<%`uBKmRFrC zdt7}Renf9zX5l7{aB`~d)I9Z6c?K^_eoUb64L7POTS**~Tc0sJ)tOnQz zFzJ+Kk2LU&pEV4a^x{;NfE$(nBF3w5zQVb&ixydnPF*VwSW*9s^-9k)v288E4ZYZ~ zk(#nNNsMuVv>odRHE=iXi_JN3G`CH_wkY4+#K0L>I{Dw58Rm|WG$xexm4>>~5~pVgRW#reR!yXiRFjG4 zRsUyTpWGtHj*-W(PYqvJQ~o49y+y2`Q1u8{8mvnAKfX$&p{>Mo^#6g>r~ijS$Es{cTT115;DV@Jq~`>E{1w4>p;C#z1MlQy?B=V zTSddZ>IjXzDZubn?s^-vUe1PjXU+8foxQkzPd324d#$m&-LvrP;)I7_kTMe>fzbUA zM28}cg|`kh2wM?NL}9j$@~f}7mu7i>TO`9}VTvR03@Y-$;y*a=NG zw4}tl^3Akd5A#)xG2A4p>q~}>OKZIg4oRk_ zLV%`zXXiF4mtcCtgQdOw|0oHNUXwDpy9TilBNtODLvAc7DR?+F0Y}a6Mc~LJj|mAz z{shzL8_m1^PpaBCrVHsnX3`zIrr_*|jD~EW!=a75mv`0LUm9mL&Zy1*{e%Y)&D%Bt z0JUZ=sAQ@X2YE_vcnyHknyDC$1khzxWM=yBto1l~e z@ErY}@aNUA+CT*Bmz^AmuhxNowEs|k(A#i$!|AfdCCtStl()F zHc74%G+HG4D5N^nmr4pcx~Pi^+Kyn9nd&9N;MNWFF0;aaD~XytCUAaueju0i;>413 zm1E3nx~!N>#UE3su_oDt6S|RX47X7aIA>t(>ws9*oWP5kz}z0_(R{pvk5Wbzci#k% z1f_A7) zEPG{OR_)_8O(ly=ck%fTdD|Q>oyb(K`K5qfA5y!I+<>u%a{{e=>t`l( zdAZ$>H1_!Za~PTc4C)QE+8=C-9C5jM)OT~{Wq{V`M|W<9h>Vpu*_-@r+|L`_7xR*N zu-lB~TjFK2z;I5UiXEM}4aG?@-viTvQmaCVlQUgpc9<&1xy5ITXeX0x(oxffij4v1 z(9RKSH4bWw`N7rWX_-rT33#+cdU&ni+V6gCvrY*)i?6V2<2rkR?$6w1uLspOjuFr8 z^4k%{UsZxKcRZ3SVBJ#rJBS_oZm#I)FsLuZGPztepMLmbr@vsxew=av3f`c-KIf9U zx@d*(D`iyp`sn#>?)nmm88XFLP5Y~KOnh&enT22vdCEOt^=BJzbLH-zp}dCOb{EA( zFT~9y4sO;@Iuk#=whlCRaZxT>A)p5sx*&s~0hT{EYMGiQDSAw-JX~_`CH=>j&Dai& z6S+Csz?8(ang`4jhijK(ha+^Iw&rAaMBbaToYIS&K_GI{>ydPW_i~r{t-4h*+M@QS9Ub1WTLB==qJfqxC?>X;ra0fWP-!97SD7_& zowaj6C}`hVMpk%8KwyV_ck3+F_ilK;`U#!4vF7E*6DZ-0pIu?3<`BI_83SmOQn?!4 zq}uT9q%k;&<3Xjgke_0&=B$;nQ~A#6$W?(k>Dhm>ZquKHn|h0t!zP6Jc^clh^n{{E zPUF08g$>WmMz?ho<>VY6m|kZA4XfUf7AgykJ0xAW^QBEBNjA+!K8U&c>HQ|blIsOd zI#0DEIev3Ui@g2v!z9xxD)1OB^IX9}cT+$A`I3qigKC#`L zpfOOM66A2NR$1g5`Fun{yQ*oTZSr;j-%tBveOC^pGE3>_vQjoPr5H%n*AjTeZ0HO} z5es}5zm_M9279c>8;xKTU?A_it;vR?g?>ut%KO#sjHJE zcdC(0UiGpzE9I=5to^2<{~Zx;J*5Q{hOp4XMo1UzTIVR4#$ud~4s=2K$)jCVA01Mt z9(A2mLCrr!VV024ehk!_a=wYmJ?*PT;vwFsF38C|BO0?#9lBaMN^!@o>C-Yby2OpR zs&35C=~}|tIu_{D4aa*G&@gWb4o3Jt1?wJfX^vgrKv9sn zr`q^Fa$h%b+ZqQ8+t)ECc2Irr30>wyT?!hrv`vu?tH#C`#jMdt+fW+xN{+YGp~e*r zboBwYNa);td?W2qkdJ}*79YXL#Duj@l1Fg^X>$WVgdsB>jbeS`_cy4UM6VEUoQ{q; z9(@!NK_H>8bwZCkX_#vRjboN%nuxqm*wKW@;dzUJ20TfX*DR4}iPB_7V5HApwdPo* zIa6QBncXeEB5%qcpZF;$e!%u&5gB>0avAul;7FF8C#>afLUj#8m!c9Mn?_rtrUMbZ zCm#fmiB)4V&j&jY>*gCRiLd=qEcfeTNhnV){x2a7DJ}-%si*Hfr&gT>!j%DanI_M~ zWA(f9zZmlu)SkuWxoEnFT!Xmv)ynctf?oreo@`MR8zq@uL6#V723Ui~v=~)Pt?JB_ zmF2<%i91s4jC`}@zcHJx~|d48Py>93HR%JewuHq$@5P05qoQ;#ESCbO`}Zyq6Kcal;Yn7RmgZ)7{jFl1QA6M1N{Em*wa#ni^2 zF{{1h)p6%5&e2VSxgF}EKSALs`5}O|i67-cby@E8ihNwS-kGSaI2CYQAMRae#eDgf z2>&Y?DS5TLzxaX*h4|eD@WJoNkFE>SCuxO0h}%5f&a6cSa+b4j^%!Y3j8=EsOhx|1 zxK*V~lvy1ill_>I=$Qf~MM%PV&dHh+J!XgJ|gdyh%no~G>XU59+I-Ev|CVeWB4jekBqh#yQ z5q_kX{Y^K4^rUYaA0(N)jtY#Eyo;{;d%<;gG_#Ct=4S*Q@?Cnmjir*`MAo(nI_<$5 zNN5YQhBgOw6Sf?V+tvw$OCL(-W;~ormax+0s(r}5=OuQkWugo}NCJtZ13G4_sZc57 z$cFlHXX_h_HuAux=0W2!i-%!)mn*m=jr%O3(t&K-e{K@}L;BM+`^|<;Ry6>6q|XQ* zXI2F@rIeIS$pg;dll^1|)S4+~=`-F^@FfTZ(B%abDQf<99=TEwgy|)Y zz=bj2KY~E^itKO&tbPp8b+%2W4Y-kFn{y=H%an8yYzL`JZMXJ>wsp-!L7;uW~0;icCv!0>@`f$H<3!AVl#BFlN@6ry*wR!{pRi&l8!w zDiE`kRy8*Kxph>^jbPqXu*igrr1*I`*kOIi3vqkaCgPvqE$ynDe{7F4Y-vc|Ju^n5 zqY|dz-Z;hSLzLa02EK)v@InY%E7#!T>Ot2uw@8TEdyU&O8rRK>HSQG@^oKD6cE-Ha#QFzM#aU#g`HgTMqnQNs{(pd2+d@oixIOtTA z);KSZqlmW9wmKy^3NveYL&!cu(Nf{p{1oo2Vt`5Qfa3YWKtr|S$~ufNzryj($hfH& zBmY1x;1=HPeN3ya_Z`VJ3x4g5M-G3UPJZoZpmF|vlwZOh@)$s~q4Jgk5ikF4lUa#Y zGr+kZ`m&S|PKy4^Gd=oiWvo*^^aa)=hYu{NF@m0^tq5=D2U~T*{_lS9-dymzF8mC3 zS5m(EhtIslqG{u(PD5Ggp?)EEF4aZFykE!kfI|Gblvh-+stWu+ z-S+#p(T(#(+PjrIap-32Fb%2FLd>|v`)Mw5Q|pPq z8<%@*4lgX)?CWzh=7$s6+8pJ5P3fj|%ANjmzqHk8BS0V;NBD>Nv#37bZ-9Ex@TT$;5Vo`y7_6omI$%cWlMg9x zO2!1XFx)i>AU#fdkggK*X6d{93sA%sXi1TM+vr^b3(#=q$(V1KL6=mZ42UHoNw=0- zvMj4EsG!rgqu)_zvF({yr>0@>w>MYFT_c0&Ww6R0=+rPnCpYbm(-*bHo17E>Q0!88 zz`tmVbH8nnhOX^zo8#+|4OGR$cp5T7+8A^C2-Bnd+QgHEvaVD@PWEungr0#x%rSKl=YDXUp=%qe-*WGCy-yL%6 zcYO7r8~kR8wohGo8q3RQZ_$i912ZWW&)s=?)2y=)1-8Xv?JU3eH34JTF8@orY?_(? z=s26~)6*&DJM_Dzk37dTIo+qu{*o4$dpS#M5%DQrB{<|G!Ni8mw|h&gDuS-`zn}BxBttIgW|X9>x&V^>y=D5bs@fANSDdF8 zLh~$bF$5|axSmHZCFBB-X>%Ir@^o??l9$gnYOJxUdDUGGfAgu0V4>;%%qrg_gmpZR zvAQLizrMIMlytW4nYC`3^4b9$6mT6w4ZCz(`H_elFoWw+z$$DY^X|P!fDB3{V%EUY zymi1`+XXza&d#A)(ByeV#llX=Q*>^pH+53~?Nhzn4Q}p_j78w@PYA{L6!aX|9e$Sh z6__H9MpOObjau@tbN(-Gu0QEAmv-b~ExRliZ8cN%72TcN=5!M1DfL{<%_DWc;$oFs zuGFa8I}nhz)Znjv^^N-XGtqH5bYrphJ5qqyz)aG9}e*Xw;mxuovpH?&a7Xu zld?i8$8T$|*H`(@;WPplanPC=^){_SBWL3={~~=txAyF=k*vD9tjuK{>lciJ8Vr{I z=qgpoQICFX-bTD%-g(WxN_P#!nbuj5D#%b^FADev{Pg}6Hh{6%k?nk=);`lxv+9_2 zMuk_k+9}e;YWKd` zL>jmOp3Al+$9~WfC7S`@3+@qr*QkWhkq?#|9?|0R%vZorQ57a?o*={7Q_-l`5J4Ap zmCr0eS?q?+bj#-EcU6ssBTc8|d8UI{J0OcE0Xee#`+V(}6_MD^!-K!6^p}cF=zx)e^aue#LKGaisl?O?{Px>l+r4M!ocnt1b$8D5c|XsEh0g!J ztHT6I$}oHU?du?>fT8HK#r%X=2|I&1;C!*sAQUJ1~q>!`}o5AC&pOn+3@fguJF%-rcZRC<$1XU14|rNkOakP)BJmwILbGCOPeT*U(VP>t$ic z#WwaEk93~byJ#{=Nr==%eL8rB`XN5he|zz8&CWt{BaVoY&bX!;8K~K zs#)DH^X;r;%BV9~(~{&~$Jk}xekW=kZEU8Guy-GPkSJ|Aabr&wn9o|hj`2U_^_W%+ zHt$r-dy+hezqia+4Y&J6_3idI-5s^e{-x<%zay5uNvio+$m9H6my4y{-n@8|Xz$+X zH}vu4B611Fxt4Jr+v!~(8BA>CTpHrZoGfe`ti+YZxhg-%emIA)M8Y<54$H?K9lde_ck0Z zqc|5*Ga%dVH7PRUxg4W&s~@+aS&HFYst4m}|qW*RG(gr<|a$KjuXW8$oFzb@i0d6^s7nd%)J zeExvFm`c$TwrLGDpb>-?ooiAQ!MI?0IFHe=edpN^#6$S4M;xN!Zcg%DO;qF1)kE28 zjtF1CsK9iKC#PE5D-t1R$@3U2Dw}tK)0ut|&&?-Qkk^p5^Xc*`%=qc>FH4_?hP`Rc z>)|DU)M0L4i_vR=t%S%`DX<+Uyp>@J?WGGL)u_7?h;d6)8S7F1 zMoM%1!JiUB@#+L+VpuEgDn_(dW6`T61iuW$Er#`!b+@hL^PY5@w4C;5&Q+hP;-T9uXv_+e&`n^@zu}96h&)oNKxaAg#5a7}y20JR(YN8ncEOXq&6<#;9Y} zuwiAF_y`TKO&q7x!mJzDcN%LA!a|iy=wI#vyXTSz@lK&TE=ZUc1aurc_97q z7OiB5=w9&M>rD)#md=9hyL#S#kvhVZ*=#euj?4`54FKs&c0&qn=b;98FAeQCeZMAp*Paw z$MhBg-`>uM9UYRjb4^iu;=CB1r(W|RF#Px3{7{uQVPzuSQz%Lftw6eC_mIC>XsLX6 zm&&`e>z_u!Qj%&vq&)?fvZm*s>KRyGZG2M;HZ9T>+)wVwWq7eFN1-=S*mXbQ^Sex* z{?O;Bwjk>;vAU`H109uXbosL^iG3y&6ij5h$5~n=p0;89frw1 z)EFU!d|aLmsUW_of7sh{Fse;y=d-1y>xZ>GrJoSha?&v|qO#GzUuI7;JZqh}vGiG& z^(X3ajPQ4#TE#77?hsJ!h_`}uM_2hjiAI|q(YFMUl&x;}5{2u7pQGfQ#O8#OCG`ab zW$_WiwDgOJDTPgNfLBdt@0d6FIZ5G4f`?H%?C5I4hrFCZ%bP8eY6MaQ0iwyaFU!z1 z0a@-7bRcju8{I>Hub@wUVhe6gU{`vzd5Jeh{z}|Gx{}3w-5Ad=`{FBi_x0bhrA*qU zO?H=$vQyBa?S%Xs_#B6wh>4;NofwNzOt(I^UWl^#kulTle74uoIPIQv z+bYI=^6BQpmNTNNIP?u|il0ehGQ;f1zrO80I+Tq<-C6POJIHyv2cCHERQ@J^p09Z_xlO&%h0zJ<%1foT3HW` z!5ZJ|jnzMHIaW`^oo#qjyh`tmfaRyT>Bx5QRR3W(}l&CmYba!679s&W}j?*-Y+N80oEB3+$@`K_E@ z;SS*Ok`Y02TGoO62Wz2E?&o$na2!r>uqOPBzKXaaFn_N9kZ^q696j7VH*?N|qLV0) z$gT`rf!mY3|JA#>Y*|1LKgB(;3kDh=1Gbv9X3I13W-`F$FSU4b{K{G|gzDz~{VT#^5?TMd2k4NB)CxeqdW5GT^zs4 zMk{3#O?YKJ@k6{gY|5Dcg$DGp+W4uw-kOwrGe%Gyc~~HbZZNx2VM>!Kg?wNs8cPuG z+LupKTDd&-YK+gC?AL2a2~<%_AUp*#6lm5>i^|PT0^XB$}9JUF<{h1`$*d2CSYBxO}0N7KP@BHD7^)%ZTZT};$c$|Ba^zln{}y!DuBL3lGE zKd+n!aQ@a>7Y~fiGr3E2>YH-8S z-3;+txto1nQifp9DHXjS;OTQ`uE@TnV1N2J>$zBn1>t#udHa7ID)RNm1$!B);86iX zVKDPYR|JeJns`|*;|7Gv?$4MNqd*h9&J!F7-tw`r3yho!ZW`uZrcJa8DgL)J^q%+M zd&1UPg+2gQf>U+wOh9kh*e>Pm1>I8c`G^?%^J>6k!utLkB}l2XXsX8lUQXD}_@IAA zED2ejb*E0ZL5hXCcP(}A^v#5r7Cao4Nu+)sMa}tYGQeEy@mPk zWBOUHxH!6*@dFhMR+z&@Rzc^nY0{u&`$TugF}lS_)}ZM(z_y(4DR z9^%_p-8Xm1tV~cQ;6m`H8+~~7@UlMKWu?#}46l}%K@wc%P=wR{HB6*SOJ5C9olu5c zakeKM!|*PIu(BptPfZ`Dw=L4>!zM<}I8+0FrH92`Zk-=vQAZ1E*h6Iu8jMBxKRF?U z1s9N(uiL~{7^&iu*?O^Nj9DW_5ugNUIr>5!t2~I`!UACj*>h;HzeeaFW&updE{ni9 zI}(&(YU>7AADIJ`efS(QI2gZhg@=aq;7}^Py+;dZl9y;JGdQHS2^O3`_a_X68-&RS zYZmfr+wqfI7@KZZGgUReu3}?LMbzd0Q+M2x?qrXns*n6`Wc4CsYV52Iq_f7b>ptoj zu{Ev5FbX!U6n<0%E}h4oe(|A|{ZLFdOrtC;#;RyV7yE>Ahs7T+$F zoB4;YPdswIz0fl3uGd4Ur7!hk!*RH1n_2f;6PZMtxYE^D=uZvi!5t;_lG|{04~#9< zE7YaKzI$b2fMEkR#Z%b7)?K9!{YI_P`8P>#)rP7_&!qcdeP6b$rxO_ zJkXE=kQShs0+*q>ctl^Dd<>$}56n(*g8kS2-tF~a8Cma0N$moGXb;{=%IY)*FpB8= zvJ+M3tX{?$GI%(m7^|vlv4$*Vd+gGVrAxDRv%j_=q1j(vI__bd#ibXKKlaHzQ%yct zoH{n??0g&~h9OfcZzOz?H=248yMpPpdMSw#*Zpf@120;@fY}u1MZE)5qM*MU0f*U; zQJN|F0)(TUK`{carWQ19Q~*?v=`m86AlXv05jLS5k2sC1OIRfFM9Jk}Uhp>pb)Amt zxiF_qTv?XtyN5w{(DD)!A#>T+bMd*VD9I5;t>l*%3eKYw0-dpz3Bk`yDX&7WZH$9M z{W@+|u$L$}pm1IQQKr2r{g!_x!9{IPJ2ujrnra%^=#7M`FKk0qQuFiW$%2L4qvx8` z^86=OXzE;3m38%21_ueOMaDyPmnF&xF=#FuXvMno7 zbb+gXN2<>TjO6i}xa*l)jqEE&Y25#|COuZ%%^PR2h5?JI!)?l zew<$S*l-%d?&U!;I9>KipU^QxVLy`qH;QZva|QiDnE8-UHgk+1&Ii z;bl@4pEr<&ziZi9!7L4eUgD~=|U zQ%V{;#&Q^N-qF*J&gho@0{`-IPtbT&s8TjN+>>?kBgkz|Y|&?YUyO0V6|s#pwAN)) z?Mk9kj>`P-_mvDiqGF~mrDLRd0&b1DOyA@NjsLWRyl7aVx!5{EdQ*GI+dr5ua(&s< zD($QBcUx~b@<`_W1SxN-&|C8GLCI7(W!xO;X7MjXrZ6#klH(HxPN8~=;9`=&HW-F7 ze_Q22rPzr5n_Hi)CU~&A(r6W)n_+bTa?PNR-T+lp=E0uf)7&h3hEnQw2etGf)XU>$ z<>{ldQntud=jR9R!0ia`^ZuQCRdQ1Xp)wP9?(k33fnuzz!1DvEQ*kDYW&;Pc+vfC?&9PeAQRx8FXmp_ex-rKGyvvY1aQsomf$1n|q2w>!Snt?QKfESbi&S-Qz||2hJ955#TU(X6Mu@hW^`vgyHx z64&Vz2HU@$Brv)pLZO#kmsv{Ga3RNUXTe#gd(tB^IjO3BM5ha@8bp;tZEs;>H&IZM zLHrXmRPz};WpS&L<;zJpj#1joMt(ji*qyRa@6&Qf689n*_tKuij9w!Frlg~t#?Q`r zo+Ip(f_1TfRmoh+I~XpV0aTiSCQ85s-&x!n^Ii36$r$*(<4F6-c9;+2~rysXi> z9q^Xe%lrRHVI!7VMpae6g{r;KqB~s(pW{w$;F+#aFcoL*{&cO5-xG@6zi4>c*5DK^ z9^Ll>mNleHGeVbNkl*I@kZAZJT6uE2y8N5Q5WwK5F{$|qv{LU@)#uF@gunaEjip4~ zfh7#yT$dO2cU(DJh#P|1SG6Y#8b)zd=_hY9)J z$X=k&`_`gs%`rz9aGLd^gHpfA8(j73{IemGSG|+eDx_jq56mWJi$(T4r{-|WX^o>v z?6LEfF#4OmVB?cv%^pcGPIv4n3b=ii5RwXqwk>USC{|Zi3Sq{℞1n9C7f*I{uQl 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 LGt+I=c8&cX6A&Gm literal 0 HcmV?d00001 diff --git a/src/components/scaffolder/scaffolder.controller.js b/src/components/scaffolder/scaffolder.controller.js new file mode 100644 index 0000000..8916850 --- /dev/null +++ b/src/components/scaffolder/scaffolder.controller.js @@ -0,0 +1,26 @@ +'use strict'; + +angular.module('iframeLayout').controller('ScaffolderCtrl', function ($scope) { + + $scope.iframeWidth = function(index, first, last) { + switch($scope.layout) { + case "horizontal": + return (100/$scope.urls.length) + "%"; + case "tail": + return "50%"; + case "head": + return "50%"; + } + }; + + $scope.iframeHeight = function(index, first, last) { + if ($scope.layout === "horizontal" + || $scope.layout === "head" && first + || $scope.layout === "tail" && last) { + return "100%"; + } else { + return (100/($scope.urls.length-1)) + "%"; + } + }; + +}); diff --git a/src/components/scaffolder/scaffolder.directive.js b/src/components/scaffolder/scaffolder.directive.js new file mode 100644 index 0000000..0b1086f --- /dev/null +++ b/src/components/scaffolder/scaffolder.directive.js @@ -0,0 +1,13 @@ +'use strict'; + +angular.module('iframeScaffolder').directive('scaffolder', function() { + return { + restrict: "E", + controller: "ScaffolderCtrl", + templateUrl: 'components/scaffolder/scaffolder.html', + scope: { + urls: "=", + layout: "=" + } + }; +}); diff --git a/src/components/scaffolder/scaffolder.html b/src/components/scaffolder/scaffolder.html new file mode 100644 index 0000000..71f0045 --- /dev/null +++ b/src/components/scaffolder/scaffolder.html @@ -0,0 +1,8 @@ +
+ +
diff --git a/src/components/scaffolder/scaffolder.less b/src/components/scaffolder/scaffolder.less new file mode 100644 index 0000000..d646464 --- /dev/null +++ b/src/components/scaffolder/scaffolder.less @@ -0,0 +1,42 @@ +.scaffolder { + width: 100%; + height: 100%; + position:relative; + + &__iframe { + display: block; + float:left; + } + + &--horizontal { + .scaffolder__iframe { + height:100%; + } + } + + &--head { + .scaffolder__iframe { + margin-left:50%; + } + + .scaffolder__iframe:first-child { + margin:0; + position:absolute; + left:0; + top:0; + } + } + + &--tail { + .scaffolder__iframe { + margin-right:50%; + } + + .scaffolder__iframe:last-child { + margin:0; + position:absolute; + right:0; + top:0; + } + } +} diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6527905307f19ba00762f9241f7eb535fa84a2f9 GIT binary patch literal 4286 zcmchaPe@cz6vpqQW1y54B@{_hhFD-kWPgyXjSGVaf);_51TESOlSPOdvy}@W5Q+** zs6~RrtlR}7(V|sCkP&1f7!5{Hixw@4+x@+HXSm*Z^WGalm2d8S=brO@=iGm9MyZ7P zPo)%}YN|=8W~EfSfibDm2H3qnGq$y%h@zqVv#zn@@WvhIGJ8*ECePe@roq(*vwGys z4?Q;bI~MRIM&jXu6Yg@wqQ#8&8x#z55E}ONd3<&rw_h!5AbBx{CcZ%&z736jHxFa0 zsBLqly3+dQ%MZGH{QU}GW6bsq=@$a@sXtac^<8>8uP>*+d!Qdtv&&mnKlvE_T-+SC z*QNCVwcvq%+&DDc+T}Uf(2_FavDN{-&hCpIs?aW=A$mcrzyD+9(025i1~K&uVf&w4 zItQLK9T{7k?s@bnU*&p+<^UI*aHA1aH+Fo^PAzM|xjNK09?2V(Cme7IFB(BP?7#at z(>DB3w`AUFS~=(LUBdZ>v-SG4J~%Mrfj&05Z)oj13l5tbEq4x>8+;FC0Dvr zbJY#7PS$+yE_Cf7gxqQEC@RoZX5J^}71l+`Q~qnOF4D za`lhjUuqZa-sj)EHDleV2i|mc!Ly-@7IwzPM{?pBUt(+@IHi8HTz#Iq9)9h|hrL3) zfOT#@|5$JCxmRjsOj>&kUt(m8*57|W(FoE`CX*8edYv%j=3sR5>!hvglJ#@8K6j$g z&IuUbRC_{)p}sbyx%UD6Fki;t6nDk0gT5&6Q_at7FbVVOu?4VK{oR#!kyYbCc;<4+LITzoZ8-~O5L+9MiLHL4NyME>! z;Ky7<)UR!gN_~GXhMvPMHNB;EmmIK}eHD&~cRx89jth}IM#tU%ablw0|GxfE9IjRR zl-)b-IvC#UD!IewzPL77SI>R+?}<2ERr|R2o~zCC8rJUR8>DI5*0O$6+k~wZ)Mt;b z(Hul-OFl+F))}lK&&Yi*+S2kJmHDbdBWOQnaSA6S|#* + + + + Iframe Scaffolder + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/e2e/main.js b/test/e2e/main.js new file mode 100644 index 0000000..d84caa7 --- /dev/null +++ b/test/e2e/main.js @@ -0,0 +1,9 @@ +'use strict'; + +describe('The main view', function () { + + beforeEach(function () { + browser.get('http://localhost:3000/index.html'); + }); + +}); diff --git a/test/karma.conf.js b/test/karma.conf.js new file mode 100644 index 0000000..773df34 --- /dev/null +++ b/test/karma.conf.js @@ -0,0 +1,28 @@ +'use strict'; + +module.exports = function(config) { + + config.set({ + basePath : '..', //!\\ Ignored through gulp-karma //!\\ + + files : [ //!\\ Ignored through gulp-karma //!\\ + 'src/bower_components/angular/angular.js', + 'src/bower_components/angular/angular-route.js', + 'src/bower_components/angular-mocks/angular-mocks.js', + 'src/{app,components}/** /*.js', + 'test/unit/** /*.js' + ], + + autoWatch : false, + + frameworks: ['jasmine'], + + browsers : ['PhantomJS'], + + plugins : [ + 'karma-phantomjs-launcher', + 'karma-jasmine' + ] + }); + +}; diff --git a/test/protractor.conf.js b/test/protractor.conf.js new file mode 100644 index 0000000..6828f62 --- /dev/null +++ b/test/protractor.conf.js @@ -0,0 +1,21 @@ +// An example configuration file. +exports.config = { + // The address of a running selenium server. + //seleniumAddress: 'http://localhost:4444/wd/hub', + seleniumServerJar: '../node_modules/protractor/selenium/selenium-server-standalone-2.43.1.jar', // Make use you check the version in the folder + + // Capabilities to be passed to the webdriver instance. + capabilities: { + 'browserName': 'chrome' + }, + + // Spec patterns are relative to the current working directly when + // protractor is called. + specs: ['test/e2e/**/*.js'], + + // Options to be passed to Jasmine-node. + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000 + } +}; diff --git a/test/unit/main.js b/test/unit/main.js new file mode 100644 index 0000000..e9c138c --- /dev/null +++ b/test/unit/main.js @@ -0,0 +1,12 @@ +'use strict'; + +describe('controllers', function(){ + var scope; + + beforeEach(module('iframeScaffolder')); + + beforeEach(inject(function($rootScope) { + scope = $rootScope.$new(); + })); + +});