From ca18093feafe501e9b4fa8c49a05d32dcd722b7d Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Mon, 5 May 2014 14:55:27 -0700 Subject: [PATCH] go.tools/cmd/present: add present tool LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/97030045 --- cmd/present/appengine.go | 24 ++ cmd/present/dir.go | 281 ++++++++++++++++ cmd/present/doc.go | 29 ++ cmd/present/js/jquery-ui.js | 6 + cmd/present/local.go | 122 +++++++ cmd/present/play.go | 43 +++ cmd/present/static/article.css | 136 ++++++++ cmd/present/static/dir.css | 186 +++++++++++ cmd/present/static/dir.js | 41 +++ cmd/present/static/favicon.ico | Bin 0 -> 785 bytes cmd/present/static/print.css | 51 +++ cmd/present/static/slides.js | 516 +++++++++++++++++++++++++++++ cmd/present/static/styles.css | 455 +++++++++++++++++++++++++ cmd/present/templates/action.tmpl | 46 +++ cmd/present/templates/article.tmpl | 58 ++++ cmd/present/templates/slides.tmpl | 58 ++++ 16 files changed, 2052 insertions(+) create mode 100644 cmd/present/appengine.go create mode 100644 cmd/present/dir.go create mode 100644 cmd/present/doc.go create mode 100644 cmd/present/js/jquery-ui.js create mode 100644 cmd/present/local.go create mode 100644 cmd/present/play.go create mode 100644 cmd/present/static/article.css create mode 100644 cmd/present/static/dir.css create mode 100644 cmd/present/static/dir.js create mode 100644 cmd/present/static/favicon.ico create mode 100644 cmd/present/static/print.css create mode 100644 cmd/present/static/slides.js create mode 100644 cmd/present/static/styles.css create mode 100644 cmd/present/templates/action.tmpl create mode 100644 cmd/present/templates/article.tmpl create mode 100644 cmd/present/templates/slides.tmpl diff --git a/cmd/present/appengine.go b/cmd/present/appengine.go new file mode 100644 index 00000000..20aa152e --- /dev/null +++ b/cmd/present/appengine.go @@ -0,0 +1,24 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +package main + +import ( + "code.google.com/p/go.tools/present" + + _ "code.google.com/p/go.tools/playground" +) + +var basePath = "./present/" + +func init() { + playScript(basePath, "HTTPTransport") + present.PlayEnabled = true +} + +func playable(c present.Code) bool { + return present.PlayEnabled && c.Play && c.Ext == ".go" +} diff --git a/cmd/present/dir.go b/cmd/present/dir.go new file mode 100644 index 00000000..a039f69d --- /dev/null +++ b/cmd/present/dir.go @@ -0,0 +1,281 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "html/template" + "io" + "log" + "net/http" + "os" + "path/filepath" + "sort" + + "code.google.com/p/go.tools/present" +) + +func init() { + http.HandleFunc("/", dirHandler) +} + +// dirHandler serves a directory listing for the requested path, rooted at basePath. +func dirHandler(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/favicon.ico" { + http.Error(w, "not found", 404) + return + } + const base = "." + name := filepath.Join(base, r.URL.Path) + if isDoc(name) { + err := renderDoc(w, basePath, name) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), 500) + } + return + } + if isDir, err := dirList(w, name); err != nil { + log.Println(err) + http.Error(w, err.Error(), 500) + return + } else if isDir { + return + } + http.FileServer(http.Dir(base)).ServeHTTP(w, r) +} + +// extensions maps the presentable file extensions to the name of the +// template to be executed. +var extensions = map[string]string{ + ".slide": "slides.tmpl", + ".article": "article.tmpl", +} + +func isDoc(path string) bool { + _, ok := extensions[filepath.Ext(path)] + return ok +} + +// renderDoc reads the present file, builds its template representation, +// and executes the template, sending output to w. +func renderDoc(w io.Writer, base, docFile string) error { + // Read the input and build the doc structure. + doc, err := parse(docFile, 0) + if err != nil { + return err + } + + // Find which template should be executed. + ext := filepath.Ext(docFile) + contentTmpl, ok := extensions[ext] + if !ok { + return fmt.Errorf("no template for extension %v", ext) + } + + // Locate the template file. + actionTmpl := filepath.Join(base, "templates/action.tmpl") + contentTmpl = filepath.Join(base, "templates", contentTmpl) + + // Read and parse the input. + tmpl := present.Template() + tmpl = tmpl.Funcs(template.FuncMap{"playable": playable}) + if _, err := tmpl.ParseFiles(actionTmpl, contentTmpl); err != nil { + return err + } + + // Execute the template. + return doc.Render(w, tmpl) +} + +func parse(name string, mode present.ParseMode) (*present.Doc, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + defer f.Close() + return present.Parse(f, name, 0) +} + +// dirList scans the given path and writes a directory listing to w. +// It parses the first part of each .slide file it encounters to display the +// presentation title in the listing. +// If the given path is not a directory, it returns (isDir == false, err == nil) +// and writes nothing to w. +func dirList(w io.Writer, name string) (isDir bool, err error) { + f, err := os.Open(name) + if err != nil { + return false, err + } + defer f.Close() + fi, err := f.Stat() + if err != nil { + return false, err + } + if isDir = fi.IsDir(); !isDir { + return false, nil + } + fis, err := f.Readdir(0) + if err != nil { + return false, err + } + d := &dirListData{Path: name} + for _, fi := range fis { + // skip the pkg directory + if name == "." && fi.Name() == "pkg" { + continue + } + e := dirEntry{ + Name: fi.Name(), + Path: filepath.ToSlash(filepath.Join(name, fi.Name())), + } + if fi.IsDir() && showDir(e.Name) { + d.Dirs = append(d.Dirs, e) + continue + } + if isDoc(e.Name) { + if p, err := parse(e.Path, present.TitlesOnly); err != nil { + log.Println(err) + } else { + e.Title = p.Title + } + switch filepath.Ext(e.Path) { + case ".article": + d.Articles = append(d.Articles, e) + case ".slide": + d.Slides = append(d.Slides, e) + } + } else if showFile(e.Name) { + d.Other = append(d.Other, e) + } + } + if d.Path == "." { + d.Path = "" + } + sort.Sort(d.Dirs) + sort.Sort(d.Slides) + sort.Sort(d.Articles) + sort.Sort(d.Other) + return true, dirListTemplate.Execute(w, d) +} + +// showFile reports whether the given file should be displayed in the list. +func showFile(n string) bool { + switch filepath.Ext(n) { + case ".pdf": + case ".html": + case ".go": + default: + return isDoc(n) + } + return true +} + +// showDir reports whether the given directory should be displayed in the list. +func showDir(n string) bool { + if len(n) > 0 && (n[0] == '.' || n[0] == '_') || n == "present" { + return false + } + return true +} + +type dirListData struct { + Path string + Dirs, Slides, Articles, Other dirEntrySlice +} + +type dirEntry struct { + Name, Path, Title string +} + +type dirEntrySlice []dirEntry + +func (s dirEntrySlice) Len() int { return len(s) } +func (s dirEntrySlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s dirEntrySlice) Less(i, j int) bool { return s[i].Name < s[j].Name } + +var dirListTemplate = template.Must(template.New("").Parse(dirListHTML)) + +const dirListHTML = ` + + + + Talks - The Go Programming Language + + + + + +
+ +
+ +

Go talks

+ + {{with .Path}}

{{.}}

{{end}} + + {{with .Articles}} +

Articles:

+
+ {{range .}} +
{{.Name}}: {{.Title}}
+ {{end}} +
+ {{end}} + + {{with .Slides}} +

Slide decks:

+
+ {{range .}} +
{{.Name}}: {{.Title}}
+ {{end}} +
+ {{end}} + + {{with .Other}} +

Files:

+
+ {{range .}} +
{{.Name}}
+ {{end}} +
+ {{end}} + + {{with .Dirs}} +

Sub-directories:

+
+ {{range .}} +
{{.Name}}
+ {{end}} +
+ {{end}} + +
+ + + + +` diff --git a/cmd/present/doc.go b/cmd/present/doc.go new file mode 100644 index 00000000..846a5317 --- /dev/null +++ b/cmd/present/doc.go @@ -0,0 +1,29 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Present displays slide presentations and articles. It runs a web server that +presents slide and article files from the current directory. + +It may be run as a stand-alone command or an App Engine app. +The stand-alone version permits the execution of programs from within a +presentation. The App Engine version does not provide this functionality. + +Usage of present: + -base="": base path for slide template and static resources + -http="127.0.0.1:3999": host:port to listen on + +You may use the app.yaml file provided in the root of the go.talks repository +to deploy present to App Engine: + appcfg.py update -A your-app-id -V your-app-version /path/to/go.talks + +Input files are named foo.extension, where "extension" defines the format of +the generated output. The supported formats are: + .slide // HTML5 slide presentation + .article // article format, such as a blog post + +The present file format is documented by the present package: +http://godoc.org/code.google.com/p/go.tools/present +*/ +package main diff --git a/cmd/present/js/jquery-ui.js b/cmd/present/js/jquery-ui.js new file mode 100644 index 00000000..f3919385 --- /dev/null +++ b/cmd/present/js/jquery-ui.js @@ -0,0 +1,6 @@ +/*! jQuery UI - v1.10.2 - 2013-03-20 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.resizable.js +* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ + +(function(e,t){function i(t,i){var a,n,r,o=t.nodeName.toLowerCase();return"area"===o?(a=t.parentNode,n=a.name,t.href&&n&&"map"===a.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&s(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var a=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var s,a,n=e(this[0]);n.length&&n[0]!==document;){if(s=n.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(a=parseInt(n.css("zIndex"),10),!isNaN(a)&&0!==a))return a;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++a)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var s=e.attr(t,"tabindex"),a=isNaN(s);return(a||s>=0)&&i(t,!a)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(i,s){function a(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===s?["Left","Right"]:["Top","Bottom"],r=s.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+s]=function(i){return i===t?o["inner"+s].call(this):this.each(function(){e(this).css(r,a(this,i)+"px")})},e.fn["outer"+s]=function(t,i){return"number"!=typeof t?o["outer"+s].call(this,t):this.each(function(){e(this).css(r,a(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,s){var a,n=e.ui[t].prototype;for(a in s)n.plugins[a]=n.plugins[a]||[],n.plugins[a].push([i,s[a]])},call:function(e,t,i){var s,a=e.plugins[t];if(a&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(s=0;a.length>s;s++)e.options[a[s][0]]&&a[s][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",a=!1;return t[s]>0?!0:(t[s]=1,a=t[s]>0,t[s]=0,a)}})})(jQuery);(function(e,t){var i=0,s=Array.prototype.slice,n=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(a){}n(t)},e.widget=function(i,s,n){var a,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],a=u+"-"+i,n||(n=s,s=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:n.version,_proto:e.extend({},n),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(n,function(i,n){return e.isFunction(n)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,a=this._superApply;return this._super=e,this._superApply=t,i=n.apply(this,arguments),this._super=s,this._superApply=a,i}}(),t):(l[i]=n,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:a}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var n,a,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(n in r[o])a=r[o][n],r[o].hasOwnProperty(n)&&a!==t&&(i[n]=e.isPlainObject(a)?e.isPlainObject(i[n])?e.widget.extend({},i[n],a):e.widget.extend({},a):a);return i},e.widget.bridge=function(i,n){var a=n.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,n=e.data(this,a);return n?e.isFunction(n[r])&&"_"!==r.charAt(0)?(s=n[r].apply(n,h),s!==n&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,a);t?t.option(r||{})._init():e.data(this,a,new n(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var n,a,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},n=i.split("."),i=n.shift(),n.length){for(a=o[i]=e.widget.extend({},this.options[i]),r=0;n.length-1>r;r++)a[n[r]]=a[n[r]]||{},a=a[n[r]];if(i=n.pop(),s===t)return a[i]===t?null:a[i];a[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var a,r=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=a=e(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,a=this.widget()),e.each(n,function(n,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=n.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?a.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var r,o=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),r=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),r&&e.effects&&e.effects.effect[o]?s[t](n):o!==t&&s[o]?s[o](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}})})(jQuery);(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(e){function t(e){return parseInt(e,10)||0}function i(e){return!isNaN(parseInt(e,10))}e.widget("ui.resizable",e.ui.mouse,{version:"1.10.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("
"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=e(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),e(this.handles[i]).length},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,a,o=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=t(this.helper.css("left")),n=t(this.helper.css("top")),o.containment&&(s+=e(o.containment).scrollLeft()||0,n+=e(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,a=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===a?this.axis+"-resize":a),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(t){var i,s=this.helper,n={},a=this.originalMousePosition,o=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,u=this.size.height,c=t.pageX-a.left||0,d=t.pageY-a.top||0,p=this._change[o];return p?(i=p.apply(this,[t,c,d]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==u&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(n)||this._trigger("resize",t,this.ui()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&e.ui.hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t,s,n,a,o,r=this.options;o={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||e)&&(t=o.minHeight*this.aspectRatio,n=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,a=o.maxWidth/this.aspectRatio,t>o.minWidth&&(o.minWidth=t),n>o.minHeight&&(o.minHeight=n),o.maxWidth>s&&(o.maxWidth=s),o.maxHeight>a&&(o.maxHeight=a)),this._vBoundaries=o},_updateCache:function(e){this.offset=this.helper.offset(),i(e.left)&&(this.position.left=e.left),i(e.top)&&(this.position.top=e.top),i(e.height)&&(this.size.height=e.height),i(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,s=this.size,n=this.axis;return i(e.height)?e.width=e.height*this.aspectRatio:i(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===n&&(e.left=t.left+(s.width-e.width),e.top=null),"nw"===n&&(e.top=t.top+(s.height-e.height),e.left=t.left+(s.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,s=this.axis,n=i(e.width)&&t.maxWidth&&t.maxWidthe.width,r=i(e.height)&&t.minHeight&&t.minHeight>e.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,u=/sw|nw|w/.test(s),c=/nw|ne|n/.test(s);return o&&(e.width=t.minWidth),r&&(e.height=t.minHeight),n&&(e.width=t.maxWidth),a&&(e.height=t.maxHeight),o&&u&&(e.left=h-t.minWidth),n&&u&&(e.left=h-t.maxWidth),r&&c&&(e.top=l-t.minHeight),a&&c&&(e.top=l-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var e,t,i,s,n,a=this.helper||this.element;for(e=0;this._proportionallyResizeElements.length>e;e++){if(n=this._proportionallyResizeElements[e],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],t=0;i.length>t;t++)this.borderDif[t]=(parseInt(i[t],10)||0)+(parseInt(s[t],10)||0);n.css({height:a.height()-this.borderDif[0]-this.borderDif[2]||0,width:a.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("
"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&e.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,a,o,r,h,l=e(this).data("ui-resizable"),u=l.options,c=l.element,d=u.containment,p=d instanceof e?d.get(0):/parent/.test(d)?c.parent().get(0):d;p&&(l.containerElement=e(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(i=e(p),s=[],e(["Top","Right","Left","Bottom"]).each(function(e,n){s[e]=t(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,a=l.containerSize.height,o=l.containerSize.width,r=e.ui.hasScroll(p,"left")?p.scrollWidth:o,h=e.ui.hasScroll(p)?p.scrollHeight:a,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(t){var i,s,n,a,o=e(this).data("ui-resizable"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,c={top:0,left:0},d=o.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(c=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-c.left),u&&(o.size.height=o.size.width/o.aspectRatio),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio),o.position.top=o._helper?h.top:0),o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top,i=Math.abs((o._helper?o.offset.left-c.left:o.offset.left-c.left)+o.sizeDiff.width),s=Math.abs((o._helper?o.offset.top-c.top:o.offset.top-h.top)+o.sizeDiff.height),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a&&(i-=o.parentData.left),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio))},stop:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=function(t){e(t).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)})},resize:function(t,i){var s=e(this).data("ui-resizable"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(t,s){e(t).each(function(){var t=e(this),n=e(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var i=(n[t]||0)+(r[t]||0);i&&i>=0&&(a[t]=i||null)}),t.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):e.each(n.alsoResize,function(e,t){h(e,t)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).data("ui-resizable");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).data("ui-resizable");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size,n=t.originalSize,a=t.originalPosition,o=t.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,u=Math.round((s.width-n.width)/h)*h,c=Math.round((s.height-n.height)/l)*l,d=n.width+u,p=n.height+c,f=i.maxWidth&&d>i.maxWidth,m=i.maxHeight&&p>i.maxHeight,g=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,g&&(d+=h),v&&(p+=l),f&&(d-=h),m&&(p-=l),/^(se|s|e)$/.test(o)?(t.size.width=d,t.size.height=p):/^(ne)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.top=a.top-c):/^(sw)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.left=a.left-u):(t.size.width=d,t.size.height=p,t.position.top=a.top-c,t.position.left=a.left-u)}})})(jQuery); \ No newline at end of file diff --git a/cmd/present/local.go b/cmd/present/local.go new file mode 100644 index 00000000..fdc265da --- /dev/null +++ b/cmd/present/local.go @@ -0,0 +1,122 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +package main + +import ( + "flag" + "fmt" + "go/build" + "log" + "net" + "net/http" + "net/url" + "os" + "runtime" + "strings" + + "code.google.com/p/go.tools/playground/socket" + "code.google.com/p/go.tools/present" +) + +const basePkg = "code.google.com/p/go.tools/cmd/present" + +var ( + basePath string + nativeClient bool +) + +func main() { + httpListen := flag.String("http", "127.0.0.1:3999", "host:port to listen on") + flag.StringVar(&basePath, "base", "", "base path for slide template and static resources") + flag.BoolVar(&present.PlayEnabled, "play", true, "enable playground (permit execution of arbitrary user code)") + flag.BoolVar(&nativeClient, "nacl", false, "use Native Client environment playground (prevents non-Go code execution)") + flag.Parse() + + if basePath == "" { + p, err := build.Default.Import(basePkg, "", build.FindOnly) + if err != nil { + fmt.Fprintf(os.Stderr, "Couldn't find gopresent files: %v\n", err) + fmt.Fprintf(os.Stderr, basePathMessage, basePkg) + os.Exit(1) + } + basePath = p.Dir + } + + if present.PlayEnabled { + if nativeClient { + socket.RunScripts = false + socket.Environ = func() []string { + if runtime.GOARCH == "amd64" { + return environ("GOOS=nacl", "GOARCH=amd64p32") + } + return environ("GOOS=nacl") + } + } + playScript(basePath, "SocketTransport") + + host, port, err := net.SplitHostPort(*httpListen) + if err != nil { + log.Fatal(err) + } + origin := &url.URL{Scheme: "http", Host: host + ":" + port} + http.Handle("/socket", socket.NewHandler(origin)) + } + http.Handle("/static/", http.FileServer(http.Dir(basePath))) + + if !strings.HasPrefix(*httpListen, "127.0.0.1") && + !strings.HasPrefix(*httpListen, "localhost") && + present.PlayEnabled && !nativeClient { + log.Print(localhostWarning) + } + + log.Printf("Open your web browser and visit http://%s/", *httpListen) + log.Fatal(http.ListenAndServe(*httpListen, nil)) +} + +func playable(c present.Code) bool { + return present.PlayEnabled && c.Play +} + +func environ(vars ...string) []string { + env := os.Environ() + for _, r := range vars { + k := strings.SplitAfter(r, "=")[0] + var found bool + for i, v := range env { + if strings.HasPrefix(v, k) { + env[i] = r + found = true + } + } + if !found { + env = append(env, r) + } + } + return env +} + +const basePathMessage = ` +By default, gopresent locates the slide template files and associated +static content by looking for a %q package +in your Go workspaces (GOPATH). + +You may use the -base flag to specify an alternate location. +` + +const localhostWarning = ` +WARNING! WARNING! WARNING! + +The present server appears to be listening on an address that is not localhost. +Anyone with access to this address and port will have access to this machine as +the user running present. + +To avoid this message, listen on localhost or run with -play=false. + +If you don't understand this message, hit Control-C to terminate this process. + +WARNING! WARNING! WARNING! +` diff --git a/cmd/present/play.go b/cmd/present/play.go new file mode 100644 index 00000000..d347e311 --- /dev/null +++ b/cmd/present/play.go @@ -0,0 +1,43 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "path/filepath" + "time" + + "code.google.com/p/go.tools/godoc/static" +) + +var scripts = []string{"jquery.js", "jquery-ui.js", "playground.js", "play.js"} + +// playScript registers an HTTP handler at /play.js that serves all the +// scripts specified by the variable above, and appends a line that +// initializes the playground with the specified transport. +func playScript(root, transport string) { + modTime := time.Now() + var buf bytes.Buffer + for _, p := range scripts { + if s, ok := static.Files[p]; ok { + buf.WriteString(s) + continue + } + b, err := ioutil.ReadFile(filepath.Join(root, "js", p)) + if err != nil { + panic(err) + } + buf.Write(b) + } + fmt.Fprintf(&buf, "\ninitPlayground(new %v());\n", transport) + b := buf.Bytes() + http.HandleFunc("/play.js", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-type", "application/javascript") + http.ServeContent(w, r, "", modTime, bytes.NewReader(b)) + }) +} diff --git a/cmd/present/static/article.css b/cmd/present/static/article.css new file mode 100644 index 00000000..e6ab1e84 --- /dev/null +++ b/cmd/present/static/article.css @@ -0,0 +1,136 @@ +body { + margin: 0; + font-family: Helvetica, Arial, sans-serif; + font-size: 16px; +} +pre, +code { + font-family: Menlo, monospace; + font-size: 14px; +} +pre { + line-height: 18px; + margin: 0; + padding: 0; +} +a { + color: #375EAB; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +p, ul, ol { + margin: 20px; +} + +h1, h2, h3, h4 { + margin: 20px 0; + padding: 0; + color: #375EAB; + font-weight: bold; +} +h1 { + font-size: 24px; +} +h2 { + font-size: 20px; + background: #E0EBF5; + padding: 2px 5px; +} +h3 { + font-size: 20px; +} +h3, h4 { + margin: 20px 5px; +} +h4 { + font-size: 16px; +} + +div#heading { + float: left; + margin: 0 0 10px 0; + padding: 21px 0; + font-size: 20px; + font-weight: normal; +} + +div#topbar { + background: #E0EBF5; + height: 64px; + overflow: hidden; +} + +body { + text-align: center; +} +div#page { + width: 100%; +} +div#page > .container, +div#topbar > .container { + text-align: left; + margin-left: auto; + margin-right: auto; + padding: 0 20px; + width: 900px; +} +div#page.wide > .container, +div#topbar.wide > .container { + width: auto; +} + +div#footer { + text-align: center; + color: #666; + font-size: 14px; + margin: 40px 0; +} + +.author p { + margin: 20, 0, 0, 0px; +} + +div.code, +div.output { + margin: 20px; + padding: 10px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +div.code { background: #e9e9e9; } +div.output { background: black; } +div.output .stdout { color: #e6e6e6; } +div.output .stderr { color: rgb(244, 74, 63); } +div.output .system { color: rgb(255, 209, 77) } + +.buttons { + margin-left: 20px; +} +div.output .buttons { + margin-left: 0; + margin-bottom: 10px; +} + +#toc { + float: right; + margin: 0px 10px; + padding: 10px; + border: 1px solid #e5ecf9; + background-color: white; + max-width: 33%; + + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +#toc ul, #toc a { + list-style-type: none; + padding-left: 10px; + color: black; + margin: 0px; +} diff --git a/cmd/present/static/dir.css b/cmd/present/static/dir.css new file mode 100644 index 00000000..97587e62 --- /dev/null +++ b/cmd/present/static/dir.css @@ -0,0 +1,186 @@ +/* copied from $GOROOT/doc/style.css */ + +body { + margin: 0; + font-family: Helvetica, Arial, sans-serif; + font-size: 16px; +} +pre, +code { + font-family: Menlo, monospace; + font-size: 14px; +} +pre { + line-height: 18px; +} +pre .comment { + color: #375EAB; +} +pre .highlight, +pre .highlight-comment, +pre .selection-highlight, +pre .selection-highlight-comment { + background: #FFFF00; +} +pre .selection, +pre .selection-comment { + background: #FF9632; +} +pre .ln { + color: #999; +} +body { + color: #222; +} +a, +.exampleHeading .text { + color: #375EAB; + text-decoration: none; +} +a:hover, +.exampleHeading .text:hover { + text-decoration: underline; +} +p, +pre, +ul, +ol { + margin: 20px; +} +pre { + background: #e9e9e9; + padding: 10px; + + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +h1, +h2, +h3, +h4, +.rootHeading { + margin: 20px 0; + padding: 0; + color: #375EAB; + font-weight: bold; +} +h1 { + font-size: 24px; +} +h2 { + font-size: 20px; + background: #E0EBF5; + padding: 2px 5px; +} +h3 { + font-size: 20px; +} +h3, +h4 { + margin: 20px 5px; +} +h4 { + font-size: 16px; +} + +dl { + margin: 20px; +} +dd { + margin: 2px 20px; +} +dl, +dd { + font-size: 14px; +} +div#nav table td { + vertical-align: top; +} + +div#heading { + float: left; + margin: 0 0 10px 0; + padding: 21px 0; + font-size: 20px; + font-weight: normal; +} +div#heading a { + color: #222; + text-decoration: none; +} + +div#topbar { + background: #E0EBF5; + height: 64px; +} + +body { + text-align: center; +} +div#page, +div#topbar > .container { + clear: both; + text-align: left; + margin-left: auto; + margin-right: auto; + padding: 0 20px; + width: 900px; +} +div#page.wide, +div#topbar > .wide { + width: auto; +} +div#plusone { + float: right; +} + +div#footer { + color: #666; + font-size: 14px; + margin: 40px 0; +} + +div#menu > a, +div#menu > input { + padding: 10px; + + text-decoration: none; + font-size: 16px; + + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +div#menu > a, +div#menu > input { + border: 1px solid #375EAB; +} +div#menu > a { + color: white; + background: #375EAB; +} + +div#menu { + float: right; + min-width: 590px; + padding: 10px 0; + text-align: right; +} +div#menu > a { + margin-right: 5px; + margin-bottom: 10px; + + padding: 10px; +} +div#menu > input { + position: relative; + top: 1px; + width: 60px; + background: white; + color: #222; +} +div#menu > input.inactive { + color: #999; +} diff --git a/cmd/present/static/dir.js b/cmd/present/static/dir.js new file mode 100644 index 00000000..5b0c37e5 --- /dev/null +++ b/cmd/present/static/dir.js @@ -0,0 +1,41 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// copied from $GOROOT/doc/godocs.js + +function bindEvent(el, e, fn) { + if (el.addEventListener){ + el.addEventListener(e, fn, false); + } else if (el.attachEvent){ + el.attachEvent('on'+e, fn); + } +} + +function godocs_bindSearchEvents() { + var search = document.getElementById('search'); + if (!search) { + // no search box (index disabled) + return; + } + function clearInactive() { + if (search.className == "inactive") { + search.value = ""; + search.className = ""; + } + } + function restoreInactive() { + if (search.value !== "") { + return; + } + if (search.type != "search") { + search.value = search.getAttribute("placeholder"); + } + search.className = "inactive"; + } + restoreInactive(); + bindEvent(search, 'focus', clearInactive); + bindEvent(search, 'blur', restoreInactive); +} + +bindEvent(window, 'load', godocs_bindSearchEvents); diff --git a/cmd/present/static/favicon.ico b/cmd/present/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..48854ff3b7225c8b4e8aa8a25754e1d0b7c77b6e GIT binary patch literal 785 zcmV+s1Md8ZP)5r00004XF*Lt007q5 z)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!qe(a@st@4BKo_oJPzw>?HIhVm0L#Ej6 zcCguOm(QI#dLysUSQM1xW#7b?WhI9coK{!icDucq@rulkmX=oZy1mWeXsEqpG#cQz z^?utRB)7Nn2_^KAYm5|#yEXazMjH4t8k!0_NeXY&iE#p@M7{5k^WvsIwt5X66u zgMz_u`%zcjR>QW&SS(65Ye^9(fMuCu1-f+|cW+i$cI({q=d?f-4KkbL8H||JduEK zWEsv^R+I=c^Vc^Q6f|YEz%UF)-b=4uIMaXYiY0$xaS0d}!L(ln-P#;bsW@OrfJ(`M zqjL}(Z9R?iQmBps*cDKe=-Au$LmfdmOt7Tycmj$y<|dN@QaA~tlBZF^f-Lp@sesL# z=v+{~^TgRR$*YtpDuIysfOkp+VMc;zEC#y#TrZp+NA%AD{$()=e}R z3@I8(`tF+qL{{dnWNKppLokAoTC?UfF*Tt`)9K%C@(KhS0IXFLXxD~r|ta@O^5g7&dyB3xG)uXH!$3b5r40` zx_Z)TwPycJf*@p8yGZo8%QIme`{s}EJpZ7(yZbY-h4gwoy>wZv{T5&Vs0a;<1LtDu P00000NkvXXu0mjff_q_+ literal 0 HcmV?d00001 diff --git a/cmd/present/static/print.css b/cmd/present/static/print.css new file mode 100644 index 00000000..6c582572 --- /dev/null +++ b/cmd/present/static/print.css @@ -0,0 +1,51 @@ +/* set page layout */ +@page { + size: A4 landscape; +} + +body { + display: block !important; +} + +.slides { + left: 0; + top: 0; +} + +.slides > article { + position: relative; + + left: 0; + top: 0; + + margin: 0 !important; + page-break-inside: avoid; + + text-shadow: none; /* disable shadow */ + + display: block !important; + transform: translate(0) !important; + -o-transform: translate(0) !important; + -moz-transform: translate(0) !important; + -webkit-transform: translate3d(0, 0, 0) !important; +} + +div.code { + background: rgb(240, 240, 240); +} + +/* hide click areas */ +.slide-area, #prev-slide-area, #next-slide-area { + display: none; +} + +/* add explicit links */ +a:link:after, a:visited:after { + content: " (" attr(href) ") "; + font-size: 50%; +} + +/* white background */ +body { + background: rgb(255,255,255) !important; +} diff --git a/cmd/present/static/slides.js b/cmd/present/static/slides.js new file mode 100644 index 00000000..489fb6bd --- /dev/null +++ b/cmd/present/static/slides.js @@ -0,0 +1,516 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +var PERMANENT_URL_PREFIX = '/static/'; + +var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next']; + +var PM_TOUCH_SENSITIVITY = 15; + +var curSlide; + +/* ---------------------------------------------------------------------- */ +/* classList polyfill by Eli Grey + * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */ + +if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) { + +(function (view) { + +var + classListProp = "classList" + , protoProp = "prototype" + , elemCtrProto = (view.HTMLElement || view.Element)[protoProp] + , objCtr = Object + strTrim = String[protoProp].trim || function () { + return this.replace(/^\s+|\s+$/g, ""); + } + , arrIndexOf = Array[protoProp].indexOf || function (item) { + for (var i = 0, len = this.length; i < len; i++) { + if (i in this && this[i] === item) { + return i; + } + } + return -1; + } + // Vendors: please allow content code to instantiate DOMExceptions + , DOMEx = function (type, message) { + this.name = type; + this.code = DOMException[type]; + this.message = message; + } + , checkTokenAndGetIndex = function (classList, token) { + if (token === "") { + throw new DOMEx( + "SYNTAX_ERR" + , "An invalid or illegal string was specified" + ); + } + if (/\s/.test(token)) { + throw new DOMEx( + "INVALID_CHARACTER_ERR" + , "String contains an invalid character" + ); + } + return arrIndexOf.call(classList, token); + } + , ClassList = function (elem) { + var + trimmedClasses = strTrim.call(elem.className) + , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [] + ; + for (var i = 0, len = classes.length; i < len; i++) { + this.push(classes[i]); + } + this._updateClassName = function () { + elem.className = this.toString(); + }; + } + , classListProto = ClassList[protoProp] = [] + , classListGetter = function () { + return new ClassList(this); + } +; +// Most DOMException implementations don't allow calling DOMException's toString() +// on non-DOMExceptions. Error's toString() is sufficient here. +DOMEx[protoProp] = Error[protoProp]; +classListProto.item = function (i) { + return this[i] || null; +}; +classListProto.contains = function (token) { + token += ""; + return checkTokenAndGetIndex(this, token) !== -1; +}; +classListProto.add = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.push(token); + this._updateClassName(); + } +}; +classListProto.remove = function (token) { + token += ""; + var index = checkTokenAndGetIndex(this, token); + if (index !== -1) { + this.splice(index, 1); + this._updateClassName(); + } +}; +classListProto.toggle = function (token) { + token += ""; + if (checkTokenAndGetIndex(this, token) === -1) { + this.add(token); + } else { + this.remove(token); + } +}; +classListProto.toString = function () { + return this.join(" "); +}; + +if (objCtr.defineProperty) { + var classListPropDesc = { + get: classListGetter + , enumerable: true + , configurable: true + }; + try { + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } catch (ex) { // IE 8 doesn't support enumerable:true + if (ex.number === -0x7FF5EC54) { + classListPropDesc.enumerable = false; + objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc); + } + } +} else if (objCtr[protoProp].__defineGetter__) { + elemCtrProto.__defineGetter__(classListProp, classListGetter); +} + +}(self)); + +} +/* ---------------------------------------------------------------------- */ + +/* Slide movement */ + +function getSlideEl(no) { + if ((no < 0) || (no >= slideEls.length)) { + return null; + } else { + return slideEls[no]; + } +}; + +function updateSlideClass(slideNo, className) { + var el = getSlideEl(slideNo); + + if (!el) { + return; + } + + if (className) { + el.classList.add(className); + } + + for (var i in SLIDE_CLASSES) { + if (className != SLIDE_CLASSES[i]) { + el.classList.remove(SLIDE_CLASSES[i]); + } + } +}; + +function updateSlides() { + for (var i = 0; i < slideEls.length; i++) { + switch (i) { + case curSlide - 2: + updateSlideClass(i, 'far-past'); + break; + case curSlide - 1: + updateSlideClass(i, 'past'); + break; + case curSlide: + updateSlideClass(i, 'current'); + break; + case curSlide + 1: + updateSlideClass(i, 'next'); + break; + case curSlide + 2: + updateSlideClass(i, 'far-next'); + break; + default: + updateSlideClass(i); + break; + } + } + + triggerLeaveEvent(curSlide - 1); + triggerEnterEvent(curSlide); + + window.setTimeout(function() { + // Hide after the slide + disableSlideFrames(curSlide - 2); + }, 301); + + enableSlideFrames(curSlide - 1); + enableSlideFrames(curSlide + 2); + + updateHash(); +}; + +function prevSlide() { + if (curSlide > 0) { + curSlide--; + + updateSlides(); + } +}; + +function nextSlide() { + if (curSlide < slideEls.length - 1) { + curSlide++; + + updateSlides(); + } +}; + +/* Slide events */ + +function triggerEnterEvent(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var onEnter = el.getAttribute('onslideenter'); + if (onEnter) { + new Function(onEnter).call(el); + } + + var evt = document.createEvent('Event'); + evt.initEvent('slideenter', true, true); + evt.slideNumber = no + 1; // Make it readable + + el.dispatchEvent(evt); +}; + +function triggerLeaveEvent(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var onLeave = el.getAttribute('onslideleave'); + if (onLeave) { + new Function(onLeave).call(el); + } + + var evt = document.createEvent('Event'); + evt.initEvent('slideleave', true, true); + evt.slideNumber = no + 1; // Make it readable + + el.dispatchEvent(evt); +}; + +/* Touch events */ + +function handleTouchStart(event) { + if (event.touches.length == 1) { + touchDX = 0; + touchDY = 0; + + touchStartX = event.touches[0].pageX; + touchStartY = event.touches[0].pageY; + + document.body.addEventListener('touchmove', handleTouchMove, true); + document.body.addEventListener('touchend', handleTouchEnd, true); + } +}; + +function handleTouchMove(event) { + if (event.touches.length > 1) { + cancelTouch(); + } else { + touchDX = event.touches[0].pageX - touchStartX; + touchDY = event.touches[0].pageY - touchStartY; + event.preventDefault(); + } +}; + +function handleTouchEnd(event) { + var dx = Math.abs(touchDX); + var dy = Math.abs(touchDY); + + if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) { + if (touchDX > 0) { + prevSlide(); + } else { + nextSlide(); + } + } + + cancelTouch(); +}; + +function cancelTouch() { + document.body.removeEventListener('touchmove', handleTouchMove, true); + document.body.removeEventListener('touchend', handleTouchEnd, true); +}; + +/* Preloading frames */ + +function disableSlideFrames(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var frames = el.getElementsByTagName('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + disableFrame(frame); + } +}; + +function enableSlideFrames(no) { + var el = getSlideEl(no); + if (!el) { + return; + } + + var frames = el.getElementsByTagName('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + enableFrame(frame); + } +}; + +function disableFrame(frame) { + frame.src = 'about:blank'; +}; + +function enableFrame(frame) { + var src = frame._src; + + if (frame.src != src && src != 'about:blank') { + frame.src = src; + } +}; + +function setupFrames() { + var frames = document.querySelectorAll('iframe'); + for (var i = 0, frame; frame = frames[i]; i++) { + frame._src = frame.src; + disableFrame(frame); + } + + enableSlideFrames(curSlide); + enableSlideFrames(curSlide + 1); + enableSlideFrames(curSlide + 2); +}; + +function setupInteraction() { + /* Clicking and tapping */ + + var el = document.createElement('div'); + el.className = 'slide-area'; + el.id = 'prev-slide-area'; + el.addEventListener('click', prevSlide, false); + document.querySelector('section.slides').appendChild(el); + + var el = document.createElement('div'); + el.className = 'slide-area'; + el.id = 'next-slide-area'; + el.addEventListener('click', nextSlide, false); + document.querySelector('section.slides').appendChild(el); + + /* Swiping */ + + document.body.addEventListener('touchstart', handleTouchStart, false); +} + +/* Hash functions */ + +function getCurSlideFromHash() { + var slideNo = parseInt(location.hash.substr(1)); + + if (slideNo) { + curSlide = slideNo - 1; + } else { + curSlide = 0; + } +}; + +function updateHash() { + location.replace('#' + (curSlide + 1)); +}; + +/* Event listeners */ + +function handleBodyKeyDown(event) { + // If we're in a code element, only handle pgup/down. + var inCode = event.target.classList.contains("code"); + + switch (event.keyCode) { + case 39: // right arrow + case 13: // Enter + case 32: // space + if (inCode) break; + case 34: // PgDn + nextSlide(); + event.preventDefault(); + break; + + case 37: // left arrow + case 8: // Backspace + if (inCode) break; + case 33: // PgUp + prevSlide(); + event.preventDefault(); + break; + + case 40: // down arrow + if (inCode) break; + nextSlide(); + event.preventDefault(); + break; + + case 38: // up arrow + if (inCode) break; + prevSlide(); + event.preventDefault(); + break; + } +}; + +function addEventListeners() { + document.addEventListener('keydown', handleBodyKeyDown, false); +}; + +/* Initialization */ + +function addFontStyle() { + var el = document.createElement('link'); + el.rel = 'stylesheet'; + el.type = 'text/css'; + el.href = '//fonts.googleapis.com/css?family=' + + 'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono'; + + document.body.appendChild(el); +}; + +function addGeneralStyle() { + var el = document.createElement('link'); + el.rel = 'stylesheet'; + el.type = 'text/css'; + el.href = PERMANENT_URL_PREFIX + 'styles.css'; + document.body.appendChild(el); + + var el = document.createElement('meta'); + el.name = 'viewport'; + el.content = 'width=1100,height=750'; + document.querySelector('head').appendChild(el); + + var el = document.createElement('meta'); + el.name = 'apple-mobile-web-app-capable'; + el.content = 'yes'; + document.querySelector('head').appendChild(el); +}; + +function addPrintStyle() { + var el = document.createElement('link'); + el.rel = 'stylesheet'; + el.type = 'text/css'; + el.media = "print"; + el.href = PERMANENT_URL_PREFIX + 'print.css'; + document.body.appendChild(el); +}; + +function handleDomLoaded() { + slideEls = document.querySelectorAll('section.slides > article'); + + setupFrames(); + + addFontStyle(); + addGeneralStyle(); + addPrintStyle(); + addEventListeners(); + + updateSlides(); + + setupInteraction(); + + document.body.classList.add('loaded'); +}; + +function initialize() { + getCurSlideFromHash(); + + if (window['_DEBUG']) { + PERMANENT_URL_PREFIX = '../'; + } + + if (window['_DCL']) { + handleDomLoaded(); + } else { + document.addEventListener('DOMContentLoaded', handleDomLoaded, false); + } +} + +// If ?debug exists then load the script relative instead of absolute +if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) { + document.addEventListener('DOMContentLoaded', function() { + // Avoid missing the DomContentLoaded event + window['_DCL'] = true + }, false); + + window['_DEBUG'] = true; + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = '../slides.js'; + var s = document.getElementsByTagName('script')[0]; + s.parentNode.insertBefore(script, s); + + // Remove this script + s.parentNode.removeChild(s); +} else { + initialize(); +} diff --git a/cmd/present/static/styles.css b/cmd/present/static/styles.css new file mode 100644 index 00000000..adaa9f67 --- /dev/null +++ b/cmd/present/static/styles.css @@ -0,0 +1,455 @@ +/* Framework */ + +html { + height: 100%; +} + +body { + margin: 0; + padding: 0; + + display: block !important; + + height: 100%; + min-height: 740px; + + overflow-x: hidden; + overflow-y: auto; + + background: rgb(215, 215, 215); + background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190)); + background: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(240, 240, 240)), to(rgb(190, 190, 190))); + + -webkit-font-smoothing: antialiased; +} + +.slides { + width: 100%; + height: 100%; + left: 0; + top: 0; + + position: absolute; + + -webkit-transform: translate3d(0, 0, 0); +} + +.slides > article { + display: block; + + position: absolute; + overflow: hidden; + + width: 900px; + height: 700px; + + left: 50%; + top: 50%; + + margin-left: -450px; + margin-top: -350px; + + padding: 40px 60px; + + box-sizing: border-box; + -o-box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + + background-color: white; + + border: 1px solid rgba(0, 0, 0, .3); + + /* + transition: transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + -moz-transition: -moz-transform .3s ease-out; + -webkit-transition: -webkit-transform .3s ease-out; + */ +} +.slides.layout-widescreen > article { + margin-left: -550px; + width: 1100px; +} +.slides.layout-faux-widescreen > article { + margin-left: -550px; + width: 1100px; + + padding: 40px 160px; +} + +.slides.layout-widescreen > article:not(.nobackground):not(.biglogo), +.slides.layout-faux-widescreen > article:not(.nobackground):not(.biglogo) { + background-position-x: 0, 840px; +} + +/* Clickable/tappable areas */ + +.slide-area { + z-index: 1000; + + position: absolute; + left: 0; + top: 0; + width: 150px; + height: 700px; + + left: 50%; + top: 50%; + + cursor: pointer; + margin-top: -350px; + + tap-highlight-color: transparent; + -o-tap-highlight-color: transparent; + -moz-tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; +} +#prev-slide-area { + margin-left: -550px; +} +#next-slide-area { + margin-left: 400px; +} +.slides.layout-widescreen #prev-slide-area, +.slides.layout-faux-widescreen #prev-slide-area { + margin-left: -650px; +} +.slides.layout-widescreen #next-slide-area, +.slides.layout-faux-widescreen #next-slide-area { + margin-left: 500px; +} + +/* Slides */ + +.slides > article { + display: none; +} +.slides > article.far-past { + display: block; + transform: translate(-2040px); + -o-transform: translate(-2040px); + -moz-transform: translate(-2040px); + -webkit-transform: translate3d(-2040px, 0, 0); +} +.slides > article.past { + display: block; + transform: translate(-1020px); + -o-transform: translate(-1020px); + -moz-transform: translate(-1020px); + -webkit-transform: translate3d(-1020px, 0, 0); +} +.slides > article.current { + display: block; + transform: translate(0); + -o-transform: translate(0); + -moz-transform: translate(0); + -webkit-transform: translate3d(0, 0, 0); +} +.slides > article.next { + display: block; + transform: translate(1020px); + -o-transform: translate(1020px); + -moz-transform: translate(1020px); + -webkit-transform: translate3d(1020px, 0, 0); +} +.slides > article.far-next { + display: block; + transform: translate(2040px); + -o-transform: translate(2040px); + -moz-transform: translate(2040px); + -webkit-transform: translate3d(2040px, 0, 0); +} + +.slides.layout-widescreen > article.far-past, +.slides.layout-faux-widescreen > article.far-past { + display: block; + transform: translate(-2260px); + -o-transform: translate(-2260px); + -moz-transform: translate(-2260px); + -webkit-transform: translate3d(-2260px, 0, 0); +} +.slides.layout-widescreen > article.past, +.slides.layout-faux-widescreen > article.past { + display: block; + transform: translate(-1130px); + -o-transform: translate(-1130px); + -moz-transform: translate(-1130px); + -webkit-transform: translate3d(-1130px, 0, 0); +} +.slides.layout-widescreen > article.current, +.slides.layout-faux-widescreen > article.current { + display: block; + transform: translate(0); + -o-transform: translate(0); + -moz-transform: translate(0); + -webkit-transform: translate3d(0, 0, 0); +} +.slides.layout-widescreen > article.next, +.slides.layout-faux-widescreen > article.next { + display: block; + transform: translate(1130px); + -o-transform: translate(1130px); + -moz-transform: translate(1130px); + -webkit-transform: translate3d(1130px, 0, 0); +} +.slides.layout-widescreen > article.far-next, +.slides.layout-faux-widescreen > article.far-next { + display: block; + transform: translate(2260px); + -o-transform: translate(2260px); + -moz-transform: translate(2260px); + -webkit-transform: translate3d(2260px, 0, 0); +} + +/* Styles for slides */ + +.slides > article { + font-family: 'Open Sans', Arial, sans-serif; + + color: black; + text-shadow: 0 1px 1px rgba(0, 0, 0, .1); + + font-size: 26px; + line-height: 36px; + + letter-spacing: -1px; +} + +b { + font-weight: 600; +} + +a { + color: rgb(0, 102, 204); + text-decoration: none; +} +a:visited { + color: rgba(0, 102, 204, .75); +} +a:hover { + color: black; +} + +p { + margin: 0; + padding: 0; + + margin-top: 20px; +} +p:first-child { + margin-top: 0; +} + +h1 { + font-size: 60px; + line-height: 60px; + + padding: 0; + margin: 0; + margin-top: 200px; + margin-bottom: 5px; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -3px; + + color: rgb(51, 51, 51); +} + +h2 { + font-size: 45px; + line-height: 45px; + + position: absolute; + bottom: 150px; + + padding: 0; + margin: 0; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -2px; + + color: rgb(51, 51, 51); +} + +h3 { + font-size: 30px; + line-height: 36px; + + padding: 0; + margin: 0; + padding-right: 40px; + + font-weight: 600; + + letter-spacing: -1px; + + color: rgb(51, 51, 51); +} + +ul { + margin: 0; + padding: 0; + margin-top: 20px; + margin-left: 1.5em; +} +li { + padding: 0; + margin: 0 0 .5em 0; +} + +div.code { + padding: 5px 10px; + margin-top: 20px; + margin-bottom: 20px; + overflow: hidden; + + background: rgb(240, 240, 240); + border: 1px solid rgb(224, 224, 224); +} +pre { + margin: 0; + padding: 0; + + font-family: 'Droid Sans Mono', 'Courier New', monospace; + font-size: 18px; + line-height: 24px; + letter-spacing: -1px; + + color: black; +} + +code { + font-size: 95%; + font-family: 'Droid Sans Mono', 'Courier New', monospace; + + color: black; +} + +article > .image { + text-align: center; + margin-top: 40px; +} + +table { + width: 100%; + border-collapse: collapse; + margin-top: 40px; +} +th { + font-weight: 600; + text-align: left; +} +td, +th { + border: 1px solid rgb(224, 224, 224); + padding: 5px 10px; + vertical-align: top; +} + +p.link { + margin-left: 20px; +} + +/* Code */ +div.code { + outline: 0px solid transparent; +} +div.playground { + position: relative; +} +div.output { + position: absolute; + left: 50%; + top: 50%; + right: 40px; + bottom: 40px; + background: #202020; + padding: 5px 10px; + z-index: 2; + + border-radius: 10px; + -o-border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + +} +div.output pre { + margin: 0; + padding: 0; + background: none; + border: none; + width: 100%; + height: 100%; + overflow: auto; +} +div.output .stdout, div.output pre { + color: #e6e6e6; +} +div.output .stderr, div.output .error { + color: rgb(255, 200, 200); +} +div.output .system, div.output .exit { + color: rgb(255, 230, 120) +} +.buttons { + position: relative; + float: right; + top: -60px; + right: 10px; +} +div.output .buttons { + position: absolute; + float: none; + top: auto; + right: 5px; + bottom: 5px; +} + +/* Presenter details */ +.presenter { + margin-top: 20px; +} +.presenter p, +.presenter .link { + margin: 0; + font-size: 28px; + line-height: 1.2em; +} + +/* Output resize details */ +.ui-resizable-handle { + position: absolute; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} diff --git a/cmd/present/templates/action.tmpl b/cmd/present/templates/action.tmpl new file mode 100644 index 00000000..1fa0073b --- /dev/null +++ b/cmd/present/templates/action.tmpl @@ -0,0 +1,46 @@ +{/* +This is the action template. +It determines how the formatting actions are rendered. +*/} + +{{define "section"}} + {{.FormattedNumber}} {{.Title}} + {{range .Elem}}{{elem $.Template .}}{{end}} +{{end}} + +{{define "list"}} +
    + {{range .Bullet}} +
  • {{style .}}
  • + {{end}} +
+{{end}} + +{{define "text"}} + {{if .Pre}} +
{{range .Lines}}{{.}}{{end}}
+ {{else}} +

+ {{range $i, $l := .Lines}}{{if $i}}{{template "newline"}} + {{end}}{{style $l}}{{end}} +

+ {{end}} +{{end}} + +{{define "code"}} +
{{.Text}}
+{{end}} + +{{define "image"}} +
+ +
+{{end}} + +{{define "iframe"}} + +{{end}} + +{{define "link"}}
{{end}} + +{{define "html"}}{{.HTML}}{{end}} diff --git a/cmd/present/templates/article.tmpl b/cmd/present/templates/article.tmpl new file mode 100644 index 00000000..40d1c936 --- /dev/null +++ b/cmd/present/templates/article.tmpl @@ -0,0 +1,58 @@ +{/* This is the article template. It defines how articles are formatted. */} + +{{define "root"}} + + + + {{.Title}} + + + + + +
+
+
{{.Title}} + {{with .Subtitle}}{{.}}{{end}} +
+
+
+
+
+ {{with .Sections}} +
+ {{template "TOC" .}} +
+ {{end}} + + {{range .Sections}} + {{elem $.Template .}} + {{end}}{{/* of Section block */}} + + {{if .Authors}} +

Authors

+ {{range .Authors}} +
+ {{range .Elem}}{{elem $.Template .}}{{end}} +
+ {{end}} + {{end}} +
+
+ + + +{{end}} + +{{define "TOC"}} + +{{end}} + +{{define "newline"}} +{{/* No automatic line break. Paragraphs are free-form. */}} +{{end}} diff --git a/cmd/present/templates/slides.tmpl b/cmd/present/templates/slides.tmpl new file mode 100644 index 00000000..d2abfa18 --- /dev/null +++ b/cmd/present/templates/slides.tmpl @@ -0,0 +1,58 @@ +{/* This is the slide template. It defines how presentations are formatted. */} + +{{define "root"}} + + + + {{.Title}} + + + + + + +
+ +
+

{{.Title}}

+ {{with .Subtitle}}

{{.}}

{{end}} + {{if not .Time.IsZero}}

{{.Time.Format "2 January 2006"}}

{{end}} + {{range .Authors}} +
+ {{range .TextElem}}{{elem $.Template .}}{{end}} +
+ {{end}} +
+ + {{range $i, $s := .Sections}} + +
+ {{if $s.Elem}} +

{{$s.Title}}

+ {{range $s.Elem}}{{elem $.Template .}}{{end}} + {{else}} +

{{$s.Title}}

+ {{end}} +
+ + {{end}}{{/* of Slide block */}} + +
+

Thank you

+ {{range .Authors}} +
+ {{range .Elem}}{{elem $.Template .}}{{end}} +
+ {{end}} +
+ + + {{if .PlayEnabled}} + + {{end}} + +{{end}} + +{{define "newline"}} +
+{{end}}