From 2aaa25568233cd457aafe163460ea94f82768498 Mon Sep 17 00:00:00 2001 From: Nicholas Jitkoff Date: Fri, 25 May 2018 17:16:21 -0700 Subject: [PATCH] Initial commit --- .firebaserc | 6 ++ .gitattributes | 2 + edit copy.js | 199 +++++++++++++++++++++++++++++++++++++++ edit.css | 105 +++++++++++++++++++++ edit.html | 22 +++++ edit.js | 192 +++++++++++++++++++++++++++++++++++++ favicon.ico | Bin 0 -> 5430 bytes firebase.json | 19 ++++ index.html | 33 +++++++ manifest.appcache | 5 + preamble.html | 1 + samples/calc.html | 15 +++ samples/jabberwocky.html | 39 ++++++++ samples/learnmore.html | 18 ++++ samples/preamble.html | 1 + 15 files changed, 657 insertions(+) create mode 100644 .firebaserc create mode 100644 .gitattributes create mode 100644 edit copy.js create mode 100644 edit.css create mode 100644 edit.html create mode 100644 edit.js create mode 100644 favicon.ico create mode 100644 firebase.json create mode 100644 index.html create mode 100644 manifest.appcache create mode 100644 preamble.html create mode 100644 samples/calc.html create mode 100644 samples/jabberwocky.html create mode 100644 samples/learnmore.html create mode 100644 samples/preamble.html diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 0000000..3ffe093 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,6 @@ +{ + "projects": { + "staging": "itty-bitty-app", + "default": "itty-bitty-app" + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/edit copy.js b/edit copy.js new file mode 100644 index 0000000..aeafd30 --- /dev/null +++ b/edit copy.js @@ -0,0 +1,199 @@ +var $ = document.querySelector.bind(document) +var $$ = document.querySelectorAll.bind(document) + +window.onload = function() { + becomeEditable() + + document.body.classList.toggle("edited", container.innerText.length) + + document.ondrop = dropEvent; + + var dragcount = 0; + content.ondragenter = function(e) { + console.log("enter", e) + dragcount++ + document.body.classList.toggle("drag", dragcount) + event.preventDefault() + }; + + content.ondragleave = function(e) { + console.log("leave", e) + dragcount-- + document.body.classList.toggle("drag", dragcount) + event.preventDefault() + }; + + +}; + +var DATA_PREFIX = 'data:text/html;charset=utf-8,' +var DATA_PREFIX2 = 'data:text/html;charset=utf-8;base64,' +var iframe = undefined; + +var container = undefined +function becomeEditable() { + container = document.getElementById("content") + container.addEventListener('input', inputEvent); + container.contentEditable = 'true'; + container.focus(); + container.onkeydown = handleKey; + var hash = window.location.hash.substring(1) + console.log("load", hash) + + if (hash.length) { + if (hash.startsWith('!')) { + hash = hash.substring(1) + } + if (!hash.startsWith("data:")) hash = 'data:text/html;charset=utf-8;base64,' + hash; + + dataToString(hash, function(html) { + container.innerHTML = html + }) + } +} + +function dropEvent(e) { + dragcount = 0 + document.body.classList.remove("drag") + + console.log("drop") + e.preventDefault(); + if (e.dataTransfer.files) { + var file = e.dataTransfer.files[0] + var reader = new FileReader(); + reader.addEventListener("load", function () { + var url = reader.result; + content.innerHTML = "đź“„ " + file.name + updateLink(url) + }, false); + reader.readAsDataURL(file); + } +} + +function dataURItoBlob(dataURI) { + var byteString = atob(dataURI.split(',')[1]); + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + var arrayBuffer = new ArrayBuffer(byteString.length); + var _ia = new Uint8Array(arrayBuffer); + for (var i = 0; i < byteString.length; i++) { + _ia[i] = byteString.charCodeAt(i); + } + var dataView = new DataView(arrayBuffer); + var blob = new Blob([dataView], { type: mimeString }); + return blob; +} + +function handleKey(e) { + var code = e.which; + console.log(e) + if (e.metaKey && e.altKey) { + if (code == '1'.charCodeAt(0)) { + document.execCommand("formatBlock", true, "

"); + } else if (code == '2'.charCodeAt(0)) { + document.execCommand("formatBlock", true, "

"); + } else if (code == 220) { // \ + console.log("remove") + document.execCommand("removeFormat"); + } else if (code == '0'.charCodeAt(0)) { + console.log("clear block") + document.execCommand("formatBlock", true, ""); + } + e.preventDefault() + } else if (e.metaKey) { + + console.log("KEY", e, 'V'.charCodeAt(0), 'K'.charCodeAt(0) ) + if (code == 'V'.charCodeAt(0)) { + // console.log("paste") + // e.preventDefault() + } else if (code == 'K'.charCodeAt(0)) { + console.log("link") + var url = prompt("Add a link", "") + document.execCommand("createLink", true, url); + } + } +}; + +function stringToData(string, callback) { + if (!string.length) return callback(""); + var a = new FileReader(); + a.onload = function(e) { callback(e.target.result.replace()) } + a.readAsDataURL(new Blob([string], {encoding:"UTF-8",type:"text/html;charset=UTF-8"})); +} + +function dataToString(data, callback) { + var blob = dataURItoBlob(data) + // if (!data.length) return callback(""); + var reader = new FileReader(); + reader.onload = function(e) { callback(reader.result) } + reader.readAsText(blob); +} + +function stripPrefix(url) { + if (url) { + var dataRE = /data:(text\/html[^,]*)(;base64),(.*)/ + var match = url.match(dataRE); + if (match) return "!" + match[3]; + } + return url; +} + +function inputEvent(e) { + document.body.classList.toggle("edited", container.innerText.length) + var content = container.innerText + if (content.includes(" + <') + } else { + var title = content.split("\n")[0] + content = container.innerHTML + var meta = [] + meta.push("" + title + "") + document.head.childNodes.forEach( function(el) { + if (el.attributes && !el.attributes.doNotEncode) meta.push(el.outerHTML); + }); + } + + console.log("Encoding:\n" + content) + stringToData(content, function(hash) { + var plain = encodeURIComponent(content) + // if (plain.length < hash.length) hash = plain; + updateLink(hash) + }); +} + +function updateLink(url) { + url = stripPrefix(url); + // $('#link').href = "/#" + url + // $('#link').innerText = $('#link').href + window.history.replaceState(null, null, "/#" + url); + var length = url.length + $('#length').innerText = (url.length - 1)/1000 + "/1000" +} + +function makeLink() { + +} + +function makeQRCode() { + //https://developers.google.com/chart/infographics/docs/qr_codes + //https://zxing.org/w/chart?cht=qr&chs=350x350&chld=L&choe=UTF-8&chl= + // chart.googleapis.com/chart?chs=400x400&cht= + location.href = "https://zxing.org/w/chart?cht=qr&chs=548x548&chld=L|1&choe=UTF-8&chl=" + encodeURIComponent(location.href) + +} + +function makeShortLink() { + +} + +function textToClipboard (text) { + var dummy = document.createElement("input"); + document.body.appendChild(dummy); + dummy.value = text; + dummy.select(); + document.execCommand("copy"); + document.body.removeChild(dummy); +} + +function copyLink() { + textToClipboard(location.href) +} \ No newline at end of file diff --git a/edit.css b/edit.css new file mode 100644 index 0000000..96a02a2 --- /dev/null +++ b/edit.css @@ -0,0 +1,105 @@ +body { + margin: 0 auto;padding:12vmin 10vmin; + max-width:35em; + line-height:1.5em; + font-family: -apple-system, BlinkMacSystemFont, sans-serif; +} + +h1 { font-weight:400; } +h2 { font-weight:500; } + +body.placeholder #placeholder { + display:block; +} + +#placeholder { + display:none; + font-style:italic; + color:rgba(0,0,0,0.3); + pointer-events: none; + position:absolute; +} + +body.drag #content { + outline: 3px dashed #ccc; + background-color:#fafafa; + border-radius:1em; + pointer-events: all; +} + +#content, #placeholder{ + width:100%; + margin:-1em; padding: 1em; + min-height:50vh +} + +#content { + outline:none; +} +#content:focus { + outline-color: #ccc; +} +#content:empty:before { + content: attr(placeholder); + color: rgba(0, 0, 0, 0.2); + background: transparent; +} +.ib-file { + border-radius: 1em; + background: #ebeff9; + padding: 0.25em 1em; + font-size:smaller; +} + +#ib-info { + pointer-events: all +} +/*#toolbar a#copy { + transition: transform 1s; + cursor: default; +} + +#copy:active { + transform:translate(0, -0.5em); + transition: transform 100ms; + color:red; +} +*/ + +body.has-content #toolbar { + opacity:1.0; + transition: opacity 2s ease-out; + +} + +#toolbar { + opacity:0.0; + position:fixed; + top:0; + right:0; + padding:1em; + transition: opacity 218ms ease-in; + text-align:center; + background-color:white; + border-bottom-left-radius:1em; +} + +#toolbar button { + vertical-align: baseline; + margin-bottom:11px; +} + +#toolbar a.invalid { + text-decoration: line-through; +} + +#length { + border:1px solid transparent +} + + + +#toolbar a {font-size:11px; margin-right:0.5em; cursor: pointer; text-decoration:none; color:gray;} +#toolbar a:hover { text-decoration: underline; color:blue;} + +*[contenteditable="true"]{display: inline-block;} \ No newline at end of file diff --git a/edit.html b/edit.html new file mode 100644 index 0000000..1b8cc9b --- /dev/null +++ b/edit.html @@ -0,0 +1,22 @@ + + + + +itty bitty + + + + + + Bitly + QR Code + Twitter +
+
+

+ Share itty bitty things
with just a link.
+ To get started, type here
or drop an HTML file.
+

Learn more

+
+ + \ No newline at end of file diff --git a/edit.js b/edit.js new file mode 100644 index 0000000..838172f --- /dev/null +++ b/edit.js @@ -0,0 +1,192 @@ +var $ = document.querySelector.bind(document) +var $$ = document.querySelectorAll.bind(document) + +var DATA_PREFIX = 'data:text/html;base64,' +var DATA_PREFIX_8 = 'data:text/html;charset=utf-8;base64,' + +var content = undefined +window.onload = function() { + window.onpopstate = function(e) { setContent(e.state) } + + content = document.getElementById("content"); + content.ondrop = dropEvent; + document.body.ondragenter = function(e) { document.body.classList.add("drag"); }; + document.body.ondragleave = function(e) { document.body.classList.remove("drag"); }; + document.body.onclick = function() { content.focus()}; + content.oninput = handleInput; + content.onkeydown = handleKey; + content.contentEditable = 'true'; + content.focus(); + $('#qrcode').onclick = makeQRCode + $('#copy').onclick = copyLink + var hash = window.location.hash.substring(1) + if (hash.length) { + updateLink(hash) + if (hash.startsWith('!')) { hash = hash.substring(1) } + if (!hash.startsWith("data:")) { hash = 'data:text/html;charset=utf-8;base64,' + hash; } + dataToString(hash, setContent); + } else { + updateBodyClass() + } +}; + +function setContent(html) { + content.innerHTML = html + updateBodyClass() +} + +function updateBodyClass() { + var length = content.innerText.length; + document.body.classList.toggle("has-content", length) + document.body.classList.toggle("placeholder", !length) +} + +function dropEvent(e) { + e.preventDefault(); + if (e.dataTransfer.files) { + var file = e.dataTransfer.files[0] + var reader = new FileReader(); + reader.addEventListener("load", function () { + var url = reader.result; + url = url.replace(DATA_PREFIX, DATA_PREFIX_8) + updateLink(url, true) + setContent(' đź“„' + file.name + '

'); + }, false); + reader.readAsDataURL(file); + } + document.body.classList.remove("drag") +} + +function handleKey(e) { + var code = e.which; + if (e.metaKey && e.altKey) { + if (code == '1'.charCodeAt(0)) { + document.execCommand("formatBlock", true, "

"); + } else if (code == '2'.charCodeAt(0)) { + document.execCommand("formatBlock", true, "

"); + } else if (code == 220) { // \ + document.execCommand("removeFormat"); + } else if (code == '0'.charCodeAt(0)) { + document.execCommand("formatBlock", true, ""); + } + e.preventDefault() + } else if (e.metaKey) { + if (code == 'K'.charCodeAt(0)) { + var url = prompt("Add a link", "") + if (url) { document.execCommand("createLink", true, url); }; + } + } +}; + +function stringToData(string, callback) { + if (!string.length) return callback(""); + var a = new FileReader(); + a.onload = function(e) { callback(e.target.result.replace()) } + a.readAsDataURL(new Blob([string], {encoding:"UTF-8",type:"text/html;charset=UTF-8"})); +} + +function dataToString(data, callback) { + var blob = dataURItoBlob(data) + var reader = new FileReader(); + reader.onload = function(e) { callback(reader.result) } + reader.readAsText(blob); +} + +function dataURItoBlob(dataURI) { + var byteString = atob(dataURI.split(',')[1]); + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + var arrayBuffer = new ArrayBuffer(byteString.length); + var _ia = new Uint8Array(arrayBuffer); + for (var i = 0; i < byteString.length; i++) { + _ia[i] = byteString.charCodeAt(i); + } + var dataView = new DataView(arrayBuffer); + var blob = new Blob([dataView], { type: mimeString }); + return blob; +} + +function stripPrefix(url) { + if (url) { + var dataRE = /data:(text\/html[^,]*)(;base64),(.*)/ + var match = url.match(dataRE); + if (match) return "!" + match[3]; + } + return url; +} + +function handleInput(e) { + updateBodyClass(); + var text = content.innerText + var strip = false; + if (text.includes(" + <') + } else { + var title = text.split("\n")[0] + text = content.innerHTML + strip = true + } + stringToData(text, function(hash) { + var plain = encodeURIComponent(text) + if (strip) hash = stripPrefix(hash); + updateLink(hash) + }); +} + +var maxLengths = { + "#twitter": 4088, + "#qrcode": 2610, + "#bitly": 2048, +} +function updateLink(url, push) { + url = "/#" + url + var hash = location.hash + if (push || !hash || !hash.length) { + window.history.pushState(content.innerHTML, null, url); + } else { + window.history.replaceState(content.innerHTML, null, url); + } + + var length = location.href.length + $('#length').innerText = length + " bytes" + $('#length').href = url + for (var key in maxLengths) { + var maxLength = maxLengths[key] + $(key).classList.toggle("invalid", length > maxLength) + }; + +} + + +function makeShortLink() { + +} + +function makeQRCode() { + var url = "https://zxing.org/w/chart?cht=qr&chs=548x548&chld=L|1&choe=UTF-8&chl=" + encodeURIComponent(location.href) + this.href = url + + // window.open(url, '_blank'); + // return false; + //https://developers.google.com/chart/infographics/docs/qr_codes +} + +function copyLink() { + var text = location.href + var dummy = document.createElement("input"); + document.body.appendChild(dummy); + dummy.value = text; + dummy.select(); + document.execCommand("copy"); + document.body.removeChild(dummy); +} + +function saveLink() { + var url = "/" + location.hash + window.history.pushState(null, null, url); + location.reload() +} + +function tweetLink() { + var url = "https://twitter.com/intent/tweet?url=" + encodeURIComponent(location.href); + window.open(url, '_blank'); +} diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..cd1b1e51629ad0ab39bfa2a74478c9f6b5e71d97 GIT binary patch literal 5430 zcmdUyTW^*{5XTp)DUx6zqJj~vN1AvFp6V&_O}takh#D56EO(<&NJ8_JHreUEpr;J$M0_md}Bj$F6jI2OrKQ&;KX-gUsKt zw}F-9Z;<`_m>98tPtbP%+;hiDw*YHLdk2X1(p;qZky7S{OSw2y%H+C`F7hqRLS)iL zTgNzd4CN^30PmwKTg=UuYvA56gfS?{$!&&f=Zdv^RLgq?S(Hqj4$09jSVNZQHR?}8XB zx7x?SBT4Sry#Z_m)s=KuW56W{f#E+h2Aq>llva}QL)dBo>!=ulz5k{(Rf_qJH&v9|L3kx&FFI9{Sbh2ht+)-MQLv!~X**zW49+8s@;e z-m{SDMLIFJe%~MWv8H^7`!A7c1D!J<{O``nro9oK&q4i-&EMZcE#rOPgn!qPDeHVI z`>k)I#}S4PxiN$C`@^@_rcl5~Kz@U5PrCiIvrpeROOgMp+1@_-BQduYN8rvJv;{T`|KQj?-Spk<|E?lqOI*zlBx53r0+pUyE+g0u!d$p z#5zj*{nYnOlItw&y2uBOjp*)!Iw&QUF! zyraA)&82l{48NPgbL%(6ca--)eYYU`Z_{5u7vrY>J@L+Is>5p%PrhxMgTeH+7AS7H+SFPFc-5dZ)H literal 0 HcmV?d00001 diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..e67789d --- /dev/null +++ b/firebase.json @@ -0,0 +1,19 @@ +{ + "hosting": { + "public": ".", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**", + "samples/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ], + "cleanUrls": true, + "trailingSlash": false + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..45e1ba5 --- /dev/null +++ b/index.html @@ -0,0 +1,33 @@ + +itty bitty + + + + + \ No newline at end of file diff --git a/manifest.appcache b/manifest.appcache new file mode 100644 index 0000000..accccbb --- /dev/null +++ b/manifest.appcache @@ -0,0 +1,5 @@ +CACHE MANIFEST + +CACHE: +/ +/favicon.ico \ No newline at end of file diff --git a/preamble.html b/preamble.html new file mode 100644 index 0000000..3f40466 --- /dev/null +++ b/preamble.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/samples/calc.html b/samples/calc.html new file mode 100644 index 0000000..614adb3 --- /dev/null +++ b/samples/calc.html @@ -0,0 +1,15 @@ + +
C

7
8
9
Ă·

4
5
6
Ă—

1
2
3
-

.
0
=
+
+ \ No newline at end of file diff --git a/samples/jabberwocky.html b/samples/jabberwocky.html new file mode 100644 index 0000000..5fab673 --- /dev/null +++ b/samples/jabberwocky.html @@ -0,0 +1,39 @@ +

Jabberwocky

+

+’Twas brillig, and the slithy toves
+Did gyre and gimble in the wabe:
+All mimsy were the borogoves,
+And the mome raths outgrabe. +

+“Beware the Jabberwock, my son!
+The jaws that bite, the claws that catch!
+Beware the Jubjub bird, and shun
+The frumious Bandersnatch!” +

+He took his vorpal sword in hand;
+Long time the manxome foe he sought—
+So rested he by the Tumtum tree
+And stood awhile in thought. +

+And, as in uffish thought he stood,
+The Jabberwock, with eyes of flame,
+Came whiffling through the tulgey wood,
+And burbled as it came! +

+One, two! One, two! And through and through
+The vorpal blade went snicker-snack!
+He left it dead, and with its head
+He went galumphing back. +

+“And hast thou slain the Jabberwock?
+Come to my arms, my beamish boy!
+O frabjous day! Callooh! Callay!”
+He chortled in his joy. +

+’Twas brillig, and the slithy toves
+Did gyre and gimble in the wabe:
+All mimsy were the borogoves,
+And the mome raths outgrabe. +

+Lewis Carroll +

\ No newline at end of file diff --git a/samples/learnmore.html b/samples/learnmore.html new file mode 100644 index 0000000..a7e8b9d --- /dev/null +++ b/samples/learnmore.html @@ -0,0 +1,18 @@ +Itty bitty lets you create tiny sites and apps that are stored in the link itself. To make them, you can edit this text directly, or drag an HTML file in to generate a link. + +

Use it to share poetry, quick reference, tools, and more. + +

When done, you can share these links through email, twitter, domain redirects and many other places you can post a link. When bookmarked on iOS, they work offline. + +

Note: Each medium has a maximum size ranging from 1000 to 10000 characters. + +

+ diff --git a/samples/preamble.html b/samples/preamble.html new file mode 100644 index 0000000..bd03e2a --- /dev/null +++ b/samples/preamble.html @@ -0,0 +1 @@ + \ No newline at end of file