Fixed main provider synchronization
This commit is contained in:
		
							parent
							
								
									79b954f0f1
								
							
						
					
					
						commit
						f8f3a87559
					
				
							
								
								
									
										11
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								index.html
									
									
									
									
									
								
							@ -3,6 +3,17 @@
 | 
				
			|||||||
  <head>
 | 
					  <head>
 | 
				
			||||||
    <meta charset="utf-8">
 | 
					    <meta charset="utf-8">
 | 
				
			||||||
    <title>StackEdit</title>
 | 
					    <title>StackEdit</title>
 | 
				
			||||||
 | 
					    <link rel="canonical" href="https://stackedit.io/app">
 | 
				
			||||||
 | 
					    <!-- <link rel="icon" href="res-min/img/stackedit-32.ico" type="image/x-icon"> -->
 | 
				
			||||||
 | 
					    <!-- <link rel="icon" sizes="192x192" href="res-min/img/logo-highres.png"> -->
 | 
				
			||||||
 | 
					    <!-- <link rel="shortcut icon" href="res-min/img/stackedit-32.ico" type="image/x-icon"> -->
 | 
				
			||||||
 | 
					    <!-- <link rel="shortcut icon" sizes="192x192" href="res-min/img/logo-highres.png"> -->
 | 
				
			||||||
 | 
					    <!-- <link rel="apple-touch-icon-precomposed" sizes="152x152" href="res-min/img/logo-ipad-retina.png"> -->
 | 
				
			||||||
 | 
					    <meta name="description" content="Free, open-source, full-featured Markdown editor.">
 | 
				
			||||||
 | 
					    <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
 | 
				
			||||||
 | 
					    <meta name="mobile-web-app-capable" content="yes">
 | 
				
			||||||
 | 
					    <meta name="apple-mobile-web-app-capable" content="yes">
 | 
				
			||||||
 | 
					    <meta name="apple-mobile-web-app-status-bar-style" content="black">
 | 
				
			||||||
  </head>
 | 
					  </head>
 | 
				
			||||||
  <body>
 | 
					  <body>
 | 
				
			||||||
    <div id="app"></div>
 | 
					    <div id="app"></div>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										10
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								index.js
									
									
									
									
									
								
							@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					process.env.NODE_ENV = 'production';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var cluster = require('cluster');
 | 
					var cluster = require('cluster');
 | 
				
			||||||
var http = require('http');
 | 
					var http = require('http');
 | 
				
			||||||
var https = require('https');
 | 
					var https = require('https');
 | 
				
			||||||
@ -7,13 +9,13 @@ var app = express();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
require('./server')(app);
 | 
					require('./server')(app);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var port = process.env.PORT || 8080;
 | 
					var port = parseInt(process.env.PORT || 8080, 10);
 | 
				
			||||||
if(port === 443) {
 | 
					if(port === 443) {
 | 
				
			||||||
	var fs = require('fs');
 | 
						var fs = require('fs');
 | 
				
			||||||
	var credentials = {
 | 
						var credentials = {
 | 
				
			||||||
		key: fs.readFileSync(path.join(__dirname, '/../../shared/config/ssl.key'), 'utf8'),
 | 
							key: fs.readFileSync(path.join(__dirname, 'ssl.key'), 'utf8'),
 | 
				
			||||||
		cert: fs.readFileSync(path.join(__dirname, '/../../shared/config/ssl.crt'), 'utf8'),
 | 
							cert: fs.readFileSync(path.join(__dirname, 'ssl.crt'), 'utf8'),
 | 
				
			||||||
		ca: fs.readFileSync(path.join(__dirname, '/../../shared/config/ssl.ca'), 'utf8').split('\n\n')
 | 
							ca: fs.readFileSync(path.join(__dirname, 'ssl.ca'), 'utf8').split('\n\n')
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	var httpsServer = https.createServer(credentials, app);
 | 
						var httpsServer = https.createServer(credentials, app);
 | 
				
			||||||
	httpsServer.listen(port, null, function() {
 | 
						httpsServer.listen(port, null, function() {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "stackedit",
 | 
					  "name": "stackedit",
 | 
				
			||||||
  "version": "5.0.1",
 | 
					  "version": "5.0.2",
 | 
				
			||||||
  "description": "Free, open-source, full-featured Markdown editor",
 | 
					  "description": "Free, open-source, full-featured Markdown editor",
 | 
				
			||||||
  "author": "Benoit Schweblin",
 | 
					  "author": "Benoit Schweblin",
 | 
				
			||||||
  "license": "Apache-2.0",
 | 
					  "license": "Apache-2.0",
 | 
				
			||||||
@ -39,7 +39,7 @@
 | 
				
			|||||||
    "raw-loader": "^0.5.1",
 | 
					    "raw-loader": "^0.5.1",
 | 
				
			||||||
    "request": "^2.82.0",
 | 
					    "request": "^2.82.0",
 | 
				
			||||||
    "serve-static": "^1.12.6",
 | 
					    "serve-static": "^1.12.6",
 | 
				
			||||||
    "stackedit": "^4.3.16",
 | 
					    "stackedit": "^4.3.17",
 | 
				
			||||||
    "vue": "^2.3.3",
 | 
					    "vue": "^2.3.3",
 | 
				
			||||||
    "vuex": "^2.3.1"
 | 
					    "vuex": "^2.3.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
				
			|||||||
@ -3,48 +3,56 @@ var serveStatic = require('serve-static');
 | 
				
			|||||||
var path = require('path');
 | 
					var path = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = function (app) {
 | 
					module.exports = function (app) {
 | 
				
			||||||
  // Force HTTPS on stackedit.io
 | 
					 | 
				
			||||||
  app.all('*', function(req, res, next) {
 | 
					 | 
				
			||||||
    if (req.headers.host === 'stackedit.io' && !req.secure && req.headers['x-forwarded-proto'] !== 'https') {
 | 
					 | 
				
			||||||
      return res.redirect('https://stackedit.io' + req.url);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /\.(eot|ttf|woff|svg)$/.test(req.url) && res.header('Access-Control-Allow-Origin', '*');
 | 
					 | 
				
			||||||
    next();
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Use gzip compression
 | 
					  // Use gzip compression
 | 
				
			||||||
  app.use(compression());
 | 
					  if (process.env.NODE_ENV === 'production') {
 | 
				
			||||||
 | 
					    // Force HTTPS on stackedit.io
 | 
				
			||||||
 | 
					    app.all('*', function(req, res, next) {
 | 
				
			||||||
 | 
					      if (req.headers.host === 'stackedit.io' && !req.secure && req.headers['x-forwarded-proto'] !== 'https') {
 | 
				
			||||||
 | 
					        return res.redirect('https://stackedit.io' + req.url);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      /\.(eot|ttf|woff|svg)$/.test(req.url) && res.header('Access-Control-Allow-Origin', '*');
 | 
				
			||||||
 | 
					      next();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    app.use(compression());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  app.post('/pdfExport', require('./pdf').export);
 | 
					 | 
				
			||||||
  app.get('/oauth2/githubToken', require('./github').githubToken);
 | 
					  app.get('/oauth2/githubToken', require('./github').githubToken);
 | 
				
			||||||
 | 
					  app.post('/pdfExport', require('stackedit/app/pdf').export);
 | 
				
			||||||
 | 
					  app.post('/sshPublish', require('stackedit/app/ssh').publish);
 | 
				
			||||||
 | 
					  app.post('/picasaImportImg', require('stackedit/app/picasa').importImg);
 | 
				
			||||||
 | 
					  app.get('/downloadImport', require('stackedit/app/download').importPublic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Serve landing.html in /
 | 
					 | 
				
			||||||
  app.get('/', function(req, res) {
 | 
					 | 
				
			||||||
    res.sendFile(require.resolve('stackedit/views/landing.html'));
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  // Serve editor.html in /viewer
 | 
					 | 
				
			||||||
  app.get('/editor', function(req, res) {
 | 
					 | 
				
			||||||
    res.sendFile(require.resolve('stackedit/views/editor.html'));
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  // Serve viewer.html in /viewer
 | 
					 | 
				
			||||||
  app.get('/viewer', function(req, res) {
 | 
					 | 
				
			||||||
    res.sendFile(require.resolve('stackedit/views/viewer.html'));
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  // Serve index.html in /app
 | 
					 | 
				
			||||||
  app.get('/app', function(req, res) {
 | 
					 | 
				
			||||||
    res.sendFile(path.join(__dirname, '../dist/index.html'));
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
  // Serve callback.html in /app
 | 
					  // Serve callback.html in /app
 | 
				
			||||||
  app.get('/oauth2/callback', function(req, res) {
 | 
					  app.get('/oauth2/callback', function(req, res) {
 | 
				
			||||||
    res.sendFile(path.join(__dirname, '../dist/static/oauth2/callback.html'));
 | 
					    res.sendFile(path.join(__dirname, '../static/oauth2/callback.html'));
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Serve static resources
 | 
					  // Serve static resources
 | 
				
			||||||
  app.use(serveStatic(path.join(__dirname, '../dist'))); // v5
 | 
					  if (process.env.NODE_ENV === 'production') {
 | 
				
			||||||
  app.use(serveStatic(path.dirname(require.resolve('stackedit/public/cache.manifest')))); // v4
 | 
					    // Serve landing.html in /
 | 
				
			||||||
 | 
					    app.get('/', function(req, res) {
 | 
				
			||||||
 | 
					      res.sendFile(require.resolve('stackedit/views/landing.html'));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    // Serve editor.html in /viewer
 | 
				
			||||||
 | 
					    app.get('/editor', function(req, res) {
 | 
				
			||||||
 | 
					      res.sendFile(require.resolve('stackedit/views/editor.html'));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    // Serve viewer.html in /viewer
 | 
				
			||||||
 | 
					    app.get('/viewer', function(req, res) {
 | 
				
			||||||
 | 
					      res.sendFile(require.resolve('stackedit/views/viewer.html'));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    // Serve index.html in /app
 | 
				
			||||||
 | 
					    app.get('/app', function(req, res) {
 | 
				
			||||||
 | 
					      res.sendFile(path.join(__dirname, '../dist/index.html'));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Error 404
 | 
					    app.use(serveStatic(path.join(__dirname, '../dist'))); // v5
 | 
				
			||||||
  app.use(function(req, res) {
 | 
					    app.use(serveStatic(path.dirname(require.resolve('stackedit/public/cache.manifest')))); // v4
 | 
				
			||||||
    res.status(404).sendFile(require.resolve('stackedit/views/error_404.html'));
 | 
					
 | 
				
			||||||
  });
 | 
					    // Error 404
 | 
				
			||||||
 | 
					    app.use(function(req, res) {
 | 
				
			||||||
 | 
					      res.status(404).sendFile(require.resolve('stackedit/views/error_404.html'));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
		 Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 2.1 KiB  | 
@ -372,7 +372,7 @@ $t: 3000ms;
 | 
				
			|||||||
.navigation-bar__spinner {
 | 
					.navigation-bar__spinner {
 | 
				
			||||||
  width: 22px;
 | 
					  width: 22px;
 | 
				
			||||||
  margin: 8px 0 0 8px;
 | 
					  margin: 8px 0 0 8px;
 | 
				
			||||||
  color: rgba(255, 255, 255, 0.67);
 | 
					  color: #b2b2b2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .icon {
 | 
					  .icon {
 | 
				
			||||||
    width: 22px;
 | 
					    width: 22px;
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,16 @@
 | 
				
			|||||||
      <div>Reset application</div>
 | 
					      <div>Reset application</div>
 | 
				
			||||||
      <span>Sign out and clean local data.</span>
 | 
					      <span>Sign out and clean local data.</span>
 | 
				
			||||||
    </menu-entry>
 | 
					    </menu-entry>
 | 
				
			||||||
 | 
					    <hr>
 | 
				
			||||||
 | 
					    <a href="editor" target="_blank" class="menu-entry button flex flex--row flex--align-center">
 | 
				
			||||||
 | 
					      <div class="menu-entry__icon flex flex--column flex--center">
 | 
				
			||||||
 | 
					        <icon-alert></icon-alert>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="flex flex--column">
 | 
				
			||||||
 | 
					        <div>StackEdit v4</div>
 | 
				
			||||||
 | 
					        <span>Deprecated.</span>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </a>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import 'babel-polyfill';
 | 
				
			|||||||
import 'indexeddbshim/dist/indexeddbshim';
 | 
					import 'indexeddbshim/dist/indexeddbshim';
 | 
				
			||||||
import utils from './utils';
 | 
					import utils from './utils';
 | 
				
			||||||
import store from '../store';
 | 
					import store from '../store';
 | 
				
			||||||
 | 
					import welcomeFile from '../data/welcomeFile.md';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const indexedDB = window.indexedDB;
 | 
					const indexedDB = window.indexedDB;
 | 
				
			||||||
const dbVersion = 1;
 | 
					const dbVersion = 1;
 | 
				
			||||||
@ -91,7 +92,7 @@ const contentTypes = {
 | 
				
			|||||||
  syncedContent: true,
 | 
					  syncedContent: true,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					const localDbSvc = {
 | 
				
			||||||
  lastTx: 0,
 | 
					  lastTx: 0,
 | 
				
			||||||
  hashMap,
 | 
					  hashMap,
 | 
				
			||||||
  connection: new Connection(),
 | 
					  connection: new Connection(),
 | 
				
			||||||
@ -297,3 +298,77 @@ export default {
 | 
				
			|||||||
    }, () => store.dispatch('notification/error', 'Could not delete local database.'));
 | 
					    }, () => store.dispatch('notification/error', 'Could not delete local database.'));
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const loader = type => fileId => localDbSvc.loadItem(`${fileId}/${type}`)
 | 
				
			||||||
 | 
					  // Item does not exist, create it
 | 
				
			||||||
 | 
					  .catch(() => store.commit(`${type}/setItem`, {
 | 
				
			||||||
 | 
					    id: `${fileId}/${type}`,
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					localDbSvc.loadSyncedContent = loader('syncedContent');
 | 
				
			||||||
 | 
					localDbSvc.loadContentState = loader('contentState');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ifNoId = cb => (obj) => {
 | 
				
			||||||
 | 
					  if (obj.id) {
 | 
				
			||||||
 | 
					    return obj;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return cb();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Load the DB on boot
 | 
				
			||||||
 | 
					localDbSvc.sync()
 | 
				
			||||||
 | 
					  // And watch file changing
 | 
				
			||||||
 | 
					  .then(() => store.watch(
 | 
				
			||||||
 | 
					    () => store.getters['file/current'].id,
 | 
				
			||||||
 | 
					    () => Promise.resolve(store.getters['file/current'])
 | 
				
			||||||
 | 
					      // If current file has no ID, get the most recent file
 | 
				
			||||||
 | 
					      .then(ifNoId(() => store.getters['file/lastOpened']))
 | 
				
			||||||
 | 
					      // If still no ID, create a new file
 | 
				
			||||||
 | 
					      .then(ifNoId(() => {
 | 
				
			||||||
 | 
					        const id = utils.uid();
 | 
				
			||||||
 | 
					        store.commit('content/setItem', {
 | 
				
			||||||
 | 
					          id: `${id}/content`,
 | 
				
			||||||
 | 
					          text: welcomeFile,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        store.commit('file/setItem', {
 | 
				
			||||||
 | 
					          id,
 | 
				
			||||||
 | 
					          name: 'Welcome file',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return store.state.file.itemMap[id];
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
 | 
					      .then((currentFile) => {
 | 
				
			||||||
 | 
					        // Fix current file ID
 | 
				
			||||||
 | 
					        if (store.getters['file/current'].id !== currentFile.id) {
 | 
				
			||||||
 | 
					          store.commit('file/setCurrentId', currentFile.id);
 | 
				
			||||||
 | 
					          // Wait for the next watch tick
 | 
				
			||||||
 | 
					          return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return Promise.resolve()
 | 
				
			||||||
 | 
					          // Load contentState from DB
 | 
				
			||||||
 | 
					          .then(() => localDbSvc.loadContentState(currentFile.id))
 | 
				
			||||||
 | 
					          // Load syncedContent from DB
 | 
				
			||||||
 | 
					          .then(() => localDbSvc.loadSyncedContent(currentFile.id))
 | 
				
			||||||
 | 
					          // Load content from DB
 | 
				
			||||||
 | 
					          .then(() => localDbSvc.loadItem(`${currentFile.id}/content`))
 | 
				
			||||||
 | 
					          .then(
 | 
				
			||||||
 | 
					            // Success, set last opened file
 | 
				
			||||||
 | 
					            () => store.dispatch('data/setLastOpenedId', currentFile.id),
 | 
				
			||||||
 | 
					            (err) => {
 | 
				
			||||||
 | 
					              // Failure (content is not available), go back to previous file
 | 
				
			||||||
 | 
					              const lastOpenedFile = store.getters['file/lastOpened'];
 | 
				
			||||||
 | 
					              store.commit('file/setCurrentId', lastOpenedFile.id);
 | 
				
			||||||
 | 
					              throw err;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch((err) => {
 | 
				
			||||||
 | 
					        console.error(err); // eslint-disable-line no-console
 | 
				
			||||||
 | 
					        store.dispatch('notification/error', err);
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      immediate: true,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Sync local DB periodically
 | 
				
			||||||
 | 
					utils.setInterval(() => localDbSvc.sync(), 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default localDbSvc;
 | 
				
			||||||
 | 
				
			|||||||
@ -62,8 +62,7 @@ export default providerRegistry.register({
 | 
				
			|||||||
      .then(() => syncData);
 | 
					      .then(() => syncData);
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  downloadContent(token, syncLocation) {
 | 
					  downloadContent(token, syncLocation) {
 | 
				
			||||||
    return this.downloadData(token, `${syncLocation.fileId}/content`)
 | 
					    return this.downloadData(token, `${syncLocation.fileId}/content`);
 | 
				
			||||||
      .then(() => syncLocation);
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  downloadData(token, dataId) {
 | 
					  downloadData(token, dataId) {
 | 
				
			||||||
    const syncData = store.getters['data/syncDataByItemId'][dataId];
 | 
					    const syncData = store.getters['data/syncDataByItemId'][dataId];
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
import localDbSvc from './localDbSvc';
 | 
					import localDbSvc from './localDbSvc';
 | 
				
			||||||
import store from '../store';
 | 
					import store from '../store';
 | 
				
			||||||
import welcomeFile from '../data/welcomeFile.md';
 | 
					 | 
				
			||||||
import utils from './utils';
 | 
					import utils from './utils';
 | 
				
			||||||
import diffUtils from './diffUtils';
 | 
					import diffUtils from './diffUtils';
 | 
				
			||||||
import providerRegistry from './providers/providerRegistry';
 | 
					import providerRegistry from './providers/providerRegistry';
 | 
				
			||||||
@ -54,15 +53,6 @@ function cleanSyncedContent(syncedContent) {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const loader = type => fileId => localDbSvc.loadItem(`${fileId}/${type}`)
 | 
					 | 
				
			||||||
  // Item does not exist, create it
 | 
					 | 
				
			||||||
  .catch(() => store.commit(`${type}/setItem`, {
 | 
					 | 
				
			||||||
    id: `${fileId}/${type}`,
 | 
					 | 
				
			||||||
  }));
 | 
					 | 
				
			||||||
const loadContent = loader('content');
 | 
					 | 
				
			||||||
const loadSyncedContent = loader('syncedContent');
 | 
					 | 
				
			||||||
const loadContentState = loader('contentState');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function applyChanges(changes) {
 | 
					function applyChanges(changes) {
 | 
				
			||||||
  const token = mainProvider.getToken();
 | 
					  const token = mainProvider.getToken();
 | 
				
			||||||
  const storeItemMap = { ...store.getters.allItemMap };
 | 
					  const storeItemMap = { ...store.getters.allItemMap };
 | 
				
			||||||
@ -70,31 +60,31 @@ function applyChanges(changes) {
 | 
				
			|||||||
  let syncDataChanged = false;
 | 
					  let syncDataChanged = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  changes.forEach((change) => {
 | 
					  changes.forEach((change) => {
 | 
				
			||||||
    const existingSyncData = syncData[change.fileId];
 | 
					    // Ignore items that belong to another user (like settings)
 | 
				
			||||||
    const existingItem = existingSyncData && storeItemMap[existingSyncData.itemId];
 | 
					    if (!change.item || !change.item.sub || change.item.sub === token.sub) {
 | 
				
			||||||
    if (change.removed && existingSyncData) {
 | 
					      const existingSyncData = syncData[change.fileId];
 | 
				
			||||||
      if (existingItem) {
 | 
					      const existingItem = existingSyncData && storeItemMap[existingSyncData.itemId];
 | 
				
			||||||
        // Remove object from the store
 | 
					      if (change.removed && existingSyncData) {
 | 
				
			||||||
        store.commit(`${existingItem.type}/deleteItem`, existingItem.id);
 | 
					        if (existingItem) {
 | 
				
			||||||
        delete storeItemMap[existingItem.id];
 | 
					          // Remove object from the store
 | 
				
			||||||
      }
 | 
					          store.commit(`${existingItem.type}/deleteItem`, existingItem.id);
 | 
				
			||||||
      delete syncData[change.fileId];
 | 
					          delete storeItemMap[existingItem.id];
 | 
				
			||||||
      syncDataChanged = true;
 | 
					 | 
				
			||||||
    } else if (!change.removed && change.item && change.item.hash && (
 | 
					 | 
				
			||||||
      // Ignore items that belong to another user (like settings)
 | 
					 | 
				
			||||||
      !change.item.sub || change.item.sub === token.sub
 | 
					 | 
				
			||||||
    )) {
 | 
					 | 
				
			||||||
      if (!existingSyncData || (existingSyncData.hash !== change.item.hash && (
 | 
					 | 
				
			||||||
        !existingItem || existingItem.hash !== change.item.hash
 | 
					 | 
				
			||||||
      ))) {
 | 
					 | 
				
			||||||
        // Put object in the store
 | 
					 | 
				
			||||||
        if (change.item.type !== 'content') { // Merge contents later
 | 
					 | 
				
			||||||
          store.commit(`${change.item.type}/setItem`, change.item);
 | 
					 | 
				
			||||||
          storeItemMap[change.item.id] = change.item;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        delete syncData[change.fileId];
 | 
				
			||||||
 | 
					        syncDataChanged = true;
 | 
				
			||||||
 | 
					      } else if (!change.removed && change.item && change.item.hash) {
 | 
				
			||||||
 | 
					        if (!existingSyncData || (existingSyncData.hash !== change.item.hash && (
 | 
				
			||||||
 | 
					          !existingItem || existingItem.hash !== change.item.hash
 | 
				
			||||||
 | 
					        ))) {
 | 
				
			||||||
 | 
					          // Put object in the store
 | 
				
			||||||
 | 
					          if (change.item.type !== 'content') { // Merge contents later
 | 
				
			||||||
 | 
					            store.commit(`${change.item.type}/setItem`, change.item);
 | 
				
			||||||
 | 
					            storeItemMap[change.item.id] = change.item;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        syncData[change.fileId] = change.syncData;
 | 
				
			||||||
 | 
					        syncDataChanged = true;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      syncData[change.fileId] = change.syncData;
 | 
					 | 
				
			||||||
      syncDataChanged = true;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -121,7 +111,7 @@ function createSyncLocation(syncLocation) {
 | 
				
			|||||||
        ...content,
 | 
					        ...content,
 | 
				
			||||||
        history: [content.hash],
 | 
					        history: [content.hash],
 | 
				
			||||||
      }, syncLocation)
 | 
					      }, syncLocation)
 | 
				
			||||||
        .then(syncLocationToStore => loadSyncedContent(fileId)
 | 
					        .then(syncLocationToStore => localDbSvc.loadSyncedContent(fileId)
 | 
				
			||||||
          .then(() => {
 | 
					          .then(() => {
 | 
				
			||||||
            const newSyncedContent = utils.deepCopy(
 | 
					            const newSyncedContent = utils.deepCopy(
 | 
				
			||||||
              store.state.syncedContent.itemMap[`${fileId}/syncedContent`]);
 | 
					              store.state.syncedContent.itemMap[`${fileId}/syncedContent`]);
 | 
				
			||||||
@ -137,9 +127,11 @@ function createSyncLocation(syncLocation) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function syncFile(fileId) {
 | 
					function syncFile(fileId, needSyncRestartParam = false) {
 | 
				
			||||||
  return loadSyncedContent(fileId)
 | 
					  let needSyncRestart = needSyncRestartParam;
 | 
				
			||||||
    .then(() => loadContent(fileId))
 | 
					  return localDbSvc.loadSyncedContent(fileId)
 | 
				
			||||||
 | 
					    .then(() => localDbSvc.loadItem(`${fileId}/content`)
 | 
				
			||||||
 | 
					      .catch(() => {})) // Item may not exist if content has not been downloaded yet
 | 
				
			||||||
    .then(() => {
 | 
					    .then(() => {
 | 
				
			||||||
      const getContent = () => store.state.content.itemMap[`${fileId}/content`];
 | 
					      const getContent = () => store.state.content.itemMap[`${fileId}/content`];
 | 
				
			||||||
      const getSyncedContent = () => store.state.syncedContent.itemMap[`${fileId}/syncedContent`];
 | 
					      const getSyncedContent = () => store.state.syncedContent.itemMap[`${fileId}/syncedContent`];
 | 
				
			||||||
@ -176,6 +168,9 @@ function syncFile(fileId) {
 | 
				
			|||||||
                  const syncHistoryItem = getSyncHistoryItem(syncLocation.id);
 | 
					                  const syncHistoryItem = getSyncHistoryItem(syncLocation.id);
 | 
				
			||||||
                  let mergedContent = (() => {
 | 
					                  let mergedContent = (() => {
 | 
				
			||||||
                    const clientContent = utils.deepCopy(getContent());
 | 
					                    const clientContent = utils.deepCopy(getContent());
 | 
				
			||||||
 | 
					                    if (!clientContent) {
 | 
				
			||||||
 | 
					                      return utils.deepCopy(serverContent);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                    if (!serverContent) {
 | 
					                    if (!serverContent) {
 | 
				
			||||||
                      // Sync location has not been created yet
 | 
					                      // Sync location has not been created yet
 | 
				
			||||||
                      return clientContent;
 | 
					                      return clientContent;
 | 
				
			||||||
@ -200,10 +195,17 @@ function syncFile(fileId) {
 | 
				
			|||||||
                    return diffUtils.mergeContent(serverContent, clientContent, lastMergedContent);
 | 
					                    return diffUtils.mergeContent(serverContent, clientContent, lastMergedContent);
 | 
				
			||||||
                  })();
 | 
					                  })();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  // Update content in store
 | 
					                  if (!mergedContent) {
 | 
				
			||||||
                  store.commit('content/patchItem', {
 | 
					                    errorLocations[syncLocation.id] = true;
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  // Update or set content in store
 | 
				
			||||||
 | 
					                  delete mergedContent.history;
 | 
				
			||||||
 | 
					                  store.commit('content/setItem', {
 | 
				
			||||||
                    id: `${fileId}/content`,
 | 
					                    id: `${fileId}/content`,
 | 
				
			||||||
                    ...mergedContent,
 | 
					                    ...mergedContent,
 | 
				
			||||||
 | 
					                    hash: 0,
 | 
				
			||||||
                  });
 | 
					                  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                  // Retrieve content with new `hash` and freeze it
 | 
					                  // Retrieve content with new `hash` and freeze it
 | 
				
			||||||
@ -272,6 +274,12 @@ function syncFile(fileId) {
 | 
				
			|||||||
                      ) {
 | 
					                      ) {
 | 
				
			||||||
                        store.commit('syncLocation/patchItem', syncLocationToStore);
 | 
					                        store.commit('syncLocation/patchItem', syncLocationToStore);
 | 
				
			||||||
                      }
 | 
					                      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                      // If content was just created, restart sync to create the file as well
 | 
				
			||||||
 | 
					                      const syncDataByItemId = store.getters['data/syncDataByItemId'];
 | 
				
			||||||
 | 
					                      if (!syncDataByItemId[fileId]) {
 | 
				
			||||||
 | 
					                        needSyncRestart = true;
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .catch((err) => {
 | 
					                .catch((err) => {
 | 
				
			||||||
@ -298,13 +306,15 @@ function syncFile(fileId) {
 | 
				
			|||||||
        .then(() => {
 | 
					        .then(() => {
 | 
				
			||||||
          throw err;
 | 
					          throw err;
 | 
				
			||||||
        }))
 | 
					        }))
 | 
				
			||||||
    .catch((err) => {
 | 
					    .then(
 | 
				
			||||||
      if (err && err.message === 'TOO_LATE') {
 | 
					      () => needSyncRestart,
 | 
				
			||||||
        // Restart sync
 | 
					      (err) => {
 | 
				
			||||||
        return syncFile(fileId);
 | 
					        if (err && err.message === 'TOO_LATE') {
 | 
				
			||||||
      }
 | 
					          // Restart sync
 | 
				
			||||||
      throw err;
 | 
					          return syncFile(fileId, needSyncRestart);
 | 
				
			||||||
    });
 | 
					        }
 | 
				
			||||||
 | 
					        throw err;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -320,7 +330,10 @@ function syncDataItem(dataId) {
 | 
				
			|||||||
    .then((serverItem = null) => {
 | 
					    .then((serverItem = null) => {
 | 
				
			||||||
      const dataSyncData = store.getters['data/dataSyncData'][dataId];
 | 
					      const dataSyncData = store.getters['data/dataSyncData'][dataId];
 | 
				
			||||||
      let mergedItem = (() => {
 | 
					      let mergedItem = (() => {
 | 
				
			||||||
        const clientItem = utils.deepCopy(store.getters[`data/${dataId}`]);
 | 
					        const clientItem = utils.deepCopy(store.state.data.itemMap[dataId]);
 | 
				
			||||||
 | 
					        if (!clientItem) {
 | 
				
			||||||
 | 
					          return serverItem;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        if (!serverItem) {
 | 
					        if (!serverItem) {
 | 
				
			||||||
          return clientItem;
 | 
					          return clientItem;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -341,6 +354,10 @@ function syncDataItem(dataId) {
 | 
				
			|||||||
        return clientItem;
 | 
					        return clientItem;
 | 
				
			||||||
      })();
 | 
					      })();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!mergedItem) {
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Update item in store
 | 
					      // Update item in store
 | 
				
			||||||
      store.commit('data/setItem', {
 | 
					      store.commit('data/setItem', {
 | 
				
			||||||
        id: dataId,
 | 
					        id: dataId,
 | 
				
			||||||
@ -401,7 +418,10 @@ function sync() {
 | 
				
			|||||||
        Object.keys(storeItemMap).some((id) => {
 | 
					        Object.keys(storeItemMap).some((id) => {
 | 
				
			||||||
          const item = storeItemMap[id];
 | 
					          const item = storeItemMap[id];
 | 
				
			||||||
          const existingSyncData = syncDataByItemId[id];
 | 
					          const existingSyncData = syncDataByItemId[id];
 | 
				
			||||||
          if (!existingSyncData || existingSyncData.hash !== item.hash) {
 | 
					          if ((!existingSyncData || existingSyncData.hash !== item.hash) &&
 | 
				
			||||||
 | 
					            // Add file if content has been uploaded
 | 
				
			||||||
 | 
					            (item.type !== 'file' || syncDataByItemId[`${id}/content`])
 | 
				
			||||||
 | 
					          ) {
 | 
				
			||||||
            result = mainProvider.saveItem(
 | 
					            result = mainProvider.saveItem(
 | 
				
			||||||
              mainToken,
 | 
					              mainToken,
 | 
				
			||||||
              // Use deepCopy to freeze objects
 | 
					              // Use deepCopy to freeze objects
 | 
				
			||||||
@ -454,9 +474,12 @@ function sync() {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const getOneFileIdToSync = () => {
 | 
					      const getOneFileIdToSync = () => {
 | 
				
			||||||
        const allContentIds = Object.keys(localDbSvc.hashMap.content);
 | 
					        const contentIds = [...new Set([
 | 
				
			||||||
 | 
					          ...Object.keys(localDbSvc.hashMap.content),
 | 
				
			||||||
 | 
					          ...store.getters['file/items'].map(file => `${file.id}/content`),
 | 
				
			||||||
 | 
					        ])];
 | 
				
			||||||
        let fileId;
 | 
					        let fileId;
 | 
				
			||||||
        allContentIds.some((contentId) => {
 | 
					        contentIds.some((contentId) => {
 | 
				
			||||||
          // Get content hash from itemMap or from localDbSvc if not loaded
 | 
					          // Get content hash from itemMap or from localDbSvc if not loaded
 | 
				
			||||||
          const loadedContent = store.state.content.itemMap[contentId];
 | 
					          const loadedContent = store.state.content.itemMap[contentId];
 | 
				
			||||||
          const hash = loadedContent ? loadedContent.hash : localDbSvc.hashMap.content[contentId];
 | 
					          const hash = loadedContent ? loadedContent.hash : localDbSvc.hashMap.content[contentId];
 | 
				
			||||||
@ -470,10 +493,13 @@ function sync() {
 | 
				
			|||||||
        return fileId;
 | 
					        return fileId;
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const syncNextFile = () => {
 | 
					      const syncNextFile = (needSyncRestartParam) => {
 | 
				
			||||||
        const fileId = getOneFileIdToSync();
 | 
					        const fileId = getOneFileIdToSync();
 | 
				
			||||||
        return fileId && syncFile(fileId)
 | 
					        if (!fileId) {
 | 
				
			||||||
          .then(() => syncNextFile());
 | 
					          return needSyncRestartParam;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return syncFile(fileId, needSyncRestartParam)
 | 
				
			||||||
 | 
					          .then(needSyncRestart => syncNextFile(needSyncRestart));
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return Promise.resolve()
 | 
					      return Promise.resolve()
 | 
				
			||||||
@ -482,21 +508,29 @@ function sync() {
 | 
				
			|||||||
        .then(() => syncDataItem('settings'))
 | 
					        .then(() => syncDataItem('settings'))
 | 
				
			||||||
        .then(() => syncDataItem('templates'))
 | 
					        .then(() => syncDataItem('templates'))
 | 
				
			||||||
        .then(() => {
 | 
					        .then(() => {
 | 
				
			||||||
          const currentFileId = store.getters['content/current'].id;
 | 
					          const currentFileId = store.getters['file/current'].id;
 | 
				
			||||||
          if (currentFileId) {
 | 
					          if (currentFileId) {
 | 
				
			||||||
            // Sync current file first
 | 
					            // Sync current file first
 | 
				
			||||||
            return syncFile(currentFileId)
 | 
					            return syncFile(currentFileId)
 | 
				
			||||||
              .then(() => syncNextFile());
 | 
					              .then(needSyncRestart => syncNextFile(needSyncRestart));
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          return syncNextFile();
 | 
					          return syncNextFile();
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .catch((err) => {
 | 
					        .then(
 | 
				
			||||||
          if (err && err.message === 'TOO_LATE') {
 | 
					          (needSyncRestart) => {
 | 
				
			||||||
            // Restart sync
 | 
					            if (needSyncRestart) {
 | 
				
			||||||
            return sync();
 | 
					              // Restart sync
 | 
				
			||||||
          }
 | 
					              return sync();
 | 
				
			||||||
          throw err;
 | 
					            }
 | 
				
			||||||
        });
 | 
					            return null;
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          (err) => {
 | 
				
			||||||
 | 
					            if (err && err.message === 'TOO_LATE') {
 | 
				
			||||||
 | 
					              // Restart sync
 | 
				
			||||||
 | 
					              return sync();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            throw err;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -552,58 +586,6 @@ utils.setInterval(() => {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}, 1000);
 | 
					}, 1000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const ifNoId = cb => (obj) => {
 | 
					 | 
				
			||||||
  if (obj.id) {
 | 
					 | 
				
			||||||
    return obj;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return cb();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Load the DB on boot
 | 
					 | 
				
			||||||
localDbSvc.sync()
 | 
					 | 
				
			||||||
  // And watch file changing
 | 
					 | 
				
			||||||
  .then(() => store.watch(
 | 
					 | 
				
			||||||
    () => store.getters['file/current'].id,
 | 
					 | 
				
			||||||
    () => Promise.resolve(store.getters['file/current'])
 | 
					 | 
				
			||||||
      // If current file has no ID, get the most recent file
 | 
					 | 
				
			||||||
      .then(ifNoId(() => store.getters['file/lastOpened']))
 | 
					 | 
				
			||||||
      // If still no ID, create a new file
 | 
					 | 
				
			||||||
      .then(ifNoId(() => {
 | 
					 | 
				
			||||||
        const id = utils.uid();
 | 
					 | 
				
			||||||
        store.commit('content/setItem', {
 | 
					 | 
				
			||||||
          id: `${id}/content`,
 | 
					 | 
				
			||||||
          text: welcomeFile,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        store.commit('file/setItem', {
 | 
					 | 
				
			||||||
          id,
 | 
					 | 
				
			||||||
          name: 'Welcome file',
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return store.state.file.itemMap[id];
 | 
					 | 
				
			||||||
      }))
 | 
					 | 
				
			||||||
      .then((currentFile) => {
 | 
					 | 
				
			||||||
        // Fix current file ID
 | 
					 | 
				
			||||||
        if (store.getters['file/current'].id !== currentFile.id) {
 | 
					 | 
				
			||||||
          store.commit('file/setCurrentId', currentFile.id);
 | 
					 | 
				
			||||||
          // Wait for the next watch tick
 | 
					 | 
				
			||||||
          return null;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // Set last opened
 | 
					 | 
				
			||||||
        store.dispatch('data/setLastOpenedId', currentFile.id);
 | 
					 | 
				
			||||||
        return Promise.resolve()
 | 
					 | 
				
			||||||
          // Load contentState from DB
 | 
					 | 
				
			||||||
          .then(() => loadContentState(currentFile.id))
 | 
					 | 
				
			||||||
          // Load syncedContent from DB
 | 
					 | 
				
			||||||
          .then(() => loadSyncedContent(currentFile.id))
 | 
					 | 
				
			||||||
          // Load content from DB
 | 
					 | 
				
			||||||
          .then(() => localDbSvc.loadItem(`${currentFile.id}/content`));
 | 
					 | 
				
			||||||
      }),
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      immediate: true,
 | 
					 | 
				
			||||||
    }));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Sync local DB periodically
 | 
					 | 
				
			||||||
utils.setInterval(() => localDbSvc.sync(), 1000);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Unload contents from memory periodically
 | 
					// Unload contents from memory periodically
 | 
				
			||||||
utils.setInterval(() => {
 | 
					utils.setInterval(() => {
 | 
				
			||||||
  // Wait for sync and publish to finish
 | 
					  // Wait for sync and publish to finish
 | 
				
			||||||
 | 
				
			|||||||
@ -5945,9 +5945,9 @@ sshpk@^1.7.0:
 | 
				
			|||||||
    jsbn "~0.1.0"
 | 
					    jsbn "~0.1.0"
 | 
				
			||||||
    tweetnacl "~0.14.0"
 | 
					    tweetnacl "~0.14.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
stackedit@^4.3.16:
 | 
					stackedit@^4.3.17:
 | 
				
			||||||
  version "4.3.16"
 | 
					  version "4.3.17"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/stackedit/-/stackedit-4.3.16.tgz#e4df6af29e70d2c45a547523e6aa4f8025c1556d"
 | 
					  resolved "https://registry.yarnpkg.com/stackedit/-/stackedit-4.3.17.tgz#3c524a625f7399d13b06706da2305a131a8df56c"
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    bower "^1.8.2"
 | 
					    bower "^1.8.2"
 | 
				
			||||||
    compression "^1.0.11"
 | 
					    compression "^1.0.11"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user