resolve merge conflict

snap7
Michael Ball 2021-05-24 19:09:33 -10:00
commit 221b46bd02
6 zmienionych plików z 268 dodań i 186 usunięć

Wyświetl plik

@ -8,6 +8,33 @@
* **Notable Fixes:** * **Notable Fixes:**
* made scrollbars in the wardrobe and jukebox more responsive * made scrollbars in the wardrobe and jukebox more responsive
### 2021-05-21
* gui, scenes, store: proxied thumbnail, name and notes in project, restored in XML
* gui: distinguished project name from scene names, removed hidden "export as plain text" option
* gui: sceneified project notes
* gui: adjusted project thumbnail in "save" dialog
* gui: some cleanups
* gui, scenes: sceneified unsaved changes management
* blocks: fixed search-blocks for scenesMenu
### 2021-05-20
* gui: marked projectName to be refactored and sceneified
### 2021-05-19
* gui: disabled scene icon context menu for project scene
* gui: disabled dragging the project scene icon
* gui: made sure the project scene stays in place
* gui: added exporting single scenes
* scenes, store: removed redundant properties "notes" and "thumbnail" from project
* store: removed "thumbnail" property from scene xml
### 2021-05-18
* gui: fixed exporting media only for a single scene
* gui: fixed cloud file format components
* gui: "projectized" cloud file format for a single scene
* gui: fixed cloud file format for multi-scene projects
* gui: ensured unique scene names
### 2021-05-11 ### 2021-05-11
* gui: add multi-scene projects * gui: add multi-scene projects
* gui: adjusted scene album rendering * gui: adjusted scene album rendering

Wyświetl plik

@ -8,11 +8,11 @@
<script src="src/morphic.js?version=2021-04-12"></script> <script src="src/morphic.js?version=2021-04-12"></script>
<script src="src/symbols.js?version=2021-03-03"></script> <script src="src/symbols.js?version=2021-03-03"></script>
<script src="src/widgets.js?version=2021-01-05"></script> <script src="src/widgets.js?version=2021-01-05"></script>
<script src="src/blocks.js?version=2021-04-12"></script> <script src="src/blocks.js?version=2021-05-21"></script>
<script src="src/threads.js?version=2021-04-17"></script> <script src="src/threads.js?version=2021-04-17"></script>
<script src="src/objects.js?version=2021-04-23"></script> <script src="src/objects.js?version=2021-04-23"></script>
<script src="src/scenes.js?version=2021-04-23"></script> <script src="src/scenes.js?version=2021-05-21"></script>
<script src="src/gui.js?version=2021-05-11"></script> <script src="src/gui.js?version=2021-05-21"></script>
<script src="src/paint.js?version=2021-03-17"></script> <script src="src/paint.js?version=2021-03-17"></script>
<script src="src/lists.js?version=2021-03-15"></script> <script src="src/lists.js?version=2021-03-15"></script>
<script src="src/byob.js?version=2021-05-04"></script> <script src="src/byob.js?version=2021-05-04"></script>
@ -21,7 +21,7 @@
<script src="src/video.js?version=2019-06-27"></script> <script src="src/video.js?version=2019-06-27"></script>
<script src="src/maps.js?version=2020-03-25"></script> <script src="src/maps.js?version=2020-03-25"></script>
<script src="src/xml.js?version=2020-04-27"></script> <script src="src/xml.js?version=2020-04-27"></script>
<script src="src/store.js?version=2021-04-23"></script> <script src="src/store.js?version=2021-05-21"></script>
<script src="src/locale.js?version=2021-03-15"></script> <script src="src/locale.js?version=2021-03-15"></script>
<script src="src/cloud.js?version=2021-02-04"></script> <script src="src/cloud.js?version=2021-02-04"></script>
<script src="src/api.js?version=2021-01-25"></script> <script src="src/api.js?version=2021-01-25"></script>

Wyświetl plik

@ -158,7 +158,7 @@ CustomCommandBlockMorph, SymbolMorph, ToggleButtonMorph, DialMorph*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.blocks = '2021-April-12'; modules.blocks = '2021-May-21';
var SyntaxElementMorph; var SyntaxElementMorph;
var BlockMorph; var BlockMorph;
@ -9745,16 +9745,18 @@ InputSlotMorph.prototype.audioMenu = function (searching) {
}; };
InputSlotMorph.prototype.scenesMenu = function (searching) { InputSlotMorph.prototype.scenesMenu = function (searching) {
var scenes = this.parentThatIsA(IDE_Morph).scenes, var dict = {},
dict = {}; scenes;
if (!searching) {
if (!searching && scenes.length() > 1) { scenes = this.parentThatIsA(IDE_Morph).scenes;
if (scenes.length() > 1) {
scenes.itemsArray().forEach(scn => { scenes.itemsArray().forEach(scn => {
if (scn.name) { if (scn.name) {
dict[scn.name] = scn.name; dict[scn.name] = scn.name;
} }
}); });
} }
}
dict['~'] = null; dict['~'] = null;
dict.next = ['next']; dict.next = ['next'];
dict.previous = ['previous']; dict.previous = ['previous'];

Wyświetl plik

@ -68,7 +68,7 @@
/*global modules, Morph, SpriteMorph, SyntaxElementMorph, Color, Cloud, Audio, /*global modules, Morph, SpriteMorph, SyntaxElementMorph, Color, Cloud, Audio,
ListWatcherMorph, TextMorph, newCanvas, useBlurredShadows, Sound, Scene, Note, ListWatcherMorph, TextMorph, newCanvas, useBlurredShadows, Sound, Scene, Note,
StringMorph, Point, MenuMorph, morphicVersion, DialogBoxMorph, normalizeCanvas, StringMorph, Point, MenuMorph, morphicVersion, DialogBoxMorph, BlockEditorMorph,
ToggleButtonMorph, contains, ScrollFrameMorph, StageMorph, PushButtonMorph, sb, ToggleButtonMorph, contains, ScrollFrameMorph, StageMorph, PushButtonMorph, sb,
InputFieldMorph, FrameMorph, Process, nop, SnapSerializer, ListMorph, detect, InputFieldMorph, FrameMorph, Process, nop, SnapSerializer, ListMorph, detect,
AlignmentMorph, TabMorph, Costume, MorphicPreferences,BlockMorph, ToggleMorph, AlignmentMorph, TabMorph, Costume, MorphicPreferences,BlockMorph, ToggleMorph,
@ -79,11 +79,11 @@ CommandBlockMorph, BooleanSlotMorph, RingReporterSlotMorph, ScriptFocusMorph,
BlockLabelPlaceHolderMorph, SpeechBubbleMorph, XML_Element, WatcherMorph, WHITE, BlockLabelPlaceHolderMorph, SpeechBubbleMorph, XML_Element, WatcherMorph, WHITE,
BlockRemovalDialogMorph,TableMorph, isSnapObject, isRetinaEnabled, SliderMorph, BlockRemovalDialogMorph,TableMorph, isSnapObject, isRetinaEnabled, SliderMorph,
disableRetinaSupport, enableRetinaSupport, isRetinaSupported, MediaRecorder, disableRetinaSupport, enableRetinaSupport, isRetinaSupported, MediaRecorder,
Animation, BoxMorph, BlockEditorMorph, BlockDialogMorph, Project, ZERO, BLACK*/ Animation, BoxMorph, BlockDialogMorph, Project, ZERO, BLACK*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.gui = '2021-May-11'; modules.gui = '2021-May-21';
// Declarations // Declarations
@ -248,8 +248,6 @@ IDE_Morph.prototype.init = function (isAutoFill) {
this.globalVariables = this.scene.globalVariables; this.globalVariables = this.scene.globalVariables;
this.currentSprite = this.scene.addDefaultSprite(); this.currentSprite = this.scene.addDefaultSprite();
this.sprites = this.scene.sprites; this.sprites = this.scene.sprites;
this.projectName = this.scene.name;
this.projectNotes = this.scene.notes;
if (this.scene.unifiedPalette) { if (this.scene.unifiedPalette) {
this.currentCategory = 'unified'; this.currentCategory = 'unified';
} else { } else {
@ -283,9 +281,7 @@ IDE_Morph.prototype.init = function (isAutoFill) {
this.filePicker = null; this.filePicker = null;
// incrementally saving projects to the cloud is currently unused // incrementally saving projects to the cloud is currently unused
this.hasChangedMedia = false; this.hasChangedMedia = false; // +++ sceneify, or get of it
this.hasUnsavedEdits = false; // keeping track of when to internally backup
this.isAnimating = true; this.isAnimating = true;
this.paletteWidth = 200; // initially same as logo width this.paletteWidth = 200; // initially same as logo width
@ -1181,7 +1177,7 @@ IDE_Morph.prototype.createControlBar = function () {
}; };
this.controlBar.updateLabel = function () { this.controlBar.updateLabel = function () {
var prefix = myself.hasUnsavedEdits ? '\u270E ' : '', var prefix = myself.hasUnsavedEdits() ? '\u270E ' : '',
suffix = myself.world().isDevMode ? suffix = myself.world().isDevMode ?
' - ' + localize('development mode') : '', ' - ' + localize('development mode') : '',
txt; txt;
@ -1193,7 +1189,7 @@ IDE_Morph.prototype.createControlBar = function () {
return; return;
} }
txt = new StringMorph( txt = new StringMorph(
prefix + (myself.projectName || localize('untitled')) + suffix, prefix + (myself.scene.name || localize('untitled')) + suffix,
14, 14,
'sans-serif', 'sans-serif',
true, true,
@ -1941,17 +1937,17 @@ IDE_Morph.prototype.createCorral = function (keepSceneAlbum) {
this.corral.frame = frame; this.corral.frame = frame;
this.corral.add(frame); this.corral.add(frame);
// scenes ++++ // scenes corral
this.corral.album = keepSceneAlbum ? album this.corral.album = keepSceneAlbum ? album
: new SceneAlbumMorph(this, this.sliderColor); : new SceneAlbumMorph(this, this.sliderColor);
this.corral.album.color = this.frameColor; // this.groupColor; this.corral.album.color = this.frameColor;
this.corral.add(this.corral.album); this.corral.add(this.corral.album);
this.corral.fixLayout = function () { this.corral.fixLayout = function () {
this.stageIcon.setCenter(this.center()); this.stageIcon.setCenter(this.center());
this.stageIcon.setLeft(this.left() + padding); this.stageIcon.setLeft(this.left() + padding);
// scenes +++ // scenes
if (myself.scenes.length() < 2) { if (myself.scenes.length() < 2) {
this.album.hide(); this.album.hide();
} else { } else {
@ -1960,7 +1956,9 @@ IDE_Morph.prototype.createCorral = function (keepSceneAlbum) {
this.album.setLeft(this.left()); this.album.setLeft(this.left());
this.album.setTop(this.stageIcon.bottom() + padding); this.album.setTop(this.stageIcon.bottom() + padding);
this.album.setWidth(this.stageIcon.width() + padding * 2); this.album.setWidth(this.stageIcon.width() + padding * 2);
this.album.setHeight(this.height() - this.stageIcon.height() - padding); // +++ this.album.setHeight(
this.height() - this.stageIcon.height() - padding
);
} }
this.frame.setLeft(this.stageIcon.right() + padding); this.frame.setLeft(this.stageIcon.right() + padding);
@ -2130,10 +2128,40 @@ IDE_Morph.prototype.fixLayout = function (situation) {
} }
}; };
// IDE_Morph project properties
IDE_Morph.prototype.getProjectName = function () {
return this.scenes.at(1).name;
};
IDE_Morph.prototype.setProjectName = function (string) { IDE_Morph.prototype.setProjectName = function (string) {
this.projectName = string.replace(/['"]/g, ''); // filter quotation marks var projectScene = this.scenes.at(1),
this.hasChangedMedia = true; name = this.newSceneName(string, projectScene);
if (name !== projectScene.name) {
projectScene.name = name;
projectScene.stage.version = Date.now();
this.recordUnsavedChanges(); // +++ sceneify this
if (projectScene === this.scene) {
this.controlBar.updateLabel(); this.controlBar.updateLabel();
}
}
return name;
};
IDE_Morph.prototype.getProjectNotes = function () {
return this.scenes.at(1).notes;
};
IDE_Morph.prototype.setProjectNotes = function (string) {
var projectScene = this.scenes.at(1);
if (string !== projectScene.notes) {
projectScene.notes = string;
projectScene.stage.version = Date.now();
this.recordUnsavedChanges(); // +++ sceneify this
if (projectScene === this.scene) {
this.controlBar.updateLabel();
}
}
}; };
// IDE_Morph resizing // IDE_Morph resizing
@ -2783,13 +2811,17 @@ IDE_Morph.prototype.hasLocalStorage = function () {
// IDE_Morph recording unsaved changes // IDE_Morph recording unsaved changes
IDE_Morph.prototype.hasUnsavedEdits = function () {
return this.scenes.itemsArray().some(any => any.hasUnsavedEdits);
};
IDE_Morph.prototype.recordUnsavedChanges = function () { IDE_Morph.prototype.recordUnsavedChanges = function () {
this.hasUnsavedEdits = true; this.scene.hasUnsavedEdits = true;
this.updateChanges(); this.updateChanges();
}; };
IDE_Morph.prototype.recordSavedChanges = function () { IDE_Morph.prototype.recordSavedChanges = function () {
this.hasUnsavedEdits = false; this.scenes.itemsArray().forEach(scene => scene.hasUnsavedEdits = false);
this.updateChanges(); this.updateChanges();
}; };
@ -2813,7 +2845,7 @@ IDE_Morph.prototype.backup = function (callback) {
// Save the current project for the currently logged in user // Save the current project for the currently logged in user
// to localstorage, then perform the given callback, e.g. // to localstorage, then perform the given callback, e.g.
// load a new project. // load a new project.
if (this.hasUnsavedEdits) { if (this.hasUnsavedEdits()) {
this.confirm( this.confirm(
'Replace the current project with a new one?', 'Replace the current project with a new one?',
'Unsaved Changes!', 'Unsaved Changes!',
@ -3229,6 +3261,14 @@ IDE_Morph.prototype.newSpriteName = function (name, ignoredSprite) {
return this.newName(name, all); return this.newName(name, all);
}; };
IDE_Morph.prototype.newSceneName = function (name, ignoredScene) {
var sName = name.replace(/['"]/g, ''), // filter out quotation marks
all = this.scenes.asArray().filter(each =>
each !== ignoredScene
).map(each => each.name);
return this.newName(sName, all);
};
IDE_Morph.prototype.newName = function (name, elements) { IDE_Morph.prototype.newName = function (name, elements) {
var ix = name.indexOf('('), var ix = name.indexOf('('),
stem = (ix < 0) ? name : name.substring(0, ix), stem = (ix < 0) ? name : name.substring(0, ix),
@ -3372,8 +3412,9 @@ IDE_Morph.prototype.cloudMenu = function () {
menu.addItem( menu.addItem(
'export project media only...', 'export project media only...',
() => { () => {
if (this.projectName) { var pn = this.getProjectName();
this.exportProjectMedia(this.projectName); if (pn) {
this.exportProjectMedia(pn);
} else { } else {
this.prompt( this.prompt(
'Export Project As...', 'Export Project As...',
@ -3389,8 +3430,9 @@ IDE_Morph.prototype.cloudMenu = function () {
menu.addItem( menu.addItem(
'export project without media...', 'export project without media...',
() => { () => {
if (this.projectName) { var pn = this.getProjectName();
this.exportProjectNoMedia(this.projectName); if (pn) {
this.exportProjectNoMedia(pn);
} else { } else {
this.prompt( this.prompt(
'Export Project As...', 'Export Project As...',
@ -3406,8 +3448,9 @@ IDE_Morph.prototype.cloudMenu = function () {
menu.addItem( menu.addItem(
'export project as cloud data...', 'export project as cloud data...',
() => { () => {
if (this.projectName) { var pn = this.getProjectName();
this.exportProjectAsCloudData(this.projectName); if (pn) {
this.exportProjectAsCloudData(pn);
} else { } else {
this.prompt( this.prompt(
'Export Project As...', 'Export Project As...',
@ -3984,10 +4027,7 @@ IDE_Morph.prototype.projectMenu = function () {
backup = this.availableBackup(shiftClicked); backup = this.availableBackup(shiftClicked);
menu = new MenuMorph(this); menu = new MenuMorph(this);
if (this.scenes.length() > 1) { menu.addItem('Notes...', 'editNotes');
menu.addItem('Scenes...', 'scenesMenu');
}
menu.addItem('Project notes...', 'editProjectNotes');
menu.addLine(); menu.addLine();
menu.addPair('New', 'createNewProject', '^N'); menu.addPair('New', 'createNewProject', '^N');
menu.addPair('Open...', 'openProjectsBrowser', '^O'); menu.addPair('Open...', 'openProjectsBrowser', '^O');
@ -4015,46 +4055,22 @@ IDE_Morph.prototype.projectMenu = function () {
'importLocalFile', 'importLocalFile',
'file menu import hint' // looks up the actual text in the translator 'file menu import hint' // looks up the actual text in the translator
); );
if (shiftClicked) {
menu.addItem( menu.addItem(
localize( 'Export project...',
'Export project...') + ' ' + localize('(in a new window)'
),
() => { () => {
if (this.projectName) { var pn = this.getProjectName();
this.exportProject(this.projectName, shiftClicked); if (pn) {
this.exportProject(pn);
} else { } else {
this.prompt( this.prompt(
'Export Project As...', 'Export Project As...',
// false - override the shiftClick setting to use XML: name => this.exportProject(name),
name => this.exportProject(name, false),
null, null,
'exportProject' 'exportProject'
); );
} }
}, },
'show project data as XML\nin a new browser window', 'save project data as XML\nto your downloads folder'
new Color(100, 0, 0)
);
}
menu.addItem(
shiftClicked ?
'Export project as plain text...' : 'Export project...',
() => {
if (this.projectName) {
this.exportProject(this.projectName, shiftClicked);
} else {
this.prompt(
'Export Project As...',
name => this.exportProject(name, shiftClicked),
null,
'exportProject'
);
}
},
'save project data as XML\nto your downloads folder',
shiftClicked ? new Color(100, 0, 0) : null
); );
if (this.stage.globalBlocks.length) { if (this.stage.globalBlocks.length) {
@ -4095,12 +4111,12 @@ IDE_Morph.prototype.projectMenu = function () {
); );
} }
// +++
menu.addLine(); menu.addLine();
if (this.scenes.length() > 1) {
menu.addItem('Scenes...', 'scenesMenu');
}
menu.addPair('New scene', 'createNewScene'); menu.addPair('New scene', 'createNewScene');
menu.addPair('Add scene...', 'addScene'); menu.addPair('Add scene...', 'addScene');
// +++
menu.addLine(); menu.addLine();
menu.addItem( menu.addItem(
'Libraries...', 'Libraries...',
@ -4682,10 +4698,10 @@ IDE_Morph.prototype.scenesMenu = function () {
menu.popup(world, pos); menu.popup(world, pos);
}; };
IDE_Morph.prototype.editProjectNotes = function () { IDE_Morph.prototype.editNotes = function () {
var dialog = new DialogBoxMorph().withKey('projectNotes'), var dialog = new DialogBoxMorph().withKey('notes'),
frame = new ScrollFrameMorph(), frame = new ScrollFrameMorph(),
text = new TextMorph(this.projectNotes || ''), text = new TextMorph(this.scene.notes || ''),
size = 250, size = 250,
world = this.world(); world = this.world();
@ -4715,13 +4731,13 @@ IDE_Morph.prototype.editProjectNotes = function () {
dialog.target = this; dialog.target = this;
dialog.action = (note) => { dialog.action = (note) => {
this.projectNotes = note; this.scene.notes = note;
this.recordUnsavedChanges(); this.recordUnsavedChanges(); // +++ sceneify this
}; };
dialog.justDropped = () => text.edit(); dialog.justDropped = () => text.edit();
dialog.labelString = 'Project Notes'; dialog.labelString = 'Notes';
dialog.createLabel(); dialog.createLabel();
dialog.addBody(frame); dialog.addBody(frame);
dialog.addButton('ok', 'OK'); dialog.addButton('ok', 'OK');
@ -4743,7 +4759,7 @@ IDE_Morph.prototype.newProject = function () {
this.openProject(project); this.openProject(project);
}; };
IDE_Morph.prototype.createNewScene = function () { // +++ IDE_Morph.prototype.createNewScene = function () {
var setting = this.isAddingScenes; var setting = this.isAddingScenes;
this.isAddingScenes = true; this.isAddingScenes = true;
this.newProject(); this.newProject();
@ -4753,13 +4769,14 @@ IDE_Morph.prototype.createNewScene = function () { // +++
IDE_Morph.prototype.save = function () { IDE_Morph.prototype.save = function () {
// temporary hack - only allow exporting projects to disk // temporary hack - only allow exporting projects to disk
// when running Snap! locally without a web server // when running Snap! locally without a web server
var pn = this.getProjectName();
if (location.protocol === 'file:') { if (location.protocol === 'file:') {
if (this.projectName) { if (pn) {
this.exportProject(this.projectName, false); this.exportProject(pn);
} else { } else {
this.prompt( this.prompt(
'Export Project As...', 'Export Project As...',
name => this.exportProject(name, false), name => this.exportProject(name),
null, null,
'exportProject' 'exportProject'
); );
@ -4774,11 +4791,11 @@ IDE_Morph.prototype.save = function () {
if (this.cloud.disabled) {this.source = 'disk'; } if (this.cloud.disabled) {this.source = 'disk'; }
if (this.projectName) { if (pn) {
if (this.source === 'disk') { if (this.source === 'disk') {
this.exportProject(this.projectName); this.exportProject(pn);
} else if (this.source === 'cloud') { } else if (this.source === 'cloud') {
this.saveProjectToCloud(this.projectName); this.saveProjectToCloud(pn);
} else { } else {
this.saveProjectsBrowser(); this.saveProjectsBrowser();
} }
@ -4787,22 +4804,17 @@ IDE_Morph.prototype.save = function () {
} }
}; };
IDE_Morph.prototype.exportProject = function (name, plain) { IDE_Morph.prototype.exportProject = function (name) {
// Export project XML, saving a file to disk // Export project XML, saving a file to disk
// newWindow requests displaying the project in a new tab. var menu, str;
var menu, str, dataPrefix;
name = this.scenes.at(1).name; // +++
if (name) { if (name) {
this.setProjectName(name); name = this.setProjectName(name);
dataPrefix = 'data:text/' + plain ? 'plain,' : 'xml,';
try { try {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = this.serializer.serialize( str = this.serializer.serialize(
new Project(this.scenes, this.scene) new Project(this.scenes, this.scene)
); );
this.setURL('#open:' + dataPrefix + encodeURIComponent(str)); this.setURL('#open:data:text/xml,' + encodeURIComponent(str));
this.saveXMLAs(str, name); this.saveXMLAs(str, name);
menu.destroy(); menu.destroy();
this.recordSavedChanges(); this.recordSavedChanges();
@ -4928,7 +4940,7 @@ IDE_Morph.prototype.exportScriptsPicture = function () {
y += padding; y += padding;
y += each.height; y += each.height;
}); });
this.saveCanvasAs(pic, this.projectName || localize('Untitled')); this.saveCanvasAs(pic, this.scene.name || localize('Untitled'));
}; };
IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) { IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
@ -5031,7 +5043,7 @@ IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
} }
} }
pname = this.projectName || localize('untitled'); pname = this.scene.name || localize('untitled');
html = new XML_Element('html'); html = new XML_Element('html');
html.attributes.lang = SnapTranslator.language; html.attributes.lang = SnapTranslator.language;
@ -5092,7 +5104,7 @@ IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
} }
// project notes // project notes
notes = Process.prototype.reportTextSplit(this.projectNotes, 'line'); notes = Process.prototype.reportTextSplit(this.scene.notes, 'line');
notes.asArray().forEach(paragraph => add(paragraph)); notes.asArray().forEach(paragraph => add(paragraph));
// table of contents // table of contents
@ -5212,7 +5224,7 @@ IDE_Morph.prototype.exportProjectSummary = function (useDropShadows) {
IDE_Morph.prototype.openProjectString = function (str, callback) { IDE_Morph.prototype.openProjectString = function (str, callback) {
var msg; var msg;
if (this.bulkDropInProgress || this.isAddingScenes) { // +++ if (this.bulkDropInProgress || this.isAddingScenes) {
this.rawOpenProjectString(str); this.rawOpenProjectString(str);
if (callback) {callback(); } if (callback) {callback(); }
return; return;
@ -5260,7 +5272,7 @@ IDE_Morph.prototype.openCloudDataString = function (str) {
IDE_Morph.prototype.rawOpenCloudDataString = function (str) { IDE_Morph.prototype.rawOpenCloudDataString = function (str) {
var model, var model,
setting = this.isAddingScenes; // +++ setting = this.isAddingScenes;
if (this.isAddingNextScene) { if (this.isAddingNextScene) {
this.isAddingScenes = true; this.isAddingScenes = true;
@ -5484,7 +5496,10 @@ IDE_Morph.prototype.openProjectName = function (name) {
IDE_Morph.prototype.openProject = function (project) { IDE_Morph.prototype.openProject = function (project) {
if (this.isAddingScenes) { if (this.isAddingScenes) {
project.scenes.itemsArray().forEach(scene => this.scenes.add(scene)); project.scenes.itemsArray().forEach(scene => {
scene.name = this.newSceneName(scene.name, scene);
this.scenes.add(scene);
});
} else { } else {
this.scenes = project.scenes; this.scenes = project.scenes;
} }
@ -5503,8 +5518,6 @@ IDE_Morph.prototype.switchToScene = function (scene, refreshAlbum) {
); );
this.scene.captureGlobalSettings(); this.scene.captureGlobalSettings();
this.scene = scene; this.scene = scene;
this.projectName = scene.name;
this.projectNotes = scene.notes || '';
this.globalVariables = scene.globalVariables; this.globalVariables = scene.globalVariables;
this.stage.destroy(); this.stage.destroy();
this.add(scene.stage); this.add(scene.stage);
@ -5521,7 +5534,6 @@ IDE_Morph.prototype.switchToScene = function (scene, refreshAlbum) {
} }
}); });
scene.applyGlobalSettings(); scene.applyGlobalSettings();
this.hasUnsavedEdits = false;
this.world().keyboardFocus = this.stage; this.world().keyboardFocus = this.stage;
}; };
@ -5978,7 +5990,7 @@ IDE_Morph.prototype.createNewProject = function () {
this.backup(() => this.newProject()); this.backup(() => this.newProject());
}; };
IDE_Morph.prototype.addScene = function () { // +++ IDE_Morph.prototype.addScene = function () {
var setting = this.isAddingScenes; var setting = this.isAddingScenes;
if (location.protocol === 'file:') { if (location.protocol === 'file:') {
// bypass the project import dialog and directly pop up // bypass the project import dialog and directly pop up
@ -6013,7 +6025,7 @@ IDE_Morph.prototype.saveProjectsBrowser = function () {
if (location.protocol === 'file:') { if (location.protocol === 'file:') {
this.prompt( this.prompt(
'Export Project As...', 'Export Project As...',
name => this.exportProject(name, false), name => this.exportProject(name),
null, null,
'exportProject' 'exportProject'
); );
@ -6574,22 +6586,23 @@ IDE_Morph.prototype.logout = function () {
); );
}; };
IDE_Morph.prototype.buildProjectRequest = function () { // +++ Oh, sweet Jesus! IDE_Morph.prototype.buildProjectRequest = function () {
var xml = this.serializer.serialize(this.scene), var proj = new Project(this.scenes, this.scene),
thumbnail = normalizeCanvas( body,
this.stage.thumbnail( xml;
SnapSerializer.prototype.thumbnailSize
)).toDataURL(),
body;
this.serializer.isCollectingMedia = true; this.serializer.isCollectingMedia = true;
xml = this.serializer.serialize(proj);
body = { body = {
notes: this.projectNotes, notes: proj.notes,
xml: xml, xml: xml,
media: this.hasChangedMedia ? /*
this.serializer.mediaXML(this.projectName) : null, media: this.hasChangedMedia ? // incremental media upload, disabled
thumbnail: thumbnail, this.serializer.mediaXML(proj.name) : null,
remixID: this.stage.remixID */
media: this.serializer.mediaXML(proj.name),
thumbnail: proj.thumbnail.toDataURL(),
remixID: this.stage.remixID // +++ sceneify remixID
}; };
this.serializer.isCollectingMedia = false; this.serializer.isCollectingMedia = false;
this.serializer.flushMedia(); this.serializer.flushMedia();
@ -6637,7 +6650,7 @@ IDE_Morph.prototype.saveProjectToCloud = function (name) {
var projectBody, projectSize; var projectBody, projectSize;
if (name) { if (name) {
this.setProjectName(name); name = this.setProjectName(name);
} }
this.showMessage('Saving project\nto the cloud...'); this.showMessage('Saving project\nto the cloud...');
@ -6648,7 +6661,7 @@ IDE_Morph.prototype.saveProjectToCloud = function (name) {
'Uploading ' + Math.round(projectSize / 1024) + ' KB...' 'Uploading ' + Math.round(projectSize / 1024) + ' KB...'
); );
this.cloud.saveProject( this.cloud.saveProject(
this.projectName, name,
projectBody, projectBody,
() => { () => {
this.recordSavedChanges(); this.recordSavedChanges();
@ -6665,8 +6678,9 @@ IDE_Morph.prototype.exportProjectMedia = function (name) {
this.setProjectName(name); this.setProjectName(name);
try { try {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
this.serializer.serialize(new Project(this.scenes, this.scene));
media = this.serializer.mediaXML(name); media = this.serializer.mediaXML(name);
this.saveXMLAs(media, this.projectName + ' media'); this.saveXMLAs(media, this.getProjectName() + ' media');
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} catch (err) { } catch (err) {
@ -6683,16 +6697,18 @@ IDE_Morph.prototype.exportProjectMedia = function (name) {
// this.hasChangedMedia = false; // this.hasChangedMedia = false;
}; };
IDE_Morph.prototype.exportProjectNoMedia = function (name) { // +++ Sigh... IDE_Morph.prototype.exportProjectNoMedia = function (name) {
var menu, str; var menu, str;
this.serializer.isCollectingMedia = true; this.serializer.isCollectingMedia = true;
if (name) { if (name) {
this.setProjectName(name); name = this.setProjectName(name);
if (Process.prototype.isCatchingErrors) { if (Process.prototype.isCatchingErrors) {
try { try {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = this.serializer.serialize(this.scene); str = this.serializer.serialize(
this.saveXMLAs(str, this.projectName); new Project(this.scenes, this.scene)
);
this.saveXMLAs(str, name);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} catch (err) { } catch (err) {
@ -6701,8 +6717,10 @@ IDE_Morph.prototype.exportProjectNoMedia = function (name) { // +++ Sigh...
} }
} else { } else {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = this.serializer.serialize(this.scene); str = this.serializer.serialize(
this.saveXMLAs(str, this.projectName); new Project(this.scenes, this.scene)
);
this.saveXMLAs(str, name);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} }
@ -6711,18 +6729,20 @@ IDE_Morph.prototype.exportProjectNoMedia = function (name) { // +++ Sigh...
this.serializer.flushMedia(); this.serializer.flushMedia();
}; };
IDE_Morph.prototype.exportProjectAsCloudData = function (name) { // +++ revisit IDE_Morph.prototype.exportProjectAsCloudData = function (name) {
var menu, str, media, dta; var menu, str, media, dta;
this.serializer.isCollectingMedia = true; this.serializer.isCollectingMedia = true;
if (name) { if (name) {
this.setProjectName(name); name = this.setProjectName(name);
if (Process.prototype.isCatchingErrors) { if (Process.prototype.isCatchingErrors) {
try { try {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = this.serializer.serialize(this.scene); str = this.serializer.serialize(
new Project(this.scenes, this.scene)
);
media = this.serializer.mediaXML(name); media = this.serializer.mediaXML(name);
dta = '<snapdata>' + str + media + '</snapdata>'; dta = '<snapdata>' + str + media + '</snapdata>';
this.saveXMLAs(str, this.projectName); this.saveXMLAs(dta, name);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} catch (err) { } catch (err) {
@ -6731,10 +6751,12 @@ IDE_Morph.prototype.exportProjectAsCloudData = function (name) { // +++ revisit
} }
} else { } else {
menu = this.showMessage('Exporting'); menu = this.showMessage('Exporting');
str = this.serializer.serialize(this.scene); str = this.serializer.serialize(
new Project(this.scenes, this.scene)
);
media = this.serializer.mediaXML(name); media = this.serializer.mediaXML(name);
dta = '<snapdata>' + str + media + '</snapdata>'; dta = '<snapdata>' + str + media + '</snapdata>';
this.saveXMLAs(str, this.projectName); this.saveXMLAs(str, name);
menu.destroy(); menu.destroy();
this.showMessage('Exported!', 1); this.showMessage('Exported!', 1);
} }
@ -7097,7 +7119,7 @@ ProjectDialogMorph.prototype.buildContents = function () {
this.body.add(this.srcBar); this.body.add(this.srcBar);
if (this.task === 'save') { if (this.task === 'save') {
this.nameField = new InputFieldMorph(this.ide.projectName); this.nameField = new InputFieldMorph(this.ide.getProjectName());
this.body.add(this.nameField); this.body.add(this.nameField);
} }
@ -7137,7 +7159,7 @@ ProjectDialogMorph.prototype.buildContents = function () {
this.body.add(this.preview); this.body.add(this.preview);
if (this.task === 'save') { if (this.task === 'save') {
thumbnail = this.ide.stage.thumbnail( thumbnail = this.ide.scenes.at(1).stage.thumbnail(
SnapSerializer.prototype.thumbnailSize SnapSerializer.prototype.thumbnailSize
); );
this.preview.texture = null; this.preview.texture = null;
@ -7161,7 +7183,7 @@ ProjectDialogMorph.prototype.buildContents = function () {
if (this.task === 'open' || this.task === 'add') { if (this.task === 'open' || this.task === 'add') {
this.notesText = new TextMorph(''); this.notesText = new TextMorph('');
} else { // 'save' } else { // 'save'
this.notesText = new TextMorph(this.ide.projectNotes); this.notesText = new TextMorph(this.ide.getProjectNotes());
this.notesText.isEditable = true; this.notesText.isEditable = true;
this.notesText.enableSelecting(); this.notesText.enableSelecting();
} }
@ -7698,7 +7720,7 @@ ProjectDialogMorph.prototype.recoveryDialog = function () {
new ProjectRecoveryDialogMorph(this.ide, proj.projectname, this).popUp(); new ProjectRecoveryDialogMorph(this.ide, proj.projectname, this).popUp();
}; };
ProjectDialogMorph.prototype.addScene = function () { // +++ ProjectDialogMorph.prototype.addScene = function () {
var proj = this.listField.selected, var proj = this.listField.selected,
src; src;
if (!proj) {return; } if (!proj) {return; }
@ -7784,8 +7806,8 @@ ProjectDialogMorph.prototype.saveProject = function () {
var name = this.nameField.contents().text.text, var name = this.nameField.contents().text.text,
notes = this.notesText.text; notes = this.notesText.text;
if (this.ide.projectNotes !== notes) { if (this.ide.getProjectNotes() !== notes) {
this.ide.projectNotes = notes; this.ide.setProjectNotes(notes);
} }
if (name) { if (name) {
if (this.source === 'cloud') { if (this.source === 'cloud') {
@ -7808,7 +7830,7 @@ ProjectDialogMorph.prototype.saveProject = function () {
this.saveCloudProject(); this.saveCloudProject();
} }
} else if (this.source === 'disk') { } else if (this.source === 'disk') {
this.ide.exportProject(name, false); this.ide.exportProject(name);
this.ide.source = 'disk'; this.ide.source = 'disk';
this.destroy(); this.destroy();
} }
@ -7895,7 +7917,7 @@ ProjectDialogMorph.prototype.shareProject = function () {
this.ide.showMessage('shared.', 2); this.ide.showMessage('shared.', 2);
// Set the Shared URL if the project is currently open // Set the Shared URL if the project is currently open
if (proj.projectname === ide.projectName) { if (proj.projectname === ide.getProjectName()) {
var usr = ide.cloud.username, var usr = ide.cloud.username,
projectId = 'Username=' + projectId = 'Username=' +
encodeURIComponent(usr.toLowerCase()) + encodeURIComponent(usr.toLowerCase()) +
@ -7939,7 +7961,7 @@ ProjectDialogMorph.prototype.unshareProject = function () {
this.buttons.fixLayout(); this.buttons.fixLayout();
this.rerender(); this.rerender();
this.ide.showMessage('unshared.', 2); this.ide.showMessage('unshared.', 2);
if (proj.projectname === ide.projectName) { if (proj.projectname === ide.getProjectName()) {
location.hash = ''; location.hash = '';
} }
}, },
@ -7979,7 +8001,7 @@ ProjectDialogMorph.prototype.publishProject = function () {
this.ide.showMessage('published.', 2); this.ide.showMessage('published.', 2);
// Set the Shared URL if the project is currently open // Set the Shared URL if the project is currently open
if (proj.projectname === ide.projectName) { if (proj.projectname === ide.getProjectName()) {
var usr = ide.cloud.username, var usr = ide.cloud.username,
projectId = 'Username=' + projectId = 'Username=' +
encodeURIComponent(usr.toLowerCase()) + encodeURIComponent(usr.toLowerCase()) +
@ -10253,7 +10275,7 @@ SceneIconMorph.uber = ToggleButtonMorph.prototype;
// SceneIconMorph settings // SceneIconMorph settings
SceneIconMorph.prototype.thumbSize = new Point(40, 30); // +++ (40, 40), (80, 60); SceneIconMorph.prototype.thumbSize = new Point(40, 30);
SceneIconMorph.prototype.labelShadowOffset = null; SceneIconMorph.prototype.labelShadowOffset = null;
SceneIconMorph.prototype.labelShadowColor = null; SceneIconMorph.prototype.labelShadowColor = null;
SceneIconMorph.prototype.labelColor = WHITE; SceneIconMorph.prototype.labelColor = WHITE;
@ -10302,7 +10324,7 @@ SceneIconMorph.prototype.init = function (aScene) {
colors, // color overrides, <array>: [normal, highlight, pressed] colors, // color overrides, <array>: [normal, highlight, pressed]
null, // target - not needed here null, // target - not needed here
action, // a toggle function action, // a toggle function
this.object.name || localize('untitled'), // label string // +++ this.object.name || localize('untitled'), // label string
query, // predicate/selector query, // predicate/selector
null, // environment null, // environment
null // hint null // hint
@ -10332,12 +10354,7 @@ SceneIconMorph.prototype.createThumbnail = function () {
this.add(this.thumbnail); this.add(this.thumbnail);
}; };
/* +++ SceneIconMorph.prototype.createLabel = function () {
SceneIconMorph.prototype.createLabel
= SpriteIconMorph.prototype.createLabel;
*/
SceneIconMorph.prototype.createLabel = function () { // +++
var txt; var txt;
if (this.label) { if (this.label) {
@ -10384,31 +10401,34 @@ SceneIconMorph.prototype.fixLayout
// SceneIconMorph menu // SceneIconMorph menu
SceneIconMorph.prototype.userMenu = function () { SceneIconMorph.prototype.userMenu = function () {
var menu = new MenuMorph(this), var menu = new MenuMorph(this);
ide = this.parentThatIsA(IDE_Morph); if (!(this.object instanceof Scene)) {
if (!(this.object instanceof Scene)) {return null; } return null;
}
if (!this.isProjectScene()) {
menu.addItem("rename", "renameScene"); menu.addItem("rename", "renameScene");
if (ide.scenes.length() > 1) {
menu.addItem("delete", "removeScene"); menu.addItem("delete", "removeScene");
} }
// menu.addItem("export", "exportScene"); menu.addItem("export", "exportScene");
return menu; return menu;
}; };
SceneIconMorph.prototype.renameScene = function () { SceneIconMorph.prototype.renameScene = function () {
var scene = this.object, var scene = this.object,
album = this.parentThatIsA(SceneAlbumMorph),
ide = this.parentThatIsA(IDE_Morph); ide = this.parentThatIsA(IDE_Morph);
new DialogBoxMorph( new DialogBoxMorph(
null, null,
answer => { answer => {
if (answer && (answer !== scene.name)) { if (answer && (answer !== scene.name)) {
scene.name = album.scene.newSceneName( scene.name = ide.newSceneName(
answer, answer,
scene scene
); );
scene.stage.version = Date.now(); // +++ also do this in other places scene.stage.version = Date.now(); // +++ also do this in other places
ide.recordUnsavedChanges(); if (scene === ide.scene) {
ide.controlBar.updateLabel();
}
ide.recordUnsavedChanges(); // ++++ sceneify unsaved changes
} }
} }
).prompt( ).prompt(
@ -10430,9 +10450,35 @@ SceneIconMorph.prototype.removeScene = function () {
}; };
SceneIconMorph.prototype.exportScene = function () { SceneIconMorph.prototype.exportScene = function () {
// under construction // Export scene as project XML, saving a file to disk
var ide = this.parentThatIsA(IDE_Morph); var menu, str,
ide.saveFileAs(this.object.contents.src, 'text/svg', this.object.name); ide = this.parentThatIsA(IDE_Morph),
name = this.object.name || localize('untitled');
try {
menu = ide.showMessage('Exporting');
str = ide.serializer.serialize(
new Project(new List([this.object]), this.object)
);
ide.saveXMLAs(str, name);
menu.destroy();
ide.showMessage('Exported!', 1);
} catch (err) {
if (Process.prototype.isCatchingErrors) {
ide.showMessage('Export failed: ' + err);
} else {
throw err;
}
}
};
// SceneIconMorph ops
SceneIconMorph.prototype.isProjectScene = function (anIDE) {
// the first scene of a project cannot be renamed, deleted or rearranged,
// because its name and project notes are those of the project
var ide = anIDE || this.parentThatIsA(IDE_Morph);
return ide.scenes.indexOf(this.object) === 1;
}; };
// SceneIconMorph drawing // SceneIconMorph drawing
@ -10443,8 +10489,6 @@ SceneIconMorph.prototype.render
// SceneIconMorph drag & drop // SceneIconMorph drag & drop
SceneIconMorph.prototype.rootForGrab = function () { SceneIconMorph.prototype.rootForGrab = function () {
// +++ to do: make sure scene icons can only be grabbed if there are
// more than 1
return this; return this;
}; };
@ -10503,8 +10547,11 @@ SceneAlbumMorph.prototype.updateList = function () {
}; };
this.addBack(this.contents); this.addBack(this.contents);
this.ide.scenes.asArray().forEach(scene => { this.ide.scenes.asArray().forEach((scene, i) => {
icon = new SceneIconMorph(scene); icon = new SceneIconMorph(scene);
if (i < 1) {
icon.isDraggable = false; // project scene cannot be rearranged
}
icon.setPosition(new Point(x, y)); icon.setPosition(new Point(x, y));
this.addContents(icon); this.addContents(icon);
y = icon.bottom() + padding; y = icon.bottom() + padding;
@ -10561,6 +10608,7 @@ SceneAlbumMorph.prototype.reactToDropOf = function (icon) {
idx += 1; idx += 1;
} }
}); });
idx = Math.max(idx, 1); // the project scene cannot the rearranged
this.ide.scenes.add(scene, idx + 1); this.ide.scenes.add(scene, idx + 1);
this.updateList(); this.updateList();
icon.mouseClickLeft(); // select icon.mouseClickLeft(); // select

Wyświetl plik

@ -48,9 +48,10 @@
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
/*global modules, VariableFrame, StageMorph, SpriteMorph, Process, List*/ /*global modules, VariableFrame, StageMorph, SpriteMorph, Process, List,
normalizeCanvas, SnapSerializer*/
modules.scenes = '2021-April-23'; modules.scenes = '2021-May-21';
// Projecct ///////////////////////////////////////////////////////// // Projecct /////////////////////////////////////////////////////////
@ -61,12 +62,25 @@ modules.scenes = '2021-April-23';
// Project instance creation: // Project instance creation:
function Project(scenes, current) { function Project(scenes, current) {
this.name = 'Test'; var projectScene;
this.notes = 'some notes';
this.thumbnail = null;
this.scenes = scenes || new List(); this.scenes = scenes || new List();
this.currentScene = current; this.currentScene = current;
// proxied for display
this.name = null;
this.notes = null;
this.thumbnail = null;
projectScene = this.scenes.at(1);
if (projectScene) {
this.name = projectScene.name;
this.notes = projectScene.notes;
this.thumbnail = normalizeCanvas(
projectScene.stage.thumbnail(SnapSerializer.prototype.thumbnailSize)
);
}
// for deserializing - do not persist // for deserializing - do not persist
this.sceneIdx = null; this.sceneIdx = null;
@ -102,6 +116,7 @@ function Scene(aStageMorph) {
this.globalVariables = aStageMorph ? this.globalVariables = aStageMorph ?
aStageMorph.globalVariables() : new VariableFrame(); aStageMorph.globalVariables() : new VariableFrame();
this.stage = aStageMorph || new StageMorph(this.globalVariables); this.stage = aStageMorph || new StageMorph(this.globalVariables);
this.hasUnsavedEdits = false;
// cached IDE state // cached IDE state
this.sprites = new List(); this.sprites = new List();

Wyświetl plik

@ -61,7 +61,7 @@ Project*/
// Global stuff //////////////////////////////////////////////////////// // Global stuff ////////////////////////////////////////////////////////
modules.store = '2021-April-23'; modules.store = '2021-May-21';
// XML_Serializer /////////////////////////////////////////////////////// // XML_Serializer ///////////////////////////////////////////////////////
@ -1672,7 +1672,6 @@ Project.prototype.toXML = function (serializer) {
Scene.prototype.toXML = function (serializer) { Scene.prototype.toXML = function (serializer) {
var tmp = new Scene(), var tmp = new Scene(),
thumbdata,
xml; xml;
function code(key) { function code(key) {
@ -1691,19 +1690,11 @@ Scene.prototype.toXML = function (serializer) {
return str; return str;
} }
// catch cross-origin tainting exception when using SVG costumes
try {
thumbdata = this.thumbnail.toDataURL('image/png');
} catch (error) {
thumbdata = null;
}
tmp.captureGlobalSettings(); tmp.captureGlobalSettings();
this.applyGlobalSettings(); this.applyGlobalSettings();
xml = serializer.format( xml = serializer.format(
'<scene name="@">' + '<scene name="@">' +
'<notes>$</notes>' + '<notes>$</notes>' +
'<thumbnail>$</thumbnail>' +
'<hidden>$</hidden>' + '<hidden>$</hidden>' +
'<headers>%</headers>' + '<headers>%</headers>' +
'<code>%</code>' + '<code>%</code>' +
@ -1713,7 +1704,6 @@ Scene.prototype.toXML = function (serializer) {
'</scene>', '</scene>',
this.name || localize('Untitled'), this.name || localize('Untitled'),
this.notes || '', this.notes || '',
thumbdata,
Object.keys(StageMorph.prototype.hiddenPrimitives).reduce( Object.keys(StageMorph.prototype.hiddenPrimitives).reduce(
(a, b) => a + ' ' + b, (a, b) => a + ' ' + b,
'' ''