Skip to content

Commit

Permalink
feat: support safari 14
Browse files Browse the repository at this point in the history
  • Loading branch information
ineo6 committed Nov 27, 2020
1 parent e73aa88 commit d24a92c
Show file tree
Hide file tree
Showing 23 changed files with 1,133 additions and 50 deletions.
3 changes: 2 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"chrome": "49",
"firefox": "52",
"opera": "36",
"edge": "79"
"edge": "79",
"safari": "14"
}
}
]
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"build:chrome": "cross-env NODE_ENV=production cross-env TARGET_BROWSER=chrome webpack",
"build:firefox": "cross-env NODE_ENV=production cross-env TARGET_BROWSER=firefox webpack",
"build:opera": "cross-env NODE_ENV=production cross-env TARGET_BROWSER=opera webpack",
"build:safari": "cross-env NODE_ENV=production cross-env TARGET_BROWSER=safari webpack",
"build": "yarn run build:chrome && yarn run build:firefox && yarn run build:opera",
"tpl": "node ./scripts/tpl.js",
"analyzer": "yarn build:chrome -- --analyzer",
Expand Down
36 changes: 36 additions & 0 deletions scripts/wext-manifest/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @author abhijithvijayan <abhijithvijayan.in>
* from https://github.com/abhijithvijayan/wext-manifest-loader/blob/wext-manifest/index.js
*/

const transformVendorKeys = require('./transformVendorKeys');

exports.chrome = input => {
const manifest = transformVendorKeys(input, 'chrome');

return { name: 'manifest.json', content: JSON.stringify(manifest, null, 2) };
};

exports.firefox = input => {
const manifest = transformVendorKeys(input, 'firefox');

return { name: 'manifest.json', content: JSON.stringify(manifest, null, 2) };
};

exports.opera = input => {
const manifest = transformVendorKeys(input, 'opera');

return { name: 'manifest.json', content: JSON.stringify(manifest, null, 2) };
};

exports.edge = input => {
const manifest = transformVendorKeys(input, 'edge');

return { name: 'manifest.json', content: JSON.stringify(manifest, null, 2) };
};

exports.safari = input => {
const manifest = transformVendorKeys(input, 'safari');

return { name: 'manifest.json', content: JSON.stringify(manifest, null, 2) };
};
35 changes: 35 additions & 0 deletions scripts/wext-manifest/transformVendorKeys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const browserVendors = ['chrome', 'firefox', 'opera', 'edge', 'safari'];
const vendorRegExp = new RegExp(`^__((?:(?:${browserVendors.join('|')})\\|?)+)__(.*)`);

/**
* Fork of `webextension-toolbox/webpack-webextension-plugin`
*/
const transformVendorKeys = (manifest, vendor) => {
if (Array.isArray(manifest)) {
return manifest.map(newManifest => {
return transformVendorKeys(newManifest, vendor);
});
}

if (typeof manifest === 'object') {
return Object.entries(manifest).reduce((newManifest, [key, value]) => {
const match = key.match(vendorRegExp);

if (match) {
const vendors = match[1].split('|');

// Swap key with non prefixed name
if (vendors.indexOf(vendor) > -1) {
newManifest[match[2]] = value;
}
} else {
newManifest[key] = transformVendorKeys(value, vendor);
}

return newManifest;
}, {});
}

return manifest;
};
module.exports = transformVendorKeys;
113 changes: 66 additions & 47 deletions src/common/core.storage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {browser} from 'webextension-polyfill-ts';
import { browser } from 'webextension-polyfill-ts';
import { DEFAULTS, EVENT, STORE } from './core.constants';
import { isSafari, promisify } from './util.misc';

Expand All @@ -12,51 +12,79 @@ function _parse(val) {

class ExtStore {
constructor(values, defaults) {
this._isSafari = isSafari();
this._isSafari = process.env.TARGET_BROWSER === 'safari';

this._tempChanges = {};

if (!this._isSafari) {
this._setInExtensionStorage = browser.storage.local.set;
this._getInExtensionStorage = browser.storage.local.get;
this._removeInExtensionStorage = browser.storage.local.remove;
}
this._setInExtensionStorage = this.storageSetWrap(browser.storage.local.set);
this._getInExtensionStorage = browser.storage.local.get;
this._removeInExtensionStorage = browser.storage.local.remove;

// Initialize default values
this._init = Promise.all(
Object.keys(values)
.map(async (key) => {
const existingVal = await this._innerGet(values[key]);
if (existingVal == null) {
await this._innerSet(values[key], defaults[key]);
Object.keys(values).map(async key => {
const existingVal = await this._innerGet(values[key]);
if (existingVal == null) {
await this._innerSet(values[key], defaults[key]);
}
})
).then(() => {
this._init = null;
this._setupOnChangeEvent();
});
}

storageSetWrap(fn) {
return function(obj) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async resolve => {
fn(obj).then(() => {
resolve();

if (this._isSafari) {
// should notify in safari
// browser.storage.onChanged.addListener not work in safari 14
const entries = Object.entries(obj);

if (entries.length > 0) {
const [key, newValue] = entries[0];
try {
if (!this._init) {
this._getInExtensionStorage(key).then(savedValue => {
const oldValue = savedValue[key];

this._notifyChange(key, oldValue, newValue);
});
}
} catch (e) {
const msg =
'GitMaster cannot save its settings. ' + 'If the local storage for this domain is full, please clean it up and try again.';
console.error(msg, e);
}
}
}
}),
)
.then(() => {
this._init = null;
this._setupOnChangeEvent();
});
});
};
}

_setupOnChangeEvent() {
window.addEventListener('storage', (evt) => {
if (this._isOctotreeKey(evt.key)) {
window.addEventListener('storage', evt => {
if (this.isMyStorageKey(evt.key)) {
this._notifyChange(evt.key, _parse(evt.oldValue), _parse(evt.newValue));
}
});

if (!this._isSafari) {
browser.storage.onChanged.addListener((changes) => {
Object.entries(changes)
.forEach(([key, change]) => {
if (this._isOctotreeKey(key)) {
this._notifyChange(key, change.oldValue, change.newValue);
}
});
browser.storage.onChanged.addListener(changes => {
Object.entries(changes).forEach(([key, change]) => {
if (this.isMyStorageKey(key)) {
this._notifyChange(key, change.oldValue, change.newValue);
}
});
}
});
}

_isOctotreeKey(key) {
isMyStorageKey(key) {
return key.startsWith('gitmaster');
}

Expand All @@ -66,8 +94,7 @@ class ExtStore {
this._tempTimer && clearTimeout(this._tempTimer);
this._tempChanges[key] = [oldVal, newVal];
this._tempTimer = setTimeout(() => {
$(this)
.trigger(EVENT.STORE_CHANGE, this._tempChanges);
$(this).trigger(EVENT.STORE_CHANGE, this._tempChanges);
this._tempTimer = null;
this._tempChanges = {};
}, 50);
Expand Down Expand Up @@ -98,36 +125,30 @@ class ExtStore {

// Private
async _innerGet(key) {
const result = (key.endsWith('local') || this._isSafari)
? await this._getLocal(key)
: await this._getInExtensionStorage(key);
const result = key.endsWith('local') ? await this._getLocal(key) : await this._getInExtensionStorage(key);

return result[key];
return result ? result[key] : '';
}

_innerSet(key, value) {
const payload = { [key]: value };
return (key.endsWith('local') || this._isSafari)
? this._setLocal(payload)
: this._setInExtensionStorage(payload);
return key.endsWith('local') ? this._setLocal(payload) : this._setInExtensionStorage(payload);
}

_innerRemove(key) {
return (key.endsWith('local') || this._isSafari)
? this._removeLocal(key)
: this._removeInExtensionStorage(key);
return key.endsWith('local') ? this._removeLocal(key) : this._removeInExtensionStorage(key);
}

_getLocal(key) {
return new Promise((resolve) => {
return new Promise(resolve => {
const value = _parse(localStorage.getItem(key));
resolve({ [key]: value });
});
}

_setLocal(obj) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
return new Promise(async resolve => {
const entries = Object.entries(obj);

if (entries.length > 0) {
Expand All @@ -142,9 +163,7 @@ class ExtStore {
}
localStorage.setItem(key, value);
} catch (e) {
const msg =
'GitMaster cannot save its settings. ' +
'If the local storage for this domain is full, please clean it up and try again.';
const msg = 'GitMaster cannot save its settings. ' + 'If the local storage for this domain is full, please clean it up and try again.';
console.error(msg, e);
}
resolve();
Expand All @@ -153,7 +172,7 @@ class ExtStore {
}

_removeLocal(key) {
return new Promise((resolve) => {
return new Promise(resolve => {
localStorage.removeItem(key);
resolve();
});
Expand Down
6 changes: 6 additions & 0 deletions src/common/libs/webextension-polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* eslint-disable */
if (typeof browser === 'undefined' || Object.getPrototypeOf(browser) !== Object.prototype) {
module.exports = require('webextension-polyfill-origin');
} else {
module.exports = browser;
}
6 changes: 4 additions & 2 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const path = require('path');
const webpack = require('webpack');
const wextManifest = require('wext-manifest');
const ZipPlugin = require('zip-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
Expand All @@ -11,7 +10,7 @@ const { CheckerPlugin } = require('awesome-typescript-loader');
const ExtensionReloader = require('webpack-extension-reloader');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { argv } = require('yargs');

const wextManifest = require('./scripts/wext-manifest');
const manifestInput = require('./src/manifest');

const viewsPath = path.join(__dirname, 'views');
Expand Down Expand Up @@ -67,6 +66,7 @@ const extPath = {
chrome: 'chrome-extension://__MSG_@@extension_id__',
firefox: 'moz-extension://__MSG_@@extension_id__',
opera: 'chrome-extension://__MSG_@@extension_id__',
safari: 'chrome-extension://__MSG_@@extension_id__',
};

function getLessVar() {
Expand Down Expand Up @@ -104,6 +104,8 @@ module.exports = {
extensions: ['.ts', '.tsx', '.js', '.json'],
alias: {
'webextension-polyfill-ts': path.resolve(path.join(__dirname, 'node_modules', 'webextension-polyfill-ts')),
'webextension-polyfill': path.resolve(path.join(__dirname, './src/common/libs/webextension-polyfill.js')),
'webextension-polyfill-origin': path.resolve(path.join(__dirname, 'node_modules', 'webextension-polyfill')),
key: path.resolve(path.join(__dirname, './src/common/libs/keymaster.js')),
'@': path.resolve(__dirname, 'src'),
},
Expand Down
21 changes: 21 additions & 0 deletions xProject/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# See LICENSE folder for this sample’s licensing information.
#
# Apple sample code gitignore configuration.

# Finder
.DS_Store

# Xcode - User files
xcuserdata/

**/*.xcodeproj/project.xcworkspace/*
!**/*.xcodeproj/project.xcworkspace/xcshareddata

**/*.xcodeproj/project.xcworkspace/xcshareddata/*
!**/*.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings

**/*.playground/playground.xcworkspace/*
!**/*.playground/playground.xcworkspace/xcshareddata

**/*.playground/playground.xcworkspace/xcshareddata/*
!**/*.playground/playground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
10 changes: 10 additions & 0 deletions xProject/Git Master Extension/Git_Master_Extension.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>
33 changes: 33 additions & 0 deletions xProject/Git Master Extension/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Git Master Extension</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.Safari.web-extension</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).SafariWebExtensionHandler</string>
</dict>
</dict>
</plist>

0 comments on commit d24a92c

Please sign in to comment.