From c4d7013d2c2084c290a751d6bfcfcd3f1a753e05 Mon Sep 17 00:00:00 2001 From: Dustin Wehr Date: Sat, 6 Jun 2015 23:35:38 -0400 Subject: [PATCH 1/5] Sufficiently complete for basic use of the API. Needs additions for multiple collaborators and some other things, which will be added in the coming months. --- google-realtime/google-realtime.d.ts | 521 +++++++++++++++++++++++++++ google-realtime/library-tests.ts | 196 ++++++++++ 2 files changed, 717 insertions(+) create mode 100644 google-realtime/google-realtime.d.ts create mode 100644 google-realtime/library-tests.ts diff --git a/google-realtime/google-realtime.d.ts b/google-realtime/google-realtime.d.ts new file mode 100644 index 000000000..b72471a04 --- /dev/null +++ b/google-realtime/google-realtime.d.ts @@ -0,0 +1,521 @@ +// Type definitions for Google Realtime API +// Project: https://developers.google.com/google-apps/realtime/ +// Definitions by: Dustin Wehr +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +// For Typescript newbs: To get shorter names, use e.g. +// type CollabModel = googleRealtime.Model; +// interface CollabList extends googleRealtime.CollaborativeList {} +// See section "Type Aliases" of http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf + +// Note the occurrences of "INCOMPLETE". For some interfaces and object types, I have only included +// the properties and methods that I've actually used so-far, and will add more as they become useful to me. +// Or, maybe you want to complete them? + +declare module googleRealtime { + + type GoogEventHandler = ((evt:ObjectChangedEvent) => void) | ((e:Event) => void) | EventListener; + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.CollaborativeObject + export class CollaborativeObject { + // The id of this collaborative object. Read-only. + id:string; + + // The type of this collaborative object. For standard collaborative objects, + // see gapi.drive.realtime.CollaborrativeType for possible values; for custom collaborative objects, this value is + // application-defined. + // Addition: the possible values for standard objects are EditableString, List, and Map. + type:string; + + // Adds an event listener to the event target. The same handler can only be added once per the type. + // Even if you add the same handler multiple times using the same type then it will only be called once + // when the event is dispatched. + addEventListener(type:string, listener: GoogEventHandler, opt_capture?:boolean):void; + + // Removes all event listeners from this object. + removeAllEventListeners():void; + + // Removes an event listener from the event target. The handler must be the same object as the one added. + // If the handler has not been added then nothing is done. + removeEventListener(type:string, listener: GoogEventHandler, opt_capture?:boolean):void; + + // Returns a string representation of this collaborative object. + toString():string; + } + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.IndexReference + export class IndexReference extends CollaborativeObject { + // (Categories of) the shift behavior of an index reference when the element it points at is deleted. + static DeleteMode:{ + SHIFT_AFTER_DELETE: string + SHIFT_BEFORE_DELETE: string + SHIFT_TO_INVALID: string + }; + + //The index of the current location the reference points to. Write to this property to change the referenced index. + index:number; + + // The behavior of this index reference when the element it points at is deleted. + // @return one of the elements of DeleteMode + deleteMode():string; + + // The object this reference points to. Read-only. + referencedObject():V; + } + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.CollaborativeMap + export class CollaborativeMap extends CollaborativeObject { + size:string; + + static type:string; // equals "Map" + + // Removes all entries. + clear():void; + + // Removes the entry for the given key (if such an entry exists). + // @return the value that was mapped to this key, or null if there was no existing value. + delete(key:string):V; + + // Returns the value mapped to the given key. + get(key:string):V; + + // Checks if this map contains an entry for the given key. + has(key:string):boolean; + + // Returns whether this map is empty. + isEmpty():boolean; + + // Returns an array containing a copy of the items in this map. Modifications to the returned array do + // not modify this collaborative map. + // @return non-null Array of Arrays, where the inner arrays are tupples [string, V] + items():[string,V][]; + + // Returns an array containing a copy of the keys in this map. Modifications to the returned array + // do not modify this collaborative map. + keys():string[]; + + // Put the value into the map with the given key, overwriting an existing value for that key. + // @return the old map value, if any, that used to be mapped to the given key. + set(key:string, value:V):V; + + // Returns an array containing a copy of the values in this map. Modifications to the returned array + // do not modify this collaborative map. + values():V[]; + } + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.CollaborativeString + export class CollaborativeString extends CollaborativeObject { + // The length of the string. Read only. + length:number; + + // The text of this collaborative string. Reading from this property is equivalent to calling getText(). Writing to this property is equivalent to calling setText(). + text:string; + + static type:string; // equals "EditableString" + + // Appends a string to the end of this one. + append(text:string):void; + + // Gets a string representation of the collaborative string. + getText():string; + + // Inserts a string into the collaborative string at a specific index. + insertString(index:number, text:string):void; + + // Creates an IndexReference at the given {@code index}. If {@code canBeDeleted} is set, then a delete + // over the index will delete the reference. Otherwise the reference will shift to the beginning of the deleted range. + registerReference(index:number, canBeDeleted:boolean):IndexReference; + + // Deletes the text between startIndex (inclusive) and endIndex (exclusive). + removeRange(startIndex:number, endIndex:number):void; + + // Sets the contents of this collaborative string. Note that this method performs a text diff between the + // current string contents and the new contents so that the string will be modified using the minimum number + // of text inserts and deletes possible to change the current contents to the newly-specified contents. + setText(text:string):void; + } + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.CollaborativeList + export class CollaborativeList extends CollaborativeObject { + // The number of entries in the list. Assign to this field to reduce the size of the list. + // Note that the length given must be less than or equal to the current size. + // The length of a list cannot be extended in this way. + length:number; + + static type:string; // equals "List" + + // Returns a copy of the contents of this collaborative list as an array. + // Changes to the returned object will not affect the original collaborative list. + asArray():V[]; + + // Removes all values from the list. + clear():void; + + // Gets the value at the given index. + get(ind:number):V; + + //Returns the first index of the given value, or -1 if it cannot be found. + indexOf(value:V, opt_comparatorFn?:(x1:V, x2:V) => boolean):number; + + //Inserts an item into the list at a given index. + insert(index:number, value:V):void; + + // Inserts a list of items into the list at a given index. + insertAll(index:number, values:V[]):void; + + // Returns the last index of the given value, or -1 if it cannot be found. + lastIndexOf(value:V, opt_comparatorFn?:(x1:V, x2:V) => boolean):number; + + //Moves a single element in this list (at index) to immediately before destinationIndex. + //Both indices are with respect to the position of elements before the move. + //For example, given the list: ['A', 'B', 'C'] + //move(0, 0) is a no-op + //move(0, 1) is a no-op + //move(0, 2) yields ['B', 'A', 'C'] ('A' is moved to immediately before 'C') + //move(0, 3) yields ['B', 'C', 'A'] ('A' is moved to immediately before an imaginary element after the list end) + //move(1, 0) yields ['B', 'A', 'C'] ('B' is moved to immediately before 'A') + //move(1, 1) is a no-op + //move(1, 2) is a no-op + //move(1, 3) yields ['A', 'C', 'B'] ('B' is moved to immediately before an imaginary element after the list end) + move(index:number, destinationIndex:number):void; + + // Moves a single element in this list (at index) to immediately before destinationIndex in the list destination. + // Both indices are with respect to the position of elements before the move. + // If the provided destination is this list, this function is identical to move(index, destinationIndex). + moveToList(index:number, destination:CollaborativeList, destinationIndex:number):void; + + // Adds an item to the end of the list. + // @return the new length of the list + push(value:V):number; + + // Adds an array of values to the end of the list. + pushAll(values:V[]):void; + + // Creates an IndexReference at the given index. If canBeDeleted is true, then a delete over the index will delete + // the reference. Otherwise the reference will shift to the beginning of the deleted range. + registerReference(index:number, canBeDeleted:boolean):IndexReference>; + + // Removes the item at the given index from the list. + remove(index:number):void; + + // Removes the items between startIndex (inclusive) and endIndex (exclusive). + removeRange(startIndex:number, endIndex:number):void; + + // Removes the first instance of the given value from the list. + // @return whether the item was removed + removeValue(value:V):boolean; + + // Replaces items in the list with the given items, starting at the given index. + replaceRange(index:number, values:V[]):void; + + // Sets the item at the given index + set(index:number, value:V):void; + } + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.Model + export class Model { + + // Returns the collaborative object with the given id. + // @return non-null Object + getObject:any; + + // An estimate of the number of bytes used by data stored in the model. + bytesUsed:number; + + // True if the model can currently redo. + canRedo:boolean; + + // True if the model can currently undo. + canUndo:boolean; + + // Creates the native JS object for a given collaborative object type. + // @return non-null Object + createJsObject(typeName:string):any; + + // Adds an event listener to the event target. + // The same handler can only be added once per the type. Even if you add the same handler multiple times using the + // same type then it will only be called once when the event is dispatched. + addEventListener(type:string, listener:() => void | EventListener, opt_capture?:boolean):void; + + // Starts a compound operation. If a name is given, that name will be recorded in the mutation for use in revision + // history, undo menus, etc. When beginCompoundOperation() is called, all subsequent edits to the data model will + // be batched together in the undo stack and revision history until endCompoundOperation() is called. + // Compound operations may be nested inside other compound operations. + // If the root compound operation is undoable, all nested compound operations must be undoable as well. + // If the root compound operation is non-undoable, nested operations can be undoable, although the entire operation + // will obey the root's opt_isUndoable value. + // Note that the compound operation MUST start and end in the same synchronous execution block. If this invariant + // is violated, the data model will become invalid and all future changes will fail. + beginCompoundOperation(opt_name?:string, opt_isUndoable?:boolean):void; + + + // Creates and returns a new collaborative object. This can be used to create custom collaborative objects. + // For built in types, use the specific create* functions. + // @return non-null Object + create(ref:string|Function, ...var_args:any[]):any; + + // Creates a collaborative list. + createList(opt_initialValue?:Array):CollaborativeList; + + // Creates a collaborative map. + createMap(opt_initialValue?:Array<[string,T]>):CollaborativeMap; + + // Creates a collaborative string. + createString(opt_initialValue?:string):CollaborativeString; + + //Ends a compound operation. This method will throw an exception if no compound operation is in progress. + endCompoundOperation():void; + + // Returns the root of the object model. + getRoot():CollaborativeMap; + + // The mode of the document. If true, the document is read-only. If false, it is editable. + isReadOnly():boolean; + + // Redo the last thing the active collaborator undid. + redo():void; + + // Removes all event listeners from this object. + removeAllEventListeners():void; + + // Removes an event listener from the event target. The handler must be the same object as the one added. + // If the handler has not been added then nothing is done. + removeEventListener(type:string, listener:() => void | EventListener, opt_capture?:boolean):void; + + // The current server revision number for this model. The revision number begins at 1 (the initial empty model) + // and is incremented each time the model is changed on the server (either by the current session or any + // other collaborator). Because this revision number includes only changes that the server knows about, + // it is only updated while this client is connected to the Realtime API server and it does not include changes + // that have not yet been saved to the server. + serverRevision():number; + + // Serializes this data model to a JSON-based format which is compatible with the Realtime API's import/export + // REST API. The exported JSON can also be used with gapi.drive.realtime.loadFromJson to load an in-memory + // version of this data model which does not require a network connection. + // See https://developers.google.com/drive/v2/reference/realtime/update for more information. + toJson(opt_appId?:string, opt_revision?:number):string; + + // Undo the last thing the active collaborator did. + undo():void; + } + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.BaseModelEvent + interface BaseModelEvent { + // Whether this event bubbles. + bubbles : boolean; + + // The list of names from the hierarchy of compound operations that initiated this event. + compoundOperationNames : string[]; + + // True if this event originated in the local session. + isLocal : boolean; + + // True if this event originated from a redo call. + isRedo : boolean; + + // True if this event originated from an undo call. + isUndo : boolean; + + // Prevents an event from performing its default action. In the Realtime API, this function is only present + // for compatibility with the DOM event interface and therefore it does nothing. + preventDefault() : void; + + // The id of the session that initiated this event. + sessionId : string; + + // The collaborative object that initiated this event. + target : Object; + + // The type of the event. + type : string; + + // The user id of the user that initiated this event. + userId : string; + + // Stops an event which bubbles from propagating to the target's parent. + stopPropagation() : void; + + /* Parameters: + target + gapi.drive.realtime.CollaborativeObject + The collaborative object that initiated the event. + Value must not be null. + + sessionId + string + The id of the session that initiated the event. + + userId + string + The user id of the user that initiated the event. + + compoundOperationNames + Array of string + The list of names from the hierarchy of compound operations that initiated the event. + Value must not be null. + isLocal + boolean + True if the event originated in the local session. + + isUndo + boolean + True if the event originated from an undo call. + + isRedo + boolean + True if the event originated from a redo call. + */ + new (target:CollaborativeObject, sessionId:string, userId:string, compoundOperationNames: string[], + isLocal:boolean, isUndo:boolean, isRedo:boolean) : BaseModelEvent; + } + + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.ObjectChangedEvent + interface ObjectChangedEvent extends BaseModelEvent { + // parameters as in BaseModelEvent above except for addition of: + // events: + // Array of gapi.drive.realtime.BaseModelEvent + // The specific events that document the changes that occurred on the object. + // Value must not be null. + new (target:CollaborativeObject, sessionId:string, userId:string, compoundOperationNames: string[], + isLocal:boolean, isUndo:boolean, isRedo:boolean, events:BaseModelEvent[]) : ObjectChangedEvent; + + // The specific events that document the changes that occurred on the object. + events : BaseModelEvent[]; + } + + + // INCOMPLETE + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.Document + export class Document { + // Gets the collaborative model associated with this document. + // @return non-null Model + getModel():Model; + + // Closes the document and disconnects from the server. + // After this function is called, event listeners will no longer fire and attempts to access the document, model, + // or model objects will throw a gapi.drive.realtime.DocumentClosedError. + // Calling this function after the document has been closed will have no effect. + close():void; + } + + // *********************************** + // The remainder of this file types some (not all) things in realtime-client-utils.js, found here: + // https://developers.google.com/google-apps/realtime/realtime-quickstart + // and + // https://apis.google.com/js/api.js + // *********************************** + + + // Complete + export interface LoaderOptions { + // Your Application ID from the Google APIs Console. + appId: string; + + // Autocreate files right after auth automatically. + autoCreate: boolean; + + // Client ID from the console. + clientId: string; + + // The ID of the button to click to authorize. Must be a DOM element ID. + authButtonElementId: string; + + // The MIME type of newly created Drive Files. By default the application + // specific MIME type will be used: + // application/vnd.google-apps.drive-sdk. + newFileMimeType: string; + //newFileMimeType = null // default + + // Function to be called to initialize custom Collaborative Objects types. + registerTypes: () => void; + + // The name of newly created Drive files, if no title is specified. + defaultTitle: string; + + // Function to be called after authorization and before loading files. + afterAuth: () => void; + + // Function to be called when a Realtime model is first created. + initializeModel: (model:Model) => void; + + // Function to be called every time a Realtime file is loaded. + onFileLoaded: (rtdoc:Document) => void; + } + + // INCOMPLETE + export interface DriveAPIFileResource { + id: string; + } + + // INCOMPLETE + export interface RealtimeLoader { + start():void; + load():void; + } + interface RealtimeLoaderFactory { + new (options:googleRealtime.LoaderOptions) : RealtimeLoader; + } + + // INCOMPLETE + export interface ClientUtils { + // INCOMPLETE + params: { + // string containing one or more file ids separated by spaces. + fileIds : string + }; + RealtimeLoader : RealtimeLoaderFactory; + + /** + * Creates a new Realtime file. + * @param title {string} title of the newly created file. + * @param mimeType {string} the MIME type of the new file. + * @param callback {(file:DriveAPIFileResource) => void} the callback to call after creation. + */ + createRealtimeFile(title:string, mimeType:string, callback:(file:DriveAPIFileResource) => void) : void; + } + + // COMPLETE + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.databinding.Binding + export interface Binding { + // Throws gapi.drive.realtime.databinding.AlreadyBoundError If domElement has already been bound. + + // The collaborative object to bind. + collaborativeObject : CollaborativeObject; + + // The DOM element that the collaborative object is bound to. Value must not be null. + domElement : Element; + + // Unbinds the domElement from collaborativeObject. + unbind() : void; + } + + export interface GoogleAPI { + drive : { + realtime : { + databinding : { + bindString(s:googleRealtime.CollaborativeString, textinput:HTMLInputElement) : googleRealtime.Binding; + } + EventType : { + TEXT_INSERTED: string; + TEXT_DELETED: string; + OBJECT_CHANGED: string; + } + } + } + } + +} + +// global var introduced by realtime-client-utils.js +declare var rtclient:googleRealtime.ClientUtils; + +// global var introduced by https://apis.google.com/js/api.js +declare var gapi: googleRealtime.GoogleAPI; \ No newline at end of file diff --git a/google-realtime/library-tests.ts b/google-realtime/library-tests.ts new file mode 100644 index 000000000..5adc8184a --- /dev/null +++ b/google-realtime/library-tests.ts @@ -0,0 +1,196 @@ +/// + +// Don't use this as a reference. Use the examples at +// https://developers.google.com/google-apps/realtime/ +// To use the Realtime API effectively, I needed to read lots of the +// (well-written) documentation on the site, and to understand parts of +// realtime-client-utils.js +// which you can find in the tutorial section of the project's homepage. + +declare var $ : any; +interface JQuery { + [key: string]: any; +}; + +type CollabModel = googleRealtime.Model; +type CollabDoc = googleRealtime.Document; +interface CollaborativeObject extends googleRealtime.CollaborativeObject {} +interface CollaborativeList extends googleRealtime.CollaborativeList {} +interface CollaborativeMap extends googleRealtime.CollaborativeMap {} +interface IndexReference extends googleRealtime.IndexReference {} +interface CollaborativeString extends googleRealtime.CollaborativeString {} + +type CListOfCObj = CollaborativeList +type CObjOrStr = CollaborativeObject | string; +type CMapOfCObjOrStr = CollaborativeMap; + + +module GRealtime { + + + + + var default_loader_options : googleRealtime.LoaderOptions = { + // Your Application ID from the Google APIs Console. + appId: "YOUR_APP_ID", + + // This tells us if need to we automatically create a file after auth. + autoCreate: false, + + // Client ID from the console. + clientId: 'YOUR_CLIENT_ID.apps.googleusercontent.com', + + // The ID of the button to click to authorize. Must be a DOM element ID. + authButtonElementId: 'realtime-authorize-button', + + // The MIME type of newly created Drive Files. By default the application + // specific MIME type will be used: + // application/vnd.google-apps.drive-sdk. + //newFileMimeType: 'text/json', + newFileMimeType: 'text', + //newFileMimeType: null, // default + + // Function to be called to initialize custom Collaborative Objects types. + registerTypes: null, // No action + + defaultTitle: "Default default-doc-title", + + // The rest are only defaults + afterAuth: function() : void { + console.log("default afterAuth called") + }, + + initializeModel: function(rtmodel:CollabModel) : void { + console.log("default initializeModel called"); + }, + + onFileLoaded : function(rtdoc:CollabDoc) : void { + console.log("default onFileLoaded called"); + } + + }; + + export class MyRTLoader { + public loader_options : googleRealtime.LoaderOptions = $.extend({},default_loader_options); + private rtloader_client : googleRealtime.RealtimeLoader; + + // call after setting loader_options appropriately + authorize() { + this.rtloader_client = new rtclient.RealtimeLoader(this.loader_options); + this.rtloader_client.start(); + } + + createNew(title:string, callback: (file:any) => void) { + rtclient.createRealtimeFile(title, null, callback); + } + + loadAfterAuth(fileid:string) { + // use this as part of your afterAuth callback + rtclient.params.fileIds = fileid; + this.rtloader_client.load(); + } + } + + export class MyRealtimeDoc { + protected rtmodel: CollabModel; + protected rtdoc: CollabDoc; + private myRTLoader = new GRealtime.MyRTLoader(); + + newFile(title: string, + initializeModel: (x:CollabModel) => void, + onFileLoaded: (x:CollabDoc) => void) : void { + + var _afterAuth = () => { + this.myRTLoader.createNew(title, (file:googleRealtime.DriveAPIFileResource) => { + console.log(`\n\nThis is the createNew callback. New file's id: ${file.id}\n\n`); + $("#file-id-text-input").val(file.id); + this.myRTLoader.loadAfterAuth(file.id) + }) + } + + var _initializeModel = (model:CollabModel) => { + console.log("\n\nRTModel initialized for NEW document.\n\n"); + this.rtmodel = model; + if( initializeModel ) { + initializeModel(model); + } + } + + var _onFileLoaded = (doc:CollabDoc) => { + console.log("\n\nNEW document loaded.\n\n"); + this.rtmodel = doc.getModel(); + this.rtdoc = doc; + if( onFileLoaded ) { + onFileLoaded(doc); + } + } + + this.myRTLoader.loader_options.onFileLoaded = _onFileLoaded; + this.myRTLoader.loader_options.afterAuth = _afterAuth; + this.myRTLoader.loader_options.initializeModel = _initializeModel; + this.myRTLoader.authorize(); + } + + loadExisting(fileid: string, + onFileLoaded: (doc:CollabDoc) => void) : void { + + rtclient.params.fileIds = fileid; + + var _onFileLoaded = (doc:CollabDoc) => { + console.log("\n\nEXISTING document loaded.\n\n"); + this.rtdoc = doc; + this.rtmodel = doc.getModel(); + if( onFileLoaded ) { + onFileLoaded(doc); + } + }; + + this.myRTLoader.loader_options.onFileLoaded = _onFileLoaded; + //this.myRTLoader.loader_options.afterAuth = ... + this.myRTLoader.authorize(); + } + + createString() : CollaborativeString { return this.rtmodel.createString(""); } + + createList() : CollaborativeList { return this.rtmodel.createList(); } + + createMap() : CollaborativeMap { return this.rtmodel.createMap(); } + + addToPersistDocRoot(x:{pdata:any}, key:string) { + this.rtmodel.getRoot().set(key,x.pdata); + } + + bindString(istring:CollaborativeString, $textinput: JQuery) : googleRealtime.Binding { + return gapi.drive.realtime.databinding.bindString( + istring, + $textinput[0] ); + } + + + } + + // alternative to RealtimePSDoc.bindString + function registerLocalStringChangeListener( + x: CollaborativeString, + listener_or_callback: (e:Event) => void | EventListener) : void { + x.addEventListener(gapi.drive.realtime.EventType.TEXT_INSERTED, listener_or_callback); + x.addEventListener(gapi.drive.realtime.EventType.TEXT_DELETED, listener_or_callback); + } + +} + + +// Next example from https://developers.google.com/google-apps/realtime/model-events + +declare var doc : CollabDoc; +function displayObjectChangedEvent(evt:googleRealtime.ObjectChangedEvent) { + var events = evt.events; + var eventCount = evt.events.length; + for (var i = 0; i < eventCount; i++) { + console.log('Event type: ' + events[i].type); + console.log('Local event: ' + events[i].isLocal); + console.log('User ID: ' + events[i].userId); + console.log('Session ID: ' + events[i].sessionId); + } +} +doc.getModel().getRoot().addEventListener(gapi.drive.realtime.EventType.OBJECT_CHANGED, displayObjectChangedEvent); \ No newline at end of file From 468f1a1007ac727c953e66f3a6765aabee6f02dc Mon Sep 17 00:00:00 2001 From: Dustin Wehr Date: Mon, 8 Jun 2015 14:42:11 -0400 Subject: [PATCH 2/5] renamed. made compatible with ../gapi/gapi.d.ts. --- .../google-drive-realtime-api-tests.ts | 28 +-- .../google-drive-realtime-api.d.ts | 184 ++++++++++-------- 2 files changed, 113 insertions(+), 99 deletions(-) rename google-realtime/library-tests.ts => google-drive-realtime-api/google-drive-realtime-api-tests.ts (85%) rename google-realtime/google-realtime.d.ts => google-drive-realtime-api/google-drive-realtime-api.d.ts (87%) diff --git a/google-realtime/library-tests.ts b/google-drive-realtime-api/google-drive-realtime-api-tests.ts similarity index 85% rename from google-realtime/library-tests.ts rename to google-drive-realtime-api/google-drive-realtime-api-tests.ts index 5adc8184a..62578f42a 100644 --- a/google-realtime/library-tests.ts +++ b/google-drive-realtime-api/google-drive-realtime-api-tests.ts @@ -1,4 +1,4 @@ -/// +/// // Don't use this as a reference. Use the examples at // https://developers.google.com/google-apps/realtime/ @@ -12,13 +12,13 @@ interface JQuery { [key: string]: any; }; -type CollabModel = googleRealtime.Model; -type CollabDoc = googleRealtime.Document; -interface CollaborativeObject extends googleRealtime.CollaborativeObject {} -interface CollaborativeList extends googleRealtime.CollaborativeList {} -interface CollaborativeMap extends googleRealtime.CollaborativeMap {} -interface IndexReference extends googleRealtime.IndexReference {} -interface CollaborativeString extends googleRealtime.CollaborativeString {} +type CollabModel = gapi.drive.realtime.Model; +type CollabDoc = gapi.drive.realtime.Document; +interface CollaborativeObject extends gapi.drive.realtime.CollaborativeObject {} +interface CollaborativeList extends gapi.drive.realtime.CollaborativeList {} +interface CollaborativeMap extends gapi.drive.realtime.CollaborativeMap {} +interface IndexReference extends gapi.drive.realtime.IndexReference {} +interface CollaborativeString extends gapi.drive.realtime.CollaborativeString {} type CListOfCObj = CollaborativeList type CObjOrStr = CollaborativeObject | string; @@ -30,7 +30,7 @@ module GRealtime { - var default_loader_options : googleRealtime.LoaderOptions = { + var default_loader_options : rtclient.LoaderOptions = { // Your Application ID from the Google APIs Console. appId: "YOUR_APP_ID", @@ -71,8 +71,8 @@ module GRealtime { }; export class MyRTLoader { - public loader_options : googleRealtime.LoaderOptions = $.extend({},default_loader_options); - private rtloader_client : googleRealtime.RealtimeLoader; + public loader_options : rtclient.LoaderOptions = $.extend({},default_loader_options); + private rtloader_client : rtclient.RealtimeLoader; // call after setting loader_options appropriately authorize() { @@ -101,7 +101,7 @@ module GRealtime { onFileLoaded: (x:CollabDoc) => void) : void { var _afterAuth = () => { - this.myRTLoader.createNew(title, (file:googleRealtime.DriveAPIFileResource) => { + this.myRTLoader.createNew(title, (file:rtclient.DriveAPIFileResource) => { console.log(`\n\nThis is the createNew callback. New file's id: ${file.id}\n\n`); $("#file-id-text-input").val(file.id); this.myRTLoader.loadAfterAuth(file.id) @@ -160,7 +160,7 @@ module GRealtime { this.rtmodel.getRoot().set(key,x.pdata); } - bindString(istring:CollaborativeString, $textinput: JQuery) : googleRealtime.Binding { + bindString(istring:CollaborativeString, $textinput: JQuery) : gapi.drive.realtime.databinding.Binding { return gapi.drive.realtime.databinding.bindString( istring, $textinput[0] ); @@ -183,7 +183,7 @@ module GRealtime { // Next example from https://developers.google.com/google-apps/realtime/model-events declare var doc : CollabDoc; -function displayObjectChangedEvent(evt:googleRealtime.ObjectChangedEvent) { +function displayObjectChangedEvent(evt:gapi.drive.realtime.ObjectChangedEvent) { var events = evt.events; var eventCount = evt.events.length; for (var i = 0; i < eventCount; i++) { diff --git a/google-realtime/google-realtime.d.ts b/google-drive-realtime-api/google-drive-realtime-api.d.ts similarity index 87% rename from google-realtime/google-realtime.d.ts rename to google-drive-realtime-api/google-drive-realtime-api.d.ts index b72471a04..8cf4aa97b 100644 --- a/google-realtime/google-realtime.d.ts +++ b/google-drive-realtime-api/google-drive-realtime-api.d.ts @@ -3,16 +3,19 @@ // Definitions by: Dustin Wehr // Definitions: https://github.com/borisyankov/DefinitelyTyped -// For Typescript newbs: To get shorter names, use e.g. -// type CollabModel = googleRealtime.Model; -// interface CollabList extends googleRealtime.CollaborativeList {} -// See section "Type Aliases" of http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf +// This definition file is merge-compatible with ../gapi/gapi.d.ts // Note the occurrences of "INCOMPLETE". For some interfaces and object types, I have only included // the properties and methods that I've actually used so-far, and will add more as they become useful to me. // Or, maybe you want to complete them? -declare module googleRealtime { +// For Typescript newbs: To get shorter names, use e.g. +// type CollabModel = gapi.drive.realtime.Model; +// interface CollabList extends gapi.drive.realtime.CollaborativeList {} +// See section "Type Aliases" of http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf + +// gapi is a global var introduced by https://apis.google.com/js/api.js +declare module gapi.drive.realtime { type GoogEventHandler = ((evt:ObjectChangedEvent) => void) | ((e:Event) => void) | EventListener; @@ -31,14 +34,14 @@ declare module googleRealtime { // Adds an event listener to the event target. The same handler can only be added once per the type. // Even if you add the same handler multiple times using the same type then it will only be called once // when the event is dispatched. - addEventListener(type:string, listener: GoogEventHandler, opt_capture?:boolean):void; + addEventListener(type:string, listener:GoogEventHandler, opt_capture?:boolean):void; // Removes all event listeners from this object. removeAllEventListeners():void; // Removes an event listener from the event target. The handler must be the same object as the one added. // If the handler has not been added then nothing is done. - removeEventListener(type:string, listener: GoogEventHandler, opt_capture?:boolean):void; + removeEventListener(type:string, listener:GoogEventHandler, opt_capture?:boolean):void; // Returns a string representation of this collaborative object. toString():string; @@ -309,13 +312,13 @@ declare module googleRealtime { // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.BaseModelEvent interface BaseModelEvent { // Whether this event bubbles. - bubbles : boolean; + bubbles : boolean; // The list of names from the hierarchy of compound operations that initiated this event. compoundOperationNames : string[]; // True if this event originated in the local session. - isLocal : boolean; + isLocal : boolean; // True if this event originated from a redo call. isRedo : boolean; @@ -325,54 +328,54 @@ declare module googleRealtime { // Prevents an event from performing its default action. In the Realtime API, this function is only present // for compatibility with the DOM event interface and therefore it does nothing. - preventDefault() : void; + preventDefault() : void; // The id of the session that initiated this event. - sessionId : string; + sessionId : string; // The collaborative object that initiated this event. - target : Object; + target : Object; // The type of the event. - type : string; + type : string; // The user id of the user that initiated this event. - userId : string; + userId : string; // Stops an event which bubbles from propagating to the target's parent. - stopPropagation() : void; + stopPropagation() : void; /* Parameters: - target - gapi.drive.realtime.CollaborativeObject - The collaborative object that initiated the event. - Value must not be null. + target + gapi.drive.realtime.CollaborativeObject + The collaborative object that initiated the event. + Value must not be null. - sessionId - string - The id of the session that initiated the event. + sessionId + string + The id of the session that initiated the event. - userId - string - The user id of the user that initiated the event. + userId + string + The user id of the user that initiated the event. - compoundOperationNames - Array of string - The list of names from the hierarchy of compound operations that initiated the event. - Value must not be null. - isLocal - boolean - True if the event originated in the local session. + compoundOperationNames + Array of string + The list of names from the hierarchy of compound operations that initiated the event. + Value must not be null. + isLocal + boolean + True if the event originated in the local session. - isUndo - boolean - True if the event originated from an undo call. + isUndo + boolean + True if the event originated from an undo call. - isRedo - boolean - True if the event originated from a redo call. - */ - new (target:CollaborativeObject, sessionId:string, userId:string, compoundOperationNames: string[], + isRedo + boolean + True if the event originated from a redo call. + */ + new (target:CollaborativeObject, sessionId:string, userId:string, compoundOperationNames:string[], isLocal:boolean, isUndo:boolean, isRedo:boolean) : BaseModelEvent; } @@ -384,7 +387,7 @@ declare module googleRealtime { // Array of gapi.drive.realtime.BaseModelEvent // The specific events that document the changes that occurred on the object. // Value must not be null. - new (target:CollaborativeObject, sessionId:string, userId:string, compoundOperationNames: string[], + new (target:CollaborativeObject, sessionId:string, userId:string, compoundOperationNames:string[], isLocal:boolean, isUndo:boolean, isRedo:boolean, events:BaseModelEvent[]) : ObjectChangedEvent; // The specific events that document the changes that occurred on the object. @@ -405,6 +408,46 @@ declare module googleRealtime { // Calling this function after the document has been closed will have no effect. close():void; } +} + + +declare module gapi.drive.realtime.databinding { + // COMPLETE + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.databinding.Binding + export interface Binding { + // Throws gapi.drive.realtime.databinding.AlreadyBoundError If domElement has already been bound. + + // The collaborative object to bind. + collaborativeObject : CollaborativeObject; + + // The DOM element that the collaborative object is bound to. Value must not be null. + domElement : Element; + + // Unbinds the domElement from collaborativeObject. + unbind() : void; + } + + export function bindString(s:CollaborativeString, textinput:HTMLInputElement) : Binding +} + + +declare module gapi.drive.realtime.EventType { + export var TEXT_INSERTED: string + export var TEXT_DELETED: string + export var OBJECT_CHANGED: string +} + + +// rtclient is a global var introduced by realtime-client-utils.js +declare module rtclient { + // INCOMPLETE + export interface RealtimeLoader { + start():void; + load():void; + } + interface RealtimeLoaderFactory { + new (options:LoaderOptions) : RealtimeLoader; + } // *********************************** // The remainder of this file types some (not all) things in realtime-client-utils.js, found here: @@ -444,10 +487,10 @@ declare module googleRealtime { afterAuth: () => void; // Function to be called when a Realtime model is first created. - initializeModel: (model:Model) => void; + initializeModel: (model:gapi.drive.realtime.Model) => void; // Function to be called every time a Realtime file is loaded. - onFileLoaded: (rtdoc:Document) => void; + onFileLoaded: (rtdoc:gapi.drive.realtime.Document) => void; } // INCOMPLETE @@ -455,15 +498,6 @@ declare module googleRealtime { id: string; } - // INCOMPLETE - export interface RealtimeLoader { - start():void; - load():void; - } - interface RealtimeLoaderFactory { - new (options:googleRealtime.LoaderOptions) : RealtimeLoader; - } - // INCOMPLETE export interface ClientUtils { // INCOMPLETE @@ -482,40 +516,20 @@ declare module googleRealtime { createRealtimeFile(title:string, mimeType:string, callback:(file:DriveAPIFileResource) => void) : void; } - // COMPLETE - // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.databinding.Binding - export interface Binding { - // Throws gapi.drive.realtime.databinding.AlreadyBoundError If domElement has already been bound. - - // The collaborative object to bind. - collaborativeObject : CollaborativeObject; - - // The DOM element that the collaborative object is bound to. Value must not be null. - domElement : Element; - - // Unbinds the domElement from collaborativeObject. - unbind() : void; - } - - export interface GoogleAPI { - drive : { - realtime : { - databinding : { - bindString(s:googleRealtime.CollaborativeString, textinput:HTMLInputElement) : googleRealtime.Binding; - } - EventType : { - TEXT_INSERTED: string; - TEXT_DELETED: string; - OBJECT_CHANGED: string; - } - } - } - } + export var RealtimeLoader : RealtimeLoaderFactory + /** + * Creates a new Realtime file. + * @param title {string} title of the newly created file. + * @param mimeType {string} the MIME type of the new file. + * @param callback {(file:DriveAPIFileResource) => void} the callback to call after creation. + */ + export function createRealtimeFile(title:string, mimeType:string, callback:(file:DriveAPIFileResource) => void) : void } -// global var introduced by realtime-client-utils.js -declare var rtclient:googleRealtime.ClientUtils; +// INCOMPLETE +declare module rtclient.params { + // string containing one or more file ids separated by spaces. + export var fileIds:string +} -// global var introduced by https://apis.google.com/js/api.js -declare var gapi: googleRealtime.GoogleAPI; \ No newline at end of file From 86d2c6672785f69f38060ea5cfba5b92a9eaa0fe Mon Sep 17 00:00:00 2001 From: Dustin Wehr Date: Thu, 11 Jun 2015 17:22:10 -0400 Subject: [PATCH 3/5] couple type tightenings --- google-drive-realtime-api/google-drive-realtime-api.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/google-drive-realtime-api/google-drive-realtime-api.d.ts b/google-drive-realtime-api/google-drive-realtime-api.d.ts index 8cf4aa97b..8bb4af5c0 100644 --- a/google-drive-realtime-api/google-drive-realtime-api.d.ts +++ b/google-drive-realtime-api/google-drive-realtime-api.d.ts @@ -226,7 +226,7 @@ declare module gapi.drive.realtime { // Returns the collaborative object with the given id. // @return non-null Object - getObject:any; + getObject: (id:string) => CollaborativeObject; // An estimate of the number of bytes used by data stored in the model. bytesUsed:number; @@ -334,7 +334,7 @@ declare module gapi.drive.realtime { sessionId : string; // The collaborative object that initiated this event. - target : Object; + target : CollaborativeObject; // The type of the event. type : string; From 7f74fc1a314a0cecaab10522e5e84a804711fa48 Mon Sep 17 00:00:00 2001 From: Dustin Wehr Date: Thu, 11 Jun 2015 17:43:06 -0400 Subject: [PATCH 4/5] Add definition for gapi.drive.realtime.Document --- .../google-drive-realtime-api.d.ts | 50 +++++++++++++++++-- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/google-drive-realtime-api/google-drive-realtime-api.d.ts b/google-drive-realtime-api/google-drive-realtime-api.d.ts index 8bb4af5c0..b1d970e3c 100644 --- a/google-drive-realtime-api/google-drive-realtime-api.d.ts +++ b/google-drive-realtime-api/google-drive-realtime-api.d.ts @@ -19,6 +19,9 @@ declare module gapi.drive.realtime { type GoogEventHandler = ((evt:ObjectChangedEvent) => void) | ((e:Event) => void) | EventListener; + // TODO + export class Collaborator {} + // Complete // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.CollaborativeObject export class CollaborativeObject { @@ -395,18 +398,57 @@ declare module gapi.drive.realtime { } - // INCOMPLETE + // Complete // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.Document export class Document { - // Gets the collaborative model associated with this document. - // @return non-null Model - getModel():Model; + // Whether the document is closed. Read-only; call close() to close the document. + isClosed : boolean; + + // Whether the document is stored in Google Drive. Read-only. + // This property is false for documents created using gapi.drive.realtime.newInMemoryDocument or + // gapi.drive.realtime.loadFromJson and true for all other documents. + isInGoogleDrive : boolean; + + // The approximate amount of time (in milliseconds) that changes have been waiting to be saved in Google Drive. + // If there are no unsaved changes or this is an in-memory document, this value is always 0. + // This value should remain low (for example, less than a few seconds) as long as the network is healthy and + // changes are being saved as quickly as they are generated. If the network is unreliable or down, or if changes + // are being made to the model more quickly than they can be saved, this value will continue to grow until the + // network catches up and the changes are successfully saved. + saveDelay : number; + + // Adds an event listener to the event target. The same handler can only be added once per the type. + // Even if you add the same handler multiple times using the same type then it will only be called once when + // the event is dispatched. + addEventListener(type:string, listener:GoogEventHandler, opt_capture?:boolean) : void; // Closes the document and disconnects from the server. // After this function is called, event listeners will no longer fire and attempts to access the document, model, // or model objects will throw a gapi.drive.realtime.DocumentClosedError. // Calling this function after the document has been closed will have no effect. close():void; + + // Gets an array of collaborators active in this session. Each collaborator is a jsMap with these fields: + // sessionId, userId, displayName, color, isMe, isAnonymous. + getCollaborators() : Collaborator[]; + + // Gets the collaborative model associated with this document. + // @return non-null Model + getModel():Model; + + // Removes all event listeners from this object. + removeAllEventListeners() : void; + + // Removes an event listener from the event target. The handler must be the same object as the one added. + // If the handler has not been added then nothing is done. + removeEventListener(type:string, listener:GoogEventHandler, opt_capture?:boolean) : void; + + // Saves a copy of this document to a new file. After this function is called, all changes to this document no + // longer affect the old document and are instead saved to the new file. + // The provided file ID must refer to a valid file in Drive which does not have any Realtime data for your app. + // This function can also be used on an in-memory file to convert it to a Drive-connected file. + saveAs(fileId:string) : void; + } } From b496f1e760bbbc3256ae54a0cabda1263b60c55c Mon Sep 17 00:00:00 2001 From: Dustin Wehr Date: Sat, 13 Jun 2015 16:02:41 -0400 Subject: [PATCH 5/5] add gapi.drive.realtime.Collaborator --- .../google-drive-realtime-api.d.ts | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/google-drive-realtime-api/google-drive-realtime-api.d.ts b/google-drive-realtime-api/google-drive-realtime-api.d.ts index b1d970e3c..95f239a34 100644 --- a/google-drive-realtime-api/google-drive-realtime-api.d.ts +++ b/google-drive-realtime-api/google-drive-realtime-api.d.ts @@ -19,8 +19,41 @@ declare module gapi.drive.realtime { type GoogEventHandler = ((evt:ObjectChangedEvent) => void) | ((e:Event) => void) | EventListener; - // TODO - export class Collaborator {} + // Complete + // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.Collaborator + export class Collaborator { + // The HTML color associated with this collaborator. When possible, collaborators are assigned unique colors. + color : string; + + // The display name for this collaborator. + displayName : string; + + // True if this collaborator is anonymous, false otherwise. + isAnonymous : boolean + + // True if this collaborator is the local user, false otherwise. + isMe : boolean; + + // The permission ID for this collaborator. This ID is stable for a given user and is compatible with the + // Drive API permissions APIs. Use the userId property for all other uses. + permissionId : string; + + // A URL that points to the profile photo for this collaborator, or to a generic profile photo for + // anonymous collaborators. + photoUrl : string; + + // The session ID for this collaborator. A single user may have multiple sessions if they have the same document + // open on multiple devices or in multiple browser tabs. + sessionId : string; + + // The user ID for this collaborator. This ID is stable for a given user and is compatible with most Google APIs + // except the Drive API permission APIs. For an ID which is compatible with the Drive API permission APIs, + // use the permissionId property. + userId : string; + + new (sessionId:string, userId:string, displayName:string, color:string, isMe:boolean, isAnonymous:boolean, + photoUrl:string, permissionId:string) : Collaborator; + } // Complete // https://developers.google.com/google-apps/realtime/reference/gapi.drive.realtime.CollaborativeObject