From 07fe63f21daeedd2c40e53348e9aadd12153b453 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Tue, 26 Jan 2021 22:44:45 +0200 Subject: [PATCH 01/13] add mousetrap lib to keys js files, and load js file in html --- app/static/keyboard_shortcuts/__init__.py | 0 .../keyboard_shortcuts/home_shortcuts.js | 9 + app/static/keyboard_shortcuts/mousetrap.js | 1058 +++++++++++++++++ .../keyboard_shortcuts/mousetrap_bind_dict.js | 40 + .../keyboard_shortcuts/profile_shortcuts.js | 7 + app/templates/base.html | 1 + app/templates/profile.html | 2 +- 7 files changed, 1116 insertions(+), 1 deletion(-) create mode 100644 app/static/keyboard_shortcuts/__init__.py create mode 100644 app/static/keyboard_shortcuts/home_shortcuts.js create mode 100644 app/static/keyboard_shortcuts/mousetrap.js create mode 100644 app/static/keyboard_shortcuts/mousetrap_bind_dict.js create mode 100644 app/static/keyboard_shortcuts/profile_shortcuts.js diff --git a/app/static/keyboard_shortcuts/__init__.py b/app/static/keyboard_shortcuts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/static/keyboard_shortcuts/home_shortcuts.js b/app/static/keyboard_shortcuts/home_shortcuts.js new file mode 100644 index 00000000..fd32c1e9 --- /dev/null +++ b/app/static/keyboard_shortcuts/home_shortcuts.js @@ -0,0 +1,9 @@ +import './mousetrap.js' +import './mousetrap_bind_dict.js' + +let key_shortcuts = { + 'alt+c+i': function() { window.open('invitations/', '_self'); }, + 'alt+c+p': function() { window.open('profile/', '_self'); } +}; + +Mousetrap.bind(key_shortcuts); \ No newline at end of file diff --git a/app/static/keyboard_shortcuts/mousetrap.js b/app/static/keyboard_shortcuts/mousetrap.js new file mode 100644 index 00000000..ab71d582 --- /dev/null +++ b/app/static/keyboard_shortcuts/mousetrap.js @@ -0,0 +1,1058 @@ +/*global define:false */ +/** + * Copyright 2012-2017 Craig Campbell + * + * 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. + * + * Mousetrap is a simple keyboard shortcut library for Javascript with + * no external dependencies + * + * @version 1.6.5 + * @url craig.is/killing/mice + */ +(function(window, document, undefined) { + + // Check if mousetrap is used inside browser, if not, return + if (!window) { + return; + } + + /** + * mapping of special keycodes to their corresponding keys + * + * everything in this dictionary cannot use keypress events + * so it has to be here to map to the correct keycodes for + * keyup/keydown events + * + * @type {Object} + */ + var _MAP = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'ctrl', + 18: 'alt', + 20: 'capslock', + 27: 'esc', + 32: 'space', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'ins', + 46: 'del', + 91: 'meta', + 93: 'meta', + 224: 'meta' + }; + + /** + * mapping for special characters so they can support + * + * this dictionary is only used incase you want to bind a + * keyup or keydown event to one of these keys + * + * @type {Object} + */ + var _KEYCODE_MAP = { + 106: '*', + 107: '+', + 109: '-', + 110: '.', + 111 : '/', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: '\'' + }; + + /** + * this is a mapping of keys that require shift on a US keypad + * back to the non shift equivelents + * + * this is so you can use keyup events with these keys + * + * note that this will only work reliably on US keyboards + * + * @type {Object} + */ + var _SHIFT_MAP = { + '~': '`', + '!': '1', + '@': '2', + '#': '3', + '$': '4', + '%': '5', + '^': '6', + '&': '7', + '*': '8', + '(': '9', + ')': '0', + '_': '-', + '+': '=', + ':': ';', + '\"': '\'', + '<': ',', + '>': '.', + '?': '/', + '|': '\\' + }; + + /** + * this is a list of special strings you can use to map + * to modifier keys when you specify your keyboard shortcuts + * + * @type {Object} + */ + var _SPECIAL_ALIASES = { + 'option': 'alt', + 'command': 'meta', + 'return': 'enter', + 'escape': 'esc', + 'plus': '+', + 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl' + }; + + /** + * variable to store the flipped version of _MAP from above + * needed to check if we should use keypress or not when no action + * is specified + * + * @type {Object|undefined} + */ + var _REVERSE_MAP; + + /** + * loop through the f keys, f1 to f19 and add them to the map + * programatically + */ + for (var i = 1; i < 20; ++i) { + _MAP[111 + i] = 'f' + i; + } + + /** + * loop through to map numbers on the numeric keypad + */ + for (i = 0; i <= 9; ++i) { + + // This needs to use a string cause otherwise since 0 is falsey + // mousetrap will never fire for numpad 0 pressed as part of a keydown + // event. + // + // @see https://github.com/ccampbell/mousetrap/pull/258 + _MAP[i + 96] = i.toString(); + } + + /** + * cross browser add event method + * + * @param {Element|HTMLDocument} object + * @param {string} type + * @param {Function} callback + * @returns void + */ + function _addEvent(object, type, callback) { + if (object.addEventListener) { + object.addEventListener(type, callback, false); + return; + } + + object.attachEvent('on' + type, callback); + } + + /** + * takes the event and returns the key character + * + * @param {Event} e + * @return {string} + */ + function _characterFromEvent(e) { + + // for keypress events we should return the character as is + if (e.type == 'keypress') { + var character = String.fromCharCode(e.which); + + // if the shift key is not pressed then it is safe to assume + // that we want the character to be lowercase. this means if + // you accidentally have caps lock on then your key bindings + // will continue to work + // + // the only side effect that might not be desired is if you + // bind something like 'A' cause you want to trigger an + // event when capital A is pressed caps lock will no longer + // trigger the event. shift+a will though. + if (!e.shiftKey) { + character = character.toLowerCase(); + } + + return character; + } + + // for non keypress events the special maps are needed + if (_MAP[e.which]) { + return _MAP[e.which]; + } + + if (_KEYCODE_MAP[e.which]) { + return _KEYCODE_MAP[e.which]; + } + + // if it is not in the special map + + // with keydown and keyup events the character seems to always + // come in as an uppercase character whether you are pressing shift + // or not. we should make sure it is always lowercase for comparisons + return String.fromCharCode(e.which).toLowerCase(); + } + + /** + * checks if two arrays are equal + * + * @param {Array} modifiers1 + * @param {Array} modifiers2 + * @returns {boolean} + */ + function _modifiersMatch(modifiers1, modifiers2) { + return modifiers1.sort().join(',') === modifiers2.sort().join(','); + } + + /** + * takes a key event and figures out what the modifiers are + * + * @param {Event} e + * @returns {Array} + */ + function _eventModifiers(e) { + var modifiers = []; + + if (e.shiftKey) { + modifiers.push('shift'); + } + + if (e.altKey) { + modifiers.push('alt'); + } + + if (e.ctrlKey) { + modifiers.push('ctrl'); + } + + if (e.metaKey) { + modifiers.push('meta'); + } + + return modifiers; + } + + /** + * prevents default for this event + * + * @param {Event} e + * @returns void + */ + function _preventDefault(e) { + if (e.preventDefault) { + e.preventDefault(); + return; + } + + e.returnValue = false; + } + + /** + * stops propogation for this event + * + * @param {Event} e + * @returns void + */ + function _stopPropagation(e) { + if (e.stopPropagation) { + e.stopPropagation(); + return; + } + + e.cancelBubble = true; + } + + /** + * determines if the keycode specified is a modifier key or not + * + * @param {string} key + * @returns {boolean} + */ + function _isModifier(key) { + return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; + } + + /** + * reverses the map lookup so that we can look for specific keys + * to see what can and can't use keypress + * + * @return {Object} + */ + function _getReverseMap() { + if (!_REVERSE_MAP) { + _REVERSE_MAP = {}; + for (var key in _MAP) { + + // pull out the numeric keypad from here cause keypress should + // be able to detect the keys from the character + if (key > 95 && key < 112) { + continue; + } + + if (_MAP.hasOwnProperty(key)) { + _REVERSE_MAP[_MAP[key]] = key; + } + } + } + return _REVERSE_MAP; + } + + /** + * picks the best action based on the key combination + * + * @param {string} key - character for key + * @param {Array} modifiers + * @param {string=} action passed in + */ + function _pickBestAction(key, modifiers, action) { + + // if no action was picked in we should try to pick the one + // that we think would work best for this key + if (!action) { + action = _getReverseMap()[key] ? 'keydown' : 'keypress'; + } + + // modifier keys don't work as expected with keypress, + // switch to keydown + if (action == 'keypress' && modifiers.length) { + action = 'keydown'; + } + + return action; + } + + /** + * Converts from a string key combination to an array + * + * @param {string} combination like "command+shift+l" + * @return {Array} + */ + function _keysFromString(combination) { + if (combination === '+') { + return ['+']; + } + + combination = combination.replace(/\+{2}/g, '+plus'); + return combination.split('+'); + } + + /** + * Gets info for a specific key combination + * + * @param {string} combination key combination ("command+s" or "a" or "*") + * @param {string=} action + * @returns {Object} + */ + function _getKeyInfo(combination, action) { + var keys; + var key; + var i; + var modifiers = []; + + // take the keys from this pattern and figure out what the actual + // pattern is all about + keys = _keysFromString(combination); + + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + + // normalize key names + if (_SPECIAL_ALIASES[key]) { + key = _SPECIAL_ALIASES[key]; + } + + // if this is not a keypress event then we should + // be smart about using shift keys + // this will only work for US keyboards however + if (action && action != 'keypress' && _SHIFT_MAP[key]) { + key = _SHIFT_MAP[key]; + modifiers.push('shift'); + } + + // if this key is a modifier then add it to the list of modifiers + if (_isModifier(key)) { + modifiers.push(key); + } + } + + // depending on what the key combination is + // we will try to pick the best event for it + action = _pickBestAction(key, modifiers, action); + + return { + key: key, + modifiers: modifiers, + action: action + }; + } + + function _belongsTo(element, ancestor) { + if (element === null || element === document) { + return false; + } + + if (element === ancestor) { + return true; + } + + return _belongsTo(element.parentNode, ancestor); + } + + function Mousetrap(targetElement) { + var self = this; + + targetElement = targetElement || document; + + if (!(self instanceof Mousetrap)) { + return new Mousetrap(targetElement); + } + + /** + * element to attach key events to + * + * @type {Element} + */ + self.target = targetElement; + + /** + * a list of all the callbacks setup via Mousetrap.bind() + * + * @type {Object} + */ + self._callbacks = {}; + + /** + * direct map of string combinations to callbacks used for trigger() + * + * @type {Object} + */ + self._directMap = {}; + + /** + * keeps track of what level each sequence is at since multiple + * sequences can start out with the same sequence + * + * @type {Object} + */ + var _sequenceLevels = {}; + + /** + * variable to store the setTimeout call + * + * @type {null|number} + */ + var _resetTimer; + + /** + * temporary state where we will ignore the next keyup + * + * @type {boolean|string} + */ + var _ignoreNextKeyup = false; + + /** + * temporary state where we will ignore the next keypress + * + * @type {boolean} + */ + var _ignoreNextKeypress = false; + + /** + * are we currently inside of a sequence? + * type of action ("keyup" or "keydown" or "keypress") or false + * + * @type {boolean|string} + */ + var _nextExpectedAction = false; + + /** + * resets all sequence counters except for the ones passed in + * + * @param {Object} doNotReset + * @returns void + */ + function _resetSequences(doNotReset) { + doNotReset = doNotReset || {}; + + var activeSequences = false, + key; + + for (key in _sequenceLevels) { + if (doNotReset[key]) { + activeSequences = true; + continue; + } + _sequenceLevels[key] = 0; + } + + if (!activeSequences) { + _nextExpectedAction = false; + } + } + + /** + * finds all callbacks that match based on the keycode, modifiers, + * and action + * + * @param {string} character + * @param {Array} modifiers + * @param {Event|Object} e + * @param {string=} sequenceName - name of the sequence we are looking for + * @param {string=} combination + * @param {number=} level + * @returns {Array} + */ + function _getMatches(character, modifiers, e, sequenceName, combination, level) { + var i; + var callback; + var matches = []; + var action = e.type; + + // if there are no events related to this keycode + if (!self._callbacks[character]) { + return []; + } + + // if a modifier key is coming up on its own we should allow it + if (action == 'keyup' && _isModifier(character)) { + modifiers = [character]; + } + + // loop through all callbacks for the key that was pressed + // and see if any of them match + for (i = 0; i < self._callbacks[character].length; ++i) { + callback = self._callbacks[character][i]; + + // if a sequence name is not specified, but this is a sequence at + // the wrong level then move onto the next match + if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) { + continue; + } + + // if the action we are looking for doesn't match the action we got + // then we should keep going + if (action != callback.action) { + continue; + } + + // if this is a keypress event and the meta key and control key + // are not pressed that means that we need to only look at the + // character, otherwise check the modifiers as well + // + // chrome will not fire a keypress if meta or control is down + // safari will fire a keypress if meta or meta+shift is down + // firefox will fire a keypress if meta or control is down + if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) { + + // when you bind a combination or sequence a second time it + // should overwrite the first one. if a sequenceName or + // combination is specified in this call it does just that + // + // @todo make deleting its own method? + var deleteCombo = !sequenceName && callback.combo == combination; + var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level; + if (deleteCombo || deleteSequence) { + self._callbacks[character].splice(i, 1); + } + + matches.push(callback); + } + } + + return matches; + } + + /** + * actually calls the callback function + * + * if your callback function returns false this will use the jquery + * convention - prevent default and stop propogation on the event + * + * @param {Function} callback + * @param {Event} e + * @returns void + */ + function _fireCallback(callback, e, combo, sequence) { + + // if this event should not happen stop here + if (self.stopCallback(e, e.target || e.srcElement, combo, sequence)) { + return; + } + + if (callback(e, combo) === false) { + _preventDefault(e); + _stopPropagation(e); + } + } + + /** + * handles a character key event + * + * @param {string} character + * @param {Array} modifiers + * @param {Event} e + * @returns void + */ + self._handleKey = function(character, modifiers, e) { + var callbacks = _getMatches(character, modifiers, e); + var i; + var doNotReset = {}; + var maxLevel = 0; + var processedSequenceCallback = false; + + // Calculate the maxLevel for sequences so we can only execute the longest callback sequence + for (i = 0; i < callbacks.length; ++i) { + if (callbacks[i].seq) { + maxLevel = Math.max(maxLevel, callbacks[i].level); + } + } + + // loop through matching callbacks for this key event + for (i = 0; i < callbacks.length; ++i) { + + // fire for all sequence callbacks + // this is because if for example you have multiple sequences + // bound such as "g i" and "g t" they both need to fire the + // callback for matching g cause otherwise you can only ever + // match the first one + if (callbacks[i].seq) { + + // only fire callbacks for the maxLevel to prevent + // subsequences from also firing + // + // for example 'a option b' should not cause 'option b' to fire + // even though 'option b' is part of the other sequence + // + // any sequences that do not match here will be discarded + // below by the _resetSequences call + if (callbacks[i].level != maxLevel) { + continue; + } + + processedSequenceCallback = true; + + // keep a list of which sequences were matches for later + doNotReset[callbacks[i].seq] = 1; + _fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq); + continue; + } + + // if there were no sequence matches but we are still here + // that means this is a regular match so we should fire that + if (!processedSequenceCallback) { + _fireCallback(callbacks[i].callback, e, callbacks[i].combo); + } + } + + // if the key you pressed matches the type of sequence without + // being a modifier (ie "keyup" or "keypress") then we should + // reset all sequences that were not matched by this event + // + // this is so, for example, if you have the sequence "h a t" and you + // type "h e a r t" it does not match. in this case the "e" will + // cause the sequence to reset + // + // modifier keys are ignored because you can have a sequence + // that contains modifiers such as "enter ctrl+space" and in most + // cases the modifier key will be pressed before the next key + // + // also if you have a sequence such as "ctrl+b a" then pressing the + // "b" key will trigger a "keypress" and a "keydown" + // + // the "keydown" is expected when there is a modifier, but the + // "keypress" ends up matching the _nextExpectedAction since it occurs + // after and that causes the sequence to reset + // + // we ignore keypresses in a sequence that directly follow a keydown + // for the same character + var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress; + if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) { + _resetSequences(doNotReset); + } + + _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown'; + }; + + /** + * handles a keydown event + * + * @param {Event} e + * @returns void + */ + function _handleKeyEvent(e) { + + // normalize e.which for key events + // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion + if (typeof e.which !== 'number') { + e.which = e.keyCode; + } + + var character = _characterFromEvent(e); + + // no character found then stop + if (!character) { + return; + } + + // need to use === for the character check because the character can be 0 + if (e.type == 'keyup' && _ignoreNextKeyup === character) { + _ignoreNextKeyup = false; + return; + } + + self.handleKey(character, _eventModifiers(e), e); + } + + /** + * called to set a 1 second timeout on the specified sequence + * + * this is so after each key press in the sequence you have 1 second + * to press the next key before you have to start over + * + * @returns void + */ + function _resetSequenceTimer() { + clearTimeout(_resetTimer); + _resetTimer = setTimeout(_resetSequences, 1000); + } + + /** + * binds a key sequence to an event + * + * @param {string} combo - combo specified in bind call + * @param {Array} keys + * @param {Function} callback + * @param {string=} action + * @returns void + */ + function _bindSequence(combo, keys, callback, action) { + + // start off by adding a sequence level record for this combination + // and setting the level to 0 + _sequenceLevels[combo] = 0; + + /** + * callback to increase the sequence level for this sequence and reset + * all other sequences that were active + * + * @param {string} nextAction + * @returns {Function} + */ + function _increaseSequence(nextAction) { + return function() { + _nextExpectedAction = nextAction; + ++_sequenceLevels[combo]; + _resetSequenceTimer(); + }; + } + + /** + * wraps the specified callback inside of another function in order + * to reset all sequence counters as soon as this sequence is done + * + * @param {Event} e + * @returns void + */ + function _callbackAndReset(e) { + _fireCallback(callback, e, combo); + + // we should ignore the next key up if the action is key down + // or keypress. this is so if you finish a sequence and + // release the key the final key will not trigger a keyup + if (action !== 'keyup') { + _ignoreNextKeyup = _characterFromEvent(e); + } + + // weird race condition if a sequence ends with the key + // another sequence begins with + setTimeout(_resetSequences, 10); + } + + // loop through keys one at a time and bind the appropriate callback + // function. for any key leading up to the final one it should + // increase the sequence. after the final, it should reset all sequences + // + // if an action is specified in the original bind call then that will + // be used throughout. otherwise we will pass the action that the + // next key in the sequence should match. this allows a sequence + // to mix and match keypress and keydown events depending on which + // ones are better suited to the key provided + for (var i = 0; i < keys.length; ++i) { + var isFinal = i + 1 === keys.length; + var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action); + _bindSingle(keys[i], wrappedCallback, action, combo, i); + } + } + + /** + * binds a single keyboard combination + * + * @param {string} combination + * @param {Function} callback + * @param {string=} action + * @param {string=} sequenceName - name of sequence if part of sequence + * @param {number=} level - what part of the sequence the command is + * @returns void + */ + function _bindSingle(combination, callback, action, sequenceName, level) { + + // store a direct mapped reference for use with Mousetrap.trigger + self._directMap[combination + ':' + action] = callback; + + // make sure multiple spaces in a row become a single space + combination = combination.replace(/\s+/g, ' '); + + var sequence = combination.split(' '); + var info; + + // if this pattern is a sequence of keys then run through this method + // to reprocess each pattern one key at a time + if (sequence.length > 1) { + _bindSequence(combination, sequence, callback, action); + return; + } + + info = _getKeyInfo(combination, action); + + // make sure to initialize array if this is the first time + // a callback is added for this key + self._callbacks[info.key] = self._callbacks[info.key] || []; + + // remove an existing match if there is one + _getMatches(info.key, info.modifiers, {type: info.action}, sequenceName, combination, level); + + // add this call back to the array + // if it is a sequence put it at the beginning + // if not put it at the end + // + // this is important because the way these are processed expects + // the sequence ones to come first + self._callbacks[info.key][sequenceName ? 'unshift' : 'push']({ + callback: callback, + modifiers: info.modifiers, + action: info.action, + seq: sequenceName, + level: level, + combo: combination + }); + } + + /** + * binds multiple combinations to the same callback + * + * @param {Array} combinations + * @param {Function} callback + * @param {string|undefined} action + * @returns void + */ + self._bindMultiple = function(combinations, callback, action) { + for (var i = 0; i < combinations.length; ++i) { + _bindSingle(combinations[i], callback, action); + } + }; + + // start! + _addEvent(targetElement, 'keypress', _handleKeyEvent); + _addEvent(targetElement, 'keydown', _handleKeyEvent); + _addEvent(targetElement, 'keyup', _handleKeyEvent); + } + + /** + * binds an event to mousetrap + * + * can be a single key, a combination of keys separated with +, + * an array of keys, or a sequence of keys separated by spaces + * + * be sure to list the modifier keys first to make sure that the + * correct key ends up getting bound (the last key in the pattern) + * + * @param {string|Array} keys + * @param {Function} callback + * @param {string=} action - 'keypress', 'keydown', or 'keyup' + * @returns void + */ + Mousetrap.prototype.bind = function(keys, callback, action) { + var self = this; + keys = keys instanceof Array ? keys : [keys]; + self._bindMultiple.call(self, keys, callback, action); + return self; + }; + + /** + * unbinds an event to mousetrap + * + * the unbinding sets the callback function of the specified key combo + * to an empty function and deletes the corresponding key in the + * _directMap dict. + * + * TODO: actually remove this from the _callbacks dictionary instead + * of binding an empty function + * + * the keycombo+action has to be exactly the same as + * it was defined in the bind method + * + * @param {string|Array} keys + * @param {string} action + * @returns void + */ + Mousetrap.prototype.unbind = function(keys, action) { + var self = this; + return self.bind.call(self, keys, function() {}, action); + }; + + /** + * triggers an event that has already been bound + * + * @param {string} keys + * @param {string=} action + * @returns void + */ + Mousetrap.prototype.trigger = function(keys, action) { + var self = this; + if (self._directMap[keys + ':' + action]) { + self._directMap[keys + ':' + action]({}, keys); + } + return self; + }; + + /** + * resets the library back to its initial state. this is useful + * if you want to clear out the current keyboard shortcuts and bind + * new ones - for example if you switch to another page + * + * @returns void + */ + Mousetrap.prototype.reset = function() { + var self = this; + self._callbacks = {}; + self._directMap = {}; + return self; + }; + + /** + * should we stop this event before firing off callbacks + * + * @param {Event} e + * @param {Element} element + * @return {boolean} + */ + Mousetrap.prototype.stopCallback = function(e, element) { + var self = this; + + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + if (_belongsTo(element, self.target)) { + return false; + } + + // Events originating from a shadow DOM are re-targetted and `e.target` is the shadow host, + // not the initial event target in the shadow tree. Note that not all events cross the + // shadow boundary. + // For shadow trees with `mode: 'open'`, the initial event target is the first element in + // the event’s composed path. For shadow trees with `mode: 'closed'`, the initial event + // target cannot be obtained. + if ('composedPath' in e && typeof e.composedPath === 'function') { + // For open shadow trees, update `element` so that the following check works. + var initialEventTarget = e.composedPath()[0]; + if (initialEventTarget !== e.target) { + element = initialEventTarget; + } + } + + // stop for input, select, and textarea + return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable; + }; + + /** + * exposes _handleKey publicly so it can be overwritten by extensions + */ + Mousetrap.prototype.handleKey = function() { + var self = this; + return self._handleKey.apply(self, arguments); + }; + + /** + * allow custom key mappings + */ + Mousetrap.addKeycodes = function(object) { + for (var key in object) { + if (object.hasOwnProperty(key)) { + _MAP[key] = object[key]; + } + } + _REVERSE_MAP = null; + }; + + /** + * Init the global mousetrap functions + * + * This method is needed to allow the global mousetrap functions to work + * now that mousetrap is a constructor function. + */ + Mousetrap.init = function() { + var documentMousetrap = Mousetrap(document); + for (var method in documentMousetrap) { + if (method.charAt(0) !== '_') { + Mousetrap[method] = (function(method) { + return function() { + return documentMousetrap[method].apply(documentMousetrap, arguments); + }; + } (method)); + } + } + }; + + Mousetrap.init(); + + // expose mousetrap to the global object + window.Mousetrap = Mousetrap; + + // expose as a common js module + if (typeof module !== 'undefined' && module.exports) { + module.exports = Mousetrap; + } + + // expose mousetrap as an AMD module + if (typeof define === 'function' && define.amd) { + define(function() { + return Mousetrap; + }); + } +}) (typeof window !== 'undefined' ? window : null, typeof window !== 'undefined' ? document : null); diff --git a/app/static/keyboard_shortcuts/mousetrap_bind_dict.js b/app/static/keyboard_shortcuts/mousetrap_bind_dict.js new file mode 100644 index 00000000..3ecc1b02 --- /dev/null +++ b/app/static/keyboard_shortcuts/mousetrap_bind_dict.js @@ -0,0 +1,40 @@ + +/** + * Overwrites default Mousetrap.bind method to optionally accept + * an object to bind multiple key events in a single call + * + * You can pass it in like: + * + * Mousetrap.bind({ + * 'a': function() { console.log('a'); }, + * 'b': function() { console.log('b'); } + * }); + * + * And can optionally pass in 'keypress', 'keydown', or 'keyup' + * as a second argument + * + */ +/* global Mousetrap:true */ +(function(Mousetrap) { + var _oldBind = Mousetrap.prototype.bind; + var args; + + Mousetrap.prototype.bind = function() { + var self = this; + args = arguments; + + // normal call + if (typeof args[0] == 'string' || args[0] instanceof Array) { + return _oldBind.call(self, args[0], args[1], args[2]); + } + + // object passed in + for (var key in args[0]) { + if (args[0].hasOwnProperty(key)) { + _oldBind.call(self, key, args[0][key], args[1]); + } + } + }; + + Mousetrap.init(); +}) (Mousetrap); \ No newline at end of file diff --git a/app/static/keyboard_shortcuts/profile_shortcuts.js b/app/static/keyboard_shortcuts/profile_shortcuts.js new file mode 100644 index 00000000..4bcbb098 --- /dev/null +++ b/app/static/keyboard_shortcuts/profile_shortcuts.js @@ -0,0 +1,7 @@ +import './mousetrap.js' + +Mousetrap.bind('alt+n', function () { + var nameModal = document.getElementById("updateNameModal"); + nameModal.style = 'padding-right: 16px; display: block;'; + console.log('hey') +}); \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index 97360bd6..4432e615 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -61,5 +61,6 @@ integrity="sha512-d9xgZrVZpmmQlfonhQUvTR7lMPtO7NkZMkA0ABN3PHCbKA5nqylQ/yWlFAyY6hYgdF1Qh6nYiuADWwKB4C2WSw==" crossorigin="anonymous"> + diff --git a/app/templates/profile.html b/app/templates/profile.html index 9a0ddbda..aa33e4a8 100644 --- a/app/templates/profile.html +++ b/app/templates/profile.html @@ -245,5 +245,5 @@
{{ user.full_name }}
- + {% endblock %} From 9aa7e780632c718a90856469b5a98b870968bdc1 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Fri, 29 Jan 2021 16:01:07 +0200 Subject: [PATCH 02/13] Change shortcuts from home page to general remove bootstrap and js file from home_shortcuts add test for router --- .../keyboard_shortcuts/general_shortcuts.js | 13 ++++++++++++ .../keyboard_shortcuts/home_shortcuts.js | 12 ----------- app/templates/base.html | 1 + app/templates/home.html | 1 - app/templates/keyboard_shortcuts.html | 21 +++++++------------ tests/test_keyboard_shortcuts_route.py | 14 +++++++++++++ 6 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 app/static/keyboard_shortcuts/general_shortcuts.js delete mode 100644 app/static/keyboard_shortcuts/home_shortcuts.js create mode 100644 tests/test_keyboard_shortcuts_route.py diff --git a/app/static/keyboard_shortcuts/general_shortcuts.js b/app/static/keyboard_shortcuts/general_shortcuts.js new file mode 100644 index 00000000..50587035 --- /dev/null +++ b/app/static/keyboard_shortcuts/general_shortcuts.js @@ -0,0 +1,13 @@ +import './mousetrap.js' +import './mousetrap_bind_dict.js' + +let key_shortcuts = { + 'alt+c+h': function() { window.open('/', '_self'); }, + 'alt+c+i': function() { window.open('/invitations/', '_self'); }, + 'alt+c+p': function() { window.open('/profile/', '_self'); }, + 'alt+c+s': function() { window.open('/search/', '_self'); }, + 'alt+c+a': function() { window.open('/agenda/', '_self'); }, + 'ctrl+.': function() { window.open('/keyboard_shortcuts/', '_self'); } +}; + +Mousetrap.bind(key_shortcuts); \ No newline at end of file diff --git a/app/static/keyboard_shortcuts/home_shortcuts.js b/app/static/keyboard_shortcuts/home_shortcuts.js deleted file mode 100644 index 587fe6e8..00000000 --- a/app/static/keyboard_shortcuts/home_shortcuts.js +++ /dev/null @@ -1,12 +0,0 @@ -import './mousetrap.js' -import './mousetrap_bind_dict.js' - -let key_shortcuts = { - 'alt+c+i': function() { window.open('invitations/', '_self'); }, - 'alt+c+p': function() { window.open('profile/', '_self'); }, - 'alt+c+s': function() { window.open('search/', '_self'); }, - 'alt+c+a': function() { window.open('agenda/', '_self'); }, - 'ctrl+.': function() { window.open('keyboard_shortcuts/', '_self'); } -}; - -Mousetrap.bind(key_shortcuts); \ No newline at end of file diff --git a/app/templates/base.html b/app/templates/base.html index 767f59cc..93237422 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -64,5 +64,6 @@ integrity="sha512-d9xgZrVZpmmQlfonhQUvTR7lMPtO7NkZMkA0ABN3PHCbKA5nqylQ/yWlFAyY6hYgdF1Qh6nYiuADWwKB4C2WSw==" crossorigin="anonymous"> + diff --git a/app/templates/home.html b/app/templates/home.html index b58e5e02..452a518d 100644 --- a/app/templates/home.html +++ b/app/templates/home.html @@ -5,5 +5,4 @@

{{message}}

- {% endblock %} \ No newline at end of file diff --git a/app/templates/keyboard_shortcuts.html b/app/templates/keyboard_shortcuts.html index 39dd82dc..36329b5e 100644 --- a/app/templates/keyboard_shortcuts.html +++ b/app/templates/keyboard_shortcuts.html @@ -1,23 +1,17 @@ {% extends "base.html" %} -{% block head %} - {{ super() }} - - -{% endblock %} {% block content %}
-
+
-
-
+
@@ -27,6 +21,10 @@
+ + + + @@ -56,9 +54,6 @@
- diff --git a/tests/test_keyboard_shortcuts_route.py b/tests/test_keyboard_shortcuts_route.py new file mode 100644 index 00000000..2b727c58 --- /dev/null +++ b/tests/test_keyboard_shortcuts_route.py @@ -0,0 +1,14 @@ +OK_STATUS_CODE = 200 +HOME = 'Home' + + +class TestKeyboardShortcuts: + URL = "/keyboard_shortcuts" + + def test_get_page(self, client): + res = client.get(self.URL) + assert res.status_code == OK_STATUS_CODE + + def test_home_shortcuts(self, client): + res = client.get(self.URL) + assert HOME in res.data From ab47c1eda0cb45f16c555f8dee4116949b442b4c Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Fri, 29 Jan 2021 16:18:30 +0200 Subject: [PATCH 03/13] remove home test --- tests/test_keyboard_shortcuts_route.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/test_keyboard_shortcuts_route.py b/tests/test_keyboard_shortcuts_route.py index 2b727c58..8c7276bb 100644 --- a/tests/test_keyboard_shortcuts_route.py +++ b/tests/test_keyboard_shortcuts_route.py @@ -1,5 +1,4 @@ OK_STATUS_CODE = 200 -HOME = 'Home' class TestKeyboardShortcuts: @@ -8,7 +7,3 @@ class TestKeyboardShortcuts: def test_get_page(self, client): res = client.get(self.URL) assert res.status_code == OK_STATUS_CODE - - def test_home_shortcuts(self, client): - res = client.get(self.URL) - assert HOME in res.data From da42ebbab0e89f0e5c774ddce9e583f0149ecfe3 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Sat, 30 Jan 2021 20:06:05 +0200 Subject: [PATCH 04/13] Change navigate to navigation --- app/templates/keyboard_shortcuts.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/keyboard_shortcuts.html b/app/templates/keyboard_shortcuts.html index 36329b5e..8067612f 100644 --- a/app/templates/keyboard_shortcuts.html +++ b/app/templates/keyboard_shortcuts.html @@ -7,7 +7,7 @@
From 9c29e960952ff41732d7f9eba8742083fb9ee7a1 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Sat, 30 Jan 2021 20:14:54 +0200 Subject: [PATCH 05/13] delete profile_shortcuts.js file --- app/static/keyboard_shortcuts/profile_shortcuts.js | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 app/static/keyboard_shortcuts/profile_shortcuts.js diff --git a/app/static/keyboard_shortcuts/profile_shortcuts.js b/app/static/keyboard_shortcuts/profile_shortcuts.js deleted file mode 100644 index 4bcbb098..00000000 --- a/app/static/keyboard_shortcuts/profile_shortcuts.js +++ /dev/null @@ -1,7 +0,0 @@ -import './mousetrap.js' - -Mousetrap.bind('alt+n', function () { - var nameModal = document.getElementById("updateNameModal"); - nameModal.style = 'padding-right: 16px; display: block;'; - console.log('hey') -}); \ No newline at end of file From 1cdbfd11190c7e9411701e077f12a8f4ba4e827a Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Sat, 30 Jan 2021 20:32:50 +0200 Subject: [PATCH 06/13] Fix - Pylint check - line too long --- app/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/main.py b/app/main.py index 4f46f77d..4e85b25e 100644 --- a/app/main.py +++ b/app/main.py @@ -9,7 +9,8 @@ MEDIA_PATH, STATIC_PATH, templates) from app.internal.quotes import load_quotes, daily_quotes from app.routers import ( - agenda, dayview, email, event, invitation, profile, search, telegram, keyboard_shortcuts, whatsapp) + agenda, dayview, email, event, invitation, profile, search, telegram, + keyboard_shortcuts, whatsapp) from app.telegram.bot import telegram_bot from app.internal.logger_customizer import LoggerCustomizer From b257545e4a5c1c08bf0e9573a6502f7357eede04 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Sun, 31 Jan 2021 22:15:32 +0200 Subject: [PATCH 07/13] Add test to test_keyboard_shortcuts_route.py --- tests/test_keyboard_shortcuts_route.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_keyboard_shortcuts_route.py b/tests/test_keyboard_shortcuts_route.py index 8c7276bb..86b7f98a 100644 --- a/tests/test_keyboard_shortcuts_route.py +++ b/tests/test_keyboard_shortcuts_route.py @@ -1,4 +1,5 @@ OK_STATUS_CODE = 200 +DATA_IN_SHORTCUTS_PAGE = b'General Shortcuts' class TestKeyboardShortcuts: @@ -7,3 +8,7 @@ class TestKeyboardShortcuts: def test_get_page(self, client): res = client.get(self.URL) assert res.status_code == OK_STATUS_CODE + + def test_get_keyboard_shortcuts_page(self, client): + res = client.get(self.URL) + assert DATA_IN_SHORTCUTS_PAGE in res.content From 3615ddc715c372ffdb93be868f7b725851cc9f4f Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Tue, 2 Feb 2021 22:01:36 +0200 Subject: [PATCH 08/13] Add Cypress Test --- .../keyboard_shortcuts_navigation.spec.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 cypress/integration/keyboard_shortcuts_navigation.spec.js diff --git a/cypress/integration/keyboard_shortcuts_navigation.spec.js b/cypress/integration/keyboard_shortcuts_navigation.spec.js new file mode 100644 index 00000000..5b76b1d4 --- /dev/null +++ b/cypress/integration/keyboard_shortcuts_navigation.spec.js @@ -0,0 +1,47 @@ +/// + + +Cypress.on('uncaught:exception', (err, runnable) => { + // returning false here prevents Cypress from + // failing the test + return false +}); + +context('Navigation Test', () => { + beforeEach(() => { + cy.visit('http://127.0.0.1:8000/') + }); + + describe('Navigation Test', () => { + + it('Home page has activated', () => { + cy.get('body').type('{alt}{c}{h}'); + cy.contains('Hello'); + }); + + it('Profile page has activated', () => { + cy.get('body').type('{alt}{c}{p}'); + cy.contains('Explore'); + }); + + it('Agenda page has activated', () => { + cy.get('body').type('{alt}{c}{a}'); + cy.contains('Next Week'); + }); + + it('Invitations page has activated', () => { + cy.get('body').type('{alt}{c}{i}'); + cy.contains('You don\'t have any invitations.'); + }); + + it('Search page has activated', () => { + cy.get('body').type('{alt}{c}{s}'); + cy.contains('Hello'); + }); + + it('Keyboard shortcuts page has activated', () => { + cy.get('body').type('{ctrl}.'); + cy.contains('General'); + }); + }); +}); From f5e397d173f36fdee8625add568ddc3dc880f493 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Tue, 23 Feb 2021 11:58:49 +0200 Subject: [PATCH 09/13] Fix alphabetic order --- app/main.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/main.py b/app/main.py index 19bc9aa7..bbd9b028 100644 --- a/app/main.py +++ b/app/main.py @@ -1,5 +1,3 @@ -import uvicorn - from fastapi import Depends, FastAPI, Request, status from fastapi.openapi.docs import ( get_swagger_ui_html, @@ -67,6 +65,7 @@ def create_tables(engine, psql_environment): google_connect, invitation, joke, + keyboard_shortcuts, login, logout, profile, @@ -77,7 +76,6 @@ def create_tables(engine, psql_environment): weekview, weight, whatsapp, - keyboard_shortcuts, ) json_data_loader.load_to_database(next(get_db())) @@ -117,6 +115,7 @@ async def swagger_ui_redirect(): google_connect.router, invitation.router, joke.router, + keyboard_shortcuts.router, login.router, logout.router, profile.router, @@ -128,7 +127,6 @@ async def swagger_ui_redirect(): weekview.router, weight.router, whatsapp.router, - keyboard_shortcuts.router, ] for router in routers_to_include: @@ -151,6 +149,3 @@ async def home(request: Request, db: Session = Depends(get_db)): custom_openapi(app) - -if __name__ == "__main__": - uvicorn.run(app, host="127.0.0.1", port=8000) From c1c274345af1884c07ffd474048ac66d0392f47e Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Tue, 23 Feb 2021 12:33:30 +0200 Subject: [PATCH 10/13] Change indent to 2 spaces --- app/templates/home.html | 56 +++++------ app/templates/keyboard_shortcuts.html | 96 +++++++++---------- .../sidebar_left/features_card.html | 66 ++++++------- 3 files changed, 109 insertions(+), 109 deletions(-) diff --git a/app/templates/home.html b/app/templates/home.html index a589591a..7d0f8536 100644 --- a/app/templates/home.html +++ b/app/templates/home.html @@ -3,36 +3,36 @@ {% block content %} -
-
+
+
-
-
- +
+
+ - -
- {% if quote %} - {% if not quote.author %} -

"{{ quote.text }}"

- {% else %} -

"{{ quote.text }}"   \ {{ quote.author }}

- {% endif %} - {% endif %} -
+ +
+ {% if quote %} + {% if not quote.author %} +

"{{ quote.text }}"

+ {% else %} +

"{{ quote.text }}"   \ {{ quote.author }}

+ {% endif %} + {% endif %} +
- -
- {% if quote %} - {% if not quote.author %} -

"{{ quote.text }}"

- {% else %} -

"{{ quote.text }}"   \ {{ quote.author }}

- {% endif %} - {% endif %} -
+ +
+ {% if quote %} + {% if not quote.author %} +

"{{ quote.text }}"

+ {% else %} +

"{{ quote.text }}"   \ {{ quote.author }}

+ {% endif %} + {% endif %} +
{% endblock %} diff --git a/app/templates/keyboard_shortcuts.html b/app/templates/keyboard_shortcuts.html index 65d66362..05ba75c7 100644 --- a/app/templates/keyboard_shortcuts.html +++ b/app/templates/keyboard_shortcuts.html @@ -1,54 +1,54 @@ {% extends "base.html" %} {% block content %} -
-
-
-
- -
-
-
-
-
Open HomePress Alt+C+H
Open Profile Press Alt+C+P
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ActionShortcut
Open HomePress Alt+C+H
Open ProfilePress Alt+C+P
Open AgendaPress Alt+C+A
Open InvitationsPress Alt+C+I
Open SearchPress Alt+C+S
Open All ShortcutsPress Ctrl+.
-
-
+
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionShortcut
Open HomePress Alt+C+H
Open ProfilePress Alt+C+P
Open AgendaPress Alt+C+A
Open InvitationsPress Alt+C+I
Open SearchPress Alt+C+S
Open All ShortcutsPress Ctrl+.
+
+
{% endblock %} diff --git a/app/templates/partials/user_profile/sidebar_left/features_card.html b/app/templates/partials/user_profile/sidebar_left/features_card.html index 1a4dcc0a..d760f07d 100644 --- a/app/templates/partials/user_profile/sidebar_left/features_card.html +++ b/app/templates/partials/user_profile/sidebar_left/features_card.html @@ -1,42 +1,42 @@
-
+
-

- Explore more features -

+

+ Explore more features +

-
+ +
From b0a5938d0f75392730a70f87b9f4333fa07814c6 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Thu, 25 Feb 2021 20:57:15 +0200 Subject: [PATCH 11/13] Change keyboard_shortcuts to modal --- app/main.py | 2 - .../keyboard_shortcuts/general_shortcuts.js | 5 +- app/templates/base.html | 171 +++++++++--------- app/templates/keyboard_shortcuts.html | 54 ------ .../keyboard_shortcuts_modal.html | 47 +++++ .../sidebar_left/features_card.html | 5 +- tests/test_keyboard_shortcuts_route.py | 14 -- 7 files changed, 143 insertions(+), 155 deletions(-) delete mode 100644 app/templates/keyboard_shortcuts.html create mode 100644 app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html delete mode 100644 tests/test_keyboard_shortcuts_route.py diff --git a/app/main.py b/app/main.py index bbd9b028..aa95cc21 100644 --- a/app/main.py +++ b/app/main.py @@ -65,7 +65,6 @@ def create_tables(engine, psql_environment): google_connect, invitation, joke, - keyboard_shortcuts, login, logout, profile, @@ -115,7 +114,6 @@ async def swagger_ui_redirect(): google_connect.router, invitation.router, joke.router, - keyboard_shortcuts.router, login.router, logout.router, profile.router, diff --git a/app/static/keyboard_shortcuts/general_shortcuts.js b/app/static/keyboard_shortcuts/general_shortcuts.js index 50587035..62fd9da6 100644 --- a/app/static/keyboard_shortcuts/general_shortcuts.js +++ b/app/static/keyboard_shortcuts/general_shortcuts.js @@ -6,8 +6,7 @@ let key_shortcuts = { 'alt+c+i': function() { window.open('/invitations/', '_self'); }, 'alt+c+p': function() { window.open('/profile/', '_self'); }, 'alt+c+s': function() { window.open('/search/', '_self'); }, - 'alt+c+a': function() { window.open('/agenda/', '_self'); }, - 'ctrl+.': function() { window.open('/keyboard_shortcuts/', '_self'); } + 'alt+c+a': function() { window.open('/agenda/', '_self'); } }; -Mousetrap.bind(key_shortcuts); \ No newline at end of file +Mousetrap.bind(key_shortcuts); diff --git a/app/templates/base.html b/app/templates/base.html index fe42719a..de5321a7 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -2,98 +2,107 @@ - {% block head %} + {% block head %} - - + + PyLendar {% block title %}{% endblock %} - {% endblock %} + {% endblock %} -
-
-
- -
- - {% block content %}{% endblock %} -
- - - - - - - - - - - - - - +
+
+
+ +
+ {% block content %}{% endblock %} +
+ + + + + + + + + + + + + + diff --git a/app/templates/keyboard_shortcuts.html b/app/templates/keyboard_shortcuts.html deleted file mode 100644 index 05ba75c7..00000000 --- a/app/templates/keyboard_shortcuts.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "base.html" %} - -{% block content %} -
-
-
-
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ActionShortcut
Open HomePress Alt+C+H
Open ProfilePress Alt+C+P
Open AgendaPress Alt+C+A
Open InvitationsPress Alt+C+I
Open SearchPress Alt+C+S
Open All ShortcutsPress Ctrl+.
-
-
-
-
-{% endblock %} diff --git a/app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html b/app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html new file mode 100644 index 00000000..e8317cd1 --- /dev/null +++ b/app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html @@ -0,0 +1,47 @@ + diff --git a/app/templates/partials/user_profile/sidebar_left/features_card.html b/app/templates/partials/user_profile/sidebar_left/features_card.html index d760f07d..77c193ac 100644 --- a/app/templates/partials/user_profile/sidebar_left/features_card.html +++ b/app/templates/partials/user_profile/sidebar_left/features_card.html @@ -29,9 +29,12 @@ Sync with Google {% endif %} +
  • - Keyboard Shortcuts + Keyboard Shortcuts
  • + {% include 'partials/user_profile/middle_content/keyboard_shortcuts_modal.html' %}
  • {% include 'partials/user_profile/sidebar_left/features_card/export_calendar.html' %} diff --git a/tests/test_keyboard_shortcuts_route.py b/tests/test_keyboard_shortcuts_route.py deleted file mode 100644 index da17d070..00000000 --- a/tests/test_keyboard_shortcuts_route.py +++ /dev/null @@ -1,14 +0,0 @@ -OK_STATUS_CODE = 200 -DATA_IN_SHORTCUTS_PAGE = b"General Shortcuts" - - -class TestKeyboardShortcuts: - URL = "/keyboard_shortcuts" - - def test_get_page(self, client): - res = client.get(self.URL) - assert res.ok - - def test_get_keyboard_shortcuts_page(self, client): - res = client.get(self.URL) - assert DATA_IN_SHORTCUTS_PAGE in res.content From 2973ec853b801dafa1f8853576761ddd24b17773 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Thu, 25 Feb 2021 21:01:04 +0200 Subject: [PATCH 12/13] Remove keyboard_shortcuts.py --- app/routers/keyboard_shortcuts.py | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 app/routers/keyboard_shortcuts.py diff --git a/app/routers/keyboard_shortcuts.py b/app/routers/keyboard_shortcuts.py deleted file mode 100644 index 30313636..00000000 --- a/app/routers/keyboard_shortcuts.py +++ /dev/null @@ -1,11 +0,0 @@ -from app.dependencies import templates -from fastapi import APIRouter, Request -from starlette.templating import _TemplateResponse - -router = APIRouter() - - -@router.get("/keyboard_shortcuts") -def keyboard_shortcuts(request: Request) -> _TemplateResponse: - return templates.TemplateResponse("keyboard_shortcuts.html", { - "request": request}) From 91e50ce6b9e9dc0da9ad0ff0ef23d1620aa5ebd1 Mon Sep 17 00:00:00 2001 From: Yair Engel Date: Thu, 25 Feb 2021 22:43:48 +0200 Subject: [PATCH 13/13] CHange U letter to u lowercase to check upload --- .../user_profile/middle_content/keyboard_shortcuts_modal.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html b/app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html index 9ed9cf39..0c781398 100644 --- a/app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html +++ b/app/templates/partials/user_profile/middle_content/keyboard_shortcuts_modal.html @@ -29,7 +29,7 @@ Open Audio Settings - Press Alt+C+U + Press Alt+C+u Open Search