Permalink
Browse files

fix: assitive keyboard

A dynamic keyboard that sits at the base of the screen that can trigger emmet and code completion on mobile, along with some custom mappings.
  • Loading branch information...
1 parent 74525e9 commit 4311ad3cb5d4c5cff98a2307a464d0fcad4268b6 @remy remy committed Aug 3, 2016
View
@@ -249,10 +249,50 @@
position: fixed;
bottom: 0;
width: 100%;
- height: 44px;
+ height: 54px;
background: #eee;
z-index: 10;
- overflow: scroll;
+ line-height: 57px;
+ /* padding: 5px; */
+ padding-left: 0;
+ }
+
+ #strip > div {
+ overflow-x: scroll;
+ white-space: nowrap;
+ overflow-y: hidden;
+ }
+
+ #strip:before {
+ position: absolute;
+ content: ' ';
+ box-shadow: 0 0 20px 3px rgba(0,0,0,.15);
+ right: 0;
+ width: 0px;
+ height: 100%;
+ top: 10px;
+ }
+
+ #strip div:after {
+ content: ' ';
+ width: 5px;
+ display: inline-block;
+ position: relative;
+ right: 0;
+ }
+
+ #strip button {
+ box-sizing: border-box;
+ font-family: SourceCodeProRegular, Monaco, consolas, monospace;
+ font-size: 18px;
+ background: #ccc;
+ border: 0;
+ border-radius: 3px;
+ height: 44px;
+ min-width: 44px;
+ margin: 5px;
+ padding: 5px;
+ display: inline-block;
}
}
@@ -269,7 +309,16 @@
}
.mobile .editbox textarea {
- padding-bottom: 70%;
+ bottom: 0;
+ position: absolute;
+ top: 0;
+ height: auto;
+ }
+
+ .mobile .editbox > div {
+ padding-bottom: 50%;
+ position: relative;
+ height: 100%;
}
#source {
@@ -294,6 +343,12 @@
#history {
top: 0;
}
+
+ .mobile .editbox {
+ bottom: 54px;
+ overflow: scroll;
+ /* position: relative; */
+ }
}
@media only screen and (max-width: 320px) {
@@ -0,0 +1,57 @@
+var commandMaps = [
+ {
+ value: '',
+ callback: function () { return this.complete(); }
+ },
+ {
+ value: '{$0}',
+ panel: 'css',
+ callback: function () {
+ return '{\n $0\n}';
+ },
+ },
+ {
+ value: 'fn',
+ callback: () => 'function $0() {\n $1\n}',
+ panel: ['js', 'console']
+ },
+ {
+ value: 'log',
+ callback: () => 'console.log($0)',
+ panel: 'js',
+ },
+ {
+ value: '<$0',
+ panel: 'html',
+ },
+ {
+ value: '>$0',
+ panel: 'html',
+ },
+ {
+ value: '</>',
+ callback: function () { return this.close('>'); },
+ panel: 'html',
+ },
+ {
+ value: '="$0"',
+ panel: 'html',
+ },
+ {
+ value: '&rarr;|',
+ callback: function () {
+ return ' $0';
+ },
+ },
+ {
+ value: ': "$0";',
+ panel: 'css',
+ },
+];
+
+
+/**
+ * Notes
+ *
+ * - Undo isn't really possible. I tried it. It was terrible.
+ */
@@ -0,0 +1,146 @@
+(function () {
+ /* globals jsbin, $, escapeHTML, $document, editors, commandMaps */
+ if (!jsbin.mobile) {
+ return;
+ }
+
+ var getCursor = function (field) {
+ if (field.selectionStart) {
+ return field.selectionStart;
+ }
+ if (field.createTextRange) {
+ var range = field.createTextRange();
+ return range.startOffset;
+ }
+ };
+
+ var getTA = function () {
+ return jsbin.panels.focused.editor.textarea;
+ };
+
+ var mobileUtils = {
+ next: function () {
+
+ },
+ close: function (needle) {
+ var ta = getTA();
+ var pos = getCursor(ta);
+ // look backwards
+ var tagposition = ta.value.substring(0, pos).lastIndexOf(needle);
+ if (needle === '>') {
+ var start = 0;
+ while (start > -1) {
+ start = ta.value.substring(0, tagposition).lastIndexOf('<') + 1;
+ var c = ta.value.substr(start, 1);
+ if (c === '/') {
+ // we've got another closing tag, move back
+ var matched = ta.value.substr(start + 1, ta.value.substr(start).indexOf('>') - 1);
+ tagposition = ta.value.lastIndexOf('<' + matched);
+ continue;
+ }
+
+ if (c === '!') {
+ return '';
+ }
+
+ if (start === 0) {
+ return '';
+ }
+ break;
+ }
+
+ var tail = ta.value.substr(start, tagposition).indexOf(needle);
+ return '</' + ta.value.substr(start, tail) + '>$0';
+ }
+ },
+ complete: function () {
+ var focused = jsbin.panels.focused;
+ if (focused.id === 'html' || focused.id === 'css') {
+ CodeMirror.commands['emmet.expand_abbreviation_with_tab'].call(null, focused.editor);
+ } else {
+ CodeMirror.commands.autocomplete(focused.editor);
+ }
+ focused.editor.focus();
+ },
+ };
+
+ var buttons = {
+ html: $(),
+ css: $(),
+ js: $(),
+ console: $(),
+ all: $(),
+ };
+
+ var makeCommand = function (command) {
+ var button = $('<button>');
+ var toinsert = command.value;
+ var label = command.value.replace(/\$0/, '');
+ if (!command.callback) {
+ command.callback = function () {
+ return toinsert;
+ };
+ }
+
+ button.on('click', function () {
+ var focused = jsbin.panels.focused;
+ if (focused.editor) {
+ var pos = focused.editor.getCursor();
+ var value = (command.callback.call(mobileUtils) || '');
+ if (value === null) {
+ return;
+ }
+ var resetTo = value.indexOf('$0');
+ if (resetTo === -1) {
+ resetTo = 0;
+ }
+ var offset = focused.editor.cursorPosition().character + resetTo;
+ if (pos !== -1) {
+ value = value.replace('$0', '');
+ }
+ focused.editor.replaceRange(value, pos, pos);
+ focused.editor.setCursor(offset);
+
+ focused.editor.textarea.focus();
+ } else if (focused.id === 'console') {
+ focused.setCursorTo(command.callback().replace('\$0', ''), true);
+ focused.$el.click();
+ }
+ });
+
+ button.html(escapeHTML(label));
+ strip.find('div').append(button);
+
+ if (command.panel) {
+ if (typeof command.panel === 'string') {
+ buttons[command.panel] = buttons[command.panel].add(button);
+ } else {
+ command.panel.forEach(function (p) {
+ buttons[p] = buttons[p].add(button);
+ });
+ }
+ buttons.all = buttons.all.add(button);
+ }
+ };
+
+ var strip = $('<div id="strip"><div class="inner-strip"></div></div>');
+
+ commandMaps.map(makeCommand);
+
+ $('body').append(strip);
+
+ var hideAll = function (panel) {
+ return function () {
+ buttons.all.hide();
+ buttons[panel].show();
+ };
+ };
+
+ $document.on('jsbinReady', function () {
+ // hook up which buttons should be shown and when
+ editors.html.on('show', hideAll('html'));
+ editors.css.on('show', hideAll('css'));
+ editors.javascript.on('show', hideAll('js'));
+ editors.console.on('show', hideAll('console'))
+ });
+})();
Oops, something went wrong.

0 comments on commit 4311ad3

Please sign in to comment.