UserHotKeys.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <template>
  2. <div class="table col column no-wrap">
  3. <!-- header -->
  4. <div class="table-row row">
  5. <div class="desc q-pa-sm bg-blue-2">Команда</div>
  6. <div class="hotKeys col q-pa-sm bg-blue-2 row no-wrap">
  7. <div style="width: 80px">Сочетание клавиш</div>
  8. <q-input ref="input" class="q-ml-sm col"
  9. outlined dense rounded
  10. bg-color="grey-4"
  11. placeholder="Найти"
  12. v-model="search"
  13. @click.stop
  14. />
  15. <div v-show="!readonly" class="q-ml-sm column justify-center">
  16. <q-btn class="bg-grey-4 text-grey-6" style="height: 35px; width: 35px" rounded flat icon="la la-broom" @click="defaultHotKeyAll">
  17. <q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
  18. Установить все сочетания по умолчанию
  19. </q-tooltip>
  20. </q-btn>
  21. </div>
  22. </div>
  23. </div>
  24. <!-- body -->
  25. <div class="table-row row" v-for="(action, index) in tableData" :key="index">
  26. <div class="desc q-pa-sm">{{ rstore.readerActions[action] }}</div>
  27. <div class="hotKeys col q-pa-sm">
  28. <q-chip
  29. :color="collisions[code] ? 'red' : 'grey-7'"
  30. :removable="!readonly" :clickable="collisions[code] ? true : false"
  31. text-color="white" v-for="(code, index) in value[action]" :key="index" @remove="removeCode(action, code)"
  32. @click="collisionWarning(code)"
  33. >
  34. {{ code }}
  35. </q-chip>
  36. </div>
  37. <div v-show="!readonly" class="column q-pa-xs">
  38. <q-icon
  39. name="la la-plus-circle"
  40. class="button bg-green-8 text-white"
  41. @click="addHotKey(action)"
  42. v-ripple
  43. :disabled="value[action].length >= maxCodesLength"
  44. >
  45. <q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
  46. Добавить сочетание клавиш
  47. </q-tooltip>
  48. </q-icon>
  49. <q-icon
  50. name="la la-broom"
  51. class="button text-grey-5"
  52. @click="defaultHotKey(action)"
  53. v-ripple
  54. >
  55. <q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
  56. По умолчанию
  57. </q-tooltip>
  58. </q-icon>
  59. </div>
  60. </div>
  61. </div>
  62. </template>
  63. <script>
  64. //-----------------------------------------------------------------------------
  65. import Vue from 'vue';
  66. import Component from 'vue-class-component';
  67. import rstore from '../../../../store/modules/reader';
  68. //import * as utils from '../../share/utils';
  69. const UserHotKeysProps = Vue.extend({
  70. props: {
  71. value: Object,
  72. readonly: Boolean,
  73. }
  74. });
  75. export default @Component({
  76. watch: {
  77. search: function() {
  78. this.updateTableData();
  79. },
  80. value: function() {
  81. this.checkCollisions();
  82. this.updateTableData();
  83. }
  84. },
  85. })
  86. class UserHotKeys extends UserHotKeysProps {
  87. search = '';
  88. rstore = {};
  89. tableData = [];
  90. collisions = {};
  91. maxCodesLength = 10;
  92. created() {
  93. this.rstore = rstore;
  94. }
  95. mounted() {
  96. this.checkCollisions();
  97. this.updateTableData();
  98. }
  99. updateTableData() {
  100. let result = rstore.hotKeys.map(hk => hk.name);
  101. const search = this.search.toLowerCase();
  102. const codesIncludeSearch = (action) => {
  103. for (const code of this.value[action]) {
  104. if (code.toLowerCase().includes(search))
  105. return true;
  106. }
  107. return false;
  108. };
  109. result = result.filter(item => {
  110. return !search ||
  111. rstore.readerActions[item].toLowerCase().includes(search) ||
  112. codesIncludeSearch(item)
  113. });
  114. this.tableData = result;
  115. }
  116. checkCollisions() {
  117. const cols = {};
  118. for (const [action, codes] of Object.entries(this.value)) {
  119. codes.forEach(code => {
  120. if (!cols[code])
  121. cols[code] = [];
  122. if (cols[code].indexOf(action) < 0)
  123. cols[code].push(action);
  124. });
  125. }
  126. const result = {};
  127. for (const [code, actions] of Object.entries(cols)) {
  128. if (actions.length > 1)
  129. result[code] = actions;
  130. }
  131. this.collisions = result;
  132. }
  133. collisionWarning(code) {
  134. if (this.collisions[code]) {
  135. const descs = this.collisions[code].map(action => `<b>${rstore.readerActions[action]}</b>`);
  136. this.$root.stdDialog.alert(`Сочетание '${code}' одновременно назначено<br>следующим командам:<br>${descs.join('<br>')}<br><br>
  137. Возможно неожиданное поведение.`, 'Предупреждение');
  138. }
  139. }
  140. removeCode(action, code) {
  141. let codes = Array.from(this.value[action]);
  142. const index = codes.indexOf(code);
  143. if (index >= 0) {
  144. codes.splice(index, 1);
  145. const newValue = Object.assign({}, this.value, {[action]: codes});
  146. this.$emit('input', newValue);
  147. }
  148. }
  149. async addHotKey(action) {
  150. if (this.value[action].length >= this.maxCodesLength)
  151. return;
  152. try {
  153. const result = await this.$root.stdDialog.getHotKey(`Добавить сочетание для:<br><b>${rstore.readerActions[action]}</b>`, '');
  154. if (result) {
  155. let codes = Array.from(this.value[action]);
  156. if (codes.indexOf(result) < 0) {
  157. codes.push(result);
  158. const newValue = Object.assign({}, this.value, {[action]: codes});
  159. this.$emit('input', newValue);
  160. this.$nextTick(() => {
  161. this.collisionWarning(result);
  162. });
  163. }
  164. }
  165. } catch (e) {
  166. //
  167. }
  168. }
  169. async defaultHotKey(action) {
  170. try {
  171. if (await this.$root.stdDialog.confirm(`Подтвердите сброс сочетаний клавиш<br>в значения по умолчанию для команды:<br><b>${rstore.readerActions[action]}</b>`, ' ')) {
  172. const codes = Array.from(rstore.settingDefaults.userHotKeys[action]);
  173. const newValue = Object.assign({}, this.value, {[action]: codes});
  174. this.$emit('input', newValue);
  175. }
  176. } catch (e) {
  177. //
  178. }
  179. }
  180. async defaultHotKeyAll() {
  181. try {
  182. if (await this.$root.stdDialog.confirm('Подтвердите сброс сочетаний клавиш<br>для ВСЕХ команд в значения по умолчанию:', ' ')) {
  183. const newValue = Object.assign({}, rstore.settingDefaults.userHotKeys);
  184. this.$emit('input', newValue);
  185. }
  186. } catch (e) {
  187. //
  188. }
  189. }
  190. }
  191. //-----------------------------------------------------------------------------
  192. </script>
  193. <style scoped>
  194. .table {
  195. border-left: 1px solid grey;
  196. border-top: 1px solid grey;
  197. }
  198. .table-row {
  199. border-right: 1px solid grey;
  200. border-bottom: 1px solid grey;
  201. }
  202. .table-row:nth-child(even) {
  203. background-color: #f7f7f7;
  204. }
  205. .table-row:hover {
  206. background-color: #f0f0f0;
  207. }
  208. .desc {
  209. width: 130px;
  210. overflow-wrap: break-word;
  211. word-wrap: break-word;
  212. white-space: normal;
  213. }
  214. .hotKeys {
  215. border-left: 1px solid grey;
  216. }
  217. .button {
  218. font-size: 25px;
  219. border-radius: 25px;
  220. cursor: pointer;
  221. }
  222. </style>