diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..797bb19 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,62 @@ +{ + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "es3": false, + "forin": true, + "freeze": true, + "immed": true, + "indent": 4, + "latedef": "nofunc", + "newcap": true, + "noarg": true, + "noempty": true, + "nonbsp": true, + "nonew": true, + "plusplus": false, + "quotmark": "single", + "undef": true, + "unused": false, + "strict": false, + "maxparams": 10, + "maxdepth": 5, + "maxstatements": 40, + "maxcomplexity": 8, + "maxlen": 120, + + "asi": false, + "boss": false, + "debug": false, + "eqnull": true, + "esnext": false, + "evil": false, + "expr": false, + "funcscope": false, + "globalstrict": false, + "iterator": false, + "lastsemic": false, + "laxbreak": false, + "laxcomma": false, + "loopfunc": true, + "maxerr": false, + "moz": false, + "multistr": false, + "notypeof": false, + "proto": false, + "scripturl": false, + "shadow": false, + "sub": true, + "supernew": false, + "validthis": false, + "noyield": false, + + "browser": true, + "node": true, + + "globals": { + "angular": false, + "Tether": false, + "$": false + } +} diff --git a/Gruntfile.js b/Gruntfile.js index 3fdadea..e12dc47 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,10 +6,10 @@ module.exports = function (grunt) { grunt.initConfig({ pkg: require('./bower.json'), paths : { - src : "src", - dist : "dist", - demo : "examples", - tmp : ".tmp" + src : 'src', + dist : 'dist', + demo : 'examples', + tmp : '.tmp' }, watch: { sass: { @@ -70,21 +70,21 @@ module.exports = function (grunt) { } }, concat: { - options: { - banner: - '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + - '<%= grunt.template.today("yyyy-mm-dd") %> */' + - '(function (root, factory) {' + - 'if (typeof define === "function" && define.amd) {' + - 'define(["tether"], factory);' + - '} else if (typeof exports === "object") {' + - 'module.exports = factory(require("tether"));' + - '} else {' + - 'root.test = factory(root.Tether)};' + - '}(this, function(Tether) {' + - ' ', - footer: '}));' - }, + //options: { + // banner: + // '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + + // '<%= grunt.template.today("yyyy-mm-dd") %> */' + + // '(function (root, factory) {' + + // 'if (typeof define === "function" && define.amd) {' + + // 'define(["tether"], factory);' + + // '} else if (typeof exports === "object") {' + + // 'module.exports = factory(require("tether"));' + + // '} else {' + + // 'root.test = factory(root.Tether)};' + + // '}(this, function(Tether) {' + + // ' ', + // footer: '}));' + //}, dist: { src: ['<%= paths.tmp %>/**/*.js'], dest: '<%= paths.dist %>/angular-tether.js' diff --git a/bower.json b/bower.json index d54ce1c..65e3b0b 100755 --- a/bower.json +++ b/bower.json @@ -1,18 +1,18 @@ { "name": "angular-tether", - "version": "0.1.5", + "version": "0.2.0", "main": "./dist/angular-tether.js", "repository": { "type": "git", "url": "git://github.com/nissoh/angular-tether.git" }, "dependencies": { - "angular": "~1.2", "tether": "~0.6.5", - "angular-animate": "~1.2.18" + "angular": "~1.3.8", + "angular-animate": "~1.3.8" }, "devDependencies": { - "angular-ui-ace": "~0.1.1" + "angular-ui-ace": "~0.1.2" }, "ignore": [ "node_modules", diff --git a/dist/angular-tether.js b/dist/angular-tether.js index 1cd3d20..9da8957 100644 --- a/dist/angular-tether.js +++ b/dist/angular-tether.js @@ -1,16 +1,14 @@ -/*! angular-tether - v0.1.5 - 2014-07-15 */(function (root, factory) {if (typeof define === "function" && define.amd) {define(["tether"], factory);} else if (typeof exports === "object") {module.exports = factory(require("tether"));} else {root.test = factory(root.Tether)};}(this, function(Tether) { angular.module('ngTetherPopover', ['ngTether']).directive('tetherPopover', [ - 'Tether', - '$parse', - 'Utils', - function (Tether, $parse, Utils) { +(function () { + angular.module('ngTetherPopover', ['ngTether']).directive('tetherPopover', tetherPopoverDirective); + function tetherPopoverDirective(Tether, TetherUtils) { return { restrict: 'A', scope: { tetherPopover: '=', config: '=' }, - link: function postLink(scope, elem, attrs) { - scope.tetherPopover = new Tether(Utils.extendDeep({ + link: function postLink(scope, elem) { + scope.tetherPopover = new Tether(TetherUtils.extendDeep({ parentScope: scope.$parent, leaveOnBlur: true, tether: { @@ -23,31 +21,20 @@ }] } }, scope.config)); - scope.$watch('tetherPopover.config.targetAttachment', function () { - if (scope.tetherPopover.isActive()) { - scope.tetherPopover.position(); - } - }, true); - scope.$watch('tetherPopover.config.attachment', function () { - if (scope.tetherPopover.isActive()) { - scope.tetherPopover.position(); - } - }, true); } }; } -]); -angular.module('ngTetherTooltip', ['ngTether']).directive('tetherTooltip', [ - 'Tether', - 'Utils', - function (Tether, Utils) { +}()); +(function () { + angular.module('ngTetherTooltip', ['ngTether']).directive('tetherTooltip', tetherTooltipDirective); + function tetherTooltipDirective(Tether, TetherUtils) { return { scope: { content: '@tetherTooltip', config: '=config' }, - link: function postLink(scope, elem, attrs) { - var tooltip = new Tether(Utils.extendDeep({ + link: function postLink(scope, elem) { + var tooltip = new Tether(TetherUtils.extendDeep({ template: '
{{ content }}
', parentScope: scope, tether: { @@ -65,154 +52,139 @@ angular.module('ngTetherTooltip', ['ngTether']).directive('tetherTooltip', [ tooltip.enter(); }); elem.on('mouseleave', function () { - tooltip.leave(); - }); - scope.$on('$destroy', function () { - elem.unbind('hover'); - elem.unbind('mouseleave'); + scope.$apply(tooltip.leave); }); } }; } -]); -angular.module('ngTether', []).factory('Utils', [ - '$compile', - function ($compile) { +}()); +(function (Tether, angular) { + angular.module('ngTether', []).factory('TetherUtils', tetherUtils).factory('Tether', tetherInstanceDirective); + function tetherUtils() { var Utils = {}; Utils.extendDeep = function deepExtend(target, source) { - for (var prop in source) - if (prop in target) - angular.extend(target[prop], source[prop]); - else - target[prop] = source[prop]; + for (var key in source) { + if (key in target) { + angular.extend(target[key], source[key]); + } else { + target[key] = source[key]; + } + } return target; }; return Utils; } -]).factory('Tether', [ - '$compile', - '$rootScope', - '$log', - '$window', - '$animate', - '$controller', - '$timeout', - '$q', - '$http', - '$templateCache', - function ($compile, $rootScope, $log, $window, $animate, $controller, $timeout, $q, $http, $templateCache) { + tetherInstanceDirective.$inject = [ + '$compile', + '$rootScope', + '$document', + '$templateCache', + '$animate', + '$controller', + '$q', + '$http' + ]; + function tetherInstanceDirective($compile, $rootScope, $document, $templateCache, $animate, $controller, $q, $http) { return function (config) { 'use strict'; - if (!(!config.template ^ !config.templateUrl)) { + if (!(config.template || config.templateUrl)) { throw new Error('Expected one of either `template` or `templateUrl`'); } - config.tether = config.tether || {}; - var controller = config.controller || angular.noop, controllerAs = config.controllerAs, parentScope = config.parentScope || $rootScope, extend = angular.extend, element = null, scope, html, tether, bodyEl = angular.element($window.document.body); - // Attach a tether element and the target element. - function attachTether() { - tether = new Tether(extend({ element: element[0] }, config.tether)); + if (!Tether) { + throw new Error('Tether is required`'); } - function templateDfd() { - var template = config.template ? $templateCache.get(config.template) || config.template : $http.get(config.templateUrl, { cache: $templateCache }).then(function (resp) { + config.tether = config.tether || {}; + var controller = config.controller || angular.noop, controllerAs = config.controllerAs, parentScope = config.parentScope || $rootScope, extend = angular.extend, element = null, scope, activeAnimatePromise; + var tether = { + enter: enter, + leave: leave, + active: false, + config: config.tether + }; + // backward compatible method until next major version is released + tether.isActive = function () { + return tether.active; + }; + function templateDeferred() { + var template; + if (config.template) { + template = $templateCache.get(config.template) || config.template; + } else { + template = $http.get(config.templateUrl, { cache: $templateCache }).then(function (resp) { return resp.data; }); + } return $q.when(template); } function create(html, locals) { + var ctrl; element = angular.element(html.trim()); + tether.tetherInstance = new Tether(extend({ element: element[0] }, config.tether)); scope = parentScope.$new(); // assign locals being passed on enter method. if (locals) { - for (var prop in locals) { - scope[prop] = locals[prop]; + for (var key in locals) { + if (locals.hasOwnProperty(key)) { + scope[key] = locals[key]; + } } } if (config.controller) { - var ctrl = $controller(controller, { $scope: scope }); + ctrl = $controller(controller, { $scope: scope }); } if (controllerAs) { scope[controllerAs] = ctrl; } $compile(element)(scope); - scope.$on('$destroy', destroy); - // Hack. html is being compiled asynchronously the dimensions of the element - // would most likley have a different dimensions after compilation - $timeout(function () { - if (!element) - return; - $animate.enter(element, bodyEl); - attachTether(); - tether.position(); + tether.active = true; + scope.$watch(function () { + tether.tetherInstance.position(); + }); + // prevents document instant click fire. there's no need to run digest cycle. + setTimeout(function () { if (config.leaveOnBlur) { - bodyEl.on('click touchend', leaveOnBlur); + $document.on('click touchend', leaveOnBlur); } - }, 15); + }, 0); + activeAnimatePromise = $animate.enter(element, $document.find('body')); + return activeAnimatePromise; } function leaveOnBlur(evt) { var target = evt.target; - if (!element || target === element[0]) { + if (tether.active === false || target === element[0]) { return; } while (target.parentElement !== null) { - if (target.parentElement == element[0]) { + if (target.parentElement === element[0]) { return; } target = target.parentElement; } - return leave(); + scope.$applyAsync(leave); } // Attach tether and add it to the dom function enter(locals) { - if (element) { - return $log.debug('Tethered instance is already active; now toggling'); + if (tether.active) { + leave(); } - templateDfd().then(function (html) { - create(html, locals); + return templateDeferred().then(function (html) { + return create(html, locals); }); } // Detach the tether and remove it from the dom function leave() { - if (config.leaveOnBlur) { - bodyEl.off('click touchend', leaveOnBlur); - } - if (!isActive()) { - if (element) { - element = null; - } - return false; - } - tether.destroy(); - $timeout(function () { - element && $animate.leave(element, function () { - destroy(); - }); - }); - } - function destroy() { - if (!element) { - return; + if (tether.active === false) { + return $q.when(tether.active); } - element.remove(); - element = null; - } - function position() { - if (element) { - $animate.move(element, bodyEl); - attachTether(); + if (config.leaveOnBlur) { + $document.off('click touchend', leaveOnBlur); } + tether.active = false; + tether.tetherInstance.destroy(); + scope.$destroy(); + return $animate.leave(element); } - // bool. is tethered instance got destroyed - function isActive() { - return tether && tether.enabled; - } - return { - enter: enter, - leave: leave, - position: position, - isActive: isActive, - tether: html, - config: config.tether - }; + return tether; }; } -]);})); \ No newline at end of file +}(Tether, angular)); \ No newline at end of file diff --git a/dist/angular-tether.min.js b/dist/angular-tether.min.js index a61a3cb..747843e 100644 --- a/dist/angular-tether.min.js +++ b/dist/angular-tether.min.js @@ -1 +1 @@ -/*! angular-tether - v0.1.5 - 2014-07-15 */!function(a,b){"function"==typeof define&&define.amd?define(["tether"],b):"object"==typeof exports?module.exports=b(require("tether")):a.test=b(a.Tether)}(this,function(a){angular.module("ngTetherPopover",["ngTether"]).directive("tetherPopover",["Tether","$parse","Utils",function(a,b,c){return{restrict:"A",scope:{tetherPopover:"=",config:"="},link:function(b,d){b.tetherPopover=new a(c.extendDeep({parentScope:b.$parent,leaveOnBlur:!0,tether:{target:d[0],attachment:"top center",targetAttachment:"bottom center",constraints:[{to:"window",attachment:"together"}]}},b.config)),b.$watch("tetherPopover.config.targetAttachment",function(){b.tetherPopover.isActive()&&b.tetherPopover.position()},!0),b.$watch("tetherPopover.config.attachment",function(){b.tetherPopover.isActive()&&b.tetherPopover.position()},!0)}}}]),angular.module("ngTetherTooltip",["ngTether"]).directive("tetherTooltip",["Tether","Utils",function(a,b){return{scope:{content:"@tetherTooltip",config:"=config"},link:function(c,d){var e=new a(b.extendDeep({template:'
{{ content }}
',parentScope:c,tether:{target:d[0],attachment:"top center",targetAttachment:"bottom center",constraints:[{to:"window",attachment:"together",pin:!0}]}},c.config));d.on("mouseenter",function(){e.enter()}),d.on("mouseleave",function(){e.leave()}),c.$on("$destroy",function(){d.unbind("hover"),d.unbind("mouseleave")})}}}]),angular.module("ngTether",[]).factory("Utils",["$compile",function(){var a={};return a.extendDeep=function(a,b){for(var c in b)c in a?angular.extend(a[c],b[c]):a[c]=b[c];return a},a}]).factory("Tether",["$compile","$rootScope","$log","$window","$animate","$controller","$timeout","$q","$http","$templateCache",function(b,c,d,e,f,g,h,i,j,k){return function(l){"use strict";function m(){x=new a(B({element:C[0]},l.tether))}function n(){var a=l.template?k.get(l.template)||l.template:j.get(l.templateUrl,{cache:k}).then(function(a){return a.data});return i.when(a)}function o(a,c){if(C=angular.element(a.trim()),v=A.$new(),c)for(var d in c)v[d]=c[d];if(l.controller)var e=g(y,{$scope:v});z&&(v[z]=e),b(C)(v),v.$on("$destroy",s),h(function(){C&&(f.enter(C,D),m(),x.position(),l.leaveOnBlur&&D.on("click touchend",p))},15)}function p(a){var b=a.target;if(C&&b!==C[0]){for(;null!==b.parentElement;){if(b.parentElement==C[0])return;b=b.parentElement}return r()}}function q(a){return C?d.debug("Tethered instance is already active; now toggling"):void n().then(function(b){o(b,a)})}function r(){return l.leaveOnBlur&&D.off("click touchend",p),u()?(x.destroy(),void h(function(){C&&f.leave(C,function(){s()})})):(C&&(C=null),!1)}function s(){C&&(C.remove(),C=null)}function t(){C&&(f.move(C,D),m())}function u(){return x&&x.enabled}if(!(!l.template^!l.templateUrl))throw new Error("Expected one of either `template` or `templateUrl`");l.tether=l.tether||{};var v,w,x,y=l.controller||angular.noop,z=l.controllerAs,A=l.parentScope||c,B=angular.extend,C=null,D=angular.element(e.document.body);return{enter:q,leave:r,position:t,isActive:u,tether:w,config:l.tether}}}])}); \ No newline at end of file +!function(){function a(a,b){return{restrict:"A",scope:{tetherPopover:"=",config:"="},link:function(c,d){c.tetherPopover=new a(b.extendDeep({parentScope:c.$parent,leaveOnBlur:!0,tether:{target:d[0],attachment:"top center",targetAttachment:"bottom center",constraints:[{to:"window",attachment:"together"}]}},c.config))}}}angular.module("ngTetherPopover",["ngTether"]).directive("tetherPopover",a)}(),function(){function a(a,b){return{scope:{content:"@tetherTooltip",config:"=config"},link:function(c,d){var e=new a(b.extendDeep({template:'
{{ content }}
',parentScope:c,tether:{target:d[0],attachment:"top center",targetAttachment:"bottom center",constraints:[{to:"window",attachment:"together",pin:!0}]}},c.config));d.on("mouseenter",function(){e.enter()}),d.on("mouseleave",function(){c.$apply(e.leave)})}}}angular.module("ngTetherTooltip",["ngTether"]).directive("tetherTooltip",a)}(),function(a,b){function c(){var a={};return a.extendDeep=function(a,c){for(var d in c)d in a?b.extend(a[d],c[d]):a[d]=c[d];return a},a}function d(c,d,e,f,g,h,i,j){return function(k){"use strict";function l(){var a;return a=k.template?f.get(k.template)||k.template:j.get(k.templateUrl,{cache:f}).then(function(a){return a.data}),i.when(a)}function m(d,f){var i;if(w=b.element(d.trim()),x.tetherInstance=new a(v({element:w[0]},k.tether)),q=u.$new(),f)for(var j in f)f.hasOwnProperty(j)&&(q[j]=f[j]);return k.controller&&(i=h(s,{$scope:q})),t&&(q[t]=i),c(w)(q),x.active=!0,q.$watch(function(){x.tetherInstance.position()}),setTimeout(function(){k.leaveOnBlur&&e.on("click touchend",n)},0),r=g.enter(w,e.find("body"))}function n(a){var b=a.target;if(x.active!==!1&&b!==w[0]){for(;null!==b.parentElement;){if(b.parentElement===w[0])return;b=b.parentElement}q.$applyAsync(p)}}function o(a){return x.active&&p(),l().then(function(b){return m(b,a)})}function p(){return x.active===!1?i.when(x.active):(k.leaveOnBlur&&e.off("click touchend",n),x.active=!1,x.tetherInstance.destroy(),q.$destroy(),g.leave(w))}if(!k.template&&!k.templateUrl)throw new Error("Expected one of either `template` or `templateUrl`");if(!a)throw new Error("Tether is required`");k.tether=k.tether||{};var q,r,s=k.controller||b.noop,t=k.controllerAs,u=k.parentScope||d,v=b.extend,w=null,x={enter:o,leave:p,active:!1,config:k.tether};return x.isActive=function(){return x.active},x}}b.module("ngTether",[]).factory("TetherUtils",c).factory("Tether",d),d.$inject=["$compile","$rootScope","$document","$templateCache","$animate","$controller","$q","$http"]}(Tether,angular); \ No newline at end of file diff --git a/examples/appctrl.js b/examples/appctrl.js index 74b2f9f..734bced 100644 --- a/examples/appctrl.js +++ b/examples/appctrl.js @@ -1,634 +1,85 @@ -var app = angular.module('app', ['ng', 'ngAnimate', 'ngTetherTooltip', 'ngTetherPopover', 'ui.ace']); +angular.module('app', ['ng', 'ngAnimate', 'ngTetherTooltip', 'ngTetherPopover', 'ui.ace']) + .controller('appCtrl', function($scope, Tether, $templateCache) { -app.controller('appCtrl', function($scope, Tether, $templateCache){ - - $scope.aceLoaded = function(_editor) { - _editor.renderer.setShowGutter(false); - _editor.renderer.setHighlightGutterLine(false); - _editor.getSession().setValue($templateCache.get('popoverDemo.html')); + $scope.aceLoaded = function(_editor) { + _editor.renderer.setShowGutter(false); + _editor.renderer.setHighlightGutterLine(false); + _editor.getSession().setValue($templateCache.get('popoverDemo.html')); // _editor.setReadOnly(true); - }; - - $scope.getTemplate = function(){ - return 'popoverDemo.html' - }; - - $scope.aceChanged = function(args) { - var changed = args[0]; - var _editor = args[1]; - $templateCache.put('popoverDemo.html', _editor.getSession().getValue()); - - }; - - $scope.editorConfig = { - showLineNumbers: false, - mode: 'html', - onLoad: $scope.aceLoaded, - onChange: $scope.aceChanged - }; - - - $scope.intro = Tether({ - templateUrl: 'intro.html', - tether : { - target: '#intro', - attachment: 'bottom center', - targetAttachment: 'middle center', - targetModifier: 'visible', - constraints: [ - { - to: '#intro', - pin: true - } - ] - } - }); - - $scope.intro.enter(); - - $scope.footer = Tether({ - templateUrl: 'intro.html', - tether : { - target: '#footer', - attachment: 'top center', - targetAttachment: 'middle center', - targetModifier: 'visible', - constraints: [ - { - to: '#footer', - pin: true - } - ] - } - }); - - $scope.footer.enter(); - - - $scope.MIRROR_ATTACH = [ - 'top', 'right', 'bottom', 'left', - 'center', 'middle' - ]; - - $scope.popoverConfig = { - template: 'popover.html', - tether: { - attachment: 'middle right', - targetAttachment: 'middle left' - } - }; - - $scope.posX = [ - 'left', - 'right', - 'center' - ]; - $scope.posY = [ - 'top', - 'bottom', - 'middle' - ]; - - -// $scope.tetherConfig = { -// attachment: 'bottom center', -// targetAttachment: 'top center', -// constraints: [ -// { -// to: 'window', -// attachment: 'together' -// } -// ] -// }; - -}); - - -// SmoothScroll for websites v1.2.1 -// Licensed under the terms of the MIT license. - -// People involved -// - Balazs Galambosi (maintainer) -// - Michael Herf (Pulse Algorithm) - -// SmoothScroll for websites v1.2.1 -// Licensed under the terms of the MIT license. - -// People involved -// - Balazs Galambosi (maintainer) -// - Michael Herf (Pulse Algorithm) - -(function(){ - -// Scroll Variables (tweakable) - var defaultOptions = { - - // Scrolling Core - frameRate : 150, // [Hz] - animationTime : 500, // [px] - stepSize : 150, // [px] - - // Pulse (less tweakable) - // ratio of "tail" to "acceleration" - pulseAlgorithm : true, - pulseScale : 6, - pulseNormalize : 1, - - // Acceleration - accelerationDelta : 20, // 20 - accelerationMax : 1, // 1 - - // Keyboard Settings - keyboardSupport : true, // option - arrowScroll : 50, // [px] - - // Other - touchpadSupport : true, - fixedBackground : true, - excluded : "" - }; - - var options = defaultOptions; - - -// Other Variables - var isExcluded = false; - var isFrame = false; - var direction = { x: 0, y: 0 }; - var initDone = false; - var root = document.documentElement; - var activeElement; - var observer; - var deltaBuffer = [ 120, 120, 120 ]; - - var key = { left: 37, up: 38, right: 39, down: 40, spacebar: 32, - pageup: 33, pagedown: 34, end: 35, home: 36 }; - - - /*********************************************** - * SETTINGS - ***********************************************/ - - var options = defaultOptions; - - - /*********************************************** - * INITIALIZE - ***********************************************/ - - /** - * Tests if smooth scrolling is allowed. Shuts down everything if not. - */ - function initTest() { - - var disableKeyboard = false; - - // disable keyboard support if anything above requested it - if (disableKeyboard) { - removeEvent("keydown", keydown); - } - - if (options.keyboardSupport && !disableKeyboard) { - addEvent("keydown", keydown); - } - } - - /** - * Sets up scrolls array, determines if frames are involved. - */ - function init() { - - if (!document.body) return; - - var body = document.body; - var html = document.documentElement; - var windowHeight = window.innerHeight; - var scrollHeight = body.scrollHeight; - - // check compat mode for root element - root = (document.compatMode.indexOf('CSS') >= 0) ? html : body; - activeElement = body; - - initTest(); - initDone = true; - - // Checks if this script is running in a frame - if (top != self) { - isFrame = true; - } - - /** - * This fixes a bug where the areas left and right to - * the content does not trigger the onmousewheel event - * on some pages. e.g.: html, body { height: 100% } - */ - else if (scrollHeight > windowHeight && - (body.offsetHeight <= windowHeight || - html.offsetHeight <= windowHeight)) { - - // clearfix - if (root.offsetHeight <= windowHeight) { - var underlay = document.createElement("div"); - underlay.style.clear = "both"; - body.appendChild(underlay); - } - } - - // disable fixed background - if (!options.fixedBackground && !isExcluded) { - body.style.backgroundAttachment = "scroll"; - html.style.backgroundAttachment = "scroll"; - } - } - - - /************************************************ - * SCROLLING - ************************************************/ - - var que = []; - var pending = false; - var lastScroll = +new Date; - - /** - * Pushes scroll actions to the scrolling queue. - */ - function scrollArray(elem, left, top, delay) { - - delay || (delay = 1000); - directionCheck(left, top); - - if (options.accelerationMax != 1) { - var now = +new Date; - var elapsed = now - lastScroll; - if (elapsed < options.accelerationDelta) { - var factor = (1 + (30 / elapsed)) / 2; - if (factor > 1) { - factor = Math.min(factor, options.accelerationMax); - left *= factor; - top *= factor; - } - } - lastScroll = +new Date; - } - - // push a scroll command - que.push({ - x: left, - y: top, - lastX: (left < 0) ? 0.99 : -0.99, - lastY: (top < 0) ? 0.99 : -0.99, - start: +new Date - }); - - // don't act if there's a pending queue - if (pending) { - return; - } - - var scrollWindow = (elem === document.body); - - var step = function (time) { - - var now = +new Date; - var scrollX = 0; - var scrollY = 0; - - for (var i = 0; i < que.length; i++) { - - var item = que[i]; - var elapsed = now - item.start; - var finished = (elapsed >= options.animationTime); + }; - // scroll position: [0, 1] - var position = (finished) ? 1 : elapsed / options.animationTime; + $scope.getTemplate = function() { + return 'popoverDemo.html'; + }; - // easing [optional] - if (options.pulseAlgorithm) { - position = pulse(position); - } + $scope.aceChanged = function(args) { + var changed = args[0]; + var _editor = args[1]; + $templateCache.put('popoverDemo.html', _editor.getSession().getValue()); - // only need the difference - var x = (item.x * position - item.lastX) >> 0; - var y = (item.y * position - item.lastY) >> 0; + }; - // add this to the total scrolling - scrollX += x; - scrollY += y; + $scope.editorConfig = { + showLineNumbers: false, + mode: 'html', + onLoad: $scope.aceLoaded, + onChange: $scope.aceChanged + }; - // update last values - item.lastX += x; - item.lastY += y; + $scope.MIRROR_ATTACH = [ + 'top', 'right', 'bottom', 'left', + 'center', 'middle' + ]; - // delete and step back if it's over - if (finished) { - que.splice(i, 1); i--; + $scope.popoverConfig = { + template: 'popover.html', + tether: { + attachment: 'middle right', + targetAttachment: 'middle left' } - } - - // scroll left and top - if (scrollWindow) { - window.scrollBy(scrollX, scrollY); - } - else { - if (scrollX) elem.scrollLeft += scrollX; - if (scrollY) elem.scrollTop += scrollY; - } - - // clean up if there's nothing left to do - if (!left && !top) { - que = []; - } - - if (que.length) { - requestFrame(step, elem, (delay / options.frameRate + 1)); - } else { - pending = false; - } - }; - - // start a new queue of actions - requestFrame(step, elem, 0); - pending = true; - } - - - /*********************************************** - * EVENTS - ***********************************************/ - - /** - * Mouse wheel handler. - * @param {Object} event - */ - function wheel(event) { - - if (!initDone) { - init(); - } - - var target = event.target; - var overflowing = overflowingAncestor(target); - - // use default if there's no overflowing - // element or default action is prevented - if (!overflowing || event.defaultPrevented || - isNodeName(activeElement, "embed") || - (isNodeName(target, "embed") && /\.pdf/i.test(target.src))) { - return true; - } - - var deltaX = event.wheelDeltaX || 0; - var deltaY = event.wheelDeltaY || 0; - - // use wheelDelta if deltaX/Y is not available - if (!deltaX && !deltaY) { - deltaY = event.wheelDelta || 0; - } - - // check if it's a touchpad scroll that should be ignored - if (!options.touchpadSupport && isTouchpad(deltaY)) { - return true; - } - - // scale by step size - // delta is 120 most of the time - // synaptics seems to send 1 sometimes - if (Math.abs(deltaX) > 1.2) { - deltaX *= options.stepSize / 120; - } - if (Math.abs(deltaY) > 1.2) { - deltaY *= options.stepSize / 120; - } - - scrollArray(overflowing, -deltaX, -deltaY); - event.preventDefault(); - } - - /** - * Keydown event handler. - * @param {Object} event - */ - function keydown(event) { - - var target = event.target; - var modifier = event.ctrlKey || event.altKey || event.metaKey || - (event.shiftKey && event.keyCode !== key.spacebar); - - // do nothing if user is editing text - // or using a modifier key (except shift) - // or in a dropdown - if ( /input|textarea|select|embed/i.test(target.nodeName) || - target.isContentEditable || - event.defaultPrevented || - modifier ) { - return true; - } - // spacebar should trigger button press - if (isNodeName(target, "button") && - event.keyCode === key.spacebar) { - return true; - } - - var shift, x = 0, y = 0; - var elem = overflowingAncestor(activeElement); - var clientHeight = elem.clientHeight; - - if (elem == document.body) { - clientHeight = window.innerHeight; - } - - switch (event.keyCode) { - case key.up: - y = -options.arrowScroll; - break; - case key.down: - y = options.arrowScroll; - break; - case key.spacebar: // (+ shift) - shift = event.shiftKey ? 1 : -1; - y = -shift * clientHeight * 0.9; - break; - case key.pageup: - y = -clientHeight * 0.9; - break; - case key.pagedown: - y = clientHeight * 0.9; - break; - case key.home: - y = -elem.scrollTop; - break; - case key.end: - var damt = elem.scrollHeight - elem.scrollTop - clientHeight; - y = (damt > 0) ? damt+10 : 0; - break; - case key.left: - x = -options.arrowScroll; - break; - case key.right: - x = options.arrowScroll; - break; - default: - return true; // a key we don't care about - } - - scrollArray(elem, x, y); - event.preventDefault(); - } - - /** - * Mousedown event only for updating activeElement - */ - function mousedown(event) { - activeElement = event.target; - } - - - /*********************************************** - * OVERFLOW - ***********************************************/ - - var cache = {}; // cleared out every once in while - setInterval(function () { cache = {}; }, 10 * 1000); - - var uniqueID = (function () { - var i = 0; - return function (el) { - return el.uniqueID || (el.uniqueID = i++); - }; - })(); - - function setCache(elems, overflowing) { - for (var i = elems.length; i--;) - cache[uniqueID(elems[i])] = overflowing; - return overflowing; - } + }; - function overflowingAncestor(el) { - var elems = []; - var rootScrollHeight = root.scrollHeight; - do { - var cached = cache[uniqueID(el)]; - if (cached) { - return setCache(elems, cached); - } - elems.push(el); - if (rootScrollHeight === el.scrollHeight) { - if (!isFrame || root.clientHeight + 10 < rootScrollHeight) { - return setCache(elems, document.body); // scrolling root in WebKit - } - } else if (el.clientHeight + 10 < el.scrollHeight) { - overflow = getComputedStyle(el, "").getPropertyValue("overflow-y"); - if (overflow === "scroll" || overflow === "auto") { - return setCache(elems, el); + $scope.posX = [ + 'left', + 'right', + 'center' + ]; + $scope.posY = [ + 'top', + 'bottom', + 'middle' + ]; + + }) + + .directive('tetherBlock', function(Tether){ + return { + scope: { + options : '=', + tetherOptions: '=' + }, + link: function(scope, elm){ + Tether({ + templateUrl: 'intro.html', + tether: angular.extend({ + target: elm[0], + attachment: 'bottom center', + targetAttachment: 'middle center', + targetModifier: 'visible', + constraints: [ + { + to: elm, + pin: true + } + ] + }, scope.tetherOptions) + }).enter(); } - } - } while (el = el.parentNode); - } - - - /*********************************************** - * HELPERS - ***********************************************/ - - function addEvent(type, fn, bubble) { - window.addEventListener(type, fn, (bubble||false)); - } - - function removeEvent(type, fn, bubble) { - window.removeEventListener(type, fn, (bubble||false)); - } - - function isNodeName(el, tag) { - return (el.nodeName||"").toLowerCase() === tag.toLowerCase(); - } - - function directionCheck(x, y) { - x = (x > 0) ? 1 : -1; - y = (y > 0) ? 1 : -1; - if (direction.x !== x || direction.y !== y) { - direction.x = x; - direction.y = y; - que = []; - lastScroll = 0; - } - } - - var deltaBufferTimer; - - function isTouchpad(deltaY) { - if (!deltaY) return; - deltaY = Math.abs(deltaY) - deltaBuffer.push(deltaY); - deltaBuffer.shift(); - clearTimeout(deltaBufferTimer); - deltaBufferTimer = setTimeout(function () { - chrome.storage.local.set({ deltaBuffer: deltaBuffer }); - }, 1000); - var allDivisable = (isDivisible(deltaBuffer[0], 120) && - isDivisible(deltaBuffer[1], 120) && - isDivisible(deltaBuffer[2], 120)); - return !allDivisable; - } - - function isDivisible(n, divisor) { - return (Math.floor(n / divisor) == n / divisor); - } - - var requestFrame = (function () { - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - function (callback, element, delay) { - window.setTimeout(callback, delay || (1000/60)); }; - })(); - - - /*********************************************** - * PULSE - ***********************************************/ - - /** - * Viscous fluid with a pulse for part and decay for the rest. - * - Applies a fixed force over an interval (a damped acceleration), and - * - Lets the exponential bleed away the velocity over a longer interval - * - Michael Herf, http://stereopsis.com/stopping/ - */ - function pulse_(x) { - var val, start, expx; - // test - x = x * options.pulseScale; - if (x < 1) { // acceleartion - val = x - (1 - Math.exp(-x)); - } else { // tail - // the previous animation ended here: - start = Math.exp(-1); - // simple viscous drag - x -= 1; - expx = 1 - Math.exp(-x); - val = start + (expx * (1 - start)); - } - return val * options.pulseNormalize; - } - - function pulse(x) { - if (x >= 1) return 1; - if (x <= 0) return 0; + }) - if (options.pulseNormalize == 1) { - options.pulseNormalize /= pulse_(1); - } - return pulse_(x); - } +; - var isChrome = /chrome/i.test(window.navigator.userAgent); - var isMouseWheelSupported = 'onmousewheel' in document; - if (isMouseWheelSupported && isChrome) { - addEvent("mousedown", mousedown); - addEvent("mousewheel", wheel); - addEvent("load", init); - } -})(); \ No newline at end of file diff --git a/examples/index.html b/examples/index.html index 9ce6b53..c6faefd 100755 --- a/examples/index.html +++ b/examples/index.html @@ -17,10 +17,544 @@ + + - +