diff --git a/app/assets/javascripts/app/lib/base/jquery.contenteditable.js b/app/assets/javascripts/app/lib/base/jquery.contenteditable.js index 85618ba36..cc4139e3e 100644 --- a/app/assets/javascripts/app/lib/base/jquery.contenteditable.js +++ b/app/assets/javascripts/app/lib/base/jquery.contenteditable.js @@ -66,402 +66,406 @@ this.browserMagicKey = App.Browser.magicKey() this.browserHotkeys = App.Browser.hotkeys() - this.init(); + this.init() } Plugin.prototype.init = function () { - var _this = this + this.bindEvents() + } - this.toggleBlock = function(tag) { - sel = window.getSelection() - node = $(sel.anchorNode) - if (node.is(tag) || node.parent().is(tag) || node.parent().parent().is(tag)) { - document.execCommand('formatBlock', false, 'div') - //document.execCommand('RemoveFormat') + Plugin.prototype.bindEvents = function () { + this.$element.on('keydown', this.onKeydown.bind(this)) + this.$element.on('paste', this.onPaste.bind(this)) + this.$element.on('dragover', this.onDragover.bind(this)) + this.$element.on('drop', this.onDrop.bind(this)) + } + + Plugin.prototype.toggleBlock = function(tag) { + sel = window.getSelection() + node = $(sel.anchorNode) + if (node.is(tag) || node.parent().is(tag) || node.parent().parent().is(tag)) { + document.execCommand('formatBlock', false, 'div') + //document.execCommand('RemoveFormat') + } + else { + document.execCommand('formatBlock', false, tag) + } + } + + Plugin.prototype.onKeydown = function (e) { + this.log('keydown', e.keyCode) + if (this.preventInput) { + this.log('preventInput', this.preventInput) + return + } + + // strap the return key being pressed + if (e.keyCode === 13) { + + // disbale multi line + if (!this.options.multiline) { + e.preventDefault() + return } - else { - document.execCommand('formatBlock', false, tag) + + // break
after enter on empty line + sel = window.getSelection() + if (sel) { + node = $(sel.anchorNode) + if (node && node.parent() && node.parent().is('blockquote')) { + e.preventDefault() + document.execCommand('Insertparagraph') + document.execCommand('Outdent') + return + } + } + + // behavior to enter new line on alt+enter + // on alt + enter not realy newline is fired, to make + // it compat. to other systems, do it here + if (!e.shiftKey && e.altKey && !e.ctrlKey && !e.metaKey) { + e.preventDefault() + this.paste('
') + return } } - // handle enter - this.$element.on('keydown', function (e) { - _this.log('keydown', e.keyCode) - if (_this.preventInput) { - this.log('preventInput', _this.preventInput) - return + // on zammad magicKey + i/b/u/s + // hotkeys + u -> Toggles the current selection between underlined and not underlined + // hotkeys + b -> Toggles the current selection between bold and non-bold + // hotkeys + i -> Toggles the current selection between italic and non-italic + // hotkeys + v -> Toggles the current selection between strike and non-strike + // hotkeys + f -> Removes the formatting tags from the current selection + // hotkeys + y -> Removes the formatting from while textarea + // hotkeys + z -> Inserts a Horizontal Rule + // hotkeys + l -> Toggles the text selection between an unordered list and a normal block + // hotkeys + k -> Toggles the text selection between an ordered list and a normal block + // hotkeys + o -> Draws a line through the middle of the current selection + // hotkeys + w -> Removes any hyperlink from the current selection + var richtTextControl = false + if (this.browserMagicKey == 'cmd') { + if (!e.altKey && !e.ctrlKey && e.metaKey) { + richtTextControl = true } - - // strap the return key being pressed - if (e.keyCode === 13) { - - // disbale multi line - if (!_this.options.multiline) { - e.preventDefault() - return - } - - // breakafter enter on empty line - sel = window.getSelection() - if (sel) { - node = $(sel.anchorNode) - if (node && node.parent() && node.parent().is('blockquote')) { - e.preventDefault() - document.execCommand('Insertparagraph') - document.execCommand('Outdent') - return - } - } - - // behavior to enter new line on alt+enter - // on alt + enter not realy newline is fired, to make - // it compat. to other systems, do it here - if (!e.shiftKey && e.altKey && !e.ctrlKey && !e.metaKey) { - e.preventDefault() - _this.paste('
') - return - } + } + else { + if (!e.altKey && e.ctrlKey && !e.metaKey) { + richtTextControl = true } - - // on zammad magicKey + i/b/u/s - // hotkeys + u -> Toggles the current selection between underlined and not underlined - // hotkeys + b -> Toggles the current selection between bold and non-bold - // hotkeys + i -> Toggles the current selection between italic and non-italic - // hotkeys + v -> Toggles the current selection between strike and non-strike - // hotkeys + f -> Removes the formatting tags from the current selection - // hotkeys + y -> Removes the formatting from while textarea - // hotkeys + z -> Inserts a Horizontal Rule - // hotkeys + l -> Toggles the text selection between an unordered list and a normal block - // hotkeys + k -> Toggles the text selection between an ordered list and a normal block - // hotkeys + o -> Draws a line through the middle of the current selection - // hotkeys + w -> Removes any hyperlink from the current selection - var richtTextControl = false - if (_this.browserMagicKey == 'cmd') { - if (!e.altKey && !e.ctrlKey && e.metaKey) { - richtTextControl = true - } - } - else { - if (!e.altKey && e.ctrlKey && !e.metaKey) { - richtTextControl = true - } - } - if (richtTextControl && _this.options.richTextFormatKey[ e.keyCode ]) { - e.preventDefault() - if (e.keyCode == 66) { - document.execCommand('bold') - return true - } - if (e.keyCode == 73) { - document.execCommand('italic') - return true - } - if (e.keyCode == 85) { - document.execCommand('underline') - return true - } - if (e.keyCode == 83) { - document.execCommand('strikeThrough') - return true - } - } - - var hotkeys = false - if (_this.browserHotkeys == 'ctrl+shift') { - if (!e.altKey && e.ctrlKey && !e.metaKey && e.shiftKey) { - hotkeys = true - } - } - else { - if (e.altKey && e.ctrlKey && !e.metaKey) { - hotkeys = true - } - } - - if (hotkeys && (_this.options.richTextFormatKey[ e.keyCode ] - || e.keyCode == 49 - || e.keyCode == 50 - || e.keyCode == 51 - || e.keyCode == 66 - || e.keyCode == 70 - || e.keyCode == 90 - || e.keyCode == 70 - || e.keyCode == 73 - || e.keyCode == 75 - || e.keyCode == 76 - || e.keyCode == 85 - || e.keyCode == 86 - || e.keyCode == 88 - || e.keyCode == 90 - || e.keyCode == 89)) { - e.preventDefault() - - // disable rich text b/u/i - if ( _this.options.mode === 'textonly' ) { - return - } - - if (e.keyCode == 49) { - _this.toggleBlock('h1') - } - if (e.keyCode == 50) { - _this.toggleBlock('h2') - } - if (e.keyCode == 51) { - _this.toggleBlock('h3') - } - if (e.keyCode == 66) { - document.execCommand('bold') - } - if (e.keyCode == 70) { - document.execCommand('removeFormat') - } - if (e.keyCode == 73) { - document.execCommand('italic') - } - if (e.keyCode == 75) { - document.execCommand('insertOrderedList') - } - if (e.keyCode == 76) { - document.execCommand('insertUnorderedList') - } - if (e.keyCode == 85) { - document.execCommand('underline') - } - if (e.keyCode == 86) { - document.execCommand('strikeThrough') - } - if (e.keyCode == 88) { - document.execCommand('unlink') - } - if (e.keyCode == 89) { - var cleanHtml = App.Utils.htmlRemoveRichtext(_this.$element.html()) - _this.$element.html(cleanHtml) - } - if (e.keyCode == 90) { - document.execCommand('insertHorizontalRule') - } - _this.log('content editable richtext key', e.keyCode) + } + if (richtTextControl && this.options.richTextFormatKey[ e.keyCode ]) { + e.preventDefault() + if (e.keyCode == 66) { + document.execCommand('bold') return true } - - // limit check - if ( !_this.allowKey(e) ) { - if ( !_this.maxLengthOk(1) ) { - e.preventDefault() - return - } + if (e.keyCode == 73) { + document.execCommand('italic') + return true } - }) + if (e.keyCode == 85) { + document.execCommand('underline') + return true + } + if (e.keyCode == 83) { + document.execCommand('strikeThrough') + return true + } + } - // just paste text - this.$element.on('paste', function (e) { + var hotkeys = false + if (this.browserHotkeys == 'ctrl+shift') { + if (!e.altKey && e.ctrlKey && !e.metaKey && e.shiftKey) { + hotkeys = true + } + } + else { + if (e.altKey && e.ctrlKey && !e.metaKey) { + hotkeys = true + } + } + + if (hotkeys && (this.options.richTextFormatKey[ e.keyCode ] + || e.keyCode == 49 + || e.keyCode == 50 + || e.keyCode == 51 + || e.keyCode == 66 + || e.keyCode == 70 + || e.keyCode == 90 + || e.keyCode == 70 + || e.keyCode == 73 + || e.keyCode == 75 + || e.keyCode == 76 + || e.keyCode == 85 + || e.keyCode == 86 + || e.keyCode == 88 + || e.keyCode == 90 + || e.keyCode == 89)) { e.preventDefault() - _this.log('paste') - // insert and in case, resize images - var clipboardData - if (e.clipboardData) { // ie - clipboardData = e.clipboardData - } - else if (window.clipboardData) { // ie - clipboardData = window.clipboardData - } - else if (e.originalEvent.clipboardData) { // other browsers - clipboardData = e.originalEvent.clipboardData - } - else { - throw "No clipboardData support" - } - - if (clipboardData && clipboardData.items && clipboardData.items[0]) { - var imageInserted = false - var item = clipboardData.items[0] - if (item.kind == 'file' && (item.type == 'image/png' || item.type == 'image/jpeg')) { - _this.log('paste image', item) - console.log(item) - - var imageFile = item.getAsFile() - var reader = new FileReader() - - reader.onload = function (e) { - var result = e.target.result - var img = document.createElement('img') - img.src = result - maxWidth = _this.$element.width() || 500 - scaleFactor = 2 - //scaleFactor = 1 - //if (window.isRetina && window.isRetina()) { - // scaleFactor = 2 - //} - - insert = function(dataUrl, width, height, isResized) { - //console.log('dataUrl', dataUrl) - //console.log('scaleFactor', scaleFactor, isResized, maxWidth, width, height) - _this.log('image inserted') - result = dataUrl - if (_this.options.imageWidth == 'absolute') { - img = "" - } - else { - img = "" - } - _this.paste(img) - } - - // resize if to big - App.ImageService.resize(img.src, maxWidth, 'auto', scaleFactor, 'image/jpeg', 'auto', insert) - } - reader.readAsDataURL(imageFile) - imageInserted = true - } - } - if (imageInserted) { + // disable rich text b/u/i + if ( this.options.mode === 'textonly' ) { return } - // check existing + paste text for limit - var text, docType - try { - text = clipboardData.getData('text/html') - docType = 'html' - if (!text || text.length === 0) { - docType = 'text' - text = clipboardData.getData('text/plain') - } - if (!text || text.length === 0) { - docType = 'text2' - text = clipboardData.getData('text') - } + if (e.keyCode == 49) { + this.toggleBlock('h1') } - catch (e) { - console.log('Sorry, can\'t insert markup because browser is not supporting it.') - docType = 'text3' - text = clipboardData.getData('text') + if (e.keyCode == 50) { + this.toggleBlock('h2') } - _this.log('paste', docType, text) - - if (docType == 'html') { - if (_this.options.mode === 'textonly') { - if (!_this.options.multiline) { - text = App.Utils.htmlRemoveTags(text) - _this.log('htmlRemoveTags', text) - } - else { - _this.log('htmlRemoveRichtext', text) - text = App.Utils.htmlRemoveRichtext(text) - } - } - else { - _this.log('htmlCleanup', text) - text = App.Utils.htmlCleanup(text) - } - text = text.html() - _this.log('text.html()', text) - - // as fallback, take text - if (!text) { - text = App.Utils.text2html(text.text()) - _this.log('text2html', text) - } + if (e.keyCode == 51) { + this.toggleBlock('h3') } - else { - text = App.Utils.text2html(text) - _this.log('text2html', text) + if (e.keyCode == 66) { + document.execCommand('bold') } - - if (!_this.maxLengthOk(text.length)) { - return + if (e.keyCode == 70) { + document.execCommand('removeFormat') } - - // cleanup - text = App.Utils.removeEmptyLines(text) - _this.log('insert', text) - - _this.paste(text) + if (e.keyCode == 73) { + document.execCommand('italic') + } + if (e.keyCode == 75) { + document.execCommand('insertOrderedList') + } + if (e.keyCode == 76) { + document.execCommand('insertUnorderedList') + } + if (e.keyCode == 85) { + document.execCommand('underline') + } + if (e.keyCode == 86) { + document.execCommand('strikeThrough') + } + if (e.keyCode == 88) { + document.execCommand('unlink') + } + if (e.keyCode == 89) { + var cleanHtml = App.Utils.htmlRemoveRichtext(this.$element.html()) + this.$element.html(cleanHtml) + } + if (e.keyCode == 90) { + document.execCommand('insertHorizontalRule') + } + this.log('content editable richtext key', e.keyCode) return true - }) + } - this.$element.on('dragover', function (e) { - e.stopPropagation() - e.preventDefault() - _this.log('dragover') - }) - - this.$element.on('drop', function (e) { - e.stopPropagation(); - e.preventDefault(); - _this.log('drop') - - var dataTransfer - if (window.dataTransfer) { // ie - dataTransfer = window.dataTransfer - } - else if (e.originalEvent.dataTransfer) { // other browsers - dataTransfer = e.originalEvent.dataTransfer - } - else { - throw "No clipboardData support" + // limit check + if ( !this.allowKey(e) ) { + if ( !this.maxLengthOk(1) ) { + e.preventDefault() + return } + } + } - // x and y coordinates of dropped item - x = e.clientX - y = e.clientY - var file = dataTransfer.files[0] + Plugin.prototype.onPaste = function (e) { + e.preventDefault() + this.log('paste') - // look for images - if (file.type.match('image.*')) { + // insert and in case, resize images + var clipboardData + if (e.clipboardData) { // ie + clipboardData = e.clipboardData + } + else if (window.clipboardData) { // ie + clipboardData = window.clipboardData + } + else if (e.originalEvent.clipboardData) { // other browsers + clipboardData = e.originalEvent.clipboardData + } + else { + throw "No clipboardData support" + } + + if (clipboardData && clipboardData.items && clipboardData.items[0]) { + var imageInserted = false + var item = clipboardData.items[0] + if (item.kind == 'file' && (item.type == 'image/png' || item.type == 'image/jpeg')) { + this.log('paste image', item) + console.log(item) + + var imageFile = item.getAsFile() var reader = new FileReader() - reader.onload = (function(e) { + + reader.onload = function (e) { var result = e.target.result var img = document.createElement('img') img.src = result - maxWidth = _this.$element.width() || 500 + maxWidth = this.$element.width() || 500 scaleFactor = 2 //scaleFactor = 1 //if (window.isRetina && window.isRetina()) { // scaleFactor = 2 //} - //Insert the image at the carat insert = function(dataUrl, width, height, isResized) { - //console.log('dataUrl', dataUrl) //console.log('scaleFactor', scaleFactor, isResized, maxWidth, width, height) - _this.log('image inserted') + this.log('image inserted') result = dataUrl - if (_this.options.imageWidth == 'absolute') { - img = $("") + if (this.options.imageWidth == 'absolute') { + img = "" } else { - img = $("") - } - img = img.get(0) - - if (document.caretPositionFromPoint) { - var pos = document.caretPositionFromPoint(x, y) - range = document.createRange(); - range.setStart(pos.offsetNode, pos.offset) - range.collapse() - range.insertNode(img) - } - else if (document.caretRangeFromPoint) { - range = document.caretRangeFromPoint(x, y) - range.insertNode(img) - } - else { - console.log('could not find carat') + img = "" } + this.paste(img) } // resize if to big App.ImageService.resize(img.src, maxWidth, 'auto', scaleFactor, 'image/jpeg', 'auto', insert) - }) - reader.readAsDataURL(file) + } + reader.readAsDataURL(imageFile) + imageInserted = true } - }) + } + if (imageInserted) { + return + } + // check existing + paste text for limit + var text, docType + try { + text = clipboardData.getData('text/html') + docType = 'html' + if (!text || text.length === 0) { + docType = 'text' + text = clipboardData.getData('text/plain') + } + if (!text || text.length === 0) { + docType = 'text2' + text = clipboardData.getData('text') + } + } + catch (e) { + console.log('Sorry, can\'t insert markup because browser is not supporting it.') + docType = 'text3' + text = clipboardData.getData('text') + } + this.log('paste', docType, text) + + if (docType == 'html') { + if (this.options.mode === 'textonly') { + if (!this.options.multiline) { + text = App.Utils.htmlRemoveTags(text) + this.log('htmlRemoveTags', text) + } + else { + this.log('htmlRemoveRichtext', text) + text = App.Utils.htmlRemoveRichtext(text) + } + } + else { + this.log('htmlCleanup', text) + text = App.Utils.htmlCleanup(text) + } + text = text.html() + this.log('text.html()', text) + + // as fallback, take text + if (!text) { + text = App.Utils.text2html(text.text()) + this.log('text2html', text) + } + } + else { + text = App.Utils.text2html(text) + this.log('text2html', text) + } + + if (!this.maxLengthOk(text.length)) { + return + } + + // cleanup + text = App.Utils.removeEmptyLines(text) + this.log('insert', text) + + this.paste(text) + return true + } + + Plugin.prototype.onDragover = function (e) { + e.stopPropagation() + e.preventDefault() + this.log('dragover') + } + + Plugin.prototype.onDrop = function (e) { + e.stopPropagation(); + e.preventDefault(); + this.log('drop') + + var dataTransfer + if (window.dataTransfer) { // ie + dataTransfer = window.dataTransfer + } + else if (e.originalEvent.dataTransfer) { // other browsers + dataTransfer = e.originalEvent.dataTransfer + } + else { + throw "No clipboardData support" + } + + // x and y coordinates of dropped item + x = e.clientX + y = e.clientY + var file = dataTransfer.files[0] + + // look for images + if (file.type.match('image.*')) { + var reader = new FileReader() + reader.onload = (function(e) { + var result = e.target.result + var img = document.createElement('img') + img.src = result + maxWidth = this.$element.width() || 500 + scaleFactor = 2 + //scaleFactor = 1 + //if (window.isRetina && window.isRetina()) { + // scaleFactor = 2 + //} + + //Insert the image at the carat + insert = function(dataUrl, width, height, isResized) { + + //console.log('dataUrl', dataUrl) + //console.log('scaleFactor', scaleFactor, isResized, maxWidth, width, height) + this.log('image inserted') + result = dataUrl + if (this.options.imageWidth == 'absolute') { + img = $("") + } + else { + img = $("") + } + img = img.get(0) + + if (document.caretPositionFromPoint) { + var pos = document.caretPositionFromPoint(x, y) + range = document.createRange(); + range.setStart(pos.offsetNode, pos.offset) + range.collapse() + range.insertNode(img) + } + else if (document.caretRangeFromPoint) { + range = document.caretRangeFromPoint(x, y) + range.insertNode(img) + } + else { + console.log('could not find carat') + } + } + + // resize if to big + App.ImageService.resize(img.src, maxWidth, 'auto', scaleFactor, 'image/jpeg', 'auto', insert) + }) + reader.readAsDataURL(file) + } } // check if key is allowed, even if length limit is reached diff --git a/app/assets/javascripts/app/lib/base/jquery.textmodule.js b/app/assets/javascripts/app/lib/base/jquery.textmodule.js index 40b95fffe..377461abf 100644 --- a/app/assets/javascripts/app/lib/base/jquery.textmodule.js +++ b/app/assets/javascripts/app/lib/base/jquery.textmodule.js @@ -34,160 +34,163 @@ this.ce = $.data(element, 'plugin_ce') } - this.init(); + this.init() } Plugin.prototype.init = function () { this.renderBase() - var _this = this + this.bindEvents() + } - this.$element.on('keydown', function (e) { + Plugin.prototype.bindEvents = function () { + this.$element.on('keydown', this.onKeydown.bind(this)) + this.$element.on('keypress', this.onKeypress.bind(this)) + this.$element.on('focus', this.onFocus.bind(this)) + } - // navigate through item - if (_this.isActive()) { + Plugin.prototype.onFocus = function (e) { + this.close() + } - // esc - if (e.keyCode === 27) { - e.preventDefault() - e.stopPropagation() - _this.close() - return - } - - // enter - if (e.keyCode === 13) { - e.preventDefault() - e.stopPropagation() - var id = _this.$widget.find('.dropdown-menu li.is-active').data('id') - - // as fallback use hovered element - if (!id) { - id = _this.$widget.find('.dropdown-menu li:hover').data('id') - } - - // as fallback first element - if (!id) { - id = _this.$widget.find('.dropdown-menu li:first-child').data('id') - } - _this.take(id) - return - } - - // arrow keys left/right - if (e.keyCode === 37 || e.keyCode === 39) { - e.preventDefault() - e.stopPropagation() - return - } - - // up or down - if (e.keyCode === 38 || e.keyCode === 40) { - e.preventDefault() - e.stopPropagation() - var active = _this.$widget.find('.dropdown-menu li.is-active') - active.removeClass('is-active') - - if (e.keyCode == 38 && active.prev().size()) { - active = active.prev() - } - else if (e.keyCode == 40 && active.next().size()) { - active = active.next() - } - - active.addClass('is-active') - - var menu = _this.$widget.find('.dropdown-menu') - - if (!active.get(0)) { - return - } - if (active.position().top < 0) { - // scroll up - menu.scrollTop( menu.scrollTop() + active.position().top ) - } - else if ( active.position().top + active.height() > menu.height() ) { - // scroll down - var invisibleHeight = active.position().top + active.height() - menu.height() - menu.scrollTop( menu.scrollTop() + invisibleHeight ) - } - } - } + Plugin.prototype.onKeydown = function (e) { + console.log("onKeydown", this.isActive()) + // navigate through item + if (this.isActive()) { // esc if (e.keyCode === 27) { - _this.close() + e.preventDefault() + e.stopPropagation() + this.close() + return } - }) - - // reduce buffer, in case close it - this.$element.on('keydown', function (e) { - - // backspace - if (e.keyCode === 8 && _this.buffer) { - - // backspace + buffer === :: -> close textmodule - if (_this.buffer === '::') { - _this.close(true) - e.preventDefault() - return - } - - // reduce buffer and show new result - var length = _this.buffer.length - _this.buffer = _this.buffer.substr(0, length-1) - _this.log('BS backspace', _this.buffer) - _this.result(_this.buffer.substr(2, length-1)) - } - }) - - // build buffer - this.$element.on('keypress', function (e) { - _this.log('BUFF', _this.buffer, e.keyCode, String.fromCharCode(e.which)) - - // shift - if (e.keyCode === 16) return // enter - if (e.keyCode === 13) return + if (e.keyCode === 13) { + e.preventDefault() + e.stopPropagation() + var id = this.$widget.find('.dropdown-menu li.is-active').data('id') - // arrow keys - if (e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40) return - - // observer other second key - if (_this.buffer === ':' && String.fromCharCode(e.which) !== ':') { - _this.buffer = '' - } - - // oberserve second : - if (_this.buffer === ':' && String.fromCharCode(e.which) === ':') { - _this.buffer = _this.buffer + ':' - } - - // oberserve first : - if (!_this.buffer && String.fromCharCode(e.which) === ':') { - _this.buffer = _this.buffer + ':' - } - - if (_this.buffer && _this.buffer.substr(0,2) === '::') { - - var sign = String.fromCharCode(e.which) - if ( sign && sign !== ':' && e.which != 8 ) { // 8 == backspace - _this.buffer = _this.buffer + sign - //_this.log('BUFF ADD', sign, this.buffer, sign.length, e.which) - } - _this.log('BUFF HINT', _this.buffer, _this.buffer.length, e.which, String.fromCharCode(e.which)) - - if (!_this.isActive()) { - _this.open() + // as fallback use hovered element + if (!id) { + id = this.$widget.find('.dropdown-menu li:hover').data('id') } - _this.result(_this.buffer.substr(2, _this.buffer.length)) + // as fallback first element + if (!id) { + id = this.$widget.find('.dropdown-menu li:first-child').data('id') + } + this.take(id) + return } - }).on('focus', function (e) { - _this.close() - }) - }; + // arrow keys left/right + if (e.keyCode === 37 || e.keyCode === 39) { + e.preventDefault() + e.stopPropagation() + return + } + + // up or down + if (e.keyCode === 38 || e.keyCode === 40) { + e.preventDefault() + e.stopPropagation() + var active = this.$widget.find('.dropdown-menu li.is-active') + active.removeClass('is-active') + + if (e.keyCode == 38 && active.prev().size()) { + active = active.prev() + } + else if (e.keyCode == 40 && active.next().size()) { + active = active.next() + } + + active.addClass('is-active') + + var menu = this.$widget.find('.dropdown-menu') + + if (!active.get(0)) { + return + } + if (active.position().top < 0) { + // scroll up + menu.scrollTop( menu.scrollTop() + active.position().top ) + } + else if ( active.position().top + active.height() > menu.height() ) { + // scroll down + var invisibleHeight = active.position().top + active.height() - menu.height() + menu.scrollTop( menu.scrollTop() + invisibleHeight ) + } + } + } + + // esc + if (e.keyCode === 27) { + this.close() + } + + // reduce buffer, in case close it + // backspace + if (e.keyCode === 8 && this.buffer) { + + // backspace + buffer === :: -> close textmodule + if (this.buffer === '::') { + this.close(true) + e.preventDefault() + return + } + + // reduce buffer and show new result + var length = this.buffer.length + this.buffer = this.buffer.substr(0, length-1) + this.log('BS backspace', this.buffer) + this.result(this.buffer.substr(2, length-1)) + } + } + + Plugin.prototype.onKeypress = function (e) { + this.log('BUFF', this.buffer, e.keyCode, String.fromCharCode(e.which)) + + // shift + if (e.keyCode === 16) return + + // enter + if (e.keyCode === 13) return + + // arrow keys + if (e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40) return + + // observer other second key + if (this.buffer === ':' && String.fromCharCode(e.which) !== ':') { + this.buffer = '' + } + + // oberserve second : + if (this.buffer === ':' && String.fromCharCode(e.which) === ':') { + this.buffer = this.buffer + ':' + } + + // oberserve first : + if (!this.buffer && String.fromCharCode(e.which) === ':') { + this.buffer = this.buffer + ':' + } + + if (this.buffer && this.buffer.substr(0,2) === '::') { + + var sign = String.fromCharCode(e.which) + if ( sign && sign !== ':' && e.which != 8 ) { // 8 == backspace + this.buffer = this.buffer + sign + //this.log('BUFF ADD', sign, this.buffer, sign.length, e.which) + } + this.log('BUFF HINT', this.buffer, this.buffer.length, e.which, String.fromCharCode(e.which)) + + if (!this.isActive()) { + this.open() + } + + this.result(this.buffer.substr(2, this.buffer.length)) + } + } // create base template Plugin.prototype.renderBase = function() {