copy_tuner_client 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/package.json CHANGED
@@ -5,10 +5,23 @@
5
5
  "author": "SonicGarden",
6
6
  "license": "MIT",
7
7
  "scripts": {
8
- "build": "coffee -o app/assets/javascripts -c src/copyray.coffee",
9
- "watch": "coffee -o app/assets/javascripts -w src/copyray.coffee"
8
+ "build": "rollup -c",
9
+ "watch": "rollup -c -w"
10
+ },
11
+ "dependencies": {
12
+ "keycode-js": "0.0.4",
13
+ "lodash.debounce": "^4.0.8"
10
14
  },
11
15
  "devDependencies": {
12
- "coffeescript": "^1.12.6"
16
+ "babel-plugin-external-helpers": "^6.22.0",
17
+ "babel-preset-env": "^1.6.0",
18
+ "eslint": "^3.19.0",
19
+ "eslint-config-airbnb-base": "^11.2.0",
20
+ "eslint-plugin-import": "^2.7.0",
21
+ "rollup": "^0.45.2",
22
+ "rollup-plugin-babel": "^2.7.1",
23
+ "rollup-plugin-commonjs": "^8.0.2",
24
+ "rollup-plugin-node-resolve": "^3.0.0",
25
+ "rollup-watch": "^4.3.1"
13
26
  }
14
27
  }
data/rollup.config.js ADDED
@@ -0,0 +1,14 @@
1
+ import babel from 'rollup-plugin-babel';
2
+ import resolve from 'rollup-plugin-node-resolve';
3
+ import commonjs from 'rollup-plugin-commonjs';
4
+
5
+ export default {
6
+ entry: 'src/main.js',
7
+ dest: 'app/assets/javascripts/copyray.js',
8
+ format: 'iife',
9
+ plugins: [
10
+ resolve({ jsnext: true, main: true }),
11
+ commonjs(),
12
+ babel({ exclude: 'node_modules/**' }),
13
+ ],
14
+ };
data/src/copyray.js ADDED
@@ -0,0 +1,111 @@
1
+ import Specimen from './specimen';
2
+ import CopyTunerBar from './copytuner_bar';
3
+
4
+ const findBlurbs = () => {
5
+ const filterNone = () => NodeFilter.FILTER_ACCEPT;
6
+
7
+ const iterator = document.createNodeIterator(
8
+ document.body,
9
+ NodeFilter.SHOW_COMMENT,
10
+ filterNone,
11
+ false,
12
+ );
13
+
14
+ const comments = [];
15
+ let curNode;
16
+ // eslint-disable-next-line no-cond-assign
17
+ while ((curNode = iterator.nextNode())) {
18
+ comments.push(curNode);
19
+ }
20
+
21
+ return comments.filter(comment => comment.nodeValue.startsWith('COPYRAY')).map((comment) => {
22
+ const [, key] = comment.nodeValue.match(/^COPYRAY (\S*)$/);
23
+ const element = comment.parentNode;
24
+ return { key, element };
25
+ });
26
+ };
27
+
28
+ export default class Copyray {
29
+ constructor(baseUrl, data) {
30
+ this.baseUrl = baseUrl;
31
+ this.data = data;
32
+ this.isShowing = false;
33
+ this.specimens = [];
34
+ this.overlay = this.makeOverlay();
35
+ this.toggleButton = this.makeToggleButton();
36
+ this.boundOpen = this.open.bind(this);
37
+
38
+ this.copyTunerBar = new CopyTunerBar(
39
+ document.getElementById('copy-tuner-bar'),
40
+ this.data,
41
+ this.boundOpen,
42
+ );
43
+ }
44
+
45
+ show() {
46
+ this.reset();
47
+
48
+ document.body.appendChild(this.overlay);
49
+ this.makeSpecimens();
50
+
51
+ this.specimens.forEach((specimen) => {
52
+ specimen.show();
53
+ });
54
+
55
+ this.copyTunerBar.show();
56
+ this.isShowing = true;
57
+ }
58
+
59
+ hide() {
60
+ this.overlay.remove();
61
+ this.reset();
62
+ this.copyTunerBar.hide();
63
+ this.isShowing = false;
64
+ }
65
+
66
+ toggle() {
67
+ if (this.isShowing) {
68
+ this.hide();
69
+ } else {
70
+ this.show();
71
+ }
72
+ }
73
+
74
+ open(key) {
75
+ const url = `${this.baseUrl}/blurbs/${key}/edit`;
76
+ window.open(url, null, 'width=700, height=600');
77
+ }
78
+
79
+ makeSpecimens() {
80
+ findBlurbs().forEach(({ element, key }) => {
81
+ this.specimens.push(new Specimen(element, key, this.boundOpen));
82
+ });
83
+ }
84
+
85
+ makeToggleButton() {
86
+ const element = document.createElement('a');
87
+
88
+ element.addEventListener('click', () => {
89
+ this.show();
90
+ });
91
+
92
+ element.classList.add('copyray-toggle-button');
93
+ element.textContent = 'Open CopyTuner';
94
+ document.body.appendChild(element);
95
+
96
+ return element;
97
+ }
98
+
99
+ makeOverlay() {
100
+ const div = document.createElement('div');
101
+ div.setAttribute('id', 'copyray-overlay');
102
+ div.addEventListener('click', () => this.hide());
103
+ return div;
104
+ }
105
+
106
+ reset() {
107
+ this.specimens.forEach((specimen) => {
108
+ specimen.remove();
109
+ });
110
+ }
111
+ }
@@ -0,0 +1,96 @@
1
+ import debounce from 'lodash.debounce';
2
+
3
+ const HIDDEN_CLASS = 'copy-tuner-hidden';
4
+
5
+ export default class CopytunerBar {
6
+ constructor(element, data, callback) {
7
+ this.element = element;
8
+ this.data = data;
9
+ this.callback = callback;
10
+ this.searchBoxElement = element.querySelector('.js-copy-tuner-bar-search');
11
+ this.logMenuElement = this.makeLogMenu();
12
+ this.element.appendChild(this.logMenuElement);
13
+
14
+ this.addHandler();
15
+ }
16
+
17
+ addHandler() {
18
+ const openLogButton = this.element.querySelector('.js-copy-tuner-bar-open-log');
19
+ openLogButton.addEventListener('click', (event) => {
20
+ event.preventDefault();
21
+ this.toggleLogMenu();
22
+ });
23
+
24
+ this.searchBoxElement.addEventListener('input', debounce(this.onKeyup.bind(this), 250));
25
+ }
26
+
27
+ show() {
28
+ this.element.classList.remove(HIDDEN_CLASS);
29
+ this.searchBoxElement.focus();
30
+ }
31
+
32
+ hide() {
33
+ this.element.classList.add(HIDDEN_CLASS);
34
+ }
35
+
36
+ showLogMenu() {
37
+ this.logMenuElement.classList.remove(HIDDEN_CLASS);
38
+ }
39
+
40
+ toggleLogMenu() {
41
+ this.logMenuElement.classList.toggle(HIDDEN_CLASS);
42
+ }
43
+
44
+ makeLogMenu() {
45
+ const div = document.createElement('div');
46
+ div.setAttribute('id', 'copy-tuner-bar-log-menu');
47
+ div.classList.add(HIDDEN_CLASS);
48
+
49
+ const table = document.createElement('table');
50
+ const tbody = document.createElement('tbody');
51
+ tbody.classList.remove('is-not-initialized');
52
+
53
+ Object.keys(this.data).sort().forEach((key) => {
54
+ const value = this.data[key];
55
+
56
+ if (value === '') {
57
+ return;
58
+ }
59
+
60
+ const td1 = document.createElement('td');
61
+ td1.textContent = key;
62
+ const td2 = document.createElement('td');
63
+ td2.textContent = value;
64
+ const tr = document.createElement('tr');
65
+ tr.classList.add('copy-tuner-bar-log-menu__row');
66
+ tr.dataset.key = key;
67
+
68
+ tr.addEventListener('click', ({ currentTarget }) => {
69
+ this.callback(currentTarget.dataset.key);
70
+ });
71
+
72
+ tr.appendChild(td1);
73
+ tr.appendChild(td2);
74
+ tbody.appendChild(tr);
75
+ });
76
+
77
+ table.appendChild(tbody);
78
+ div.appendChild(table);
79
+
80
+ return div;
81
+ }
82
+
83
+ onKeyup({ target }) {
84
+ const keyword = target.value.trim();
85
+ this.showLogMenu();
86
+
87
+ const rows = Array.from(this.logMenuElement.getElementsByTagName('tr'));
88
+
89
+ rows.forEach((row) => {
90
+ const isShow =
91
+ keyword === '' ||
92
+ Array.from(row.getElementsByTagName('td')).some(td => td.textContent.includes(keyword));
93
+ row.classList.toggle(HIDDEN_CLASS, !isShow);
94
+ });
95
+ }
96
+ }
data/src/main.js ADDED
@@ -0,0 +1,42 @@
1
+ import KeyCode from 'keycode-js';
2
+ import Copyray from './copyray';
3
+ import { isMac } from './util';
4
+
5
+ const start = () => {
6
+ const dataElement = document.getElementById('copy-tuner-data');
7
+ const copyTunerUrl = dataElement.dataset.copyTunerUrl;
8
+ const data = JSON.parse(
9
+ document.getElementById('copy-tuner-data').dataset.copyTunerTranslationLog,
10
+ );
11
+ const copyray = new Copyray(copyTunerUrl, data);
12
+
13
+ document.addEventListener('keydown', (event) => {
14
+ if (copyray.isShowing && event.keyCode === KeyCode.KEY_ESCAPE) {
15
+ copyray.hide();
16
+ return;
17
+ }
18
+
19
+ if (
20
+ ((isMac && event.metaKey) || (!isMac && event.ctrlKey)) &&
21
+ event.shiftKey &&
22
+ event.keyCode === KeyCode.KEY_K
23
+ ) {
24
+ copyray.toggle();
25
+ }
26
+ });
27
+
28
+ if (console) {
29
+ // eslint-disable-next-line no-console
30
+ console.log(
31
+ `Ready to Copyray. Press ${isMac ? 'cmd+shift+k' : 'ctrl+shift+k'} to scan your UI.`,
32
+ );
33
+ }
34
+
35
+ window.copyray = copyray;
36
+ };
37
+
38
+ if (document.readyState === 'complete' || document.readyState !== 'loading') {
39
+ start();
40
+ } else {
41
+ document.addEventListener('DOMContentLoaded', start);
42
+ }
data/src/specimen.js ADDED
@@ -0,0 +1,63 @@
1
+ import { computeBoundingBox } from './util';
2
+
3
+ const ZINDEX = 2000000000;
4
+
5
+ export default class Specimen {
6
+ constructor(element, key, callback) {
7
+ this.element = element;
8
+ this.key = key;
9
+ this.callback = callback;
10
+ }
11
+
12
+ show() {
13
+ this.box = this.makeBox();
14
+ if (this.box === null) return;
15
+
16
+ this.box.addEventListener('click', () => {
17
+ this.callback(this.key);
18
+ });
19
+
20
+ document.body.appendChild(this.box);
21
+ }
22
+
23
+ remove() {
24
+ if (!this.box) {
25
+ return;
26
+ }
27
+ this.box.remove();
28
+ this.box = null;
29
+ }
30
+
31
+ makeBox() {
32
+ const box = document.createElement('div');
33
+ box.classList.add('copyray-specimen');
34
+ box.classList.add('Specimen');
35
+
36
+ const bounds = computeBoundingBox(this.element);
37
+ if (bounds === null) return null;
38
+
39
+ Object.keys(bounds).forEach((key) => {
40
+ const value = bounds[key];
41
+ box.style[key] = `${value}px`;
42
+ });
43
+ box.style.zIndex = ZINDEX;
44
+
45
+ const { position, top, left } = getComputedStyle(this.element);
46
+ if (position === 'fixed') {
47
+ this.box.style.position = 'fixed';
48
+ this.box.style.top = `${top}px`;
49
+ this.box.style.left = `${left}px`;
50
+ }
51
+
52
+ box.appendChild(this.makeLabel());
53
+ return box;
54
+ }
55
+
56
+ makeLabel() {
57
+ const div = document.createElement('div');
58
+ div.classList.add('copyray-specimen-handle');
59
+ div.classList.add('Specimen');
60
+ div.textContent = this.key;
61
+ return div;
62
+ }
63
+ }
data/src/util.js ADDED
@@ -0,0 +1,32 @@
1
+ const isMac = navigator.platform.toUpperCase().indexOf('MAC') !== -1;
2
+
3
+ const isVisible = element =>
4
+ !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
5
+
6
+ const getOffset = (elment) => {
7
+ const box = elment.getBoundingClientRect();
8
+
9
+ return {
10
+ top: box.top + (window.pageYOffset - document.documentElement.clientTop),
11
+ left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
12
+ };
13
+ };
14
+
15
+ const computeBoundingBox = (element) => {
16
+ if (!isVisible(element)) {
17
+ return null;
18
+ }
19
+
20
+ const boxFrame = getOffset(element);
21
+ boxFrame.right = boxFrame.left + element.offsetWidth;
22
+ boxFrame.bottom = boxFrame.top + element.offsetHeight;
23
+
24
+ return {
25
+ left: boxFrame.left,
26
+ top: boxFrame.top,
27
+ width: boxFrame.right - boxFrame.left,
28
+ height: boxFrame.bottom - boxFrame.top,
29
+ };
30
+ };
31
+
32
+ export { isMac, isVisible, getOffset, computeBoundingBox };
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: copy_tuner_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - SonicGarden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-13 00:00:00.000000000 Z
11
+ date: 2017-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -226,6 +226,8 @@ executables: []
226
226
  extensions: []
227
227
  extra_rdoc_files: []
228
228
  files:
229
+ - ".babelrc"
230
+ - ".eslintrc"
229
231
  - ".gitignore"
230
232
  - ".rspec"
231
233
  - ".ruby-version"
@@ -239,7 +241,6 @@ files:
239
241
  - app/assets/javascripts/copyray.js
240
242
  - app/assets/stylesheets/copyray.css
241
243
  - app/views/_copy_tuner_bar.html.erb
242
- - coffeelint.json
243
244
  - copy_tuner_client.gemspec
244
245
  - features/rails.feature
245
246
  - features/step_definitions/copycopter_server_steps.rb
@@ -270,6 +271,7 @@ files:
270
271
  - lib/tasks/copy_tuner_client_tasks.rake
271
272
  - package-lock.json
272
273
  - package.json
274
+ - rollup.config.js
273
275
  - spec/copy_tuner_client/cache_spec.rb
274
276
  - spec/copy_tuner_client/client_spec.rb
275
277
  - spec/copy_tuner_client/configuration_spec.rb
@@ -291,7 +293,11 @@ files:
291
293
  - spec/support/fake_unicorn.rb
292
294
  - spec/support/middleware_stack.rb
293
295
  - spec/support/writing_cache.rb
294
- - src/copyray.coffee
296
+ - src/copyray.js
297
+ - src/copytuner_bar.js
298
+ - src/main.js
299
+ - src/specimen.js
300
+ - src/util.js
295
301
  - ui/views/copytuner/index.html.erb
296
302
  - ui/views/layouts/copytuner_default.html.erb
297
303
  homepage: https://github.com/SonicGarden/copy-tuner-ruby-client