diff --git a/html/src/app.js b/html/src/app.js
index 05f8f1aa..7f95337b 100644
--- a/html/src/app.js
+++ b/html/src/app.js
@@ -1805,7 +1805,7 @@ speechSynthesis.getVoices();
/*
params: {
- worldId: string
+ id: string
}
*/
API.saveWorld = function (params) {
@@ -1822,6 +1822,44 @@ speechSynthesis.getVoices();
});
};
+ /*
+ params: {
+ worldId: string
+ }
+ */
+ API.publishWorld = function (params) {
+ return this.call(`worlds/${params.worldId}/publish`, {
+ method: 'PUT',
+ params
+ }).then((json) => {
+ var args = {
+ json,
+ params
+ };
+ this.$emit('WORLD:SAVE', args);
+ return args;
+ });
+ };
+
+ /*
+ params: {
+ worldId: string
+ }
+ */
+ API.unpublishWorld = function (params) {
+ return this.call(`worlds/${params.worldId}/publish`, {
+ method: 'DELETE',
+ params
+ }).then((json) => {
+ var args = {
+ json,
+ params
+ };
+ this.$emit('WORLD:SAVE', args);
+ return args;
+ });
+ };
+
/*
params: {
worldId: string,
@@ -10253,6 +10291,88 @@ speechSynthesis.getVoices();
});
};
+ $app.methods.promptChangeWorldCapacity = function (world) {
+ this.$prompt('Enter world capacity, Max: 40', 'Change Capacity', {
+ distinguishCancelAndClose: true,
+ confirmButtonText: 'OK',
+ cancelButtonText: 'Cancel',
+ inputValue: world.ref.capacity,
+ inputPattern: /\d+$/,
+ inputErrorMessage: 'Valid number is required',
+ callback: (action, instance) => {
+ if (
+ action === 'confirm' &&
+ instance.inputValue !== world.ref.capacity
+ ) {
+ API.saveWorld({
+ id: world.id,
+ capacity: instance.inputValue
+ }).then((args) => {
+ this.$message({
+ message: 'World capacity changed',
+ type: 'success'
+ });
+ return args;
+ });
+ }
+ }
+ });
+ };
+
+ $app.methods.promptChangeWorldYouTubePreview = function (world) {
+ this.$prompt(
+ 'Enter world YouTube preview, WARNING: once a preview is added it cannot be removed',
+ 'Change YouTube Preview',
+ {
+ distinguishCancelAndClose: true,
+ confirmButtonText: 'OK',
+ cancelButtonText: 'Cancel',
+ inputValue: world.ref.previewYoutubeId,
+ inputErrorMessage: 'Valid YouTube URL is required',
+ callback: (action, instance) => {
+ if (
+ action === 'confirm' &&
+ instance.inputValue !== world.ref.previewYoutubeId
+ ) {
+ if (instance.inputValue.length > 11) {
+ try {
+ var url = new URL(instance.inputValue);
+ var id1 = url.pathname;
+ var id2 = url.searchParams.get('v');
+ if (id1 && id1.length === 12) {
+ instance.inputValue = id1.substring(1, 12);
+ }
+ if (id2 && id2.length === 11) {
+ instance.inputValue = id2;
+ }
+ } catch {
+ this.$message({
+ message: 'Invalid YouTube URL',
+ type: 'error'
+ });
+ return;
+ }
+ }
+ if (
+ instance.inputValue !== world.ref.previewYoutubeId
+ ) {
+ API.saveWorld({
+ id: world.id,
+ previewYoutubeId: instance.inputValue
+ }).then((args) => {
+ this.$message({
+ message: 'World YouTube preview changed',
+ type: 'success'
+ });
+ return args;
+ });
+ }
+ }
+ }
+ }
+ );
+ };
+
$app.methods.promptMaxTableSizeDialog = function () {
this.$prompt('Enter a number', 'Max Table Size', {
distinguishCancelAndClose: true,
@@ -11462,6 +11582,15 @@ speechSynthesis.getVoices();
case 'Change Description':
this.promptChangeWorldDescription(D);
break;
+ case 'Change Capacity':
+ this.promptChangeWorldCapacity(D);
+ break;
+ case 'Change YouTube Preview':
+ this.promptChangeWorldYouTubePreview(D);
+ break;
+ case 'Change Tags':
+ this.showSetWorldTagsDialog();
+ break;
case 'Download Unity Package':
this.openExternalLink(this.worldDialog.ref.unityPackageUrl);
break;
@@ -11502,6 +11631,28 @@ speechSynthesis.getVoices();
return args;
});
break;
+ case 'Publish':
+ API.publishWorld({
+ worldId: D.id
+ }).then((args) => {
+ this.$message({
+ message: 'World has been published',
+ type: 'success'
+ });
+ return args;
+ });
+ break;
+ case 'Unpublish':
+ API.unpublishWorld({
+ worldId: D.id
+ }).then((args) => {
+ this.$message({
+ message: 'World has been unpublished',
+ type: 'success'
+ });
+ return args;
+ });
+ break;
case 'Delete':
API.deleteWorld({
worldId: D.id
@@ -12343,6 +12494,56 @@ speechSynthesis.getVoices();
D.visible = true;
};
+ // App: Set World Tags Dialog
+
+ $app.data.setWorldTagsDialog = {
+ visible: false,
+ tags: [],
+ debugAllowed: false
+ };
+
+ $app.methods.showSetWorldTagsDialog = function () {
+ this.$nextTick(() => adjustDialogZ(this.$refs.setWorldTagsDialog.$el));
+ var D = this.setWorldTagsDialog;
+ D.visible = true;
+ var oldTags = this.worldDialog.ref.tags;
+ var tags = [];
+ oldTags.forEach((tag) => {
+ if (tag.includes('author_tag_')) {
+ tags.unshift(tag.substring(11));
+ }
+ if (tag === 'debug_allowed') {
+ D.debugAllowed = true;
+ }
+ });
+ D.tags = tags.toString();
+ };
+
+ $app.methods.saveSetWorldTagsDialog = function () {
+ var D = this.setWorldTagsDialog;
+ var oldTags = D.tags.split(',');;
+ var tags = [];
+ oldTags.forEach((tag) => {
+ if (tag) {
+ tags.unshift(`author_tag_${tag}`);
+ }
+ });
+ if (D.debugAllowed) {
+ tags.unshift('debug_allowed');
+ }
+ API.saveWorld({
+ id: $app.worldDialog.id,
+ tags
+ }).then((args) => {
+ this.$message({
+ message: 'Tags updated',
+ type: 'success'
+ });
+ D.visible = false;
+ return args;
+ });
+ };
+
// App: Notification position
$app.data.notificationPositionDialog = {
diff --git a/html/src/index.pug b/html/src/index.pug
index e0a4eec4..e0b85e59 100644
--- a/html/src/index.pug
+++ b/html/src/index.pug
@@ -1398,9 +1398,14 @@ html
template(v-else)
el-dropdown-item(icon="el-icon-edit" command="Rename") Rename
el-dropdown-item(icon="el-icon-edit" command="Change Description") Change Description
+ el-dropdown-item(icon="el-icon-edit" command="Change Capacity") Change Capacity
+ el-dropdown-item(icon="el-icon-edit" command="Change YouTube Preview") Change YouTube Preview
+ el-dropdown-item(icon="el-icon-edit" command="Change Tags") Change Tags
el-dropdown-item(icon="el-icon-picture-outline" command="Change Image") Change Image
el-dropdown-item(v-if="worldDialog.ref.unityPackageUrl" icon="el-icon-download" command="Download Unity Package") Download Unity Package
- el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C" divided) Delete
+ el-dropdown-item(v-if="worldDialog.ref.tags.includes('system_approved') || worldDialog.ref.tags.includes('system_labs')" icon="el-icon-view" command="Unpublish" divided) Unpublish From Labs
+ el-dropdown-item(v-else icon="el-icon-view" command="Publish" divided) Publish To Labs
+ el-dropdown-item(icon="el-icon-delete" command="Delete" style="color:#F56C6C") Delete
el-tabs
el-tab-pane(label="Instances")
div.
@@ -1439,12 +1444,17 @@ html
timer(:epoch="user.$location_at")
el-tab-pane(label="Info")
.x-friend-list(style="max-height:none")
- .x-friend-item(style="width:100%;cursor:default")
- .detail
- span.name World ID
- span.extra {{ worldDialog.id }}
- el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips")
- el-button(@click="copyWorld(worldDialog.id)" size="mini" icon="el-icon-s-order" style="margin-left:5px" circle)
+ div(style="width:100%;display:flex")
+ .x-friend-item(style="width:350px;cursor:default")
+ .detail
+ span.name World ID
+ span.extra {{ worldDialog.id }}
+ el-tooltip(placement="top" content="Copy to clipboard" :disabled="hideTooltips")
+ el-button(@click="copyWorld(worldDialog.id)" size="mini" icon="el-icon-s-order" style="margin-left:5px" circle)
+ .x-friend-item(v-if="worldDialog.ref.previewYoutubeId" style="width:350px" @click="openExternalLink(`https://www.youtube.com/watch?v=${worldDialog.ref.previewYoutubeId}`)")
+ .detail
+ span.name YouTube Preview
+ span.extra https://www.youtube.com/watch?v={{ worldDialog.ref.previewYoutubeId }}
.x-friend-item(style="cursor:default")
.detail
span.name Players
@@ -1817,6 +1827,17 @@ html
div(style="display:flex")
el-button(size="small" @click="openExternalLink('https://rapidapi.com/blog/how-to-get-youtube-api-key/')") Guide
el-button(type="primary" size="small" @click="testYouTubeApiKey" style="margin-left:auto") Save
+
+ //- dialog: Set World Tags
+ el-dialog.x-dialog(ref="setWorldTagsDialog" :visible.sync="setWorldTagsDialog.visible" title="Set World Tags" width="400px")
+ el-checkbox(v-model="setWorldTagsDialog.debugAllowed") Enable world debugging for others
+ div(style='font-size:12px;margin-top:10px')
+ | Enter tags comma separated #[br]
+ el-input(type="textarea" v-model="setWorldTagsDialog.tags" size="mini" show-word-limit :autosize="{ minRows:2, maxRows:5 }" placeholder="" style="margin-top:10px")
+ template(#footer)
+ div(style="display:flex")
+ el-button(size="small" @click="setWorldTagsDialog.visible = false") Cancel
+ el-button(type="primary" size="small" @click="saveSetWorldTagsDialog") Save
//- dialog: Cache Download
el-dialog.x-dialog(ref="downloadDialog" :visible.sync="downloadDialog.visible" title="Download History" width="770px")