gethue
Version:
Hue is an Open source SQL Query Editor for Databases/Warehouses
250 lines (220 loc) • 7.96 kB
JavaScript
// 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 I18n from '../../utils/i18n';
ko.bindingHandlers.tagEditor = {
init: function (element, valueAccessor) {
let options = valueAccessor();
const $element = $(element);
const validRegExp = options.validRegExp ? new RegExp(options.validRegExp) : undefined;
const showValidationError = function () {
const $errorWrapper = $element.siblings('.selectize-error');
if (options.invalidMessage && $errorWrapper.length > 0) {
$errorWrapper.find('.message').text(options.invalidMessage);
$errorWrapper.show();
window.setTimeout(() => {
$errorWrapper.fadeOut(400, () => {
$errorWrapper.hide();
});
}, 5000);
}
};
options = $.extend(
{
plugins: ['remove_button'],
options: $.map(options.setTags(), value => {
return { value: value, text: value };
}),
delimiter: ',',
items: options.setTags(),
closeAfterSelect: true,
persist: true,
preload: true,
create: function (input) {
if (typeof validRegExp !== 'undefined' && !validRegExp.test(input)) {
showValidationError();
return false;
}
return {
value: input.replace(/\s/g, '-'),
text: input.replace(/\s/g, '-')
};
}
},
options
);
const $readOnlyContainer = $('<div>')
.hide()
.addClass('selectize-control selectize-read-only multi')
.attr('style', $element.attr('style'))
.insertAfter($(element));
if (!options.readOnly) {
$readOnlyContainer.on('mouseover', () => {
$readOnlyContainer.find('.selectize-actions').addClass('selectize-actions-visible');
});
$readOnlyContainer.on('mouseout', () => {
$readOnlyContainer.find('.selectize-actions').removeClass('selectize-actions-visible');
});
}
$element.hide();
let currentSelectize;
let optionsBeforeEdit = [];
const saveOnClickOutside = function (event) {
if (
$.contains(document, event.target) &&
currentSelectize &&
!$.contains(currentSelectize.$wrapper[0], event.target)
) {
if (currentSelectize.getValue() !== optionsBeforeEdit.join(',')) {
options.onSave(currentSelectize.getValue());
}
$(document).off('click', saveOnClickOutside);
$(document).off('keyup', hideOnEscape);
showReadOnly();
}
};
const hideOnEscape = function (event) {
if (event.which === 27) {
showReadOnly();
}
};
let sizeCheckInterval = -1;
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
window.clearInterval(sizeCheckInterval);
});
const showEdit = function () {
window.clearInterval(sizeCheckInterval);
optionsBeforeEdit = options.setTags().concat();
options.options = $.map(options.setTags(), value => {
return { value: value, text: value };
});
currentSelectize = $element.selectize(options)[0].selectize;
$readOnlyContainer.hide();
$element.next().find('.selectize-input').css('padding-right', '38px');
$element.next().find('input').focus();
const $editActions = $('<div>').addClass('selectize-actions').appendTo($element.next());
$('<i>')
.addClass('fa fa-check')
.click(() => {
if (currentSelectize.getValue() !== optionsBeforeEdit.join(',')) {
options.onSave(currentSelectize.getValue());
}
showReadOnly();
})
.appendTo($editActions);
$('<i>')
.addClass('fa fa-close')
.click(() => {
showReadOnly();
})
.appendTo($editActions);
window.setTimeout(() => {
$(document).on('click', saveOnClickOutside);
$(document).on('keyup', hideOnEscape);
}, 0);
};
let lastKnownOffsetWidth = -1;
let lastKnownOffsetHeight = -1;
const addReadOnlyTagsTillOverflow = function ($readOnlyInner) {
$readOnlyInner.empty();
const tagElements = [];
options.setTags().forEach(tag => {
tagElements.push($('<div>').text(tag).appendTo($readOnlyInner));
});
if (!options.readOnly && !options.hasErrors()) {
$('<i>')
.addClass('fa fa-pencil selectize-edit pointer')
.attr('title', I18n('Edit tags'))
.appendTo($readOnlyInner);
$readOnlyInner.click(() => {
showEdit();
});
}
if (!options.overflowEllipsis) {
return;
}
if (
$readOnlyInner[0].offsetHeight < $readOnlyInner[0].scrollHeight ||
($readOnlyInner[0].offsetWidth < $readOnlyInner[0].scrollWidth && tagElements.length)
) {
tagElements[tagElements.length - 1].after(
$('<div>').addClass('hue-tag-overflow').text('...')
);
}
while (
tagElements.length &&
($readOnlyInner[0].offsetHeight < $readOnlyInner[0].scrollHeight ||
$readOnlyInner[0].offsetWidth < $readOnlyInner[0].scrollWidth)
) {
tagElements.pop().remove();
}
lastKnownOffsetWidth = $readOnlyInner[0].offsetWidth;
lastKnownOffsetHeight = $readOnlyInner[0].offsetHeight;
};
const showReadOnly = function () {
window.clearInterval(sizeCheckInterval);
$(document).off('click', saveOnClickOutside);
$(document).off('keyup', hideOnEscape);
if (currentSelectize) {
currentSelectize.destroy();
$element.hide();
$element.val(options.setTags().join(','));
}
$readOnlyContainer.empty();
const $readOnlyInner = $('<div>')
.addClass('selectize-input items not-full has-options has-items')
.appendTo($readOnlyContainer);
if (options.setTags().length > 0) {
addReadOnlyTagsTillOverflow($readOnlyInner);
if (options.overflowEllipsis) {
sizeCheckInterval = window.setInterval(() => {
if (
$readOnlyInner[0].offsetWidth !== lastKnownOffsetWidth ||
$readOnlyInner[0].offsetHeight !== lastKnownOffsetHeight
) {
addReadOnlyTagsTillOverflow($readOnlyInner);
}
}, 500);
}
} else {
if (options.hasErrors()) {
$('<span>')
.addClass('selectize-no-tags')
.text(options.errorMessage)
.appendTo($readOnlyInner);
} else {
$('<span>')
.addClass('selectize-no-tags')
.text(options.emptyPlaceholder)
.appendTo($readOnlyInner);
}
if (!options.readOnly && !options.hasErrors()) {
$('<i>')
.addClass('fa fa-pencil selectize-edit pointer')
.attr('title', I18n('Edit tags'))
.appendTo($readOnlyInner);
$readOnlyInner.click(() => {
showEdit();
});
}
}
$readOnlyContainer.attr('title', options.setTags().join(', '));
$readOnlyContainer.show();
};
showReadOnly();
}
};