"
39 | html += "Error: Not A WebKit Browser"
40 | html += "Your browser is not supported. Please use Safari or Chrome. "
41 | html += "Try anyway"
42 | html += "
"
43 |
44 | showAlert(html)
45 | }
46 |
47 | function showFileLoadingAlert() {
48 | var html = ""
49 | html += "
"
50 | html += "Error: Local File Restrictions"
51 | html += "Preview this prototype with Framer Mirror or learn more about "
52 | html += "file restrictions. "
53 | html += "Try anyway"
54 | html += "
"
55 |
56 | showAlert(html)
57 | }
58 |
59 | function loadProject() {
60 | CoffeeScript.load("app.coffee")
61 | }
62 |
63 | function setDefaultPageTitle() {
64 | // If no title was set we set it to the project folder name so
65 | // you get a nice name on iOS if you bookmark to desktop.
66 | document.addEventListener("DOMContentLoaded", function() {
67 | if (document.title == "") {
68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) {
69 | document.title = window.FramerStudioInfo.documentTitle
70 | } else {
71 | document.title = window.location.pathname.replace(/\//g, "")
72 | }
73 | }
74 | })
75 | }
76 |
77 | function init() {
78 |
79 | if (Utils.isFramerStudio()) {
80 | return
81 | }
82 |
83 | setDefaultPageTitle()
84 |
85 | if (!isCompatibleBrowser()) {
86 | return showBrowserAlert()
87 | }
88 |
89 | if (!isFileLoadingAllowed()) {
90 | return showFileLoadingAlert()
91 | }
92 |
93 | loadProject()
94 |
95 | }
96 |
97 | init()
98 |
99 | })()
100 |
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/cursor-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/cursor-active.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/cursor-active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/cursor-active@2x.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/cursor.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/cursor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/cursor@2x.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/icon-120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/icon-120.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/icon-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/icon-152.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/icon-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/icon-180.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/icon-192.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/images/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/framer/images/icon-76.png
--------------------------------------------------------------------------------
/Cantor.framer/framer/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | border: none;
5 | -webkit-user-select: none;
6 | -webkit-tap-highlight-color: rgba(0,0,0,0);
7 | }
8 |
9 | body {
10 | background-color: #fff;
11 | font: 28px/1em "Helvetica";
12 | color: gray;
13 | overflow: hidden;
14 | }
15 |
16 | a {
17 | color: gray;
18 | }
19 |
20 | body {
21 | cursor: url('images/cursor.png') 32 32, auto;
22 | cursor: -webkit-image-set(
23 | url('images/cursor.png') 1x,
24 | url('images/cursor@2x.png') 2x
25 | ) 32 32, auto;
26 | }
27 |
28 | body:active {
29 | cursor: url('images/cursor-active.png') 32 32, auto;
30 | cursor: -webkit-image-set(
31 | url('images/cursor-active.png') 1x,
32 | url('images/cursor-active@2x.png') 2x
33 | ) 32 32, auto;
34 | }
35 |
36 | .framerAlertBackground {
37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px;
38 | z-index: 1000;
39 | background-color: #fff;
40 | }
41 |
42 | .framerAlert {
43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif;
44 | -webkit-font-smoothing:antialiased;
45 | color:#616367; text-align:center;
46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px;
47 | }
48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; }
49 | .framerAlert a { color:#28AFFA; }
50 | .framerAlert .btn {
51 | font-weight:500; text-decoration:none; line-height:1;
52 | display:inline-block; padding:6px 12px 7px 12px;
53 | border-radius:3px; margin-top:12px;
54 | background:#28AFFA; color:#fff;
55 | }
56 |
57 | ::-webkit-scrollbar {
58 | display: none;
59 | }
--------------------------------------------------------------------------------
/Cantor.framer/framer/version:
--------------------------------------------------------------------------------
1 | 4
--------------------------------------------------------------------------------
/Cantor.framer/images/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/images/.gitkeep
--------------------------------------------------------------------------------
/Cantor.framer/images/ants.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/images/ants.gif
--------------------------------------------------------------------------------
/Cantor.framer/images/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/images/dash.png
--------------------------------------------------------------------------------
/Cantor.framer/images/grid-high-contrast.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Cantor.framer/images/grid.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Cantor.framer/images/triangle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/images/triangle@2x.png
--------------------------------------------------------------------------------
/Cantor.framer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Cantor.framer/modules/TextLayer.coffee:
--------------------------------------------------------------------------------
1 | class TextLayer extends Layer
2 |
3 | constructor: (options={}) ->
4 | @doAutoSize = false
5 | @doAutoSizeHeight = false
6 | options.backgroundColor ?= if options.setup then "hsla(60, 90%, 47%, .4)" else "transparent"
7 | options.color ?= "red"
8 | options.lineHeight ?= 1.25
9 | options.fontFamily ?= "Helvetica"
10 | options.fontSize ?= 20
11 | options.text ?= "Use layer.text to add text"
12 | super options
13 | @style.whiteSpace = "pre-line" # allow \n in .text
14 | @style.outline = "none" # no border when selected
15 |
16 | setStyle: (property, value, pxSuffix = false) ->
17 | @style[property] = if pxSuffix then value+"px" else value
18 | @emit("change:#{property}", value)
19 | if @doAutoSize then @calcSize()
20 |
21 | calcSize: ->
22 | sizeAffectingStyles =
23 | lineHeight: @style["line-height"]
24 | fontSize: @style["font-size"]
25 | fontWeight: @style["font-weight"]
26 | paddingTop: @style["padding-top"]
27 | paddingRight: @style["padding-right"]
28 | paddingBottom: @style["padding-bottom"]
29 | paddingLeft: @style["padding-left"]
30 | textTransform: @style["text-transform"]
31 | borderWidth: @style["border-width"]
32 | letterSpacing: @style["letter-spacing"]
33 | fontFamily: @style["font-family"]
34 | fontStyle: @style["font-style"]
35 | fontVariant: @style["font-variant"]
36 | constraints = {}
37 | if @doAutoSizeHeight then constraints.width = @width
38 | size = Utils.textSize @text, sizeAffectingStyles, constraints
39 | if @style.textAlign is "right"
40 | @width = size.width
41 | @x = @x-@width
42 | else
43 | @width = size.width
44 | @height = size.height
45 |
46 | @define "autoSize",
47 | get: -> @doAutoSize
48 | set: (value) ->
49 | @doAutoSize = value
50 | if @doAutoSize then @calcSize()
51 | @define "autoSizeHeight",
52 | set: (value) ->
53 | @doAutoSize = value
54 | @doAutoSizeHeight = value
55 | if @doAutoSize then @calcSize()
56 | @define "contentEditable",
57 | set: (boolean) ->
58 | @_element.contentEditable = boolean
59 | @ignoreEvents = !boolean
60 | @on "input", -> @calcSize() if @doAutoSize
61 | @define "text",
62 | get: -> @_element.textContent
63 | set: (value) ->
64 | @_element.textContent = value
65 | @emit("change:text", value)
66 | if @doAutoSize then @calcSize()
67 | @define "fontFamily",
68 | get: -> @style.fontFamily
69 | set: (value) -> @setStyle("fontFamily", value)
70 | @define "fontSize",
71 | get: -> @style.fontSize.replace("px","")
72 | set: (value) -> @setStyle("fontSize", value, true)
73 | @define "lineHeight",
74 | get: -> @style.lineHeight
75 | set: (value) -> @setStyle("lineHeight", value)
76 | @define "fontWeight",
77 | get: -> @style.fontWeight
78 | set: (value) -> @setStyle("fontWeight", value)
79 | @define "fontStyle",
80 | get: -> @style.fontStyle
81 | set: (value) -> @setStyle("fontStyle", value)
82 | @define "fontVariant",
83 | get: -> @style.fontVariant
84 | set: (value) -> @setStyle("fontVariant", value)
85 | @define "padding",
86 | set: (value) ->
87 | @setStyle("paddingTop", value, true)
88 | @setStyle("paddingRight", value, true)
89 | @setStyle("paddingBottom", value, true)
90 | @setStyle("paddingLeft", value, true)
91 | @define "paddingTop",
92 | get: -> @style.paddingTop.replace("px","")
93 | set: (value) -> @setStyle("paddingTop", value, true)
94 | @define "paddingRight",
95 | get: -> @style.paddingRight.replace("px","")
96 | set: (value) -> @setStyle("paddingRight", value, true)
97 | @define "paddingBottom",
98 | get: -> @style.paddingBottom.replace("px","")
99 | set: (value) -> @setStyle("paddingBottom", value, true)
100 | @define "paddingLeft",
101 | get: -> @style.paddingLeft.replace("px","")
102 | set: (value) -> @setStyle("paddingLeft", value, true)
103 | @define "textAlign",
104 | set: (value) -> @setStyle("textAlign", value)
105 | @define "textTransform",
106 | get: -> @style.textTransform
107 | set: (value) -> @setStyle("textTransform", value)
108 | @define "letterSpacing",
109 | get: -> @style.letterSpacing.replace("px","")
110 | set: (value) -> @setStyle("letterSpacing", value, true)
111 | @define "length",
112 | get: -> @text.length
113 |
114 | convertToTextLayer = (layer) ->
115 | t = new TextLayer
116 | name: layer.name
117 | frame: layer.frame
118 | parent: layer.parent
119 |
120 | cssObj = {}
121 | css = layer._info.metadata.css
122 | css.forEach (rule) ->
123 | return if _.contains rule, '/*'
124 | arr = rule.split(': ')
125 | cssObj[arr[0]] = arr[1].replace(';','')
126 | t.style = cssObj
127 |
128 | importPath = layer.__framerImportedFromPath
129 | if _.contains importPath, '@2x'
130 | t.fontSize *= 2
131 | t.lineHeight = (parseInt(t.lineHeight)*2)+'px'
132 | t.letterSpacing *= 2
133 |
134 | t.y -= (parseInt(t.lineHeight)-t.fontSize)/2 # compensate for how CSS handles line height
135 | t.y -= t.fontSize * 0.1 # sketch padding
136 | t.x -= t.fontSize * 0.08 # sketch padding
137 | t.width += t.fontSize * 0.5 # sketch padding
138 |
139 | t.text = layer._info.metadata.string
140 | layer.destroy()
141 | return t
142 |
143 | Layer::convertToTextLayer = -> convertToTextLayer(@)
144 |
145 | convertTextLayers = (obj) ->
146 | for prop,layer of obj
147 | if layer._info.kind is "text"
148 | obj[prop] = convertToTextLayer(layer)
149 |
150 | # Backwards compability. Replaced by convertToTextLayer()
151 | Layer::frameAsTextLayer = (properties) ->
152 | t = new TextLayer
153 | t.frame = @frame
154 | t.superLayer = @superLayer
155 | _.extend t,properties
156 | @destroy()
157 | t
158 |
159 | exports.TextLayer = TextLayer
160 | exports.convertTextLayers = convertTextLayers
161 |
--------------------------------------------------------------------------------
/Cantor.framer/modules/inline-worker.js:
--------------------------------------------------------------------------------
1 | var WORKER_ENABLED = !!(global === global.window && global.URL && global.Blob && global.Worker);
2 |
3 | function InlineWorker(func, self) {
4 | var _this = this;
5 | var functionBody;
6 |
7 | self = self || {};
8 |
9 | if (WORKER_ENABLED) {
10 | functionBody = func.toString().trim().match(
11 | /^function\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}$/
12 | )[1];
13 |
14 | return new global.Worker(global.URL.createObjectURL(
15 | new global.Blob([ functionBody ], { type: "text/javascript" })
16 | ));
17 | }
18 |
19 | function postMessage(data) {
20 | setTimeout(function() {
21 | _this.onmessage({ data: data });
22 | }, 0);
23 | }
24 |
25 | this.self = self;
26 | this.self.postMessage = postMessage;
27 |
28 | setTimeout(func.bind(self, self), 0);
29 | }
30 |
31 | InlineWorker.prototype.postMessage = function postMessage(data) {
32 | var _this = this;
33 |
34 | setTimeout(function() {
35 | _this.self.onmessage({ data: data });
36 | }, 0);
37 | };
38 |
39 | module.exports = InlineWorker;
40 |
--------------------------------------------------------------------------------
/Cantor.framer/modules/kaColors.js:
--------------------------------------------------------------------------------
1 | // Khan Academy Color Module
2 | //
3 | // This module is meant to be imported by Framer. To use it in a Framer project:
4 | // kaColors = require "kaColors"
5 | // someLayer.backgroundColor = kaColors.kaGreen
6 | //
7 | // This file is generated by a script. You should not modify it manually. To update this file, rerun generate_framer_color_module.swift.
8 |
9 | exports.alert = "rgba(181, 16, 25, 1.0)";
10 | exports.kaGreen = "rgba(82, 141, 28, 1.0)";
11 | exports.kaBlue = "rgba(37, 52, 65, 1.0)";
12 | exports.mint1 = "rgba(217, 224, 193, 1.0)";
13 | exports.mint2 = "rgba(233, 240, 215, 1.0)";
14 | exports.mint3 = "rgba(243, 248, 226, 1.0)";
15 | exports.black = "rgba(0, 0, 0, 1.0)";
16 | exports.gray17 = "rgba(25, 27, 33, 1.0)";
17 | exports.gray25 = "rgba(45, 47, 49, 1.0)";
18 | exports.gray41 = "rgba(79, 82, 86, 1.0)";
19 | exports.gray68 = "rgba(117, 122, 129, 1.0)";
20 | exports.gray76 = "rgba(172, 176, 181, 1.0)";
21 | exports.gray85 = "rgba(205, 207, 209, 1.0)";
22 | exports.gray90 = "rgba(220, 223, 224, 1.0)";
23 | exports.gray95 = "rgba(236, 237, 239, 1.0)";
24 | exports.gray97 = "rgba(244, 245, 245, 1.0)";
25 | exports.gray98 = "rgba(249, 249, 249, 1.0)";
26 | exports.white = "rgba(255, 255, 255, 1.0)";
27 | exports.math4 = "rgba(13, 67, 83, 1.0)";
28 | exports.math3 = "rgba(18, 108, 135, 1.0)";
29 | exports.math1 = "rgba(25, 156, 194, 1.0)";
30 | exports.math2 = "rgba(85, 209, 229, 1.0)";
31 | exports.math5 = "rgba(114, 245, 255, 1.0)";
32 | exports.math6 = "rgba(194, 249, 255, 1.0)";
33 | exports.partner4 = "rgba(18, 63, 52, 1.0)";
34 | exports.partner3 = "rgba(29, 111, 93, 1.0)";
35 | exports.partner1 = "rgba(20, 155, 131, 1.0)";
36 | exports.partner2 = "rgba(26, 201, 180, 1.0)";
37 | exports.partner5 = "rgba(43, 236, 203, 1.0)";
38 | exports.partner6 = "rgba(134, 255, 242, 1.0)";
39 | exports.cs4 = "rgba(14, 77, 31, 1.0)";
40 | exports.cs3 = "rgba(22, 131, 48, 1.0)";
41 | exports.cs1 = "rgba(32, 159, 67, 1.0)";
42 | exports.cs2 = "rgba(100, 201, 93, 1.0)";
43 | exports.cs5 = "rgba(124, 244, 110, 1.0)";
44 | exports.cs6 = "rgba(170, 255, 161, 1.0)";
45 | exports.economics4 = "rgba(129, 44, 5, 1.0)";
46 | exports.economics3 = "rgba(149, 71, 9, 1.0)";
47 | exports.economics1 = "rgba(214, 105, 16, 1.0)";
48 | exports.economics5 = "rgba(253, 138, 44, 1.0)";
49 | exports.economics6 = "rgba(253, 173, 94, 1.0)";
50 | exports.economics7 = "rgba(254, 198, 153, 1.0)";
51 | exports.economics2 = "rgba(253, 178, 30, 1.0)";
52 | exports.humanities4 = "rgba(120, 16, 13, 1.0)";
53 | exports.humanities3 = "rgba(174, 20, 16, 1.0)";
54 | exports.humanities1 = "rgba(223, 54, 44, 1.0)";
55 | exports.humanities5 = "rgba(244, 80, 75, 1.0)";
56 | exports.humanities2 = "rgba(252, 109, 111, 1.0)";
57 | exports.humanities6 = "rgba(249, 150, 153, 1.0)";
58 | exports.science4 = "rgba(87, 0, 40, 1.0)";
59 | exports.science3 = "rgba(138, 0, 61, 1.0)";
60 | exports.science1 = "rgba(188, 26, 105, 1.0)";
61 | exports.science5 = "rgba(230, 67, 149, 1.0)";
62 | exports.science2 = "rgba(252, 122, 186, 1.0)";
63 | exports.science6 = "rgba(253, 172, 217, 1.0)";
64 | exports.testprep4 = "rgba(36, 24, 53, 1.0)";
65 | exports.testprep3 = "rgba(66, 41, 101, 1.0)";
66 | exports.testprep1 = "rgba(100, 60, 155, 1.0)";
67 | exports.testprep2 = "rgba(152, 108, 255, 1.0)";
68 | exports.testprep5 = "rgba(185, 167, 251, 1.0)";
69 | exports.testprep6 = "rgba(213, 204, 255, 1.0)";
70 | exports.default4 = "rgba(2, 30, 57, 1.0)";
71 | exports.default3 = "rgba(5, 51, 105, 1.0)";
72 | exports.default1 = "rgba(17, 57, 146, 1.0)";
73 | exports.default6 = "rgba(29, 87, 189, 1.0)";
74 | exports.default5 = "rgba(48, 123, 222, 1.0)";
75 | exports.default2 = "rgba(85, 158, 227, 1.0)";
76 | exports.yellow1 = "rgba(194, 157, 21, 1.0)";
77 | exports.yellow2 = "rgba(225, 182, 24, 1.0)";
78 | exports.yellow3 = "rgba(240, 204, 54, 1.0)";
79 | exports.yellow4 = "rgba(251, 221, 74, 1.0)";
80 | exports.yellow5 = "rgba(255, 231, 130, 1.0)";
81 | exports.yellow6 = "rgba(255, 239, 168, 1.0)";
82 |
--------------------------------------------------------------------------------
/Cantor.framer/modules/myModule.coffee:
--------------------------------------------------------------------------------
1 | # Add the following line to your project in Framer Studio.
2 | # myModule = require "myModule"
3 | # Reference the contents by name, like myModule.myFunction() or myModule.myVar
4 |
5 | exports.myVar = "myVariable"
6 |
7 | exports.myFunction = ->
8 | print "myFunction is running"
9 |
10 | exports.myArray = [1, 2, 3]
--------------------------------------------------------------------------------
/Cantor.framer/modules/npm.coffee:
--------------------------------------------------------------------------------
1 | exports.deepEqual = require "deep-equal"
2 |
--------------------------------------------------------------------------------
/Cantor.framer/modules/recorder.js:
--------------------------------------------------------------------------------
1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Recorder = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
2 | return Math.max(min, Math.min(max, value))
3 |
4 | exports.pointInsideLayer = (layer, point) ->
5 | return layer.x <= point.x && layer.maxX > point.x && layer.y <= point.y && layer.maxY > point.y
6 |
7 | exports.layersIntersect = (layerA, layerB) ->
8 | x = Math.max(layerA.x, layerB.x)
9 | y = Math.max(layerA.y, layerB.y)
10 | maxX = Math.min(layerA.maxX, layerB.maxX)
11 | maxY = Math.min(layerA.maxY, layerB.maxY)
12 | return maxX >= x && maxY >= y
13 |
14 | exports.framesIntersect = (frameA, frameB) ->
15 | x = Math.max(frameA.x, frameB.x)
16 | y = Math.max(frameA.y, frameB.y)
17 | maxX = Math.min(frameA.x + frameA.width, frameB.x + frameB.width)
18 | maxY = Math.min(frameA.y + frameA.height, frameB.y + frameB.height)
19 | return maxX >= x && maxY >= y
20 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '0.8'
4 | - '0.10'
5 | - '0.12'
6 | - 'iojs'
7 | before_install:
8 | - npm install -g npm@latest
9 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/LICENSE:
--------------------------------------------------------------------------------
1 | This software is released under the MIT license:
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/example/cmp.js:
--------------------------------------------------------------------------------
1 | var equal = require('../');
2 | console.dir([
3 | equal(
4 | { a : [ 2, 3 ], b : [ 4 ] },
5 | { a : [ 2, 3 ], b : [ 4 ] }
6 | ),
7 | equal(
8 | { x : 5, y : [6] },
9 | { x : 5, y : 6 }
10 | )
11 | ]);
12 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/index.js:
--------------------------------------------------------------------------------
1 | var pSlice = Array.prototype.slice;
2 | var objectKeys = require('./lib/keys.js');
3 | var isArguments = require('./lib/is_arguments.js');
4 |
5 | var deepEqual = module.exports = function (actual, expected, opts) {
6 | if (!opts) opts = {};
7 | // 7.1. All identical values are equivalent, as determined by ===.
8 | if (actual === expected) {
9 | return true;
10 |
11 | } else if (actual instanceof Date && expected instanceof Date) {
12 | return actual.getTime() === expected.getTime();
13 |
14 | // 7.3. Other pairs that do not both pass typeof value == 'object',
15 | // equivalence is determined by ==.
16 | } else if (!actual || !expected || typeof actual != 'object' && typeof expected != 'object') {
17 | return opts.strict ? actual === expected : actual == expected;
18 |
19 | // 7.4. For all other Object pairs, including Array objects, equivalence is
20 | // determined by having the same number of owned properties (as verified
21 | // with Object.prototype.hasOwnProperty.call), the same set of keys
22 | // (although not necessarily the same order), equivalent values for every
23 | // corresponding key, and an identical 'prototype' property. Note: this
24 | // accounts for both named and indexed properties on Arrays.
25 | } else {
26 | return objEquiv(actual, expected, opts);
27 | }
28 | }
29 |
30 | function isUndefinedOrNull(value) {
31 | return value === null || value === undefined;
32 | }
33 |
34 | function isBuffer (x) {
35 | if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;
36 | if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
37 | return false;
38 | }
39 | if (x.length > 0 && typeof x[0] !== 'number') return false;
40 | return true;
41 | }
42 |
43 | function objEquiv(a, b, opts) {
44 | var i, key;
45 | if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
46 | return false;
47 | // an identical 'prototype' property.
48 | if (a.prototype !== b.prototype) return false;
49 | //~~~I've managed to break Object.keys through screwy arguments passing.
50 | // Converting to array solves the problem.
51 | if (isArguments(a)) {
52 | if (!isArguments(b)) {
53 | return false;
54 | }
55 | a = pSlice.call(a);
56 | b = pSlice.call(b);
57 | return deepEqual(a, b, opts);
58 | }
59 | if (isBuffer(a)) {
60 | if (!isBuffer(b)) {
61 | return false;
62 | }
63 | if (a.length !== b.length) return false;
64 | for (i = 0; i < a.length; i++) {
65 | if (a[i] !== b[i]) return false;
66 | }
67 | return true;
68 | }
69 | try {
70 | var ka = objectKeys(a),
71 | kb = objectKeys(b);
72 | } catch (e) {//happens when one is a string literal and the other isn't
73 | return false;
74 | }
75 | // having the same number of owned properties (keys incorporates
76 | // hasOwnProperty)
77 | if (ka.length != kb.length)
78 | return false;
79 | //the same set of keys (although not necessarily the same order),
80 | ka.sort();
81 | kb.sort();
82 | //~~~cheap key test
83 | for (i = ka.length - 1; i >= 0; i--) {
84 | if (ka[i] != kb[i])
85 | return false;
86 | }
87 | //equivalent values for every corresponding key, and
88 | //~~~possibly expensive deep test
89 | for (i = ka.length - 1; i >= 0; i--) {
90 | key = ka[i];
91 | if (!deepEqual(a[key], b[key], opts)) return false;
92 | }
93 | return typeof a === typeof b;
94 | }
95 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/lib/is_arguments.js:
--------------------------------------------------------------------------------
1 | var supportsArgumentsClass = (function(){
2 | return Object.prototype.toString.call(arguments)
3 | })() == '[object Arguments]';
4 |
5 | exports = module.exports = supportsArgumentsClass ? supported : unsupported;
6 |
7 | exports.supported = supported;
8 | function supported(object) {
9 | return Object.prototype.toString.call(object) == '[object Arguments]';
10 | };
11 |
12 | exports.unsupported = unsupported;
13 | function unsupported(object){
14 | return object &&
15 | typeof object == 'object' &&
16 | typeof object.length == 'number' &&
17 | Object.prototype.hasOwnProperty.call(object, 'callee') &&
18 | !Object.prototype.propertyIsEnumerable.call(object, 'callee') ||
19 | false;
20 | };
21 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/lib/keys.js:
--------------------------------------------------------------------------------
1 | exports = module.exports = typeof Object.keys === 'function'
2 | ? Object.keys : shim;
3 |
4 | exports.shim = shim;
5 | function shim (obj) {
6 | var keys = [];
7 | for (var key in obj) keys.push(key);
8 | return keys;
9 | }
10 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_args": [
3 | [
4 | "deep-equal",
5 | "/Users/andymatuschak/khan/Prototypes/Cantor/Cantor.framer"
6 | ]
7 | ],
8 | "_from": "deep-equal@latest",
9 | "_id": "deep-equal@1.0.1",
10 | "_inCache": true,
11 | "_installable": true,
12 | "_location": "/deep-equal",
13 | "_nodeVersion": "2.4.0",
14 | "_npmUser": {
15 | "email": "substack@gmail.com",
16 | "name": "substack"
17 | },
18 | "_npmVersion": "3.2.2",
19 | "_phantomChildren": {},
20 | "_requested": {
21 | "name": "deep-equal",
22 | "raw": "deep-equal",
23 | "rawSpec": "",
24 | "scope": null,
25 | "spec": "latest",
26 | "type": "tag"
27 | },
28 | "_requiredBy": [
29 | "#USER"
30 | ],
31 | "_resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
32 | "_shasum": "f5d260292b660e084eff4cdbc9f08ad3247448b5",
33 | "_shrinkwrap": null,
34 | "_spec": "deep-equal",
35 | "_where": "/Users/andymatuschak/khan/Prototypes/Cantor/Cantor.framer",
36 | "author": {
37 | "email": "mail@substack.net",
38 | "name": "James Halliday",
39 | "url": "http://substack.net"
40 | },
41 | "bugs": {
42 | "url": "https://github.com/substack/node-deep-equal/issues"
43 | },
44 | "dependencies": {},
45 | "description": "node's assert.deepEqual algorithm",
46 | "devDependencies": {
47 | "tape": "^3.5.0"
48 | },
49 | "directories": {
50 | "example": "example",
51 | "lib": ".",
52 | "test": "test"
53 | },
54 | "dist": {
55 | "shasum": "f5d260292b660e084eff4cdbc9f08ad3247448b5",
56 | "tarball": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz"
57 | },
58 | "gitHead": "59c511f5aeae19e3dd1de054077a789d7302be34",
59 | "homepage": "https://github.com/substack/node-deep-equal#readme",
60 | "keywords": [
61 | "compare",
62 | "equal",
63 | "equality"
64 | ],
65 | "license": "MIT",
66 | "main": "index.js",
67 | "maintainers": [
68 | {
69 | "name": "substack",
70 | "email": "mail@substack.net"
71 | }
72 | ],
73 | "name": "deep-equal",
74 | "optionalDependencies": {},
75 | "readme": "ERROR: No README data found!",
76 | "repository": {
77 | "type": "git",
78 | "url": "git+ssh://git@github.com/substack/node-deep-equal.git"
79 | },
80 | "scripts": {
81 | "test": "tape test/*.js"
82 | },
83 | "testling": {
84 | "browsers": {
85 | "chrome": [
86 | 10,
87 | 22
88 | ],
89 | "ff": [
90 | 10,
91 | 15,
92 | 3.5
93 | ],
94 | "ie": [
95 | 6,
96 | 7,
97 | 8,
98 | 9
99 | ],
100 | "opera": [
101 | 12
102 | ],
103 | "safari": [
104 | 5.1
105 | ]
106 | },
107 | "files": "test/*.js"
108 | },
109 | "version": "1.0.1"
110 | }
111 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/readme.markdown:
--------------------------------------------------------------------------------
1 | # deep-equal
2 |
3 | Node's `assert.deepEqual() algorithm` as a standalone module.
4 |
5 | This module is around [5 times faster](https://gist.github.com/2790507)
6 | than wrapping `assert.deepEqual()` in a `try/catch`.
7 |
8 | [](https://ci.testling.com/substack/node-deep-equal)
9 |
10 | [](https://travis-ci.org/substack/node-deep-equal)
11 |
12 | # example
13 |
14 | ``` js
15 | var equal = require('deep-equal');
16 | console.dir([
17 | equal(
18 | { a : [ 2, 3 ], b : [ 4 ] },
19 | { a : [ 2, 3 ], b : [ 4 ] }
20 | ),
21 | equal(
22 | { x : 5, y : [6] },
23 | { x : 5, y : 6 }
24 | )
25 | ]);
26 | ```
27 |
28 | # methods
29 |
30 | ``` js
31 | var deepEqual = require('deep-equal')
32 | ```
33 |
34 | ## deepEqual(a, b, opts)
35 |
36 | Compare objects `a` and `b`, returning whether they are equal according to a
37 | recursive equality algorithm.
38 |
39 | If `opts.strict` is `true`, use strict equality (`===`) to compare leaf nodes.
40 | The default is to use coercive equality (`==`) because that's how
41 | `assert.deepEqual()` works by default.
42 |
43 | # install
44 |
45 | With [npm](http://npmjs.org) do:
46 |
47 | ```
48 | npm install deep-equal
49 | ```
50 |
51 | # test
52 |
53 | With [npm](http://npmjs.org) do:
54 |
55 | ```
56 | npm test
57 | ```
58 |
59 | # license
60 |
61 | MIT. Derived largely from node's assert module.
62 |
--------------------------------------------------------------------------------
/Cantor.framer/node_modules/deep-equal/test/cmp.js:
--------------------------------------------------------------------------------
1 | var test = require('tape');
2 | var equal = require('../');
3 | var isArguments = require('../lib/is_arguments.js');
4 | var objectKeys = require('../lib/keys.js');
5 |
6 | test('equal', function (t) {
7 | t.ok(equal(
8 | { a : [ 2, 3 ], b : [ 4 ] },
9 | { a : [ 2, 3 ], b : [ 4 ] }
10 | ));
11 | t.end();
12 | });
13 |
14 | test('not equal', function (t) {
15 | t.notOk(equal(
16 | { x : 5, y : [6] },
17 | { x : 5, y : 6 }
18 | ));
19 | t.end();
20 | });
21 |
22 | test('nested nulls', function (t) {
23 | t.ok(equal([ null, null, null ], [ null, null, null ]));
24 | t.end();
25 | });
26 |
27 | test('strict equal', function (t) {
28 | t.notOk(equal(
29 | [ { a: 3 }, { b: 4 } ],
30 | [ { a: '3' }, { b: '4' } ],
31 | { strict: true }
32 | ));
33 | t.end();
34 | });
35 |
36 | test('non-objects', function (t) {
37 | t.ok(equal(3, 3));
38 | t.ok(equal('beep', 'beep'));
39 | t.ok(equal('3', 3));
40 | t.notOk(equal('3', 3, { strict: true }));
41 | t.notOk(equal('3', [3]));
42 | t.end();
43 | });
44 |
45 | test('arguments class', function (t) {
46 | t.ok(equal(
47 | (function(){return arguments})(1,2,3),
48 | (function(){return arguments})(1,2,3),
49 | "compares arguments"
50 | ));
51 | t.notOk(equal(
52 | (function(){return arguments})(1,2,3),
53 | [1,2,3],
54 | "differenciates array and arguments"
55 | ));
56 | t.end();
57 | });
58 |
59 | test('test the arguments shim', function (t) {
60 | t.ok(isArguments.supported((function(){return arguments})()));
61 | t.notOk(isArguments.supported([1,2,3]));
62 |
63 | t.ok(isArguments.unsupported((function(){return arguments})()));
64 | t.notOk(isArguments.unsupported([1,2,3]));
65 |
66 | t.end();
67 | });
68 |
69 | test('test the keys shim', function (t) {
70 | t.deepEqual(objectKeys.shim({ a: 1, b : 2 }), [ 'a', 'b' ]);
71 | t.end();
72 | });
73 |
74 | test('dates', function (t) {
75 | var d0 = new Date(1387585278000);
76 | var d1 = new Date('Fri Dec 20 2013 16:21:18 GMT-0800 (PST)');
77 | t.ok(equal(d0, d1));
78 | t.end();
79 | });
80 |
81 | test('buffers', function (t) {
82 | t.ok(equal(Buffer('xyz'), Buffer('xyz')));
83 | t.end();
84 | });
85 |
86 | test('booleans and arrays', function (t) {
87 | t.notOk(equal(true, []));
88 | t.end();
89 | })
90 |
91 | test('null == undefined', function (t) {
92 | t.ok(equal(null, undefined))
93 | t.notOk(equal(null, undefined, { strict: true }))
94 | t.end()
95 | })
96 |
--------------------------------------------------------------------------------
/Cantor.framer/recordings/1.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Khan/Cantor/80c65205a83e58160369806471bdf981c3bfa26a/Cantor.framer/recordings/1.wav
--------------------------------------------------------------------------------
/Readme.mdown:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Prototypes around a medium and toolset for exploring quantities and arithmetic operations.
4 |
5 | More notes here to come, but in the meantime:
6 | * [A medium supporting the exploration of quantities](http://klr.tumblr.com/post/147245626988/a-medium-supporting-the-exploration-of-quantities)
7 | * [Old and new ways of looking at number](http://klr.tumblr.com/post/149677916243/old-and-new-ways-of-looking-at-numbers)
8 |
9 | # Recording
10 |
11 | We're interested in Cantor interactions which trade off control between recordings and the student. I expect we'll write about that more extensively eventually, but in the meantime, to record an interactive:
12 |
13 | * **Get Cantor ready for recording** (Chrome tries to protect you but gets in the way!)
14 | * Open the project in Framer.
15 | * Click the "Mirror" toolbar icon, then "Open in Browser".
16 | * Copy that URL, then paste it into Chrome Canary.
17 | * Change the IP address in the address bar (e.g. `10.0.0.15`) to `localhost` and hit Return.
18 | * Press the "R" key once to start a test recording. Give Chrome permission to use your microphone.
19 | * Press "R" again to stop the test recording. You should now be ready to record a talky segment!
20 | * **Record a segment**:
21 | * Press the "R" key to start recording (you'll have to approve mic usage the first time).
22 | * Press the "R" key again when you're done.
23 | * Press the "P" key to play back the last recorded segment.
24 | * Press the "D" key to download the last recorded segment (a `wav` and a `json` file).
25 | * **Arrange segments into an interactive sequence**:
26 | * Put the `wav` and `json` files in `Cantor.framer/recordings`.
27 | * Rename them as `1.json`, `2.json`, etc in the order you'd like them to be sequenced.
28 | * **Play back a sequence**:
29 | * Use the ➡ button to play the next segment in the sequence stored in `recordings`.
30 | * Refresh the browser to start over with the first segment again.
31 | * **Share a sequence**:
32 | * Get the files in `recordings` as you want them.
33 | * Click the "Share" toolbar icon in Framer.
34 |
--------------------------------------------------------------------------------
/Sketches/3d layered operation viz.framer/.gitignore:
--------------------------------------------------------------------------------
1 | # Framer Git Ignore
2 |
3 | # General OSX
4 |
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 |
9 | # Icon must end with two \r
10 | Icon
11 |
12 |
13 | # Thumbnails
14 | ._*
15 |
16 | # Files that might appear in the root of a volume
17 | .DocumentRevisions-V100
18 | .fseventsd
19 | .Spotlight-V100
20 | .TemporaryItems
21 | .Trashes
22 | .VolumeIcon.icns
23 |
24 | # Directories potentially created on remote AFP share
25 | .AppleDB
26 | .AppleDesktop
27 | Network Trash Folder
28 | Temporary Items
29 | .apdisk
30 |
31 |
32 | # Framer Specific
33 | .*.html
34 | framer/*.old*
35 | framer/backup.coffee
36 | framer/backups/*
37 | framer/.*.hash
38 | framer/preview.png
39 | framer/manifest.txt
40 |
--------------------------------------------------------------------------------
/Sketches/3d layered operation viz.framer/app.coffee:
--------------------------------------------------------------------------------
1 | # Visualizing 10 - 4 + 7 by separating into several layers on drag.
2 |
3 | kaColors = require "kaColors"
4 |
5 | Screen.backgroundColor = "white"
6 |
7 | blockSize = 50
8 |
9 | root = new Layer
10 | size: Screen.size
11 | backgroundColor: ""
12 | perspective: 100
13 |
14 | blockParent = new Layer
15 | y: 300
16 | width: 500
17 | height: 100
18 | parent: root
19 | backgroundColor: ""
20 | x: 125
21 |
22 | blockParent.draggable.enabled = true
23 | blockParent.draggable.horizontal = false
24 | blockParent.draggable.momentum = false
25 |
26 | makeBlock = ->
27 | new Layer
28 | width: blockSize
29 | parent: blockParent
30 | height: blockSize
31 | backgroundColor: kaColors.math1
32 | borderColor: kaColors.math2
33 | borderWidth: 1
34 |
35 | zSpacing = 3
36 |
37 | first = []
38 | for i in [0...10]
39 | block = makeBlock()
40 | block.x = i * blockSize
41 | block.y = 0
42 | first.push(block)
43 |
44 | second = []
45 | for i in [0...4]
46 | block = makeBlock()
47 | block.x = i * blockSize + 6 * blockSize
48 | block.y = 0
49 | block.backgroundColor = "white"
50 | block.style["border"] = "1px dashed gray"
51 | second.push(block)
52 |
53 | third = []
54 | thirdAux = []
55 | for i in [0...4]
56 | block = makeBlock()
57 | block.x = i * blockSize + 6 * blockSize
58 | block.y = 0
59 | block.backgroundColor = "rgba(25, 156, 194, 1.0)";
60 | third.push(block)
61 |
62 | for i in [0...3]
63 | block = makeBlock()
64 | block.x = i * blockSize
65 | block.y = blockSize
66 | block.backgroundColor = "rgba(25, 156, 194, 1.0)";
67 | third.push(block)
68 |
69 | block = makeBlock()
70 | block.x = i * blockSize
71 | block.y = blockSize
72 | block.opacity = 0
73 | block.backgroundColor = kaColors.cs1
74 | block.borderWidth = 0
75 | thirdAux.push(block)
76 |
77 |
78 |
79 | # state = false
80 | root.onTouchStart ->
81 | for block in second
82 | block.animate
83 | properties: {z: zSpacing}
84 | time: 0.2
85 | for block in third
86 | block.animate
87 | properties:
88 | z: zSpacing * 2
89 | backgroundColor: "rgba(32, 159, 67, 0.8)"
90 | borderColor: "rgba(100, 201, 93, 1.0)"
91 | time: 0.2
92 | for block in thirdAux
93 | block.animate
94 | properties: {opacity: 0.4}
95 | time: 0.2
96 |
97 |
98 | root.onTouchEnd ->
99 | for block in second
100 | block.animate
101 | properties: {z: 0}
102 | time: 0.2
103 | for block in third
104 | block.animate
105 | properties:
106 | z: 0
107 | backgroundColor: kaColors.math1
108 | borderColor: kaColors.math2
109 | time: 0.2
110 | for block in thirdAux
111 | block.animate
112 | properties: {opacity: 0}
113 | time: 0.2
--------------------------------------------------------------------------------
/Sketches/3d layered operation viz.framer/framer/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "propertyPanelToggleStates" : {
3 | "Filters" : false
4 | },
5 | "deviceOrientation" : 0,
6 | "sharedPrototype" : 0,
7 | "contentScale" : 1,
8 | "deviceType" : "apple-iphone-6s-silver",
9 | "selectedHand" : "",
10 | "updateDelay" : 0.3,
11 | "deviceScale" : "fit",
12 | "foldedCodeRanges" : [
13 |
14 | ],
15 | "orientation" : 0,
16 | "fullScreen" : false
17 | }
--------------------------------------------------------------------------------
/Sketches/3d layered operation viz.framer/framer/framer.generated.js:
--------------------------------------------------------------------------------
1 | // This is autogenerated by Framer
2 |
3 |
4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})}
5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false};
6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-6s-silver","contentScale":1,"orientation":0};
7 | }
8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-6s-silver","contentScale":1,"orientation":0};
9 | }
10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"3d layered operation viz.framer"};
11 |
12 | Framer.Device = new Framer.DeviceView();
13 | Framer.Device.setupContext();
--------------------------------------------------------------------------------
/Sketches/3d layered operation viz.framer/framer/framer.init.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | function isFileLoadingAllowed() {
4 | return (window.location.protocol.indexOf("file") == -1)
5 | }
6 |
7 | function isHomeScreened() {
8 | return ("standalone" in window.navigator) && window.navigator.standalone == true
9 | }
10 |
11 | function isCompatibleBrowser() {
12 | return Utils.isWebKit()
13 | }
14 |
15 | var alertNode;
16 |
17 | function dismissAlert() {
18 | alertNode.parentElement.removeChild(alertNode)
19 | loadProject()
20 | }
21 |
22 | function showAlert(html) {
23 |
24 | alertNode = document.createElement("div")
25 |
26 | alertNode.classList.add("framerAlertBackground")
27 | alertNode.innerHTML = html
28 |
29 | document.addEventListener("DOMContentLoaded", function(event) {
30 | document.body.appendChild(alertNode)
31 | })
32 |
33 | window.dismissAlert = dismissAlert;
34 | }
35 |
36 | function showBrowserAlert() {
37 | var html = ""
38 | html += "
"
39 | html += "Error: Not A WebKit Browser"
40 | html += "Your browser is not supported. Please use Safari or Chrome. "
41 | html += "Try anyway"
42 | html += "
"
43 |
44 | showAlert(html)
45 | }
46 |
47 | function showFileLoadingAlert() {
48 | var html = ""
49 | html += "
"
50 | html += "Error: Local File Restrictions"
51 | html += "Preview this prototype with Framer Mirror or learn more about "
52 | html += "file restrictions. "
53 | html += "Try anyway"
54 | html += "
"
39 | html += "Error: Not A WebKit Browser"
40 | html += "Your browser is not supported. Please use Safari or Chrome. "
41 | html += "Try anyway"
42 | html += "
"
43 |
44 | showAlert(html)
45 | }
46 |
47 | function showFileLoadingAlert() {
48 | var html = ""
49 | html += "
"
50 | html += "Error: Local File Restrictions"
51 | html += "Preview this prototype with Framer Mirror or learn more about "
52 | html += "file restrictions. "
53 | html += "Try anyway"
54 | html += "
"
39 | html += "Error: Not A WebKit Browser"
40 | html += "Your browser is not supported. Please use Safari or Chrome. "
41 | html += "Try anyway"
42 | html += "
"
43 |
44 | showAlert(html)
45 | }
46 |
47 | function showFileLoadingAlert() {
48 | var html = ""
49 | html += "
"
50 | html += "Error: Local File Restrictions"
51 | html += "Preview this prototype with Framer Mirror or learn more about "
52 | html += "file restrictions. "
53 | html += "Try anyway"
54 | html += "
"
39 | html += "Error: Not A WebKit Browser"
40 | html += "Your browser is not supported. Please use Safari or Chrome. "
41 | html += "Try anyway"
42 | html += "
"
43 |
44 | showAlert(html)
45 | }
46 |
47 | function showFileLoadingAlert() {
48 | var html = ""
49 | html += "
"
50 | html += "Error: Local File Restrictions"
51 | html += "Preview this prototype with Framer Mirror or learn more about "
52 | html += "file restrictions. "
53 | html += "Try anyway"
54 | html += "