Fixed publishing
This commit is contained in:
parent
bdb01f407b
commit
d4624eba9d
@ -8,7 +8,9 @@ ENV V4_VERSION 4.3.22
|
||||
RUN npm pack stackedit@$V4_VERSION \
|
||||
&& tar xzf stackedit-*.tgz --strip 1 \
|
||||
&& yarn \
|
||||
&& yarn cache clean
|
||||
&& yarn cache clean \
|
||||
&& rm -rf ~/.cache/bower \
|
||||
&& rm -rf ~/.local/share/bower
|
||||
|
||||
WORKDIR /opt/stackedit
|
||||
|
||||
|
@ -53,7 +53,9 @@ export default {
|
||||
this.ready = true;
|
||||
tempFileSvc.setReady();
|
||||
} catch (err) {
|
||||
if (err && err.message !== 'RELOAD') {
|
||||
if (err && err.message === 'RELOAD') {
|
||||
window.location.reload();
|
||||
} else if (err && err.message !== 'RELOAD') {
|
||||
console.error(err); // eslint-disable-line no-console
|
||||
this.$store.dispatch('notification/error', err);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
<div class="tour-step__inner" v-else-if="step === 'editor'">
|
||||
<h2>Your Markdown editor</h2>
|
||||
<p>StackEdit renders your Markdown into HTML in real-time.</p>
|
||||
<p>StackEdit converts your Markdown to HTML in real-time.</p>
|
||||
<p>Click <icon-side-preview></icon-side-preview> to toggle the side preview.</p>
|
||||
<div class="tour-step__button-bar">
|
||||
<button class="button" @click="finish">Skip</button>
|
||||
@ -144,7 +144,7 @@ $tour-step-width: 240px;
|
||||
.tour-step__inner {
|
||||
position: absolute;
|
||||
background-color: $tour-step-background;
|
||||
padding: 1em;
|
||||
padding: 1.5em;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.33;
|
||||
width: $tour-step-width;
|
||||
@ -213,8 +213,10 @@ $tour-step-width: 240px;
|
||||
}
|
||||
|
||||
.tour-step__button-bar {
|
||||
margin-top: 1.75em;
|
||||
text-align: right;
|
||||
margin-top: 1.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
|
||||
.button {
|
||||
font-size: 1.1em;
|
||||
|
@ -7,7 +7,7 @@
|
||||
</div>
|
||||
<div class="flex flex--column">
|
||||
<div>Import Markdown</div>
|
||||
<span>Open a plain text file.</span>
|
||||
<span>Import a plain text file.</span>
|
||||
</div>
|
||||
</label>
|
||||
<input class="hidden-file" id="import-html-file-input" type="file" @change="onImportHtml">
|
||||
|
@ -77,11 +77,8 @@ export default {
|
||||
...utils.queryParams,
|
||||
exportWorkspace: true,
|
||||
}, true);
|
||||
const iframeElt = utils.createHiddenIframe(url);
|
||||
document.body.appendChild(iframeElt);
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(iframeElt);
|
||||
}, 60000);
|
||||
window.location.href = url;
|
||||
window.location.reload(true);
|
||||
},
|
||||
async settings() {
|
||||
try {
|
||||
|
@ -24,7 +24,7 @@
|
||||
span {
|
||||
display: inline-block;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.6;
|
||||
opacity: 0.67;
|
||||
line-height: 1.3;
|
||||
|
||||
.menu-entry__label {
|
||||
|
@ -7,7 +7,8 @@
|
||||
<p v-if="publishLocations.length"><b>{{currentFileName}}</b> is published to the following location(s):</p>
|
||||
<p v-else><b>{{currentFileName}}</b> is not published yet.</p>
|
||||
<div>
|
||||
<div class="publish-entry flex flex--row flex--align-center" v-for="location in publishLocations" :key="location.id">
|
||||
<div class="publish-entry flex flex--column" v-for="location in publishLocations" :key="location.id">
|
||||
<div class="publish-entry__header flex flex--row flex--align-center">
|
||||
<div class="publish-entry__icon flex flex--column flex--center">
|
||||
<icon-provider :provider-id="location.providerId"></icon-provider>
|
||||
</div>
|
||||
@ -15,14 +16,25 @@
|
||||
{{location.description}}
|
||||
</div>
|
||||
<div class="publish-entry__buttons flex flex--row flex--center">
|
||||
<a class="publish-entry__button button" :href="location.url" target="_blank" v-title="'Open location'">
|
||||
<icon-open-in-new></icon-open-in-new>
|
||||
</a>
|
||||
<button class="publish-entry__button button" @click="remove(location)" v-title="'Remove location'">
|
||||
<icon-delete></icon-delete>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="publish-entry__row flex flex--row flex--align-center">
|
||||
<div class="publish-entry__url">
|
||||
{{location.url}}
|
||||
</div>
|
||||
<div class="publish-entry__buttons flex flex--row flex--center" v-if="location.url">
|
||||
<button class="publish-entry__button button" v-clipboard="location.url" @click="info('Location URL copied to clipboard!')" v-title="'Copy URL'">
|
||||
<icon-content-copy></icon-content-copy>
|
||||
</button>
|
||||
<a class="publish-entry__button button" v-if="location.url" :href="location.url" target="_blank" v-title="'Open location'">
|
||||
<icon-open-in-new></icon-open-in-new>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal__info" v-if="publishLocations.length">
|
||||
<b>Tip:</b> Removing a location won't delete any file.
|
||||
@ -35,7 +47,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import ModalInner from './common/ModalInner';
|
||||
|
||||
export default {
|
||||
@ -54,6 +66,9 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('notification', [
|
||||
'info',
|
||||
]),
|
||||
remove(location) {
|
||||
this.$store.commit('publishLocation/deleteItem', location.id);
|
||||
},
|
||||
@ -65,40 +80,70 @@ export default {
|
||||
@import '../../styles/variables.scss';
|
||||
|
||||
.publish-entry {
|
||||
padding: 0.5rem 0.25rem;
|
||||
border-bottom: 1px solid $hr-color;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
margin: 1.5em 0;
|
||||
height: auto;
|
||||
font-size: 17px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
$button-size: 30px;
|
||||
$small-button-size: 22px;
|
||||
|
||||
.publish-entry__header {
|
||||
line-height: $button-size;
|
||||
}
|
||||
|
||||
.publish-entry__row {
|
||||
margin-top: 1px;
|
||||
padding-top: 1px;
|
||||
border-top: 1px solid rgba(128, 128, 128, 0.15);
|
||||
line-height: $small-button-size;
|
||||
}
|
||||
|
||||
.publish-entry__icon {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
margin-right: 0.75rem;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.publish-entry__description {
|
||||
opacity: 0.5;
|
||||
line-height: 1.4;
|
||||
font-size: 0.9em;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.publish-entry__url {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
opacity: 0.5;
|
||||
font-size: 0.67em;
|
||||
}
|
||||
|
||||
.publish-entry__buttons {
|
||||
margin-left: 0.75rem;
|
||||
|
||||
.publish-entry__row & {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.publish-entry__button {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
padding: 6px;
|
||||
width: $button-size;
|
||||
height: $button-size;
|
||||
padding: 4px;
|
||||
background-color: transparent;
|
||||
opacity: 0.75;
|
||||
|
||||
.publish-entry__row & {
|
||||
width: $small-button-size;
|
||||
height: $small-button-size;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:hover {
|
||||
|
@ -32,7 +32,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<form-entry label="Template">
|
||||
<form-entry label="Template" v-if="format === 'html'">
|
||||
<select slot="field" class="textfield" v-model="selectedTemplate" @keydown.enter="resolve()">
|
||||
<option v-for="(template, id) in allTemplatesById" :key="id" :value="id">
|
||||
{{ template.name }}
|
||||
@ -84,7 +84,7 @@ export default modalTemplate({
|
||||
resolve() {
|
||||
// Return new location
|
||||
const location = googleDriveProvider.makeLocation(this.config.token, this.fileId);
|
||||
if (this.format) {
|
||||
if (this.format === 'html') {
|
||||
location.templateId = this.selectedTemplate;
|
||||
}
|
||||
this.config.resolve(location);
|
||||
|
@ -9,7 +9,7 @@
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="domain" @keydown.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> example.wordpress.com<br>
|
||||
<b>Jetpack plugin</b> is required for self-hosted sites.
|
||||
<b>Note:</b> Jetpack is required for self-hosted sites.
|
||||
</div>
|
||||
</form-entry>
|
||||
<form-entry label="Existing post ID" info="optional">
|
||||
|
@ -332,7 +332,6 @@ const localDbSvc = {
|
||||
// Clean data stored in localStorage
|
||||
localStorage.removeItem(`data/${id}`);
|
||||
});
|
||||
window.location.reload();
|
||||
throw new Error('RELOAD');
|
||||
}
|
||||
|
||||
@ -349,7 +348,7 @@ const localDbSvc = {
|
||||
type: 'text/plain;charset=utf-8',
|
||||
});
|
||||
FileSaver.saveAs(blob, 'StackEdit workspace.json');
|
||||
return;
|
||||
throw new Error('RELOAD');
|
||||
}
|
||||
|
||||
// Watch workspace deletions and persist them as soon as possible
|
||||
|
@ -87,7 +87,7 @@ export default {
|
||||
date,
|
||||
}) {
|
||||
const refreshedToken = await this.refreshToken(token);
|
||||
await request(refreshedToken, {
|
||||
return request(refreshedToken, {
|
||||
method: 'POST',
|
||||
url: `https://public-api.wordpress.com/rest/v1.2/sites/${siteId || domain}/posts/${postId || 'new'}`,
|
||||
body: {
|
||||
|
@ -122,6 +122,7 @@ export default {
|
||||
});
|
||||
|
||||
// Build the tree
|
||||
const parentsMap = {};
|
||||
Object.entries(nodeMap).forEach(([, node]) => {
|
||||
let parentNode = nodeMap[node.item.parentId];
|
||||
if (!parentNode || !parentNode.isFolder) {
|
||||
@ -129,6 +130,18 @@ export default {
|
||||
return;
|
||||
}
|
||||
parentNode = rootNode;
|
||||
} else if (node.isFolder) {
|
||||
// Detect circular reference
|
||||
const parentParents = parentsMap[node.item.parentId] || {};
|
||||
if (parentParents[node.item.id]) {
|
||||
// Node is already a parent of its supposed parent
|
||||
parentNode = rootNode;
|
||||
} else {
|
||||
parentsMap[node.item.id] = {
|
||||
...parentParents,
|
||||
[node.item.parentId]: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (node.isFolder) {
|
||||
parentNode.folders.push(node);
|
||||
|
@ -83,33 +83,25 @@ const store = new Vuex.Store({
|
||||
},
|
||||
pathsByItemId: (state, getters) => {
|
||||
const result = {};
|
||||
const foldersById = state.folder.itemsById;
|
||||
const getPath = (item) => {
|
||||
let itemPath = result[item.id];
|
||||
if (!itemPath) {
|
||||
if (item.parentId === 'trash') {
|
||||
itemPath = `.stackedit-trash/${item.name}`;
|
||||
} else {
|
||||
let { name } = item;
|
||||
if (foldersById[item.id]) {
|
||||
name += '/';
|
||||
const processNode = (node, parentPath = '') => {
|
||||
let path = parentPath;
|
||||
if (node.item.id) {
|
||||
path += node.item.name;
|
||||
if (node.isTrash) {
|
||||
path = '.stackedit-trash/';
|
||||
} else if (node.isFolder) {
|
||||
path += '/';
|
||||
}
|
||||
const parentFolder = foldersById[item.parentId];
|
||||
if (parentFolder) {
|
||||
itemPath = getPath(parentFolder) + name;
|
||||
} else {
|
||||
itemPath = name;
|
||||
result[node.item.id] = path;
|
||||
}
|
||||
|
||||
if (node.isFolder) {
|
||||
node.folders.forEach(child => processNode(child, path));
|
||||
node.files.forEach(child => processNode(child, path));
|
||||
}
|
||||
}
|
||||
result[item.id] = itemPath;
|
||||
return itemPath;
|
||||
};
|
||||
|
||||
[
|
||||
...getters['folder/items'],
|
||||
...getters['file/items'],
|
||||
].forEach(item => getPath(item));
|
||||
processNode(getters['explorer/rootNode']);
|
||||
return result;
|
||||
},
|
||||
itemsByPath: (state, { allItemsById, pathsByItemId }) => {
|
||||
|
Loading…
Reference in New Issue
Block a user