kopia lustrzana https://github.com/backface/turtlestitch
				
				
				
			
		
			
				
	
	
		
			453 wiersze
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
			
		
		
	
	
			453 wiersze
		
	
	
		
			15 KiB
		
	
	
	
		
			JavaScript
		
	
	
SnapSerializer.prototype.app = 'TurtleStitch 2.5, http://www.turtlestitch.org';
 | 
						|
SnapSerializer.prototype.thumbnailSize = new Point(480, 360);
 | 
						|
 | 
						|
SnapSerializer.prototype.openProject = function (project, ide) {
 | 
						|
    var stage = ide.stage,
 | 
						|
        sprites = [],
 | 
						|
        sprite;
 | 
						|
    if (!project || !project.stage) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    ide.projectName = project.name;
 | 
						|
    ide.projectNotes = project.notes || '';
 | 
						|
    ide.origName = project.origName || '';
 | 
						|
    ide.origCreator = project.origCreator || '';
 | 
						|
    ide.creator = project.creator || '';
 | 
						|
    ide.remixHistory = project.remixHistorycreat || '';
 | 
						|
    //console.log("name: " + ide.projectName + ", creator: " + ide.creator + ", origName: " + ide.origName + ", origCreator: " + ide.origCreator);    
 | 
						|
    if (ide.globalVariables) {
 | 
						|
        ide.globalVariables = project.globalVariables;
 | 
						|
    }
 | 
						|
    if (stage) {
 | 
						|
        stage.destroy();
 | 
						|
    }
 | 
						|
    ide.add(project.stage);
 | 
						|
    ide.stage = project.stage;
 | 
						|
    sprites = ide.stage.children.filter(function (child) {
 | 
						|
        return child instanceof SpriteMorph;
 | 
						|
    });
 | 
						|
    sprites.sort(function (x, y) {
 | 
						|
        return x.idx - y.idx;
 | 
						|
    });
 | 
						|
 | 
						|
    ide.sprites = new List(sprites);
 | 
						|
    sprite = sprites[0] || project.stage;
 | 
						|
 | 
						|
    if (sizeOf(this.mediaDict) > 0) {
 | 
						|
        ide.hasChangedMedia = false;
 | 
						|
        this.mediaDict = {};
 | 
						|
    } else {
 | 
						|
        ide.hasChangedMedia = true;
 | 
						|
    }
 | 
						|
    project.stage.drawNew();
 | 
						|
    ide.createCorral();
 | 
						|
    ide.selectSprite(sprite);
 | 
						|
    ide.fixLayout();
 | 
						|
 | 
						|
    // force watchers to update
 | 
						|
    //project.stage.watchers().forEach(function (watcher) {
 | 
						|
    //  watcher.onNextStep = function () {this.currentValue = null;};
 | 
						|
    //})
 | 
						|
 | 
						|
    ide.world().keyboardReceiver = project.stage;
 | 
						|
    ide.stage.initCamera();
 | 
						|
};
 | 
						|
 | 
						|
SnapSerializer.prototype.rawLoadProjectModel = function (xmlNode) {
 | 
						|
    // private
 | 
						|
    var myself = this,
 | 
						|
        project = {sprites: {}},
 | 
						|
        model,
 | 
						|
        nameID;
 | 
						|
 | 
						|
    this.project = project;
 | 
						|
 | 
						|
    model = {project: xmlNode };
 | 
						|
    if (+xmlNode.attributes.version > this.version) {
 | 
						|
        throw 'Project uses newer version of Serializer';
 | 
						|
    }
 | 
						|
 | 
						|
    /* Project Info */
 | 
						|
 | 
						|
    this.objects = {};
 | 
						|
    project.name = model.project.attributes.name;
 | 
						|
    project.origName = model.project.childNamed('origName') ? model.project.childNamed('origName').contents : ""
 | 
						|
    project.creator =  model.project.childNamed('creator') ? model.project.childNamed('creator').contents : ""
 | 
						|
    project.origCreator =  model.project.childNamed('origCreator') ? model.project.childNamed('origCreator').contents : ""
 | 
						|
    project.remixHistory =  model.project.childNamed('origCreator') ? model.project.childNamed('origCreator').contents : ""
 | 
						|
 | 
						|
    if (!project.name) {
 | 
						|
        nameID = 1;
 | 
						|
        while (
 | 
						|
            Object.prototype.hasOwnProperty.call(
 | 
						|
                localStorage,
 | 
						|
                '-snap-project-Untitled ' + nameID
 | 
						|
            )
 | 
						|
        ) {
 | 
						|
            nameID += 1;
 | 
						|
        }
 | 
						|
        project.name = 'Untitled ' + nameID;
 | 
						|
    }
 | 
						|
    model.notes = model.project.childNamed('notes');
 | 
						|
    if (model.notes) {
 | 
						|
        project.notes = model.notes.contents;
 | 
						|
    }
 | 
						|
    model.globalVariables = model.project.childNamed('variables');
 | 
						|
    project.globalVariables = new VariableFrame();
 | 
						|
 | 
						|
    /* Stage */
 | 
						|
 | 
						|
    model.stage = model.project.require('stage');
 | 
						|
    StageMorph.prototype.frameRate = 0;
 | 
						|
    project.stage = new StageMorph(project.globalVariables);
 | 
						|
    if (Object.prototype.hasOwnProperty.call(
 | 
						|
            model.stage.attributes,
 | 
						|
            'id'
 | 
						|
        )) {
 | 
						|
        this.objects[model.stage.attributes.id] = project.stage;
 | 
						|
    }
 | 
						|
    if (model.stage.attributes.name) {
 | 
						|
        project.stage.name = model.stage.attributes.name;
 | 
						|
    }
 | 
						|
    if (model.stage.attributes.scheduled === 'true') {
 | 
						|
        project.stage.fps = 30;
 | 
						|
        StageMorph.prototype.frameRate = 30;
 | 
						|
    }
 | 
						|
    model.pentrails = model.stage.childNamed('pentrails');
 | 
						|
    if (model.pentrails) {
 | 
						|
        project.pentrails = new Image();
 | 
						|
        project.pentrails.onload = function () {
 | 
						|
            if (project.stage.trailsCanvas) { // work-around a bug in FF
 | 
						|
                normalizeCanvas(project.stage.trailsCanvas);
 | 
						|
                var context = project.stage.trailsCanvas.getContext('2d');
 | 
						|
                if (context) context.drawImage(project.pentrails, 0, 0);
 | 
						|
                project.stage.changed();
 | 
						|
            }
 | 
						|
        };
 | 
						|
        project.pentrails.src = model.pentrails.contents;
 | 
						|
    }
 | 
						|
    project.stage.setTempo(model.stage.attributes.tempo);
 | 
						|
    StageMorph.prototype.dimensions = new Point(480, 360);
 | 
						|
    if (model.stage.attributes.width) {
 | 
						|
        StageMorph.prototype.dimensions.x =
 | 
						|
            Math.max(+model.stage.attributes.width, 480);
 | 
						|
    }
 | 
						|
    if (model.stage.attributes.height) {
 | 
						|
        StageMorph.prototype.dimensions.y =
 | 
						|
            Math.max(+model.stage.attributes.height, 180);
 | 
						|
    }
 | 
						|
    project.stage.setExtent(StageMorph.prototype.dimensions);
 | 
						|
    SpriteMorph.prototype.useFlatLineEnds =
 | 
						|
        model.stage.attributes.lines === 'flat';
 | 
						|
    BooleanSlotMorph.prototype.isTernary =
 | 
						|
        model.stage.attributes.ternary !== 'false';
 | 
						|
    project.stage.isThreadSafe =
 | 
						|
        model.stage.attributes.threadsafe === 'true';
 | 
						|
    StageMorph.prototype.enableCodeMapping =
 | 
						|
        model.stage.attributes.codify === 'true';
 | 
						|
    StageMorph.prototype.enableInheritance =
 | 
						|
        model.stage.attributes.inheritance !== 'false';
 | 
						|
    StageMorph.prototype.enableSublistIDs =
 | 
						|
        model.stage.attributes.sublistIDs === 'true';
 | 
						|
 | 
						|
    model.hiddenPrimitives = model.project.childNamed('hidden');
 | 
						|
    if (model.hiddenPrimitives) {
 | 
						|
        model.hiddenPrimitives.contents.split(' ').forEach(
 | 
						|
            function (sel) {
 | 
						|
                if (sel) {
 | 
						|
                    StageMorph.prototype.hiddenPrimitives[sel] = true;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    model.codeHeaders = model.project.childNamed('headers');
 | 
						|
    if (model.codeHeaders) {
 | 
						|
        model.codeHeaders.children.forEach(function (xml) {
 | 
						|
            StageMorph.prototype.codeHeaders[xml.tag] = xml.contents;
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    model.codeMappings = model.project.childNamed('code');
 | 
						|
    if (model.codeMappings) {
 | 
						|
        model.codeMappings.children.forEach(function (xml) {
 | 
						|
            StageMorph.prototype.codeMappings[xml.tag] = xml.contents;
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    model.globalBlocks = model.project.childNamed('blocks');
 | 
						|
    if (model.globalBlocks) {
 | 
						|
        this.loadCustomBlocks(project.stage, model.globalBlocks, true);
 | 
						|
        this.populateCustomBlocks(
 | 
						|
            project.stage,
 | 
						|
            model.globalBlocks,
 | 
						|
            true
 | 
						|
        );
 | 
						|
    }
 | 
						|
    this.loadObject(project.stage, model.stage);
 | 
						|
 | 
						|
    /* Sprites */
 | 
						|
 | 
						|
    model.sprites = model.stage.require('sprites');
 | 
						|
    project.sprites[project.stage.name] = project.stage;
 | 
						|
 | 
						|
    model.sprites.childrenNamed('sprite').forEach(function (model) {
 | 
						|
        myself.loadValue(model);
 | 
						|
    });
 | 
						|
 | 
						|
    // restore inheritance and nesting associations
 | 
						|
    myself.project.stage.children.forEach(function (sprite) {
 | 
						|
        var exemplar, anchor;
 | 
						|
        if (sprite.inheritanceInfo) { // only sprites can inherit
 | 
						|
            exemplar = myself.project.sprites[
 | 
						|
                sprite.inheritanceInfo.exemplar
 | 
						|
            ];
 | 
						|
            if (exemplar) {
 | 
						|
                sprite.setExemplar(exemplar);
 | 
						|
            }
 | 
						|
            sprite.inheritedAttributes = sprite.inheritanceInfo.delegated || [];
 | 
						|
        }
 | 
						|
        if (sprite.nestingInfo) { // only sprites may have nesting info
 | 
						|
            anchor = myself.project.sprites[sprite.nestingInfo.anchor];
 | 
						|
            if (anchor) {
 | 
						|
                anchor.attachPart(sprite);
 | 
						|
            }
 | 
						|
            sprite.rotatesWithAnchor = (sprite.nestingInfo.synch === 'true');
 | 
						|
        }
 | 
						|
    });
 | 
						|
    myself.project.stage.children.forEach(function (sprite) {
 | 
						|
        var costume;
 | 
						|
        if (sprite.nestingInfo) { // only sprites may have nesting info
 | 
						|
            sprite.nestingScale = +(sprite.nestingInfo.scale || sprite.scale);
 | 
						|
            delete sprite.nestingInfo;
 | 
						|
        }
 | 
						|
        ['scripts', 'costumes', 'sounds'].forEach(function (att) {
 | 
						|
            if (sprite.inheritsAttribute(att)) {
 | 
						|
                sprite.refreshInheritedAttribute(att);
 | 
						|
            }
 | 
						|
        });
 | 
						|
        if (sprite.inheritsAttribute('costumes')) {
 | 
						|
            costume = sprite.costumes.asArray()[
 | 
						|
                sprite.inheritanceInfo.costumeNumber - 1
 | 
						|
            ];
 | 
						|
            if (costume) {
 | 
						|
                if (costume.loaded) {
 | 
						|
                    sprite.wearCostume(costume, true);
 | 
						|
                } else {
 | 
						|
                    costume.loaded = function () {
 | 
						|
                        sprite.wearCostume(costume, true);
 | 
						|
                        this.loaded = true;
 | 
						|
                    };
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        delete sprite.inheritanceInfo;
 | 
						|
    });
 | 
						|
 | 
						|
    /* Global Variables */
 | 
						|
 | 
						|
    if (model.globalVariables) {
 | 
						|
        this.loadVariables(
 | 
						|
            project.globalVariables,
 | 
						|
            model.globalVariables
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    this.objects = {};
 | 
						|
 | 
						|
    /* Watchers */
 | 
						|
 | 
						|
    model.sprites.childrenNamed('watcher').forEach(function (model) {
 | 
						|
        var watcher, color, target, hidden, extX, extY;
 | 
						|
 | 
						|
        color = myself.loadColor(model.attributes.color);
 | 
						|
        target = Object.prototype.hasOwnProperty.call(
 | 
						|
            model.attributes,
 | 
						|
            'scope'
 | 
						|
        ) ? project.sprites[model.attributes.scope] : null;
 | 
						|
 | 
						|
        // determine whether the watcher is hidden, slightly
 | 
						|
        // complicated to retain backward compatibility
 | 
						|
        // with former tag format: hidden="hidden"
 | 
						|
        // now it's: hidden="true"
 | 
						|
        hidden = Object.prototype.hasOwnProperty.call(
 | 
						|
            model.attributes,
 | 
						|
            'hidden'
 | 
						|
        ) && (model.attributes.hidden !== 'false');
 | 
						|
 | 
						|
        if (Object.prototype.hasOwnProperty.call(
 | 
						|
                model.attributes,
 | 
						|
                'var'
 | 
						|
            )) {
 | 
						|
            watcher = new WatcherMorph(
 | 
						|
                model.attributes['var'],
 | 
						|
                color,
 | 
						|
                isNil(target) ? project.globalVariables
 | 
						|
                    : target.variables,
 | 
						|
                model.attributes['var'],
 | 
						|
                hidden
 | 
						|
            );
 | 
						|
        } else {
 | 
						|
            watcher = new WatcherMorph(
 | 
						|
                localize(myself.watcherLabels[model.attributes.s]),
 | 
						|
                color,
 | 
						|
                target,
 | 
						|
                model.attributes.s,
 | 
						|
                hidden
 | 
						|
            );
 | 
						|
        }
 | 
						|
        watcher.setStyle(model.attributes.style || 'normal');
 | 
						|
        if (watcher.style === 'slider') {
 | 
						|
            watcher.setSliderMin(model.attributes.min || '1', true);
 | 
						|
            watcher.setSliderMax(model.attributes.max || '100', true);
 | 
						|
        }
 | 
						|
        watcher.setPosition(
 | 
						|
            project.stage.topLeft().add(new Point(
 | 
						|
                +model.attributes.x || 0,
 | 
						|
                +model.attributes.y || 0
 | 
						|
            ))
 | 
						|
        );
 | 
						|
        project.stage.add(watcher);
 | 
						|
        watcher.onNextStep = function () {this.currentValue = null; };
 | 
						|
 | 
						|
        // set watcher's contentsMorph's extent if it is showing a list and
 | 
						|
        // its monitor dimensions are given
 | 
						|
        if (watcher.currentValue instanceof List) {
 | 
						|
            extX = model.attributes.extX;
 | 
						|
            if (extX) {
 | 
						|
                watcher.cellMorph.contentsMorph.setWidth(+extX);
 | 
						|
            }
 | 
						|
            extY = model.attributes.extY;
 | 
						|
            if (extY) {
 | 
						|
                watcher.cellMorph.contentsMorph.setHeight(+extY);
 | 
						|
            }
 | 
						|
            // adjust my contentsMorph's handle position
 | 
						|
            watcher.cellMorph.contentsMorph.handle.drawNew();
 | 
						|
        }
 | 
						|
    });
 | 
						|
 | 
						|
    // clear sprites' inherited methods caches, if any
 | 
						|
    myself.project.stage.children.forEach(function (sprite) {
 | 
						|
        sprite.inheritedMethodsCache = [];
 | 
						|
    });
 | 
						|
 | 
						|
    this.objects = {};
 | 
						|
    return project;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
StageMorph.prototype.toXML = function (serializer) {
 | 
						|
    var thumbnail = normalizeCanvas(
 | 
						|
            this.thumbnail(SnapSerializer.prototype.thumbnailSize),
 | 
						|
            true
 | 
						|
        ),
 | 
						|
        thumbdata,
 | 
						|
        ide = this.parentThatIsA(IDE_Morph);
 | 
						|
 | 
						|
    // catch cross-origin tainting exception when using SVG costumes
 | 
						|
    try {
 | 
						|
        thumbdata = thumbnail.toDataURL('image/png');
 | 
						|
    } catch (error) {
 | 
						|
        thumbdata = null;
 | 
						|
    }
 | 
						|
 | 
						|
    function code(key) {
 | 
						|
        var str = '';
 | 
						|
        Object.keys(StageMorph.prototype[key]).forEach(
 | 
						|
            function (selector) {
 | 
						|
                str += (
 | 
						|
                    '<' + selector + '>' +
 | 
						|
                        XML_Element.prototype.escape(
 | 
						|
                            StageMorph.prototype[key][selector]
 | 
						|
                        ) +
 | 
						|
                        '</' + selector + '>'
 | 
						|
                );
 | 
						|
            }
 | 
						|
        );
 | 
						|
        return str;
 | 
						|
    }
 | 
						|
 | 
						|
    this.removeAllClones();
 | 
						|
    return serializer.format(
 | 
						|
        '<project name="@" app="@" version="@">\n' +
 | 
						|
            '<notes>$</notes>\n' +
 | 
						|
            '<creator>$</creator>\n' +
 | 
						|
            '<origCreator>$</origCreator>\n' +
 | 
						|
            '<origName>$</origName>\n' +
 | 
						|
            '<remixHistory>$</remixHistory>\n' +
 | 
						|
            '<thumbnail>$</thumbnail>\n' +
 | 
						|
            '<stage name="@" width="@" height="@" ' +
 | 
						|
            'costume="@" tempo="@" threadsafe="@" ' +
 | 
						|
            '%' +
 | 
						|
            'lines="@" ' +
 | 
						|
            'ternary="@" ' +
 | 
						|
            'codify="@" ' +
 | 
						|
            'inheritance="@" ' +
 | 
						|
            'sublistIDs="@" ' +
 | 
						|
            'scheduled="@" ~>' +
 | 
						|
            '<pentrails>$</pentrails>' +
 | 
						|
            '<costumes>%</costumes>' +
 | 
						|
            '<sounds>%</sounds>' +
 | 
						|
            '<variables>%</variables>' +
 | 
						|
            '<blocks>%</blocks>' +
 | 
						|
            '<scripts>%</scripts><sprites>%</sprites>' +
 | 
						|
            '</stage>\n' +
 | 
						|
            '<hidden>$</hidden>' +
 | 
						|
            '<headers>%</headers>' +
 | 
						|
            '<code>%</code>' +
 | 
						|
            '<blocks>%</blocks>' +
 | 
						|
            '<variables>%</variables>\n' +
 | 
						|
            '</project>',
 | 
						|
        (ide && ide.projectName) ? ide.projectName : localize('Untitled'),  
 | 
						|
        serializer.app,
 | 
						|
        serializer.version,
 | 
						|
        (ide && ide.projectNotes) ? ide.projectNotes : '',
 | 
						|
        (ide && ide.creator) ? ide.creator : '',
 | 
						|
        (ide && ide.origCreator) ? ide.origCreator : '',
 | 
						|
        (ide && ide.origName) ? ide.origName : '',
 | 
						|
        (ide && ide.remixHistory) ? ide.remixHistory : '',
 | 
						|
        thumbdata,
 | 
						|
        this.name,
 | 
						|
        StageMorph.prototype.dimensions.x,
 | 
						|
        StageMorph.prototype.dimensions.y,
 | 
						|
        this.getCostumeIdx(),
 | 
						|
        this.getTempo(),
 | 
						|
        this.isThreadSafe,
 | 
						|
        this.instrument ?
 | 
						|
                ' instrument="' + parseInt(this.instrument) + '" ' : '',
 | 
						|
        SpriteMorph.prototype.useFlatLineEnds ? 'flat' : 'round',
 | 
						|
        BooleanSlotMorph.prototype.isTernary,
 | 
						|
        this.enableCodeMapping,
 | 
						|
        this.enableInheritance,
 | 
						|
        this.enableSublistIDs,
 | 
						|
        StageMorph.prototype.frameRate !== 0,
 | 
						|
        normalizeCanvas(this.trailsCanvas, true).toDataURL('image/png'),
 | 
						|
        serializer.store(this.costumes, this.name + '_cst'),
 | 
						|
        serializer.store(this.sounds, this.name + '_snd'),
 | 
						|
        serializer.store(this.variables),
 | 
						|
        serializer.store(this.customBlocks),
 | 
						|
        serializer.store(this.scripts),
 | 
						|
        serializer.store(this.children),
 | 
						|
        Object.keys(StageMorph.prototype.hiddenPrimitives).reduce(
 | 
						|
                function (a, b) {return a + ' ' + b; },
 | 
						|
                ''
 | 
						|
            ),
 | 
						|
        code('codeHeaders'),
 | 
						|
        code('codeMappings'),
 | 
						|
        serializer.store(this.globalBlocks),
 | 
						|
        (ide && ide.globalVariables) ?
 | 
						|
                    serializer.store(ide.globalVariables) : ''
 | 
						|
    );
 | 
						|
};
 | 
						|
 | 
						|
XML_Serializer.prototype.serialize = function (object, forBlocksLibrary) {
 | 
						|
    // public: answer an XML string representing the given object
 | 
						|
    var xml;
 | 
						|
    this.flush(); // in case an error occurred in an earlier attempt
 | 
						|
    this.flushMedia();
 | 
						|
    this.isExportingBlocksLibrary = forBlocksLibrary;
 | 
						|
    xml = this.store(object);
 | 
						|
    this.flush();
 | 
						|
    return xml;
 | 
						|
};
 |