/* ------------------------------------------------------------------------* * Copyright 2013-2014 Arne F. Claassen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *-------------------------------------------------------------------------*/ var Josh = Josh || {}; (function (root, $, _) { $.fn.josh_caretTo = function (index) { return this.queue(function (next) { if (this.createTextRange) { var range = this.createTextRange(); range.move("character", index); range.select(); } else if (this.selectionStart !== null) { this.setSelectionRange(index, index); } next(); }); }; $.fn.josh_caretPosition = function () { var el = this.get(0); if (el.createTextRange) { var range = el.createTextRange(); range.moveStart('character', -el.value.length); return range.text.length; } else if (el.selectionStart !== null) { return el.selectionStart; } return 0; }; var history = Josh.History(); var killring = new Josh.KillRing(); Josh.Input = function (config) { config = config || {}; // instance fields var _console = config.console || (Josh.Debug && root.console ? root.console : { log: function () { } }); var _id = "#" + config.id; var _blinktime = config.blinktime || 500; var _active = false; var _cursor_visible = false; var _isInput = false; var _history = config.history || history; var _killring = config.killring || killring; var _text; var self = { templates: { span: _.template('') }, history: _history, killring: _killring }; $(document).ready(function () { var $input = $(_id); var el = $input.get(0); var readline = new Josh.ReadLine({ history: _history, killring: _killring, console: _console }); self.readline = readline; readline.attach(el); var activate = null; _isInput = $input.is('input'); if (_isInput) { _console.log(_id + ' is an input'); function renderInput(line) { var text = line ? line.text : ''; _text = text; $input.val(text); $input.josh_caretTo(line.cursor); } readline.onChange(renderInput); $input.click(function() { var line = readline.getLine(); line.cursor = $input.josh_caretPosition(); readline.setLine(line); }); activate = function() { // Note: have to re-render with a setTimeout, because on focus, but after the onfocus event is processed, // the input will select all, invalidating our render setTimeout(function() { renderInput(readline.getLine()); }, 0); }; } else { _console.log(_id + ' is a non-input element'); $input.html(self.templates.span()); if(typeof $input.attr('tabindex') === 'undefined') { $input.attr('tabindex',0); } var $left = $input.find('.left'); var $right = $input.find('.right'); var $cursor = $input.find('.cursor'); function renderSpan(line) { var text = line.text || ''; _text = text; var cursorIdx = line.cursor || 0; var left = _.escape(text.substr(0, cursorIdx)).replace(/ /g, ' '); var cursor = text.substr(cursorIdx, 1); var right = _.escape(text.substr(cursorIdx + 1)).replace(/ /g, ' '); $left.html(left); if (!cursor) { $cursor.html(' ').css('textDecoration', 'underline'); } else { $cursor.text(cursor).css('textDecoration', 'underline'); } $right.html(right); } function blinkCursor() { if (!_active) { return; } root.setTimeout(function () { if (!_active) { return; } _cursor_visible = !_cursor_visible; if (_cursor_visible) { $cursor.css('textDecoration', 'underline'); } else { $cursor.css('textDecoration', ''); } blinkCursor(); }, _blinktime); } activate = function () { blinkCursor(); } readline.onChange(renderSpan); } readline.unbind({keyCode: Josh.Keys.Special.Tab}); readline.unbind({'char': 'R', ctrlKey: true}); readline.onActivate(function () { _active = true; activate(); }); readline.onDeactivate(function () { _active = false; if (_text) { _history.accept(_text); } }); }); return self; } })(this, $, _);