copy_tuner_client 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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