diff --git a/app/Resources/TwigBundle/views/Exception/error.html.twig b/app/Resources/TwigBundle/views/Exception/error.html.twig new file mode 100644 index 0000000..7ae51b2 --- /dev/null +++ b/app/Resources/TwigBundle/views/Exception/error.html.twig @@ -0,0 +1,39 @@ + + + + + {{ 'An Error Occured' | trans }}: {{ status_text }} + + + + +
+
+
+

{{ "We've got a problem" | trans }}

+
+
+
+
+
    +
  • +
+
+
+
{{ status_code }}
+
+
+
+
+
{{ status_text }}
+
+
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/src/FDevs/CommonBundle/Resources/public/css/error_page.css b/src/FDevs/CommonBundle/Resources/public/css/error_page.css new file mode 100644 index 0000000..673232a --- /dev/null +++ b/src/FDevs/CommonBundle/Resources/public/css/error_page.css @@ -0,0 +1,25 @@ +.error-container { + text-align: center; +} + +.error-container img { + width: 350px; +} + +.error-container h1 { + margin: 50px 0; +} + +.error-container .error-code { + font-size: 150px; + line-height: 150px; + margin: 80px 0 0 0; + font-weight: bold; + color: #AA3333; +} +.error-container .error-msg { + font-size: 60px; + line-height: 60px; + font-weight: bold; + margin: 20px 0; +} \ No newline at end of file diff --git a/src/FDevs/CommonBundle/Resources/public/images/bart.gif b/src/FDevs/CommonBundle/Resources/public/images/bart.gif new file mode 100644 index 0000000..36136f1 Binary files /dev/null and b/src/FDevs/CommonBundle/Resources/public/images/bart.gif differ diff --git a/src/FDevs/CommonBundle/Resources/public/js/error_page.js b/src/FDevs/CommonBundle/Resources/public/js/error_page.js new file mode 100644 index 0000000..db0cd96 --- /dev/null +++ b/src/FDevs/CommonBundle/Resources/public/js/error_page.js @@ -0,0 +1,14 @@ +$(document).ready(function() { + $('#scene').parallax({ + calibrateX: false, + calibrateY: false, + invertX: true, + invertY: true, + limitX: false, + limitY: false, + scalarX: 5, + scalarY: 4, + frictionX: 0.3, + frictionY: 0.6 + }); +}); diff --git a/src/FDevs/CommonBundle/Resources/public/js/vendor/jquery.parallax.js b/src/FDevs/CommonBundle/Resources/public/js/vendor/jquery.parallax.js new file mode 100644 index 0000000..ad91709 --- /dev/null +++ b/src/FDevs/CommonBundle/Resources/public/js/vendor/jquery.parallax.js @@ -0,0 +1,481 @@ +//============================================================ +// +// The MIT License +// +// Copyright (C) 2013 Matthew Wagerfield - @mwagerfield +// +// 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. +// +//============================================================ + +/** + * jQuery/Zepto Parallax Plugin + * @author Matthew Wagerfield - @mwagerfield + * @description Creates a parallax effect between an array of layers, + * driving the motion from the gyroscope output of a smartdevice. + * If no gyroscope is available, the cursor position is used. + */ +;(function($, window, document, undefined) { + + var NAME = 'parallax'; + var MAGIC_NUMBER = 30; + var DEFAULTS = { + calibrationThreshold: 100, + calibrationDelay: 500, + supportDelay: 500, + calibrateX: false, + calibrateY: true, + invertX: true, + invertY: true, + limitX: false, + limitY: false, + scalarX: 10.0, + scalarY: 10.0, + frictionX: 0.1, + frictionY: 0.1 + }; + + function Plugin(element, options) { + + // DOM Context + this.element = element; + + // Selections + this.$context = $(element).data('api', this); + this.$layers = this.$context.find('.layer'); + + // Data Extraction + var data = { + calibrateX: this.$context.data('calibrate-x') || null, + calibrateY: this.$context.data('calibrate-y') || null, + invertX: this.$context.data('invert-x') || null, + invertY: this.$context.data('invert-y') || null, + limitX: parseFloat(this.$context.data('limit-x')) || null, + limitY: parseFloat(this.$context.data('limit-y')) || null, + scalarX: parseFloat(this.$context.data('scalar-x')) || null, + scalarY: parseFloat(this.$context.data('scalar-y')) || null, + frictionX: parseFloat(this.$context.data('friction-x')) || null, + frictionY: parseFloat(this.$context.data('friction-y')) || null + }; + + // Delete Null Data Values + for (var key in data) { + if (data[key] === null) delete data[key]; + } + + // Compose Settings Object + $.extend(this, DEFAULTS, options, data); + + // States + this.calibrationTimer = null; + this.calibrationFlag = true; + this.enabled = false; + this.depths = []; + this.raf = null; + + // Offset + this.ox = 0; + this.oy = 0; + this.ow = 0; + this.oh = 0; + + // Calibration + this.cx = 0; + this.cy = 0; + + // Input + this.ix = 0; + this.iy = 0; + + // Motion + this.mx = 0; + this.my = 0; + + // Velocity + this.vx = 0; + this.vy = 0; + + // Callbacks + this.onMouseMove = this.onMouseMove.bind(this); + this.onDeviceOrientation = this.onDeviceOrientation.bind(this); + this.onOrientationTimer = this.onOrientationTimer.bind(this); + this.onCalibrationTimer = this.onCalibrationTimer.bind(this); + this.onAnimationFrame = this.onAnimationFrame.bind(this); + this.onWindowResize = this.onWindowResize.bind(this); + + // Initialise + this.initialise(); + } + + Plugin.prototype.transformSupport = function(value) { + var element = document.createElement('div'); + var propertySupport = false; + var propertyValue = null; + var featureSupport = false; + var cssProperty = null; + var jsProperty = null; + for (var i = 0, l = this.vendors.length; i < l; i++) { + if (this.vendors[i] !== null) { + cssProperty = this.vendors[i][0] + 'transform'; + jsProperty = this.vendors[i][1] + 'Transform'; + } else { + cssProperty = 'transform'; + jsProperty = 'transform'; + } + if (element.style[jsProperty] !== undefined) { + propertySupport = true; + break; + } + } + switch(value) { + case '2D': + featureSupport = propertySupport; + break; + case '3D': + if (propertySupport) { + document.body.appendChild(element); + element.style[jsProperty] = 'translate3d(1px,1px,1px)'; + propertyValue = window.getComputedStyle(element).getPropertyValue(cssProperty); + featureSupport = propertyValue !== undefined && propertyValue.length > 0 && propertyValue !== "none"; + document.body.removeChild(element); + } + break; + } + return featureSupport; + }; + + Plugin.prototype.ww = null; + Plugin.prototype.wh = null; + Plugin.prototype.hw = null; + Plugin.prototype.hh = null; + Plugin.prototype.portrait = null; + Plugin.prototype.desktop = !navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|mobi|tablet|opera mini|nexus 7)/i); + Plugin.prototype.vendors = [null,['-webkit-','webkit'],['-moz-','Moz'],['-o-','O'],['-ms-','ms']]; + Plugin.prototype.motionSupport = !!window.DeviceMotionEvent; + Plugin.prototype.orientationSupport = !!window.DeviceOrientationEvent; + Plugin.prototype.orientationStatus = 0; + Plugin.prototype.transform2DSupport = Plugin.prototype.transformSupport('2D'); + Plugin.prototype.transform3DSupport = Plugin.prototype.transformSupport('3D'); + + Plugin.prototype.initialise = function() { + + // Configure Styles + if (this.$context.css('position') === 'static') { + this.$context.css({ + position:'relative' + }); + } + this.$layers.css({ + position:'absolute', + display:'block', + height:'100%', + width:'100%', + left: 0, + top: 0 + }); + this.$layers.first().css({ + position:'relative' + }); + + // Cache Depths + this.$layers.each($.proxy(function(index, element) { + this.depths.push($(element).data('depth') || 0); + }, this)); + + // Hardware Accelerate Elements + this.accelerate(this.$context); + this.accelerate(this.$layers); + + // Setup + this.updateDimensions(); + this.enable(); + this.queueCalibration(this.calibrationDelay); + }; + + Plugin.prototype.updateDimensions = function() { + + // Cache Context Dimensions + this.ox = this.$context.offset().left; + this.oy = this.$context.offset().top; + this.ow = this.$context.width(); + this.oh = this.$context.height(); + + // Cache Window Dimensions + this.ww = window.innerWidth; + this.wh = window.innerHeight; + this.hw = this.ww / 2; + this.hh = this.wh / 2; + }; + + Plugin.prototype.queueCalibration = function(delay) { + clearTimeout(this.calibrationTimer); + this.calibrationTimer = setTimeout(this.onCalibrationTimer, delay); + }; + + Plugin.prototype.enable = function() { + if (!this.enabled) { + this.enabled = true; + if (this.orientationSupport) { + this.portrait = null; + window.addEventListener('deviceorientation', this.onDeviceOrientation); + setTimeout(this.onOrientationTimer, this.supportDelay); + } else { + this.cx = 0; + this.cy = 0; + this.portrait = false; + window.addEventListener('mousemove', this.onMouseMove); + } + window.addEventListener('resize', this.onWindowResize); + this.raf = requestAnimationFrame(this.onAnimationFrame); + } + }; + + Plugin.prototype.disable = function() { + if (this.enabled) { + this.enabled = false; + if (this.orientationSupport) { + window.removeEventListener('deviceorientation', this.onDeviceOrientation); + } else { + window.removeEventListener('mousemove', this.onMouseMove); + } + window.removeEventListener('resize', this.onWindowResize); + cancelAnimationFrame(this.raf); + } + }; + + Plugin.prototype.calibrate = function(x, y) { + this.calibrateX = x === undefined ? this.calibrateX : x; + this.calibrateY = y === undefined ? this.calibrateY : y; + }; + + Plugin.prototype.invert = function(x, y) { + this.invertX = x === undefined ? this.invertX : x; + this.invertY = y === undefined ? this.invertY : y; + }; + + Plugin.prototype.friction = function(x, y) { + this.frictionX = x === undefined ? this.frictionX : x; + this.frictionY = y === undefined ? this.frictionY : y; + }; + + Plugin.prototype.scalar = function(x, y) { + this.scalarX = x === undefined ? this.scalarX : x; + this.scalarY = y === undefined ? this.scalarY : y; + }; + + Plugin.prototype.limit = function(x, y) { + this.limitX = x === undefined ? this.limitX : x; + this.limitY = y === undefined ? this.limitY : y; + }; + + Plugin.prototype.clamp = function(value, min, max) { + value = Math.max(value, min); + value = Math.min(value, max); + return value; + }; + + Plugin.prototype.css = function(element, property, value) { + var jsProperty = null; + for (var i = 0, l = this.vendors.length; i < l; i++) { + if (this.vendors[i] !== null) { + jsProperty = $.camelCase(this.vendors[i][1] + '-' + property); + } else { + jsProperty = property; + } + if (element.style[jsProperty] !== undefined) { + element.style[jsProperty] = value; + break; + } + } + }; + + Plugin.prototype.accelerate = function($element) { + for (var i = 0, l = $element.length; i < l; i++) { + var element = $element[i]; + this.css(element, 'transform', 'translate3d(0,0,0)'); + this.css(element, 'transform-style', 'preserve-3d'); + this.css(element, 'backface-visibility', 'hidden'); + } + }; + + Plugin.prototype.setPosition = function(element, x, y) { + x += '%'; + y += '%'; + if (this.transform3DSupport) { + this.css(element, 'transform', 'translate3d('+x+','+y+',0)'); + } else if (this.transform2DSupport) { + this.css(element, 'transform', 'translate('+x+','+y+')'); + } else { + element.style.left = x; + element.style.top = y; + } + }; + + Plugin.prototype.onOrientationTimer = function(event) { + if (this.orientationSupport && this.orientationStatus === 0) { + this.disable(); + this.orientationSupport = false; + this.enable(); + } + }; + + Plugin.prototype.onCalibrationTimer = function(event) { + this.calibrationFlag = true; + }; + + Plugin.prototype.onWindowResize = function(event) { + this.updateDimensions(); + }; + + Plugin.prototype.onAnimationFrame = function() { + var dx = this.ix - this.cx; + var dy = this.iy - this.cy; + if ((Math.abs(dx) > this.calibrationThreshold) || (Math.abs(dy) > this.calibrationThreshold)) { + this.queueCalibration(0); + } + if (this.portrait) { + this.mx = (this.calibrateX ? dy : this.iy) * this.scalarX; + this.my = (this.calibrateY ? dx : this.ix) * this.scalarY; + } else { + this.mx = (this.calibrateX ? dx : this.ix) * this.scalarX; + this.my = (this.calibrateY ? dy : this.iy) * this.scalarY; + } + if (!isNaN(parseFloat(this.limitX))) { + this.mx = this.clamp(this.mx, -this.limitX, this.limitX); + } + if (!isNaN(parseFloat(this.limitY))) { + this.my = this.clamp(this.my, -this.limitY, this.limitY); + } + this.vx += (this.mx - this.vx) * this.frictionX; + this.vy += (this.my - this.vy) * this.frictionY; + for (var i = 0, l = this.$layers.length; i < l; i++) { + var depth = this.depths[i]; + var layer = this.$layers[i]; + var xOffset = this.vx * depth * (this.invertX ? -1 : 1); + var yOffset = this.vy * depth * (this.invertY ? -1 : 1); + this.setPosition(layer, xOffset, yOffset); + } + this.raf = requestAnimationFrame(this.onAnimationFrame); + }; + + Plugin.prototype.onDeviceOrientation = function(event) { + + // Validate environment and event properties. + if (!this.desktop && event.beta !== null && event.gamma !== null) { + + // Set orientation status. + this.orientationStatus = 1; + + // Extract Rotation + var x = (event.beta || 0) / MAGIC_NUMBER; // -90 :: 90 + var y = (event.gamma || 0) / MAGIC_NUMBER; // -180 :: 180 + + // Detect Orientation Change + var portrait = window.innerHeight > window.innerWidth; + if (this.portrait !== portrait) { + this.portrait = portrait; + this.calibrationFlag = true; + } + + // Set Calibration + if (this.calibrationFlag) { + this.calibrationFlag = false; + this.cx = x; + this.cy = y; + } + + // Set Input + this.ix = x; + this.iy = y; + } + }; + + Plugin.prototype.onMouseMove = function(event) { + + // Calculate Input + this.ix = (event.pageX - this.hw) / this.hw; + this.iy = (event.pageY - this.hh) / this.hh; + }; + + var API = { + enable: Plugin.prototype.enable, + disable: Plugin.prototype.disable, + calibrate: Plugin.prototype.calibrate, + friction: Plugin.prototype.friction, + invert: Plugin.prototype.invert, + scalar: Plugin.prototype.scalar, + limit: Plugin.prototype.limit + }; + + $.fn[NAME] = function (value) { + var args = arguments; + return this.each(function () { + var $this = $(this); + var plugin = $this.data(NAME); + if (!plugin) { + plugin = new Plugin(this, value); + $this.data(NAME, plugin); + } + if (API[value]) { + plugin[value].apply(plugin, Array.prototype.slice.call(args, 1)); + } + }); + }; + +})(window.jQuery || window.Zepto, window, document); + +/** + * Request Animation Frame Polyfill. + * @author Tino Zijdel + * @author Paul Irish + * @see https://gist.github.com/paulirish/1579671 + */ +;(function() { + + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + + for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) { + window.requestAnimationFrame = function(callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function() { callback(currTime + timeToCall); }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + } + + if (!window.cancelAnimationFrame) { + window.cancelAnimationFrame = function(id) { + clearTimeout(id); + }; + } + +}());