├── .gitignore ├── Gruntfile.coffee ├── LICENSE ├── README.md ├── bower.json ├── coffee └── ruban.coffee ├── css ├── ruban-print.css ├── ruban-print.min.css ├── ruban.css └── ruban.min.css ├── index.html ├── js ├── ruban.js └── ruban.min.js ├── less ├── ruban-print.less └── ruban.less └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | components/ 4 | js/*-dev.js 5 | css/*-dev.css 6 | -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (grunt) -> 2 | 3 | # Project configuration 4 | grunt.initConfig( 5 | pkg: grunt.file.readJSON('package.json') 6 | meta: 7 | banner: """ 8 | /** 9 | * <%= pkg.name %> v<%= pkg.version %> 10 | * 11 | * Copyright (c) 2013 <%= pkg.author %> 12 | * Distributed under the <%= pkg.license %> license 13 | */ 14 | 15 | """ 16 | coffee: 17 | compile: 18 | files: 19 | 'js/ruban-dev.js': 'coffee/ruban.coffee' 20 | dist: 21 | files: 22 | 'js/ruban.js': 'coffee/ruban.coffee' 23 | less: 24 | compile: 25 | files: 26 | 'css/ruban-dev.css': 'less/ruban.less' 27 | 'css/ruban-print-dev.css': 'less/ruban-print.less' 28 | dist: 29 | files: 30 | 'css/ruban.css': 'less/ruban.less' 31 | 'css/ruban-print.css': 'less/ruban-print.less' 32 | uglify: 33 | options: 34 | banner: '<%= meta.banner %>' 35 | dist: 36 | files: 37 | 'js/ruban.min.js': 'js/ruban.js' 38 | cssmin: 39 | options: 40 | banner: '<%= meta.banner %>' 41 | dist: 42 | files: 43 | 'css/ruban.min.css': 'css/ruban.css' 44 | 'css/ruban-print.min.css': 'css/ruban-print.css' 45 | copy: 46 | libs: 47 | expand: true 48 | cwd: 'bower_components/' 49 | src: [ 50 | 'normalize-css/normalize.css', 51 | 'font-awesome/css/font-awesome.min.css' 52 | 'font-awesome/fonts/fontawesome-*' 53 | 'highlightjs/styles/tomorrow.css', 54 | 'jquery/jquery.min.js', 55 | 'keymaster/keymaster.js', 56 | 'hammerjs/hammer.min.js', 57 | 'highlightjs/highlight.pack.js' 58 | ] 59 | dest: 'components/' 60 | watch: 61 | coffee: 62 | files: 'coffee/ruban.coffee' 63 | tasks: 'coffee:compile' 64 | less: 65 | files: ['less/ruban.less','less/ruban-print.less'] 66 | tasks: 'less:compile' 67 | ) 68 | 69 | # Load plugins 70 | grunt.loadNpmTasks('grunt-contrib-coffee'); 71 | grunt.loadNpmTasks('grunt-contrib-less'); 72 | grunt.loadNpmTasks('grunt-contrib-uglify'); 73 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 74 | grunt.loadNpmTasks('grunt-contrib-copy'); 75 | grunt.loadNpmTasks('grunt-contrib-watch'); 76 | 77 | # Default tasks 78 | grunt.registerTask('default', ['copy', 'coffee:compile', 'less:compile', 'watch']) 79 | grunt.registerTask('dist', ['copy', 'coffee:dist', 'uglify', 'less:dist', 'cssmin']) 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Loïc Frering 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ruban 2 | ===== 3 | 4 | A simple framework for building nice HTML5 based presentations. 5 | 6 | Documentation 7 | ------------- 8 | 9 | You'll find the documentation on a Ruban: http://loicfrering.github.io/ruban/. 10 | 11 | Changelog 12 | --------- 13 | 14 | ### 0.3.2 15 | 16 | * Add additional functions to allow Ruban's support in 17 | [deck2pdf](https://github.com/melix/deck2pdf) which can convert HTML5 18 | presentations to PDF (thanks @jnizet). 19 | 20 | ### 0.3.1 21 | 22 | * Add `first()` and `last()` functions to go to the first and last slide. 23 | * Bind the `home` and `end` keys to these new functions. 24 | * Introduce the title option which allows to display a fixed title for the 25 | presentation in the footer. 26 | * Add a .center class to easily center text. 27 | * Correctly set the `main` property of the bower.json. 28 | * Update Font-Awesome to 4.1.0. 29 | 30 | ### 0.3.0 31 | 32 | * Do not reset the steps when coming from the following slide but allow passing 33 | them in the backward direction. 34 | * Do not entirely strip HTML tags in the generated table of contents. It allows 35 | to have Font-Awesome icons in the TOC. 36 | * Do not display the pagination when printing because it is dynamically updated 37 | with JavaScript and thus static and wrong in the print. You can use the 38 | pagination capabilities of the printer's driver to get pagination in a print. 39 | * Support navigating through the Ruban with left and right mouse clicks. 40 | Disabled by default because it prevents text selection and the display of the 41 | context menu. 42 | * Support navigating with the mouse wheel. Disabled by default. 43 | 44 | ### 0.2.2 45 | 46 | * Bind pageup and pagedown keys. 47 | * Update Font-Awesome to 4.0.3. 48 | * Update other dependencies versions. 49 | 50 | ### 0.2.1 51 | 52 | * Improve and fix navigation with gestures on mobile devices. 53 | * Fix an issue with resizing on Webkit. 54 | 55 | ### 0.2.0 56 | 57 | * Move css and js files from dist/ to css/ and js/ directories. 58 | * Do not generate the Table of Content's title. 59 | * Add a quickstart distribution. 60 | * Fix some resizing issues. 61 | * Improve the documentation. 62 | 63 | ### 0.1.2 64 | 65 | * Table of Contents automatic generation. 66 | * StyleSheet dedicated to print media. 67 | * Support adding extra details in tags. 68 | 69 | ### 0.1.1 70 | 71 | * Support pagination. 72 | * Fix a resizing issue. 73 | 74 | ### 0.1.0 75 | 76 | * Initial release. 77 | 78 | License 79 | ------- 80 | 81 | Copyright (c) 2013 [Loïc Frering](https://github.com/loicfrering), licensed 82 | under the MIT license. See the LICENSE file for more informations. 83 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ruban", 3 | "author": "Loïc Frering ", 4 | "version": "0.3.2", 5 | "main": ["js/ruban.min.js", "css/ruban.min.css", "css/ruban-print.min.css"], 6 | "ignore": [ 7 | "**/.*", 8 | "node_modules", 9 | "components" 10 | ], 11 | "dependencies": { 12 | "jquery": "~2.0.3", 13 | "keymaster": "~1.6.1", 14 | "hammerjs": "~1.0.6", 15 | "normalize-css": "~2.1.0", 16 | "font-awesome": "~4.1.0", 17 | "highlightjs": "~7.5.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /coffee/ruban.coffee: -------------------------------------------------------------------------------- 1 | class Ruban 2 | constructor: (@options = {}) -> 3 | @initOptions() 4 | @$sections = $('section').wrapAll('
') 5 | @$ruban = $('.ruban') 6 | 7 | @toc() 8 | @current(@$sections.first()) 9 | @pagination() 10 | @checkHash() 11 | @highlight() 12 | @resize() 13 | @bind() 14 | @$ruban.css('transition-property', 'transform') 15 | @$ruban.css('-webkit-transition-property', '-webkit-transform') 16 | @$ruban.css('transition-duration', @options.transitionDuration) 17 | 18 | initOptions: () -> 19 | @options.ratio ?= 4/3 20 | @options.minPadding ?= '0.4em' 21 | @options.transitionDuration ?= '1s' 22 | @options.pagination ?= false 23 | @options.title ?= null 24 | @options.stripHtmlInToc ?= false 25 | @options.bindClicks ?= false 26 | @options.bindMouseWheel ?= false 27 | 28 | bind: -> 29 | @bindKeys() 30 | @bindGestures() 31 | @bindClicks() if @options.bindClicks 32 | @bindMouseWheel() if @options.bindMouseWheel 33 | 34 | @bindResize() 35 | @bindHashChange() 36 | 37 | bindKeys: -> 38 | key('right, down, space, return, j, l, pagedown', @next) 39 | key('left, up, backspace, k, h, pageup', @prev) 40 | key('home', @first) 41 | key('last', @last) 42 | 43 | bindGestures: -> 44 | Hammer(document, { 45 | drag_block_vertical: true, 46 | drag_block_horizontal: true 47 | }).on('swipeleft swipeup', @next) 48 | .on('swiperight swipedown', @prev) 49 | 50 | bindClicks: -> 51 | @$ruban.contextmenu(-> false) 52 | @$ruban.mousedown((e) => 53 | switch e.which 54 | when 1 then @next() 55 | when 3 then @prev() 56 | ) 57 | 58 | bindMouseWheel: -> 59 | @$ruban.on('wheel', (e) => 60 | if e.originalEvent.deltaY > 0 61 | @next() 62 | else if e.originalEvent.deltaY < 0 63 | @prev() 64 | ) 65 | 66 | bindResize: -> 67 | $(window).resize(=> 68 | @resize() 69 | @go(@$current, force: true) 70 | ) 71 | 72 | bindHashChange: -> 73 | $(window).on('hashchange', @checkHash) 74 | 75 | disableTransitions: -> 76 | @$ruban.css('transition-property', 'none') 77 | 78 | enableTransitions: -> 79 | @$ruban.css('transition-property', 'transform') 80 | 81 | resize: -> 82 | [outerWidth, outerHeight] = [$(window).width(), $(window).height()] 83 | if outerWidth > @options.ratio * outerHeight 84 | min = outerHeight 85 | paddingV = @options.minPadding 86 | @$ruban.parent().css('font-size', "#{min * 0.4}%") 87 | @$sections.css( 88 | 'padding-top': paddingV, 89 | 'padding-bottom': paddingV 90 | ) 91 | height = @$current.height() 92 | width = @options.ratio * height 93 | paddingH = "#{(outerWidth - width)/2}px" 94 | @$sections.css( 95 | 'padding-left': paddingH 96 | 'padding-right': paddingH 97 | ) 98 | else 99 | min = outerWidth / @options.ratio 100 | paddingH = @options.minPadding 101 | @$ruban.parent().css('font-size', "#{min * 0.4}%") 102 | @$sections.css( 103 | 'padding-left': paddingH, 104 | 'padding-right': paddingH 105 | ) 106 | width = @$current.width() 107 | height = width / @options.ratio 108 | paddingV = "#{(outerHeight - height)/2}px" 109 | @$sections.css( 110 | 'padding-top': paddingV, 111 | 'padding-bottom': paddingV 112 | ) 113 | 114 | checkHash: => 115 | hash = window.location.hash 116 | if slide = hash.substr(2) 117 | @go(slide) 118 | 119 | highlight: -> 120 | hljs.initHighlightingOnLoad() 121 | 122 | first: => 123 | @firstSlide() 124 | 125 | firstSlide: -> 126 | @go(@getFirstSlide(), direction: 'backward') 127 | 128 | getFirstSlide: -> 129 | @$sections.first() 130 | 131 | isFirstSlide: -> 132 | @$current.is(@getFirstSlide()) 133 | 134 | prev: => 135 | if @hasSteps() 136 | @prevStep() 137 | else 138 | @prevSlide() 139 | 140 | prevSlide: -> 141 | $prev = @$current.prev('section') 142 | @go($prev, direction: 'backward') 143 | 144 | prevStep: -> 145 | @$steps.eq(@index).removeClass('step').fadeOut() 146 | $prev = @$steps.eq(--@index) 147 | unless @index < -1 148 | if $prev.is(':visible') 149 | $prev.addClass('step').trigger('step') 150 | else if @index > -1 151 | @prevStep() 152 | else 153 | @prevSlide() 154 | 155 | last: => 156 | @lastSlide() 157 | 158 | lastSlide: -> 159 | @go(@getLastSlide(), direction: 'forward') 160 | 161 | getLastSlide: -> 162 | @$sections.last() 163 | 164 | isLastSlide: -> 165 | @$current.is(@getLastSlide()) 166 | 167 | isLastStep: -> 168 | not @hasSteps() or @index is @$steps.length - 1 169 | 170 | next: => 171 | if @hasSteps() 172 | @nextStep() 173 | else 174 | @nextSlide() 175 | 176 | nextSlide: -> 177 | $next = @$current.next('section') 178 | @go($next, direction: 'forward') 179 | 180 | nextStep: -> 181 | @$steps.eq(@index).removeClass('step') 182 | $next = @$steps.eq(++@index) 183 | if $next.length 184 | $next.fadeIn().addClass('step').trigger('step') 185 | else 186 | @nextSlide() 187 | 188 | checkSteps: ($section, direction) -> 189 | @$steps = $section.find('.steps').children() 190 | unless @$steps.length 191 | @$steps = $section.find('.step') 192 | 193 | if direction is 'backward' 194 | @index = @$steps.length - 1 195 | else 196 | @index = -1 197 | @$steps.hide() 198 | 199 | hasSteps: -> 200 | @$steps? and @$steps.length isnt 0 201 | 202 | find: (slide) -> 203 | if slide instanceof $ 204 | slide 205 | else 206 | $section = $("##{slide}") 207 | if $section.length is 0 208 | $section = @$sections.eq(parseInt(slide) - 1) 209 | $section 210 | 211 | go: (slide = 1, options = {}) -> 212 | $section = @find(slide) 213 | 214 | if $section.length and (options.force or not $section.is(@$current)) 215 | @checkSteps($section, options.direction) 216 | @navigate($section) 217 | @translate($section) 218 | @current($section) 219 | @pagination() 220 | 221 | navigate: ($section) -> 222 | window.location.hash = "/#{$section.attr('id') || $section.index() + 1}" 223 | 224 | translate: ($section) -> 225 | y = $section.prevAll().map(-> 226 | $(@).outerHeight() 227 | ).get().reduce((memo, height) -> 228 | memo + height 229 | , 0) 230 | @$ruban.css('transform', "translateY(-#{y}px)") 231 | 232 | 233 | current: ($section) -> 234 | $prev = @$current 235 | @$current = $section 236 | $prev.removeClass('active').trigger('inactive') if $prev? 237 | @$current.addClass('active').trigger('active') 238 | 239 | pagination: -> 240 | @paginationText = [] 241 | @paginationText.push @options.title if @options.title 242 | if @options.pagination or @options.title 243 | unless @$pagination 244 | @$ruban.parent().append('
') 245 | @$pagination = $('.pagination') 246 | @total = @$sections.length 247 | if @options.pagination 248 | @paginationText.push("#{@$current.index() + 1}/#{@total}") 249 | @$pagination.html(@paginationText.join(' - ')) 250 | 251 | toc: -> 252 | $toc = $('.toc').first() 253 | if $toc.length 254 | stripHtmlInToc = @options.stripHtmlInToc 255 | $ul = $('