Skip to content
This repository was archived by the owner on Oct 2, 2018. It is now read-only.

Commit 64904d7

Browse files
committed
Merge pull request #309 from twiss/builder
Add build script
2 parents 5de7160 + e6424c5 commit 64904d7

File tree

7 files changed

+322
-2
lines changed

7 files changed

+322
-2
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/build/
2+
/builder/node_modules/
3+
logs
4+
*.log
5+
npm-debug.log*
16
.DS_Store
27
._.DS_Store
38
.db

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
path = scripts/parsers/odt.js
33
url = https://github.com/codexa/odt.js.git
44
branch = master
5+
[submodule "builder/airbornos"]
6+
path = builder/airbornos
7+
url = https://github.com/airbornos/airbornos

builder/airbornos

Submodule airbornos added at 83c2920

builder/build

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env bash
2+
3+
original_dir=$(pwd)
4+
5+
cd $(dirname $BASH_SOURCE)
6+
7+
npm install
8+
9+
[ -e ../build ] || mkdir ../build
10+
11+
node build.js ../index.html "$@"
12+
[ -e ../build/scripts.js.map ] && (echo "//# sourceMappingURL=scripts.js.map" >> ../build/scripts.js)
13+
14+
cp -r ../modules ../build
15+
cp -r ../locales ../build
16+
cp ../manifest.webapp ../build
17+
18+
mkdir -p ../build/scripts/lib
19+
mkdir -p ../build/scripts/parsers/odt.js/lib
20+
cp ../scripts/messages.js ../build/scripts
21+
cp ../scripts/lib/jszip.js ../build/scripts/lib
22+
cp ../scripts/lib/jszip-deflate.js ../build/scripts/lib
23+
cp ../scripts/lib/jszip-inflate.js ../build/scripts/lib
24+
cp ../scripts/lib/jszip-load.js ../build/scripts/lib
25+
cp ../scripts/lib/stringview.js ../build/scripts/lib
26+
cp ../scripts/lib/innertext.js ../build/scripts/lib
27+
cp ../scripts/parsers/docx.js ../build/scripts/parsers
28+
cp ../scripts/parsers/plain-text.js ../build/scripts/parsers
29+
cp ../scripts/parsers/odt.js/lib/odt.js ../build/scripts/parsers/odt.js/lib
30+
31+
mkdir -p ../build/style/icons/app
32+
cp ../style/icons/app/32.png ../build/style/icons/app
33+
cp ../style/icons/app/60.png ../build/style/icons/app
34+
cp ../style/icons/app/90.png ../build/style/icons/app
35+
cp ../style/icons/app/120.png ../build/style/icons/app
36+
cp ../style/icons/app/256.png ../build/style/icons/app
37+
cp ../style/icons/app/firetext_christmas.svg ../build/style/icons/app
38+
39+
cd $original_dir

builder/build.js

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/*** SET UP AIRBORN OS ***/
2+
3+
var fs = require('fs');
4+
5+
var window = global.window = global;
6+
global.parent = global;
7+
8+
window.sjcl = require('sjcl');
9+
10+
function randomWords(n) {
11+
return Array.apply(null, new Array(n)).map(function() { return Math.floor(Math.random() * 0xFFFFFFFF); });
12+
}
13+
var hmac_bits = randomWords(4);
14+
var files_hmac = window.files_hmac = new sjcl.misc.hmac(hmac_bits);
15+
16+
window.XMLHttpRequest = function() {
17+
this.listeners = {};
18+
};
19+
window.XMLHttpRequest.prototype.addEventListener = function(name, listener) {
20+
if(!this.listeners[name]) {
21+
this.listeners[name] = [];
22+
}
23+
this.listeners[name].push(listener);
24+
};
25+
window.XMLHttpRequest.prototype.emit = function(name) {
26+
if(this.listeners[name]) {
27+
var _this = this;
28+
this.listeners[name].forEach(function(listener) {
29+
listener.call(_this);
30+
});
31+
}
32+
};
33+
window.XMLHttpRequest.prototype.open = function(method, url) {
34+
if(url.substr(0, 8) === '/object/' && method === 'GET') {
35+
var hash = url.split('#')[1]
36+
url = '../' + hash.substr(hash.indexOf('.') + 1).replace('/Core/', 'builder/airbornos/');
37+
Object.defineProperty(this, 'send', {value: function() {
38+
var _this = this;
39+
fs.readFile(url, 'base64', function(err, contents) {
40+
Object.defineProperty(_this, 'readyState', {get: function() { return 4; }});
41+
if(err) {
42+
Object.defineProperty(_this, 'status', {get: function() {
43+
return 404;
44+
}});
45+
} else {
46+
Object.defineProperty(_this, 'status', {get: function() {
47+
return 200;
48+
}, configurable: true});
49+
Object.defineProperty(_this, 'response', {get: function() {
50+
return codec.base64.toAB(contents);
51+
}});
52+
}
53+
_this.emit('readystatechange');
54+
_this.emit('load');
55+
});
56+
}});
57+
return;
58+
} else if(url.substr(0, 8) === '/object/' || url.substr(0, 13) === '/transaction/') {
59+
Object.defineProperty(this, 'setRequestHeader', {value: function() {}});
60+
Object.defineProperty(this, 'send', {value: function() {
61+
Object.defineProperty(this, 'readyState', {get: function() { return 4; }});
62+
Object.defineProperty(this, 'status', {get: function() {
63+
return 200;
64+
}});
65+
this.emit('readystatechange');
66+
this.emit('load');
67+
}});
68+
return;
69+
}
70+
throw new Error('Unknown XMLHttpRequest url: ' + url);
71+
};
72+
73+
window.document = {};
74+
document.createElement = function() {
75+
return {};
76+
};
77+
document.head = {};
78+
document.head.appendChild = function() {};
79+
80+
window.crypto = {};
81+
window.crypto.getRandomValues = function(array) {
82+
var words = randomWords(array.length);
83+
words.forEach(function(word, i) {
84+
array[i] = word;
85+
});
86+
};
87+
88+
window.atob = function(str) { return new Buffer(str, 'base64').toString('binary'); };
89+
window.btoa = function(str) { return new Buffer(str, 'binary').toString('base64'); };
90+
91+
window.TextDecoder = function() {};
92+
TextDecoder.prototype.decode = function(dataview) { return new Buffer(codec.base64.fromAB(dataview.buffer), 'base64').toString('utf8'); };
93+
window.TextEncoder = function() {};
94+
TextEncoder.prototype.encode = function(str) { return {buffer: codec.base64.toAB(new Buffer(str, 'utf8').toString('base64'))}; };
95+
96+
window.navigator = {};
97+
window.navigator.userAgent = {
98+
match: function() { return String.prototype.match.apply('Safari', arguments); }, // Use the full set of variable rewrites
99+
indexOf: function() { return String.prototype.match.apply('Chrome', arguments); }, // Use Data URLs
100+
};
101+
window.location = {};
102+
window.location.protocol = 'https:';
103+
104+
window.eval(fs.readFileSync('airbornos/core.js', 'utf8'));
105+
106+
window.encrypt = window.decrypt = function(key, content, callback) {
107+
callback(content);
108+
};
109+
110+
/*** END SET UP AIRBORN OS ***/
111+
112+
113+
var argv = require('yargs').argv;
114+
115+
// Compile everything into a single html file
116+
prepareFile(argv._[0].replace('../', ''), {compat: false, _compat: false, bootstrap: false, rootParent: ''}, function(contents) {
117+
118+
// Extract scripts
119+
var scripts = [];
120+
contents = contents.replace(/<script([^>]*)src="([^"]*)"([^>]*)><\/script>/g, function(match, preAttrs, url, postAttrs) {
121+
scripts.push('../' + decodeURIComponent(url.split(',')[0].match(/filename=([^;]*);/)[1]));
122+
return '';
123+
});
124+
125+
126+
// Minify scripts
127+
var scriptsFileName = argv._[0].replace('../', '../build/').replace(/[^\/]*\.html/, 'scripts.js');
128+
var cc = require('child_process').spawn('java', [
129+
'-jar', 'node_modules/google-closure-compiler/compiler.jar',
130+
'--language_in', 'ECMASCRIPT5',
131+
'--js_output_file', scriptsFileName,
132+
].concat(argv.sourceMap === false ? [] : [
133+
'--create_source_map', '%outname%.map'
134+
]).concat(scripts));
135+
cc.stderr.on('data', function(data) {
136+
console.error('' + data);
137+
});
138+
cc.on('close', function() {
139+
contents = contents.replace(/(?=<\/head)/i, '<script src="scripts.js"></script>');
140+
141+
142+
// Extract styles
143+
var styles = [];
144+
contents = contents.replace(/<link([^>]*)href="([^"]*)"([^>]*)>/g, function(match, preAttrs, url, postAttrs) {
145+
var attrs = preAttrs + postAttrs;
146+
if(attrs.indexOf(' rel="stylesheet"') !== -1) {
147+
var style = decodeURIComponent(url.split(',')[1]);
148+
var media = attrs.match(/media="([^"]*)"/);
149+
if(media) style = '@media ' + media[1] + '{' + style + '}';
150+
styles.push(style);
151+
return '';
152+
}
153+
return match;
154+
});
155+
156+
157+
// Remove unused css
158+
require('uncss')(contents, {
159+
raw: styles.join('\n'),
160+
ignoreModifiers: [
161+
'[disabled]',
162+
'.current',
163+
'.parent',
164+
'.active',
165+
'.selected-tab-button',
166+
'.selected-tab',
167+
'.shown',
168+
'.hidden-item',
169+
'[dir="rtl"]',
170+
'.fullscreen',
171+
'.night',
172+
'.previews',
173+
'[data-state="drawer"]',
174+
'.titlePopup',
175+
],
176+
ignore: [
177+
/section\[role="status"\]/,
178+
'.mainButtons button b',
179+
/\.fileListItem/,
180+
'[data-type="list"] li > a',
181+
'[data-type="list"] aside[class*=" icon-"]',
182+
'label.pack-checkbox',
183+
'label.pack-checkbox input',
184+
'label.pack-checkbox input ~ span',
185+
'label.pack-checkbox.danger input ~ span',
186+
/\.CodeMirror/,
187+
/\.cm-/,
188+
/\.icon-fullscreen-exit/,
189+
/\.icon-file/,
190+
/\.icon-format-align-left/,
191+
/\.icon-format-float-left/,
192+
]
193+
}, function(err, css) {
194+
// Remove unused glyphs from icon font
195+
var rIconFontUrl = /(url\(".*?materialdesignicons-webfont.woff.*?base64,)(.*?)("\))/;
196+
var rIconRuleMatch = /\.icon-.*?:before {\n content: "\\([\da-f]+)";\n}/g;
197+
var rIconRuleExtract = /\.icon-.*?:before {\n content: "\\([\da-f]+)";\n}/; // not global
198+
199+
window.language = 'en-US'; // Since there is a window, fontmin expects window.language
200+
201+
var Fontmin = require('fontmin');
202+
var fontmin = new Fontmin()
203+
.src(argv._[0].replace(/[^\/]*\.html/, 'style/fonts/materialdesignicons-webfont.ttf'))
204+
.use(Fontmin.glyph({
205+
text: css.match(rIconRuleMatch).map(function(iconRule) {
206+
return String.fromCharCode(parseInt(iconRule.match(rIconRuleExtract)[1], 16));
207+
}).join(''),
208+
}))
209+
.use(Fontmin.ttf2woff({
210+
deflate: true // Does nothing but shouldn't hurt
211+
}));
212+
fontmin.run(function(err, files) {
213+
if(err) {
214+
throw err;
215+
}
216+
217+
css = css.replace(rIconFontUrl,
218+
'$1' +
219+
files[0].contents.toString('base64') +
220+
'$3'
221+
);
222+
223+
224+
// Minify css
225+
css = require('more-css').compress(css);
226+
fs.writeFileSync(argv._[0].replace('../', '../build/').replace(/[^\/]*\.html/, 'styles.css'), css);
227+
contents = contents.replace(/<head>/i, '$&<link rel="stylesheet" href="styles.css">');
228+
229+
230+
// Minify html
231+
contents = require('html-minifier').minify(contents, {
232+
removeComments: true,
233+
removeCommentsFromCDATA: true,
234+
collapseWhitespace: true,
235+
collapseBooleanAttributes: true,
236+
removeAttributeQuotes: true,
237+
removeScriptTypeAttributes: true,
238+
removeStyleLinkTypeAttributes: true,
239+
minifyJS: true,
240+
minifyCSS: true,
241+
});
242+
243+
244+
// Pre-prepare script
245+
// We do this now instead of immediately in order to have a working script for uncss (phantomjs).
246+
if(argv.airborn) {
247+
prepareFile(scriptsFileName.replace('../', ''), {}, function(prepared) {
248+
contents = contents.split('<script src=scripts.js></script>').join('<script>' + prepared.replace(/<\/(script)/ig, '<\\\/$1') + '</script>'); // split and join instead of replace to not interpret replacement string ($1 etc)
249+
fs.unlinkSync(scriptsFileName);
250+
251+
// Write to build folder
252+
fs.writeFileSync(argv._[0].replace('../', '../build/'), contents);
253+
});
254+
} else {
255+
// Write to build folder
256+
fs.writeFileSync(argv._[0].replace('../', '../build/'), contents);
257+
}
258+
});
259+
});
260+
});
261+
262+
});

builder/package.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"devDependencies": {
3+
"sjcl": "~1.0.3",
4+
"html-minifier": "~0.7.2",
5+
"uncss": "https://github.com/twiss/uncss/tarball/6f21bc960b45534ead2674b19e969176d6a85b0d",
6+
"google-closure-compiler": "~20150505.0.0",
7+
"more-css": "~0.12.0",
8+
"fontmin": "0.9.0-alpha-3",
9+
"yargs": "~3.31.0"
10+
}
11+
}

style/icons.css

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
/* MaterialDesignIcons.com */
22
@font-face {
33
font-family: "Material Design Icons";
4-
src: url("fonts/materialdesignicons-webfont.eot");
5-
src: url("fonts/materialdesignicons-webfont.eot?#iefix") format("embedded-opentype"), url("fonts/materialdesignicons-webfont.woff2") format("woff2"), url("fonts/materialdesignicons-webfont.woff") format("woff"), url("fonts/materialdesignicons-webfont.ttf") format("truetype"), url("fonts/materialdesignicons-webfont.svg#materialdesigniconsregular") format("svg");
4+
src: url("fonts/materialdesignicons-webfont.woff") format("woff");
65
font-weight: normal;
76
font-style: normal;
87
}

0 commit comments

Comments
 (0)