UNPKG

gethue

Version:

Hue is an Open source SQL Query Editor for Databases/Warehouses

246 lines (228 loc) 8.18 kB
// Licensed to Cloudera, Inc. under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. Cloudera, Inc. licenses this file // to you 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. import $ from 'jquery'; import * as ko from 'knockout'; import huePubSub from '../../utils/huePubSub'; ko.bindingHandlers.autocomplete = { init: function (element, valueAccessor) { let options = valueAccessor(); const $element = $(element); const getMenuElement = () => { if (typeof options.appendTo === 'string') { return $(options.appendTo); } return options.appendTo; }; const delay = 400; const showSpinner = function () { if (options.showSpinner) { $element.addClass('input-spinner'); } }; let spinThrottle = -1; const hideSpinner = function () { window.clearTimeout(spinThrottle); $element.removeClass('input-spinner'); }; options = $.extend( { addCount: false, closeOnEnter: true, blurOnEnter: false, classPrefix: 'hue-', showOnFocus: false, minLength: 0, limitWidthToInput: false, minWidth: 200, delay: delay, search: function () { window.clearTimeout(spinThrottle); if (!$element.hueAutocomplete('option', 'disabled')) { spinThrottle = window.setTimeout(showSpinner, 50); } }, open: function () { hideSpinner(); }, close: function () { hideSpinner(); } }, options ); if (options.addCount) { const oldSource = options.source; options.source = function (request, callback) { oldSource(request, values => { callback(values); const $menu = $($element.data('custom-hueAutocomplete').menu.element); $menu.children('.autocomplete-count').remove(); const count = options.realCountCallback ? options.realCountCallback() : values.filter(value => { return !value.divider && !value.noMatch; }).length; if (count > 0) { $('<div>') .addClass('autocomplete-count') .text('(' + count + ')') .appendTo(getMenuElement()); } }); }; } if (typeof $().hueAutocomplete === 'undefined') { $.widget('custom.hueAutocomplete', $.ui.autocomplete, { _renderItemData: function (ul, item) { if (item.error && this.options.errorTemplate) { const $li = $( '<li data-bind="template: { name: \'' + this.options.errorTemplate + '\' }">' ) .addClass(this.options.classPrefix + 'autocomplete-item') .appendTo(ul) .data('ui-autocomplete-item', item); ko.applyBindings(item, $li[0]); } else if (item.noMatch && this.options.noMatchTemplate) { const $li = $( '<li data-bind="template: { name: \'' + this.options.noMatchTemplate + '\' }">' ) .addClass(this.options.classPrefix + 'autocomplete-item') .appendTo(ul) .data('ui-autocomplete-item', item); ko.applyBindings(item, $li[0]); } else if (item.divider) { $('<li></li>') .addClass(this.options.classPrefix + 'autocomplete-divider') .appendTo(ul); } else { const $li = $( '<li data-bind="template: { name: \'' + this.options.itemTemplate + '\', data: $data }">' ) .addClass(this.options.classPrefix + 'autocomplete-item') .appendTo(ul) .data('ui-autocomplete-item', item); ko.applyBindings(item.data, $li[0]); } }, _resizeMenu: function () { // This overrides the default behaviour of using dropdown width of the same size as input autocomplete box if (options.limitWidthToInput) { this.menu.element.outerWidth(options.minWidth); } }, _renderMenu: function (ul, items) { const self = this; hideSpinner(); if (options.limitWidthToInput) { ul.css('max-width', Math.max(options.minWidth, $element.outerWidth(true)) + 'px'); } ul.css('min-width', options.minWidth || $element.outerWidth(true)); ul.css('min-height', options.minHeight || '20px'); ul.addClass(this.options.classPrefix + 'autocomplete'); $.each(items, (index, item) => { self._renderItemData(ul, item); }); } }); } if (options.closeOnEnter || options.onEnter || options.blurOnEnter) { $element.on('keyup', e => { if (e.which === 13) { if (options.reopenPattern && options.reopenPattern.test($element.val())) { window.setTimeout(() => { $element.hueAutocomplete('search', $element.val()); }, 0); return; } if (options.closeOnEnter) { hideSpinner(); $element.hueAutocomplete('close'); // Prevent autocomplete on enter $element.hueAutocomplete('option', 'disabled', true); window.setTimeout(() => { $element.hueAutocomplete('option', 'disabled', false); }, delay + 200); } if (options.valueObservable) { options.valueObservable($element.val()); } if (options.onEnter) { options.onEnter(); } if (options.blurOnEnter) { hideSpinner(); $element.blur(); } } }); } $element.on('keydown', e => { // ctrl + backspace to delete words if (e.which === 8 && e.ctrlKey) { const lastSpaceOrColon = Math.max( $element.val().lastIndexOf(' '), $element.val().lastIndexOf(':') ); if (lastSpaceOrColon < $element.val().length - 1) { if (lastSpaceOrColon !== -1) { $element.val($element.val().substring(0, lastSpaceOrColon + 1)); } else { $element.val(''); } e.preventDefault(); return false; } } else if (e.which === 32 && e.ctrlKey) { $element.hueAutocomplete('search', $element.val()); } }); if (options.showOnFocus) { $element.on('focus', () => { $element.hueAutocomplete('search', $element.val()); }); } const closeSubscription = huePubSub.subscribe('autocomplete.close', () => { hideSpinner(); $element.hueAutocomplete('close'); }); ko.utils.domNodeDisposal.addDisposeCallback(element, () => { closeSubscription.remove(); }); if (options.reopenPattern || options.valueObservable || options.onSelect) { const oldSelect = options.select; options.select = function (event, ui) { if (options.reopenPattern && options.reopenPattern.test(ui.item.value)) { window.setTimeout(() => { $element.hueAutocomplete('search', $element.val()); }, 0); return; } if (options.valueObservable) { options.valueObservable(ui.item.value); } if (options.onSelect) { options.onSelect(ui.item); } if (oldSelect) { oldSelect(event, ui); } }; } $element.hueAutocomplete(options); } };