summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js
blob: c17877a276d6bf6562d5f126fbb6397f40023c98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import sqljs from 'sql.js';
import { template as _template } from 'underscore';

const PREVIEW_TEMPLATE = _template(`
  <div class="panel panel-default">
    <div class="panel-heading"><%- name %></div>
    <div class="panel-body">
      <img class="img-thumbnail" src="data:image/png;base64,<%- image %>"/>
    </div>
  </div>
`);

class BalsamiqViewer {
  constructor(viewer) {
    this.viewer = viewer;
  }

  loadFile(endpoint) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();

      xhr.open('GET', endpoint, true);
      xhr.responseType = 'arraybuffer';
      xhr.onload = loadEvent => this.fileLoaded(loadEvent, resolve, reject);
      xhr.onerror = reject;

      xhr.send();
    });
  }

  fileLoaded(loadEvent, resolve, reject) {
    if (loadEvent.target.status !== 200) return reject();

    this.renderFile(loadEvent);

    return resolve();
  }

  renderFile(loadEvent) {
    const container = document.createElement('ul');

    this.initDatabase(loadEvent.target.response);

    const previews = this.getPreviews();
    previews.forEach((preview) => {
      const renderedPreview = this.renderPreview(preview);

      container.appendChild(renderedPreview);
    });

    container.classList.add('list-inline');
    container.classList.add('previews');

    this.viewer.appendChild(container);
  }

  initDatabase(data) {
    const previewBinary = new Uint8Array(data);

    this.database = new sqljs.Database(previewBinary);
  }

  getPreviews() {
    const thumbnails = this.database.exec('SELECT * FROM thumbnails');

    return thumbnails[0].values.map(BalsamiqViewer.parsePreview);
  }

  getResource(resourceID) {
    const resources = this.database.exec(`SELECT * FROM resources WHERE id = '${resourceID}'`);

    return resources[0];
  }

  renderPreview(preview) {
    const previewElement = document.createElement('li');

    previewElement.classList.add('preview');
    previewElement.innerHTML = this.renderTemplate(preview);

    return previewElement;
  }

  renderTemplate(preview) {
    const resource = this.getResource(preview.resourceID);
    const name = BalsamiqViewer.parseTitle(resource);
    const image = preview.image;

    const template = PREVIEW_TEMPLATE({
      name,
      image,
    });

    return template;
  }

  static parsePreview(preview) {
    return JSON.parse(preview[1]);
  }

  /*
   * resource = {
   *   columns: ['ID', 'BRANCHID', 'ATTRIBUTES', 'DATA'],
   *   values: [['id', 'branchId', 'attributes', 'data']],
   * }
   *
   * 'attributes' being a JSON string containing the `name` property.
   */
  static parseTitle(resource) {
    return JSON.parse(resource.values[0][2]).name;
  }
}

export default BalsamiqViewer;