├── LICENSE ├── README.md ├── build.py ├── logo.svg ├── modules ├── canvg │ ├── canvg.js │ ├── pow.canvg.js │ └── rgbcolor.js ├── highlight │ ├── highlight.js │ ├── html-xml.js │ ├── ir_black.css │ ├── javascript.js │ └── pow.highlight.js ├── live │ ├── pow.live.js │ └── socket.io.js └── touch │ └── pow.touch.js ├── pow.html └── src ├── pow.compat.js ├── pow.core.js ├── pow.edit.js ├── pow.init.js ├── pow.nav.js ├── pow.slides.js └── pow.ui.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Max Goodman 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 3. Neither the name of the POW nor the names of its contributors may be used 13 | to endorse or promote products derived from this software without specific 14 | prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | 28 | 29 | === Included components === 30 | modules/highlight/: highlight.js, javascript.js, html-xmljs, tir_black.css 31 | from http://softwaremaniacs.org/soft/highlight/en/ 32 | --- 33 | Copyright (c) 2006, Ivan Sagalaev 34 | All rights reserved. 35 | Redistribution and use in source and binary forms, with or without 36 | modification, are permitted provided that the following conditions are met: 37 | 38 | * Redistributions of source code must retain the above copyright 39 | notice, this list of conditions and the following disclaimer. 40 | * Redistributions in binary form must reproduce the above copyright 41 | notice, this list of conditions and the following disclaimer in the 42 | documentation and/or other materials provided with the distribution. 43 | * Neither the name of highlight.js nor the names of its contributors 44 | may be used to endorse or promote products derived from this software 45 | without specific prior written permission. 46 | 47 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 48 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 49 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 50 | DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 51 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 52 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 53 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 54 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 56 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 | 58 | 59 | modules/canvg/rgbcolor.js 60 | from http://code.google.com/p/canvg/ 61 | by Stoyan Stefanov 62 | 63 | modules/canvg/canvg.js 64 | from http://code.google.com/p/canvg/ 65 | --- 66 | Permission is hereby granted, free of charge, to any person obtaining a copy of 67 | this software and associated documentation files (the 'Software'), to deal in 68 | the Software without restriction, including without limitation the rights to 69 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 70 | of the Software, and to permit persons to whom the Software is furnished to do 71 | so, subject to the following conditions: 72 | 73 | The above copyright notice and this permission notice shall be included in all 74 | copies or substantial portions of the Software. 75 | 76 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 77 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 78 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 79 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 80 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 81 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 82 | SOFTWARE. 83 | 84 | 85 | modules/live/socket.io.js 86 | from https://github.com/learnboost/socket.io 87 | --- 88 | Copyright (c) 2010 LearnBoost 89 | 90 | Permission is hereby granted, free of charge, to any person obtaining a copy of 91 | this software and associated documentation files (the 'Software'), to deal in 92 | the Software without restriction, including without limitation the rights to 93 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 94 | of the Software, and to permit persons to whom the Software is furnished to do 95 | so, subject to the following conditions: 96 | 97 | The above copyright notice and this permission notice shall be included in all 98 | copies or substantial portions of the Software. 99 | 100 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 101 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 102 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 103 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 104 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 105 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 106 | SOFTWARE. 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | POW is a simple presentation system for HTML5. 4 | 5 | Features: 6 | 7 | * Write slides with simple HTML 8 | * Apply consistent styles using CSS 9 | * Flexible scripting using JavaScript 10 | * Extensible through modules 11 | * Self-embedding for standalone offline use 12 | 13 | # Example 14 | 15 | See POW in action (and view source): [usepow.com](http://usepow.com) 16 | 17 | The markup for a simple presentation looks like this: 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |

Hello, world.

27 |
28 |
29 | 30 | 31 | -------------------------------------------------------------------------------- /build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import re 4 | from os.path import splitext 5 | from subprocess import Popen, PIPE 6 | import json 7 | 8 | class ClosureError(Exception): pass 9 | class Closure: 10 | def __init__(self, jarpath, args): 11 | self.jarpath = jarpath 12 | self.args = args 13 | 14 | def _run(self, args, expected_code=0): 15 | p = Popen(['java', '-jar', self.jarpath] + self.args + args, stdout=PIPE, stderr=PIPE) 16 | out, msg = p.communicate() 17 | if p.returncode != expected_code: 18 | raise ClosureError(msg) 19 | else: 20 | return out, msg 21 | 22 | def version(self): 23 | out, msg = self._run(['--version', '--help'], 255) 24 | return int(re.search('Version: (\d+)', msg).group(1)) 25 | 26 | def compile(self, scripts, args=None): 27 | args = args or [] 28 | for script in scripts: 29 | args.append('--js') 30 | args.append(script) 31 | return self._run(args)[0] 32 | 33 | class Module: 34 | def __init__(self, name, src, includes=None): 35 | self.name = name 36 | self.src = src 37 | self.includes = includes 38 | 39 | def build(self): 40 | if self.includes: 41 | data = open(self.src).read() 42 | for name, include in self.includes.iteritems(): 43 | data = data.replace('/*~{0}~*/'.format(name), include.read()) 44 | 45 | name, ext = splitext(self.src) 46 | src = name + '.all' + ext 47 | open(src, 'w').write(data) 48 | return src 49 | else: 50 | return self.src 51 | 52 | def get_version(self): 53 | p = Popen(['git', 'log', '--format=format:%ct', '-n 1', self.src], stdout=PIPE, stderr=PIPE) 54 | out, msg = p.communicate() 55 | return int(out) if out else 0 56 | 57 | class ModuleFile: 58 | def __init__(self, src): 59 | self.src = src 60 | 61 | def read(self): 62 | return open(self.src).read() 63 | 64 | class ModuleFileData(ModuleFile): 65 | def read(self): 66 | return repr(ModuleFile.read(self)) 67 | 68 | class Bundle: 69 | def __init__(self, name, header, modules): 70 | self.name = name 71 | self.header = header 72 | self.modules = modules 73 | 74 | def get_versions(self): 75 | return dict((module.name, module.get_version()) for module in self.modules) 76 | 77 | def build(self, closure, versions=None, wrap_fmt=None, extra_data=None): 78 | src = closure.compile(module.build() for module in self.modules) 79 | header = self.header.replace('\n', '\n// ') 80 | versions = versions or self.get_versions() 81 | wrap_fmt = wrap_fmt or '\n'.join([ 82 | '// {header}', 83 | 'pow.bundle({bundle})']) 84 | bundle = { 85 | 'versions': versions, 86 | 'data': src, 87 | 'wrap': wrap_fmt.format(header=header, bundle='~b~') 88 | } 89 | if (extra_data): bundle.update(extra_data) 90 | return bundle['wrap'].replace('~b~', json.dumps(bundle, indent=1, sort_keys=True)) 91 | 92 | class InitBundle(Bundle): 93 | def build(self, closure): 94 | # Include the init module in the versions mapping but not the code 95 | init = Module('init', 'src/pow.init.js') 96 | versions = self.get_versions() 97 | versions['init'] = init.get_version() 98 | 99 | # To bootstrap, call the init module if pow is not defined. 100 | loader_wrap_fmt = '\n'.join([ 101 | '// {header}', 102 | '(function(b) {{ if (!window.pow) eval(b.init); pow.bundle(b); }})({bundle})']) 103 | 104 | # Build bundle with a special init property containing the init module. 105 | return Bundle.build(self, closure, 106 | versions=versions, 107 | wrap_fmt=loader_wrap_fmt, 108 | extra_data={'init': closure.compile([init.src])}) 109 | 110 | bundles = [{ 111 | 'name': 'pow', 112 | 'class': InitBundle, 113 | 'filename': 'pow.js', 114 | 'header': '\n'.join([ 115 | '', 116 | 'POW: a simple javascript presentation tool.', 117 | 'source code: http://github.com/chromakode/pow']), 118 | 'modules': [ 119 | Module('compat', 'src/pow.compat.js'), 120 | Module('core', 'src/pow.core.js'), 121 | Module('ui', 'src/pow.ui.js'), 122 | Module('slides', 'src/pow.slides.js'), 123 | Module('nav', 'src/pow.nav.js')], 124 | }, { 125 | 'name': 'highlight', 126 | 'header': '\n'.join([ 127 | 'pow.highlight: Syntax highlighting by highlight.js.', 128 | 'Thanks to http://softwaremaniacs.org/soft/highlight/en/']), 129 | 'modules': [ 130 | Module('highlight', 'modules/highlight/pow.highlight.js', { 131 | 'highlight.js': ModuleFile('modules/highlight/highlight.js'), 132 | 'javascript.js': ModuleFile('modules/highlight/javascript.js'), 133 | 'html-xml.js': ModuleFile('modules/highlight/html-xml.js'), 134 | 'ir_black.css': ModuleFileData('modules/highlight/ir_black.css')})], 135 | }, { 136 | 'name': 'mobile', 137 | 'header': 'pow.mobile: Improved support and functionality on mobile devices.', 138 | 'modules': [ 139 | Module('touch', 'modules/touch/pow.touch.js'), 140 | Module('canvg', 'modules/canvg/pow.canvg.js', { 141 | 'rgbcolor.js': ModuleFile('modules/canvg/rgbcolor.js'), 142 | 'canvg.js': ModuleFile('modules/canvg/canvg.js')})], 143 | }, { 144 | 'name': 'live', 145 | 'header': '\n'.join([ 146 | 'pow.live: Synchronized presentations across multiple devices.', 147 | 'Powered by http://usepow.com/live']), 148 | 'modules': [ 149 | Module('live', 'modules/live/pow.live.js', { 150 | 'socket.io.js': ModuleFile('modules/live/socket.io.js')})], 151 | }] 152 | 153 | def main(): 154 | if len(sys.argv) < 2: 155 | print "Usage: build.py path-to-closure-compiler" 156 | sys.exit(1) 157 | 158 | closure = Closure(sys.argv[1], [ 159 | '--language_in=ECMASCRIPT5', 160 | '--compilation_level=SIMPLE_OPTIMIZATIONS']) 161 | if closure.version() < 771: 162 | print "ERROR: Old version of Closure Compiler detected: at least 771 is required." 163 | sys.exit(1) 164 | 165 | try: 166 | for data in bundles: 167 | cls = data.get('class', Bundle) 168 | filename = data.get('filename', 'pow.{0}.js'.format(data['name'])) 169 | bundle = cls(data['name'], data['header'], data['modules']) 170 | open(filename, 'w').write(bundle.build(closure)) 171 | print 'Built bundle {0}: {1}'.format(data['name'], filename) 172 | 173 | except ClosureError, e: 174 | print "ERROR: An unknown error occurred running Closure Compiler:" 175 | print e 176 | sys.exit(1) 177 | 178 | if __name__ == '__main__': 179 | main() 180 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 25 | 29 | 33 | 37 | 38 | 47 | 49 | 53 | 57 | 58 | 67 | 76 | 86 | 95 | 104 | 113 | 114 | 132 | 134 | 135 | 137 | image/svg+xml 138 | 140 | 141 | 142 | 143 | 144 | 149 | 155 | 161 | 163 | 169 | 174 | 179 | 184 | 189 | 194 | 195 | 198 | 202 | 208 | 213 | 219 | 225 | 231 | 232 | 236 | 242 | 247 | 253 | 259 | 265 | 266 | 270 | 275 | 280 | 285 | 291 | 296 | 297 | 303 | 304 | 305 | 306 | -------------------------------------------------------------------------------- /modules/canvg/pow.canvg.js: -------------------------------------------------------------------------------- 1 | pow.module('canvg', function() { 2 | /*~rgbcolor.js~*/ 3 | /*~canvg.js~*/ 4 | function toArray(o) { 5 | return Array.prototype.slice.call(o) 6 | } 7 | 8 | function replaceSVG(svgTag) { 9 | var c = document.createElement('canvas') 10 | c.setAttribute('class', svgTag.getAttribute('class')) 11 | svgTag.parentNode.insertBefore(c, svgTag) 12 | svgTag.parentNode.removeChild(svgTag) 13 | c.width = c.clientWidth 14 | c.height = c.clientHeight 15 | 16 | // Work around automatic lowercasing of the viewbox attribute in some parsers. 17 | if (svgTag.hasAttribute('viewbox')) { 18 | svgTag.setAttributeNS('', 'viewBox', svgTag.getAttribute('viewBox')) 19 | } 20 | 21 | options = {ignoreMouse:true, ignoreDimensions:true} 22 | if (svgTag.nodeName == 'OBJECT') { 23 | canvg(c, svgTag.data, options) 24 | } else { 25 | var div = document.createElement('div') 26 | div.appendChild(svgTag) 27 | canvg(c, div.innerHTML, options) 28 | } 29 | } 30 | 31 | function canvgChildren(el) { 32 | if (el.nodeName == '#text') { return } 33 | var svgTags = [].concat( 34 | toArray(el.getElementsByTagName('svg')), 35 | toArray(el.getElementsByTagName('object'))) 36 | svgTags.forEach(replaceSVG) 37 | } 38 | 39 | if (!pow.compat.inlineSVG) { 40 | pow.slides.on.show(function(slide) { 41 | canvgChildren(slide.el) 42 | }, false) 43 | 44 | pow.on.start(function() { 45 | toArray(document.body.childNodes).forEach(function(el) { 46 | if (el.id != 'slides') { canvgChildren(el) } 47 | }) 48 | }) 49 | } 50 | }) 51 | -------------------------------------------------------------------------------- /modules/canvg/rgbcolor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A class to parse color values 3 | * @author Stoyan Stefanov 4 | * @link http://www.phpied.com/rgb-color-parser-in-javascript/ 5 | * @license Use it if you like it 6 | */ 7 | function RGBColor(color_string) 8 | { 9 | this.ok = false; 10 | 11 | // strip any leading # 12 | if (color_string.charAt(0) == '#') { // remove # if any 13 | color_string = color_string.substr(1,6); 14 | } 15 | 16 | color_string = color_string.replace(/ /g,''); 17 | color_string = color_string.toLowerCase(); 18 | 19 | // before getting into regexps, try simple matches 20 | // and overwrite the input 21 | var simple_colors = { 22 | aliceblue: 'f0f8ff', 23 | antiquewhite: 'faebd7', 24 | aqua: '00ffff', 25 | aquamarine: '7fffd4', 26 | azure: 'f0ffff', 27 | beige: 'f5f5dc', 28 | bisque: 'ffe4c4', 29 | black: '000000', 30 | blanchedalmond: 'ffebcd', 31 | blue: '0000ff', 32 | blueviolet: '8a2be2', 33 | brown: 'a52a2a', 34 | burlywood: 'deb887', 35 | cadetblue: '5f9ea0', 36 | chartreuse: '7fff00', 37 | chocolate: 'd2691e', 38 | coral: 'ff7f50', 39 | cornflowerblue: '6495ed', 40 | cornsilk: 'fff8dc', 41 | crimson: 'dc143c', 42 | cyan: '00ffff', 43 | darkblue: '00008b', 44 | darkcyan: '008b8b', 45 | darkgoldenrod: 'b8860b', 46 | darkgray: 'a9a9a9', 47 | darkgreen: '006400', 48 | darkkhaki: 'bdb76b', 49 | darkmagenta: '8b008b', 50 | darkolivegreen: '556b2f', 51 | darkorange: 'ff8c00', 52 | darkorchid: '9932cc', 53 | darkred: '8b0000', 54 | darksalmon: 'e9967a', 55 | darkseagreen: '8fbc8f', 56 | darkslateblue: '483d8b', 57 | darkslategray: '2f4f4f', 58 | darkturquoise: '00ced1', 59 | darkviolet: '9400d3', 60 | deeppink: 'ff1493', 61 | deepskyblue: '00bfff', 62 | dimgray: '696969', 63 | dodgerblue: '1e90ff', 64 | feldspar: 'd19275', 65 | firebrick: 'b22222', 66 | floralwhite: 'fffaf0', 67 | forestgreen: '228b22', 68 | fuchsia: 'ff00ff', 69 | gainsboro: 'dcdcdc', 70 | ghostwhite: 'f8f8ff', 71 | gold: 'ffd700', 72 | goldenrod: 'daa520', 73 | gray: '808080', 74 | green: '008000', 75 | greenyellow: 'adff2f', 76 | honeydew: 'f0fff0', 77 | hotpink: 'ff69b4', 78 | indianred : 'cd5c5c', 79 | indigo : '4b0082', 80 | ivory: 'fffff0', 81 | khaki: 'f0e68c', 82 | lavender: 'e6e6fa', 83 | lavenderblush: 'fff0f5', 84 | lawngreen: '7cfc00', 85 | lemonchiffon: 'fffacd', 86 | lightblue: 'add8e6', 87 | lightcoral: 'f08080', 88 | lightcyan: 'e0ffff', 89 | lightgoldenrodyellow: 'fafad2', 90 | lightgrey: 'd3d3d3', 91 | lightgreen: '90ee90', 92 | lightpink: 'ffb6c1', 93 | lightsalmon: 'ffa07a', 94 | lightseagreen: '20b2aa', 95 | lightskyblue: '87cefa', 96 | lightslateblue: '8470ff', 97 | lightslategray: '778899', 98 | lightsteelblue: 'b0c4de', 99 | lightyellow: 'ffffe0', 100 | lime: '00ff00', 101 | limegreen: '32cd32', 102 | linen: 'faf0e6', 103 | magenta: 'ff00ff', 104 | maroon: '800000', 105 | mediumaquamarine: '66cdaa', 106 | mediumblue: '0000cd', 107 | mediumorchid: 'ba55d3', 108 | mediumpurple: '9370d8', 109 | mediumseagreen: '3cb371', 110 | mediumslateblue: '7b68ee', 111 | mediumspringgreen: '00fa9a', 112 | mediumturquoise: '48d1cc', 113 | mediumvioletred: 'c71585', 114 | midnightblue: '191970', 115 | mintcream: 'f5fffa', 116 | mistyrose: 'ffe4e1', 117 | moccasin: 'ffe4b5', 118 | navajowhite: 'ffdead', 119 | navy: '000080', 120 | oldlace: 'fdf5e6', 121 | olive: '808000', 122 | olivedrab: '6b8e23', 123 | orange: 'ffa500', 124 | orangered: 'ff4500', 125 | orchid: 'da70d6', 126 | palegoldenrod: 'eee8aa', 127 | palegreen: '98fb98', 128 | paleturquoise: 'afeeee', 129 | palevioletred: 'd87093', 130 | papayawhip: 'ffefd5', 131 | peachpuff: 'ffdab9', 132 | peru: 'cd853f', 133 | pink: 'ffc0cb', 134 | plum: 'dda0dd', 135 | powderblue: 'b0e0e6', 136 | purple: '800080', 137 | red: 'ff0000', 138 | rosybrown: 'bc8f8f', 139 | royalblue: '4169e1', 140 | saddlebrown: '8b4513', 141 | salmon: 'fa8072', 142 | sandybrown: 'f4a460', 143 | seagreen: '2e8b57', 144 | seashell: 'fff5ee', 145 | sienna: 'a0522d', 146 | silver: 'c0c0c0', 147 | skyblue: '87ceeb', 148 | slateblue: '6a5acd', 149 | slategray: '708090', 150 | snow: 'fffafa', 151 | springgreen: '00ff7f', 152 | steelblue: '4682b4', 153 | tan: 'd2b48c', 154 | teal: '008080', 155 | thistle: 'd8bfd8', 156 | tomato: 'ff6347', 157 | turquoise: '40e0d0', 158 | violet: 'ee82ee', 159 | violetred: 'd02090', 160 | wheat: 'f5deb3', 161 | white: 'ffffff', 162 | whitesmoke: 'f5f5f5', 163 | yellow: 'ffff00', 164 | yellowgreen: '9acd32' 165 | }; 166 | for (var key in simple_colors) { 167 | if (color_string == key) { 168 | color_string = simple_colors[key]; 169 | } 170 | } 171 | // emd of simple type-in colors 172 | 173 | // array of color definition objects 174 | var color_defs = [ 175 | { 176 | re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, 177 | example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], 178 | process: function (bits){ 179 | return [ 180 | parseInt(bits[1]), 181 | parseInt(bits[2]), 182 | parseInt(bits[3]) 183 | ]; 184 | } 185 | }, 186 | { 187 | re: /^(\w{2})(\w{2})(\w{2})$/, 188 | example: ['#00ff00', '336699'], 189 | process: function (bits){ 190 | return [ 191 | parseInt(bits[1], 16), 192 | parseInt(bits[2], 16), 193 | parseInt(bits[3], 16) 194 | ]; 195 | } 196 | }, 197 | { 198 | re: /^(\w{1})(\w{1})(\w{1})$/, 199 | example: ['#fb0', 'f0f'], 200 | process: function (bits){ 201 | return [ 202 | parseInt(bits[1] + bits[1], 16), 203 | parseInt(bits[2] + bits[2], 16), 204 | parseInt(bits[3] + bits[3], 16) 205 | ]; 206 | } 207 | } 208 | ]; 209 | 210 | // search through the definitions to find a match 211 | for (var i = 0; i < color_defs.length; i++) { 212 | var re = color_defs[i].re; 213 | var processor = color_defs[i].process; 214 | var bits = re.exec(color_string); 215 | if (bits) { 216 | channels = processor(bits); 217 | this.r = channels[0]; 218 | this.g = channels[1]; 219 | this.b = channels[2]; 220 | this.ok = true; 221 | } 222 | 223 | } 224 | 225 | // validate/cleanup values 226 | this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); 227 | this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); 228 | this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); 229 | 230 | // some getters 231 | this.toRGB = function () { 232 | return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; 233 | } 234 | this.toHex = function () { 235 | var r = this.r.toString(16); 236 | var g = this.g.toString(16); 237 | var b = this.b.toString(16); 238 | if (r.length == 1) r = '0' + r; 239 | if (g.length == 1) g = '0' + g; 240 | if (b.length == 1) b = '0' + b; 241 | return '#' + r + g + b; 242 | } 243 | 244 | // help 245 | this.getHelpXML = function () { 246 | 247 | var examples = new Array(); 248 | // add regexps 249 | for (var i = 0; i < color_defs.length; i++) { 250 | var example = color_defs[i].example; 251 | for (var j = 0; j < example.length; j++) { 252 | examples[examples.length] = example[j]; 253 | } 254 | } 255 | // add type-in colors 256 | for (var sc in simple_colors) { 257 | examples[examples.length] = sc; 258 | } 259 | 260 | var xml = document.createElement('ul'); 261 | xml.setAttribute('id', 'rgbcolor-examples'); 262 | for (var i = 0; i < examples.length; i++) { 263 | try { 264 | var list_item = document.createElement('li'); 265 | var list_color = new RGBColor(examples[i]); 266 | var example_div = document.createElement('div'); 267 | example_div.style.cssText = 268 | 'margin: 3px; ' 269 | + 'border: 1px solid black; ' 270 | + 'background:' + list_color.toHex() + '; ' 271 | + 'color:' + list_color.toHex() 272 | ; 273 | example_div.appendChild(document.createTextNode('test')); 274 | var list_item_value = document.createTextNode( 275 | ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() 276 | ); 277 | list_item.appendChild(example_div); 278 | list_item.appendChild(list_item_value); 279 | xml.appendChild(list_item); 280 | 281 | } catch(e){} 282 | } 283 | return xml; 284 | 285 | } 286 | 287 | } 288 | 289 | -------------------------------------------------------------------------------- /modules/highlight/highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | Syntax highlighting with language autodetection. 3 | http://softwaremaniacs.org/soft/highlight/ 4 | */ 5 | 6 | var hljs = new function() { 7 | var LANGUAGES = {} 8 | // selected_languages is used to support legacy mode of selecting languages 9 | // available for highlighting by passing them as arguments into 10 | // initHighlighting function. Currently the whole library is expected to 11 | // contain only those language definitions that are actually get used. 12 | var selected_languages = {}; 13 | 14 | /* Utility functions */ 15 | 16 | function escape(value) { 17 | return value.replace(/&/gm, '&').replace(//gm, '>'); 18 | } 19 | 20 | function contains(array, item) { 21 | if (!array) 22 | return false; 23 | for (var i = 0; i < array.length; i++) 24 | if (array[i] == item) 25 | return true; 26 | return false; 27 | } 28 | 29 | function langRe(language, value, global) { 30 | var mode = 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : ''); 31 | return new RegExp(value, mode); 32 | } 33 | 34 | function findCode(pre) { 35 | for (var i = 0; i < pre.childNodes.length; i++) { 36 | node = pre.childNodes[i]; 37 | if (node.nodeName == 'CODE') 38 | return node; 39 | if (!(node.nodeType == 3 && node.nodeValue.match(/\s+/))) 40 | return null; 41 | } 42 | } 43 | 44 | function blockText(block, ignoreNewLines) { 45 | var result = ''; 46 | for (var i = 0; i < block.childNodes.length; i++) 47 | if (block.childNodes[i].nodeType == 3) { 48 | var chunk = block.childNodes[i].nodeValue; 49 | if (ignoreNewLines) 50 | chunk = chunk.replace(/\n/g, ''); 51 | result += chunk; 52 | } else if (block.childNodes[i].nodeName == 'BR') 53 | result += '\n'; 54 | else 55 | result += blockText(block.childNodes[i]); 56 | // Thank you, MSIE... 57 | result = result.replace(/\r/g, '\n'); 58 | return result; 59 | } 60 | 61 | function blockLanguage(block) { 62 | var classes = block.className.split(/\s+/) 63 | classes = classes.concat(block.parentNode.className.split(/\s+/)); 64 | for (var i = 0; i < classes.length; i++) { 65 | var class_ = classes[i].replace(/^language-/, ''); 66 | if (LANGUAGES[class_] || class_ == 'no-highlight') { 67 | return class_; 68 | } 69 | } 70 | } 71 | 72 | /* Stream merging */ 73 | 74 | function nodeStream(node) { 75 | var result = []; 76 | (function (node, offset) { 77 | for (var i = 0; i < node.childNodes.length; i++) { 78 | if (node.childNodes[i].nodeType == 3) 79 | offset += node.childNodes[i].nodeValue.length; 80 | else if (node.childNodes[i].nodeName == 'BR') 81 | offset += 1 82 | else { 83 | result.push({ 84 | event: 'start', 85 | offset: offset, 86 | node: node.childNodes[i] 87 | }); 88 | offset = arguments.callee(node.childNodes[i], offset) 89 | result.push({ 90 | event: 'stop', 91 | offset: offset, 92 | node: node.childNodes[i] 93 | }); 94 | } 95 | } 96 | return offset; 97 | })(node, 0); 98 | return result; 99 | } 100 | 101 | function mergeStreams(stream1, stream2, value) { 102 | var processed = 0; 103 | var result = ''; 104 | var nodeStack = []; 105 | 106 | function selectStream() { 107 | if (stream1.length && stream2.length) { 108 | if (stream1[0].offset != stream2[0].offset) 109 | return (stream1[0].offset < stream2[0].offset) ? stream1 : stream2; 110 | else 111 | return (stream1[0].event == 'start' && stream2[0].event == 'stop') ? stream2 : stream1; 112 | } else { 113 | return stream1.length ? stream1 : stream2; 114 | } 115 | } 116 | 117 | function open(node) { 118 | var result = '<' + node.nodeName.toLowerCase(); 119 | for (var i = 0; i < node.attributes.length; i++) { 120 | var attribute = node.attributes[i]; 121 | result += ' ' + attribute.nodeName.toLowerCase(); 122 | if (attribute.nodeValue != undefined) { 123 | result += '="' + escape(attribute.nodeValue) + '"'; 124 | } 125 | } 126 | return result + '>'; 127 | } 128 | 129 | function close(node) { 130 | return ''; 131 | } 132 | 133 | while (stream1.length || stream2.length) { 134 | var current = selectStream().splice(0, 1)[0]; 135 | result += escape(value.substr(processed, current.offset - processed)); 136 | processed = current.offset; 137 | if ( current.event == 'start') { 138 | result += open(current.node); 139 | nodeStack.push(current.node); 140 | } else if (current.event == 'stop') { 141 | var i = nodeStack.length; 142 | do { 143 | i--; 144 | var node = nodeStack[i]; 145 | result += close(node); 146 | } while (node != current.node); 147 | nodeStack.splice(i, 1); 148 | while (i < nodeStack.length) { 149 | result += open(nodeStack[i]); 150 | i++; 151 | } 152 | } 153 | } 154 | result += value.substr(processed); 155 | return result; 156 | } 157 | 158 | /* Core highlighting function */ 159 | 160 | function highlight(language_name, value) { 161 | 162 | function subMode(lexem, mode) { 163 | for (var i = 0; i < mode.sub_modes.length; i++) { 164 | if (mode.sub_modes[i].beginRe.test(lexem)) { 165 | return mode.sub_modes[i]; 166 | } 167 | } 168 | return null; 169 | } 170 | 171 | function endOfMode(mode_index, lexem) { 172 | if (modes[mode_index].end && modes[mode_index].endRe.test(lexem)) 173 | return 1; 174 | if (modes[mode_index].endsWithParent) { 175 | var level = endOfMode(mode_index - 1, lexem); 176 | return level ? level + 1 : 0; 177 | } 178 | return 0; 179 | } 180 | 181 | function isIllegal(lexem, mode) { 182 | return mode.illegalRe && mode.illegalRe.test(lexem); 183 | } 184 | 185 | function compileTerminators(mode, language) { 186 | var terminators = []; 187 | 188 | for (var i = 0; i < mode.sub_modes.length; i++) { 189 | terminators.push(mode.sub_modes[i].begin); 190 | } 191 | 192 | var index = modes.length - 1; 193 | do { 194 | if (modes[index].end) { 195 | terminators.push(modes[index].end); 196 | } 197 | index--; 198 | } while (modes[index + 1].endsWithParent); 199 | 200 | if (mode.illegal) { 201 | terminators.push(mode.illegal); 202 | } 203 | 204 | return langRe(language, '(' + terminators.join('|') + ')', true); 205 | } 206 | 207 | function eatModeChunk(value, index) { 208 | var mode = modes[modes.length - 1]; 209 | if (!mode.terminators) { 210 | mode.terminators = compileTerminators(mode, language); 211 | } 212 | mode.terminators.lastIndex = index; 213 | var match = mode.terminators.exec(value); 214 | if (match) 215 | return [value.substr(index, match.index - index), match[0], false]; 216 | else 217 | return [value.substr(index), '', true]; 218 | } 219 | 220 | function keywordMatch(mode, match) { 221 | var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0] 222 | for (var className in mode.keywordGroups) { 223 | if (!mode.keywordGroups.hasOwnProperty(className)) 224 | continue; 225 | var value = mode.keywordGroups[className].hasOwnProperty(match_str); 226 | if (value) 227 | return [className, value]; 228 | } 229 | return false; 230 | } 231 | 232 | function processKeywords(buffer, mode) { 233 | if (!mode.keywords || !mode.lexems) 234 | return escape(buffer); 235 | if (!mode.lexemsRe) { 236 | var lexems_re = '(' + mode.lexems.join('|') + ')'; 237 | mode.lexemsRe = langRe(language, lexems_re, true); 238 | } 239 | var result = ''; 240 | var last_index = 0; 241 | mode.lexemsRe.lastIndex = 0; 242 | var match = mode.lexemsRe.exec(buffer); 243 | while (match) { 244 | result += escape(buffer.substr(last_index, match.index - last_index)); 245 | var keyword_match = keywordMatch(mode, match); 246 | if (keyword_match) { 247 | keyword_count += keyword_match[1]; 248 | result += '' + escape(match[0]) + ''; 249 | } else { 250 | result += escape(match[0]); 251 | } 252 | last_index = mode.lexemsRe.lastIndex; 253 | match = mode.lexemsRe.exec(buffer); 254 | } 255 | result += escape(buffer.substr(last_index, buffer.length - last_index)); 256 | return result; 257 | } 258 | 259 | function processBuffer(buffer, mode) { 260 | if (mode.subLanguage && selected_languages[mode.subLanguage]) { 261 | var result = highlight(mode.subLanguage, buffer); 262 | keyword_count += result.keyword_count; 263 | relevance += result.relevance; 264 | return result.value; 265 | } else { 266 | return processKeywords(buffer, mode); 267 | } 268 | } 269 | 270 | function startNewMode(mode, lexem) { 271 | var markup = mode.noMarkup?'':''; 272 | if (mode.returnBegin) { 273 | result += markup; 274 | mode.buffer = ''; 275 | } else if (mode.excludeBegin) { 276 | result += escape(lexem) + markup; 277 | mode.buffer = ''; 278 | } else { 279 | result += markup; 280 | mode.buffer = lexem; 281 | } 282 | modes[modes.length] = mode; 283 | } 284 | 285 | function processModeInfo(buffer, lexem, end) { 286 | var current_mode = modes[modes.length - 1]; 287 | if (end) { 288 | result += processBuffer(current_mode.buffer + buffer, current_mode); 289 | return false; 290 | } 291 | 292 | var new_mode = subMode(lexem, current_mode); 293 | if (new_mode) { 294 | result += processBuffer(current_mode.buffer + buffer, current_mode); 295 | startNewMode(new_mode, lexem); 296 | relevance += new_mode.relevance; 297 | return new_mode.returnBegin; 298 | } 299 | 300 | var end_level = endOfMode(modes.length - 1, lexem); 301 | if (end_level) { 302 | var markup = current_mode.noMarkup?'':''; 303 | if (current_mode.returnEnd) { 304 | result += processBuffer(current_mode.buffer + buffer, current_mode) + markup; 305 | } else if (current_mode.excludeEnd) { 306 | result += processBuffer(current_mode.buffer + buffer, current_mode) + markup + escape(lexem); 307 | } else { 308 | result += processBuffer(current_mode.buffer + buffer + lexem, current_mode) + markup; 309 | } 310 | while (end_level > 1) { 311 | markup = modes[modes.length - 2].noMarkup?'':''; 312 | result += markup; 313 | end_level--; 314 | modes.length--; 315 | } 316 | var last_ended_mode = modes[modes.length - 1]; 317 | modes.length--; 318 | modes[modes.length - 1].buffer = ''; 319 | if (last_ended_mode.starts) { 320 | for (var i = 0; i < language.modes.length; i++) { 321 | if (language.modes[i].className == last_ended_mode.starts) { 322 | startNewMode(language.modes[i], ''); 323 | break; 324 | } 325 | } 326 | } 327 | return current_mode.returnEnd; 328 | } 329 | 330 | if (isIllegal(lexem, current_mode)) 331 | throw 'Illegal'; 332 | } 333 | 334 | var language = LANGUAGES[language_name]; 335 | var modes = [language.defaultMode]; 336 | var relevance = 0; 337 | var keyword_count = 0; 338 | var result = ''; 339 | try { 340 | var index = 0; 341 | language.defaultMode.buffer = ''; 342 | do { 343 | var mode_info = eatModeChunk(value, index); 344 | var return_lexem = processModeInfo(mode_info[0], mode_info[1], mode_info[2]); 345 | index += mode_info[0].length; 346 | if (!return_lexem) { 347 | index += mode_info[1].length; 348 | } 349 | } while (!mode_info[2]); 350 | if(modes.length > 1) 351 | throw 'Illegal'; 352 | return { 353 | language: language_name, 354 | relevance: relevance, 355 | keyword_count: keyword_count, 356 | value: result 357 | } 358 | } catch (e) { 359 | if (e == 'Illegal') { 360 | return { 361 | language: null, 362 | relevance: 0, 363 | keyword_count: 0, 364 | value: escape(value) 365 | } 366 | } else { 367 | throw e; 368 | } 369 | } 370 | } 371 | 372 | /* Initialization */ 373 | 374 | function compileModes() { 375 | 376 | function compileMode(mode, language) { 377 | if (mode.compiled) 378 | return; 379 | 380 | if (mode.begin) 381 | mode.beginRe = langRe(language, '^' + mode.begin); 382 | if (mode.end) 383 | mode.endRe = langRe(language, '^' + mode.end); 384 | if (mode.illegal) 385 | mode.illegalRe = langRe(language, '^(?:' + mode.illegal + ')'); 386 | if (mode.relevance == undefined) 387 | mode.relevance = 1; 388 | if (!mode.displayClassName) 389 | mode.displayClassName = mode.className; 390 | if (!mode.className) 391 | mode.noMarkup = true; 392 | for (var key in mode.keywords) { 393 | if (!mode.keywords.hasOwnProperty(key)) 394 | continue; 395 | if (mode.keywords[key] instanceof Object) 396 | mode.keywordGroups = mode.keywords; 397 | else 398 | mode.keywordGroups = {'keyword': mode.keywords}; 399 | break; 400 | } 401 | mode.sub_modes = []; 402 | if (mode.contains) { 403 | for (var i = 0; i < mode.contains.length; i++) { 404 | if (mode.contains[i] instanceof Object) { // inline mode 405 | mode.sub_modes.push(mode.contains[i]); 406 | } else { // named mode 407 | for (var j = 0; j < language.modes.length; j++) { 408 | if (language.modes[j].className == mode.contains[i]) { 409 | mode.sub_modes.push(language.modes[j]); 410 | } 411 | } 412 | } 413 | } 414 | } 415 | // compiled flag is set before compiling submodes to avoid self-recursion 416 | // (see lisp where quoted_list contains quoted_list) 417 | mode.compiled = true; 418 | for (var i = 0; i < mode.sub_modes.length; i++) { 419 | compileMode(mode.sub_modes[i], language); 420 | } 421 | } 422 | 423 | for (var i in LANGUAGES) { 424 | if (!LANGUAGES.hasOwnProperty(i)) 425 | continue; 426 | var modes = [LANGUAGES[i].defaultMode].concat(LANGUAGES[i].modes); 427 | for (var j = 0; j < modes.length; j++) { 428 | compileMode(modes[j], LANGUAGES[i]); 429 | } 430 | } 431 | } 432 | 433 | function initialize() { 434 | if (initialize.called) 435 | return; 436 | initialize.called = true; 437 | compileModes(); 438 | selected_languages = LANGUAGES; 439 | } 440 | 441 | /* Public library functions */ 442 | 443 | function highlightBlock(block, tabReplace, useBR) { 444 | initialize(); 445 | 446 | var text = blockText(block, useBR); 447 | var language = blockLanguage(block); 448 | if (language == 'no-highlight') 449 | return; 450 | if (language) { 451 | var result = highlight(language, text); 452 | } else { 453 | var result = {language: '', keyword_count: 0, relevance: 0, value: escape(text)}; 454 | var second_best = result; 455 | for (var key in selected_languages) { 456 | if (!selected_languages.hasOwnProperty(key)) 457 | continue; 458 | var current = highlight(key, text); 459 | if (current.keyword_count + current.relevance > second_best.keyword_count + second_best.relevance) { 460 | second_best = current; 461 | } 462 | if (current.keyword_count + current.relevance > result.keyword_count + result.relevance) { 463 | second_best = result; 464 | result = current; 465 | } 466 | } 467 | } 468 | 469 | var class_name = block.className; 470 | if (!class_name.match(result.language)) { 471 | class_name = class_name ? (class_name + ' ' + result.language) : result.language; 472 | } 473 | var original = nodeStream(block); 474 | if (original.length) { 475 | var pre = document.createElement('pre'); 476 | pre.innerHTML = result.value; 477 | result.value = mergeStreams(original, nodeStream(pre), text); 478 | } 479 | if (tabReplace) { 480 | result.value = result.value.replace(/^((<[^>]+>|\t)+)/gm, function(match, p1, offset, s) { 481 | return p1.replace(/\t/g, tabReplace); 482 | }) 483 | } 484 | if (useBR) { 485 | result.value = result.value.replace(/\n/g, '
'); 486 | } 487 | if (/MSIE [678]/.test(navigator.userAgent) && block.tagName == 'CODE' && block.parentNode.tagName == 'PRE') { 488 | // This is for backwards compatibility only. IE needs this strange 489 | // hack becasue it cannot just cleanly replace block contents. 490 | var pre = block.parentNode; 491 | var container = document.createElement('div'); 492 | container.innerHTML = '
' + result.value + '
'; 493 | block = container.firstChild.firstChild; 494 | container.firstChild.className = pre.className; 495 | pre.parentNode.replaceChild(container.firstChild, pre); 496 | } else { 497 | block.innerHTML = result.value; 498 | } 499 | block.className = class_name; 500 | block.dataset = {}; 501 | block.dataset.result = { 502 | language: result.language, 503 | kw: result.keyword_count, 504 | re: result.relevance 505 | }; 506 | if (second_best && second_best.language) { 507 | block.dataset.second_best = { 508 | language: second_best.language, 509 | kw: second_best.keyword_count, 510 | re: second_best.relevance 511 | }; 512 | } 513 | } 514 | 515 | function initHighlighting() { 516 | if (initHighlighting.called) 517 | return; 518 | initHighlighting.called = true; 519 | initialize(); 520 | if (arguments.length) { 521 | for (var i = 0; i < arguments.length; i++) { 522 | if (LANGUAGES[arguments[i]]) { 523 | selected_languages[arguments[i]] = LANGUAGES[arguments[i]]; 524 | } 525 | } 526 | } 527 | var pres = document.getElementsByTagName('pre'); 528 | for (var i = 0; i < pres.length; i++) { 529 | var code = findCode(pres[i]); 530 | if (code) 531 | highlightBlock(code, hljs.tabReplace); 532 | } 533 | } 534 | 535 | function initHighlightingOnLoad() { 536 | var original_arguments = arguments; 537 | var handler = function(){initHighlighting.apply(null, original_arguments)}; 538 | if (window.addEventListener) { 539 | window.addEventListener('DOMContentLoaded', handler, false); 540 | window.addEventListener('load', handler, false); 541 | } else if (window.attachEvent) 542 | window.attachEvent('onload', handler); 543 | else 544 | window.onload = handler; 545 | } 546 | 547 | /* Interface definition */ 548 | 549 | this.LANGUAGES = LANGUAGES; 550 | this.initHighlightingOnLoad = initHighlightingOnLoad; 551 | this.highlightBlock = highlightBlock; 552 | this.initHighlighting = initHighlighting; 553 | 554 | // Common regexps 555 | this.IMMEDIATE_RE = '\\b|\\B' 556 | this.IDENT_RE = '[a-zA-Z][a-zA-Z0-9_]*'; 557 | this.UNDERSCORE_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_]*'; 558 | this.NUMBER_RE = '\\b\\d+(\\.\\d+)?'; 559 | this.C_NUMBER_RE = '\\b(0x[A-Za-z0-9]+|\\d+(\\.\\d+)?)'; 560 | this.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; 561 | 562 | // Common modes 563 | this.APOS_STRING_MODE = { 564 | className: 'string', 565 | begin: '\'', end: '\'', 566 | illegal: '\\n', 567 | contains: ['escape'], 568 | relevance: 0 569 | }; 570 | this.QUOTE_STRING_MODE = { 571 | className: 'string', 572 | begin: '"', end: '"', 573 | illegal: '\\n', 574 | contains: ['escape'], 575 | relevance: 0 576 | }; 577 | this.BACKSLASH_ESCAPE = { 578 | className: 'escape', 579 | begin: '\\\\.', end: this.IMMEDIATE_RE, noMarkup: true, 580 | relevance: 0 581 | }; 582 | this.C_LINE_COMMENT_MODE = { 583 | className: 'comment', 584 | begin: '//', end: '$', 585 | relevance: 0 586 | }; 587 | this.C_BLOCK_COMMENT_MODE = { 588 | className: 'comment', 589 | begin: '/\\*', end: '\\*/' 590 | }; 591 | this.HASH_COMMENT_MODE = { 592 | className: 'comment', 593 | begin: '#', end: '$' 594 | }; 595 | this.NUMBER_MODE = { 596 | className: 'number', 597 | begin: this.NUMBER_RE, end: this.IMMEDIATE_RE, 598 | relevance: 0 599 | }; 600 | this.C_NUMBER_MODE = { 601 | className: 'number', 602 | begin: this.C_NUMBER_RE, end: this.IMMEDIATE_RE, 603 | relevance: 0 604 | }; 605 | 606 | // Utility functions 607 | this.inherit = function(parent, obj) { 608 | var result = {} 609 | for (var key in parent) 610 | result[key] = parent[key]; 611 | if (obj) 612 | for (var key in obj) 613 | result[key] = obj[key]; 614 | return result; 615 | } 616 | }(); 617 | 618 | var initHighlightingOnLoad = hljs.initHighlightingOnLoad; 619 | -------------------------------------------------------------------------------- /modules/highlight/html-xml.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: HTML, XML 3 | */ 4 | 5 | (function(){ 6 | 7 | var XML_IDENT_RE = '[A-Za-z0-9\\._:-]+'; 8 | 9 | var PI = { 10 | className: 'pi', 11 | begin: '<\\?', end: '\\?>', 12 | relevance: 10 13 | }; 14 | var DOCTYPE = { 15 | className: 'doctype', 16 | begin: '', 17 | relevance: 10 18 | }; 19 | var COMMENT = { 20 | className: 'comment', 21 | begin: '' 22 | }; 23 | var TAG = { 24 | className: 'tag', 25 | begin: '', 26 | contains: ['title', 'tag_internal'] 27 | }; 28 | var TITLE = { 29 | className: 'title', 30 | begin: XML_IDENT_RE, end: hljs.IMMEDIATE_RE 31 | }; 32 | var TAG_INTERNAL = { 33 | className: 'tag_internal', 34 | begin: hljs.IMMEDIATE_RE, endsWithParent: true, noMarkup: true, 35 | contains: ['attribute', 'value_container'], 36 | relevance: 0 37 | }; 38 | var ATTR = { 39 | className: 'attribute', 40 | begin: XML_IDENT_RE, end: hljs.IMMEDIATE_RE, 41 | relevance: 0 42 | }; 43 | var VALUE_CONTAINER_QUOT = { 44 | className: 'value_container', 45 | begin: '="', returnBegin: true, end: '"', noMarkup: true, 46 | contains: [{ 47 | className: 'value', 48 | begin: '"', endsWithParent: true 49 | }] 50 | }; 51 | var VALUE_CONTAINER_APOS = { 52 | className: 'value_container', 53 | begin: '=\'', returnBegin: true, end: '\'', noMarkup: true, 54 | contains: [{ 55 | className: 'value', 56 | begin: '\'', endsWithParent: true 57 | }] 58 | }; 59 | 60 | hljs.LANGUAGES.xml = { 61 | defaultMode: { 62 | contains: ['pi', 'doctype', 'comment', 'cdata', 'tag'] 63 | }, 64 | case_insensitive: true, 65 | modes: [ 66 | { 67 | className: 'cdata', 68 | begin: '<\\!\\[CDATA\\[', end: '\\]\\]>', 69 | relevance: 10 70 | }, 71 | PI, 72 | DOCTYPE, 73 | COMMENT, 74 | TAG, 75 | hljs.inherit(TITLE, {relevance: 1.75}), 76 | TAG_INTERNAL, 77 | ATTR, 78 | VALUE_CONTAINER_QUOT, 79 | VALUE_CONTAINER_APOS 80 | ] 81 | }; 82 | 83 | var HTML_TAGS = { 84 | 'code': 1, 'kbd': 1, 'font': 1, 'noscript': 1, 'style': 1, 'img': 1, 85 | 'title': 1, 'menu': 1, 'tt': 1, 'tr': 1, 'param': 1, 'li': 1, 'tfoot': 1, 86 | 'th': 1, 'input': 1, 'td': 1, 'dl': 1, 'blockquote': 1, 'fieldset': 1, 87 | 'big': 1, 'dd': 1, 'abbr': 1, 'optgroup': 1, 'dt': 1, 'button': 1, 88 | 'isindex': 1, 'p': 1, 'small': 1, 'div': 1, 'dir': 1, 'em': 1, 'frame': 1, 89 | 'meta': 1, 'sub': 1, 'bdo': 1, 'label': 1, 'acronym': 1, 'sup': 1, 'body': 1, 90 | 'basefont': 1, 'base': 1, 'br': 1, 'address': 1, 'strong': 1, 'legend': 1, 91 | 'ol': 1, 'script': 1, 'caption': 1, 's': 1, 'col': 1, 'h2': 1, 'h3': 1, 92 | 'h1': 1, 'h6': 1, 'h4': 1, 'h5': 1, 'table': 1, 'select': 1, 'noframes': 1, 93 | 'span': 1, 'area': 1, 'dfn': 1, 'strike': 1, 'cite': 1, 'thead': 1, 94 | 'head': 1, 'option': 1, 'form': 1, 'hr': 1, 'var': 1, 'link': 1, 'b': 1, 95 | 'colgroup': 1, 'ul': 1, 'applet': 1, 'del': 1, 'iframe': 1, 'pre': 1, 96 | 'frameset': 1, 'ins': 1, 'tbody': 1, 'html': 1, 'samp': 1, 'map': 1, 97 | 'object': 1, 'a': 1, 'xmlns': 1, 'center': 1, 'textarea': 1, 'i': 1, 'q': 1, 98 | 'u': 1, 'section': 1, 'nav': 1, 'article': 1, 'aside': 1, 'hgroup': 1, 99 | 'header': 1, 'footer': 1, 'figure': 1, 'figurecaption': 1, 'time': 1, 100 | 'mark': 1, 'wbr': 1, 'embed': 1, 'video': 1, 'audio': 1, 'source': 1, 101 | 'canvas': 1, 'datalist': 1, 'keygen': 1, 'output': 1, 'progress': 1, 102 | 'meter': 1, 'details': 1, 'summary': 1, 'command': 1 103 | }; 104 | 105 | hljs.LANGUAGES.html = { 106 | defaultMode: { 107 | contains: ['comment', 'pi', 'doctype', 'vbscript', 'tag'] 108 | }, 109 | case_insensitive: true, 110 | modes: [ 111 | { 112 | className: 'tag', 113 | begin: '', 114 | lexems: [hljs.IDENT_RE], keywords: {'style': 1}, 115 | contains: ['tag_internal'], 116 | starts: 'css' 117 | }, 118 | { 119 | className: 'tag', 120 | begin: '', 121 | lexems: [hljs.IDENT_RE], keywords: {'script': 1}, 122 | contains: ['tag_internal'], 123 | starts: 'javascript' 124 | }, 125 | { 126 | className: 'css', 127 | end: '', returnEnd: true, 128 | subLanguage: 'css' 129 | }, 130 | { 131 | className: 'javascript', 132 | end: '', returnEnd: true, 133 | subLanguage: 'javascript' 134 | }, 135 | { 136 | className: 'vbscript', 137 | begin: '<%', end: '%>', 138 | subLanguage: 'vbscript' 139 | }, 140 | COMMENT, 141 | PI, 142 | DOCTYPE, 143 | hljs.inherit(TAG), 144 | hljs.inherit(TITLE, { 145 | lexems: [hljs.IDENT_RE], keywords: HTML_TAGS 146 | }), 147 | hljs.inherit(TAG_INTERNAL), 148 | ATTR, 149 | VALUE_CONTAINER_QUOT, 150 | VALUE_CONTAINER_APOS, 151 | { 152 | className: 'value_container', 153 | begin: '=', end: hljs.IMMEDIATE_RE, 154 | contains: [ 155 | { 156 | className: 'unquoted_value', displayClassName: 'value', 157 | begin: '[^\\s/>]+', end: hljs.IMMEDIATE_RE 158 | } 159 | ] 160 | } 161 | ] 162 | }; 163 | 164 | })(); 165 | -------------------------------------------------------------------------------- /modules/highlight/ir_black.css: -------------------------------------------------------------------------------- 1 | /* 2 | IR_Black style (c) Vasily Mikhailitchenko 3 | */ 4 | 5 | pre code { 6 | display: block; padding: 0.5em; 7 | background: #000; color: #f8f8f8; 8 | } 9 | 10 | pre .shebang, 11 | pre .comment, 12 | pre .template_comment, 13 | pre .javadoc { 14 | color: #7c7c7c; 15 | } 16 | 17 | pre .keyword, 18 | pre .tag, 19 | pre .ruby .function .keyword, 20 | pre .tex .command { 21 | color: #96CBFE; 22 | } 23 | 24 | pre .function .keyword, 25 | pre .sub .keyword, 26 | pre .method, 27 | pre .list .title { 28 | color: #FFFFB6; 29 | } 30 | 31 | pre .string, 32 | pre .tag .value, 33 | pre .cdata, 34 | pre .filter .argument, 35 | pre .attr_selector, 36 | pre .apache .cbracket, 37 | pre .date { 38 | color: #A8FF60; 39 | } 40 | 41 | pre .subst { 42 | color: #DAEFA3; 43 | } 44 | 45 | pre .regexp { 46 | color: #E9C062; 47 | } 48 | 49 | pre .function .title, 50 | pre .sub .identifier, 51 | pre .pi, 52 | pre .decorator, 53 | pre .ini .title, 54 | pre .tex .special { 55 | color: #FFFFB6; 56 | } 57 | 58 | pre .class .title, 59 | pre .constant, 60 | pre .smalltalk .class, 61 | pre .javadoctag, 62 | pre .yardoctag, 63 | pre .phpdoc, 64 | pre .nginx .built_in { 65 | color: #FFFFB6; 66 | } 67 | 68 | pre .symbol, 69 | pre .ruby .symbol .string, 70 | pre .ruby .symbol .keyword, 71 | pre .ruby .symbol .keymethods, 72 | pre .number, 73 | pre .variable, 74 | pre .vbscript, 75 | pre .literal { 76 | color: #C6C5FE; 77 | } 78 | 79 | pre .css .keyword { 80 | color: #96CBFE; 81 | } 82 | 83 | pre .css .rule .keyword, 84 | pre .css .id { 85 | color: #FFFFB6; 86 | } 87 | 88 | pre .css .class { 89 | color: #FFF; 90 | } 91 | 92 | pre .hexcolor { 93 | color: #C6C5FE; 94 | } 95 | 96 | pre .number { 97 | color:#FF73FD; 98 | } 99 | 100 | pre .tex .formula { 101 | opacity: 0.7; 102 | } 103 | -------------------------------------------------------------------------------- /modules/highlight/javascript.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Javascript 3 | */ 4 | 5 | hljs.LANGUAGES.javascript = { 6 | defaultMode: { 7 | lexems: [hljs.UNDERSCORE_IDENT_RE], 8 | contains: ['string', 'comment', 'number', 'regexp_container', 'function'], 9 | keywords: { 10 | 'keyword': {'in': 1, 'if': 1, 'for': 1, 'while': 1, 'finally': 1, 'var': 1, 'new': 1, 'function': 1, 'do': 1, 'return': 1, 'void': 1, 'else': 1, 'break': 1, 'catch': 1, 'instanceof': 1, 'with': 1, 'throw': 1, 'case': 1, 'default': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'typeof': 1, 'delete': 1}, 11 | 'literal': {'true': 1, 'false': 1, 'null': 1} 12 | } 13 | }, 14 | modes: [ 15 | hljs.C_LINE_COMMENT_MODE, 16 | hljs.C_BLOCK_COMMENT_MODE, 17 | hljs.C_NUMBER_MODE, 18 | hljs.APOS_STRING_MODE, 19 | hljs.QUOTE_STRING_MODE, 20 | hljs.BACKSLASH_ESCAPE, 21 | { 22 | className: 'regexp_container', 23 | begin: '(' + hljs.RE_STARTERS_RE + '|case|return|throw)\\s*', end: hljs.IMMEDIATE_RE, noMarkup: true, 24 | lexems: [hljs.IDENT_RE], 25 | keywords: {'return': 1, 'throw': 1, 'case': 1}, 26 | contains: [ 27 | 'comment', 28 | { 29 | className: 'regexp', 30 | begin: '/.*?[^\\\\/]/[gim]*', end: hljs.IMMEDIATE_RE 31 | } 32 | ], 33 | relevance: 0 34 | }, 35 | { 36 | className: 'function', 37 | begin: '\\bfunction\\b', end: '{', 38 | lexems: [hljs.UNDERSCORE_IDENT_RE], 39 | keywords: {'function': 1}, 40 | contains: [ 41 | { 42 | className: 'title', 43 | begin: '[A-Za-z$_][0-9A-Za-z$_]*', end: hljs.IMMEDIATE_RE 44 | }, 45 | { 46 | className: 'params', 47 | begin: '\\(', end: '\\)', 48 | contains: ['string', 'comment'] 49 | } 50 | ] 51 | } 52 | ] 53 | }; 54 | -------------------------------------------------------------------------------- /modules/highlight/pow.highlight.js: -------------------------------------------------------------------------------- 1 | pow.module('highlight', function() { 2 | /*~highlight.js~*/ 3 | /*~javascript.js~*/ 4 | /*~html-xml.js~*/ 5 | var irBlackStyle = /*~ir_black.css~*/ 6 | pow.on.load(function() { 7 | pow.style.get('pow-highlight-style').innerHTML = irBlackStyle 8 | }) 9 | hljs.tabReplace = ' ' 10 | hljs.initHighlightingOnLoad() 11 | }) 12 | -------------------------------------------------------------------------------- /modules/live/pow.live.js: -------------------------------------------------------------------------------- 1 | pow.module('live', function() { 2 | /*~socket.io.js~*/ 3 | pow.live = {} 4 | pow.live.login = function(cb) { 5 | if (pow.live.token) { cb(pow.live.token) } 6 | 7 | var dialog = new pow.ui.Dialog(), 8 | iframe = document.createElement('iframe') 9 | iframe.src = pow.live.origin + '/authorize' 10 | iframe.style.cssText = 'width:100%; height:100%; border:none;' 11 | dialog.el.appendChild(iframe) 12 | window.addEventListener('message', function(e) { 13 | if (e.origin == pow.live.origin) { 14 | var msg = JSON.parse(e.data) 15 | if (msg.name == 'authorized') { 16 | pow.live.token = msg.token 17 | window.removeEventListener('message', arguments.callee, false) 18 | setTimeout(function() { 19 | dialog.close() 20 | }, 750) 21 | cb(msg.token) 22 | } 23 | } 24 | }, false) 25 | dialog.show() 26 | } 27 | pow.live.start = function() { 28 | var origin = pow.live.origin.split(/:\/\/|:/), 29 | socket = pow.live.socket = new io.Socket(origin[1], { 30 | port: origin[2], 31 | secure: true, 32 | resource: 'live', 33 | transports: ['xhr-polling', 'jsonp-polling'], 34 | rememberTransport: false 35 | }) 36 | socket.on('connect', function() { 37 | pow.log('pow.live connected.') 38 | if (pow.live.role == 'present') { 39 | pow.live.login(function(token) { 40 | pow.live.socket.send({ name:'authorize', token:token }) 41 | }) 42 | } else { 43 | pow.live.hud.show() 44 | } 45 | }) 46 | socket.on('message', function(msg) { 47 | pow.live.processing = true 48 | if (msg.name == 'authorized') { 49 | if (msg.success == true) { 50 | pow.live.hud.show() 51 | socket.send({ name:'slide', index:pow.slide.index }) 52 | } else { 53 | delete pow.live.token 54 | } 55 | } if (msg.name == 'slide') { 56 | pow.slides.go(msg.index) 57 | } 58 | pow.live.processing = false 59 | }) 60 | socket.on('disconnect', function(){}) 61 | 62 | pow.slides.on.show(function(slide) { 63 | if (pow.live.role == 'present' && !pow.live.processing) { 64 | socket.send({ name:'slide', index:slide.index }) 65 | } 66 | }) 67 | 68 | socket.connect() 69 | } 70 | pow.live.hud = {} 71 | pow.live.hud.fade = new pow.Animation(400, { 72 | frame: function(val) { pow.live.hud.el.style.opacity = .75 * val } 73 | }) 74 | pow.live.hud.show = function() { 75 | if (!this.el) { 76 | this.el = pow.el.replace('pow-live-hud', document.getElementById('slides')) 77 | pow.style.get('pow-live-style').innerHTML = '#pow-live-hud { border:.25em solid red; color:red; padding:0 .15em; font-family:sans-serif; font-size:30em; font-weight:bold; letter-spacing:-.05em; border-radius:.25em; position:absolute; right:1em; bottom:1em; }' 78 | this.el.textContent = 'LIVE' 79 | } 80 | this.fade.play() 81 | this.fade.on.finish.once(function() { 82 | setTimeout(function() { 83 | pow.live.hud.hide() 84 | }, 2000) 85 | }) 86 | } 87 | pow.live.hud.hide = function() { 88 | if (this.el) { 89 | this.fade.reverse() 90 | } 91 | } 92 | pow.live.load = pow.on.start(function() { 93 | var origin = pow.params.get('live') 94 | 95 | if (origin) { 96 | var role = 'view' 97 | data = origin.split('@') 98 | if (data.length == 2) { 99 | role = data[0] 100 | origin = data[1] 101 | } 102 | 103 | pow.live.origin = 'https://' + origin 104 | pow.live.role = role 105 | 106 | // FIXME: HACK: Wait until the window has finished loading to 107 | // prevent an infinite loading indicator. 108 | window.addEventListener('load', function() { 109 | setTimeout(function() { 110 | pow.live.start() 111 | }, 0) 112 | }, false) 113 | } 114 | }) 115 | }) 116 | -------------------------------------------------------------------------------- /modules/live/socket.io.js: -------------------------------------------------------------------------------- 1 | /** Socket.IO 0.6.2 - Built with build.js */ 2 | /** 3 | * Socket.IO client 4 | * 5 | * @author Guillermo Rauch 6 | * @license The MIT license. 7 | * @copyright Copyright (c) 2010 LearnBoost 8 | */ 9 | 10 | this.io = { 11 | version: '0.6.2', 12 | 13 | setPath: function(path){ 14 | if (window.console && console.error) console.error('io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf'); 15 | this.path = /\/$/.test(path) ? path : path + '/'; 16 | WEB_SOCKET_SWF_LOCATION = path + 'lib/vendor/web-socket-js/WebSocketMain.swf'; 17 | } 18 | }; 19 | 20 | if ('jQuery' in this) jQuery.io = this.io; 21 | 22 | if (typeof window != 'undefined'){ 23 | // WEB_SOCKET_SWF_LOCATION = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//cdn.socket.io/' + this.io.version + '/WebSocketMain.swf'; 24 | if (typeof WEB_SOCKET_SWF_LOCATION === 'undefined') 25 | WEB_SOCKET_SWF_LOCATION = '/socket.io/lib/vendor/web-socket-js/WebSocketMain.swf'; 26 | } 27 | 28 | /** 29 | * Socket.IO client 30 | * 31 | * @author Guillermo Rauch 32 | * @license The MIT license. 33 | * @copyright Copyright (c) 2010 LearnBoost 34 | */ 35 | 36 | (function(){ 37 | 38 | var _pageLoaded = false; 39 | 40 | io.util = { 41 | 42 | ios: false, 43 | 44 | load: function(fn){ 45 | if (/loaded|complete/.test(document.readyState) || _pageLoaded) return fn(); 46 | if ('attachEvent' in window){ 47 | window.attachEvent('onload', fn); 48 | } else { 49 | window.addEventListener('load', fn, false); 50 | } 51 | }, 52 | 53 | inherit: function(ctor, superCtor){ 54 | // no support for `instanceof` for now 55 | for (var i in superCtor.prototype){ 56 | ctor.prototype[i] = superCtor.prototype[i]; 57 | } 58 | }, 59 | 60 | indexOf: function(arr, item, from){ 61 | for (var l = arr.length, i = (from < 0) ? Math.max(0, l + from) : from || 0; i < l; i++){ 62 | if (arr[i] === item) return i; 63 | } 64 | return -1; 65 | }, 66 | 67 | isArray: function(obj){ 68 | return Object.prototype.toString.call(obj) === '[object Array]'; 69 | }, 70 | 71 | merge: function(target, additional){ 72 | for (var i in additional) 73 | if (additional.hasOwnProperty(i)) 74 | target[i] = additional[i]; 75 | } 76 | 77 | }; 78 | 79 | io.util.ios = /iphone|ipad/i.test(navigator.userAgent); 80 | io.util.android = /android/i.test(navigator.userAgent); 81 | io.util.opera = /opera/i.test(navigator.userAgent); 82 | 83 | io.util.load(function(){ 84 | _pageLoaded = true; 85 | }); 86 | 87 | })(); 88 | 89 | /** 90 | * Socket.IO client 91 | * 92 | * @author Guillermo Rauch 93 | * @license The MIT license. 94 | * @copyright Copyright (c) 2010 LearnBoost 95 | */ 96 | 97 | // abstract 98 | 99 | (function(){ 100 | 101 | var frame = '~m~', 102 | 103 | stringify = function(message){ 104 | if (Object.prototype.toString.call(message) == '[object Object]'){ 105 | if (!('JSON' in window)){ 106 | if ('console' in window && console.error) console.error('Trying to encode as JSON, but JSON.stringify is missing.'); 107 | return '{ "$error": "Invalid message" }'; 108 | } 109 | return '~j~' + JSON.stringify(message); 110 | } else { 111 | return String(message); 112 | } 113 | }; 114 | 115 | Transport = io.Transport = function(base, options){ 116 | this.base = base; 117 | this.options = { 118 | timeout: 15000 // based on heartbeat interval default 119 | }; 120 | io.util.merge(this.options, options); 121 | }; 122 | 123 | Transport.prototype.send = function(){ 124 | throw new Error('Missing send() implementation'); 125 | }; 126 | 127 | Transport.prototype.connect = function(){ 128 | throw new Error('Missing connect() implementation'); 129 | }; 130 | 131 | Transport.prototype.disconnect = function(){ 132 | throw new Error('Missing disconnect() implementation'); 133 | }; 134 | 135 | Transport.prototype._encode = function(messages){ 136 | var ret = '', message, 137 | messages = io.util.isArray(messages) ? messages : [messages]; 138 | for (var i = 0, l = messages.length; i < l; i++){ 139 | message = messages[i] === null || messages[i] === undefined ? '' : stringify(messages[i]); 140 | ret += frame + message.length + frame + message; 141 | } 142 | return ret; 143 | }; 144 | 145 | Transport.prototype._decode = function(data){ 146 | var messages = [], number, n; 147 | do { 148 | if (data.substr(0, 3) !== frame) return messages; 149 | data = data.substr(3); 150 | number = '', n = ''; 151 | for (var i = 0, l = data.length; i < l; i++){ 152 | n = Number(data.substr(i, 1)); 153 | if (data.substr(i, 1) == n){ 154 | number += n; 155 | } else { 156 | data = data.substr(number.length + frame.length); 157 | number = Number(number); 158 | break; 159 | } 160 | } 161 | messages.push(data.substr(0, number)); // here 162 | data = data.substr(number); 163 | } while(data !== ''); 164 | return messages; 165 | }; 166 | 167 | Transport.prototype._onData = function(data){ 168 | this._setTimeout(); 169 | var msgs = this._decode(data); 170 | if (msgs && msgs.length){ 171 | for (var i = 0, l = msgs.length; i < l; i++){ 172 | this._onMessage(msgs[i]); 173 | } 174 | } 175 | }; 176 | 177 | Transport.prototype._setTimeout = function(){ 178 | var self = this; 179 | if (this._timeout) clearTimeout(this._timeout); 180 | this._timeout = setTimeout(function(){ 181 | self._onTimeout(); 182 | }, this.options.timeout); 183 | }; 184 | 185 | Transport.prototype._onTimeout = function(){ 186 | this._onDisconnect(); 187 | }; 188 | 189 | Transport.prototype._onMessage = function(message){ 190 | if (!this.sessionid){ 191 | this.sessionid = message; 192 | this._onConnect(); 193 | } else if (message.substr(0, 3) == '~h~'){ 194 | this._onHeartbeat(message.substr(3)); 195 | } else if (message.substr(0, 3) == '~j~'){ 196 | this.base._onMessage(JSON.parse(message.substr(3))); 197 | } else { 198 | this.base._onMessage(message); 199 | } 200 | }, 201 | 202 | Transport.prototype._onHeartbeat = function(heartbeat){ 203 | this.send('~h~' + heartbeat); // echo 204 | }; 205 | 206 | Transport.prototype._onConnect = function(){ 207 | this.connected = true; 208 | this.connecting = false; 209 | this.base._onConnect(); 210 | this._setTimeout(); 211 | }; 212 | 213 | Transport.prototype._onDisconnect = function(){ 214 | this.connecting = false; 215 | this.connected = false; 216 | this.sessionid = null; 217 | this.base._onDisconnect(); 218 | }; 219 | 220 | Transport.prototype._prepareUrl = function(){ 221 | return (this.base.options.secure ? 'https' : 'http') 222 | + '://' + this.base.host 223 | + ':' + this.base.options.port 224 | + '/' + this.base.options.resource 225 | + '/' + this.type 226 | + (this.sessionid ? ('/' + this.sessionid) : '/'); 227 | }; 228 | 229 | })(); 230 | /** 231 | * Socket.IO client 232 | * 233 | * @author Guillermo Rauch 234 | * @license The MIT license. 235 | * @copyright Copyright (c) 2010 LearnBoost 236 | */ 237 | 238 | (function(){ 239 | 240 | var empty = new Function, 241 | 242 | XMLHttpRequestCORS = (function(){ 243 | if (!('XMLHttpRequest' in window)) return false; 244 | // CORS feature detection 245 | var a = new XMLHttpRequest(); 246 | return a.withCredentials != undefined; 247 | })(), 248 | 249 | request = function(xdomain){ 250 | if ('XDomainRequest' in window && xdomain) return new XDomainRequest(); 251 | if ('XMLHttpRequest' in window && (!xdomain || XMLHttpRequestCORS)) return new XMLHttpRequest(); 252 | if (!xdomain){ 253 | try { 254 | var a = new ActiveXObject('MSXML2.XMLHTTP'); 255 | return a; 256 | } catch(e){} 257 | 258 | try { 259 | var b = new ActiveXObject('Microsoft.XMLHTTP'); 260 | return b; 261 | } catch(e){} 262 | } 263 | return false; 264 | }, 265 | 266 | XHR = io.Transport.XHR = function(){ 267 | io.Transport.apply(this, arguments); 268 | this._sendBuffer = []; 269 | }; 270 | 271 | io.util.inherit(XHR, io.Transport); 272 | 273 | XHR.prototype.connect = function(){ 274 | this._get(); 275 | return this; 276 | }; 277 | 278 | XHR.prototype._checkSend = function(){ 279 | if (!this._posting && this._sendBuffer.length){ 280 | var encoded = this._encode(this._sendBuffer); 281 | this._sendBuffer = []; 282 | this._send(encoded); 283 | } 284 | }; 285 | 286 | XHR.prototype.send = function(data){ 287 | if (io.util.isArray(data)){ 288 | this._sendBuffer.push.apply(this._sendBuffer, data); 289 | } else { 290 | this._sendBuffer.push(data); 291 | } 292 | this._checkSend(); 293 | return this; 294 | }; 295 | 296 | XHR.prototype._send = function(data){ 297 | var self = this; 298 | this._posting = true; 299 | this._sendXhr = this._request('send', 'POST'); 300 | this._sendXhr.onreadystatechange = function(){ 301 | var status; 302 | if (self._sendXhr.readyState == 4){ 303 | self._sendXhr.onreadystatechange = empty; 304 | try { status = self._sendXhr.status; } catch(e){} 305 | self._posting = false; 306 | if (status == 200){ 307 | self._checkSend(); 308 | } else { 309 | self._onDisconnect(); 310 | } 311 | } 312 | }; 313 | this._sendXhr.send('data=' + encodeURIComponent(data)); 314 | }; 315 | 316 | XHR.prototype.disconnect = function(){ 317 | // send disconnection signal 318 | this._onDisconnect(); 319 | return this; 320 | }; 321 | 322 | XHR.prototype._onDisconnect = function(){ 323 | if (this._xhr){ 324 | this._xhr.onreadystatechange = empty; 325 | try { 326 | this._xhr.abort(); 327 | } catch(e){} 328 | this._xhr = null; 329 | } 330 | if (this._sendXhr){ 331 | this._sendXhr.onreadystatechange = empty; 332 | try { 333 | this._sendXhr.abort(); 334 | } catch(e){} 335 | this._sendXhr = null; 336 | } 337 | this._sendBuffer = []; 338 | io.Transport.prototype._onDisconnect.call(this); 339 | }; 340 | 341 | XHR.prototype._request = function(url, method, multipart){ 342 | var req = request(this.base._isXDomain()); 343 | if (multipart) req.multipart = true; 344 | req.open(method || 'GET', this._prepareUrl() + (url ? '/' + url : '')); 345 | if (method == 'POST' && 'setRequestHeader' in req){ 346 | req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=utf-8'); 347 | } 348 | return req; 349 | }; 350 | 351 | XHR.check = function(xdomain){ 352 | try { 353 | if (request(xdomain)) return true; 354 | } catch(e){} 355 | return false; 356 | }; 357 | 358 | XHR.xdomainCheck = function(){ 359 | return XHR.check(true); 360 | }; 361 | 362 | XHR.request = request; 363 | 364 | })(); 365 | 366 | /** 367 | * Socket.IO client 368 | * 369 | * @author Guillermo Rauch 370 | * @license The MIT license. 371 | * @copyright Copyright (c) 2010 LearnBoost 372 | */ 373 | 374 | (function(){ 375 | 376 | var WS = io.Transport.websocket = function(){ 377 | io.Transport.apply(this, arguments); 378 | }; 379 | 380 | io.util.inherit(WS, io.Transport); 381 | 382 | WS.prototype.type = 'websocket'; 383 | 384 | WS.prototype.connect = function(){ 385 | var self = this; 386 | this.socket = new WebSocket(this._prepareUrl()); 387 | this.socket.onmessage = function(ev){ self._onData(ev.data); }; 388 | this.socket.onclose = function(ev){ self._onClose(); }; 389 | this.socket.onerror = function(e){ self._onError(e); }; 390 | return this; 391 | }; 392 | 393 | WS.prototype.send = function(data){ 394 | if (this.socket) this.socket.send(this._encode(data)); 395 | return this; 396 | }; 397 | 398 | WS.prototype.disconnect = function(){ 399 | if (this.socket) this.socket.close(); 400 | return this; 401 | }; 402 | 403 | WS.prototype._onClose = function(){ 404 | this._onDisconnect(); 405 | return this; 406 | }; 407 | 408 | WS.prototype._onError = function(e){ 409 | this.base.emit('error', [e]); 410 | }; 411 | 412 | WS.prototype._prepareUrl = function(){ 413 | return (this.base.options.secure ? 'wss' : 'ws') 414 | + '://' + this.base.host 415 | + ':' + this.base.options.port 416 | + '/' + this.base.options.resource 417 | + '/' + this.type 418 | + (this.sessionid ? ('/' + this.sessionid) : ''); 419 | }; 420 | 421 | WS.check = function(){ 422 | // we make sure WebSocket is not confounded with a previously loaded flash WebSocket 423 | return 'WebSocket' in window && WebSocket.prototype && ( WebSocket.prototype.send && !!WebSocket.prototype.send.toString().match(/native/i)) && typeof WebSocket !== "undefined"; 424 | }; 425 | 426 | WS.xdomainCheck = function(){ 427 | return true; 428 | }; 429 | 430 | })(); 431 | 432 | /** 433 | * Socket.IO client 434 | * 435 | * @author Guillermo Rauch 436 | * @license The MIT license. 437 | * @copyright Copyright (c) 2010 LearnBoost 438 | */ 439 | 440 | (function(){ 441 | 442 | var Flashsocket = io.Transport.flashsocket = function(){ 443 | io.Transport.websocket.apply(this, arguments); 444 | }; 445 | 446 | io.util.inherit(Flashsocket, io.Transport.websocket); 447 | 448 | Flashsocket.prototype.type = 'flashsocket'; 449 | 450 | Flashsocket.prototype.connect = function(){ 451 | var self = this, args = arguments; 452 | WebSocket.__addTask(function(){ 453 | io.Transport.websocket.prototype.connect.apply(self, args); 454 | }); 455 | return this; 456 | }; 457 | 458 | Flashsocket.prototype.send = function(){ 459 | var self = this, args = arguments; 460 | WebSocket.__addTask(function(){ 461 | io.Transport.websocket.prototype.send.apply(self, args); 462 | }); 463 | return this; 464 | }; 465 | 466 | Flashsocket.check = function(){ 467 | if (typeof WebSocket == 'undefined' || !('__addTask' in WebSocket)) return false; 468 | if (io.util.opera) return false; // opera is buggy with this transport 469 | if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']){ 470 | return !!navigator.plugins['Shockwave Flash'].description; 471 | } 472 | if ('ActiveXObject' in window) { 473 | try { 474 | return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); 475 | } catch (e) {} 476 | } 477 | return false; 478 | }; 479 | 480 | Flashsocket.xdomainCheck = function(){ 481 | return true; 482 | }; 483 | 484 | })(); 485 | /** 486 | * Socket.IO client 487 | * 488 | * @author Guillermo Rauch 489 | * @license The MIT license. 490 | * @copyright Copyright (c) 2010 LearnBoost 491 | */ 492 | 493 | (function(){ 494 | 495 | var HTMLFile = io.Transport.htmlfile = function(){ 496 | io.Transport.XHR.apply(this, arguments); 497 | }; 498 | 499 | io.util.inherit(HTMLFile, io.Transport.XHR); 500 | 501 | HTMLFile.prototype.type = 'htmlfile'; 502 | 503 | HTMLFile.prototype._get = function(){ 504 | var self = this; 505 | this._open(); 506 | window.attachEvent('onunload', function(){ self._destroy(); }); 507 | }; 508 | 509 | HTMLFile.prototype._open = function(){ 510 | this._doc = new ActiveXObject('htmlfile'); 511 | this._doc.open(); 512 | this._doc.write(''); 513 | this._doc.parentWindow.s = this; 514 | this._doc.close(); 515 | 516 | var _iframeC = this._doc.createElement('div'); 517 | this._doc.body.appendChild(_iframeC); 518 | this._iframe = this._doc.createElement('iframe'); 519 | _iframeC.appendChild(this._iframe); 520 | this._iframe.src = this._prepareUrl() + '/' + (+ new Date); 521 | }; 522 | 523 | HTMLFile.prototype._ = function(data, doc){ 524 | this._onData(data); 525 | var script = doc.getElementsByTagName('script')[0]; 526 | script.parentNode.removeChild(script); 527 | }; 528 | 529 | HTMLFile.prototype._destroy = function(){ 530 | if (this._iframe){ 531 | this._iframe.src = 'about:blank'; 532 | this._doc = null; 533 | CollectGarbage(); 534 | } 535 | }; 536 | 537 | HTMLFile.prototype.disconnect = function(){ 538 | this._destroy(); 539 | return io.Transport.XHR.prototype.disconnect.call(this); 540 | }; 541 | 542 | HTMLFile.check = function(){ 543 | if ('ActiveXObject' in window){ 544 | try { 545 | var a = new ActiveXObject('htmlfile'); 546 | return a && io.Transport.XHR.check(); 547 | } catch(e){} 548 | } 549 | return false; 550 | }; 551 | 552 | HTMLFile.xdomainCheck = function(){ 553 | // we can probably do handling for sub-domains, we should test that it's cross domain but a subdomain here 554 | return false; 555 | }; 556 | 557 | })(); 558 | /** 559 | * Socket.IO client 560 | * 561 | * @author Guillermo Rauch 562 | * @license The MIT license. 563 | * @copyright Copyright (c) 2010 LearnBoost 564 | */ 565 | 566 | (function(){ 567 | 568 | var XHRMultipart = io.Transport['xhr-multipart'] = function(){ 569 | io.Transport.XHR.apply(this, arguments); 570 | }; 571 | 572 | io.util.inherit(XHRMultipart, io.Transport.XHR); 573 | 574 | XHRMultipart.prototype.type = 'xhr-multipart'; 575 | 576 | XHRMultipart.prototype._get = function(){ 577 | var self = this; 578 | this._xhr = this._request('', 'GET', true); 579 | this._xhr.onreadystatechange = function(){ 580 | if (self._xhr.readyState == 4) self._onData(self._xhr.responseText); 581 | }; 582 | this._xhr.send(null); 583 | }; 584 | 585 | XHRMultipart.check = function(){ 586 | return 'XMLHttpRequest' in window && 'prototype' in XMLHttpRequest && 'multipart' in XMLHttpRequest.prototype; 587 | }; 588 | 589 | XHRMultipart.xdomainCheck = function(){ 590 | return true; 591 | }; 592 | 593 | })(); 594 | 595 | /** 596 | * Socket.IO client 597 | * 598 | * @author Guillermo Rauch 599 | * @license The MIT license. 600 | * @copyright Copyright (c) 2010 LearnBoost 601 | */ 602 | 603 | (function(){ 604 | 605 | var empty = new Function(), 606 | 607 | XHRPolling = io.Transport['xhr-polling'] = function(){ 608 | io.Transport.XHR.apply(this, arguments); 609 | }; 610 | 611 | io.util.inherit(XHRPolling, io.Transport.XHR); 612 | 613 | XHRPolling.prototype.type = 'xhr-polling'; 614 | 615 | XHRPolling.prototype.connect = function(){ 616 | if (io.util.ios || io.util.android){ 617 | var self = this; 618 | io.util.load(function(){ 619 | setTimeout(function(){ 620 | io.Transport.XHR.prototype.connect.call(self); 621 | }, 10); 622 | }); 623 | } else { 624 | io.Transport.XHR.prototype.connect.call(this); 625 | } 626 | }; 627 | 628 | XHRPolling.prototype._get = function(){ 629 | var self = this; 630 | this._xhr = this._request(+ new Date, 'GET'); 631 | this._xhr.onreadystatechange = function(){ 632 | var status; 633 | if (self._xhr.readyState == 4){ 634 | self._xhr.onreadystatechange = empty; 635 | try { status = self._xhr.status; } catch(e){} 636 | if (status == 200){ 637 | self._onData(self._xhr.responseText); 638 | self._get(); 639 | } else { 640 | self._onDisconnect(); 641 | } 642 | } 643 | }; 644 | this._xhr.send(null); 645 | }; 646 | 647 | XHRPolling.check = function(){ 648 | return io.Transport.XHR.check(); 649 | }; 650 | 651 | XHRPolling.xdomainCheck = function(){ 652 | return io.Transport.XHR.xdomainCheck(); 653 | }; 654 | 655 | })(); 656 | 657 | /** 658 | * Socket.IO client 659 | * 660 | * @author Guillermo Rauch 661 | * @license The MIT license. 662 | * @copyright Copyright (c) 2010 LearnBoost 663 | */ 664 | 665 | io.JSONP = []; 666 | 667 | JSONPPolling = io.Transport['jsonp-polling'] = function(){ 668 | io.Transport.XHR.apply(this, arguments); 669 | this._insertAt = document.getElementsByTagName('script')[0]; 670 | this._index = io.JSONP.length; 671 | io.JSONP.push(this); 672 | }; 673 | 674 | io.util.inherit(JSONPPolling, io.Transport['xhr-polling']); 675 | 676 | JSONPPolling.prototype.type = 'jsonp-polling'; 677 | 678 | JSONPPolling.prototype._send = function(data){ 679 | var self = this; 680 | if (!('_form' in this)){ 681 | var form = document.createElement('FORM'), 682 | area = document.createElement('TEXTAREA'), 683 | id = this._iframeId = 'socket_io_iframe_' + this._index, 684 | iframe; 685 | 686 | form.style.position = 'absolute'; 687 | form.style.top = '-1000px'; 688 | form.style.left = '-1000px'; 689 | form.target = id; 690 | form.method = 'POST'; 691 | form.action = this._prepareUrl() + '/' + (+new Date) + '/' + this._index; 692 | area.name = 'data'; 693 | form.appendChild(area); 694 | this._insertAt.parentNode.insertBefore(form, this._insertAt); 695 | document.body.appendChild(form); 696 | 697 | this._form = form; 698 | this._area = area; 699 | } 700 | 701 | function complete(){ 702 | initIframe(); 703 | self._posting = false; 704 | self._checkSend(); 705 | }; 706 | 707 | function initIframe(){ 708 | if (self._iframe){ 709 | self._form.removeChild(self._iframe); 710 | } 711 | 712 | try { 713 | // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) 714 | iframe = document.createElement(' 63 | 64 |
65 |

Presentations can be .

66 |
67 |
68 | 90 |

Presentations can be simple.

91 |
92 |
93 |
94 |

This is .

95 | 96 |
97 |
98 |

What will you make with it?

99 |
100 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/pow.compat.js: -------------------------------------------------------------------------------- 1 | pow.module('compat', function() { 2 | pow.compat = {} 3 | pow.compat.good = true 4 | pow.compat.check = function() { 5 | if (!document.head) { 6 | document.head = document.getElementsByTagName('head')[0] 7 | pow.compat.good = false 8 | } 9 | 10 | // From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind 11 | if (!Function.prototype.bind) { 12 | Function.prototype.bind = function(obj) { 13 | var slice = [].slice, 14 | args = slice.call(arguments, 1), 15 | self = this, 16 | nop = function () {}, 17 | bound = function () { 18 | return self.apply(this instanceof nop ? this : ( obj || {} ), 19 | args.concat(slice.call(arguments))) 20 | } 21 | 22 | nop.prototype = self.prototype 23 | bound.prototype = new nop() 24 | return bound 25 | } 26 | pow.compat.good = false 27 | } 28 | 29 | // From Modernizr (http://www.modernizr.com/) 30 | var div = document.createElement('div') 31 | div.innerHTML = '' 32 | pow.compat.inlineSVG = (div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg' 33 | if (!pow.compat.inlineSVG) { 34 | pow.compat.good = false 35 | } 36 | } 37 | pow.compat.check() 38 | 39 | pow.compat.advise = function() { 40 | if (pow.compat.good) { return } 41 | 42 | if (window.localStorage) { 43 | if (window.localStorage.compatWarned) { 44 | return 45 | } else { 46 | window.localStorage.compatWarned = true 47 | } 48 | } 49 | 50 | var warning = new pow.ui.Dialog() 51 | warning.el.style.borderColor = "#cc0" 52 | warning.el.innerHTML = [ 53 | '

Warning: These slides require HTML5 features your browser does not support.

', 54 | '

Some things may not work properly in your current browser. For best goods, try the latest version of Chrome or Firefox 4.

', 55 | '

' 56 | ].join('\n') 57 | warning.el.getElementsByTagName('button')[0].onclick = function() { 58 | warning.close() 59 | } 60 | warning.show() 61 | } 62 | }) 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/pow.core.js: -------------------------------------------------------------------------------- 1 | pow.module('core', function() { 2 | pow.signal = function() { 3 | var handlers = [] 4 | function register(handler) { 5 | handlers.push(handler) 6 | return handler 7 | } 8 | register.fire = function() { 9 | for (var i = 0; i < handlers.length; i++) { 10 | handlers[i].apply(null, arguments) 11 | } 12 | } 13 | register.remove = function(handler) { 14 | handlers.splice(handlers.indexOf(handler), 1) 15 | } 16 | register.once = function(handler) { 17 | register(function() { 18 | handler.apply(null, arguments) 19 | register.remove(handler) 20 | }) 21 | } 22 | register.handlers = handlers 23 | return register 24 | } 25 | 26 | pow.on = {} 27 | pow.on.load = new pow.signal() // After DOM loading completes 28 | pow.on.start = new pow.signal() // After pow has initialized. 29 | // pow.on.cleanup -- for cleaning the dom prior to saves? 30 | 31 | pow.params = {} 32 | pow.params.data = {} 33 | pow.params.slide = 0 34 | pow.params.get = function(key) { 35 | return key == 'slide' ? this.slide : this.data[key] 36 | } 37 | pow.params.set = function(key, value) { 38 | if (key == 'slide') { 39 | this.slide = value 40 | } else { 41 | this.data[key] = value 42 | } 43 | this.save() 44 | } 45 | pow.params.save = function() { 46 | params = [] 47 | for (var key in this.data) { 48 | params.push(key+'='+this.data[key]) 49 | } 50 | if (this.slide != 0) { 51 | params.push(this.slide) 52 | } 53 | window.location.hash = params.join(',') 54 | } 55 | pow.params.load = pow.on.load(function() { 56 | window.location.hash.substr(1).split(',').forEach(function(param) { 57 | param = param.split('=') 58 | if (param.length == 1) { 59 | pow.params.slide = param[0] 60 | } else { 61 | pow.params.data[param[0]] = param[1] 62 | } 63 | }) 64 | }) 65 | 66 | // TODO: add IE support here 67 | window.addEventListener('DOMContentLoaded', function() { 68 | pow.compat.advise() 69 | pow.on.load.fire() 70 | pow.on.start.fire() 71 | }, false) 72 | }) 73 | -------------------------------------------------------------------------------- /src/pow.edit.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var style = pow.style.get('pow-edit') 3 | ;['h1', 'h2', 'li'].forEach(function(name) { 4 | style.innerHTML += 5 | '.slide[contenteditable=true] '+name+':hover { background: #eee; }' 6 | }) 7 | 8 | pow.slides.on.show(function(slide) { 9 | slide.el.setAttribute('contenteditable', 'true') 10 | }) 11 | 12 | pow.slides.on.hide(function(slide) { 13 | slide.el.removeAttribute('contenteditable') 14 | }) 15 | 16 | window.addEventListener('click', function(e) { 17 | if (e.target.isContentEditable) { 18 | e.stopPropagation() 19 | } 20 | }, true) 21 | })() 22 | -------------------------------------------------------------------------------- /src/pow.init.js: -------------------------------------------------------------------------------- 1 | // {POW!} 2 | 3 | pow = {} 4 | 5 | pow.log = function() { 6 | if ('console' in window && console.log && pow.log.enabled) { 7 | console.log.apply(console, arguments) 8 | } 9 | } 10 | pow.log.enabled = true 11 | pow.log('{POW!}') 12 | 13 | pow.module = function(name, run) { 14 | var moduleInfo = pow.module.info[name] || {version: -1}, 15 | loading = pow.module.loading 16 | 17 | if (loading && loading[name] <= moduleInfo.version) { return } 18 | pow.module.info[name] = {version: loading ? loading[name] : 'dev'} 19 | pow.log('Running module ['+name+'].') 20 | run() 21 | } 22 | pow.module.info = {} 23 | pow.updating = window.location.hash == '#update' 24 | pow.bundle = function(bundle) { 25 | function lastScript() { 26 | var scripts = document.getElementsByTagName('script') 27 | return scripts[scripts.length-1] 28 | } 29 | 30 | function runBundle() { 31 | pow.log('Running bundle {'+origin+'}.') 32 | pow.module.loading = bundle.versions 33 | eval(bundle.data) 34 | delete pow.module.loading 35 | } 36 | 37 | var script = lastScript(), 38 | origin = script.src || script.getAttribute('data-origin'), 39 | parent = script.parentNode 40 | 41 | if (script.hasAttribute('data-origin')) { 42 | if (pow.updating && !script.hasAttribute('data-loaded')) { 43 | pow.log('Updating bundle {'+origin+'}.') 44 | document.write('') 45 | var newScript = lastScript() 46 | newScript.addEventListener('load', function() { 47 | pow.log('Successfully updated bundle {'+origin+'}.') 48 | parent.removeChild(script) 49 | }, false) 50 | newScript.addEventListener('error', function() { 51 | pow.log('Failed to update bundle {'+origin+'}. Using local version.') 52 | parent.removeChild(newScript) 53 | runBundle() 54 | }, false) 55 | } else { 56 | runBundle() 57 | } 58 | script.removeAttribute('data-loaded') 59 | } else { 60 | pow.log('Inlining loaded bundle {'+origin+'}.') 61 | var inlineScript = document.createElement('script') 62 | inlineScript.innerHTML = bundle.wrap.replace('~b~', JSON.stringify(bundle)) 63 | inlineScript.setAttribute('data-origin', origin) 64 | inlineScript.setAttribute('data-loaded', true) 65 | parent.removeChild(script) 66 | parent.insertBefore(inlineScript, inlineScript.nextSibling) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/pow.nav.js: -------------------------------------------------------------------------------- 1 | pow.module('nav', function() { 2 | var icon = { 3 | first: '', 4 | prev: '', 5 | next: '', 6 | last: '' 7 | } 8 | 9 | navStyle = [ 10 | '#pow-nav { position:absolute; width:200px; height:70px; left:50%; line-height:0; margin-left:-100px; padding-top:20px; bottom:15px; opacity:0; '+pow.style.disableSelection()+'; }', 11 | '#pow-nav .nav { display:inline-block; width:48px; height:50px; }', 12 | '#pow-nav .nav, #pow-nav .status { margin:1px; background:rgba(0,0,0,.85); '+pow.style.shadow('0 3px 3px rgba(0,0,0,.5)')+'; }', 13 | '#pow-nav .nav:hover { background:rgba(0,0,0,.90); }', 14 | '#pow-nav .nav:active { background:rgba(0,0,0,1); }', 15 | '#pow-nav .nav .icon { display:block; margin:20%; width:60%; height:60%; }', 16 | '#pow-nav .nav.first { border-top-left-radius:10px; }', 17 | '#pow-nav .nav.last { border-top-right-radius:10px; }', 18 | '#pow-nav .status { height:20px; line-height:20px; text-align:center; color:#aaa; font-family:sans-serif; border-radius:0 0 10px 10px; }' 19 | ].join('\n') 20 | 21 | pow.nav = {} 22 | pow.nav.update = pow.slides.on.show(function() { 23 | pow.nav.statusEl.textContent = pow.slide.index+1 + ' / ' + pow.slides.length 24 | }) 25 | pow.nav.load = pow.on.load(function() { 26 | pow.style.get('pow-nav-style').innerHTML = navStyle 27 | 28 | var el = pow.nav.el = pow.el.replace('pow-nav') 29 | 30 | ;['first', 'prev', 'next', 'last'].forEach(function(name) { 31 | var button = document.createElement('div') 32 | button.className = 'nav '+name 33 | button.innerHTML = ''+icon[name]+'' 34 | button.addEventListener('click', function(e) { 35 | pow.slides.go[name]() 36 | e.stopPropagation() 37 | }, false) 38 | el.appendChild(button) 39 | }) 40 | 41 | var statusEl = pow.nav.statusEl = document.createElement('div') 42 | statusEl.className = 'status' 43 | el.appendChild(statusEl) 44 | 45 | var fade = new pow.Animation(250, { 46 | frame: function(val) { 47 | el.style.opacity = val 48 | } 49 | }) 50 | document.addEventListener('mousemove', function(e) { 51 | if (e.pageY > el.offsetTop) { 52 | fade.play() 53 | } else { 54 | fade.reverse() 55 | } 56 | }, true) 57 | document.addEventListener('mouseout', function(e) { 58 | if (!e.relatedTarget) { 59 | fade.reverse() 60 | } 61 | }, false) 62 | document.addEventListener('keydown', function(e) { 63 | var action = { 64 | 13: 'next', // Enter 65 | 32: 'next', // Space 66 | 37: 'prev', // Left 67 | 38: 'first', // Top 68 | 39: 'next', // Right 69 | 40: 'last' // Down 70 | }[e.keyCode] 71 | if (action) { pow.slides.go[action]() } 72 | }, false) 73 | }) 74 | }) 75 | -------------------------------------------------------------------------------- /src/pow.slides.js: -------------------------------------------------------------------------------- 1 | pow.module('slides', function() { 2 | pow.Animation = function(duration, args) { 3 | this.on = {} 4 | this.on.frame = new pow.signal() 5 | this.on.finish = new pow.signal() 6 | if (args.frame) { this.on.frame(args.frame) } 7 | if (args.finish) { this.on.finish(args.finish) } 8 | this.duration = duration 9 | this.elapsed = 0 10 | this.step = 1000/60 11 | } 12 | pow.Animation.prototype = { 13 | get finished() { 14 | return this.duration && (!this.reversed ? this.elapsed == this.duration : this.elapsed == 0) 15 | }, 16 | frame: function() { 17 | this.elapsed += this.step * (!this.reversed ? 1 : -1) 18 | this.elapsed = Math.min(Math.max(0, this.elapsed), this.duration) 19 | this.on.frame.fire(this.elapsed / this.duration) 20 | if (this.finished) { 21 | this.stop() 22 | } 23 | }, 24 | start: function() { 25 | if (this.interval || this.finished) { return } 26 | this.on.frame.fire(this.elapsed) 27 | this.interval = setInterval(this.frame.bind(this), this.step) 28 | }, 29 | stop: function() { 30 | if (this.interval) { 31 | clearInterval(this.interval) 32 | this.interval = null 33 | this.on.finish.fire() 34 | } 35 | }, 36 | play: function(reset) { 37 | if (reset) { this.elapsed = 0 } 38 | this.reversed = false 39 | this.start() 40 | }, 41 | reverse: function(reset) { 42 | if (reset) { this.elapsed = this.duration } 43 | this.reversed = true 44 | this.start() 45 | } 46 | } 47 | 48 | // Placeholder API during DOM load for scripting convenience. 49 | // This gets replaced with the current slide as soon as we have one. 50 | pow.slide = {} 51 | pow.slide.hide = function() {} 52 | pow.slide.on = {} 53 | pow.slide.on.load = function() {} 54 | pow.slide.on.show = function() {} 55 | pow.slide.on.hide = function() {} 56 | 57 | pow.Slide = function(index, el) { 58 | this.index = index 59 | this.el = el 60 | pow.el.removeClass(this.el, 'current') 61 | this._setup() 62 | } 63 | pow.Slide.prototype = { 64 | _setup: function() { 65 | this.on = {} 66 | this.on.load = new pow.signal() 67 | this.on.show = new pow.signal() 68 | this.on.hide = new pow.signal() 69 | 70 | var prevSlide = pow.slide 71 | pow.slide = this 72 | var scripts = this.el.getElementsByTagName('script') 73 | Array.prototype.forEach.call(scripts, function(script) { 74 | if (/^\s*pow\.slide\.on\.\w*\([\s\S]*\)\s*$/.test(script.innerHTML)) { 75 | eval(script.innerHTML) 76 | } 77 | }) 78 | 79 | this.on.load.fire(this) 80 | pow.slide = prevSlide 81 | }, 82 | show: function() { 83 | if (pow.slide == this) { return; } 84 | pow.slide.hide() 85 | pow.slide = this 86 | pow.el.addClass(this.el, 'current') 87 | pow.slides.on.show.fire(this) 88 | this.on.show.fire(this) 89 | }, 90 | hide: function() { 91 | pow.el.removeClass(this.el, 'current') 92 | this.on.hide.fire(this) 93 | pow.slides.on.hide.fire(this) 94 | }, 95 | get next() { 96 | return (this.index < pow.slides.length - 1) && pow.slides[this.index + 1] 97 | }, 98 | get prev() { 99 | return (this.index > 0) && pow.slides[this.index - 1] 100 | }, 101 | animate: function(duration, args) { 102 | var anim = new pow.Animation(duration, args) 103 | this.on.hide.once(anim.stop.bind(anim)) 104 | return anim 105 | } 106 | } 107 | 108 | pow.slides = [] 109 | pow.slides.on = {} 110 | pow.slides.on.show = new pow.signal() 111 | pow.slides.on.hide = new pow.signal() 112 | pow.slides.load = pow.on.load(function() { 113 | pow.slides.el = document.getElementById('slides') 114 | window.addEventListener('click', function(e) { 115 | if (e.target == document.documentElement 116 | || e.target == pow.slides.el 117 | || e.target.parentNode == pow.slides.el) 118 | { pow.slides.go.next() } 119 | }, false) 120 | 121 | var els = document.getElementsByClassName('slide') 122 | Array.prototype.forEach.call(els, function(el, index) { 123 | pow.slides.push(new pow.Slide(index, el)) 124 | }) 125 | }) 126 | 127 | pow.slides.go = function(index) { 128 | index = Number(index) || 0 129 | if (index < 0) { index += pow.slides.length } 130 | var slide = pow.slides[index] || pow.slides[0] 131 | slide.show() 132 | } 133 | pow.slides.go.first = function() { pow.slides.go(0) } 134 | pow.slides.go.last = function() { pow.slides.go(-1) } 135 | pow.slides.go.prev = function() { if (pow.slide.prev) { pow.slide.prev.show() } } 136 | pow.slides.go.next = function() { if (pow.slide.next) { pow.slide.next.show() } } 137 | 138 | pow.slides.style = {} 139 | pow.slides.style.base = [ 140 | 'html { cursor:none; }', 141 | 'body { margin:0; background:#111; }', 142 | '#slides { position:absolute; display:block; overflow:hidden; cursor:default; }', 143 | '.slide { background:#fff; border-radius:5px; }', 144 | '.slide { display:none; }', 145 | '.slide.current { display:table-cell; vertical-align:middle; }', 146 | '.slide h1, .slide h2 { text-align:center; margin:0; }', 147 | '.slide h1 { font-size:100em; }', 148 | '.slide h2 { font-size:48em; font-weight:normal; }', 149 | '.slide p, .slide > ul > li, .slide > ol > li { font-size:36em; }' 150 | ].join('\n') 151 | pow.slides.style.scale = function() { 152 | this.el = this.el || pow.style.get('pow-slide-scale-style') 153 | var width = Math.min(window.innerWidth, (4/3) * window.innerHeight) - 10, 154 | height = .75 * width - 10, 155 | padLeft = (window.innerWidth - width) / 2, 156 | padTop = (window.innerHeight - height) / 2, 157 | size = width / 800 158 | this.el.innerHTML = 159 | '#slides, .slide {' 160 | +' height:'+height.toFixed()+'px;' 161 | +' width:'+width.toFixed()+'px;' 162 | +'}\n' 163 | +'#slides {' 164 | +' left:'+padLeft+'px;' 165 | +' top:'+padTop+'px;' 166 | +' font-size:'+size.toFixed(4)+'px;' 167 | +' }\n' 168 | } 169 | pow.slides.style.load = pow.on.load(function() { 170 | pow.style.get('pow-slide-base-style').innerHTML = pow.slides.style.base 171 | pow.slides.style.scale() 172 | window.addEventListener('resize', function() { pow.slides.style.scale() }, false) 173 | }) 174 | 175 | pow.url = {} 176 | pow.url.update = pow.slides.on.show(function() { 177 | pow.params.set('slide', pow.slide.index) 178 | }) 179 | pow.url.read = pow.on.start(function() { 180 | pow.slides.go(pow.params.get('slide')) 181 | }) 182 | window.addEventListener('hashchange', pow.url.read, false) 183 | 184 | window.addEventListener('mouseover', function() { 185 | window.focus() 186 | }, false) 187 | }) 188 | -------------------------------------------------------------------------------- /src/pow.ui.js: -------------------------------------------------------------------------------- 1 | pow.module('ui', function() { 2 | pow.style = {} 3 | pow.style.get = function(styleId) { 4 | var el = document.getElementById(styleId) 5 | if (!el) { 6 | el = document.createElement('style') 7 | el.id = styleId 8 | document.head.insertBefore(el, document.getElementsByTagName('style')[0]) 9 | } 10 | return el 11 | } 12 | pow.style.shadow = function(spec) { 13 | return ['', '-webkit-', '-moz-'].map(function(prefix) { 14 | return prefix+'box-shadow: '+spec 15 | }).join('; ') 16 | } 17 | pow.style.disableSelection = function() { 18 | return ['', '-webkit-', '-moz-'].map(function(prefix) { 19 | return prefix+'user-select:none' 20 | }).join('; ') + '; cursor:default' 21 | } 22 | 23 | pow.el = {} 24 | pow.el.replace = function(elId, parentEl) { 25 | var el = document.getElementById(elId) 26 | if (el) { 27 | el.innerHTML = '' 28 | } else { 29 | el = document.createElement('div') 30 | el.id = elId 31 | ;(parentEl || document.body).appendChild(el) 32 | } 33 | return el 34 | } 35 | pow.el.addClass = function(el, className) { 36 | if (el.classList) { 37 | el.classList.add(className) 38 | } else { 39 | if (!~el.className.split(' ').indexOf(className)) { 40 | el.className += ' ' + className 41 | } 42 | } 43 | } 44 | pow.el.removeClass = function(el, className) { 45 | if (el.classList) { 46 | el.classList.remove(className) 47 | } else { 48 | var classes = el.className.split(' '), 49 | index = classes.indexOf(className) 50 | if (~index) { 51 | classes.splice(index, 1) 52 | } 53 | el.className = classes.join(' ') 54 | } 55 | } 56 | 57 | pow.Animation = function(duration, args) { 58 | this.on = {} 59 | this.on.frame = new pow.signal() 60 | this.on.finish = new pow.signal() 61 | if (args.frame) { this.on.frame(args.frame) } 62 | if (args.finish) { this.on.finish(args.finish) } 63 | this.duration = duration 64 | this.elapsed = 0 65 | this.step = 1000/60 66 | } 67 | pow.Animation.prototype = { 68 | get finished() { 69 | return this.duration && (!this.reversed ? this.elapsed == this.duration : this.elapsed == 0) 70 | }, 71 | frame: function() { 72 | this.elapsed += this.step * (!this.reversed ? 1 : -1) 73 | this.elapsed = Math.min(Math.max(0, this.elapsed), this.duration) 74 | this.on.frame.fire(this.elapsed / this.duration) 75 | if (this.finished) { 76 | this.stop() 77 | } 78 | }, 79 | start: function() { 80 | if (this.interval || this.finished) { return } 81 | this.on.frame.fire(this.elapsed) 82 | this.interval = setInterval(this.frame.bind(this), this.step) 83 | }, 84 | stop: function() { 85 | if (this.interval) { 86 | clearInterval(this.interval) 87 | this.interval = null 88 | this.on.finish.fire() 89 | } 90 | }, 91 | play: function(reset) { 92 | if (reset) { this.elapsed = 0 } 93 | this.reversed = false 94 | this.start() 95 | }, 96 | reverse: function(reset) { 97 | if (reset) { this.elapsed = this.duration } 98 | this.reversed = true 99 | this.start() 100 | } 101 | } 102 | 103 | pow.ui = {} 104 | pow.ui.mask = {} 105 | pow.ui.mask.show = function() { 106 | if (this.el) { return; } 107 | this.el = document.createElement('div') 108 | this.el.id = 'pow-mask' 109 | this.bg = document.createElement('div') 110 | this.bg.id = 'pow-mask-bg' 111 | this.el.appendChild(this.bg) 112 | document.body.appendChild(this.el) 113 | } 114 | pow.ui.mask.hide = function(cb) { 115 | if (!this.el) { return; } 116 | var self = this 117 | new pow.Animation(100, { 118 | frame: function(val) { 119 | self.el.style.opacity = val 120 | }, 121 | finish: function() { 122 | cb() 123 | self.el.parentNode.removeChild(self.el) 124 | self.el = null 125 | } 126 | }).reverse(true) 127 | } 128 | pow.ui.mask.style = [ 129 | '#pow-mask, .pow-dialog { cursor:default; }', 130 | '#pow-mask, #pow-mask-bg { position:absolute; top:0; left:0; bottom:0; right:0; z-index:998; }', 131 | '#pow-mask-bg { background:black; opacity:.5; }', 132 | '.pow-dialog { position:absolute; top:50%; height:22em; margin-top:-11.75em; left:50%; width:36em; margin-left:-18.75em; background:#111; border:.75em solid #ccc; font-family:sans-serif; color:white; z-index:999; }', 133 | '.pow-dialog h1, h2 { margin:1em; }', 134 | '.pow-dialog h1 { font-size:1.7em; }', 135 | '.pow-dialog h2 { font-size:1.5em; color:#aaa; }', 136 | '.pow-dialog a { color:white; }', 137 | '.pow-dialog p { text-align:center; margin-top:3em; }', 138 | '.pow-dialog button { font-size:20px; }' 139 | ].join('\n') 140 | pow.ui.mask.load = pow.on.load(function() { 141 | pow.style.get('pow-mask-style').innerHTML = pow.ui.mask.style 142 | }) 143 | 144 | pow.ui.Dialog = function() { 145 | this.el = document.createElement('div') 146 | this.el.className = 'pow-dialog' 147 | } 148 | pow.ui.Dialog.prototype = { 149 | show: function() { 150 | if (this.isShowing) { return } 151 | this.isShowing = true 152 | pow.ui.mask.show() 153 | pow.ui.mask.el.appendChild(this.el) 154 | }, 155 | close: function() { 156 | if (!this.isShowing) { return } 157 | var self = this 158 | pow.ui.mask.hide(function() { 159 | this.isShowing = false 160 | self.el.parentNode.removeChild(self.el) 161 | }) 162 | } 163 | } 164 | }) 165 | --------------------------------------------------------------------------------