Search code examples
google-drive-apigoogle-drive-realtime-api

Google Drive - Nested operations for undo/redo


If I have code like follows

model.beginCompoundOperation();

model.beginCompoundOperation()
someModelChanges();
model.endCompoundOperation();

model.beginCompoundOperation()
someMoreModelChanges();
model.endCompoundOperation();

model.endCompoundOperation()

When I call undo, will it group someModelChanges, and someMoreModelChanges together? I would like both to be undone as a batch operation. Thanks!


Solution

  • I put together a test page for this and it has the behavior you want and I would expect. Have fun with the realtime API!

    var clientId = "<<<REPLACE WITH YOUR CLIENT ID>>>";
    var REALTIME_MIMETYPE = 'application/vnd.google-apps.drive-sdk';
    
    // Everything interesting is at the bottom in the onDocLoaded function.
    
    function createRealtimeFile(title, description, callback)
    {
        console.log('Creating Drive Document');
        gapi.client.drive.files.insert({
            'resource':
            {
                'mimeType': REALTIME_MIMETYPE,
                'title': title,
                'description': description
            }
        }).execute(function (docInfo)
        {
            callback(docInfo, /*newDoc*/true);
        });
    }
    
    function openRealtimeFile(title, callback)
    {
        gapi.client.load('drive', 'v2', function ()
        {
            gapi.client.drive.files.list(
            {
                'q': 'title='+"'"+title+"' and 'me' in owners and trashed=false"
            }).execute(function (results)
            {
                if (!results.items)
                {
                    createRealtimeFile(title, /*DocDescription*/"", callback);
                }
                else
                {
                    callback(results.items[0], /*newDoc*/false);
                }
            });
        });
    }
    
    function onPageLoad()
    {
        var GScope =
        {
            Drive: 'https://www.googleapis.com/auth/drive.file'
        };
    
        gapi.load('auth:client,drive-realtime,drive-share', function()
        {
            var handleAuthResult = function(authResult)
            {
                console.log('Requesting Drive Document');
    
                openRealtimeFile("TESTDOC__", function (docInfo, newDoc)
                {
                    if (docInfo && docInfo.id)
                    {
                        gapi.drive.realtime.load(docInfo.id, onDocLoaded, onDocInitialized, onDocLoadError);
                    }
                    else
                    {
                        console.log('Unable to find realtime doc');
                        debugger;
                    }
                });
            };
    
            gapi.auth.authorize(
            {
                client_id: clientId,
                scope: [ GScope.Drive ],
                immediate: false
            }, handleAuthResult);
        });
    }
    
    function onDocInitialized(model)
    {
        console.log('Drive Document Initialized');
    
        var docRoot = model.createMap();
    
        model.getRoot().set('docRoot', docRoot);
    }
    
    function onDocLoaded(doc)
    {
        var docModel = doc.getModel();
        var docRoot = docModel.getRoot();
    
        console.log('Drive Document Loaded');
    
    
        // If the loaded document has already been used to test, delete any previous data.
        if (docRoot.has('testMap'))
        {
            docRoot.delete('testMap');
        }
    
        // Setup the new test data
        docRoot.set('testMap', docModel.createMap());
    
        var testMap = docRoot.get('testMap');
        console.assert(testMap, 'Test map required');
    
        var testString = docModel.createString();
        testMap.set('testString', testString);
    
        console.assert(testString.getText() === '');
    
    
    
        docModel.beginCompoundOperation();
    
        docModel.beginCompoundOperation();
        testString.append('AAA');
        docModel.endCompoundOperation();
    
        docModel.beginCompoundOperation();
        testString.append('BBB');
        docModel.endCompoundOperation();
    
        docModel.endCompoundOperation();
    
    
        console.assert(testString.getText() === 'AAABBB');
    
        docModel.undo();
    
        console.assert(testString.getText() === '');
    
        debugger;
    }
    
    function onDocLoadError(e)
    {
        console.log('Doc Load Error: ', e);
        findAndLoadDoc();
    }