Added A2HS prompt
This commit is contained in:
parent
f7542965b6
commit
0e8aa0a58a
@ -5,7 +5,6 @@ var config = require('../config')
|
|||||||
var VueLoaderPlugin = require('vue-loader/lib/plugin')
|
var VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||||
var vueLoaderConfig = require('./vue-loader.conf')
|
var vueLoaderConfig = require('./vue-loader.conf')
|
||||||
var StylelintPlugin = require('stylelint-webpack-plugin')
|
var StylelintPlugin = require('stylelint-webpack-plugin')
|
||||||
var FaviconsWebpackPlugin = require('favicons-webpack-plugin')
|
|
||||||
|
|
||||||
function resolve (dir) {
|
function resolve (dir) {
|
||||||
return path.join(__dirname, '..', dir)
|
return path.join(__dirname, '..', dir)
|
||||||
@ -48,16 +47,33 @@ module.exports = {
|
|||||||
loader: 'vue-loader',
|
loader: 'vue-loader',
|
||||||
options: vueLoaderConfig
|
options: vueLoaderConfig
|
||||||
},
|
},
|
||||||
|
// We can't pass graphlibrary to babel
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'string-replace-loader',
|
||||||
|
include: [
|
||||||
|
resolve('node_modules/graphlibrary')
|
||||||
|
],
|
||||||
|
options: {
|
||||||
|
search: '^\\s*(?:let|const) ',
|
||||||
|
replace: 'var ',
|
||||||
|
flags: 'gm'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
include: [resolve('src'), resolve('test'), resolve('node_modules/mermaid/src')],
|
include: [
|
||||||
|
resolve('src'),
|
||||||
|
resolve('test'),
|
||||||
|
resolve('node_modules/mermaid')
|
||||||
|
],
|
||||||
exclude: [
|
exclude: [
|
||||||
resolve('node_modules/mermaid/src/diagrams/class/parser'),
|
resolve('node_modules/mermaid/src/diagrams/class/parser'),
|
||||||
resolve('node_modules/mermaid/src/diagrams/flowchart/parser'),
|
resolve('node_modules/mermaid/src/diagrams/flowchart/parser'),
|
||||||
resolve('node_modules/mermaid/src/diagrams/gantt/parser'),
|
resolve('node_modules/mermaid/src/diagrams/gantt/parser'),
|
||||||
resolve('node_modules/mermaid/src/diagrams/git/parser'),
|
resolve('node_modules/mermaid/src/diagrams/git/parser'),
|
||||||
resolve('node_modules/mermaid/src/diagrams/sequence/parser'),
|
resolve('node_modules/mermaid/src/diagrams/sequence/parser')
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -86,10 +102,6 @@ module.exports = {
|
|||||||
new StylelintPlugin({
|
new StylelintPlugin({
|
||||||
files: ['**/*.vue', '**/*.scss']
|
files: ['**/*.vue', '**/*.scss']
|
||||||
}),
|
}),
|
||||||
new FaviconsWebpackPlugin({
|
|
||||||
logo: resolve('src/assets/favicon.png'),
|
|
||||||
title: 'StackEdit',
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
VERSION: JSON.stringify(require('../package.json').version)
|
VERSION: JSON.stringify(require('../package.json').version)
|
||||||
})
|
})
|
||||||
|
@ -9,6 +9,12 @@ var HtmlWebpackPlugin = require('html-webpack-plugin')
|
|||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||||
var OfflinePlugin = require('offline-plugin');
|
var OfflinePlugin = require('offline-plugin');
|
||||||
|
var WebpackPwaManifest = require('webpack-pwa-manifest')
|
||||||
|
var FaviconsWebpackPlugin = require('favicons-webpack-plugin')
|
||||||
|
|
||||||
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '..', dir)
|
||||||
|
}
|
||||||
|
|
||||||
var env = config.build.env
|
var env = config.build.env
|
||||||
|
|
||||||
@ -94,6 +100,22 @@ var webpackConfig = merge(baseWebpackConfig, {
|
|||||||
ignore: ['.*']
|
ignore: ['.*']
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
|
new FaviconsWebpackPlugin({
|
||||||
|
logo: resolve('src/assets/favicon.png'),
|
||||||
|
title: 'StackEdit',
|
||||||
|
}),
|
||||||
|
new WebpackPwaManifest({
|
||||||
|
name: 'StackEdit',
|
||||||
|
description: 'Full-featured, open-source Markdown editor',
|
||||||
|
display: 'standalone',
|
||||||
|
start_url: 'app',
|
||||||
|
background_color: '#ffffff',
|
||||||
|
crossorigin: 'use-credentials',
|
||||||
|
icons: [{
|
||||||
|
src: resolve('src/assets/favicon.png'),
|
||||||
|
sizes: [96, 128, 192, 256, 384, 512]
|
||||||
|
}]
|
||||||
|
}),
|
||||||
new OfflinePlugin({
|
new OfflinePlugin({
|
||||||
ServiceWorker: {
|
ServiceWorker: {
|
||||||
events: true
|
events: true
|
||||||
@ -101,7 +123,7 @@ var webpackConfig = merge(baseWebpackConfig, {
|
|||||||
AppCache: true,
|
AppCache: true,
|
||||||
excludes: ['**/.*', '**/*.map', '**/index.html', '**/static/oauth2/callback.html', '**/icons-*/*.png', '**/static/fonts/KaTeX_*'],
|
excludes: ['**/.*', '**/*.map', '**/index.html', '**/static/oauth2/callback.html', '**/icons-*/*.png', '**/static/fonts/KaTeX_*'],
|
||||||
externals: ['/', '/app', '/oauth2/callback']
|
externals: ['/', '/app', '/oauth2/callback']
|
||||||
})
|
}),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
82
package-lock.json
generated
82
package-lock.json
generated
@ -16854,6 +16854,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"string-replace-loader": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-0Nvw1LDclF45AFNuYPcD2Jvkv0mwb/dQSnJZMvhqGrT+zzmrpG3OJFD600qfQfNUd5aqfp7fCm2mQMfF7zLbyQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"loader-utils": "^1.1.0",
|
||||||
|
"schema-utils": "^0.4.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": {
|
||||||
|
"version": "6.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz",
|
||||||
|
"integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"fast-deep-equal": "^2.0.1",
|
||||||
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
"json-schema-traverse": "^0.4.1",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ajv-keywords": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz",
|
||||||
|
"integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"fast-deep-equal": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"json-schema-traverse": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"loader-utils": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"big.js": "^3.1.3",
|
||||||
|
"emojis-list": "^2.0.0",
|
||||||
|
"json5": "^0.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema-utils": {
|
||||||
|
"version": "0.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
|
||||||
|
"integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ajv": "^6.1.0",
|
||||||
|
"ajv-keywords": "^3.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||||
@ -19774,6 +19837,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"webpack-pwa-manifest": {
|
||||||
|
"version": "3.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webpack-pwa-manifest/-/webpack-pwa-manifest-3.7.1.tgz",
|
||||||
|
"integrity": "sha512-G37fVCa1ndij3jyz6WaOaxHLHdp2URyOHwp2GLmxt39sXL8ZdOFM1qvHagEJBkNh+3hu25eIgy6TD5J/8sgQcQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"css-color-names": "0.0.4",
|
||||||
|
"jimp": "^0.2.28",
|
||||||
|
"mime": "^1.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mime": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"webpack-sources": {
|
"webpack-sources": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz",
|
||||||
|
@ -110,6 +110,7 @@
|
|||||||
"sass-loader": "^7.0.1",
|
"sass-loader": "^7.0.1",
|
||||||
"semver": "^5.5.0",
|
"semver": "^5.5.0",
|
||||||
"shelljs": "^0.8.1",
|
"shelljs": "^0.8.1",
|
||||||
|
"string-replace-loader": "^2.1.1",
|
||||||
"stylelint": "^9.2.0",
|
"stylelint": "^9.2.0",
|
||||||
"stylelint-config-standard": "^16.0.0",
|
"stylelint-config-standard": "^16.0.0",
|
||||||
"stylelint-processor-html": "^1.0.0",
|
"stylelint-processor-html": "^1.0.0",
|
||||||
@ -124,6 +125,7 @@
|
|||||||
"webpack-dev-middleware": "^1.10.0",
|
"webpack-dev-middleware": "^1.10.0",
|
||||||
"webpack-hot-middleware": "^2.18.0",
|
"webpack-hot-middleware": "^2.18.0",
|
||||||
"webpack-merge": "^4.1.2",
|
"webpack-merge": "^4.1.2",
|
||||||
|
"webpack-pwa-manifest": "^3.7.1",
|
||||||
"worker-loader": "^1.1.1"
|
"worker-loader": "^1.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -2,12 +2,18 @@
|
|||||||
<div class="notification">
|
<div class="notification">
|
||||||
<div class="notification__item flex flex--row flex--align-center" v-for="(item, idx) in items" :key="idx">
|
<div class="notification__item flex flex--row flex--align-center" v-for="(item, idx) in items" :key="idx">
|
||||||
<div class="notification__icon flex flex--column flex--center">
|
<div class="notification__icon flex flex--column flex--center">
|
||||||
<icon-information v-if="item.type === 'info'"></icon-information>
|
<icon-alert v-if="item.type === 'error'"></icon-alert>
|
||||||
<icon-alert v-else-if="item.type === 'error'"></icon-alert>
|
<icon-information v-else></icon-information>
|
||||||
</div>
|
</div>
|
||||||
<div class="notification__content">
|
<div class="notification__content">
|
||||||
{{item.content}}
|
{{item.content}}
|
||||||
</div>
|
</div>
|
||||||
|
<button class="notification__button button" v-if="item.type === 'confirm'" @click="item.reject">
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
<button class="notification__button button" v-if="item.type === 'confirm'" @click="item.resolve">
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -49,4 +55,17 @@ export default {
|
|||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
flex: none;
|
flex: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification__button {
|
||||||
|
color: $navbar-color;
|
||||||
|
padding: 8px;
|
||||||
|
flex: none;
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
color: $navbar-hover-color;
|
||||||
|
background-color: $navbar-hover-background;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
16
src/index.js
16
src/index.js
@ -33,6 +33,22 @@ if (localStorage.updated) {
|
|||||||
setTimeout(() => localStorage.removeItem('updated'), 2000);
|
setTimeout(() => localStorage.removeItem('updated'), 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!localStorage.installPrompted) {
|
||||||
|
window.addEventListener('beforeinstallprompt', async (promptEvent) => {
|
||||||
|
// Prevent Chrome 67 and earlier from automatically showing the prompt
|
||||||
|
promptEvent.preventDefault();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await store.dispatch('notification/confirm', 'Add StackEdit to your home screen?');
|
||||||
|
promptEvent.prompt();
|
||||||
|
await promptEvent.userChoice;
|
||||||
|
} catch (err) {
|
||||||
|
// Cancel
|
||||||
|
}
|
||||||
|
localStorage.installPrompted = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
/* eslint-disable no-new */
|
||||||
|
@ -7,6 +7,7 @@ const clientId = GOOGLE_CLIENT_ID;
|
|||||||
const apiKey = 'AIzaSyC_M4RA9pY6XmM9pmFxlT59UPMO7aHr9kk';
|
const apiKey = 'AIzaSyC_M4RA9pY6XmM9pmFxlT59UPMO7aHr9kk';
|
||||||
const appsDomain = null;
|
const appsDomain = null;
|
||||||
const tokenExpirationMargin = 5 * 60 * 1000; // 5 min (Google tokens expire after 1h)
|
const tokenExpirationMargin = 5 * 60 * 1000; // 5 min (Google tokens expire after 1h)
|
||||||
|
let googlePlusNotification = true;
|
||||||
|
|
||||||
const driveAppDataScopes = ['https://www.googleapis.com/auth/drive.appdata'];
|
const driveAppDataScopes = ['https://www.googleapis.com/auth/drive.appdata'];
|
||||||
const getDriveScopes = token => [token.driveFullAccess
|
const getDriveScopes = token => [token.driveFullAccess
|
||||||
@ -160,7 +161,12 @@ export default {
|
|||||||
|
|
||||||
// Call the user info endpoint
|
// Call the user info endpoint
|
||||||
const user = await getUser('me', token);
|
const user = await getUser('me', token);
|
||||||
|
if (user.displayName) {
|
||||||
token.name = user.displayName;
|
token.name = user.displayName;
|
||||||
|
} else if (googlePlusNotification) {
|
||||||
|
store.dispatch('notification/info', 'Please activate Google Plus to change your account name and photo.');
|
||||||
|
googlePlusNotification = false;
|
||||||
|
}
|
||||||
userSvc.addInfo({
|
userSvc.addInfo({
|
||||||
id: `${subPrefix}:${user.id}`,
|
id: `${subPrefix}:${user.id}`,
|
||||||
name: user.displayName,
|
name: user.displayName,
|
||||||
@ -449,10 +455,10 @@ export default {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
revisions.forEach((revision) => {
|
revisions.forEach((revision) => {
|
||||||
store.commit('userInfo/addItem', {
|
userSvc.addInfo({
|
||||||
id: `${subPrefix}:${revision.lastModifyingUser.permissionId}`,
|
id: `${subPrefix}:${revision.lastModifyingUser.permissionId}`,
|
||||||
name: revision.lastModifyingUser.displayName,
|
name: revision.lastModifyingUser.displayName,
|
||||||
imageUrl: revision.lastModifyingUser.photoLink,
|
imageUrl: revision.lastModifyingUser.photoLink || '',
|
||||||
});
|
});
|
||||||
allRevisions.push(revision);
|
allRevisions.push(revision);
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import providerRegistry from '../services/providers/common/providerRegistry';
|
import providerRegistry from '../services/providers/common/providerRegistry';
|
||||||
|
import utils from '../services/utils';
|
||||||
|
|
||||||
const defaultTimeout = 5000;
|
const defaultTimeout = 5000; // 5 sec
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
namespaced: true,
|
namespaced: true,
|
||||||
@ -14,20 +15,49 @@ export default {
|
|||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
showItem({ state, commit }, item) {
|
showItem({ state, commit }, item) {
|
||||||
if (state.items.every(other => other.type !== item.type || other.content !== item.content)) {
|
const existingItem = utils.someResult(
|
||||||
|
state.items,
|
||||||
|
other => other.type === item.type && other.content === item.content && item,
|
||||||
|
);
|
||||||
|
if (existingItem) {
|
||||||
|
return existingItem.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.promise = new Promise((resolve, reject) => {
|
||||||
commit('setItems', [...state.items, item]);
|
commit('setItems', [...state.items, item]);
|
||||||
|
const removeItem = () => commit(
|
||||||
|
'setItems',
|
||||||
|
state.items.filter(otherItem => otherItem !== item),
|
||||||
|
);
|
||||||
setTimeout(
|
setTimeout(
|
||||||
() => commit('setItems', state.items.filter(otherItem => otherItem !== item)),
|
() => removeItem(),
|
||||||
item.timeout || defaultTimeout,
|
item.timeout || defaultTimeout,
|
||||||
);
|
);
|
||||||
}
|
item.resolve = (res) => {
|
||||||
|
removeItem();
|
||||||
|
resolve(res);
|
||||||
|
};
|
||||||
|
item.reject = (err) => {
|
||||||
|
removeItem();
|
||||||
|
reject(err);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return item.promise;
|
||||||
},
|
},
|
||||||
info({ dispatch }, info) {
|
info({ dispatch }, info) {
|
||||||
dispatch('showItem', {
|
return dispatch('showItem', {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
content: info,
|
content: info,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
confirm({ dispatch }, question) {
|
||||||
|
return dispatch('showItem', {
|
||||||
|
type: 'confirm',
|
||||||
|
content: question,
|
||||||
|
timeout: 10000, // 10 sec
|
||||||
|
});
|
||||||
|
},
|
||||||
error({ dispatch, rootState }, error) {
|
error({ dispatch, rootState }, error) {
|
||||||
const item = { type: 'error' };
|
const item = { type: 'error' };
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -48,7 +78,7 @@ export default {
|
|||||||
if (!item.content || item.content === '[object Object]') {
|
if (!item.content || item.content === '[object Object]') {
|
||||||
item.content = 'Unknown error.';
|
item.content = 'Unknown error.';
|
||||||
}
|
}
|
||||||
dispatch('showItem', item);
|
return dispatch('showItem', item);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user