Mouse inputs (#783)
* Add mouse icon * Add _updateModifiers * Add support for mouse button modifiers * Improve names of mouse inputs * Improve mouse input sorting * Rename getModifierKeyStrings to getModifierInputStrings * Refactor keyboard/mouse inputs into KeyboardMouseInputField
This commit is contained in:
parent
59559fc560
commit
0a5e832dfd
@ -113,6 +113,10 @@ html:root:not([data-options-general-result-output-mode=merge]) #dict-main-group
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.condition-mouse-button[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.audio-source-list {
|
.audio-source-list {
|
||||||
counter-reset: audio-source-id;
|
counter-reset: audio-source-id;
|
||||||
}
|
}
|
||||||
|
204
ext/bg/js/settings/keyboard-mouse-input-field.js
Normal file
204
ext/bg/js/settings/keyboard-mouse-input-field.js
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Yomichan Authors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* global
|
||||||
|
* DocumentUtil
|
||||||
|
*/
|
||||||
|
|
||||||
|
class KeyboardMouseInputField extends EventDispatcher {
|
||||||
|
constructor(inputNode, mouseButton, inputNameMap, keySeparator) {
|
||||||
|
super();
|
||||||
|
this._inputNode = inputNode;
|
||||||
|
this._keySeparator = keySeparator;
|
||||||
|
this._keyPriorities = new Map([
|
||||||
|
['meta', -4],
|
||||||
|
['ctrl', -3],
|
||||||
|
['alt', -2],
|
||||||
|
['shift', -1]
|
||||||
|
]);
|
||||||
|
this._mouseButton = mouseButton;
|
||||||
|
this._inputNameMap = inputNameMap;
|
||||||
|
this._mouseInputNamePattern = /^mouse(\d+)$/;
|
||||||
|
this._eventListeners = new EventListenerCollection();
|
||||||
|
this._value = '';
|
||||||
|
this._type = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare(value, type) {
|
||||||
|
this.cleanup();
|
||||||
|
|
||||||
|
this._value = value;
|
||||||
|
const modifiers = this._splitValue(value);
|
||||||
|
const {displayValue} = this._getInputStrings(modifiers);
|
||||||
|
const events = [
|
||||||
|
[this._inputNode, 'keydown', this._onModifierKeyDown.bind(this), false]
|
||||||
|
];
|
||||||
|
if (type === 'modifierInputs' && this._mouseButton !== null) {
|
||||||
|
events.push(
|
||||||
|
[this._mouseButton, 'mousedown', this._onMouseButtonMouseDown.bind(this), false],
|
||||||
|
[this._mouseButton, 'mouseup', this._onMouseButtonMouseUp.bind(this), false],
|
||||||
|
[this._mouseButton, 'contextmenu', this._onMouseButtonContextMenu.bind(this), false]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this._inputNode.value = displayValue;
|
||||||
|
for (const args of events) {
|
||||||
|
this._eventListeners.addEventListener(...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
this._eventListeners.removeAllEventListeners();
|
||||||
|
this._value = '';
|
||||||
|
this._type = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private
|
||||||
|
|
||||||
|
_splitValue(value) {
|
||||||
|
return value.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sortInputs(inputs) {
|
||||||
|
const pattern = this._mouseInputNamePattern;
|
||||||
|
const keyPriorities = this._keyPriorities;
|
||||||
|
const inputInfos = inputs.map((value, index) => {
|
||||||
|
const match = pattern.exec(value);
|
||||||
|
if (match !== null) {
|
||||||
|
return [value, 1, Number.parseInt(match[1], 10), index];
|
||||||
|
} else {
|
||||||
|
let priority = keyPriorities.get(value);
|
||||||
|
if (typeof priority === 'undefined') { priority = 0; }
|
||||||
|
return [value, 0, priority, index];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
inputInfos.sort((a, b) => {
|
||||||
|
let i = a[1] - b[1];
|
||||||
|
if (i !== 0) { return i; }
|
||||||
|
|
||||||
|
i = a[2] - b[2];
|
||||||
|
if (i !== 0) { return i; }
|
||||||
|
|
||||||
|
i = a[0].localeCompare(b[0], 'en-US'); // Ensure an invariant culture
|
||||||
|
if (i !== 0) { return i; }
|
||||||
|
|
||||||
|
i = a[3] - b[3];
|
||||||
|
return i;
|
||||||
|
});
|
||||||
|
return inputInfos.map(([value]) => value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getInputStrings(inputs) {
|
||||||
|
let value = '';
|
||||||
|
let displayValue = '';
|
||||||
|
let first = true;
|
||||||
|
for (const input of inputs) {
|
||||||
|
const {name} = this._getInputName(input);
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
value += ', ';
|
||||||
|
displayValue += this._keySeparator;
|
||||||
|
}
|
||||||
|
value += input;
|
||||||
|
displayValue += name;
|
||||||
|
}
|
||||||
|
return {value, displayValue};
|
||||||
|
}
|
||||||
|
|
||||||
|
_getInputName(value) {
|
||||||
|
const pattern = this._mouseInputNamePattern;
|
||||||
|
const match = pattern.exec(value);
|
||||||
|
if (match !== null) {
|
||||||
|
return {name: `Mouse ${match[1]}`, type: 'mouse'};
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = this._inputNameMap.get(value);
|
||||||
|
if (typeof name === 'undefined') { name = value; }
|
||||||
|
return {name, type: 'key'};
|
||||||
|
}
|
||||||
|
|
||||||
|
_getModifierKeys(e) {
|
||||||
|
const modifiers = DocumentUtil.getActiveModifiers(e);
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
|
||||||
|
// https://askubuntu.com/questions/567731/why-is-shift-alt-being-mapped-to-meta
|
||||||
|
// It works with mouse events on some platforms, so try to determine if metaKey is pressed.
|
||||||
|
// This is a hack and only works when both Shift and Alt are not pressed.
|
||||||
|
if (
|
||||||
|
!modifiers.has('meta') &&
|
||||||
|
DocumentUtil.getKeyFromEvent(e) === 'Meta' &&
|
||||||
|
!(
|
||||||
|
modifiers.size === 2 &&
|
||||||
|
modifiers.has('shift') &&
|
||||||
|
modifiers.has('alt')
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
modifiers.add('meta');
|
||||||
|
}
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onModifierKeyDown(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const key = DocumentUtil.getKeyFromEvent(e);
|
||||||
|
switch (key) {
|
||||||
|
case 'Escape':
|
||||||
|
case 'Backspace':
|
||||||
|
this._updateInputs([]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this._addInputs(this._getModifierKeys(e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onMouseButtonMouseDown(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this._addInputs([`mouse${e.button}`]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onMouseButtonMouseUp(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onMouseButtonContextMenu(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
_addInputs(newInputs) {
|
||||||
|
const inputs = new Set(this._splitValue(this._value));
|
||||||
|
for (const input of newInputs) {
|
||||||
|
inputs.add(input);
|
||||||
|
}
|
||||||
|
this._updateInputs([...inputs]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateInputs(inputs) {
|
||||||
|
inputs = this._sortInputs(inputs);
|
||||||
|
|
||||||
|
const node = this._inputNode;
|
||||||
|
const {value, displayValue} = this._getInputStrings(inputs);
|
||||||
|
node.value = displayValue;
|
||||||
|
if (this._value === value) { return; }
|
||||||
|
this._value = value;
|
||||||
|
this.trigger('change', {value, displayValue});
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* global
|
/* global
|
||||||
* DocumentUtil
|
* KeyboardMouseInputField
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ProfileConditionsUI {
|
class ProfileConditionsUI {
|
||||||
@ -203,35 +203,15 @@ class ProfileConditionsUI {
|
|||||||
return value.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0);
|
return value.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
getModifierKeyStrings(modifiers) {
|
|
||||||
let value = '';
|
|
||||||
let displayValue = '';
|
|
||||||
let first = true;
|
|
||||||
for (const modifier of modifiers) {
|
|
||||||
let keyName = this._keyNames.get(modifier);
|
|
||||||
if (typeof keyName === 'undefined') { keyName = modifier; }
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
value += ', ';
|
|
||||||
displayValue += this._keySeparator;
|
|
||||||
}
|
|
||||||
value += modifier;
|
|
||||||
displayValue += keyName;
|
|
||||||
}
|
|
||||||
return {value, displayValue};
|
|
||||||
}
|
|
||||||
|
|
||||||
sortModifiers(modifiers) {
|
|
||||||
return modifiers.sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPath(property) {
|
getPath(property) {
|
||||||
property = (typeof property === 'string' ? `.${property}` : '');
|
property = (typeof property === 'string' ? `.${property}` : '');
|
||||||
return `profiles[${this.index}]${property}`;
|
return `profiles[${this.index}]${property}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createKeyboardMouseInputField(inputNode, mouseButton) {
|
||||||
|
return new KeyboardMouseInputField(inputNode, mouseButton, this._keyNames, this._keySeparator);
|
||||||
|
}
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
_onAddConditionGroupButtonClick() {
|
_onAddConditionGroupButtonClick() {
|
||||||
@ -425,7 +405,9 @@ class ProfileConditionUI {
|
|||||||
this._operatorInput = null;
|
this._operatorInput = null;
|
||||||
this._valueInputContainer = null;
|
this._valueInputContainer = null;
|
||||||
this._removeButton = null;
|
this._removeButton = null;
|
||||||
|
this._mouseButton = null;
|
||||||
this._value = '';
|
this._value = '';
|
||||||
|
this._kbmInputField = null;
|
||||||
this._eventListeners = new EventListenerCollection();
|
this._eventListeners = new EventListenerCollection();
|
||||||
this._inputEventListeners = new EventListenerCollection();
|
this._inputEventListeners = new EventListenerCollection();
|
||||||
}
|
}
|
||||||
@ -460,6 +442,7 @@ class ProfileConditionUI {
|
|||||||
this._operatorOptionContainer = this._operatorInput.querySelector('optgroup');
|
this._operatorOptionContainer = this._operatorInput.querySelector('optgroup');
|
||||||
this._valueInput = this._node.querySelector('.condition-input-inner');
|
this._valueInput = this._node.querySelector('.condition-input-inner');
|
||||||
this._removeButton = this._node.querySelector('.condition-remove');
|
this._removeButton = this._node.querySelector('.condition-remove');
|
||||||
|
this._mouseButton = this._node.querySelector('.condition-mouse-button');
|
||||||
|
|
||||||
const operatorDetails = this._getOperatorDetails(type, operator);
|
const operatorDetails = this._getOperatorDetails(type, operator);
|
||||||
this._updateTypes(type);
|
this._updateTypes(type);
|
||||||
@ -538,32 +521,7 @@ class ProfileConditionUI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onModifierKeyDown({validate, normalize}, e) {
|
_onModifierInputChange({validate, normalize}, {value}) {
|
||||||
e.preventDefault();
|
|
||||||
const node = e.currentTarget;
|
|
||||||
|
|
||||||
let modifiers;
|
|
||||||
const key = DocumentUtil.getKeyFromEvent(e);
|
|
||||||
switch (key) {
|
|
||||||
case 'Escape':
|
|
||||||
case 'Backspace':
|
|
||||||
modifiers = [];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
modifiers = this._getModifiers(e);
|
|
||||||
const currentModifier = this._splitValue(this._value);
|
|
||||||
for (const modifier of currentModifier) {
|
|
||||||
modifiers.add(modifier);
|
|
||||||
}
|
|
||||||
modifiers = [...modifiers];
|
|
||||||
modifiers = this._sortModifiers(modifiers);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {value, displayValue} = this._getModifierKeyStrings(modifiers);
|
|
||||||
node.value = displayValue;
|
|
||||||
const okay = this._validateValue(value, validate);
|
const okay = this._validateValue(value, validate);
|
||||||
this._value = value;
|
this._value = value;
|
||||||
if (okay) {
|
if (okay) {
|
||||||
@ -588,18 +546,6 @@ class ProfileConditionUI {
|
|||||||
return this._parent.parent.getOperatorDetails(type, operator);
|
return this._parent.parent.getOperatorDetails(type, operator);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getModifierKeyStrings(modifiers) {
|
|
||||||
return this._parent.parent.getModifierKeyStrings(modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
_sortModifiers(modifiers) {
|
|
||||||
return this._parent.parent.sortModifiers(modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
_splitValue(value) {
|
|
||||||
return this._parent.parent.splitValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateTypes(type) {
|
_updateTypes(type) {
|
||||||
const types = this._getDescriptorTypes();
|
const types = this._getDescriptorTypes();
|
||||||
this._updateSelect(this._typeInput, this._typeOptionContainer, types, type);
|
this._updateSelect(this._typeInput, this._typeOptionContainer, types, type);
|
||||||
@ -623,10 +569,15 @@ class ProfileConditionUI {
|
|||||||
|
|
||||||
_updateValueInput(value, {type, validate, normalize}) {
|
_updateValueInput(value, {type, validate, normalize}) {
|
||||||
this._inputEventListeners.removeAllEventListeners();
|
this._inputEventListeners.removeAllEventListeners();
|
||||||
|
if (this._kbmInputField !== null) {
|
||||||
|
this._kbmInputField.cleanup();
|
||||||
|
this._kbmInputField = null;
|
||||||
|
}
|
||||||
|
|
||||||
let inputType = 'text';
|
let inputType = 'text';
|
||||||
let inputValue = value;
|
let inputValue = value;
|
||||||
let inputStep = null;
|
let inputStep = null;
|
||||||
|
let mouseButtonHidden = true;
|
||||||
const events = [];
|
const events = [];
|
||||||
const inputData = {validate, normalize};
|
const inputData = {validate, normalize};
|
||||||
const node = this._valueInput;
|
const node = this._valueInput;
|
||||||
@ -635,32 +586,35 @@ class ProfileConditionUI {
|
|||||||
case 'integer':
|
case 'integer':
|
||||||
inputType = 'number';
|
inputType = 'number';
|
||||||
inputStep = '1';
|
inputStep = '1';
|
||||||
events.push([node, 'change', this._onValueInputChange.bind(this, inputData), false]);
|
events.push(['addEventListener', node, 'change', this._onValueInputChange.bind(this, inputData), false]);
|
||||||
break;
|
break;
|
||||||
case 'modifierKeys':
|
case 'modifierKeys':
|
||||||
{
|
case 'modifierInputs':
|
||||||
const modifiers = this._splitValue(value);
|
inputValue = null;
|
||||||
const {displayValue} = this._getModifierKeyStrings(modifiers);
|
mouseButtonHidden = (type !== 'modifierInputs');
|
||||||
inputValue = displayValue;
|
this._kbmInputField = this._parent.parent.createKeyboardMouseInputField(node, this._mouseButton);
|
||||||
events.push([node, 'keydown', this._onModifierKeyDown.bind(this, inputData), false]);
|
this._kbmInputField.prepare(value, type);
|
||||||
}
|
events.push(['on', this._kbmInputField, 'change', this._onModifierInputChange.bind(this, inputData), false]);
|
||||||
break;
|
break;
|
||||||
default: // 'string'
|
default: // 'string'
|
||||||
events.push([node, 'change', this._onValueInputChange.bind(this, inputData), false]);
|
events.push(['addEventListener', node, 'change', this._onValueInputChange.bind(this, inputData), false]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._value = value;
|
this._value = value;
|
||||||
node.classList.remove('is-invalid');
|
node.classList.remove('is-invalid');
|
||||||
node.type = inputType;
|
node.type = inputType;
|
||||||
|
if (inputValue !== null) {
|
||||||
node.value = inputValue;
|
node.value = inputValue;
|
||||||
|
}
|
||||||
if (typeof inputStep === 'string') {
|
if (typeof inputStep === 'string') {
|
||||||
node.step = inputStep;
|
node.step = inputStep;
|
||||||
} else {
|
} else {
|
||||||
node.removeAttribute('step');
|
node.removeAttribute('step');
|
||||||
}
|
}
|
||||||
|
this._mouseButton.hidden = mouseButtonHidden;
|
||||||
for (const args of events) {
|
for (const args of events) {
|
||||||
this._inputEventListeners.addEventListener(...args);
|
this._inputEventListeners.addGeneric(...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._validateValue(value, validate);
|
this._validateValue(value, validate);
|
||||||
@ -675,24 +629,4 @@ class ProfileConditionUI {
|
|||||||
_normalizeValue(value, normalize) {
|
_normalizeValue(value, normalize) {
|
||||||
return (normalize !== null ? normalize(value) : value);
|
return (normalize !== null ? normalize(value) : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getModifiers(e) {
|
|
||||||
const modifiers = DocumentUtil.getActiveModifiers(e);
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/metaKey
|
|
||||||
// https://askubuntu.com/questions/567731/why-is-shift-alt-being-mapped-to-meta
|
|
||||||
// It works with mouse events on some platforms, so try to determine if metaKey is pressed.
|
|
||||||
// This is a hack and only works when both Shift and Alt are not pressed.
|
|
||||||
if (
|
|
||||||
!modifiers.has('meta') &&
|
|
||||||
DocumentUtil.getKeyFromEvent(e) === 'Meta' &&
|
|
||||||
!(
|
|
||||||
modifiers.size === 2 &&
|
|
||||||
modifiers.has('shift') &&
|
|
||||||
modifiers.has('alt')
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
modifiers.add('meta');
|
|
||||||
}
|
|
||||||
return modifiers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@
|
|||||||
<div class="input-group-btn"><select class="form-control btn btn-default condition-operator"><optgroup label="Operator"></optgroup></select></div>
|
<div class="input-group-btn"><select class="form-control btn btn-default condition-operator"><optgroup label="Operator"></optgroup></select></div>
|
||||||
<div class="condition-line-break"></div>
|
<div class="condition-line-break"></div>
|
||||||
<div class="condition-input"><input type="text" class="form-control condition-input-inner"></div>
|
<div class="condition-input"><input type="text" class="form-control condition-input-inner"></div>
|
||||||
<div class="input-group-btn"><button class="btn btn-danger condition-remove" title="Remove"><span class="glyphicon glyphicon-remove"></span></button></div>
|
<div class="input-group-btn"><button class="btn btn-default condition-mouse-button" title="Mouse button" style="padding-left: 10px; padding-right: 10px;" hidden><span style="width: 20px; height: 20px; display: block; background: url(/mixed/img/mouse.svg) no-repeat center center; background-size: 20px 20px;"></span></button><button class="btn btn-danger condition-remove" title="Remove"><span class="glyphicon glyphicon-remove"></span></button></div>
|
||||||
</div></template>
|
</div></template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1164,6 +1164,7 @@
|
|||||||
<script src="/bg/js/settings/dictionaries.js"></script>
|
<script src="/bg/js/settings/dictionaries.js"></script>
|
||||||
<script src="/bg/js/settings/dictionary-import-controller.js"></script>
|
<script src="/bg/js/settings/dictionary-import-controller.js"></script>
|
||||||
<script src="/bg/js/settings/generic-setting-controller.js"></script>
|
<script src="/bg/js/settings/generic-setting-controller.js"></script>
|
||||||
|
<script src="/bg/js/settings/keyboard-mouse-input-field.js"></script>
|
||||||
<script src="/bg/js/settings/popup-preview.js"></script>
|
<script src="/bg/js/settings/popup-preview.js"></script>
|
||||||
<script src="/bg/js/settings/profiles.js"></script>
|
<script src="/bg/js/settings/profiles.js"></script>
|
||||||
<script src="/bg/js/settings/profile-conditions-ui.js"></script>
|
<script src="/bg/js/settings/profile-conditions-ui.js"></script>
|
||||||
|
1
ext/mixed/img/mouse.svg
Normal file
1
ext/mixed/img/mouse.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M7.4883 1.0273C4.9609 1.29264 3 3.4984 3 6.1992v.30078h4.5v-5.4727c-.00385.0004-.00787-.0004-.01172 0zm1.0117 0V6.5H13v-.30078c0-2.7049-1.967-4.9121-4.5-5.1719zM3 7.5v2.3008C3 12.6816 5.23 15 8 15s5-2.3184 5-5.1992V7.5H3z" fill="#333"/></svg>
|
After Width: | Height: | Size: 314 B |
@ -341,6 +341,14 @@ class EventListenerCollection {
|
|||||||
return this._eventListeners.length;
|
return this._eventListeners.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addGeneric(type, object, ...args) {
|
||||||
|
switch (type) {
|
||||||
|
case 'addEventListener': return this.addEventListener(object, ...args);
|
||||||
|
case 'addListener': return this.addListener(object, ...args);
|
||||||
|
case 'on': return this.on(object, ...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addEventListener(object, ...args) {
|
addEventListener(object, ...args) {
|
||||||
object.addEventListener(...args);
|
object.addEventListener(...args);
|
||||||
this._eventListeners.push(['removeEventListener', object, ...args]);
|
this._eventListeners.push(['removeEventListener', object, ...args]);
|
||||||
|
@ -27,11 +27,11 @@
|
|||||||
borderopacity="1.0"
|
borderopacity="1.0"
|
||||||
inkscape:pageopacity="0.0"
|
inkscape:pageopacity="0.0"
|
||||||
inkscape:pageshadow="2"
|
inkscape:pageshadow="2"
|
||||||
inkscape:zoom="22.627417"
|
inkscape:zoom="45.254834"
|
||||||
inkscape:cx="12.059712"
|
inkscape:cx="6.9125714"
|
||||||
inkscape:cy="6.3977551"
|
inkscape:cy="9.2321432"
|
||||||
inkscape:document-units="px"
|
inkscape:document-units="px"
|
||||||
inkscape:current-layer="g1012"
|
inkscape:current-layer="layer38"
|
||||||
showgrid="true"
|
showgrid="true"
|
||||||
units="px"
|
units="px"
|
||||||
inkscape:snap-center="true"
|
inkscape:snap-center="true"
|
||||||
@ -1202,7 +1202,7 @@
|
|||||||
id="rect1210" />
|
id="rect1210" />
|
||||||
</g>
|
</g>
|
||||||
<g
|
<g
|
||||||
style="display:inline"
|
style="display:none"
|
||||||
inkscape:label="Up Arrow"
|
inkscape:label="Up Arrow"
|
||||||
id="g1012"
|
id="g1012"
|
||||||
inkscape:groupmode="layer">
|
inkscape:groupmode="layer">
|
||||||
@ -1213,4 +1213,19 @@
|
|||||||
inkscape:connector-curvature="0"
|
inkscape:connector-curvature="0"
|
||||||
sodipodi:nodetypes="cccccccc" />
|
sodipodi:nodetypes="cccccccc" />
|
||||||
</g>
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer38"
|
||||||
|
inkscape:label="Mouse">
|
||||||
|
<g
|
||||||
|
id="g1029">
|
||||||
|
<g
|
||||||
|
id="g1033">
|
||||||
|
<path
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
|
||||||
|
d="M 7.4882812 1.0273438 C 4.9608765 1.2926885 3 3.4984688 3 6.1992188 L 3 6.5 L 7.5 6.5 L 7.5 1.0273438 C 7.4961497 1.0277387 7.4921289 1.0269398 7.4882812 1.0273438 z M 8.5 1.0273438 L 8.5 6.5 L 13 6.5 L 13 6.1992188 C 13 3.4943573 11.03298 1.2871677 8.5 1.0273438 z M 3 7.5 L 3 9.8007812 C 3 12.681581 5.23 15 8 15 C 10.77 15 13 12.681581 13 9.8007812 L 13 7.5 L 3 7.5 z "
|
||||||
|
id="rect1013" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 72 KiB |
Loading…
Reference in New Issue
Block a user