├── .gitmodules
├── src
├── webext
│ └── dummy.txt
├── react-native
│ └── dummy.txt
└── electron
│ ├── icon.ico
│ ├── icon.png
│ ├── nativeshot.exe
│ ├── package.json
│ ├── index.html
│ ├── log.txt
│ ├── mac-nix-child-main.cc
│ ├── win-child-main.cpp
│ └── main.js
├── .babelrc
├── AMO-REVIEWER-README.txt
├── .gitignore
├── package.json
├── README.md
└── gulpfile.js
/.gitmodules:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/webext/dummy.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/react-native/dummy.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/electron/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Noitidart/NativeShot/HEAD/src/electron/icon.ico
--------------------------------------------------------------------------------
/src/electron/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Noitidart/NativeShot/HEAD/src/electron/icon.png
--------------------------------------------------------------------------------
/src/electron/nativeshot.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Noitidart/NativeShot/HEAD/src/electron/nativeshot.exe
--------------------------------------------------------------------------------
/src/electron/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "NativeShot",
3 | "version": "0.1.0",
4 | "main": "main.js",
5 | "devDependencies": {}
6 | }
7 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "es2017"],
3 | "plugins": ["transform-object-rest-spread"],
4 | "ignore": [
5 | "3rd/**/*",
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/src/electron/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello World!
6 |
7 |
8 | Hello World!
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/electron/log.txt:
--------------------------------------------------------------------------------
1 | startup
2 | reading length
3 | length: 6
4 | reading string
5 | read string: ["ping"]
6 | payload_str: "ping"
7 | reading length
8 | startup
9 | reading length
10 | length: 6
11 | reading string
12 | read string: ["ping"]
13 | payload_str: "ping"
14 | reading length
15 | length: 6
16 | reading string
17 | read string: ["ping"]
18 | payload_str: "ping"
19 | reading length
20 |
--------------------------------------------------------------------------------
/AMO-REVIEWER-README.txt:
--------------------------------------------------------------------------------
1 | BUILD INSTRUCTIONS
2 | cd into .tidy.ignore
3 | npm install
4 | gulp
5 | it will create dist.xpi and ./dist
6 | dist.xpi should match perfectly to the upload xpi
7 |
8 | 3RD PARTY SOURCES
9 | * ./resources/scripts/3rd/ocrad.js - https://github.com/antimatter15/ocrad.js/blob/5b0af624ebfd70cf45ddf55c58eaf25718133ba3/ocrad.js
10 | * ./resources/scripts/3rd/gocr.js - https://github.com/antimatter15/gocr.js/tree/d820e0651cf819e9649a837d83125724a2c1cc37
11 | * ./resources/scripts/3rd/tesseract.js - https://cdn.rawgit.com/naptha/tesseract.js/master/lib/worker.2015.07.26.js
12 | * ./resources/scripts/3rd/react-redux.js - https://npmcdn.com/react-redux@latest/dist/react-redux.min.js
13 | * ./resources/scripts/3rd/redux.js - https://npmcdn.com/redux@3.5.2/dist/redux.min.js
14 | * ./resources/scripts/3rd/react-with-addons.js - https://fb.me/react-with-addons-15.1.0.min.js
15 | * ./resources/scripts/3rd/react-dom.js - https://fb.me/react-dom-15.1.0.min.js
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 | supplement/
4 | .*
5 | !.babelrc
6 | !.gitignore
7 | *.xpi
8 | !-unsigned.xpi
9 |
10 | #### below is auto generated .gitignore content by Github app
11 | # Windows image file caches
12 | Thumbs.db
13 | ehthumbs.db
14 |
15 | # Folder config file
16 | Desktop.ini
17 |
18 | # Recycle Bin used on file shares
19 | $RECYCLE.BIN/
20 |
21 | # Windows Installer files
22 | *.cab
23 | *.msi
24 | *.msm
25 | *.msp
26 |
27 | # Windows shortcuts
28 | *.lnk
29 |
30 | # =========================
31 | # Operating System Files
32 | # =========================
33 |
34 | # OSX
35 | # =========================
36 |
37 | .DS_Store
38 | .AppleDouble
39 | .LSOverride
40 |
41 | # Thumbnails
42 | ._*
43 |
44 | # Files that might appear in the root of a volume
45 | .DocumentRevisions-V100
46 | .fseventsd
47 | .Spotlight-V100
48 | .TemporaryItems
49 | .Trashes
50 | .VolumeIcon.icns
51 |
52 | # Directories potentially created on remote AFP share
53 | .AppleDB
54 | .AppleDesktop
55 | Network Trash Folder
56 | Temporary Items
57 | .apdisk
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "build-babel",
3 | "version": "1.0.0",
4 | "description": "All my scripts are now babelified",
5 | "main": "index.js",
6 | "dependencies": {
7 | "gulp-rename": "^1.2.2",
8 | "nan": "^2.5.0",
9 | "react": "^15.3.2",
10 | "react-dom": "^15.3.2",
11 | "react-redux": "^4.4.5",
12 | "react-router": "^3.0.0",
13 | "redux": "^3.6.0"
14 | },
15 | "devDependencies": {
16 | "babel-plugin-transform-object-rest-spread": "^6.16.0",
17 | "babel-polyfill": "^6.16.0",
18 | "babel-preset-es2015": "^6.16.0",
19 | "babel-preset-es2017": "^6.16.0",
20 | "fs": "0.0.1-security",
21 | "gulp": "^3.9.1",
22 | "gulp-babel": "^6.1.2",
23 | "gulp-clean": "^0.3.2",
24 | "gulp-contains": "^1.1.0",
25 | "gulp-if": "^2.0.1",
26 | "gulp-insert": "^0.5.0",
27 | "gulp-js-obfuscator": "^1.0.0",
28 | "gulp-jscrambler": "^1.0.2",
29 | "gulp-jshint": "^2.0.1",
30 | "gulp-replace": "^0.5.4",
31 | "gulp-src-ordered-globs": "^1.0.3",
32 | "gulp-util": "^3.0.7",
33 | "gulp-zip": "^3.2.0",
34 | "jshint": "^2.9.4"
35 | },
36 | "scripts": {
37 | "test": "echo \"Error: no test specified\" && exit 1"
38 | },
39 | "author": "Noitidart ",
40 | "license": "ISC"
41 | }
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Download / Install
2 | * Firefox - [AMO :: NativeShot](https://addons.mozilla.org/en-US/firefox/addon/nativeshot/)
3 |
4 | ## About
5 | NativeShot is not your typical screenshot addon. The typical screenshot addon takes an image of the HTML content in your current or other tab. NativeShot features a system wide hotkey (and also a toolbar button) which takes screenshot as you would by pressing the "Print Screen" or "Screenshot" key on your computer. Everything on every monitor is captured and then opened up for editing. After you select an action from the menu, such as "Upload to Imgur", the link to the screenshot is copied to your clipboard, and a notification is shown.
6 |
7 | ## Credits
8 | * [Dakirby309](http://dakirby309.deviantart.com/) for Icon [(source)](https://www.iconfinder.com/icons/99958/screenshot_icon)
9 | * @wadie for Desktop (Electron) and Mobile (React Native) Collaboration
10 | * Translation
11 | * Arabic - @noureddin [(BZ)](http://beta.babelzilla.org/accounts/profile/noureddin/)
12 | * Bulgarian - @AdmiralAnimE [(BZ)](http://beta.babelzilla.org/accounts/profile/AdmiralAnimE/)
13 | * Catalan - @TheRabbitter [(BZ)](http://beta.babelzilla.org/accounts/profile/Rabbitter/)
14 | * German - [AlexS.](http://beta.babelzilla.org/accounts/profile/AlexS./), [Aryx](http://beta.babelzilla.org/accounts/profile/Aryx/), @Endor8 [(BZ)](http://beta.babelzilla.org/accounts/profile/endor8/)
15 | * Spanish (Spain) - @AlejandroPerezMartin [(BZ)](http://beta.babelzilla.org/accounts/profile/AlePerez92/)
16 | * Estonian - @mdr-ksk [(BZ)](http://beta.babelzilla.org/accounts/profile/mdr.ksk/)
17 | * French - @tojazmin [(BZ)](http://beta.babelzilla.org/accounts/profile/tojazmin/)
18 | * Hungarian - [Gabesz](http://beta.babelzilla.org/accounts/profile/Gabesz/)
19 | * Italian - @AlessandroMenti [(BZ)](http://beta.babelzilla.org/accounts/profile/elgaton/)
20 | * Japanese - @marsf [(BZ)](http://beta.babelzilla.org/accounts/profile/mar/)
21 | * Lithuanian - @gymka [(BZ)](http://beta.babelzilla.org/accounts/profile/gymka/), @zygimantus [(BZ)](http://beta.babelzilla.org/accounts/profile/zygimantus/)
22 | * Dutch - @MarkH [(BZ)](http://beta.babelzilla.org/accounts/profile/markh/), @TonnesM [(BZ)](http://beta.babelzilla.org/accounts/profile/Tonnes/)
23 | * Polish - @teo951 [(BZ)](http://beta.babelzilla.org/accounts/profile/teo/)
24 | * Portuguese (Brazil) - @MarceloGhelman [(BZ)](http://beta.babelzilla.org/accounts/profile/ghelman/)
25 | * Portuguese (Portugal) - @Ricardo-Simoes [(BZ)](http://beta.babelzilla.org/accounts/profile/ricardosimoes/)
26 | * Romanian - @Jobava [(BZ)](http://beta.babelzilla.org/accounts/profile/jobaval10n/)
27 | * Russian - @insolor [(BZ)](http://beta.babelzilla.org/accounts/profile/insolor/), @veadarkin [(BZ)](http://beta.babelzilla.org/accounts/profile/veadarkin/)
28 | * Turkish - [alfapegasi](http://beta.babelzilla.org/accounts/profile/alfapegasi/)
29 | * Chinese (Simplified) - @yfdyh000 [(BZ)](http://beta.babelzilla.org/accounts/profile/yfdyh000/)
30 | * Chinese (Traditional) - @goldie-lin [(BZ)](http://beta.babelzilla.org/accounts/profile/goldie/)
31 |
--------------------------------------------------------------------------------
/src/electron/mac-nix-child-main.cc:
--------------------------------------------------------------------------------
1 | // g++ main.cc -o nativeshot -std=c++11
2 | #include
3 | #include
4 |
5 | // start - debug
6 | #include
7 | #include
8 | #include
9 | #include // debug time
10 |
11 | template bool
12 | debug_log_rec(std::ostream& out, HeadType&& head) {
13 | out << head;
14 | out << std::endl;
15 | return true;
16 | }
17 |
18 | template bool
19 | debug_log_rec(std::ostream& out, HeadType&& head, TailTypes&&... tails) {
20 | out << head;
21 | out << " ";
22 | debug_log_rec(out, std::forward(tails)...);
23 | return true;
24 | }
25 |
26 | template bool
27 | debug_log(ArgTypes&&... args) {
28 | // return true; // prod
29 | std::fstream fs;
30 | fs.open("log.txt", std::fstream::app);
31 | debug_log_rec(fs, std::forward(args)...);
32 | fs.close();
33 | return true;
34 | }
35 |
36 | int nowms() {
37 | using namespace std::chrono;
38 | milliseconds ms = duration_cast(system_clock::now().time_since_epoch());
39 | return ms.count();
40 | }
41 | // end - debug
42 |
43 | bool read_u32(uint32_t* data) {
44 | return std::fread(reinterpret_cast(data), sizeof(uint32_t), 1, stdin) == 1;
45 | }
46 |
47 | bool read_string(std::string &str, uint32_t length) {
48 | str.resize(length);
49 | return std::fread(&str[0], sizeof(char), str.length(), stdin) == length;
50 | }
51 |
52 | bool write_u32(uint32_t data) {
53 | return std::fwrite(reinterpret_cast(&data), sizeof(uint32_t), 1, stdout) == 1;
54 | }
55 |
56 | bool write_string(const std::string &str) {
57 | return std::fwrite(&str[0], sizeof(char), str.length(), stdout) == str.length();
58 | }
59 |
60 | bool get_message(std::string& str) {
61 | uint32_t length;
62 | debug_log("reading length");
63 | while (true) {
64 | if (!read_u32(&length)) {
65 | // debug_log("failed to read length", "SHOULD I RETRY?");
66 | // return false; // comment this if you want retry
67 | continue; // uncomment this if you want retry
68 | }
69 | break;
70 | }
71 | debug_log("length:", length);
72 | debug_log("reading string");
73 | while (true) {
74 | if (!read_string(str, length)) {
75 | // debug_log("failed to read string", "SHOULD I RETRY?");
76 | // return false; // comment this if you want retry
77 | continue; // uncomment this if you want retry
78 | }
79 | break;
80 | }
81 | debug_log("read string: [" + str + "]");
82 | // debug_log(str.length());
83 | return true;
84 | }
85 |
86 | bool send_message(const std::string& str) {
87 | //debug_log("writing length");
88 | while (!write_u32(str.length())) {
89 | debug_log("failed to write length, for str:", str, "WILL RETRY");
90 | }
91 | //debug_log("writing string");
92 | while (!write_string(str)) {
93 | debug_log("failed to write string, for str:", str, "WILL RETRY");
94 | }
95 | //debug_log("flushing");
96 | while (std::fflush(stdout) != 0) {
97 | debug_log("failed to flush, for str:", str, "WILL RETRY");
98 | }
99 | return true;
100 | }
101 |
102 | int main(void) {
103 | debug_log("startup");
104 |
105 | std::string payload_str;
106 | while (get_message(payload_str)) {
107 | debug_log("payload_str:", payload_str);
108 | if (payload_str == "\"ping\"") {
109 | send_message("\"pong\"");
110 | }
111 | }
112 |
113 |
114 | debug_log("ending");
115 |
116 | return 0;
117 | }
118 |
--------------------------------------------------------------------------------
/src/electron/win-child-main.cpp:
--------------------------------------------------------------------------------
1 | // standard defines for win app - https://msdn.microsoft.com/en-us/library/bb384843.aspx
2 | #define WIN32
3 | #define UNICODE
4 | #define _UNICODE
5 | #define _WINDOWS
6 |
7 | // standard includes for win app - https://msdn.microsoft.com/en-us/library/bb384843.aspx
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | // start - debug
14 | #include
15 | #include
16 | #include
17 | #include // debug time
18 |
19 | template bool
20 | debug_log_rec(std::ostream& out, HeadType&& head) {
21 | out << head;
22 | out << std::endl;
23 | return true;
24 | }
25 |
26 | template bool
27 | debug_log_rec(std::ostream& out, HeadType&& head, TailTypes&&... tails) {
28 | out << head;
29 | out << " ";
30 | debug_log_rec(out, std::forward(tails)...);
31 | return true;
32 | }
33 |
34 | template bool
35 | debug_log(ArgTypes&&... args) {
36 | // return true; // prod
37 | std::fstream fs;
38 | fs.open("log.txt", std::fstream::app);
39 | debug_log_rec(fs, std::forward(args)...);
40 | fs.close();
41 | return true;
42 | }
43 |
44 | int nowms() {
45 | using namespace std::chrono;
46 | milliseconds ms = duration_cast(system_clock::now().time_since_epoch());
47 | return ms.count();
48 | }
49 | // end - debug
50 |
51 | bool read_u32(uint32_t* data) {
52 | return std::fread(reinterpret_cast(data), sizeof(uint32_t), 1, stdin) == 1;
53 | }
54 |
55 | bool read_string(std::string &str, uint32_t length) {
56 | str.resize(length);
57 | return std::fread(&str[0], sizeof(char), str.length(), stdin) == length;
58 | }
59 |
60 | bool write_u32(uint32_t data) {
61 | return std::fwrite(reinterpret_cast(&data), sizeof(uint32_t), 1, stdout) == 1;
62 | }
63 |
64 | bool write_string(const std::string &str) {
65 | return std::fwrite(&str[0], sizeof(char), str.length(), stdout) == str.length();
66 | }
67 |
68 | bool get_message(std::string& str) {
69 | uint32_t length;
70 | debug_log("reading length");
71 | while (true) {
72 | if (!read_u32(&length)) {
73 | // debug_log("failed to read length", "SHOULD I RETRY?");
74 | // return false; // comment this if you want retry
75 | continue; // uncomment this if you want retry
76 | }
77 | break;
78 | }
79 | debug_log("length:", length);
80 | debug_log("reading string");
81 | while (true) {
82 | if (!read_string(str, length)) {
83 | // debug_log("failed to read string", "SHOULD I RETRY?");
84 | // return false; // comment this if you want retry
85 | continue; // uncomment this if you want retry
86 | }
87 | break;
88 | }
89 | debug_log("read string: [" + str + "]");
90 | // debug_log(str.length());
91 | return true;
92 | }
93 |
94 | bool send_message(const std::string& str) {
95 | //debug_log("writing length");
96 | while (!write_u32(str.length())) {
97 | debug_log("failed to write length, for str:", str, "WILL RETRY");
98 | }
99 | //debug_log("writing string");
100 | while (!write_string(str)) {
101 | debug_log("failed to write string, for str:", str, "WILL RETRY");
102 | }
103 | //debug_log("flushing");
104 | while (std::fflush(stdout) != 0) {
105 | debug_log("failed to flush, for str:", str, "WILL RETRY");
106 | }
107 | return true;
108 | }
109 |
110 | int main(void) {
111 | debug_log("startup");
112 |
113 | std::string payload_str;
114 | while (get_message(payload_str)) {
115 | debug_log("payload_str:", payload_str);
116 | if (payload_str == "\"ping\"") {
117 | send_message("\"pong\"");
118 | }
119 | }
120 |
121 |
122 | debug_log("ending");
123 |
124 | return 0;
125 | }
126 |
--------------------------------------------------------------------------------
/src/electron/main.js:
--------------------------------------------------------------------------------
1 | const {app, Menu, Tray, BrowserWindow} = require('electron');
2 | const path = require('path')
3 | const url = require('url')
4 | const platform = require('os').platform();
5 |
6 | let win;
7 | function createWindow() {
8 | // Create the browser window.
9 | win = new BrowserWindow({width: 800, height: 600})
10 |
11 | // and load the index.html of the app.
12 | win.loadURL(url.format({
13 | pathname: path.join(__dirname, 'index.html'),
14 | protocol: 'file:',
15 | slashes: true
16 | }));
17 |
18 | // Open the DevTools.
19 | win.webContents.openDevTools();
20 |
21 | // Emitted when the window is closed.
22 | win.on('closed', () => {
23 | // Dereference the window object, usually you would store windows
24 | // in an array if your app supports multi windows, this is the time
25 | // when you should delete the corresponding element.
26 | win = null
27 | });
28 | }
29 |
30 | function startTray() {
31 | // run in app.on ready - i dont know why but @wadie did it like this
32 | let appIcon = new Tray('icon.' + (platform == 'win32' ? 'ico' : 'png'));
33 | const contextMenu = Menu.buildFromTemplate([
34 | {
35 | label: 'Screenshots',
36 | type: 'radio'
37 | }
38 | ]);
39 |
40 | // Make a change to the context menu
41 | contextMenu.items[0].checked = false;
42 |
43 | // Call this again for Linux because we modified the context menu
44 | appIcon.setContextMenu(contextMenu);
45 | }
46 |
47 | function startChildProc() {
48 | // run in app.on ready - because i need TextEncoder which comes in from the require statement
49 | const { spawn } = require('child_process');
50 | let child = spawn('./nativeshot' + (platform == 'win32' ? '.exe' : ''));
51 |
52 | // child.stdin.setEncoding('utf-8');
53 | // child.stdout.pipe(process.stdout);
54 |
55 | child.stdout.on('data', function (nbuf) {
56 | // nbuf stands for "node buffer" is Buffer which is Uint8Array per http://stackoverflow.com/a/12101012/1828637
57 | console.log('stdout, nbuf:', nbuf, 'nbuf.toJSON:', nbuf.toJSON());
58 |
59 | // let sizeofuint32 = new Buffer(Uint32Array.of(nbuf.length).buffer).length;
60 | // console.log('sizeofuint32:', sizeofuint32); // is 4
61 | const SIZEOFUINT32 = 4;
62 |
63 | let ix = 0;
64 | let l = nbuf.length;
65 | while(ix < l) {
66 | let lenbuf = Buffer.from(nbuf.buffer, ix, ix + SIZEOFUINT32); // 4 because size of Uint32 is 4. `sizeofuint32` gives 4
67 | console.log('lenbuf:', lenbuf.toJSON());
68 | // console.log('lenbuf:', lenbuf.toString('utf8'));
69 | let len = new Uint32Array(lenbuf)[0];
70 | console.log('len:', len);
71 |
72 | let strbuf = Buffer.from(nbuf.buffer, SIZEOFUINT32, len);
73 | console.log('strbuf:', strbuf.toJSON());
74 | let str = strbuf.toString('utf8');
75 | console.log('str:', str);
76 |
77 | ix = SIZEOFUINT32 + len;
78 | console.log('post ix:', ix, 'l:', l);
79 | }
80 | });
81 |
82 |
83 | console.log('Hey there');
84 | let message = JSON.stringify('ping');
85 |
86 | // https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/NativeMessaging.jsm#252
87 | let nbuf = Buffer.from(message, 'utf8');
88 | console.log('nbuf:', nbuf);
89 | console.log('nbuf.length:', nbuf.length);
90 | // https://dxr.mozilla.org/mozilla-central/source/toolkit/components/extensions/NativeMessaging.jsm#298
91 | let lenbuf = new Buffer(Uint32Array.of(nbuf.length).buffer);
92 | console.log('lenbuf:', lenbuf, 'length:', lenbuf.length);
93 |
94 | child.stdin.write(lenbuf);
95 | child.stdin.write(nbuf);
96 | // child.stdin.end(); // otherwise next message wont write, must do this on close of child
97 |
98 | setTimeout(function() {
99 | console.log('ok will send ping again');
100 | child.stdin.write(lenbuf);
101 | child.stdin.write(nbuf);
102 | // child.stdin.end();
103 | }, 5000);
104 | }
105 |
106 | function readyHandler() {
107 | startTray();
108 | startChildProc();
109 | createWindow();
110 | }
111 |
112 | function activateHandler() {
113 | // On macOS it's common to re-create a window in the app when the
114 | // dock icon is clicked and there are no other windows open.
115 | if (win === null) {
116 | createWindow();
117 | }
118 | }
119 |
120 | function allwinClosedHandler() {
121 | // Quit when all windows are closed.
122 | // On macOS it is common for applications and their menu bar
123 | // to stay active until the user quits explicitly with Cmd + Q
124 | if (process.platform !== 'darwin') {
125 | app.quit()
126 | }
127 | }
128 |
129 | app.on('ready', readyHandler);
130 | app.on('activate', activateHandler);
131 | app.on('window-all-closed', allwinClosedHandler);
132 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /* README
2 | * --txtype fxhyb can be omitted, its default
3 | * gulp --txtype fxhyb - will create dev vresion, with console logs
4 | * gulp --prod --txtype fxhyb - this will create release version, without console logs
5 | * gulp watch --txtype fxhyb - this will watch for changes
6 | */
7 |
8 | // Include gulp
9 | var gulp = require('gulp');
10 |
11 | // Include core modules
12 | var fs = require('fs');
13 | var path = require('path');
14 |
15 | // Include Our Plugins
16 | var babel = require('gulp-babel');
17 | var clean = require('gulp-clean');
18 | var contains = require('gulp-contains');
19 | var gulpif = require('gulp-if');
20 | var gulp_src_ordered = require('gulp-src-ordered-globs'); // http://stackoverflow.com/a/40206149/1828637
21 | var insert = require('gulp-insert');
22 | var jshint = require('gulp-jshint');
23 | var jsobfuscator = require('gulp-js-obfuscator');
24 | var jscrambler = require('gulp-jscrambler');
25 | var replace = require('gulp-replace');
26 | var rename = require('gulp-rename');
27 | var util = require('gulp-util');
28 | var zip = require('gulp-zip');
29 |
30 | // Command line options
31 | var options = { // defaults
32 | production: false, // production
33 | // clarg == --prod
34 | // strips the console messages // production/release
35 | txtype: 'fxhyb' // transpile type
36 | // clarg == --txtype BLAH
37 | // values:
38 | // fxhyb == firefox-webextension-hybrid
39 | // fxext == firefox-webextension
40 | // web == web
41 | // affects taskcopy-3rdjs - where to copy the babel-polyfill too
42 | };
43 |
44 | var clargs = process.argv.slice(2);
45 | var clargs = clargs.map(el => el.toLowerCase().trim());
46 |
47 | console.log('clargs:', clargs);
48 | // production?
49 | if (clargs.indexOf('--prod') > -1) {
50 | options.production = true;
51 | }
52 |
53 | // txtype?
54 | var ix_txtype = clargs.indexOf('--txtype');
55 | if (ix_txtype > -1) {
56 | options.txtype = clargs[++ix_txtype];
57 | }
58 |
59 | // start async-proc9939
60 | gulp.task('clean', function() {
61 | return gulp.src('dist', { read:false })
62 | .pipe(clean());
63 | });
64 |
65 | gulp.task('copy-zip-exe', ['clean'], function() {
66 | if (options.txtype == 'web') {
67 | // do nothing
68 | return gulp.src('.').pipe(util.noop());
69 | } else {
70 | var dest;
71 | var srcwebext;
72 | switch (options.txtype) {
73 | case 'fxhyb':
74 | dest = 'dist/webextension/exe';
75 | srcwebext = 'src/webextension';
76 | break;
77 | default:
78 | dest = 'dist/exe';
79 | srcwebext = 'src';
80 | }
81 |
82 | var addonname = JSON.parse(fs.readFileSync(srcwebext + '/_locales/en-US/messages.json', 'utf8')).addon_name.message;
83 | return gulp_src_ordered([
84 | '../' + addonname + 'Exe/**/*',
85 | '!../' + addonname + 'Exe/**/*.*',
86 | '../' + addonname + 'Exe/**/*.exe'
87 | ])
88 | .pipe(rename(function(file) {
89 | file.dirname = file.dirname.split(path.sep)[0];
90 | }))
91 | .pipe(gulp.dest(dest));
92 | // if not fxhyb then replaces executables with zipped version
93 | }
94 | });
95 |
96 | gulp.task('copy', ['copy-zip-exe'], function() {
97 | // copy all files but js
98 | return gulp_src_ordered([
99 | 'src/**/*',
100 | '!src/.*', // no hidden files/dirs in src
101 | '!src/.*/**/*', // no files/dirs in hidden dirs in src
102 | '!src/**/*.js', // no js files from src
103 | '!src/webextension/exe/**/*', // no exe folder
104 | 'src/**/3rd/*.js' // make sure to get 3rd party js files though
105 | ])
106 | .pipe(gulp.dest('dist'));
107 | });
108 |
109 | gulp.task('import-3rdjs', ['copy'], function() {
110 | // bring in babel-polyfill to 3rd party directory - determined by clarg txtype
111 |
112 | var dest;
113 | // switch (options.txtype) {
114 | // case 'fxhyb':
115 | // dest = 'dist/webextension/scripts/3rd';
116 | // break;
117 | // case 'web':
118 | // case 'fxext':
119 | // dest = 'dist/scripts/3rd';
120 | // break;
121 | // }
122 |
123 | if (fs.existsSync('dist/webextension/scripts/3rd')) {
124 | // options.txtype == fxhyb
125 | dest = 'dist/webextension/scripts/3rd';
126 | } else if (fs.existsSync('dist/scripts/3rd')) {
127 | // options.txtype == web || fxext
128 | dest = 'dist/scripts/3rd';
129 | } else {
130 | throw new Error('dont know where to import 3rd party scripts too!');
131 | }
132 | console.log('dest:', dest);
133 |
134 | return gulp.src([
135 | 'node_modules/babel-polyfill/dist/polyfill.min.js',
136 | 'node_modules/react/dist/react-with-addons.min.js',
137 | 'node_modules/react-dom/dist/react-dom.min.js',
138 | 'node_modules/redux/dist/redux.min.js',
139 | 'node_modules/react-redux/dist/react-redux.min.js',
140 | 'node_modules/react-router/umd/ReactRouter.min.js'
141 | ])
142 | .pipe(gulp.dest(dest));
143 | });
144 |
145 | gulp.task('initial-tx-js', ['import-3rdjs'], function() {
146 | return gulp.start('tx-then-xpi');
147 | });
148 | // end async-proc9939
149 |
150 | // start - standalone3888 - is standalone because so `gulp watch` can trigger this without triggering the clean and copy stuff from above
151 | gulp.task('tx-js', function() {
152 | // tx-js stands for transform-javascripts
153 |
154 | var include_contents = {}; // to avoid multi readFileSync on same file path
155 |
156 | return gulp_src_ordered(['src/**/*.js', '!src/**/3rd/*'])
157 | .pipe(gulpif(options.production, replace(/^.*?console\.(warn|info|log|error|exception|time|timeEnd|jsm).*?$/mg, '')))
158 | .pipe(replace(/\/\/ #include '([^']+)'/gm, function($0, $1) {
159 | // $1 - ([^']+) - path to file to include
160 | if (!include_contents[$1]) {
161 | include_contents[$1] = fs.readFileSync($1, 'utf8');
162 | if (options.production) {
163 | include_contents[$1] = include_contents[$1].replace(/^.*?console\.(warn|info|log|error|exception|time|timeEnd|jsm).*?$/mg, '');
164 | }
165 | if ($1 == 'node_modules/babel-polyfill/dist/polyfill.min.js') {
166 | include_contents[$1] = 'var global = this;\n' + include_contents[$1];
167 | }
168 | };
169 |
170 | return '// START INCLUDE - "' + $1 + '"\n' + include_contents[$1] + '// END INCLUDE - "' + $1 + '"';
171 | }))
172 | .pipe(babel())
173 | // .pipe(gulpif(options.production, jsobfuscator()))
174 | .pipe(insert.transform(function(contents, file) {
175 | var pathparts = file.path.split(/[\\\/]/);
176 | if (pathparts[pathparts.length-1] == 'bootstrap.js' && pathparts[pathparts.length-2] == 'src') {
177 | var includestr = '// START INCLUDE - babel-polyfill\nvar global = this;\n' + fs.readFileSync('node_modules/babel-polyfill/dist/polyfill.min.js', 'utf8') + '// END INCLUDE - babel-polyfill';
178 | if (contents.indexOf('\'use strict\';') === 0) {
179 | contents = contents.replace('\'use strict\';', '\'use strict\';\n\n' + includestr);
180 | } else {
181 | contents = includestr + '\n\n' + contents;
182 | }
183 | console.log('ok included babel-polyfill at top');
184 | }
185 | return contents;
186 | }))
187 | // .pipe(replace(/(^.*?$)([\s\S]*?)\/\/ #includetop-nobabel '([^']+)'/m, function($0, $1, $2, $3) {
188 | // // $1 - (^.*?$) - the "using strict" usually, so first line
189 | // // $2 - ([\s\S]*?) - all lines up till the include line
190 | // // $3 - ([^']+) - path to file to include
191 | //
192 | // if (!include_contents[$3]) {
193 | // include_contents[$3] = fs.readFileSync($3, 'utf8');
194 | // if (options.production) {
195 | // include_contents[$3] = include_contents[$3].replace(/^.*?console\.(warn|info|log|error|exception|time|timeEnd|jsm).*?$/mg, '');
196 | // }
197 | // if ($3 == 'node_modules/babel-polyfill/dist/polyfill.min.js') {
198 | // include_contents[$3] = 'var global = this;\n' + include_contents[$3];
199 | // }
200 | // };
201 | //
202 | // return $1 + '\n\n// START INCLUDE - "' + $3 + '"\n' + include_contents[$3] + '// END INCLUDE - "' + $3 + '"' + $2;
203 | // }))
204 | .pipe(gulp.dest('dist'));
205 | });
206 |
207 | gulp.task('tx-then-xpi', ['tx-js'], function() {
208 | if (options.txtype == 'web') {
209 | // do nothing
210 | return gulp.src('.').pipe(util.noop());
211 | } else {
212 | return gulp.src('dist/**/*')
213 | .pipe(zip('_dist' + Date.now() + '.xpi', { compress:false }))
214 | .pipe(gulp.dest('./'));
215 | }
216 | });
217 |
218 | gulp.task('xpi', function() {
219 | return gulp.src('dist/**/*')
220 | .pipe(zip('dist.xpi', { compress:false }))
221 | .pipe(gulp.dest('./'));
222 | });
223 | // end - standalone3888
224 |
225 |
226 | gulp.task('default', ['initial-tx-js']); // copy-3rdjs triggers tx-js
227 | gulp.task('watch', ['initial-tx-js'], function() {
228 | console.log('NOTE: wait for tx-then-xpi to finish, or it may have already finished. as that does the initial js copy');
229 | // var watcher = gulp.watch('src/**/*.js', ['tx-then-xpi']);
230 | var watcher = gulp.watch('src/**/*', ['initial-tx-js']);
231 | watcher.on('change', function(event) {
232 | console.log('JS file at path "' + event.path + '" was ' + event.type + ', running tx-js...');
233 | });
234 | });
235 |
--------------------------------------------------------------------------------