From 11348f2c42b7151e7571c7ba1def567e1d26fbe6 Mon Sep 17 00:00:00 2001 From: John Bintz Date: Tue, 18 Feb 2014 22:31:50 -0500 Subject: [PATCH] initial commit --- .gitignore | 3 + Gruntfile.coffee | 18 ++ README.md | 1 + bower.json | 18 ++ dist/angular-presentation.js | 292 ++++++++++++++++++++++++++++++++ package.json | 17 ++ src/angular-presentation.coffee | 203 ++++++++++++++++++++++ 7 files changed, 552 insertions(+) create mode 100644 .gitignore create mode 100644 Gruntfile.coffee create mode 100644 README.md create mode 100644 bower.json create mode 100644 dist/angular-presentation.js create mode 100644 package.json create mode 100644 src/angular-presentation.coffee diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51b7825 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bower_components/ +node_modules/ + diff --git a/Gruntfile.coffee b/Gruntfile.coffee new file mode 100644 index 0000000..4af5329 --- /dev/null +++ b/Gruntfile.coffee @@ -0,0 +1,18 @@ +module.exports = (grunt) -> + require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks) + + grunt.initConfig { + coffee: + compile: + expand: true + cwd: 'src' + src: [ '*.coffee' ] + dest: 'dist' + ext: '.js' + watch: + coffee: + files: [ 'src/*.coffee' ] + tasks: [ 'coffee:compile' ] + } + + grunt.registerTask 'default', 'watch:coffee' diff --git a/README.md b/README.md new file mode 100644 index 0000000..31c7d18 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +John's AngularJS-based presentation system. diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..9a4cb38 --- /dev/null +++ b/bower.json @@ -0,0 +1,18 @@ +{ + "name": "angular-presentation", + "version": "0.0.0", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "jquery": "~2.1.0", + "angular": "~1.2.14-build.2273", + "js-beautify": "~1.4.2", + "solarized": "~0.1.2", + "angular-ui-utils": "bower-keypress" + } +} diff --git a/dist/angular-presentation.js b/dist/angular-presentation.js new file mode 100644 index 0000000..416b45a --- /dev/null +++ b/dist/angular-presentation.js @@ -0,0 +1,292 @@ +(function() { + var codeGrabber, presentation, processCodeBlock; + + presentation = angular.module('presentation', ['ui.keypress']); + + presentation.factory('boundScopeHelper', function() { + return function(directive) { + var originalCompile, originalLink; + originalCompile = directive.compile; + originalLink = directive.link; + directive.compile = function(tE, tA, transclude) { + var key, value, _ref; + _ref = directive.scope; + for (key in _ref) { + value = _ref[key]; + tA[key] = key; + } + if (originalCompile != null) { + return originalCompile(tE, tA, transclude); + } else if (originalLink) { + return originalLink; + } else { + return function(scope, element, attrs) {}; + } + }; + delete directive.link; + return directive; + }; + }); + + presentation.factory('presentationOptions', function() { + var Options; + Options = (function() { + function Options() {} + + Options.prototype.slides = []; + + Options.prototype.currentSlide = null; + + Options.prototype.addSlide = function(id) { + this.slides.push(id); + return this.currentSlide || (this.currentSlide = id); + }; + + Options.prototype.currentSlideIndex = function() { + return this.slides.indexOf(this.currentSlide); + }; + + Options.prototype.nextSlide = function() { + var index; + index = this.currentSlideIndex() + 1; + if (index < this.slides.length) { + return this.switchToSlide(index); + } + }; + + Options.prototype.previousSlide = function() { + var index; + index = this.currentSlideIndex() - 1; + if (index > -1) { + return this.switchToSlide(index); + } + }; + + Options.prototype.switchToSlide = function(index) { + return this.currentSlide = this.slides[index]; + }; + + Options.prototype.hasPrevious = function() { + return this.currentSlideIndex() > 0; + }; + + Options.prototype.hasNext = function() { + return this.currentSlideIndex() < this.slides.length - 1; + }; + + Options.prototype.nextID = function() { + return "slide-" + this.slides.length; + }; + + return Options; + + })(); + return new Options(); + }); + + presentation.directive('presentation', function() { + return { + restrict: 'E', + transclude: true, + replace: true, + templateUrl: 'presentation.html', + controller: function($scope, presentationOptions) { + return $scope.options = presentationOptions; + } + }; + }); + + presentation.directive('slide', function(boundScopeHelper) { + return boundScopeHelper({ + restrict: 'E', + replace: true, + transclude: true, + templateUrl: 'slide.html', + scope: { + 'options': '=' + }, + compile: function(tE, tA, transclude) { + var id; + id = tA.id; + return function(scope, element, attrs) { + scope.id = id || scope.options.nextID(); + scope.options.addSlide(scope.id); + scope.state || (scope.state = {}); + return scope.codeBlocks || (scope.codeBlocks = {}); + }; + } + }); + }); + + presentation.simpleDirective = function(name, options) { + if (options == null) { + options = {}; + } + return this.directive(name, function($sce) { + return { + restrict: 'E', + replace: true, + transclude: true, + scope: true, + templateUrl: name + '.html', + compile: function(tE, tA, transclude) { + return function(scope, element, attrs) { + return transclude(scope, function(clone, innerScope) { + clone = angular.element('
').append(clone); + if (options.postLink != null) { + options.postLink(scope, name, clone); + return scope[name] = $sce.trustAsHtml(scope[name]); + } + }); + }; + } + }; + }); + }; + + presentation.simpleDirective('title', { + postLink: function(scope, name, clone) { + return scope[name] = clone.text(); + } + }); + + presentation.simpleDirective('subtitle', { + postLink: function(scope, name, clone) { + return scope[name] = clone.html(); + } + }); + + presentation.directive('controls', function() { + return { + restrict: 'E', + replace: true, + templateUrl: 'controls.html' + }; + }); + + codeGrabber = function(scope, element, name) { + var html; + html = element.html(); + scope.codeBlocks || (scope.codeBlocks = {}); + return scope.codeBlocks[name] = html; + }; + + presentation.directive('script', function() { + return { + restrict: 'E', + link: function(scope, element, attrs) { + if (attrs.type === 'text/code-grabber') { + return codeGrabber(scope, element, attrs["for"]); + } + } + }; + }); + + presentation.directive('codeGrabber', function() { + return { + restrict: 'A', + link: function(scope, element, attrs) { + return codeGrabber(scope, element, attrs.codeGrabber); + } + }; + }); + + presentation.directive('codeRunner', function($compile) { + return { + restrict: 'E', + replace: true, + link: function(scope, element, attrs) { + var target; + element.after("
"); + target = element.next(); + element.remove(); + return scope.$watch('codeBlocks', function(codeBlocks) { + var content; + content = angular.element("
").append(codeBlocks[attrs["for"]]); + $compile(content)(scope); + target.html(''); + return target.append(content); + }, true); + } + }; + }); + + processCodeBlock = function(code, language, callback) { + var beautifier, length, line, lines, output, prismLanguage; + prismLanguage = null; + beautifier = (function() { + switch (language) { + case 'html': + prismLanguage = 'markup'; + return window.html_beautify; + case 'javascript': + case 'json': + prismLanguage = 'javascript'; + return window.js_beautify; + case 'css': + case 'scss': + case 'sass': + prismLanguage = 'css'; + return window.css_beautify; + default: + prismLanguage = language; + return function(code, options) { + return code; + }; + } + })(); + output = beautifier(code, { + indent_size: 2 + }).replace(/'); + return element.find('code').append(highlightedCode); + }); + } + } + }; + }); + +}).call(this); diff --git a/package.json b/package.json new file mode 100644 index 0000000..841e1cf --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "angular-presentation", + "version": "0.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "BSD", + "devDependencies": { + "grunt": "~0.4.2", + "matchdep": "~0.3.0", + "grunt-contrib-coffee": "~0.10.0", + "grunt-contrib-watch": "~0.5.3" + } +} diff --git a/src/angular-presentation.coffee b/src/angular-presentation.coffee new file mode 100644 index 0000000..96e1c9d --- /dev/null +++ b/src/angular-presentation.coffee @@ -0,0 +1,203 @@ +presentation = angular.module 'presentation', [ 'ui.keypress' ] + +presentation.factory 'boundScopeHelper', -> + (directive) -> + originalCompile = directive.compile + originalLink = directive.link + + directive.compile = (tE, tA, transclude) -> + tA[key] = key for key, value of directive.scope + + if originalCompile? + originalCompile(tE, tA, transclude) + else if originalLink + originalLink + else + (scope, element, attrs) -> + + delete directive.link + + directive + +presentation.factory 'presentationOptions', -> + class Options + slides: [] + currentSlide: null + + addSlide: (id) -> + @slides.push(id) + @currentSlide ||= id + + currentSlideIndex: -> @slides.indexOf(@currentSlide) + + nextSlide: -> + index = @currentSlideIndex() + 1 + if index < @slides.length + @switchToSlide(index) + + previousSlide: -> + index = @currentSlideIndex() - 1 + if index > -1 + @switchToSlide(index) + + switchToSlide: (index) -> + @currentSlide = @slides[index] + + hasPrevious: -> + @currentSlideIndex() > 0 + + hasNext: -> + @currentSlideIndex() < @slides.length - 1 + + nextID: -> + "slide-#{@slides.length}" + + new Options() + +presentation.directive 'presentation', -> + restrict: 'E' + transclude: true + replace: true + templateUrl: 'presentation.html' + controller: ($scope, presentationOptions) -> + $scope.options = presentationOptions + +presentation.directive 'slide', (boundScopeHelper) -> + boundScopeHelper( + restrict: 'E' + replace: true + transclude: true + templateUrl: 'slide.html' + scope: + 'options': '=' + compile: (tE, tA, transclude) -> + id = tA.id + + (scope, element, attrs) -> + scope.id = id || scope.options.nextID() + scope.options.addSlide(scope.id) + + scope.state ||= {} + scope.codeBlocks ||= {} + ) + +presentation.simpleDirective = (name, options = {}) -> + @directive name, ($sce) -> + restrict: 'E' + replace: true + transclude: true + scope: true + templateUrl: name + '.html' + compile: (tE, tA, transclude) -> + (scope, element, attrs) -> + transclude scope, (clone, innerScope) -> + clone = angular.element('
').append(clone) + + if options.postLink? + options.postLink(scope, name, clone) + scope[name] = $sce.trustAsHtml(scope[name]) + +presentation.simpleDirective 'title', + postLink: (scope, name, clone) -> + scope[name] = clone.text() + +presentation.simpleDirective 'subtitle', + postLink: (scope, name, clone) -> + scope[name] = clone.html() + +presentation.directive 'controls', -> + restrict: 'E' + replace: true + templateUrl: 'controls.html' + +codeGrabber = (scope, element, name) -> + html = element.html() + + scope.codeBlocks ||= {} + scope.codeBlocks[name] = html + +presentation.directive 'script', -> + restrict: 'E' + link: (scope, element, attrs) -> + if attrs.type == 'text/code-grabber' + codeGrabber scope, element, attrs.for + +presentation.directive 'codeGrabber', -> + restrict: 'A' + link: (scope, element, attrs) -> + codeGrabber scope, element, attrs.codeGrabber + +presentation.directive 'codeRunner', ($compile) -> + restrict: 'E' + replace: true + link: (scope, element, attrs) -> + element.after "
" + target = element.next() + element.remove() + + scope.$watch( + 'codeBlocks', + (codeBlocks) -> + content = angular.element("
").append(codeBlocks[attrs.for]) + + $compile(content)(scope) + + target.html('') + target.append(content) + , true + ) + +processCodeBlock = (code, language, callback) -> + prismLanguage = null + + beautifier = switch language + when 'html' + prismLanguage = 'markup' + window.html_beautify + when 'javascript', 'json' + prismLanguage = 'javascript' + window.js_beautify + when 'css', 'scss', 'sass' + prismLanguage = 'css' + window.css_beautify + else + prismLanguage = language + (code, options) -> code + + output = beautifier(code, { indent_size: 2 }).replace(/ + boundScopeHelper { + restrict: 'E' + replace: true + scope: { + codeBlocks: '=' + state: '=' + } + templateUrl: 'code_displayer.html' + link: (scope, element, attrs) -> + scope.$watch( + 'codeBlocks', (codeBlocks) -> + if codeBlocks && codeBlocks[attrs.for] + processCodeBlock codeBlocks[attrs.for], attrs.language, (highlightedCode) -> + element.find('code').append(highlightedCode) + , true) + } + +presentation.directive 'pre', -> + restrict: 'E' + link: (scope, element, attrs) -> + if attrs.language? + processCodeBlock element.text(), attrs.language, (highlightedCode) -> + console.log highlightedCode + + element.html('') + element.append('') + element.find('code').append(highlightedCode)