initial commit
This commit is contained in:
commit
11348f2c42
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
bower_components/
|
||||
node_modules/
|
||||
|
18
Gruntfile.coffee
Normal file
18
Gruntfile.coffee
Normal file
@ -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'
|
18
bower.json
Normal file
18
bower.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
292
dist/angular-presentation.js
vendored
Normal file
292
dist/angular-presentation.js
vendored
Normal file
@ -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('<div />').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("<div class='code-runner' />");
|
||||
target = element.next();
|
||||
element.remove();
|
||||
return scope.$watch('codeBlocks', function(codeBlocks) {
|
||||
var content;
|
||||
content = angular.element("<div />").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(/</g, "<");
|
||||
lines = output.split("\n");
|
||||
length = lines[0].length - lines[0].replace(/^ */, '').length;
|
||||
output = ((function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = lines.length; _i < _len; _i++) {
|
||||
line = lines[_i];
|
||||
_results.push(line.substr(length));
|
||||
}
|
||||
return _results;
|
||||
})()).join("\n");
|
||||
return callback(Prism.highlight(output, Prism.languages[prismLanguage]));
|
||||
};
|
||||
|
||||
presentation.directive('codeDisplayer', function(boundScopeHelper) {
|
||||
return boundScopeHelper({
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
scope: {
|
||||
codeBlocks: '=',
|
||||
state: '='
|
||||
},
|
||||
templateUrl: 'code_displayer.html',
|
||||
link: function(scope, element, attrs) {
|
||||
return scope.$watch('codeBlocks', function(codeBlocks) {
|
||||
if (codeBlocks && codeBlocks[attrs["for"]]) {
|
||||
return processCodeBlock(codeBlocks[attrs["for"]], attrs.language, function(highlightedCode) {
|
||||
return element.find('code').append(highlightedCode);
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
presentation.directive('pre', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, element, attrs) {
|
||||
if (attrs.language != null) {
|
||||
return processCodeBlock(element.text(), attrs.language, function(highlightedCode) {
|
||||
console.log(highlightedCode);
|
||||
element.html('');
|
||||
element.append('<code />');
|
||||
return element.find('code').append(highlightedCode);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
}).call(this);
|
17
package.json
Normal file
17
package.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
203
src/angular-presentation.coffee
Normal file
203
src/angular-presentation.coffee
Normal file
@ -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('<div />').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 "<div class='code-runner' />"
|
||||
target = element.next()
|
||||
element.remove()
|
||||
|
||||
scope.$watch(
|
||||
'codeBlocks',
|
||||
(codeBlocks) ->
|
||||
content = angular.element("<div />").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(/</g, "<")
|
||||
|
||||
lines = output.split("\n")
|
||||
length = lines[0].length - lines[0].replace(/^ */, '').length
|
||||
|
||||
output = (line.substr(length) for line in lines).join("\n")
|
||||
|
||||
callback(Prism.highlight(output, Prism.languages[prismLanguage]))
|
||||
|
||||
presentation.directive 'codeDisplayer', (boundScopeHelper) ->
|
||||
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('<code />')
|
||||
element.find('code').append(highlightedCode)
|
Loading…
Reference in New Issue
Block a user