@kui-shell/plugin-electron-components
Version:
Kui plugin that houses electron-specific React components
245 lines (244 loc) • 8.02 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/*
* Copyright 2021 The Kubernetes Authors
*
* 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 __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const SearchInput = _react.default.lazy(() => Promise.resolve().then(() => require('@patternfly/react-core/dist/esm/components/SearchInput')).then(_ => ({
default: _.SearchInput
})));
class Search extends _react.default.Component {
constructor(props) {
super(props);
this.onKeydown = evt => {
if (!evt.defaultPrevented && evt.code === 'KeyF' && (evt.ctrlKey && process.platform !== 'darwin' || evt.metaKey)) {
if (this.state.isActive && document.activeElement !== this._input) {
this.doFocus();
} else {
this.findInPage(); // allows for search to be reinitiated when the search bar is reopened
const isActive = !this.state.isActive;
if (!isActive) {
this.stopFindInPage();
}
this.setState(() => ({
isActive,
result: undefined
}));
}
}
};
this._onChange = this.onChange.bind(this);
this._onClear = this.onClear.bind(this);
this._onNext = this.onNext.bind(this);
this._onPrevious = this.onPrevious.bind(this);
this._onRef = c => {
if (c) {
this._input = c;
}
};
this.state = {
isActive: false,
result: undefined,
currentMatchIdx: 1
};
}
/** stop findInPage, and clear selections in page */
stopFindInPage() {
return __awaiter(this, void 0, void 0, function* () {
const {
ipcRenderer
} = yield Promise.resolve().then(() => require('electron'));
// note: with 'clearSelection', the focus of the input is very
// odd; it is focused, but typing text does nothing until some
// global refresh occurs. maybe this is just a bug in electron 6?
ipcRenderer.send('synchronous-message', JSON.stringify({
operation: 'stop-find-in-page'
}));
});
}
componentDidMount() {
// this.stopFindInPage() // <-- failsafe, in case of bugs; electron seems to persist this
document.body.addEventListener('keydown', this.onKeydown);
}
componentWillUnmount() {
document.body.removeEventListener('keydown', this.onKeydown);
}
componentDidUpdate() {
if (this.state.isActive) {
setTimeout(() => this.doFocus());
}
}
onChange() {
return __awaiter(this, void 0, void 0, function* () {
if (this._input) {
if (this._input.value.length === 0) {
yield this.stopFindInPage();
this.setState({
result: undefined
});
} else {
this.findInPage();
}
}
});
}
findInPage(options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this._input || !this._input.value) {
// protect against: "Error: Could not call remote method
// 'findInPage'. Check that the method signature is
// correct. Underlying error: Error: Must provide a non-empty
// search contentUnderlying stack: Error: Must provide a
// non-empty search content"
return;
}
const {
ipcRenderer
} = yield Promise.resolve().then(() => require('electron'));
// Registering a callback handler
ipcRenderer.once('found-in-page-result', (event, result) => __awaiter(this, void 0, void 0, function* () {
if (this.state.isActive) {
// we only need hack if we're doing a find as the user is typing and the options is defined for the converse
if (!options) {
this.hack();
}
}
this.setState(() => ({
result
}));
}));
// this is where we call the electron API to initiate a new find
ipcRenderer.send('synchronous-message', JSON.stringify({
operation: 'find-in-page',
value: this._input.value,
options
}));
});
}
/** findInPage api seems to result in a loss of focus */
hack() {
const v = this._input.value;
this._input.value = '';
this._input.value = v;
this._input.focus();
}
doFocus() {
if (this.state.isActive && this._input) {
this._input.focus();
}
}
onClear() {
return __awaiter(this, void 0, void 0, function* () {
yield this.stopFindInPage();
if (this._input) {
this._input.value = '';
}
this.setState({
result: undefined,
isActive: false,
currentMatchIdx: 1
});
});
}
onNext() {
return __awaiter(this, void 0, void 0, function* () {
// if statement blocks user from pressing next arrow if already on last result
if (this.state.currentMatchIdx < this.state.result.matches) {
yield this.findInPage({
forward: true,
findNext: false
});
this.setState(prevState => {
const newCurrentResult = prevState.currentMatchIdx + 1;
return {
currentMatchIdx: newCurrentResult <= prevState.result.matches ? newCurrentResult : prevState.result.matches
};
});
}
});
}
onPrevious() {
return __awaiter(this, void 0, void 0, function* () {
// if statement blocks user from pressing previous arrow if already on first result
if (this.state.currentMatchIdx > this.state.result.matches - this.state.result.matches + 1) {
yield this.findInPage({
forward: false,
findNext: false
});
this.setState(prevState => {
const newCurrentResult = prevState.currentMatchIdx - 1;
return {
currentMatchIdx: newCurrentResult > 0 ? newCurrentResult : 1
};
});
}
});
}
resultsRender() {
if (this.state.currentMatchIdx && this.state.result) {
const curResultDisplay = this.state.currentMatchIdx.toString();
const totalResult = this.state.result.matches.toString();
return curResultDisplay + '/' + totalResult;
}
}
render() {
return _react.default.createElement(SearchInput, {
id: "search-bar",
className: 'kui--search ' + (!this.state.isActive ? 'hide' : ''),
placeholder: "Find by name",
value: this._input && this._input.value,
"aria-label": "Search",
onChange: this._onChange,
onClear: this._onClear,
spellCheck: false,
resultsCount: this.resultsRender(),
onNextClick: this._onNext,
onPreviousClick: this._onPrevious,
ref: this._onRef
});
}
}
exports.default = Search;