From 4e434867daaa955275eaf150e5ef79c381152b60 Mon Sep 17 00:00:00 2001 From: hackerwins Date: Sat, 18 Apr 2020 21:31:08 +0900 Subject: [PATCH] Add RichText --- dist/quill.html | 156 +- docker/docker-compose.yml | 1 + package.json | 2 +- src/api/converter.ts | 130 +- src/api/yorkie.proto | 40 + src/api/yorkie_pb.d.ts | 223 + src/api/yorkie_pb.js | 3758 ++++++++++++----- src/core/client.ts | 6 + src/document/json/object.ts | 10 +- src/document/json/rga_tree_split.ts | 574 +++ src/document/json/rht.ts | 94 +- src/document/json/rht_pq_map.ts | 114 + src/document/json/rich_text.ts | 293 ++ src/document/json/text.ts | 577 +-- src/document/operation/edit_operation.ts | 18 +- src/document/operation/rich_edit_operation.ts | 111 + src/document/operation/select_operation.ts | 24 +- src/document/operation/style_operation.ts | 91 + src/document/proxy/object_proxy.ts | 21 +- src/document/proxy/proxy.ts | 5 + src/document/proxy/rich_text_proxy.ts | 151 + src/document/proxy/text_proxy.ts | 9 +- src/document/time/ticket.ts | 4 + 23 files changed, 4755 insertions(+), 1657 deletions(-) create mode 100644 src/document/json/rga_tree_split.ts create mode 100644 src/document/json/rht_pq_map.ts create mode 100644 src/document/json/rich_text.ts create mode 100644 src/document/operation/rich_edit_operation.ts create mode 100644 src/document/operation/style_operation.ts create mode 100644 src/document/proxy/rich_text_proxy.ts diff --git a/dist/quill.html b/dist/quill.html index 16752b753..18a62b4ea 100644 --- a/dist/quill.html +++ b/dist/quill.html @@ -26,6 +26,30 @@ textLogHolder.innerText = doc.getRootObject().content.getAnnotatedString(); } + function toDelta(doc) { + const obj = doc.getRootObject(); + const deltas = []; + for (const val of obj.content.getValue()) { + deltas.push({ + insert: val.content, + attributes: val.attributes, + }); + } + return deltas; + } + + function toAttributes(attrs) { + if (!attrs) { + return attrs; + } + + const attributes = {}; + for (const [k, v] of Object.entries(attrs)) { + attributes[k] = v ? String(v) : null; + } + return attributes; + } + async function main() { try { // 01. create client with RPCAddr(envoy) then activate it. @@ -38,7 +62,7 @@ doc.update((root) => { if (!root.content) { - root.createText('content'); + root.createRichText('content'); } }, 'create content if not exists'); doc.subscribe((event) => { @@ -73,33 +97,46 @@ // 04. bind the document with the Quill. // 04-1. Quill to Document. quill.on('text-change', (delta, oldDelta, source) => { - if (source === 'yorkie') { + if (source === 'yorkie' || !delta.ops) { return; } - console.log(JSON.stringify(delta)); - if (delta.ops) { - let from = 0; - let to = 0; - let content = ''; - for (const op of delta.ops) { - if (op.retain) { - from = op.retain; - to = from; - } else if (op.insert) { - content = op.insert; - } else if (op.delete) { + let from = 0, to = 0; + console.log(`%c quill: ${JSON.stringify(delta.ops)}`, 'color: green'); + for (const op of delta.ops) { + if (op.attributes !== undefined || op.insert !== undefined) { + if (op.retain !== undefined) { + to = from + op.retain; + } + console.log( + `%c local: ${from}-${to}: ${op.insert} ${op.attributes ? JSON.stringify(op.attributes) : '{}'}`, + 'color: green' + ); + + doc.update((root) => { + if (op.attributes !== undefined && op.insert === undefined) { + root.content.setStyle(from, to, toAttributes(op.attributes)); + } else if (op.insert !== undefined) { + root.content.edit(from, to, op.insert, toAttributes(op.attributes)); + from = to + op.insert.length; + } + }, `update style by ${client.getID()}`); + } else if (op.delete !== undefined) { + if (op.delete !== undefined) { to = from + op.delete; } - } + console.log(`%c local: ${from}-${to}: ''`, 'color: green'); - doc.update((root) => { - root.content.edit(from, to, content); - }, `update content by ${client.getID()}`); - console.log(`%c local: ${from}-${to}: ${content}`, 'color: green'); + doc.update((root) => { + root.content.edit(from, to, ''); + }, `update content by ${client.getID()}`); + } else if (op.retain !== undefined) { + from = to + op.retain; + to = from; + } } }).on('selection-change', (range, oldRange, source) => { - if (source === 'yorkie' || !range) { + if (source === 'yorkie' || source === 'api' || !range) { return; } @@ -112,44 +149,77 @@ const text = doc.getRootObject().content; text.onChanges((changes) => { const delta = []; + let prevTo = 0; for (const change of changes) { + const actor = change.actor; + if (actor === client.getID()) { + continue; + } + + const from = change.from; + const to = change.to; + const retainFrom = from - prevTo; + const retainTo = to - from; if (change.type === 'content') { - const actor = change.actor; - const from = change.from; - const to = change.to; const content = change.content || ''; + console.log( + `%c remote: ${from}-${to}: ${content}`, + 'color: skyblue' + ); - if (actor !== client.getID()) { - console.log(`%c remote: ${from}-${to}: ${content}`, 'color: skyblue'); - if (from > 0) { - delta.push({ retain: from }); - } - if (content) { - delta.push({ insert: content }); + if (retainFrom) { + delta.push({ retain: retainFrom }); + } + if (retainTo) { + delta.push({ delete: retainTo }); + } + if (content) { + const op = { insert: content }; + if (change.attributes) { + op.attributes = change.attributes; } - if (to - from > 0) { - delta.push({ delete: to - from }); + delta.push(op); + } + } else if (change.type === 'style') { + console.log( + `%c remote: ${from}-${to}: ${JSON.stringify(change.attributes)}`, + 'color: skyblue' + ); + + if (retainFrom) { + delta.push({ retain: retainFrom }); + } + if (change.attributes) { + const op = { attributes: change.attributes }; + if (retainTo) { + op.retain = retainTo; } + + delta.push(op); } } else if (change.type === 'selection') { - const actor = change.actor; - if (actor !== client.getID()) { - const cursors = quill.getModule('cursors'); - cursors.createCursor(actor, actor, colors[0]); - cursors.moveCursor(actor, { - index: change.from, - length: change.to - change.from - }); - } + const cursors = quill.getModule('cursors'); + cursors.createCursor(actor, actor, colors[0]); + cursors.moveCursor(actor, { + index: from, + length: retainTo + }); } + + prevTo = to; } - quill.updateContents(delta, 'yorkie'); + if (delta.length) { + console.log(`%c to quill: ${JSON.stringify(delta)}`, 'color: green'); + quill.updateContents(delta, 'yorkie'); + } }); // 05. set initial value. displayLog(doc); - quill.setText(text.getValue(), 'yorkie'); + quill.setContents({ + ops: toDelta(doc) + }, 'yorkie'); } catch (e) { console.error(e); } diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 306d03cc5..04bad267f 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -7,6 +7,7 @@ services: dockerfile: ./envoy.Dockerfile image: 'grpcweb:envoy' container_name: 'envoy' + restart: always ports: - '8080:8080' - '9901:9901' diff --git a/package.json b/package.json index 8000cf8fc..8215f690e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yorkie-js-sdk", - "version": "0.0.7", + "version": "0.0.8", "description": "Yorkie JS SDK", "main": "./src/yorkie.ts", "scripts": { diff --git a/src/api/converter.ts b/src/api/converter.ts index 38d73f296..9ec376fae 100644 --- a/src/api/converter.ts +++ b/src/api/converter.ts @@ -24,18 +24,22 @@ import { AddOperation } from '../document/operation/add_operation'; import { MoveOperation } from '../document/operation/move_operation'; import { RemoveOperation } from '../document/operation/remove_operation'; import { EditOperation } from '../document/operation/edit_operation'; +import { RichEditOperation } from '../document/operation/rich_edit_operation'; import { SelectOperation } from '../document/operation/select_operation'; +import { StyleOperation } from '../document/operation/style_operation'; import { DocumentKey } from '../document/key/document_key'; import { ChangeID } from '../document/change/change_id'; import { Change } from '../document/change/change'; import { ChangePack } from '../document/change/change_pack'; import { Checkpoint } from '../document/checkpoint/checkpoint'; -import { RHT } from '../document/json/rht'; +import { RHTPQMap } from '../document/json/rht_pq_map'; import { RGATreeList } from '../document/json/rga_tree_list'; import { JSONElement } from '../document/json/element'; import { JSONObject } from '../document/json/object'; import { JSONArray } from '../document/json/array'; -import { TextNodeID, TextNodePos, TextNode, RGATreeSplit, PlainText } from '../document/json/text'; +import { RGATreeSplitNodeID, RGATreeSplitNodePos, RGATreeSplitNode, RGATreeSplit } from '../document/json/rga_tree_split'; +import { PlainText } from '../document/json/text'; +import { RichText, RichTextValue } from '../document/json/rich_text'; import { JSONPrimitive, PrimitiveType } from '../document/json/primitive'; import { ChangePack as PbChangePack, @@ -50,6 +54,7 @@ import { RHTNode as PbRHTNode, RGANode as PbRGANode, TextNode as PbTextNode, + RichTextNode as PbRichTextNode, ValueType as PbValueType, TextNodeID as PbTextNodeID, TextNodePos as PbTextNodePos, @@ -127,6 +132,9 @@ function toJSONElementSimple(jsonElement: JSONElement): PbJSONElementSimple { } else if (jsonElement instanceof PlainText) { pbJSONElement.setType(PbValueType.TEXT); pbJSONElement.setCreatedAt(toTimeTicket(jsonElement.getCreatedAt())); + } else if (jsonElement instanceof RichText) { + pbJSONElement.setType(PbValueType.RICH_TEXT); + pbJSONElement.setCreatedAt(toTimeTicket(jsonElement.getCreatedAt())); } else if (jsonElement instanceof JSONPrimitive) { const primitive = jsonElement as JSONPrimitive; pbJSONElement.setType(toValueType(primitive.getType())); @@ -139,14 +147,14 @@ function toJSONElementSimple(jsonElement: JSONElement): PbJSONElementSimple { return pbJSONElement; } -function toTextNodeID(id: TextNodeID): PbTextNodeID { +function toTextNodeID(id: RGATreeSplitNodeID): PbTextNodeID { const pbTextNodeID = new PbTextNodeID(); pbTextNodeID.setCreatedAt(toTimeTicket(id.getCreatedAt())); pbTextNodeID.setOffset(id.getOffset()); return pbTextNodeID; } -function toTextNodePos(pos: TextNodePos): PbTextNodePos { +function toTextNodePos(pos: RGATreeSplitNodePos): PbTextNodePos { const pbTextNodePos = new PbTextNodePos(); pbTextNodePos.setCreatedAt(toTimeTicket(pos.getID().getCreatedAt())); pbTextNodePos.setOffset(pos.getID().getOffset()); @@ -209,6 +217,35 @@ function toOperation(operation: Operation): PbOperation { pbSelectOperation.setTo(toTextNodePos(selectOperation.getToPos())); pbSelectOperation.setExecutedAt(toTimeTicket(selectOperation.getExecutedAt())); pbOperation.setSelect(pbSelectOperation); + } else if (operation instanceof RichEditOperation) { + const richEditOperation = operation as RichEditOperation; + const pbRichEditOperation = new PbOperation.RichEdit(); + pbRichEditOperation.setParentCreatedAt(toTimeTicket(richEditOperation.getParentCreatedAt())); + pbRichEditOperation.setFrom(toTextNodePos(richEditOperation.getFromPos())); + pbRichEditOperation.setTo(toTextNodePos(richEditOperation.getToPos())); + const pbCreatedAtMapByActor = pbRichEditOperation.getCreatedAtMapByActorMap(); + for (const [key, value] of richEditOperation.getMaxCreatedAtMapByActor()) { + pbCreatedAtMapByActor.set(key, toTimeTicket(value)); + } + pbRichEditOperation.setContent(richEditOperation.getContent()); + const pbAttributes = pbRichEditOperation.getAttributesMap() + for (const [key, value] of richEditOperation.getAttributes()) { + pbAttributes.set(key, value); + } + pbRichEditOperation.setExecutedAt(toTimeTicket(richEditOperation.getExecutedAt())); + pbOperation.setRichEdit(pbRichEditOperation); + } else if (operation instanceof StyleOperation) { + const styleOperation = operation as StyleOperation; + const pbStyleOperation = new PbOperation.Style(); + pbStyleOperation.setParentCreatedAt(toTimeTicket(styleOperation.getParentCreatedAt())); + pbStyleOperation.setFrom(toTextNodePos(styleOperation.getFromPos())); + pbStyleOperation.setTo(toTextNodePos(styleOperation.getToPos())); + const pbAttributes = pbStyleOperation.getAttributesMap(); + for (const [key, value] of styleOperation.getAttributes()) { + pbAttributes.set(key, value); + } + pbStyleOperation.setExecutedAt(toTimeTicket(styleOperation.getExecutedAt())); + pbOperation.setStyle(pbStyleOperation); } else { throw new YorkieError(Code.Unimplemented, 'unimplemented operation'); } @@ -240,7 +277,7 @@ function toChanges(changes: Change[]): PbChange[] { return pbChanges; } -function toRHTNodes(rht: RHT): PbRHTNode[] { +function toRHTNodes(rht: RHTPQMap): PbRHTNode[] { const pbRHTNodes = [] for (const rhtNode of rht) { const pbRHTNode = new PbRHTNode(); @@ -408,6 +445,8 @@ function fromJSONElementSimple(pbJSONElement: PbJSONElementSimple): JSONElement return JSONArray.create(fromTimeTicket(pbJSONElement.getCreatedAt())); case PbValueType.TEXT: return PlainText.create(RGATreeSplit.create(), fromTimeTicket(pbJSONElement.getCreatedAt())); + case PbValueType.RICH_TEXT: + return RichText.create(RGATreeSplit.create(), fromTimeTicket(pbJSONElement.getCreatedAt())); case PbValueType.BOOLEAN: case PbValueType.INTEGER: case PbValueType.LONG: @@ -424,9 +463,9 @@ function fromJSONElementSimple(pbJSONElement: PbJSONElementSimple): JSONElement throw new YorkieError(Code.Unimplemented, `unimplemented element: ${pbJSONElement}`); } -function fromTextNodePos(pbTextNodePos: PbTextNodePos): TextNodePos { - return TextNodePos.of( - TextNodeID.of( +function fromTextNodePos(pbTextNodePos: PbTextNodePos): RGATreeSplitNodePos { + return RGATreeSplitNodePos.of( + RGATreeSplitNodeID.of( fromTimeTicket(pbTextNodePos.getCreatedAt()), pbTextNodePos.getOffset() ), @@ -434,15 +473,15 @@ function fromTextNodePos(pbTextNodePos: PbTextNodePos): TextNodePos { ); } -function fromTextNodeID(pbTextNodeID: PbTextNodeID): TextNodeID { - return TextNodeID.of( +function fromTextNodeID(pbTextNodeID: PbTextNodeID): RGATreeSplitNodeID { + return RGATreeSplitNodeID.of( fromTimeTicket(pbTextNodeID.getCreatedAt()), pbTextNodeID.getOffset() ); } -function fromTextNode(pbTextNode: PbTextNode): TextNode { - const textNode = TextNode.create( +function fromTextNode(pbTextNode: PbTextNode): RGATreeSplitNode { + const textNode = RGATreeSplitNode.create( fromTextNodeID(pbTextNode.getId()), pbTextNode.getValue() ); @@ -450,6 +489,15 @@ function fromTextNode(pbTextNode: PbTextNode): TextNode { return textNode; } +function fromRichTextNode(pbTextNode: PbRichTextNode): RGATreeSplitNode { + const textNode = RGATreeSplitNode.create( + fromTextNodeID(pbTextNode.getId()), + RichTextValue.create(pbTextNode.getValue()) + ); + textNode.remove(fromTimeTicket(pbTextNode.getRemovedAt())); + return textNode; +} + function fromOperations(pbOperations: PbOperation[]): Operation[] { const operations = []; @@ -508,6 +556,38 @@ function fromOperations(pbOperations: PbOperation[]): Operation[] { fromTextNodePos(pbSelectOperation.getTo()), fromTimeTicket(pbSelectOperation.getExecutedAt()), ); + } else if (pbOperation.hasRichEdit()) { + const pbEditOperation = pbOperation.getRichEdit(); + const createdAtMapByActor = new Map(); + pbEditOperation.getCreatedAtMapByActorMap().forEach((value, key) => { + createdAtMapByActor.set(key, fromTimeTicket(value)); + }); + const attributes = new Map(); + pbEditOperation.getAttributesMap().forEach((value, key) => { + attributes.set(key, value); + }); + operation = RichEditOperation.create( + fromTimeTicket(pbEditOperation.getParentCreatedAt()), + fromTextNodePos(pbEditOperation.getFrom()), + fromTextNodePos(pbEditOperation.getTo()), + createdAtMapByActor, + pbEditOperation.getContent(), + attributes, + fromTimeTicket(pbEditOperation.getExecutedAt()), + ); + } else if (pbOperation.hasStyle()) { + const pbStyleOperation = pbOperation.getStyle(); + const attributes = new Map(); + pbStyleOperation.getAttributesMap().forEach((value, key) => { + attributes.set(key, value); + }); + operation = StyleOperation.create( + fromTimeTicket(pbStyleOperation.getParentCreatedAt()), + fromTextNodePos(pbStyleOperation.getFrom()), + fromTextNodePos(pbStyleOperation.getTo()), + attributes, + fromTimeTicket(pbStyleOperation.getExecutedAt()), + ); } else { throw new YorkieError(Code.Unimplemented, `unimplemented operation`); } @@ -549,7 +629,7 @@ function fromChangePack(pbPack: PbChangePack): ChangePack { } function fromJSONObject(pbObject: PbJSONElement.Object): JSONObject { - const rht = new RHT(); + const rht = new RHTPQMap(); for (const pbRHTNode of pbObject.getNodesList()) { // eslint-disable-next-line rht.set(pbRHTNode.getKey(), fromJSONElement(pbRHTNode.getElement())); @@ -588,7 +668,7 @@ function fromJSONText(pbText: PbJSONElement.Text): PlainText { for (const pbNode of pbText.getNodesList()) { const current = rgaTreeSplit.insertAfter(prev, fromTextNode(pbNode)); if (pbNode.hasInsPrevId()) { - current.setInsPrev(rgaTreeSplit.findTextNode(fromTextNodeID(pbNode.getInsPrevID()))); + current.setInsPrev(rgaTreeSplit.findNode(fromTextNodeID(pbNode.getInsPrevID()))); } prev = current; } @@ -601,6 +681,26 @@ function fromJSONText(pbText: PbJSONElement.Text): PlainText { return text; } +function fromJSONRichText(pbText: PbJSONElement.RichText): RichText { + const rgaTreeSplit = new RGATreeSplit(); + + let prev = rgaTreeSplit.getHead(); + for (const pbNode of pbText.getNodesList()) { + const current = rgaTreeSplit.insertAfter(prev, fromRichTextNode(pbNode)); + if (pbNode.hasInsPrevId()) { + current.setInsPrev(rgaTreeSplit.findNode(fromTextNodeID(pbNode.getInsPrevID()))); + } + prev = current; + } + + const text = RichText.create( + rgaTreeSplit, + fromTimeTicket(pbText.getCreatedAt()), + ); + text.remove(fromTimeTicket(pbText.getRemovedAt())); + return text; +} + function fromJSONElement(pbJSONElement: PbJSONElement): JSONElement { if (pbJSONElement.hasObject()) { return fromJSONObject(pbJSONElement.getObject()); @@ -610,6 +710,8 @@ function fromJSONElement(pbJSONElement: PbJSONElement): JSONElement { return fromJSONPrimitive(pbJSONElement.getPrimitive()); } else if (pbJSONElement.hasText()) { return fromJSONText(pbJSONElement.getText()); + } else if (pbJSONElement.hasRichText()) { + return fromJSONRichText(pbJSONElement.getRichText()); } else { throw new YorkieError(Code.Unimplemented, `unimplemented element: ${pbJSONElement}`); } diff --git a/src/api/yorkie.proto b/src/api/yorkie.proto index bf12e1486..33502a205 100644 --- a/src/api/yorkie.proto +++ b/src/api/yorkie.proto @@ -159,6 +159,22 @@ message Operation { TextNodePos to = 3; TimeTicket executed_at = 4; } + message RichEdit { + TimeTicket parent_created_at = 1; + TextNodePos from = 2; + TextNodePos to = 3; + map created_at_map_by_actor = 4; + string content = 5; + map attributes = 6; + TimeTicket executed_at = 7; + } + message Style { + TimeTicket parent_created_at = 1; + TextNodePos from = 2; + TextNodePos to = 3; + map attributes = 4; + TimeTicket executed_at = 5; + } oneof body { Set set = 1; @@ -167,6 +183,8 @@ message Operation { Remove remove = 4; Edit edit = 5; Select select = 6; + RichEdit rich_edit = 7; + Style style = 8; } } @@ -208,12 +226,19 @@ message JSONElement { TimeTicket updated_at = 3; TimeTicket removed_at = 4; } + message RichText { + repeated RichTextNode nodes = 1; + TimeTicket created_at = 2; + TimeTicket updated_at = 3; + TimeTicket removed_at = 4; + } oneof Body { Object object = 1; Array array = 2; Primitive primitive = 3; Text text = 4; + RichText rich_text = 5; } } @@ -234,6 +259,20 @@ message TextNode { TextNodeID ins_prev_id = 4; } +message RichTextNodeAttr { + string key = 1; + string value = 2; + TimeTicket updated_at = 3; +} + +message RichTextNode { + TextNodeID id = 1; + map attributes = 2; + string value = 3; + TimeTicket removed_at = 4; + TextNodeID ins_prev_id = 5; +} + message TextNodeID { TimeTicket created_at = 1; int32 offset = 2; @@ -277,4 +316,5 @@ enum ValueType { JSON_OBJECT = 8; JSON_ARRAY = 9; TEXT = 10; + RICH_TEXT = 11; } diff --git a/src/api/yorkie_pb.d.ts b/src/api/yorkie_pb.d.ts index 5d2f0c066..852f46a57 100644 --- a/src/api/yorkie_pb.d.ts +++ b/src/api/yorkie_pb.d.ts @@ -447,6 +447,16 @@ export class Operation extends jspb.Message { hasSelect(): boolean; clearSelect(): void; + getRichEdit(): Operation.RichEdit | undefined; + setRichEdit(value?: Operation.RichEdit): void; + hasRichEdit(): boolean; + clearRichEdit(): void; + + getStyle(): Operation.Style | undefined; + setStyle(value?: Operation.Style): void; + hasStyle(): boolean; + clearStyle(): void; + getBodyCase(): Operation.BodyCase; serializeBinary(): Uint8Array; @@ -465,6 +475,8 @@ export namespace Operation { remove?: Operation.Remove.AsObject, edit?: Operation.Edit.AsObject, select?: Operation.Select.AsObject, + richEdit?: Operation.RichEdit.AsObject, + style?: Operation.Style.AsObject, } export class Set extends jspb.Message { @@ -701,6 +713,100 @@ export namespace Operation { } + export class RichEdit extends jspb.Message { + getParentCreatedAt(): TimeTicket | undefined; + setParentCreatedAt(value?: TimeTicket): void; + hasParentCreatedAt(): boolean; + clearParentCreatedAt(): void; + + getFrom(): TextNodePos | undefined; + setFrom(value?: TextNodePos): void; + hasFrom(): boolean; + clearFrom(): void; + + getTo(): TextNodePos | undefined; + setTo(value?: TextNodePos): void; + hasTo(): boolean; + clearTo(): void; + + getCreatedAtMapByActorMap(): jspb.Map; + clearCreatedAtMapByActorMap(): void; + + getContent(): string; + setContent(value: string): void; + + getAttributesMap(): jspb.Map; + clearAttributesMap(): void; + + getExecutedAt(): TimeTicket | undefined; + setExecutedAt(value?: TimeTicket): void; + hasExecutedAt(): boolean; + clearExecutedAt(): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RichEdit.AsObject; + static toObject(includeInstance: boolean, msg: RichEdit): RichEdit.AsObject; + static serializeBinaryToWriter(message: RichEdit, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RichEdit; + static deserializeBinaryFromReader(message: RichEdit, reader: jspb.BinaryReader): RichEdit; + } + + export namespace RichEdit { + export type AsObject = { + parentCreatedAt?: TimeTicket.AsObject, + from?: TextNodePos.AsObject, + to?: TextNodePos.AsObject, + createdAtMapByActorMap: Array<[string, TimeTicket.AsObject]>, + content: string, + attributesMap: Array<[string, string]>, + executedAt?: TimeTicket.AsObject, + } + } + + + export class Style extends jspb.Message { + getParentCreatedAt(): TimeTicket | undefined; + setParentCreatedAt(value?: TimeTicket): void; + hasParentCreatedAt(): boolean; + clearParentCreatedAt(): void; + + getFrom(): TextNodePos | undefined; + setFrom(value?: TextNodePos): void; + hasFrom(): boolean; + clearFrom(): void; + + getTo(): TextNodePos | undefined; + setTo(value?: TextNodePos): void; + hasTo(): boolean; + clearTo(): void; + + getAttributesMap(): jspb.Map; + clearAttributesMap(): void; + + getExecutedAt(): TimeTicket | undefined; + setExecutedAt(value?: TimeTicket): void; + hasExecutedAt(): boolean; + clearExecutedAt(): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): Style.AsObject; + static toObject(includeInstance: boolean, msg: Style): Style.AsObject; + static serializeBinaryToWriter(message: Style, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): Style; + static deserializeBinaryFromReader(message: Style, reader: jspb.BinaryReader): Style; + } + + export namespace Style { + export type AsObject = { + parentCreatedAt?: TimeTicket.AsObject, + from?: TextNodePos.AsObject, + to?: TextNodePos.AsObject, + attributesMap: Array<[string, string]>, + executedAt?: TimeTicket.AsObject, + } + } + + export enum BodyCase { BODY_NOT_SET = 0, SET = 1, @@ -709,6 +815,8 @@ export namespace Operation { REMOVE = 4, EDIT = 5, SELECT = 6, + RICH_EDIT = 7, + STYLE = 8, } } @@ -775,6 +883,11 @@ export class JSONElement extends jspb.Message { hasText(): boolean; clearText(): void; + getRichText(): JSONElement.RichText | undefined; + setRichText(value?: JSONElement.RichText): void; + hasRichText(): boolean; + clearRichText(): void; + getBodyCase(): JSONElement.BodyCase; serializeBinary(): Uint8Array; @@ -791,6 +904,7 @@ export namespace JSONElement { array?: JSONElement.Array.AsObject, primitive?: JSONElement.Primitive.AsObject, text?: JSONElement.Text.AsObject, + richText?: JSONElement.RichText.AsObject, } export class Object extends jspb.Message { @@ -953,12 +1067,52 @@ export namespace JSONElement { } + export class RichText extends jspb.Message { + getNodesList(): Array; + setNodesList(value: Array): void; + clearNodesList(): void; + addNodes(value?: RichTextNode, index?: number): RichTextNode; + + getCreatedAt(): TimeTicket | undefined; + setCreatedAt(value?: TimeTicket): void; + hasCreatedAt(): boolean; + clearCreatedAt(): void; + + getUpdatedAt(): TimeTicket | undefined; + setUpdatedAt(value?: TimeTicket): void; + hasUpdatedAt(): boolean; + clearUpdatedAt(): void; + + getRemovedAt(): TimeTicket | undefined; + setRemovedAt(value?: TimeTicket): void; + hasRemovedAt(): boolean; + clearRemovedAt(): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RichText.AsObject; + static toObject(includeInstance: boolean, msg: RichText): RichText.AsObject; + static serializeBinaryToWriter(message: RichText, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RichText; + static deserializeBinaryFromReader(message: RichText, reader: jspb.BinaryReader): RichText; + } + + export namespace RichText { + export type AsObject = { + nodesList: Array, + createdAt?: TimeTicket.AsObject, + updatedAt?: TimeTicket.AsObject, + removedAt?: TimeTicket.AsObject, + } + } + + export enum BodyCase { BODY_NOT_SET = 0, OBJECT = 1, ARRAY = 2, PRIMITIVE = 3, TEXT = 4, + RICH_TEXT = 5, } } @@ -1048,6 +1202,74 @@ export namespace TextNode { } } +export class RichTextNodeAttr extends jspb.Message { + getKey(): string; + setKey(value: string): void; + + getValue(): string; + setValue(value: string): void; + + getUpdatedAt(): TimeTicket | undefined; + setUpdatedAt(value?: TimeTicket): void; + hasUpdatedAt(): boolean; + clearUpdatedAt(): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RichTextNodeAttr.AsObject; + static toObject(includeInstance: boolean, msg: RichTextNodeAttr): RichTextNodeAttr.AsObject; + static serializeBinaryToWriter(message: RichTextNodeAttr, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RichTextNodeAttr; + static deserializeBinaryFromReader(message: RichTextNodeAttr, reader: jspb.BinaryReader): RichTextNodeAttr; +} + +export namespace RichTextNodeAttr { + export type AsObject = { + key: string, + value: string, + updatedAt?: TimeTicket.AsObject, + } +} + +export class RichTextNode extends jspb.Message { + getId(): TextNodeID | undefined; + setId(value?: TextNodeID): void; + hasId(): boolean; + clearId(): void; + + getAttributesMap(): jspb.Map; + clearAttributesMap(): void; + + getValue(): string; + setValue(value: string): void; + + getRemovedAt(): TimeTicket | undefined; + setRemovedAt(value?: TimeTicket): void; + hasRemovedAt(): boolean; + clearRemovedAt(): void; + + getInsPrevId(): TextNodeID | undefined; + setInsPrevId(value?: TextNodeID): void; + hasInsPrevId(): boolean; + clearInsPrevId(): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): RichTextNode.AsObject; + static toObject(includeInstance: boolean, msg: RichTextNode): RichTextNode.AsObject; + static serializeBinaryToWriter(message: RichTextNode, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): RichTextNode; + static deserializeBinaryFromReader(message: RichTextNode, reader: jspb.BinaryReader): RichTextNode; +} + +export namespace RichTextNode { + export type AsObject = { + id?: TextNodeID.AsObject, + attributesMap: Array<[string, RichTextNodeAttr.AsObject]>, + value: string, + removedAt?: TimeTicket.AsObject, + insPrevId?: TextNodeID.AsObject, + } +} + export class TextNodeID extends jspb.Message { getCreatedAt(): TimeTicket | undefined; setCreatedAt(value?: TimeTicket): void; @@ -1182,4 +1404,5 @@ export enum ValueType { JSON_OBJECT = 8, JSON_ARRAY = 9, TEXT = 10, + RICH_TEXT = 11, } diff --git a/src/api/yorkie_pb.js b/src/api/yorkie_pb.js index 02a04d0c4..b12692095 100644 --- a/src/api/yorkie_pb.js +++ b/src/api/yorkie_pb.js @@ -30,6 +30,7 @@ goog.exportSymbol('proto.api.JSONElement.Array', null, global); goog.exportSymbol('proto.api.JSONElement.BodyCase', null, global); goog.exportSymbol('proto.api.JSONElement.Object', null, global); goog.exportSymbol('proto.api.JSONElement.Primitive', null, global); +goog.exportSymbol('proto.api.JSONElement.RichText', null, global); goog.exportSymbol('proto.api.JSONElement.Text', null, global); goog.exportSymbol('proto.api.JSONElementSimple', null, global); goog.exportSymbol('proto.api.Operation', null, global); @@ -38,13 +39,17 @@ goog.exportSymbol('proto.api.Operation.BodyCase', null, global); goog.exportSymbol('proto.api.Operation.Edit', null, global); goog.exportSymbol('proto.api.Operation.Move', null, global); goog.exportSymbol('proto.api.Operation.Remove', null, global); +goog.exportSymbol('proto.api.Operation.RichEdit', null, global); goog.exportSymbol('proto.api.Operation.Select', null, global); goog.exportSymbol('proto.api.Operation.Set', null, global); +goog.exportSymbol('proto.api.Operation.Style', null, global); goog.exportSymbol('proto.api.PushPullRequest', null, global); goog.exportSymbol('proto.api.PushPullResponse', null, global); goog.exportSymbol('proto.api.RGANode', null, global); goog.exportSymbol('proto.api.RHTNode', null, global); goog.exportSymbol('proto.api.RequestHeader', null, global); +goog.exportSymbol('proto.api.RichTextNode', null, global); +goog.exportSymbol('proto.api.RichTextNodeAttr', null, global); goog.exportSymbol('proto.api.TextNode', null, global); goog.exportSymbol('proto.api.TextNodeID', null, global); goog.exportSymbol('proto.api.TextNodePos', null, global); @@ -535,6 +540,48 @@ if (goog.DEBUG && !COMPILED) { */ proto.api.Operation.Select.displayName = 'proto.api.Operation.Select'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.api.Operation.RichEdit = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.api.Operation.RichEdit, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.api.Operation.RichEdit.displayName = 'proto.api.Operation.RichEdit'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.api.Operation.Style = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.api.Operation.Style, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.api.Operation.Style.displayName = 'proto.api.Operation.Style'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -661,6 +708,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.api.JSONElement.Text.displayName = 'proto.api.JSONElement.Text'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.api.JSONElement.RichText = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.api.JSONElement.RichText.repeatedFields_, null); +}; +goog.inherits(proto.api.JSONElement.RichText, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.api.JSONElement.RichText.displayName = 'proto.api.JSONElement.RichText'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -724,6 +792,48 @@ if (goog.DEBUG && !COMPILED) { */ proto.api.TextNode.displayName = 'proto.api.TextNode'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.api.RichTextNodeAttr = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.api.RichTextNodeAttr, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.api.RichTextNodeAttr.displayName = 'proto.api.RichTextNodeAttr'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.api.RichTextNode = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.api.RichTextNode, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.api.RichTextNode.displayName = 'proto.api.RichTextNode'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -4037,7 +4147,7 @@ proto.api.ChangeID.prototype.setActorId = function(value) { * @private {!Array>} * @const */ -proto.api.Operation.oneofGroups_ = [[1,2,3,4,5,6]]; +proto.api.Operation.oneofGroups_ = [[1,2,3,4,5,6,7,8]]; /** * @enum {number} @@ -4049,7 +4159,9 @@ proto.api.Operation.BodyCase = { MOVE: 3, REMOVE: 4, EDIT: 5, - SELECT: 6 + SELECT: 6, + RICH_EDIT: 7, + STYLE: 8 }; /** @@ -4095,7 +4207,9 @@ proto.api.Operation.toObject = function(includeInstance, msg) { move: (f = msg.getMove()) && proto.api.Operation.Move.toObject(includeInstance, f), remove: (f = msg.getRemove()) && proto.api.Operation.Remove.toObject(includeInstance, f), edit: (f = msg.getEdit()) && proto.api.Operation.Edit.toObject(includeInstance, f), - select: (f = msg.getSelect()) && proto.api.Operation.Select.toObject(includeInstance, f) + select: (f = msg.getSelect()) && proto.api.Operation.Select.toObject(includeInstance, f), + richEdit: (f = msg.getRichEdit()) && proto.api.Operation.RichEdit.toObject(includeInstance, f), + style: (f = msg.getStyle()) && proto.api.Operation.Style.toObject(includeInstance, f) }; if (includeInstance) { @@ -4162,6 +4276,16 @@ proto.api.Operation.deserializeBinaryFromReader = function(msg, reader) { reader.readMessage(value,proto.api.Operation.Select.deserializeBinaryFromReader); msg.setSelect(value); break; + case 7: + var value = new proto.api.Operation.RichEdit; + reader.readMessage(value,proto.api.Operation.RichEdit.deserializeBinaryFromReader); + msg.setRichEdit(value); + break; + case 8: + var value = new proto.api.Operation.Style; + reader.readMessage(value,proto.api.Operation.Style.deserializeBinaryFromReader); + msg.setStyle(value); + break; default: reader.skipField(); break; @@ -4239,6 +4363,22 @@ proto.api.Operation.serializeBinaryToWriter = function(message, writer) { proto.api.Operation.Select.serializeBinaryToWriter ); } + f = message.getRichEdit(); + if (f != null) { + writer.writeMessage( + 7, + f, + proto.api.Operation.RichEdit.serializeBinaryToWriter + ); + } + f = message.getStyle(); + if (f != null) { + writer.writeMessage( + 8, + f, + proto.api.Operation.Style.serializeBinaryToWriter + ); + } }; @@ -6057,105 +6197,221 @@ proto.api.Operation.Select.prototype.hasExecutedAt = function() { }; -/** - * optional Set set = 1; - * @return {?proto.api.Operation.Set} - */ -proto.api.Operation.prototype.getSet = function() { - return /** @type{?proto.api.Operation.Set} */ ( - jspb.Message.getWrapperField(this, proto.api.Operation.Set, 1)); -}; - - -/** - * @param {?proto.api.Operation.Set|undefined} value - * @return {!proto.api.Operation} returns this -*/ -proto.api.Operation.prototype.setSet = function(value) { - return jspb.Message.setOneofWrapperField(this, 1, proto.api.Operation.oneofGroups_[0], value); -}; - -/** - * Clears the message field making it undefined. - * @return {!proto.api.Operation} returns this - */ -proto.api.Operation.prototype.clearSet = function() { - return this.setSet(undefined); -}; +if (jspb.Message.GENERATE_TO_OBJECT) { /** - * Returns whether this field is set. - * @return {boolean} + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} */ -proto.api.Operation.prototype.hasSet = function() { - return jspb.Message.getField(this, 1) != null; +proto.api.Operation.RichEdit.prototype.toObject = function(opt_includeInstance) { + return proto.api.Operation.RichEdit.toObject(opt_includeInstance, this); }; /** - * optional Add add = 2; - * @return {?proto.api.Operation.Add} + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.api.Operation.RichEdit} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.Operation.prototype.getAdd = function() { - return /** @type{?proto.api.Operation.Add} */ ( - jspb.Message.getWrapperField(this, proto.api.Operation.Add, 2)); -}; - +proto.api.Operation.RichEdit.toObject = function(includeInstance, msg) { + var f, obj = { + parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + from: (f = msg.getFrom()) && proto.api.TextNodePos.toObject(includeInstance, f), + to: (f = msg.getTo()) && proto.api.TextNodePos.toObject(includeInstance, f), + createdAtMapByActorMap: (f = msg.getCreatedAtMapByActorMap()) ? f.toObject(includeInstance, proto.api.TimeTicket.toObject) : [], + content: jspb.Message.getFieldWithDefault(msg, 5, ""), + attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, undefined) : [], + executedAt: (f = msg.getExecutedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) + }; -/** - * @param {?proto.api.Operation.Add|undefined} value - * @return {!proto.api.Operation} returns this -*/ -proto.api.Operation.prototype.setAdd = function(value) { - return jspb.Message.setOneofWrapperField(this, 2, proto.api.Operation.oneofGroups_[0], value); + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; }; +} /** - * Clears the message field making it undefined. - * @return {!proto.api.Operation} returns this + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.api.Operation.RichEdit} */ -proto.api.Operation.prototype.clearAdd = function() { - return this.setAdd(undefined); +proto.api.Operation.RichEdit.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.api.Operation.RichEdit; + return proto.api.Operation.RichEdit.deserializeBinaryFromReader(msg, reader); }; /** - * Returns whether this field is set. - * @return {boolean} + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.api.Operation.RichEdit} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.api.Operation.RichEdit} */ -proto.api.Operation.prototype.hasAdd = function() { - return jspb.Message.getField(this, 2) != null; +proto.api.Operation.RichEdit.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setParentCreatedAt(value); + break; + case 2: + var value = new proto.api.TextNodePos; + reader.readMessage(value,proto.api.TextNodePos.deserializeBinaryFromReader); + msg.setFrom(value); + break; + case 3: + var value = new proto.api.TextNodePos; + reader.readMessage(value,proto.api.TextNodePos.deserializeBinaryFromReader); + msg.setTo(value); + break; + case 4: + var value = msg.getCreatedAtMapByActorMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.api.TimeTicket.deserializeBinaryFromReader, "", new proto.api.TimeTicket()); + }); + break; + case 5: + var value = /** @type {string} */ (reader.readString()); + msg.setContent(value); + break; + case 6: + var value = msg.getAttributesMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "", ""); + }); + break; + case 7: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setExecutedAt(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; }; /** - * optional Move move = 3; - * @return {?proto.api.Operation.Move} + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} */ -proto.api.Operation.prototype.getMove = function() { - return /** @type{?proto.api.Operation.Move} */ ( - jspb.Message.getWrapperField(this, proto.api.Operation.Move, 3)); -}; - - -/** - * @param {?proto.api.Operation.Move|undefined} value - * @return {!proto.api.Operation} returns this -*/ -proto.api.Operation.prototype.setMove = function(value) { - return jspb.Message.setOneofWrapperField(this, 3, proto.api.Operation.oneofGroups_[0], value); +proto.api.Operation.RichEdit.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.api.Operation.RichEdit.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); }; /** - * Clears the message field making it undefined. - * @return {!proto.api.Operation} returns this + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.api.Operation.RichEdit} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.Operation.prototype.clearMove = function() { - return this.setMove(undefined); +proto.api.Operation.RichEdit.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getParentCreatedAt(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } + f = message.getFrom(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.api.TextNodePos.serializeBinaryToWriter + ); + } + f = message.getTo(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.api.TextNodePos.serializeBinaryToWriter + ); + } + f = message.getCreatedAtMapByActorMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(4, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.api.TimeTicket.serializeBinaryToWriter); + } + f = message.getContent(); + if (f.length > 0) { + writer.writeString( + 5, + f + ); + } + f = message.getAttributesMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(6, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); + } + f = message.getExecutedAt(); + if (f != null) { + writer.writeMessage( + 7, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } +}; + + +/** + * optional TimeTicket parent_created_at = 1; + * @return {?proto.api.TimeTicket} + */ +proto.api.Operation.RichEdit.prototype.getParentCreatedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 1)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.Operation.RichEdit} returns this +*/ +proto.api.Operation.RichEdit.prototype.setParentCreatedAt = function(value) { + return jspb.Message.setWrapperField(this, 1, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.Operation.RichEdit} returns this + */ +proto.api.Operation.RichEdit.prototype.clearParentCreatedAt = function() { + return this.setParentCreatedAt(undefined); }; @@ -6163,36 +6419,36 @@ proto.api.Operation.prototype.clearMove = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.Operation.prototype.hasMove = function() { - return jspb.Message.getField(this, 3) != null; +proto.api.Operation.RichEdit.prototype.hasParentCreatedAt = function() { + return jspb.Message.getField(this, 1) != null; }; /** - * optional Remove remove = 4; - * @return {?proto.api.Operation.Remove} + * optional TextNodePos from = 2; + * @return {?proto.api.TextNodePos} */ -proto.api.Operation.prototype.getRemove = function() { - return /** @type{?proto.api.Operation.Remove} */ ( - jspb.Message.getWrapperField(this, proto.api.Operation.Remove, 4)); +proto.api.Operation.RichEdit.prototype.getFrom = function() { + return /** @type{?proto.api.TextNodePos} */ ( + jspb.Message.getWrapperField(this, proto.api.TextNodePos, 2)); }; /** - * @param {?proto.api.Operation.Remove|undefined} value - * @return {!proto.api.Operation} returns this + * @param {?proto.api.TextNodePos|undefined} value + * @return {!proto.api.Operation.RichEdit} returns this */ -proto.api.Operation.prototype.setRemove = function(value) { - return jspb.Message.setOneofWrapperField(this, 4, proto.api.Operation.oneofGroups_[0], value); +proto.api.Operation.RichEdit.prototype.setFrom = function(value) { + return jspb.Message.setWrapperField(this, 2, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.Operation} returns this + * @return {!proto.api.Operation.RichEdit} returns this */ -proto.api.Operation.prototype.clearRemove = function() { - return this.setRemove(undefined); +proto.api.Operation.RichEdit.prototype.clearFrom = function() { + return this.setFrom(undefined); }; @@ -6200,36 +6456,36 @@ proto.api.Operation.prototype.clearRemove = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.Operation.prototype.hasRemove = function() { - return jspb.Message.getField(this, 4) != null; +proto.api.Operation.RichEdit.prototype.hasFrom = function() { + return jspb.Message.getField(this, 2) != null; }; /** - * optional Edit edit = 5; - * @return {?proto.api.Operation.Edit} + * optional TextNodePos to = 3; + * @return {?proto.api.TextNodePos} */ -proto.api.Operation.prototype.getEdit = function() { - return /** @type{?proto.api.Operation.Edit} */ ( - jspb.Message.getWrapperField(this, proto.api.Operation.Edit, 5)); +proto.api.Operation.RichEdit.prototype.getTo = function() { + return /** @type{?proto.api.TextNodePos} */ ( + jspb.Message.getWrapperField(this, proto.api.TextNodePos, 3)); }; /** - * @param {?proto.api.Operation.Edit|undefined} value - * @return {!proto.api.Operation} returns this + * @param {?proto.api.TextNodePos|undefined} value + * @return {!proto.api.Operation.RichEdit} returns this */ -proto.api.Operation.prototype.setEdit = function(value) { - return jspb.Message.setOneofWrapperField(this, 5, proto.api.Operation.oneofGroups_[0], value); +proto.api.Operation.RichEdit.prototype.setTo = function(value) { + return jspb.Message.setWrapperField(this, 3, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.Operation} returns this + * @return {!proto.api.Operation.RichEdit} returns this */ -proto.api.Operation.prototype.clearEdit = function() { - return this.setEdit(undefined); +proto.api.Operation.RichEdit.prototype.clearTo = function() { + return this.setTo(undefined); }; @@ -6237,36 +6493,98 @@ proto.api.Operation.prototype.clearEdit = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.Operation.prototype.hasEdit = function() { - return jspb.Message.getField(this, 5) != null; +proto.api.Operation.RichEdit.prototype.hasTo = function() { + return jspb.Message.getField(this, 3) != null; }; /** - * optional Select select = 6; - * @return {?proto.api.Operation.Select} + * map created_at_map_by_actor = 4; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} */ -proto.api.Operation.prototype.getSelect = function() { - return /** @type{?proto.api.Operation.Select} */ ( - jspb.Message.getWrapperField(this, proto.api.Operation.Select, 6)); +proto.api.Operation.RichEdit.prototype.getCreatedAtMapByActorMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 4, opt_noLazyCreate, + proto.api.TimeTicket)); }; /** - * @param {?proto.api.Operation.Select|undefined} value - * @return {!proto.api.Operation} returns this + * Clears values from the map. The map will be non-null. + * @return {!proto.api.Operation.RichEdit} returns this + */ +proto.api.Operation.RichEdit.prototype.clearCreatedAtMapByActorMap = function() { + this.getCreatedAtMapByActorMap().clear(); + return this;}; + + +/** + * optional string content = 5; + * @return {string} + */ +proto.api.Operation.RichEdit.prototype.getContent = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); +}; + + +/** + * @param {string} value + * @return {!proto.api.Operation.RichEdit} returns this + */ +proto.api.Operation.RichEdit.prototype.setContent = function(value) { + return jspb.Message.setProto3StringField(this, 5, value); +}; + + +/** + * map attributes = 6; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} + */ +proto.api.Operation.RichEdit.prototype.getAttributesMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 6, opt_noLazyCreate, + null)); +}; + + +/** + * Clears values from the map. The map will be non-null. + * @return {!proto.api.Operation.RichEdit} returns this + */ +proto.api.Operation.RichEdit.prototype.clearAttributesMap = function() { + this.getAttributesMap().clear(); + return this;}; + + +/** + * optional TimeTicket executed_at = 7; + * @return {?proto.api.TimeTicket} + */ +proto.api.Operation.RichEdit.prototype.getExecutedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 7)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.Operation.RichEdit} returns this */ -proto.api.Operation.prototype.setSelect = function(value) { - return jspb.Message.setOneofWrapperField(this, 6, proto.api.Operation.oneofGroups_[0], value); +proto.api.Operation.RichEdit.prototype.setExecutedAt = function(value) { + return jspb.Message.setWrapperField(this, 7, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.Operation} returns this + * @return {!proto.api.Operation.RichEdit} returns this */ -proto.api.Operation.prototype.clearSelect = function() { - return this.setSelect(undefined); +proto.api.Operation.RichEdit.prototype.clearExecutedAt = function() { + return this.setExecutedAt(undefined); }; @@ -6274,8 +6592,8 @@ proto.api.Operation.prototype.clearSelect = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.Operation.prototype.hasSelect = function() { - return jspb.Message.getField(this, 6) != null; +proto.api.Operation.RichEdit.prototype.hasExecutedAt = function() { + return jspb.Message.getField(this, 7) != null; }; @@ -6295,8 +6613,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.JSONElementSimple.prototype.toObject = function(opt_includeInstance) { - return proto.api.JSONElementSimple.toObject(opt_includeInstance, this); +proto.api.Operation.Style.prototype.toObject = function(opt_includeInstance) { + return proto.api.Operation.Style.toObject(opt_includeInstance, this); }; @@ -6305,17 +6623,17 @@ proto.api.JSONElementSimple.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.JSONElementSimple} msg The msg instance to transform. + * @param {!proto.api.Operation.Style} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElementSimple.toObject = function(includeInstance, msg) { +proto.api.Operation.Style.toObject = function(includeInstance, msg) { var f, obj = { - createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), - updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), - type: jspb.Message.getFieldWithDefault(msg, 4, 0), - value: msg.getValue_asB64() + parentCreatedAt: (f = msg.getParentCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + from: (f = msg.getFrom()) && proto.api.TextNodePos.toObject(includeInstance, f), + to: (f = msg.getTo()) && proto.api.TextNodePos.toObject(includeInstance, f), + attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, undefined) : [], + executedAt: (f = msg.getExecutedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) }; if (includeInstance) { @@ -6329,23 +6647,23 @@ proto.api.JSONElementSimple.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.JSONElementSimple} + * @return {!proto.api.Operation.Style} */ -proto.api.JSONElementSimple.deserializeBinary = function(bytes) { +proto.api.Operation.Style.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.JSONElementSimple; - return proto.api.JSONElementSimple.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.Operation.Style; + return proto.api.Operation.Style.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.JSONElementSimple} msg The message object to deserialize into. + * @param {!proto.api.Operation.Style} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.JSONElementSimple} + * @return {!proto.api.Operation.Style} */ -proto.api.JSONElementSimple.deserializeBinaryFromReader = function(msg, reader) { +proto.api.Operation.Style.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -6355,25 +6673,28 @@ proto.api.JSONElementSimple.deserializeBinaryFromReader = function(msg, reader) case 1: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); + msg.setParentCreatedAt(value); break; case 2: - var value = new proto.api.TimeTicket; - reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); - msg.setUpdatedAt(value); + var value = new proto.api.TextNodePos; + reader.readMessage(value,proto.api.TextNodePos.deserializeBinaryFromReader); + msg.setFrom(value); break; case 3: - var value = new proto.api.TimeTicket; - reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); + var value = new proto.api.TextNodePos; + reader.readMessage(value,proto.api.TextNodePos.deserializeBinaryFromReader); + msg.setTo(value); break; case 4: - var value = /** @type {!proto.api.ValueType} */ (reader.readEnum()); - msg.setType(value); + var value = msg.getAttributesMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, "", ""); + }); break; case 5: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setValue(value); + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setExecutedAt(value); break; default: reader.skipField(); @@ -6388,9 +6709,9 @@ proto.api.JSONElementSimple.deserializeBinaryFromReader = function(msg, reader) * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.JSONElementSimple.prototype.serializeBinary = function() { +proto.api.Operation.Style.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.JSONElementSimple.serializeBinaryToWriter(this, writer); + proto.api.Operation.Style.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -6398,13 +6719,13 @@ proto.api.JSONElementSimple.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.JSONElementSimple} message + * @param {!proto.api.Operation.Style} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElementSimple.serializeBinaryToWriter = function(message, writer) { +proto.api.Operation.Style.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getCreatedAt(); + f = message.getParentCreatedAt(); if (f != null) { writer.writeMessage( 1, @@ -6412,44 +6733,42 @@ proto.api.JSONElementSimple.serializeBinaryToWriter = function(message, writer) proto.api.TimeTicket.serializeBinaryToWriter ); } - f = message.getUpdatedAt(); + f = message.getFrom(); if (f != null) { writer.writeMessage( 2, f, - proto.api.TimeTicket.serializeBinaryToWriter + proto.api.TextNodePos.serializeBinaryToWriter ); } - f = message.getRemovedAt(); + f = message.getTo(); if (f != null) { writer.writeMessage( 3, f, - proto.api.TimeTicket.serializeBinaryToWriter + proto.api.TextNodePos.serializeBinaryToWriter ); } - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( - 4, - f - ); + f = message.getAttributesMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(4, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); } - f = message.getValue_asU8(); - if (f.length > 0) { - writer.writeBytes( + f = message.getExecutedAt(); + if (f != null) { + writer.writeMessage( 5, - f + f, + proto.api.TimeTicket.serializeBinaryToWriter ); } }; /** - * optional TimeTicket created_at = 1; + * optional TimeTicket parent_created_at = 1; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElementSimple.prototype.getCreatedAt = function() { +proto.api.Operation.Style.prototype.getParentCreatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( jspb.Message.getWrapperField(this, proto.api.TimeTicket, 1)); }; @@ -6457,19 +6776,19 @@ proto.api.JSONElementSimple.prototype.getCreatedAt = function() { /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElementSimple} returns this + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.setCreatedAt = function(value) { +proto.api.Operation.Style.prototype.setParentCreatedAt = function(value) { return jspb.Message.setWrapperField(this, 1, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElementSimple} returns this + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); +proto.api.Operation.Style.prototype.clearParentCreatedAt = function() { + return this.setParentCreatedAt(undefined); }; @@ -6477,36 +6796,36 @@ proto.api.JSONElementSimple.prototype.clearCreatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElementSimple.prototype.hasCreatedAt = function() { +proto.api.Operation.Style.prototype.hasParentCreatedAt = function() { return jspb.Message.getField(this, 1) != null; }; /** - * optional TimeTicket updated_at = 2; - * @return {?proto.api.TimeTicket} + * optional TextNodePos from = 2; + * @return {?proto.api.TextNodePos} */ -proto.api.JSONElementSimple.prototype.getUpdatedAt = function() { - return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 2)); +proto.api.Operation.Style.prototype.getFrom = function() { + return /** @type{?proto.api.TextNodePos} */ ( + jspb.Message.getWrapperField(this, proto.api.TextNodePos, 2)); }; /** - * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElementSimple} returns this + * @param {?proto.api.TextNodePos|undefined} value + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.setUpdatedAt = function(value) { +proto.api.Operation.Style.prototype.setFrom = function(value) { return jspb.Message.setWrapperField(this, 2, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElementSimple} returns this + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.clearUpdatedAt = function() { - return this.setUpdatedAt(undefined); +proto.api.Operation.Style.prototype.clearFrom = function() { + return this.setFrom(undefined); }; @@ -6514,36 +6833,36 @@ proto.api.JSONElementSimple.prototype.clearUpdatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElementSimple.prototype.hasUpdatedAt = function() { +proto.api.Operation.Style.prototype.hasFrom = function() { return jspb.Message.getField(this, 2) != null; }; /** - * optional TimeTicket removed_at = 3; - * @return {?proto.api.TimeTicket} + * optional TextNodePos to = 3; + * @return {?proto.api.TextNodePos} */ -proto.api.JSONElementSimple.prototype.getRemovedAt = function() { - return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); +proto.api.Operation.Style.prototype.getTo = function() { + return /** @type{?proto.api.TextNodePos} */ ( + jspb.Message.getWrapperField(this, proto.api.TextNodePos, 3)); }; /** - * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElementSimple} returns this + * @param {?proto.api.TextNodePos|undefined} value + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.setRemovedAt = function(value) { +proto.api.Operation.Style.prototype.setTo = function(value) { return jspb.Message.setWrapperField(this, 3, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElementSimple} returns this + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); +proto.api.Operation.Style.prototype.clearTo = function() { + return this.setTo(undefined); }; @@ -6551,262 +6870,366 @@ proto.api.JSONElementSimple.prototype.clearRemovedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElementSimple.prototype.hasRemovedAt = function() { +proto.api.Operation.Style.prototype.hasTo = function() { return jspb.Message.getField(this, 3) != null; }; /** - * optional ValueType type = 4; - * @return {!proto.api.ValueType} + * map attributes = 4; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} */ -proto.api.JSONElementSimple.prototype.getType = function() { - return /** @type {!proto.api.ValueType} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); +proto.api.Operation.Style.prototype.getAttributesMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 4, opt_noLazyCreate, + null)); }; /** - * @param {!proto.api.ValueType} value - * @return {!proto.api.JSONElementSimple} returns this + * Clears values from the map. The map will be non-null. + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.setType = function(value) { - return jspb.Message.setProto3EnumField(this, 4, value); -}; +proto.api.Operation.Style.prototype.clearAttributesMap = function() { + this.getAttributesMap().clear(); + return this;}; /** - * optional bytes value = 5; - * @return {string} + * optional TimeTicket executed_at = 5; + * @return {?proto.api.TimeTicket} */ -proto.api.JSONElementSimple.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); +proto.api.Operation.Style.prototype.getExecutedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 5)); }; /** - * optional bytes value = 5; - * This is a type-conversion wrapper around `getValue()` - * @return {string} + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.Operation.Style} returns this +*/ +proto.api.Operation.Style.prototype.setExecutedAt = function(value) { + return jspb.Message.setWrapperField(this, 5, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.Operation.Style} returns this */ -proto.api.JSONElementSimple.prototype.getValue_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getValue())); +proto.api.Operation.Style.prototype.clearExecutedAt = function() { + return this.setExecutedAt(undefined); }; /** - * optional bytes value = 5; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getValue()` - * @return {!Uint8Array} + * Returns whether this field is set. + * @return {boolean} */ -proto.api.JSONElementSimple.prototype.getValue_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getValue())); +proto.api.Operation.Style.prototype.hasExecutedAt = function() { + return jspb.Message.getField(this, 5) != null; }; /** - * @param {!(string|Uint8Array)} value - * @return {!proto.api.JSONElementSimple} returns this + * optional Set set = 1; + * @return {?proto.api.Operation.Set} */ -proto.api.JSONElementSimple.prototype.setValue = function(value) { - return jspb.Message.setProto3BytesField(this, 5, value); +proto.api.Operation.prototype.getSet = function() { + return /** @type{?proto.api.Operation.Set} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.Set, 1)); }; +/** + * @param {?proto.api.Operation.Set|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setSet = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.api.Operation.oneofGroups_[0], value); +}; + /** - * Oneof group definitions for this message. Each group defines the field - * numbers belonging to that group. When of these fields' value is set, all - * other fields in the group are cleared. During deserialization, if multiple - * fields are encountered for a group, only the last value seen will be kept. - * @private {!Array>} - * @const + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this */ -proto.api.JSONElement.oneofGroups_ = [[1,2,3,4]]; +proto.api.Operation.prototype.clearSet = function() { + return this.setSet(undefined); +}; + /** - * @enum {number} + * Returns whether this field is set. + * @return {boolean} */ -proto.api.JSONElement.BodyCase = { - BODY_NOT_SET: 0, - OBJECT: 1, - ARRAY: 2, - PRIMITIVE: 3, - TEXT: 4 +proto.api.Operation.prototype.hasSet = function() { + return jspb.Message.getField(this, 1) != null; }; + /** - * @return {proto.api.JSONElement.BodyCase} + * optional Add add = 2; + * @return {?proto.api.Operation.Add} */ -proto.api.JSONElement.prototype.getBodyCase = function() { - return /** @type {proto.api.JSONElement.BodyCase} */(jspb.Message.computeOneofCase(this, proto.api.JSONElement.oneofGroups_[0])); +proto.api.Operation.prototype.getAdd = function() { + return /** @type{?proto.api.Operation.Add} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.Add, 2)); }; +/** + * @param {?proto.api.Operation.Add|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setAdd = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.api.Operation.oneofGroups_[0], value); +}; + -if (jspb.Message.GENERATE_TO_OBJECT) { /** - * Creates an object representation of this proto. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * Optional fields that are not set will be set to undefined. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * net/proto2/compiler/js/internal/generator.cc#kKeyword. - * @param {boolean=} opt_includeInstance Deprecated. whether to include the - * JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @return {!Object} + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this */ -proto.api.JSONElement.prototype.toObject = function(opt_includeInstance) { - return proto.api.JSONElement.toObject(opt_includeInstance, this); +proto.api.Operation.prototype.clearAdd = function() { + return this.setAdd(undefined); }; /** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Deprecated. Whether to include - * the JSPB instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.api.JSONElement} msg The msg instance to transform. - * @return {!Object} - * @suppress {unusedLocalVariables} f is only used for nested messages + * Returns whether this field is set. + * @return {boolean} */ -proto.api.JSONElement.toObject = function(includeInstance, msg) { - var f, obj = { - object: (f = msg.getObject()) && proto.api.JSONElement.Object.toObject(includeInstance, f), - array: (f = msg.getArray()) && proto.api.JSONElement.Array.toObject(includeInstance, f), - primitive: (f = msg.getPrimitive()) && proto.api.JSONElement.Primitive.toObject(includeInstance, f), - text: (f = msg.getText()) && proto.api.JSONElement.Text.toObject(includeInstance, f) - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; +proto.api.Operation.prototype.hasAdd = function() { + return jspb.Message.getField(this, 2) != null; }; -} /** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.JSONElement} + * optional Move move = 3; + * @return {?proto.api.Operation.Move} */ -proto.api.JSONElement.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.JSONElement; - return proto.api.JSONElement.deserializeBinaryFromReader(msg, reader); +proto.api.Operation.prototype.getMove = function() { + return /** @type{?proto.api.Operation.Move} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.Move, 3)); }; /** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.api.JSONElement} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.JSONElement} - */ -proto.api.JSONElement.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = new proto.api.JSONElement.Object; - reader.readMessage(value,proto.api.JSONElement.Object.deserializeBinaryFromReader); - msg.setObject(value); - break; - case 2: - var value = new proto.api.JSONElement.Array; - reader.readMessage(value,proto.api.JSONElement.Array.deserializeBinaryFromReader); - msg.setArray(value); - break; - case 3: - var value = new proto.api.JSONElement.Primitive; - reader.readMessage(value,proto.api.JSONElement.Primitive.deserializeBinaryFromReader); - msg.setPrimitive(value); - break; - case 4: - var value = new proto.api.JSONElement.Text; - reader.readMessage(value,proto.api.JSONElement.Text.deserializeBinaryFromReader); - msg.setText(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; + * @param {?proto.api.Operation.Move|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setMove = function(value) { + return jspb.Message.setOneofWrapperField(this, 3, proto.api.Operation.oneofGroups_[0], value); }; /** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this */ -proto.api.JSONElement.prototype.serializeBinary = function() { - var writer = new jspb.BinaryWriter(); - proto.api.JSONElement.serializeBinaryToWriter(this, writer); - return writer.getResultBuffer(); +proto.api.Operation.prototype.clearMove = function() { + return this.setMove(undefined); }; /** - * Serializes the given message to binary data (in protobuf wire - * format), writing to the given BinaryWriter. - * @param {!proto.api.JSONElement} message - * @param {!jspb.BinaryWriter} writer - * @suppress {unusedLocalVariables} f is only used for nested messages + * Returns whether this field is set. + * @return {boolean} */ -proto.api.JSONElement.serializeBinaryToWriter = function(message, writer) { - var f = undefined; - f = message.getObject(); - if (f != null) { - writer.writeMessage( - 1, - f, - proto.api.JSONElement.Object.serializeBinaryToWriter - ); - } - f = message.getArray(); - if (f != null) { - writer.writeMessage( - 2, - f, - proto.api.JSONElement.Array.serializeBinaryToWriter - ); - } - f = message.getPrimitive(); - if (f != null) { - writer.writeMessage( - 3, - f, - proto.api.JSONElement.Primitive.serializeBinaryToWriter - ); - } - f = message.getText(); - if (f != null) { - writer.writeMessage( - 4, - f, - proto.api.JSONElement.Text.serializeBinaryToWriter - ); - } +proto.api.Operation.prototype.hasMove = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional Remove remove = 4; + * @return {?proto.api.Operation.Remove} + */ +proto.api.Operation.prototype.getRemove = function() { + return /** @type{?proto.api.Operation.Remove} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.Remove, 4)); }; +/** + * @param {?proto.api.Operation.Remove|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setRemove = function(value) { + return jspb.Message.setOneofWrapperField(this, 4, proto.api.Operation.oneofGroups_[0], value); +}; + /** - * List of repeated fields within this message type. - * @private {!Array} - * @const + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this */ -proto.api.JSONElement.Object.repeatedFields_ = [1]; +proto.api.Operation.prototype.clearRemove = function() { + return this.setRemove(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.Operation.prototype.hasRemove = function() { + return jspb.Message.getField(this, 4) != null; +}; + + +/** + * optional Edit edit = 5; + * @return {?proto.api.Operation.Edit} + */ +proto.api.Operation.prototype.getEdit = function() { + return /** @type{?proto.api.Operation.Edit} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.Edit, 5)); +}; + + +/** + * @param {?proto.api.Operation.Edit|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setEdit = function(value) { + return jspb.Message.setOneofWrapperField(this, 5, proto.api.Operation.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this + */ +proto.api.Operation.prototype.clearEdit = function() { + return this.setEdit(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.Operation.prototype.hasEdit = function() { + return jspb.Message.getField(this, 5) != null; +}; + + +/** + * optional Select select = 6; + * @return {?proto.api.Operation.Select} + */ +proto.api.Operation.prototype.getSelect = function() { + return /** @type{?proto.api.Operation.Select} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.Select, 6)); +}; + + +/** + * @param {?proto.api.Operation.Select|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setSelect = function(value) { + return jspb.Message.setOneofWrapperField(this, 6, proto.api.Operation.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this + */ +proto.api.Operation.prototype.clearSelect = function() { + return this.setSelect(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.Operation.prototype.hasSelect = function() { + return jspb.Message.getField(this, 6) != null; +}; + + +/** + * optional RichEdit rich_edit = 7; + * @return {?proto.api.Operation.RichEdit} + */ +proto.api.Operation.prototype.getRichEdit = function() { + return /** @type{?proto.api.Operation.RichEdit} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.RichEdit, 7)); +}; + + +/** + * @param {?proto.api.Operation.RichEdit|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setRichEdit = function(value) { + return jspb.Message.setOneofWrapperField(this, 7, proto.api.Operation.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this + */ +proto.api.Operation.prototype.clearRichEdit = function() { + return this.setRichEdit(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.Operation.prototype.hasRichEdit = function() { + return jspb.Message.getField(this, 7) != null; +}; + + +/** + * optional Style style = 8; + * @return {?proto.api.Operation.Style} + */ +proto.api.Operation.prototype.getStyle = function() { + return /** @type{?proto.api.Operation.Style} */ ( + jspb.Message.getWrapperField(this, proto.api.Operation.Style, 8)); +}; + + +/** + * @param {?proto.api.Operation.Style|undefined} value + * @return {!proto.api.Operation} returns this +*/ +proto.api.Operation.prototype.setStyle = function(value) { + return jspb.Message.setOneofWrapperField(this, 8, proto.api.Operation.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.Operation} returns this + */ +proto.api.Operation.prototype.clearStyle = function() { + return this.setStyle(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.Operation.prototype.hasStyle = function() { + return jspb.Message.getField(this, 8) != null; +}; + + @@ -6823,8 +7246,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.JSONElement.Object.prototype.toObject = function(opt_includeInstance) { - return proto.api.JSONElement.Object.toObject(opt_includeInstance, this); +proto.api.JSONElementSimple.prototype.toObject = function(opt_includeInstance) { + return proto.api.JSONElementSimple.toObject(opt_includeInstance, this); }; @@ -6833,17 +7256,17 @@ proto.api.JSONElement.Object.prototype.toObject = function(opt_includeInstance) * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.JSONElement.Object} msg The msg instance to transform. + * @param {!proto.api.JSONElementSimple} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Object.toObject = function(includeInstance, msg) { +proto.api.JSONElementSimple.toObject = function(includeInstance, msg) { var f, obj = { - nodesList: jspb.Message.toObjectList(msg.getNodesList(), - proto.api.RHTNode.toObject, includeInstance), createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) + removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + type: jspb.Message.getFieldWithDefault(msg, 4, 0), + value: msg.getValue_asB64() }; if (includeInstance) { @@ -6857,23 +7280,23 @@ proto.api.JSONElement.Object.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.JSONElement.Object} + * @return {!proto.api.JSONElementSimple} */ -proto.api.JSONElement.Object.deserializeBinary = function(bytes) { +proto.api.JSONElementSimple.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.JSONElement.Object; - return proto.api.JSONElement.Object.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.JSONElementSimple; + return proto.api.JSONElementSimple.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.JSONElement.Object} msg The message object to deserialize into. + * @param {!proto.api.JSONElementSimple} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.JSONElement.Object} + * @return {!proto.api.JSONElementSimple} */ -proto.api.JSONElement.Object.deserializeBinaryFromReader = function(msg, reader) { +proto.api.JSONElementSimple.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -6881,25 +7304,28 @@ proto.api.JSONElement.Object.deserializeBinaryFromReader = function(msg, reader) var field = reader.getFieldNumber(); switch (field) { case 1: - var value = new proto.api.RHTNode; - reader.readMessage(value,proto.api.RHTNode.deserializeBinaryFromReader); - msg.addNodes(value); - break; - case 2: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setCreatedAt(value); break; - case 3: + case 2: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setUpdatedAt(value); break; - case 4: + case 3: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setRemovedAt(value); break; + case 4: + var value = /** @type {!proto.api.ValueType} */ (reader.readEnum()); + msg.setType(value); + break; + case 5: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setValue(value); + break; default: reader.skipField(); break; @@ -6913,9 +7339,9 @@ proto.api.JSONElement.Object.deserializeBinaryFromReader = function(msg, reader) * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.JSONElement.Object.prototype.serializeBinary = function() { +proto.api.JSONElementSimple.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.JSONElement.Object.serializeBinaryToWriter(this, writer); + proto.api.JSONElementSimple.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -6923,24 +7349,16 @@ proto.api.JSONElement.Object.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.JSONElement.Object} message + * @param {!proto.api.JSONElementSimple} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Object.serializeBinaryToWriter = function(message, writer) { +proto.api.JSONElementSimple.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getNodesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( - 1, - f, - proto.api.RHTNode.serializeBinaryToWriter - ); - } f = message.getCreatedAt(); if (f != null) { writer.writeMessage( - 2, + 1, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -6948,7 +7366,7 @@ proto.api.JSONElement.Object.serializeBinaryToWriter = function(message, writer) f = message.getUpdatedAt(); if (f != null) { writer.writeMessage( - 3, + 2, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -6956,57 +7374,70 @@ proto.api.JSONElement.Object.serializeBinaryToWriter = function(message, writer) f = message.getRemovedAt(); if (f != null) { writer.writeMessage( - 4, + 3, f, proto.api.TimeTicket.serializeBinaryToWriter ); } + f = message.getType(); + if (f !== 0.0) { + writer.writeEnum( + 4, + f + ); + } + f = message.getValue_asU8(); + if (f.length > 0) { + writer.writeBytes( + 5, + f + ); + } }; /** - * repeated RHTNode nodes = 1; - * @return {!Array} + * optional TimeTicket created_at = 1; + * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Object.prototype.getNodesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.api.RHTNode, 1)); +proto.api.JSONElementSimple.prototype.getCreatedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 1)); }; /** - * @param {!Array} value - * @return {!proto.api.JSONElement.Object} returns this + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.JSONElementSimple} returns this */ -proto.api.JSONElement.Object.prototype.setNodesList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 1, value); +proto.api.JSONElementSimple.prototype.setCreatedAt = function(value) { + return jspb.Message.setWrapperField(this, 1, value); }; /** - * @param {!proto.api.RHTNode=} opt_value - * @param {number=} opt_index - * @return {!proto.api.RHTNode} + * Clears the message field making it undefined. + * @return {!proto.api.JSONElementSimple} returns this */ -proto.api.JSONElement.Object.prototype.addNodes = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.api.RHTNode, opt_index); +proto.api.JSONElementSimple.prototype.clearCreatedAt = function() { + return this.setCreatedAt(undefined); }; /** - * Clears the list making it empty but non-null. - * @return {!proto.api.JSONElement.Object} returns this + * Returns whether this field is set. + * @return {boolean} */ -proto.api.JSONElement.Object.prototype.clearNodesList = function() { - return this.setNodesList([]); +proto.api.JSONElementSimple.prototype.hasCreatedAt = function() { + return jspb.Message.getField(this, 1) != null; }; /** - * optional TimeTicket created_at = 2; + * optional TimeTicket updated_at = 2; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Object.prototype.getCreatedAt = function() { +proto.api.JSONElementSimple.prototype.getUpdatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( jspb.Message.getWrapperField(this, proto.api.TimeTicket, 2)); }; @@ -7014,19 +7445,19 @@ proto.api.JSONElement.Object.prototype.getCreatedAt = function() { /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Object} returns this + * @return {!proto.api.JSONElementSimple} returns this */ -proto.api.JSONElement.Object.prototype.setCreatedAt = function(value) { +proto.api.JSONElementSimple.prototype.setUpdatedAt = function(value) { return jspb.Message.setWrapperField(this, 2, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Object} returns this + * @return {!proto.api.JSONElementSimple} returns this */ -proto.api.JSONElement.Object.prototype.clearCreatedAt = function() { - return this.setCreatedAt(undefined); +proto.api.JSONElementSimple.prototype.clearUpdatedAt = function() { + return this.setUpdatedAt(undefined); }; @@ -7034,16 +7465,16 @@ proto.api.JSONElement.Object.prototype.clearCreatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Object.prototype.hasCreatedAt = function() { +proto.api.JSONElementSimple.prototype.hasUpdatedAt = function() { return jspb.Message.getField(this, 2) != null; }; /** - * optional TimeTicket updated_at = 3; + * optional TimeTicket removed_at = 3; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Object.prototype.getUpdatedAt = function() { +proto.api.JSONElementSimple.prototype.getRemovedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); }; @@ -7051,19 +7482,19 @@ proto.api.JSONElement.Object.prototype.getUpdatedAt = function() { /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Object} returns this + * @return {!proto.api.JSONElementSimple} returns this */ -proto.api.JSONElement.Object.prototype.setUpdatedAt = function(value) { +proto.api.JSONElementSimple.prototype.setRemovedAt = function(value) { return jspb.Message.setWrapperField(this, 3, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Object} returns this + * @return {!proto.api.JSONElementSimple} returns this */ -proto.api.JSONElement.Object.prototype.clearUpdatedAt = function() { - return this.setUpdatedAt(undefined); +proto.api.JSONElementSimple.prototype.clearRemovedAt = function() { + return this.setRemovedAt(undefined); }; @@ -7071,55 +7502,100 @@ proto.api.JSONElement.Object.prototype.clearUpdatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Object.prototype.hasUpdatedAt = function() { +proto.api.JSONElementSimple.prototype.hasRemovedAt = function() { return jspb.Message.getField(this, 3) != null; }; /** - * optional TimeTicket removed_at = 4; - * @return {?proto.api.TimeTicket} + * optional ValueType type = 4; + * @return {!proto.api.ValueType} */ -proto.api.JSONElement.Object.prototype.getRemovedAt = function() { - return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); +proto.api.JSONElementSimple.prototype.getType = function() { + return /** @type {!proto.api.ValueType} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); }; /** - * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Object} returns this -*/ -proto.api.JSONElement.Object.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); + * @param {!proto.api.ValueType} value + * @return {!proto.api.JSONElementSimple} returns this + */ +proto.api.JSONElementSimple.prototype.setType = function(value) { + return jspb.Message.setProto3EnumField(this, 4, value); }; /** - * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Object} returns this + * optional bytes value = 5; + * @return {string} */ -proto.api.JSONElement.Object.prototype.clearRemovedAt = function() { - return this.setRemovedAt(undefined); +proto.api.JSONElementSimple.prototype.getValue = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 5, "")); }; /** - * Returns whether this field is set. - * @return {boolean} + * optional bytes value = 5; + * This is a type-conversion wrapper around `getValue()` + * @return {string} */ -proto.api.JSONElement.Object.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 4) != null; +proto.api.JSONElementSimple.prototype.getValue_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getValue())); +}; + + +/** + * optional bytes value = 5; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getValue()` + * @return {!Uint8Array} + */ +proto.api.JSONElementSimple.prototype.getValue_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getValue())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.api.JSONElementSimple} returns this + */ +proto.api.JSONElementSimple.prototype.setValue = function(value) { + return jspb.Message.setProto3BytesField(this, 5, value); }; /** - * List of repeated fields within this message type. - * @private {!Array} + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} * @const */ -proto.api.JSONElement.Array.repeatedFields_ = [1]; +proto.api.JSONElement.oneofGroups_ = [[1,2,3,4,5]]; + +/** + * @enum {number} + */ +proto.api.JSONElement.BodyCase = { + BODY_NOT_SET: 0, + OBJECT: 1, + ARRAY: 2, + PRIMITIVE: 3, + TEXT: 4, + RICH_TEXT: 5 +}; + +/** + * @return {proto.api.JSONElement.BodyCase} + */ +proto.api.JSONElement.prototype.getBodyCase = function() { + return /** @type {proto.api.JSONElement.BodyCase} */(jspb.Message.computeOneofCase(this, proto.api.JSONElement.oneofGroups_[0])); +}; @@ -7136,8 +7612,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.JSONElement.Array.prototype.toObject = function(opt_includeInstance) { - return proto.api.JSONElement.Array.toObject(opt_includeInstance, this); +proto.api.JSONElement.prototype.toObject = function(opt_includeInstance) { + return proto.api.JSONElement.toObject(opt_includeInstance, this); }; @@ -7146,17 +7622,17 @@ proto.api.JSONElement.Array.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.JSONElement.Array} msg The msg instance to transform. + * @param {!proto.api.JSONElement} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Array.toObject = function(includeInstance, msg) { +proto.api.JSONElement.toObject = function(includeInstance, msg) { var f, obj = { - nodesList: jspb.Message.toObjectList(msg.getNodesList(), - proto.api.RGANode.toObject, includeInstance), - createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), - updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), - removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) + object: (f = msg.getObject()) && proto.api.JSONElement.Object.toObject(includeInstance, f), + array: (f = msg.getArray()) && proto.api.JSONElement.Array.toObject(includeInstance, f), + primitive: (f = msg.getPrimitive()) && proto.api.JSONElement.Primitive.toObject(includeInstance, f), + text: (f = msg.getText()) && proto.api.JSONElement.Text.toObject(includeInstance, f), + richText: (f = msg.getRichText()) && proto.api.JSONElement.RichText.toObject(includeInstance, f) }; if (includeInstance) { @@ -7170,23 +7646,23 @@ proto.api.JSONElement.Array.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.JSONElement.Array} + * @return {!proto.api.JSONElement} */ -proto.api.JSONElement.Array.deserializeBinary = function(bytes) { +proto.api.JSONElement.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.JSONElement.Array; - return proto.api.JSONElement.Array.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.JSONElement; + return proto.api.JSONElement.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.JSONElement.Array} msg The message object to deserialize into. + * @param {!proto.api.JSONElement} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.JSONElement.Array} + * @return {!proto.api.JSONElement} */ -proto.api.JSONElement.Array.deserializeBinaryFromReader = function(msg, reader) { +proto.api.JSONElement.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -7194,24 +7670,29 @@ proto.api.JSONElement.Array.deserializeBinaryFromReader = function(msg, reader) var field = reader.getFieldNumber(); switch (field) { case 1: - var value = new proto.api.RGANode; - reader.readMessage(value,proto.api.RGANode.deserializeBinaryFromReader); - msg.addNodes(value); + var value = new proto.api.JSONElement.Object; + reader.readMessage(value,proto.api.JSONElement.Object.deserializeBinaryFromReader); + msg.setObject(value); break; case 2: - var value = new proto.api.TimeTicket; - reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); - msg.setCreatedAt(value); + var value = new proto.api.JSONElement.Array; + reader.readMessage(value,proto.api.JSONElement.Array.deserializeBinaryFromReader); + msg.setArray(value); break; case 3: - var value = new proto.api.TimeTicket; - reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); - msg.setUpdatedAt(value); + var value = new proto.api.JSONElement.Primitive; + reader.readMessage(value,proto.api.JSONElement.Primitive.deserializeBinaryFromReader); + msg.setPrimitive(value); break; case 4: - var value = new proto.api.TimeTicket; - reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); - msg.setRemovedAt(value); + var value = new proto.api.JSONElement.Text; + reader.readMessage(value,proto.api.JSONElement.Text.deserializeBinaryFromReader); + msg.setText(value); + break; + case 5: + var value = new proto.api.JSONElement.RichText; + reader.readMessage(value,proto.api.JSONElement.RichText.deserializeBinaryFromReader); + msg.setRichText(value); break; default: reader.skipField(); @@ -7226,9 +7707,9 @@ proto.api.JSONElement.Array.deserializeBinaryFromReader = function(msg, reader) * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.JSONElement.Array.prototype.serializeBinary = function() { +proto.api.JSONElement.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.JSONElement.Array.serializeBinaryToWriter(this, writer); + proto.api.JSONElement.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -7236,29 +7717,201 @@ proto.api.JSONElement.Array.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.JSONElement.Array} message + * @param {!proto.api.JSONElement} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Array.serializeBinaryToWriter = function(message, writer) { +proto.api.JSONElement.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getNodesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( + f = message.getObject(); + if (f != null) { + writer.writeMessage( 1, f, - proto.api.RGANode.serializeBinaryToWriter + proto.api.JSONElement.Object.serializeBinaryToWriter ); } - f = message.getCreatedAt(); + f = message.getArray(); if (f != null) { writer.writeMessage( 2, f, - proto.api.TimeTicket.serializeBinaryToWriter + proto.api.JSONElement.Array.serializeBinaryToWriter ); } - f = message.getUpdatedAt(); + f = message.getPrimitive(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.api.JSONElement.Primitive.serializeBinaryToWriter + ); + } + f = message.getText(); + if (f != null) { + writer.writeMessage( + 4, + f, + proto.api.JSONElement.Text.serializeBinaryToWriter + ); + } + f = message.getRichText(); + if (f != null) { + writer.writeMessage( + 5, + f, + proto.api.JSONElement.RichText.serializeBinaryToWriter + ); + } +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.api.JSONElement.Object.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.api.JSONElement.Object.prototype.toObject = function(opt_includeInstance) { + return proto.api.JSONElement.Object.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.api.JSONElement.Object} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.JSONElement.Object.toObject = function(includeInstance, msg) { + var f, obj = { + nodesList: jspb.Message.toObjectList(msg.getNodesList(), + proto.api.RHTNode.toObject, includeInstance), + createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.api.JSONElement.Object} + */ +proto.api.JSONElement.Object.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.api.JSONElement.Object; + return proto.api.JSONElement.Object.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.api.JSONElement.Object} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.api.JSONElement.Object} + */ +proto.api.JSONElement.Object.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.api.RHTNode; + reader.readMessage(value,proto.api.RHTNode.deserializeBinaryFromReader); + msg.addNodes(value); + break; + case 2: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setCreatedAt(value); + break; + case 3: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setUpdatedAt(value); + break; + case 4: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setRemovedAt(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.api.JSONElement.Object.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.api.JSONElement.Object.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.api.JSONElement.Object} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.JSONElement.Object.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNodesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.api.RHTNode.serializeBinaryToWriter + ); + } + f = message.getCreatedAt(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } + f = message.getUpdatedAt(); if (f != null) { writer.writeMessage( 3, @@ -7278,39 +7931,39 @@ proto.api.JSONElement.Array.serializeBinaryToWriter = function(message, writer) /** - * repeated RGANode nodes = 1; - * @return {!Array} + * repeated RHTNode nodes = 1; + * @return {!Array} */ -proto.api.JSONElement.Array.prototype.getNodesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.api.RGANode, 1)); +proto.api.JSONElement.Object.prototype.getNodesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.api.RHTNode, 1)); }; /** - * @param {!Array} value - * @return {!proto.api.JSONElement.Array} returns this + * @param {!Array} value + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.setNodesList = function(value) { +proto.api.JSONElement.Object.prototype.setNodesList = function(value) { return jspb.Message.setRepeatedWrapperField(this, 1, value); }; /** - * @param {!proto.api.RGANode=} opt_value + * @param {!proto.api.RHTNode=} opt_value * @param {number=} opt_index - * @return {!proto.api.RGANode} + * @return {!proto.api.RHTNode} */ -proto.api.JSONElement.Array.prototype.addNodes = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.api.RGANode, opt_index); +proto.api.JSONElement.Object.prototype.addNodes = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.api.RHTNode, opt_index); }; /** * Clears the list making it empty but non-null. - * @return {!proto.api.JSONElement.Array} returns this + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.clearNodesList = function() { +proto.api.JSONElement.Object.prototype.clearNodesList = function() { return this.setNodesList([]); }; @@ -7319,7 +7972,7 @@ proto.api.JSONElement.Array.prototype.clearNodesList = function() { * optional TimeTicket created_at = 2; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Array.prototype.getCreatedAt = function() { +proto.api.JSONElement.Object.prototype.getCreatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( jspb.Message.getWrapperField(this, proto.api.TimeTicket, 2)); }; @@ -7327,18 +7980,18 @@ proto.api.JSONElement.Array.prototype.getCreatedAt = function() { /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Array} returns this + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.setCreatedAt = function(value) { +proto.api.JSONElement.Object.prototype.setCreatedAt = function(value) { return jspb.Message.setWrapperField(this, 2, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Array} returns this + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.clearCreatedAt = function() { +proto.api.JSONElement.Object.prototype.clearCreatedAt = function() { return this.setCreatedAt(undefined); }; @@ -7347,7 +8000,7 @@ proto.api.JSONElement.Array.prototype.clearCreatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Array.prototype.hasCreatedAt = function() { +proto.api.JSONElement.Object.prototype.hasCreatedAt = function() { return jspb.Message.getField(this, 2) != null; }; @@ -7356,7 +8009,7 @@ proto.api.JSONElement.Array.prototype.hasCreatedAt = function() { * optional TimeTicket updated_at = 3; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Array.prototype.getUpdatedAt = function() { +proto.api.JSONElement.Object.prototype.getUpdatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); }; @@ -7364,18 +8017,18 @@ proto.api.JSONElement.Array.prototype.getUpdatedAt = function() { /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Array} returns this + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.setUpdatedAt = function(value) { +proto.api.JSONElement.Object.prototype.setUpdatedAt = function(value) { return jspb.Message.setWrapperField(this, 3, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Array} returns this + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.clearUpdatedAt = function() { +proto.api.JSONElement.Object.prototype.clearUpdatedAt = function() { return this.setUpdatedAt(undefined); }; @@ -7384,7 +8037,7 @@ proto.api.JSONElement.Array.prototype.clearUpdatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Array.prototype.hasUpdatedAt = function() { +proto.api.JSONElement.Object.prototype.hasUpdatedAt = function() { return jspb.Message.getField(this, 3) != null; }; @@ -7393,7 +8046,7 @@ proto.api.JSONElement.Array.prototype.hasUpdatedAt = function() { * optional TimeTicket removed_at = 4; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Array.prototype.getRemovedAt = function() { +proto.api.JSONElement.Object.prototype.getRemovedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); }; @@ -7401,18 +8054,18 @@ proto.api.JSONElement.Array.prototype.getRemovedAt = function() { /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Array} returns this + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.setRemovedAt = function(value) { +proto.api.JSONElement.Object.prototype.setRemovedAt = function(value) { return jspb.Message.setWrapperField(this, 4, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Array} returns this + * @return {!proto.api.JSONElement.Object} returns this */ -proto.api.JSONElement.Array.prototype.clearRemovedAt = function() { +proto.api.JSONElement.Object.prototype.clearRemovedAt = function() { return this.setRemovedAt(undefined); }; @@ -7421,12 +8074,19 @@ proto.api.JSONElement.Array.prototype.clearRemovedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Array.prototype.hasRemovedAt = function() { +proto.api.JSONElement.Object.prototype.hasRemovedAt = function() { return jspb.Message.getField(this, 4) != null; }; +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.api.JSONElement.Array.repeatedFields_ = [1]; + if (jspb.Message.GENERATE_TO_OBJECT) { @@ -7442,8 +8102,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.JSONElement.Primitive.prototype.toObject = function(opt_includeInstance) { - return proto.api.JSONElement.Primitive.toObject(opt_includeInstance, this); +proto.api.JSONElement.Array.prototype.toObject = function(opt_includeInstance) { + return proto.api.JSONElement.Array.toObject(opt_includeInstance, this); }; @@ -7452,14 +8112,14 @@ proto.api.JSONElement.Primitive.prototype.toObject = function(opt_includeInstanc * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.JSONElement.Primitive} msg The msg instance to transform. + * @param {!proto.api.JSONElement.Array} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Primitive.toObject = function(includeInstance, msg) { +proto.api.JSONElement.Array.toObject = function(includeInstance, msg) { var f, obj = { - type: jspb.Message.getFieldWithDefault(msg, 1, 0), - value: msg.getValue_asB64(), + nodesList: jspb.Message.toObjectList(msg.getNodesList(), + proto.api.RGANode.toObject, includeInstance), createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) @@ -7476,23 +8136,23 @@ proto.api.JSONElement.Primitive.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.JSONElement.Primitive} + * @return {!proto.api.JSONElement.Array} */ -proto.api.JSONElement.Primitive.deserializeBinary = function(bytes) { +proto.api.JSONElement.Array.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.JSONElement.Primitive; - return proto.api.JSONElement.Primitive.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.JSONElement.Array; + return proto.api.JSONElement.Array.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.JSONElement.Primitive} msg The message object to deserialize into. + * @param {!proto.api.JSONElement.Array} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.JSONElement.Primitive} + * @return {!proto.api.JSONElement.Array} */ -proto.api.JSONElement.Primitive.deserializeBinaryFromReader = function(msg, reader) { +proto.api.JSONElement.Array.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -7500,24 +8160,21 @@ proto.api.JSONElement.Primitive.deserializeBinaryFromReader = function(msg, read var field = reader.getFieldNumber(); switch (field) { case 1: - var value = /** @type {!proto.api.ValueType} */ (reader.readEnum()); - msg.setType(value); + var value = new proto.api.RGANode; + reader.readMessage(value,proto.api.RGANode.deserializeBinaryFromReader); + msg.addNodes(value); break; case 2: - var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setValue(value); - break; - case 3: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setCreatedAt(value); break; - case 4: + case 3: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setUpdatedAt(value); break; - case 5: + case 4: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setRemovedAt(value); @@ -7535,9 +8192,9 @@ proto.api.JSONElement.Primitive.deserializeBinaryFromReader = function(msg, read * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.JSONElement.Primitive.prototype.serializeBinary = function() { +proto.api.JSONElement.Array.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.JSONElement.Primitive.serializeBinaryToWriter(this, writer); + proto.api.JSONElement.Array.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -7545,30 +8202,24 @@ proto.api.JSONElement.Primitive.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.JSONElement.Primitive} message + * @param {!proto.api.JSONElement.Array} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Primitive.serializeBinaryToWriter = function(message, writer) { +proto.api.JSONElement.Array.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getType(); - if (f !== 0.0) { - writer.writeEnum( - 1, - f - ); - } - f = message.getValue_asU8(); + f = message.getNodesList(); if (f.length > 0) { - writer.writeBytes( - 2, - f + writer.writeRepeatedMessage( + 1, + f, + proto.api.RGANode.serializeBinaryToWriter ); } f = message.getCreatedAt(); if (f != null) { writer.writeMessage( - 3, + 2, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -7576,7 +8227,7 @@ proto.api.JSONElement.Primitive.serializeBinaryToWriter = function(message, writ f = message.getUpdatedAt(); if (f != null) { writer.writeMessage( - 4, + 3, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -7584,7 +8235,7 @@ proto.api.JSONElement.Primitive.serializeBinaryToWriter = function(message, writ f = message.getRemovedAt(); if (f != null) { writer.writeMessage( - 5, + 4, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -7593,89 +8244,67 @@ proto.api.JSONElement.Primitive.serializeBinaryToWriter = function(message, writ /** - * optional ValueType type = 1; - * @return {!proto.api.ValueType} - */ -proto.api.JSONElement.Primitive.prototype.getType = function() { - return /** @type {!proto.api.ValueType} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); -}; - - -/** - * @param {!proto.api.ValueType} value - * @return {!proto.api.JSONElement.Primitive} returns this - */ -proto.api.JSONElement.Primitive.prototype.setType = function(value) { - return jspb.Message.setProto3EnumField(this, 1, value); -}; - - -/** - * optional bytes value = 2; - * @return {string} + * repeated RGANode nodes = 1; + * @return {!Array} */ -proto.api.JSONElement.Primitive.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +proto.api.JSONElement.Array.prototype.getNodesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.api.RGANode, 1)); }; /** - * optional bytes value = 2; - * This is a type-conversion wrapper around `getValue()` - * @return {string} - */ -proto.api.JSONElement.Primitive.prototype.getValue_asB64 = function() { - return /** @type {string} */ (jspb.Message.bytesAsB64( - this.getValue())); + * @param {!Array} value + * @return {!proto.api.JSONElement.Array} returns this +*/ +proto.api.JSONElement.Array.prototype.setNodesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); }; /** - * optional bytes value = 2; - * Note that Uint8Array is not supported on all browsers. - * @see http://caniuse.com/Uint8Array - * This is a type-conversion wrapper around `getValue()` - * @return {!Uint8Array} + * @param {!proto.api.RGANode=} opt_value + * @param {number=} opt_index + * @return {!proto.api.RGANode} */ -proto.api.JSONElement.Primitive.prototype.getValue_asU8 = function() { - return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( - this.getValue())); +proto.api.JSONElement.Array.prototype.addNodes = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.api.RGANode, opt_index); }; /** - * @param {!(string|Uint8Array)} value - * @return {!proto.api.JSONElement.Primitive} returns this + * Clears the list making it empty but non-null. + * @return {!proto.api.JSONElement.Array} returns this */ -proto.api.JSONElement.Primitive.prototype.setValue = function(value) { - return jspb.Message.setProto3BytesField(this, 2, value); +proto.api.JSONElement.Array.prototype.clearNodesList = function() { + return this.setNodesList([]); }; /** - * optional TimeTicket created_at = 3; + * optional TimeTicket created_at = 2; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Primitive.prototype.getCreatedAt = function() { +proto.api.JSONElement.Array.prototype.getCreatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 2)); }; /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Primitive} returns this + * @return {!proto.api.JSONElement.Array} returns this */ -proto.api.JSONElement.Primitive.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); +proto.api.JSONElement.Array.prototype.setCreatedAt = function(value) { + return jspb.Message.setWrapperField(this, 2, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Primitive} returns this + * @return {!proto.api.JSONElement.Array} returns this */ -proto.api.JSONElement.Primitive.prototype.clearCreatedAt = function() { +proto.api.JSONElement.Array.prototype.clearCreatedAt = function() { return this.setCreatedAt(undefined); }; @@ -7684,35 +8313,35 @@ proto.api.JSONElement.Primitive.prototype.clearCreatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Primitive.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 3) != null; +proto.api.JSONElement.Array.prototype.hasCreatedAt = function() { + return jspb.Message.getField(this, 2) != null; }; /** - * optional TimeTicket updated_at = 4; + * optional TimeTicket updated_at = 3; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Primitive.prototype.getUpdatedAt = function() { +proto.api.JSONElement.Array.prototype.getUpdatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); }; /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Primitive} returns this + * @return {!proto.api.JSONElement.Array} returns this */ -proto.api.JSONElement.Primitive.prototype.setUpdatedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); +proto.api.JSONElement.Array.prototype.setUpdatedAt = function(value) { + return jspb.Message.setWrapperField(this, 3, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Primitive} returns this + * @return {!proto.api.JSONElement.Array} returns this */ -proto.api.JSONElement.Primitive.prototype.clearUpdatedAt = function() { +proto.api.JSONElement.Array.prototype.clearUpdatedAt = function() { return this.setUpdatedAt(undefined); }; @@ -7721,35 +8350,35 @@ proto.api.JSONElement.Primitive.prototype.clearUpdatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Primitive.prototype.hasUpdatedAt = function() { - return jspb.Message.getField(this, 4) != null; +proto.api.JSONElement.Array.prototype.hasUpdatedAt = function() { + return jspb.Message.getField(this, 3) != null; }; /** - * optional TimeTicket removed_at = 5; + * optional TimeTicket removed_at = 4; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Primitive.prototype.getRemovedAt = function() { +proto.api.JSONElement.Array.prototype.getRemovedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 5)); + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); }; /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Primitive} returns this + * @return {!proto.api.JSONElement.Array} returns this */ -proto.api.JSONElement.Primitive.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 5, value); +proto.api.JSONElement.Array.prototype.setRemovedAt = function(value) { + return jspb.Message.setWrapperField(this, 4, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Primitive} returns this + * @return {!proto.api.JSONElement.Array} returns this */ -proto.api.JSONElement.Primitive.prototype.clearRemovedAt = function() { +proto.api.JSONElement.Array.prototype.clearRemovedAt = function() { return this.setRemovedAt(undefined); }; @@ -7758,19 +8387,12 @@ proto.api.JSONElement.Primitive.prototype.clearRemovedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Primitive.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 5) != null; +proto.api.JSONElement.Array.prototype.hasRemovedAt = function() { + return jspb.Message.getField(this, 4) != null; }; -/** - * List of repeated fields within this message type. - * @private {!Array} - * @const - */ -proto.api.JSONElement.Text.repeatedFields_ = [1]; - if (jspb.Message.GENERATE_TO_OBJECT) { @@ -7786,8 +8408,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.JSONElement.Text.prototype.toObject = function(opt_includeInstance) { - return proto.api.JSONElement.Text.toObject(opt_includeInstance, this); +proto.api.JSONElement.Primitive.prototype.toObject = function(opt_includeInstance) { + return proto.api.JSONElement.Primitive.toObject(opt_includeInstance, this); }; @@ -7796,14 +8418,14 @@ proto.api.JSONElement.Text.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.JSONElement.Text} msg The msg instance to transform. + * @param {!proto.api.JSONElement.Primitive} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Text.toObject = function(includeInstance, msg) { +proto.api.JSONElement.Primitive.toObject = function(includeInstance, msg) { var f, obj = { - nodesList: jspb.Message.toObjectList(msg.getNodesList(), - proto.api.TextNode.toObject, includeInstance), + type: jspb.Message.getFieldWithDefault(msg, 1, 0), + value: msg.getValue_asB64(), createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) @@ -7820,23 +8442,23 @@ proto.api.JSONElement.Text.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.JSONElement.Text} + * @return {!proto.api.JSONElement.Primitive} */ -proto.api.JSONElement.Text.deserializeBinary = function(bytes) { +proto.api.JSONElement.Primitive.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.JSONElement.Text; - return proto.api.JSONElement.Text.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.JSONElement.Primitive; + return proto.api.JSONElement.Primitive.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.JSONElement.Text} msg The message object to deserialize into. + * @param {!proto.api.JSONElement.Primitive} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.JSONElement.Text} + * @return {!proto.api.JSONElement.Primitive} */ -proto.api.JSONElement.Text.deserializeBinaryFromReader = function(msg, reader) { +proto.api.JSONElement.Primitive.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -7844,21 +8466,24 @@ proto.api.JSONElement.Text.deserializeBinaryFromReader = function(msg, reader) { var field = reader.getFieldNumber(); switch (field) { case 1: - var value = new proto.api.TextNode; - reader.readMessage(value,proto.api.TextNode.deserializeBinaryFromReader); - msg.addNodes(value); + var value = /** @type {!proto.api.ValueType} */ (reader.readEnum()); + msg.setType(value); break; case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setValue(value); + break; + case 3: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setCreatedAt(value); break; - case 3: + case 4: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setUpdatedAt(value); break; - case 4: + case 5: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setRemovedAt(value); @@ -7876,9 +8501,9 @@ proto.api.JSONElement.Text.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.JSONElement.Text.prototype.serializeBinary = function() { +proto.api.JSONElement.Primitive.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.JSONElement.Text.serializeBinaryToWriter(this, writer); + proto.api.JSONElement.Primitive.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -7886,24 +8511,30 @@ proto.api.JSONElement.Text.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.JSONElement.Text} message + * @param {!proto.api.JSONElement.Primitive} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.Text.serializeBinaryToWriter = function(message, writer) { +proto.api.JSONElement.Primitive.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getNodesList(); - if (f.length > 0) { - writer.writeRepeatedMessage( + f = message.getType(); + if (f !== 0.0) { + writer.writeEnum( 1, - f, - proto.api.TextNode.serializeBinaryToWriter + f + ); + } + f = message.getValue_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f ); } f = message.getCreatedAt(); if (f != null) { writer.writeMessage( - 2, + 3, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -7911,7 +8542,7 @@ proto.api.JSONElement.Text.serializeBinaryToWriter = function(message, writer) { f = message.getUpdatedAt(); if (f != null) { writer.writeMessage( - 3, + 4, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -7919,7 +8550,7 @@ proto.api.JSONElement.Text.serializeBinaryToWriter = function(message, writer) { f = message.getRemovedAt(); if (f != null) { writer.writeMessage( - 4, + 5, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -7928,67 +8559,89 @@ proto.api.JSONElement.Text.serializeBinaryToWriter = function(message, writer) { /** - * repeated TextNode nodes = 1; - * @return {!Array} + * optional ValueType type = 1; + * @return {!proto.api.ValueType} */ -proto.api.JSONElement.Text.prototype.getNodesList = function() { - return /** @type{!Array} */ ( - jspb.Message.getRepeatedWrapperField(this, proto.api.TextNode, 1)); +proto.api.JSONElement.Primitive.prototype.getType = function() { + return /** @type {!proto.api.ValueType} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); }; /** - * @param {!Array} value - * @return {!proto.api.JSONElement.Text} returns this -*/ -proto.api.JSONElement.Text.prototype.setNodesList = function(value) { - return jspb.Message.setRepeatedWrapperField(this, 1, value); + * @param {!proto.api.ValueType} value + * @return {!proto.api.JSONElement.Primitive} returns this + */ +proto.api.JSONElement.Primitive.prototype.setType = function(value) { + return jspb.Message.setProto3EnumField(this, 1, value); }; /** - * @param {!proto.api.TextNode=} opt_value - * @param {number=} opt_index - * @return {!proto.api.TextNode} + * optional bytes value = 2; + * @return {string} */ -proto.api.JSONElement.Text.prototype.addNodes = function(opt_value, opt_index) { - return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.api.TextNode, opt_index); +proto.api.JSONElement.Primitive.prototype.getValue = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); }; /** - * Clears the list making it empty but non-null. - * @return {!proto.api.JSONElement.Text} returns this + * optional bytes value = 2; + * This is a type-conversion wrapper around `getValue()` + * @return {string} */ -proto.api.JSONElement.Text.prototype.clearNodesList = function() { - return this.setNodesList([]); +proto.api.JSONElement.Primitive.prototype.getValue_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getValue())); }; /** - * optional TimeTicket created_at = 2; + * optional bytes value = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getValue()` + * @return {!Uint8Array} + */ +proto.api.JSONElement.Primitive.prototype.getValue_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getValue())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.api.JSONElement.Primitive} returns this + */ +proto.api.JSONElement.Primitive.prototype.setValue = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional TimeTicket created_at = 3; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Text.prototype.getCreatedAt = function() { +proto.api.JSONElement.Primitive.prototype.getCreatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 2)); + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); }; /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Text} returns this + * @return {!proto.api.JSONElement.Primitive} returns this */ -proto.api.JSONElement.Text.prototype.setCreatedAt = function(value) { - return jspb.Message.setWrapperField(this, 2, value); +proto.api.JSONElement.Primitive.prototype.setCreatedAt = function(value) { + return jspb.Message.setWrapperField(this, 3, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Text} returns this + * @return {!proto.api.JSONElement.Primitive} returns this */ -proto.api.JSONElement.Text.prototype.clearCreatedAt = function() { +proto.api.JSONElement.Primitive.prototype.clearCreatedAt = function() { return this.setCreatedAt(undefined); }; @@ -7997,35 +8650,35 @@ proto.api.JSONElement.Text.prototype.clearCreatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Text.prototype.hasCreatedAt = function() { - return jspb.Message.getField(this, 2) != null; +proto.api.JSONElement.Primitive.prototype.hasCreatedAt = function() { + return jspb.Message.getField(this, 3) != null; }; /** - * optional TimeTicket updated_at = 3; + * optional TimeTicket updated_at = 4; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Text.prototype.getUpdatedAt = function() { +proto.api.JSONElement.Primitive.prototype.getUpdatedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); }; /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Text} returns this + * @return {!proto.api.JSONElement.Primitive} returns this */ -proto.api.JSONElement.Text.prototype.setUpdatedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); +proto.api.JSONElement.Primitive.prototype.setUpdatedAt = function(value) { + return jspb.Message.setWrapperField(this, 4, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Text} returns this + * @return {!proto.api.JSONElement.Primitive} returns this */ -proto.api.JSONElement.Text.prototype.clearUpdatedAt = function() { +proto.api.JSONElement.Primitive.prototype.clearUpdatedAt = function() { return this.setUpdatedAt(undefined); }; @@ -8034,35 +8687,35 @@ proto.api.JSONElement.Text.prototype.clearUpdatedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Text.prototype.hasUpdatedAt = function() { - return jspb.Message.getField(this, 3) != null; +proto.api.JSONElement.Primitive.prototype.hasUpdatedAt = function() { + return jspb.Message.getField(this, 4) != null; }; /** - * optional TimeTicket removed_at = 4; + * optional TimeTicket removed_at = 5; * @return {?proto.api.TimeTicket} */ -proto.api.JSONElement.Text.prototype.getRemovedAt = function() { +proto.api.JSONElement.Primitive.prototype.getRemovedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 5)); }; /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.JSONElement.Text} returns this + * @return {!proto.api.JSONElement.Primitive} returns this */ -proto.api.JSONElement.Text.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 4, value); +proto.api.JSONElement.Primitive.prototype.setRemovedAt = function(value) { + return jspb.Message.setWrapperField(this, 5, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement.Text} returns this + * @return {!proto.api.JSONElement.Primitive} returns this */ -proto.api.JSONElement.Text.prototype.clearRemovedAt = function() { +proto.api.JSONElement.Primitive.prototype.clearRemovedAt = function() { return this.setRemovedAt(undefined); }; @@ -8071,110 +8724,1156 @@ proto.api.JSONElement.Text.prototype.clearRemovedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.Text.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 4) != null; +proto.api.JSONElement.Primitive.prototype.hasRemovedAt = function() { + return jspb.Message.getField(this, 5) != null; }; + /** - * optional Object object = 1; - * @return {?proto.api.JSONElement.Object} + * List of repeated fields within this message type. + * @private {!Array} + * @const */ -proto.api.JSONElement.prototype.getObject = function() { - return /** @type{?proto.api.JSONElement.Object} */ ( - jspb.Message.getWrapperField(this, proto.api.JSONElement.Object, 1)); +proto.api.JSONElement.Text.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.api.JSONElement.Text.prototype.toObject = function(opt_includeInstance) { + return proto.api.JSONElement.Text.toObject(opt_includeInstance, this); }; /** - * @param {?proto.api.JSONElement.Object|undefined} value - * @return {!proto.api.JSONElement} returns this -*/ -proto.api.JSONElement.prototype.setObject = function(value) { - return jspb.Message.setOneofWrapperField(this, 1, proto.api.JSONElement.oneofGroups_[0], value); + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.api.JSONElement.Text} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.JSONElement.Text.toObject = function(includeInstance, msg) { + var f, obj = { + nodesList: jspb.Message.toObjectList(msg.getNodesList(), + proto.api.TextNode.toObject, includeInstance), + createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; }; +} /** - * Clears the message field making it undefined. - * @return {!proto.api.JSONElement} returns this + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.api.JSONElement.Text} */ -proto.api.JSONElement.prototype.clearObject = function() { - return this.setObject(undefined); +proto.api.JSONElement.Text.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.api.JSONElement.Text; + return proto.api.JSONElement.Text.deserializeBinaryFromReader(msg, reader); }; /** - * Returns whether this field is set. - * @return {boolean} + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.api.JSONElement.Text} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.api.JSONElement.Text} */ -proto.api.JSONElement.prototype.hasObject = function() { - return jspb.Message.getField(this, 1) != null; +proto.api.JSONElement.Text.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.api.TextNode; + reader.readMessage(value,proto.api.TextNode.deserializeBinaryFromReader); + msg.addNodes(value); + break; + case 2: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setCreatedAt(value); + break; + case 3: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setUpdatedAt(value); + break; + case 4: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setRemovedAt(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; }; /** - * optional Array array = 2; - * @return {?proto.api.JSONElement.Array} + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} */ -proto.api.JSONElement.prototype.getArray = function() { - return /** @type{?proto.api.JSONElement.Array} */ ( - jspb.Message.getWrapperField(this, proto.api.JSONElement.Array, 2)); +proto.api.JSONElement.Text.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.api.JSONElement.Text.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); }; /** - * @param {?proto.api.JSONElement.Array|undefined} value - * @return {!proto.api.JSONElement} returns this -*/ -proto.api.JSONElement.prototype.setArray = function(value) { - return jspb.Message.setOneofWrapperField(this, 2, proto.api.JSONElement.oneofGroups_[0], value); + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.api.JSONElement.Text} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.JSONElement.Text.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNodesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.api.TextNode.serializeBinaryToWriter + ); + } + f = message.getCreatedAt(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } + f = message.getUpdatedAt(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } + f = message.getRemovedAt(); + if (f != null) { + writer.writeMessage( + 4, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated TextNode nodes = 1; + * @return {!Array} + */ +proto.api.JSONElement.Text.prototype.getNodesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.api.TextNode, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.api.JSONElement.Text} returns this +*/ +proto.api.JSONElement.Text.prototype.setNodesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.api.TextNode=} opt_value + * @param {number=} opt_index + * @return {!proto.api.TextNode} + */ +proto.api.JSONElement.Text.prototype.addNodes = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.api.TextNode, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.api.JSONElement.Text} returns this + */ +proto.api.JSONElement.Text.prototype.clearNodesList = function() { + return this.setNodesList([]); +}; + + +/** + * optional TimeTicket created_at = 2; + * @return {?proto.api.TimeTicket} + */ +proto.api.JSONElement.Text.prototype.getCreatedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 2)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.JSONElement.Text} returns this +*/ +proto.api.JSONElement.Text.prototype.setCreatedAt = function(value) { + return jspb.Message.setWrapperField(this, 2, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement.Text} returns this + */ +proto.api.JSONElement.Text.prototype.clearCreatedAt = function() { + return this.setCreatedAt(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.Text.prototype.hasCreatedAt = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional TimeTicket updated_at = 3; + * @return {?proto.api.TimeTicket} + */ +proto.api.JSONElement.Text.prototype.getUpdatedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.JSONElement.Text} returns this +*/ +proto.api.JSONElement.Text.prototype.setUpdatedAt = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement.Text} returns this + */ +proto.api.JSONElement.Text.prototype.clearUpdatedAt = function() { + return this.setUpdatedAt(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.Text.prototype.hasUpdatedAt = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional TimeTicket removed_at = 4; + * @return {?proto.api.TimeTicket} + */ +proto.api.JSONElement.Text.prototype.getRemovedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.JSONElement.Text} returns this +*/ +proto.api.JSONElement.Text.prototype.setRemovedAt = function(value) { + return jspb.Message.setWrapperField(this, 4, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement.Text} returns this + */ +proto.api.JSONElement.Text.prototype.clearRemovedAt = function() { + return this.setRemovedAt(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.Text.prototype.hasRemovedAt = function() { + return jspb.Message.getField(this, 4) != null; +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.api.JSONElement.RichText.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.api.JSONElement.RichText.prototype.toObject = function(opt_includeInstance) { + return proto.api.JSONElement.RichText.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.api.JSONElement.RichText} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.JSONElement.RichText.toObject = function(includeInstance, msg) { + var f, obj = { + nodesList: jspb.Message.toObjectList(msg.getNodesList(), + proto.api.RichTextNode.toObject, includeInstance), + createdAt: (f = msg.getCreatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.api.JSONElement.RichText} + */ +proto.api.JSONElement.RichText.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.api.JSONElement.RichText; + return proto.api.JSONElement.RichText.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.api.JSONElement.RichText} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.api.JSONElement.RichText} + */ +proto.api.JSONElement.RichText.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.api.RichTextNode; + reader.readMessage(value,proto.api.RichTextNode.deserializeBinaryFromReader); + msg.addNodes(value); + break; + case 2: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setCreatedAt(value); + break; + case 3: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setUpdatedAt(value); + break; + case 4: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setRemovedAt(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.api.JSONElement.RichText.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.api.JSONElement.RichText.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.api.JSONElement.RichText} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.JSONElement.RichText.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNodesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.api.RichTextNode.serializeBinaryToWriter + ); + } + f = message.getCreatedAt(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } + f = message.getUpdatedAt(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } + f = message.getRemovedAt(); + if (f != null) { + writer.writeMessage( + 4, + f, + proto.api.TimeTicket.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated RichTextNode nodes = 1; + * @return {!Array} + */ +proto.api.JSONElement.RichText.prototype.getNodesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.api.RichTextNode, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.api.JSONElement.RichText} returns this +*/ +proto.api.JSONElement.RichText.prototype.setNodesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.api.RichTextNode=} opt_value + * @param {number=} opt_index + * @return {!proto.api.RichTextNode} + */ +proto.api.JSONElement.RichText.prototype.addNodes = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.api.RichTextNode, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.api.JSONElement.RichText} returns this + */ +proto.api.JSONElement.RichText.prototype.clearNodesList = function() { + return this.setNodesList([]); +}; + + +/** + * optional TimeTicket created_at = 2; + * @return {?proto.api.TimeTicket} + */ +proto.api.JSONElement.RichText.prototype.getCreatedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 2)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.JSONElement.RichText} returns this +*/ +proto.api.JSONElement.RichText.prototype.setCreatedAt = function(value) { + return jspb.Message.setWrapperField(this, 2, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement.RichText} returns this + */ +proto.api.JSONElement.RichText.prototype.clearCreatedAt = function() { + return this.setCreatedAt(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.RichText.prototype.hasCreatedAt = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional TimeTicket updated_at = 3; + * @return {?proto.api.TimeTicket} + */ +proto.api.JSONElement.RichText.prototype.getUpdatedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.JSONElement.RichText} returns this +*/ +proto.api.JSONElement.RichText.prototype.setUpdatedAt = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement.RichText} returns this + */ +proto.api.JSONElement.RichText.prototype.clearUpdatedAt = function() { + return this.setUpdatedAt(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.RichText.prototype.hasUpdatedAt = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional TimeTicket removed_at = 4; + * @return {?proto.api.TimeTicket} + */ +proto.api.JSONElement.RichText.prototype.getRemovedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); +}; + + +/** + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.JSONElement.RichText} returns this +*/ +proto.api.JSONElement.RichText.prototype.setRemovedAt = function(value) { + return jspb.Message.setWrapperField(this, 4, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement.RichText} returns this + */ +proto.api.JSONElement.RichText.prototype.clearRemovedAt = function() { + return this.setRemovedAt(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.RichText.prototype.hasRemovedAt = function() { + return jspb.Message.getField(this, 4) != null; +}; + + +/** + * optional Object object = 1; + * @return {?proto.api.JSONElement.Object} + */ +proto.api.JSONElement.prototype.getObject = function() { + return /** @type{?proto.api.JSONElement.Object} */ ( + jspb.Message.getWrapperField(this, proto.api.JSONElement.Object, 1)); +}; + + +/** + * @param {?proto.api.JSONElement.Object|undefined} value + * @return {!proto.api.JSONElement} returns this +*/ +proto.api.JSONElement.prototype.setObject = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.api.JSONElement.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement} returns this + */ +proto.api.JSONElement.prototype.clearObject = function() { + return this.setObject(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.prototype.hasObject = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Array array = 2; + * @return {?proto.api.JSONElement.Array} + */ +proto.api.JSONElement.prototype.getArray = function() { + return /** @type{?proto.api.JSONElement.Array} */ ( + jspb.Message.getWrapperField(this, proto.api.JSONElement.Array, 2)); +}; + + +/** + * @param {?proto.api.JSONElement.Array|undefined} value + * @return {!proto.api.JSONElement} returns this +*/ +proto.api.JSONElement.prototype.setArray = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.api.JSONElement.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement} returns this + */ +proto.api.JSONElement.prototype.clearArray = function() { + return this.setArray(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.prototype.hasArray = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional Primitive primitive = 3; + * @return {?proto.api.JSONElement.Primitive} + */ +proto.api.JSONElement.prototype.getPrimitive = function() { + return /** @type{?proto.api.JSONElement.Primitive} */ ( + jspb.Message.getWrapperField(this, proto.api.JSONElement.Primitive, 3)); +}; + + +/** + * @param {?proto.api.JSONElement.Primitive|undefined} value + * @return {!proto.api.JSONElement} returns this +*/ +proto.api.JSONElement.prototype.setPrimitive = function(value) { + return jspb.Message.setOneofWrapperField(this, 3, proto.api.JSONElement.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement} returns this + */ +proto.api.JSONElement.prototype.clearPrimitive = function() { + return this.setPrimitive(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.prototype.hasPrimitive = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional Text text = 4; + * @return {?proto.api.JSONElement.Text} + */ +proto.api.JSONElement.prototype.getText = function() { + return /** @type{?proto.api.JSONElement.Text} */ ( + jspb.Message.getWrapperField(this, proto.api.JSONElement.Text, 4)); +}; + + +/** + * @param {?proto.api.JSONElement.Text|undefined} value + * @return {!proto.api.JSONElement} returns this +*/ +proto.api.JSONElement.prototype.setText = function(value) { + return jspb.Message.setOneofWrapperField(this, 4, proto.api.JSONElement.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement} returns this + */ +proto.api.JSONElement.prototype.clearText = function() { + return this.setText(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.prototype.hasText = function() { + return jspb.Message.getField(this, 4) != null; +}; + + +/** + * optional RichText rich_text = 5; + * @return {?proto.api.JSONElement.RichText} + */ +proto.api.JSONElement.prototype.getRichText = function() { + return /** @type{?proto.api.JSONElement.RichText} */ ( + jspb.Message.getWrapperField(this, proto.api.JSONElement.RichText, 5)); +}; + + +/** + * @param {?proto.api.JSONElement.RichText|undefined} value + * @return {!proto.api.JSONElement} returns this +*/ +proto.api.JSONElement.prototype.setRichText = function(value) { + return jspb.Message.setOneofWrapperField(this, 5, proto.api.JSONElement.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.JSONElement} returns this + */ +proto.api.JSONElement.prototype.clearRichText = function() { + return this.setRichText(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.JSONElement.prototype.hasRichText = function() { + return jspb.Message.getField(this, 5) != null; +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.api.RHTNode.prototype.toObject = function(opt_includeInstance) { + return proto.api.RHTNode.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.api.RHTNode} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.RHTNode.toObject = function(includeInstance, msg) { + var f, obj = { + key: jspb.Message.getFieldWithDefault(msg, 1, ""), + element: (f = msg.getElement()) && proto.api.JSONElement.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.api.RHTNode} + */ +proto.api.RHTNode.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.api.RHTNode; + return proto.api.RHTNode.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.api.RHTNode} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.api.RHTNode} + */ +proto.api.RHTNode.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setKey(value); + break; + case 2: + var value = new proto.api.JSONElement; + reader.readMessage(value,proto.api.JSONElement.deserializeBinaryFromReader); + msg.setElement(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.api.RHTNode.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.api.RHTNode.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.api.RHTNode} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.RHTNode.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getKey(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = message.getElement(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.api.JSONElement.serializeBinaryToWriter + ); + } +}; + + +/** + * optional string key = 1; + * @return {string} + */ +proto.api.RHTNode.prototype.getKey = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * @param {string} value + * @return {!proto.api.RHTNode} returns this + */ +proto.api.RHTNode.prototype.setKey = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); +}; + + +/** + * optional JSONElement element = 2; + * @return {?proto.api.JSONElement} + */ +proto.api.RHTNode.prototype.getElement = function() { + return /** @type{?proto.api.JSONElement} */ ( + jspb.Message.getWrapperField(this, proto.api.JSONElement, 2)); +}; + + +/** + * @param {?proto.api.JSONElement|undefined} value + * @return {!proto.api.RHTNode} returns this +*/ +proto.api.RHTNode.prototype.setElement = function(value) { + return jspb.Message.setWrapperField(this, 2, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.RHTNode} returns this + */ +proto.api.RHTNode.prototype.clearElement = function() { + return this.setElement(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.RHTNode.prototype.hasElement = function() { + return jspb.Message.getField(this, 2) != null; +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.api.RGANode.prototype.toObject = function(opt_includeInstance) { + return proto.api.RGANode.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.api.RGANode} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.api.RGANode.toObject = function(includeInstance, msg) { + var f, obj = { + next: (f = msg.getNext()) && proto.api.RGANode.toObject(includeInstance, f), + element: (f = msg.getElement()) && proto.api.JSONElement.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.api.RGANode} + */ +proto.api.RGANode.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.api.RGANode; + return proto.api.RGANode.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.api.RGANode} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.api.RGANode} + */ +proto.api.RGANode.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.api.RGANode; + reader.readMessage(value,proto.api.RGANode.deserializeBinaryFromReader); + msg.setNext(value); + break; + case 2: + var value = new proto.api.JSONElement; + reader.readMessage(value,proto.api.JSONElement.deserializeBinaryFromReader); + msg.setElement(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; }; /** - * Clears the message field making it undefined. - * @return {!proto.api.JSONElement} returns this + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} */ -proto.api.JSONElement.prototype.clearArray = function() { - return this.setArray(undefined); +proto.api.RGANode.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.api.RGANode.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); }; /** - * Returns whether this field is set. - * @return {boolean} + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.api.RGANode} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.JSONElement.prototype.hasArray = function() { - return jspb.Message.getField(this, 2) != null; +proto.api.RGANode.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNext(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.api.RGANode.serializeBinaryToWriter + ); + } + f = message.getElement(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.api.JSONElement.serializeBinaryToWriter + ); + } }; /** - * optional Primitive primitive = 3; - * @return {?proto.api.JSONElement.Primitive} + * optional RGANode next = 1; + * @return {?proto.api.RGANode} */ -proto.api.JSONElement.prototype.getPrimitive = function() { - return /** @type{?proto.api.JSONElement.Primitive} */ ( - jspb.Message.getWrapperField(this, proto.api.JSONElement.Primitive, 3)); +proto.api.RGANode.prototype.getNext = function() { + return /** @type{?proto.api.RGANode} */ ( + jspb.Message.getWrapperField(this, proto.api.RGANode, 1)); }; /** - * @param {?proto.api.JSONElement.Primitive|undefined} value - * @return {!proto.api.JSONElement} returns this + * @param {?proto.api.RGANode|undefined} value + * @return {!proto.api.RGANode} returns this */ -proto.api.JSONElement.prototype.setPrimitive = function(value) { - return jspb.Message.setOneofWrapperField(this, 3, proto.api.JSONElement.oneofGroups_[0], value); +proto.api.RGANode.prototype.setNext = function(value) { + return jspb.Message.setWrapperField(this, 1, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement} returns this + * @return {!proto.api.RGANode} returns this */ -proto.api.JSONElement.prototype.clearPrimitive = function() { - return this.setPrimitive(undefined); +proto.api.RGANode.prototype.clearNext = function() { + return this.setNext(undefined); }; @@ -8182,36 +9881,36 @@ proto.api.JSONElement.prototype.clearPrimitive = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.prototype.hasPrimitive = function() { - return jspb.Message.getField(this, 3) != null; +proto.api.RGANode.prototype.hasNext = function() { + return jspb.Message.getField(this, 1) != null; }; /** - * optional Text text = 4; - * @return {?proto.api.JSONElement.Text} + * optional JSONElement element = 2; + * @return {?proto.api.JSONElement} */ -proto.api.JSONElement.prototype.getText = function() { - return /** @type{?proto.api.JSONElement.Text} */ ( - jspb.Message.getWrapperField(this, proto.api.JSONElement.Text, 4)); +proto.api.RGANode.prototype.getElement = function() { + return /** @type{?proto.api.JSONElement} */ ( + jspb.Message.getWrapperField(this, proto.api.JSONElement, 2)); }; /** - * @param {?proto.api.JSONElement.Text|undefined} value - * @return {!proto.api.JSONElement} returns this + * @param {?proto.api.JSONElement|undefined} value + * @return {!proto.api.RGANode} returns this */ -proto.api.JSONElement.prototype.setText = function(value) { - return jspb.Message.setOneofWrapperField(this, 4, proto.api.JSONElement.oneofGroups_[0], value); +proto.api.RGANode.prototype.setElement = function(value) { + return jspb.Message.setWrapperField(this, 2, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.JSONElement} returns this + * @return {!proto.api.RGANode} returns this */ -proto.api.JSONElement.prototype.clearText = function() { - return this.setText(undefined); +proto.api.RGANode.prototype.clearElement = function() { + return this.setElement(undefined); }; @@ -8219,8 +9918,8 @@ proto.api.JSONElement.prototype.clearText = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.JSONElement.prototype.hasText = function() { - return jspb.Message.getField(this, 4) != null; +proto.api.RGANode.prototype.hasElement = function() { + return jspb.Message.getField(this, 2) != null; }; @@ -8240,8 +9939,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.RHTNode.prototype.toObject = function(opt_includeInstance) { - return proto.api.RHTNode.toObject(opt_includeInstance, this); +proto.api.TextNode.prototype.toObject = function(opt_includeInstance) { + return proto.api.TextNode.toObject(opt_includeInstance, this); }; @@ -8250,14 +9949,16 @@ proto.api.RHTNode.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.RHTNode} msg The msg instance to transform. + * @param {!proto.api.TextNode} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.RHTNode.toObject = function(includeInstance, msg) { +proto.api.TextNode.toObject = function(includeInstance, msg) { var f, obj = { - key: jspb.Message.getFieldWithDefault(msg, 1, ""), - element: (f = msg.getElement()) && proto.api.JSONElement.toObject(includeInstance, f) + id: (f = msg.getId()) && proto.api.TextNodeID.toObject(includeInstance, f), + value: jspb.Message.getFieldWithDefault(msg, 2, ""), + removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), + insPrevId: (f = msg.getInsPrevId()) && proto.api.TextNodeID.toObject(includeInstance, f) }; if (includeInstance) { @@ -8271,23 +9972,23 @@ proto.api.RHTNode.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.RHTNode} + * @return {!proto.api.TextNode} */ -proto.api.RHTNode.deserializeBinary = function(bytes) { +proto.api.TextNode.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.RHTNode; - return proto.api.RHTNode.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.TextNode; + return proto.api.TextNode.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.RHTNode} msg The message object to deserialize into. + * @param {!proto.api.TextNode} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.RHTNode} + * @return {!proto.api.TextNode} */ -proto.api.RHTNode.deserializeBinaryFromReader = function(msg, reader) { +proto.api.TextNode.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -8295,13 +9996,23 @@ proto.api.RHTNode.deserializeBinaryFromReader = function(msg, reader) { var field = reader.getFieldNumber(); switch (field) { case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setKey(value); + var value = new proto.api.TextNodeID; + reader.readMessage(value,proto.api.TextNodeID.deserializeBinaryFromReader); + msg.setId(value); break; case 2: - var value = new proto.api.JSONElement; - reader.readMessage(value,proto.api.JSONElement.deserializeBinaryFromReader); - msg.setElement(value); + var value = /** @type {string} */ (reader.readString()); + msg.setValue(value); + break; + case 3: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setRemovedAt(value); + break; + case 4: + var value = new proto.api.TextNodeID; + reader.readMessage(value,proto.api.TextNodeID.deserializeBinaryFromReader); + msg.setInsPrevId(value); break; default: reader.skipField(); @@ -8316,9 +10027,9 @@ proto.api.RHTNode.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.RHTNode.prototype.serializeBinary = function() { +proto.api.TextNode.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.RHTNode.serializeBinaryToWriter(this, writer); + proto.api.TextNode.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -8326,73 +10037,163 @@ proto.api.RHTNode.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.RHTNode} message + * @param {!proto.api.TextNode} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.RHTNode.serializeBinaryToWriter = function(message, writer) { +proto.api.TextNode.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getKey(); + f = message.getId(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.api.TextNodeID.serializeBinaryToWriter + ); + } + f = message.getValue(); if (f.length > 0) { writer.writeString( - 1, + 2, f ); } - f = message.getElement(); + f = message.getRemovedAt(); if (f != null) { writer.writeMessage( - 2, + 3, f, - proto.api.JSONElement.serializeBinaryToWriter + proto.api.TimeTicket.serializeBinaryToWriter + ); + } + f = message.getInsPrevId(); + if (f != null) { + writer.writeMessage( + 4, + f, + proto.api.TextNodeID.serializeBinaryToWriter ); } }; /** - * optional string key = 1; - * @return {string} + * optional TextNodeID id = 1; + * @return {?proto.api.TextNodeID} + */ +proto.api.TextNode.prototype.getId = function() { + return /** @type{?proto.api.TextNodeID} */ ( + jspb.Message.getWrapperField(this, proto.api.TextNodeID, 1)); +}; + + +/** + * @param {?proto.api.TextNodeID|undefined} value + * @return {!proto.api.TextNode} returns this +*/ +proto.api.TextNode.prototype.setId = function(value) { + return jspb.Message.setWrapperField(this, 1, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.TextNode} returns this + */ +proto.api.TextNode.prototype.clearId = function() { + return this.setId(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.api.TextNode.prototype.hasId = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional string value = 2; + * @return {string} + */ +proto.api.TextNode.prototype.getValue = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.api.TextNode} returns this + */ +proto.api.TextNode.prototype.setValue = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + +/** + * optional TimeTicket removed_at = 3; + * @return {?proto.api.TimeTicket} */ -proto.api.RHTNode.prototype.getKey = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +proto.api.TextNode.prototype.getRemovedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); }; /** - * @param {string} value - * @return {!proto.api.RHTNode} returns this + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.TextNode} returns this +*/ +proto.api.TextNode.prototype.setRemovedAt = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.api.TextNode} returns this */ -proto.api.RHTNode.prototype.setKey = function(value) { - return jspb.Message.setProto3StringField(this, 1, value); +proto.api.TextNode.prototype.clearRemovedAt = function() { + return this.setRemovedAt(undefined); }; /** - * optional JSONElement element = 2; - * @return {?proto.api.JSONElement} + * Returns whether this field is set. + * @return {boolean} */ -proto.api.RHTNode.prototype.getElement = function() { - return /** @type{?proto.api.JSONElement} */ ( - jspb.Message.getWrapperField(this, proto.api.JSONElement, 2)); +proto.api.TextNode.prototype.hasRemovedAt = function() { + return jspb.Message.getField(this, 3) != null; }; /** - * @param {?proto.api.JSONElement|undefined} value - * @return {!proto.api.RHTNode} returns this + * optional TextNodeID ins_prev_id = 4; + * @return {?proto.api.TextNodeID} + */ +proto.api.TextNode.prototype.getInsPrevId = function() { + return /** @type{?proto.api.TextNodeID} */ ( + jspb.Message.getWrapperField(this, proto.api.TextNodeID, 4)); +}; + + +/** + * @param {?proto.api.TextNodeID|undefined} value + * @return {!proto.api.TextNode} returns this */ -proto.api.RHTNode.prototype.setElement = function(value) { - return jspb.Message.setWrapperField(this, 2, value); +proto.api.TextNode.prototype.setInsPrevId = function(value) { + return jspb.Message.setWrapperField(this, 4, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.RHTNode} returns this + * @return {!proto.api.TextNode} returns this */ -proto.api.RHTNode.prototype.clearElement = function() { - return this.setElement(undefined); +proto.api.TextNode.prototype.clearInsPrevId = function() { + return this.setInsPrevId(undefined); }; @@ -8400,8 +10201,8 @@ proto.api.RHTNode.prototype.clearElement = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.RHTNode.prototype.hasElement = function() { - return jspb.Message.getField(this, 2) != null; +proto.api.TextNode.prototype.hasInsPrevId = function() { + return jspb.Message.getField(this, 4) != null; }; @@ -8421,8 +10222,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.RGANode.prototype.toObject = function(opt_includeInstance) { - return proto.api.RGANode.toObject(opt_includeInstance, this); +proto.api.RichTextNodeAttr.prototype.toObject = function(opt_includeInstance) { + return proto.api.RichTextNodeAttr.toObject(opt_includeInstance, this); }; @@ -8431,14 +10232,15 @@ proto.api.RGANode.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.RGANode} msg The msg instance to transform. + * @param {!proto.api.RichTextNodeAttr} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.RGANode.toObject = function(includeInstance, msg) { +proto.api.RichTextNodeAttr.toObject = function(includeInstance, msg) { var f, obj = { - next: (f = msg.getNext()) && proto.api.RGANode.toObject(includeInstance, f), - element: (f = msg.getElement()) && proto.api.JSONElement.toObject(includeInstance, f) + key: jspb.Message.getFieldWithDefault(msg, 1, ""), + value: jspb.Message.getFieldWithDefault(msg, 2, ""), + updatedAt: (f = msg.getUpdatedAt()) && proto.api.TimeTicket.toObject(includeInstance, f) }; if (includeInstance) { @@ -8452,23 +10254,23 @@ proto.api.RGANode.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.RGANode} + * @return {!proto.api.RichTextNodeAttr} */ -proto.api.RGANode.deserializeBinary = function(bytes) { +proto.api.RichTextNodeAttr.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.RGANode; - return proto.api.RGANode.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.RichTextNodeAttr; + return proto.api.RichTextNodeAttr.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.RGANode} msg The message object to deserialize into. + * @param {!proto.api.RichTextNodeAttr} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.RGANode} + * @return {!proto.api.RichTextNodeAttr} */ -proto.api.RGANode.deserializeBinaryFromReader = function(msg, reader) { +proto.api.RichTextNodeAttr.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -8476,14 +10278,17 @@ proto.api.RGANode.deserializeBinaryFromReader = function(msg, reader) { var field = reader.getFieldNumber(); switch (field) { case 1: - var value = new proto.api.RGANode; - reader.readMessage(value,proto.api.RGANode.deserializeBinaryFromReader); - msg.setNext(value); + var value = /** @type {string} */ (reader.readString()); + msg.setKey(value); break; case 2: - var value = new proto.api.JSONElement; - reader.readMessage(value,proto.api.JSONElement.deserializeBinaryFromReader); - msg.setElement(value); + var value = /** @type {string} */ (reader.readString()); + msg.setValue(value); + break; + case 3: + var value = new proto.api.TimeTicket; + reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); + msg.setUpdatedAt(value); break; default: reader.skipField(); @@ -8498,9 +10303,9 @@ proto.api.RGANode.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.RGANode.prototype.serializeBinary = function() { +proto.api.RichTextNodeAttr.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.RGANode.serializeBinaryToWriter(this, writer); + proto.api.RichTextNodeAttr.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -8508,93 +10313,98 @@ proto.api.RGANode.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.RGANode} message + * @param {!proto.api.RichTextNodeAttr} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.RGANode.serializeBinaryToWriter = function(message, writer) { +proto.api.RichTextNodeAttr.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getNext(); - if (f != null) { - writer.writeMessage( + f = message.getKey(); + if (f.length > 0) { + writer.writeString( 1, - f, - proto.api.RGANode.serializeBinaryToWriter + f ); } - f = message.getElement(); + f = message.getValue(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } + f = message.getUpdatedAt(); if (f != null) { writer.writeMessage( - 2, + 3, f, - proto.api.JSONElement.serializeBinaryToWriter + proto.api.TimeTicket.serializeBinaryToWriter ); } }; /** - * optional RGANode next = 1; - * @return {?proto.api.RGANode} + * optional string key = 1; + * @return {string} */ -proto.api.RGANode.prototype.getNext = function() { - return /** @type{?proto.api.RGANode} */ ( - jspb.Message.getWrapperField(this, proto.api.RGANode, 1)); +proto.api.RichTextNodeAttr.prototype.getKey = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); }; /** - * @param {?proto.api.RGANode|undefined} value - * @return {!proto.api.RGANode} returns this -*/ -proto.api.RGANode.prototype.setNext = function(value) { - return jspb.Message.setWrapperField(this, 1, value); + * @param {string} value + * @return {!proto.api.RichTextNodeAttr} returns this + */ +proto.api.RichTextNodeAttr.prototype.setKey = function(value) { + return jspb.Message.setProto3StringField(this, 1, value); }; /** - * Clears the message field making it undefined. - * @return {!proto.api.RGANode} returns this + * optional string value = 2; + * @return {string} */ -proto.api.RGANode.prototype.clearNext = function() { - return this.setNext(undefined); +proto.api.RichTextNodeAttr.prototype.getValue = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); }; /** - * Returns whether this field is set. - * @return {boolean} + * @param {string} value + * @return {!proto.api.RichTextNodeAttr} returns this */ -proto.api.RGANode.prototype.hasNext = function() { - return jspb.Message.getField(this, 1) != null; +proto.api.RichTextNodeAttr.prototype.setValue = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); }; /** - * optional JSONElement element = 2; - * @return {?proto.api.JSONElement} + * optional TimeTicket updated_at = 3; + * @return {?proto.api.TimeTicket} */ -proto.api.RGANode.prototype.getElement = function() { - return /** @type{?proto.api.JSONElement} */ ( - jspb.Message.getWrapperField(this, proto.api.JSONElement, 2)); +proto.api.RichTextNodeAttr.prototype.getUpdatedAt = function() { + return /** @type{?proto.api.TimeTicket} */ ( + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); }; /** - * @param {?proto.api.JSONElement|undefined} value - * @return {!proto.api.RGANode} returns this + * @param {?proto.api.TimeTicket|undefined} value + * @return {!proto.api.RichTextNodeAttr} returns this */ -proto.api.RGANode.prototype.setElement = function(value) { - return jspb.Message.setWrapperField(this, 2, value); +proto.api.RichTextNodeAttr.prototype.setUpdatedAt = function(value) { + return jspb.Message.setWrapperField(this, 3, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.RGANode} returns this + * @return {!proto.api.RichTextNodeAttr} returns this */ -proto.api.RGANode.prototype.clearElement = function() { - return this.setElement(undefined); +proto.api.RichTextNodeAttr.prototype.clearUpdatedAt = function() { + return this.setUpdatedAt(undefined); }; @@ -8602,8 +10412,8 @@ proto.api.RGANode.prototype.clearElement = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.RGANode.prototype.hasElement = function() { - return jspb.Message.getField(this, 2) != null; +proto.api.RichTextNodeAttr.prototype.hasUpdatedAt = function() { + return jspb.Message.getField(this, 3) != null; }; @@ -8623,8 +10433,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) { * http://goto/soy-param-migration * @return {!Object} */ -proto.api.TextNode.prototype.toObject = function(opt_includeInstance) { - return proto.api.TextNode.toObject(opt_includeInstance, this); +proto.api.RichTextNode.prototype.toObject = function(opt_includeInstance) { + return proto.api.RichTextNode.toObject(opt_includeInstance, this); }; @@ -8633,14 +10443,15 @@ proto.api.TextNode.prototype.toObject = function(opt_includeInstance) { * @param {boolean|undefined} includeInstance Deprecated. Whether to include * the JSPB instance for transitional soy proto support: * http://goto/soy-param-migration - * @param {!proto.api.TextNode} msg The msg instance to transform. + * @param {!proto.api.RichTextNode} msg The msg instance to transform. * @return {!Object} * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.TextNode.toObject = function(includeInstance, msg) { +proto.api.RichTextNode.toObject = function(includeInstance, msg) { var f, obj = { id: (f = msg.getId()) && proto.api.TextNodeID.toObject(includeInstance, f), - value: jspb.Message.getFieldWithDefault(msg, 2, ""), + attributesMap: (f = msg.getAttributesMap()) ? f.toObject(includeInstance, proto.api.RichTextNodeAttr.toObject) : [], + value: jspb.Message.getFieldWithDefault(msg, 3, ""), removedAt: (f = msg.getRemovedAt()) && proto.api.TimeTicket.toObject(includeInstance, f), insPrevId: (f = msg.getInsPrevId()) && proto.api.TextNodeID.toObject(includeInstance, f) }; @@ -8656,23 +10467,23 @@ proto.api.TextNode.toObject = function(includeInstance, msg) { /** * Deserializes binary data (in protobuf wire format). * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.api.TextNode} + * @return {!proto.api.RichTextNode} */ -proto.api.TextNode.deserializeBinary = function(bytes) { +proto.api.RichTextNode.deserializeBinary = function(bytes) { var reader = new jspb.BinaryReader(bytes); - var msg = new proto.api.TextNode; - return proto.api.TextNode.deserializeBinaryFromReader(msg, reader); + var msg = new proto.api.RichTextNode; + return proto.api.RichTextNode.deserializeBinaryFromReader(msg, reader); }; /** * Deserializes binary data (in protobuf wire format) from the * given reader into the given message object. - * @param {!proto.api.TextNode} msg The message object to deserialize into. + * @param {!proto.api.RichTextNode} msg The message object to deserialize into. * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.api.TextNode} + * @return {!proto.api.RichTextNode} */ -proto.api.TextNode.deserializeBinaryFromReader = function(msg, reader) { +proto.api.RichTextNode.deserializeBinaryFromReader = function(msg, reader) { while (reader.nextField()) { if (reader.isEndGroup()) { break; @@ -8685,15 +10496,21 @@ proto.api.TextNode.deserializeBinaryFromReader = function(msg, reader) { msg.setId(value); break; case 2: + var value = msg.getAttributesMap(); + reader.readMessage(value, function(message, reader) { + jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readMessage, proto.api.RichTextNodeAttr.deserializeBinaryFromReader, "", new proto.api.RichTextNodeAttr()); + }); + break; + case 3: var value = /** @type {string} */ (reader.readString()); msg.setValue(value); break; - case 3: + case 4: var value = new proto.api.TimeTicket; reader.readMessage(value,proto.api.TimeTicket.deserializeBinaryFromReader); msg.setRemovedAt(value); break; - case 4: + case 5: var value = new proto.api.TextNodeID; reader.readMessage(value,proto.api.TextNodeID.deserializeBinaryFromReader); msg.setInsPrevId(value); @@ -8711,9 +10528,9 @@ proto.api.TextNode.deserializeBinaryFromReader = function(msg, reader) { * Serializes the message to binary data (in protobuf wire format). * @return {!Uint8Array} */ -proto.api.TextNode.prototype.serializeBinary = function() { +proto.api.RichTextNode.prototype.serializeBinary = function() { var writer = new jspb.BinaryWriter(); - proto.api.TextNode.serializeBinaryToWriter(this, writer); + proto.api.RichTextNode.serializeBinaryToWriter(this, writer); return writer.getResultBuffer(); }; @@ -8721,11 +10538,11 @@ proto.api.TextNode.prototype.serializeBinary = function() { /** * Serializes the given message to binary data (in protobuf wire * format), writing to the given BinaryWriter. - * @param {!proto.api.TextNode} message + * @param {!proto.api.RichTextNode} message * @param {!jspb.BinaryWriter} writer * @suppress {unusedLocalVariables} f is only used for nested messages */ -proto.api.TextNode.serializeBinaryToWriter = function(message, writer) { +proto.api.RichTextNode.serializeBinaryToWriter = function(message, writer) { var f = undefined; f = message.getId(); if (f != null) { @@ -8735,17 +10552,21 @@ proto.api.TextNode.serializeBinaryToWriter = function(message, writer) { proto.api.TextNodeID.serializeBinaryToWriter ); } + f = message.getAttributesMap(true); + if (f && f.getLength() > 0) { + f.serializeBinary(2, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeMessage, proto.api.RichTextNodeAttr.serializeBinaryToWriter); + } f = message.getValue(); if (f.length > 0) { writer.writeString( - 2, + 3, f ); } f = message.getRemovedAt(); if (f != null) { writer.writeMessage( - 3, + 4, f, proto.api.TimeTicket.serializeBinaryToWriter ); @@ -8753,7 +10574,7 @@ proto.api.TextNode.serializeBinaryToWriter = function(message, writer) { f = message.getInsPrevId(); if (f != null) { writer.writeMessage( - 4, + 5, f, proto.api.TextNodeID.serializeBinaryToWriter ); @@ -8765,7 +10586,7 @@ proto.api.TextNode.serializeBinaryToWriter = function(message, writer) { * optional TextNodeID id = 1; * @return {?proto.api.TextNodeID} */ -proto.api.TextNode.prototype.getId = function() { +proto.api.RichTextNode.prototype.getId = function() { return /** @type{?proto.api.TextNodeID} */ ( jspb.Message.getWrapperField(this, proto.api.TextNodeID, 1)); }; @@ -8773,18 +10594,18 @@ proto.api.TextNode.prototype.getId = function() { /** * @param {?proto.api.TextNodeID|undefined} value - * @return {!proto.api.TextNode} returns this + * @return {!proto.api.RichTextNode} returns this */ -proto.api.TextNode.prototype.setId = function(value) { +proto.api.RichTextNode.prototype.setId = function(value) { return jspb.Message.setWrapperField(this, 1, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.TextNode} returns this + * @return {!proto.api.RichTextNode} returns this */ -proto.api.TextNode.prototype.clearId = function() { +proto.api.RichTextNode.prototype.clearId = function() { return this.setId(undefined); }; @@ -8793,53 +10614,75 @@ proto.api.TextNode.prototype.clearId = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.TextNode.prototype.hasId = function() { +proto.api.RichTextNode.prototype.hasId = function() { return jspb.Message.getField(this, 1) != null; }; /** - * optional string value = 2; + * map attributes = 2; + * @param {boolean=} opt_noLazyCreate Do not create the map if + * empty, instead returning `undefined` + * @return {!jspb.Map} + */ +proto.api.RichTextNode.prototype.getAttributesMap = function(opt_noLazyCreate) { + return /** @type {!jspb.Map} */ ( + jspb.Message.getMapField(this, 2, opt_noLazyCreate, + proto.api.RichTextNodeAttr)); +}; + + +/** + * Clears values from the map. The map will be non-null. + * @return {!proto.api.RichTextNode} returns this + */ +proto.api.RichTextNode.prototype.clearAttributesMap = function() { + this.getAttributesMap().clear(); + return this;}; + + +/** + * optional string value = 3; * @return {string} */ -proto.api.TextNode.prototype.getValue = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +proto.api.RichTextNode.prototype.getValue = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); }; /** * @param {string} value - * @return {!proto.api.TextNode} returns this + * @return {!proto.api.RichTextNode} returns this */ -proto.api.TextNode.prototype.setValue = function(value) { - return jspb.Message.setProto3StringField(this, 2, value); +proto.api.RichTextNode.prototype.setValue = function(value) { + return jspb.Message.setProto3StringField(this, 3, value); }; /** - * optional TimeTicket removed_at = 3; + * optional TimeTicket removed_at = 4; * @return {?proto.api.TimeTicket} */ -proto.api.TextNode.prototype.getRemovedAt = function() { +proto.api.RichTextNode.prototype.getRemovedAt = function() { return /** @type{?proto.api.TimeTicket} */ ( - jspb.Message.getWrapperField(this, proto.api.TimeTicket, 3)); + jspb.Message.getWrapperField(this, proto.api.TimeTicket, 4)); }; /** * @param {?proto.api.TimeTicket|undefined} value - * @return {!proto.api.TextNode} returns this + * @return {!proto.api.RichTextNode} returns this */ -proto.api.TextNode.prototype.setRemovedAt = function(value) { - return jspb.Message.setWrapperField(this, 3, value); +proto.api.RichTextNode.prototype.setRemovedAt = function(value) { + return jspb.Message.setWrapperField(this, 4, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.TextNode} returns this + * @return {!proto.api.RichTextNode} returns this */ -proto.api.TextNode.prototype.clearRemovedAt = function() { +proto.api.RichTextNode.prototype.clearRemovedAt = function() { return this.setRemovedAt(undefined); }; @@ -8848,35 +10691,35 @@ proto.api.TextNode.prototype.clearRemovedAt = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.TextNode.prototype.hasRemovedAt = function() { - return jspb.Message.getField(this, 3) != null; +proto.api.RichTextNode.prototype.hasRemovedAt = function() { + return jspb.Message.getField(this, 4) != null; }; /** - * optional TextNodeID ins_prev_id = 4; + * optional TextNodeID ins_prev_id = 5; * @return {?proto.api.TextNodeID} */ -proto.api.TextNode.prototype.getInsPrevId = function() { +proto.api.RichTextNode.prototype.getInsPrevId = function() { return /** @type{?proto.api.TextNodeID} */ ( - jspb.Message.getWrapperField(this, proto.api.TextNodeID, 4)); + jspb.Message.getWrapperField(this, proto.api.TextNodeID, 5)); }; /** * @param {?proto.api.TextNodeID|undefined} value - * @return {!proto.api.TextNode} returns this + * @return {!proto.api.RichTextNode} returns this */ -proto.api.TextNode.prototype.setInsPrevId = function(value) { - return jspb.Message.setWrapperField(this, 4, value); +proto.api.RichTextNode.prototype.setInsPrevId = function(value) { + return jspb.Message.setWrapperField(this, 5, value); }; /** * Clears the message field making it undefined. - * @return {!proto.api.TextNode} returns this + * @return {!proto.api.RichTextNode} returns this */ -proto.api.TextNode.prototype.clearInsPrevId = function() { +proto.api.RichTextNode.prototype.clearInsPrevId = function() { return this.setInsPrevId(undefined); }; @@ -8885,8 +10728,8 @@ proto.api.TextNode.prototype.clearInsPrevId = function() { * Returns whether this field is set. * @return {boolean} */ -proto.api.TextNode.prototype.hasInsPrevId = function() { - return jspb.Message.getField(this, 4) != null; +proto.api.RichTextNode.prototype.hasInsPrevId = function() { + return jspb.Message.getField(this, 5) != null; }; @@ -9806,7 +11649,8 @@ proto.api.ValueType = { DATE: 7, JSON_OBJECT: 8, JSON_ARRAY: 9, - TEXT: 10 + TEXT: 10, + RICH_TEXT: 11 }; goog.object.extend(exports, proto.api); diff --git a/src/core/client.ts b/src/core/client.ts index 3ecb831ff..7d12b2dc6 100644 --- a/src/core/client.ts +++ b/src/core/client.ts @@ -111,6 +111,7 @@ export class Client implements Observable { this.client.activateClient(req, {}, (err, res) => { if (err) { + logger.error(`[AC] c:"${this.getKey()}" err :"${err}"`); reject(err); return; } @@ -150,6 +151,7 @@ export class Client implements Observable { this.client.deactivateClient(req, {}, (err,) => { if (err) { + logger.error(`[DC] c:"${this.getKey()}" err :"${err}"`); reject(err); return; } @@ -184,6 +186,7 @@ export class Client implements Observable { this.client.attachDocument(req, {}, (err, res) => { if (err) { + logger.error(`[AD] c:"${this.getKey()}" err :"${err}"`); reject(err); return; } @@ -223,6 +226,7 @@ export class Client implements Observable { this.client.detachDocument(req, {}, (err, res) => { if (err) { + logger.error(`[DD] c:"${this.getKey()}" err :"${err}"`); reject(err); return; } @@ -371,6 +375,8 @@ export class Client implements Observable { let isRejected = false; this.client.pushPull(req, {}, (err, res) => { if (err) { + logger.error(`[PP] c:"${this.getKey()}" err :"${err}"`); + isRejected = true; reject(err); return; diff --git a/src/document/json/object.ts b/src/document/json/object.ts index 0723d9127..2da5d2b7e 100644 --- a/src/document/json/object.ts +++ b/src/document/json/object.ts @@ -17,7 +17,7 @@ import { logger } from '../../util/logger'; import { TimeTicket } from '../time/ticket'; import { JSONContainer, JSONElement } from './element'; -import { RHT } from './rht'; +import { RHTPQMap } from './rht_pq_map'; import { PlainText } from './text'; /** @@ -25,15 +25,15 @@ import { PlainText } from './text'; * tickets which is created by logical clock. */ export class JSONObject extends JSONContainer { - private memberNodes: RHT; + private memberNodes: RHTPQMap; - constructor(createdAt: TimeTicket, memberNodes: RHT) { + constructor(createdAt: TimeTicket, memberNodes: RHTPQMap) { super(createdAt); this.memberNodes = memberNodes; } public static create(createdAt: TimeTicket): JSONObject { - return new JSONObject(createdAt, RHT.create()); + return new JSONObject(createdAt, RHTPQMap.create()); } public createText(key: string): PlainText { @@ -84,7 +84,7 @@ export class JSONObject extends JSONContainer { return `{${json.join(',')}}`; } - public getRHT(): RHT { + public getRHT(): RHTPQMap { return this.memberNodes; } diff --git a/src/document/json/rga_tree_split.ts b/src/document/json/rga_tree_split.ts new file mode 100644 index 000000000..d73b1b99a --- /dev/null +++ b/src/document/json/rga_tree_split.ts @@ -0,0 +1,574 @@ +/* + * Copyright 2020 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { logger } from '../../util/logger'; +import { ActorID } from '../time/actor_id'; +import { Comparator } from '../../util/comparator'; +import { SplayNode, SplayTree } from '../../util/splay_tree'; +import { LLRBTree } from '../../util/llrb_tree'; +import { InitialTimeTicket, MaxTimeTicket, TimeTicket } from '../time/ticket'; +import { JSONElement } from './element'; + +export enum ChangeType { + Content = 'content', + Selection = 'selection', + Style = 'style', +} + +export interface Change { + type: ChangeType; + actor: ActorID; + from: number; + to: number; + content?: string; + attributes?: { [key: string]: string; }; +} + +interface RGATreeSplitValue { + length: number; + substring(indexStart: number, indexEnd?: number): RGATreeSplitValue; +} + +export class RGATreeSplitNodeID { + private createdAt: TimeTicket; + private offset: number; + + constructor(createdAt: TimeTicket, offset: number) { + this.createdAt = createdAt; + this.offset = offset; + } + + public static of(createdAt: TimeTicket, offset: number): RGATreeSplitNodeID { + return new RGATreeSplitNodeID(createdAt, offset); + } + + public getCreatedAt(): TimeTicket { + return this.createdAt; + } + + public getOffset(): number { + return this.offset; + } + + public equals(other: RGATreeSplitNodeID): boolean { + return this.createdAt.compare(other.createdAt) === 0 + && this.offset === other.offset; + } + + public hasSameCreatedAt(other: RGATreeSplitNodeID): boolean { + return this.createdAt.compare(other.createdAt) === 0; + } + + public split(offset: number): RGATreeSplitNodeID { + return new RGATreeSplitNodeID(this.createdAt, this.offset + offset); + } + + public getAnnotatedString(): string { + return `${this.createdAt.getAnnotatedString()}:${this.offset}`; + } +} + +const InitialRGATreeSplitNodeID = RGATreeSplitNodeID.of(InitialTimeTicket, 0); + +export class RGATreeSplitNodePos { + private id: RGATreeSplitNodeID; + private relativeOffset: number; + + constructor(id: RGATreeSplitNodeID, relativeOffset: number) { + this.id = id; + this.relativeOffset = relativeOffset; + } + + public static of(id: RGATreeSplitNodeID, relativeOffset: number): RGATreeSplitNodePos { + return new RGATreeSplitNodePos(id, relativeOffset); + } + + public getID(): RGATreeSplitNodeID { + return this.id; + } + + public getRelativeOffset(): number { + return this.relativeOffset; + } + + public getAbsoluteID(): RGATreeSplitNodeID { + return RGATreeSplitNodeID.of( + this.id.getCreatedAt(), + this.id.getOffset() + this.relativeOffset, + ); + } + + public getAnnotatedString(): string { + return `${this.id.getAnnotatedString()}:${this.relativeOffset}`; + } +} + +export type RGATreeSplitNodeRange = [RGATreeSplitNodePos, RGATreeSplitNodePos]; + +export class RGATreeSplitNode extends SplayNode { + private id: RGATreeSplitNodeID; + private removedAt: TimeTicket; + + private prev: RGATreeSplitNode; + private next: RGATreeSplitNode; + private insPrev: RGATreeSplitNode; + private insNext: RGATreeSplitNode; + + constructor(id: RGATreeSplitNodeID, value?: T, removedAt?: TimeTicket) { + super(value); + this.id = id; + this.removedAt = removedAt; + } + + public static create(id: RGATreeSplitNodeID, value?: T): RGATreeSplitNode { + return new RGATreeSplitNode(id, value); + } + + public static createComparator(): Comparator { + return (p1: RGATreeSplitNodeID, p2: RGATreeSplitNodeID): number => { + const compare = p1.getCreatedAt().compare(p2.getCreatedAt()); + if (compare !== 0) { + return compare; + } + + if (p1.getOffset() > p2.getOffset()) { + return 1; + } else if (p1.getOffset() < p2.getOffset()) { + return -1; + } + return 0; + }; + } + + public getID(): RGATreeSplitNodeID { + return this.id; + } + + public getCreatedAt(): TimeTicket { + return this.id.getCreatedAt(); + } + + public getLength(): number { + if (this.removedAt) { + return 0; + } + return this.getContentLength(); + } + + public getContentLength(): number { + return this.value && this.value.length || 0; + } + + public getNext(): RGATreeSplitNode { + return this.next; + } + + public getInsPrev(): RGATreeSplitNode { + return this.insPrev; + } + + public getInsNext(): RGATreeSplitNode { + return this.insNext; + } + + public getInsPrevID(): RGATreeSplitNodeID { + return this.insPrev.getID(); + } + + public setPrev(node: RGATreeSplitNode): void { + this.prev = node; + node.next = this; + } + + public setInsPrev(node: RGATreeSplitNode): void { + this.insPrev = node; + node.insNext = this; + } + + public hasNext(): boolean { + return !!this.next; + } + + public hasInsPrev(): boolean { + return !!this.insPrev; + } + + public isRemoved(): boolean { + return !!this.removedAt; + } + + public getRemovedAt(): TimeTicket { + return this.removedAt; + } + + public split(offset: number): RGATreeSplitNode { + return new RGATreeSplitNode( + this.id.split(offset), + this.splitValue(offset) + ); + } + + public canDelete(editedAt: TimeTicket, latestCreatedAt: TimeTicket): boolean { + return (!this.getCreatedAt().after(latestCreatedAt) && + (!this.removedAt || editedAt.after(this.removedAt))); + } + + public remove(editedAt: TimeTicket): void { + this.removedAt = editedAt; + } + + public createRange(): RGATreeSplitNodeRange { + return [ + RGATreeSplitNodePos.of(this.id, 0), + RGATreeSplitNodePos.of(this.id, this.getLength()) + ]; + } + + public deepcopy(): RGATreeSplitNode { + return new RGATreeSplitNode( + this.id, + this.value, + this.removedAt + ); + } + + public getAnnotatedString(): string { + return `${this.id.getAnnotatedString()} ${this.value ? this.value : ''}`; + } + + private splitValue(offset: number): T { + const value = this.value; + this.value = value.substring(0, offset) as T; + return value.substring(offset, value.length) as T; + } +} + +export class RGATreeSplit { + private head: RGATreeSplitNode; + private treeByIndex: SplayTree; + private treeByID: LLRBTree>; + + constructor() { + this.head = RGATreeSplitNode.create(InitialRGATreeSplitNodeID); + this.treeByIndex = new SplayTree(); + this.treeByID = new LLRBTree(RGATreeSplitNode.createComparator()); + + this.treeByIndex.insert(this.head); + this.treeByID.put(this.head.getID(), this.head); + } + + public static create(): RGATreeSplit { + return new RGATreeSplit(); + } + + public edit( + range: RGATreeSplitNodeRange, + value: T, + latestCreatedAtMapByActor: Map, + editedAt: TimeTicket + ): [RGATreeSplitNodePos, Map, Array] { + // 01. split nodes with from and to + const [toLeft, toRight] = this.findNodeWithSplit(range[1], editedAt); + const [fromLeft, fromRight] = this.findNodeWithSplit(range[0], editedAt); + + // 02. delete between from and to + const nodesToDelete = this.findBetween(fromRight, toRight); + const [changes, latestCreatedAtMap] = this.deleteNodes( + nodesToDelete, latestCreatedAtMapByActor, editedAt + ); + + const caretID = toRight ? toRight.getID() : toLeft.getID(); + let caretPos = RGATreeSplitNodePos.of(caretID, 0); + + // 03. insert a new node + if (value) { + const idx = this.findIdxFromNodePos(fromLeft.createRange()[1], true); + + const inserted = this.insertAfter( + fromLeft, + RGATreeSplitNode.create(RGATreeSplitNodeID.of(editedAt, 0), value) + ); + + changes.push({ + type: ChangeType.Content, + actor: editedAt.getActorID(), + from: idx, + to: idx, + content: value.toString() + }); + + caretPos = RGATreeSplitNodePos.of(inserted.getID(), inserted.getContentLength()); + } + + return [caretPos, latestCreatedAtMap, changes]; + } + + public findNodePos(idx: number): RGATreeSplitNodePos { + const [node, offset] = this.treeByIndex.find(idx); + const splitNode = node as RGATreeSplitNode; + return RGATreeSplitNodePos.of(splitNode.getID(), offset); + } + + public findIndexesFromRange(range: RGATreeSplitNodeRange): [number, number] { + const [fromPos, toPos] = range; + return [ + this.findIdxFromNodePos(fromPos, false), + this.findIdxFromNodePos(toPos, true) + ]; + } + + public findIdxFromNodePos(pos: RGATreeSplitNodePos, preferToLeft: boolean): number { + const absoluteID = pos.getAbsoluteID(); + const node = preferToLeft ? + this.findFloorNodePerferToLeft(absoluteID) : this.findFloorNode(absoluteID); + const index = this.treeByIndex.indexOf(node); + if (!node) { + logger.fatal(`the node of the given id should be found: ${absoluteID.getAnnotatedString()}`); + } + const offset = node.isRemoved() ? 0 : absoluteID.getOffset() - node.getID().getOffset(); + return index + offset; + } + + public findNode(id: RGATreeSplitNodeID): RGATreeSplitNode { + return this.findFloorNode(id); + } + + public toJSON(): string { + const json = []; + + for (const node of this) { + if (!node.isRemoved()) { + json.push(node.getValue()); + } + } + + return json.join(''); + } + + public *[Symbol.iterator](): IterableIterator> { + let node = this.head.getNext(); + while(node) { + yield node; + node = node.getNext(); + } + } + + public getHead(): RGATreeSplitNode { + return this.head; + } + + public deepcopy(): RGATreeSplit { + const clone = new RGATreeSplit(); + + let node = this.head.getNext(); + + let prev = clone.head; + let current + while (node) { + current = clone.insertAfter(prev, node.deepcopy()); + if (node.hasInsPrev()) { + const insPrevNode = clone.findNode(node.getInsPrevID()); + current.setInsPrev(insPrevNode); + } + + prev = current; + node = node.getNext(); + } + + return clone; + } + + public getAnnotatedString(): string { + const result = []; + + let node = this.head; + while(node) { + if (node.isRemoved()) { + result.push(`{${node.getAnnotatedString()}}`); + } else { + result.push(`[${node.getAnnotatedString()}]`); + } + + node = node.getNext(); + } + + return result.join(''); + } + + public insertAfter(prevNode: RGATreeSplitNode, newNode: RGATreeSplitNode): RGATreeSplitNode { + const next = prevNode.getNext(); + newNode.setPrev(prevNode); + if (next) { + next.setPrev(newNode); + } + + this.treeByID.put(newNode.getID(), newNode); + this.treeByIndex.insertAfter(prevNode, newNode); + + return newNode; + } + + public findNodeWithSplit(pos: RGATreeSplitNodePos, editedAt: TimeTicket): [RGATreeSplitNode, RGATreeSplitNode] { + const absoluteID = pos.getAbsoluteID(); + let node = this.findFloorNodePerferToLeft(absoluteID); + const relativeOffset = absoluteID.getOffset() - node.getID().getOffset(); + + this.splitNode(node, relativeOffset); + + while(node.hasNext() && node.getNext().getCreatedAt().after(editedAt)) { + node = node.getNext(); + } + + return [node, node.getNext()]; + } + + private findFloorNodePerferToLeft(id: RGATreeSplitNodeID): RGATreeSplitNode { + let node = this.findFloorNode(id); + if (!node) { + logger.fatal(`the node of the given id should be found: ${id.getAnnotatedString()}`); + } + + if (id.getOffset() > 0 && node.getID().getOffset() == id.getOffset()) { + if (!node.hasInsPrev()) { + logger.fatal('insPrev should be presence'); + } + node = node.getInsPrev() + } + + return node; + } + + private findFloorNode(id: RGATreeSplitNodeID): RGATreeSplitNode { + const entry = this.treeByID.floorEntry(id); + if (!entry) { + return null; + } + + if (!entry.key.equals(id) && !entry.key.hasSameCreatedAt(id)) { + return null; + } + + return entry.value; + } + + public findBetween(fromNode: RGATreeSplitNode, toNode: RGATreeSplitNode): Array> { + const nodes = []; + + let current = fromNode; + while (current && current !== toNode) { + nodes.push(current); + current = current.getNext(); + } + + return nodes; + } + + private splitNode(node: RGATreeSplitNode, offset: number): RGATreeSplitNode { + if (offset > node.getContentLength()) { + logger.fatal('offset should be less than or equal to length'); + } + + if (offset === 0) { + return node; + } else if (offset === node.getContentLength()) { + return node.getNext(); + } + + const splitNode = node.split(offset); + this.treeByIndex.updateSubtree(splitNode); + this.insertAfter(node, splitNode); + + const insNext = node.getInsNext(); + if (insNext) { + insNext.setInsPrev(splitNode); + } + splitNode.setInsPrev(node); + + return splitNode; + } + + private deleteNodes( + candidates: Array>, + latestCreatedAtMapByActor: Map, + editedAt: TimeTicket + ): [Array, Map] { + const isRemote = !!latestCreatedAtMapByActor; + const changes: Array = []; + const createdAtMapByActor = new Map(); + const nodesToDelete = []; + + // NOTE: We need to collect indexes for change first then delete the nodes. + for (const node of candidates) { + const actorID = node.getCreatedAt().getActorID(); + + const latestCreatedAt = isRemote ? ( + latestCreatedAtMapByActor.has(actorID) ? latestCreatedAtMapByActor.get(actorID) : InitialTimeTicket + ) : MaxTimeTicket; + + // Delete nodes created before the latest time remaining in the replica that performed the deletion. + if (node.canDelete(editedAt, latestCreatedAt)) { + nodesToDelete.push(node); + + const [fromIdx, toIdx] = this.findIndexesFromRange(node.createRange()); + const change = { + type: ChangeType.Content, + actor: editedAt.getActorID(), + from: fromIdx, + to: toIdx + }; + + // Reduce adjacent deletions: i.g) [(1, 2), (2, 3)] => [(1, 3)] + if (changes.length && changes[0].to === change.from) { + changes[0].to = change.to; + } else { + changes.unshift(change); + } + + if (!createdAtMapByActor.has(actorID) || + node.getID().getCreatedAt().after(createdAtMapByActor.get(actorID))) { + createdAtMapByActor.set(actorID, node.getID().getCreatedAt()); + } + } + } + + for (const node of nodesToDelete) { + node.remove(editedAt); + this.treeByIndex.splayNode(node); + } + + return [changes, createdAtMapByActor]; + } +} + +export class Selection { + private from: RGATreeSplitNodePos; + private to: RGATreeSplitNodePos; + private updatedAt: TimeTicket; + + constructor(from: RGATreeSplitNodePos, to: RGATreeSplitNodePos, updatedAt: TimeTicket) { + this.from = from; + this.to = to; + this.updatedAt = updatedAt; + } + + public static of(range: RGATreeSplitNodeRange, updatedAt: TimeTicket): Selection { + return new Selection(range[0], range[1], updatedAt); + } + + public getUpdatedAt(): TimeTicket { + return this.updatedAt; + } +} diff --git a/src/document/json/rht.ts b/src/document/json/rht.ts index 3b4de2b2e..bb5d73a34 100644 --- a/src/document/json/rht.ts +++ b/src/document/json/rht.ts @@ -14,44 +14,46 @@ * limitations under the License. */ -import { HeapNode, Heap } from '../../util/heap'; import { TicketComparator, TimeTicket } from '../time/ticket'; import { JSONElement } from './element'; -export class RHTNode extends HeapNode { - private strKey: string; +export class RHTNode { + private key: string; + private value: string; + private updatedAt: TimeTicket; - constructor(strKey: string, value: JSONElement) { - super(value.getCreatedAt(), value); - this.strKey = strKey; + constructor(key: string, value: string, updatedAt: TimeTicket) { + this.key = key; + this.value = value; + this.updatedAt = updatedAt; } - public static of(strKey: string, value: JSONElement): RHTNode { - return new RHTNode(strKey, value); + public static of(key: string, value: string, createdAt: TimeTicket): RHTNode { + return new RHTNode(key, value, createdAt); } - public isRemoved(): boolean { - return this.getValue().isRemoved(); + public getKey(): string { + return this.key; } - public getStrKey(): string { - return this.strKey; + public getValue(): string { + return this.value; } - public remove(removedAt: TimeTicket): void { - this.getValue().remove(removedAt); + public getUpdatedAt(): TimeTicket { + return this.updatedAt; } } /** - * RHT is replicated hash table. + * RHT is replicated hash table with priority queue by creation time. */ export class RHT { - private elementQueueMapByKey: Map>; - private nodeMapByCreatedAt: Map; + private nodeMapByKey: Map; + private nodeMapByCreatedAt: Map; constructor() { - this.elementQueueMapByKey = new Map(); + this.nodeMapByKey = new Map(); this.nodeMapByCreatedAt = new Map(); } @@ -59,56 +61,48 @@ export class RHT { return new RHT() } - public set(key: string, value: JSONElement): void { - if (!this.elementQueueMapByKey.has(key)) { - this.elementQueueMapByKey.set(key, new Heap(TicketComparator)); - } - - const node = RHTNode.of(key, value); - this.elementQueueMapByKey.get(key).push(node); - this.nodeMapByCreatedAt.set(value.getCreatedAt().toIDString(), node); - } + public set(key: string, value: string, updatedAt: TimeTicket): void { + const prev = this.nodeMapByKey.get(key); - public delete(createdAt: TimeTicket, executedAt: TimeTicket): JSONElement { - if (!this.nodeMapByCreatedAt.has(createdAt.toIDString())) { - return null; + if (prev === undefined || updatedAt.after(prev.getUpdatedAt())) { + const node = RHTNode.of(key, value, updatedAt); + this.nodeMapByKey.set(key, node); + this.nodeMapByCreatedAt.set(updatedAt.toIDString(), node); } + } - this.nodeMapByCreatedAt.get(createdAt.toIDString()).remove(executedAt); + public has(key: string): boolean { + return this.nodeMapByKey.has(key); } - public deleteByKey(key: string, removedAt: TimeTicket): JSONElement { - if (!this.elementQueueMapByKey.has(key)) { + public get(key: string): string { + if (!this.nodeMapByKey.has(key)) { return null; } - const node = this.elementQueueMapByKey.get(key).peek() as RHTNode; - node.remove(removedAt); - return node.getValue(); + return this.nodeMapByKey.get(key).getValue(); } - public has(key: string): boolean { - if (!this.elementQueueMapByKey.has(key)) { - return false; + public toJSON(): string { + const items = []; + for (const [key, node] of this.nodeMapByKey) { + items.push(`"${key}":"${node.getValue()}"`); } - - const node = this.elementQueueMapByKey.get(key).peek() as RHTNode; - return !node.isRemoved(); + return `{${items.join(",")}}`; } - public get(key: string): JSONElement { - if (!this.elementQueueMapByKey.has(key)) { - return null; + public toObject(): { [key: string]: string } { + const obj = {} as { [key: string]: string }; + for (const [key, node] of this.nodeMapByKey) { + obj[key as string] = node.getValue(); } - return this.elementQueueMapByKey.get(key).peek().getValue(); + return obj; } public *[Symbol.iterator](): IterableIterator { - for (const [, heap] of this.elementQueueMapByKey) { - for (const node of heap) { - yield node as RHTNode; - } + for (const [, node] of this.nodeMapByKey) { + yield node as RHTNode; } } } diff --git a/src/document/json/rht_pq_map.ts b/src/document/json/rht_pq_map.ts new file mode 100644 index 000000000..c5cc3a90b --- /dev/null +++ b/src/document/json/rht_pq_map.ts @@ -0,0 +1,114 @@ +/* + * Copyright 2020 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HeapNode, Heap } from '../../util/heap'; +import { TicketComparator, TimeTicket } from '../time/ticket'; +import { JSONElement } from './element'; + +export class RHTPQMapNode extends HeapNode { + private strKey: string; + + constructor(strKey: string, value: JSONElement) { + super(value.getCreatedAt(), value); + this.strKey = strKey; + } + + public static of(strKey: string, value: JSONElement): RHTPQMapNode { + return new RHTPQMapNode(strKey, value); + } + + public isRemoved(): boolean { + return this.getValue().isRemoved(); + } + + public getStrKey(): string { + return this.strKey; + } + + public remove(removedAt: TimeTicket): void { + this.getValue().remove(removedAt); + } +} + +/** + * RHT is replicated hash table with priority queue by creation time. + */ +export class RHTPQMap { + private elementQueueMapByKey: Map>; + private nodeMapByCreatedAt: Map; + + constructor() { + this.elementQueueMapByKey = new Map(); + this.nodeMapByCreatedAt = new Map(); + } + + public static create(): RHTPQMap { + return new RHTPQMap() + } + + public set(key: string, value: JSONElement): void { + if (!this.elementQueueMapByKey.has(key)) { + this.elementQueueMapByKey.set(key, new Heap(TicketComparator)); + } + + const node = RHTPQMapNode.of(key, value); + this.elementQueueMapByKey.get(key).push(node); + this.nodeMapByCreatedAt.set(value.getCreatedAt().toIDString(), node); + } + + public delete(createdAt: TimeTicket, executedAt: TimeTicket): JSONElement { + if (!this.nodeMapByCreatedAt.has(createdAt.toIDString())) { + return null; + } + + this.nodeMapByCreatedAt.get(createdAt.toIDString()).remove(executedAt); + } + + public deleteByKey(key: string, removedAt: TimeTicket): JSONElement { + if (!this.elementQueueMapByKey.has(key)) { + return null; + } + + const node = this.elementQueueMapByKey.get(key).peek() as RHTPQMapNode; + node.remove(removedAt); + return node.getValue(); + } + + public has(key: string): boolean { + if (!this.elementQueueMapByKey.has(key)) { + return false; + } + + const node = this.elementQueueMapByKey.get(key).peek() as RHTPQMapNode; + return !node.isRemoved(); + } + + public get(key: string): JSONElement { + if (!this.elementQueueMapByKey.has(key)) { + return null; + } + + return this.elementQueueMapByKey.get(key).peek().getValue(); + } + + public *[Symbol.iterator](): IterableIterator { + for (const [, heap] of this.elementQueueMapByKey) { + for (const node of heap) { + yield node as RHTPQMapNode; + } + } + } +} diff --git a/src/document/json/rich_text.ts b/src/document/json/rich_text.ts new file mode 100644 index 000000000..8fee07463 --- /dev/null +++ b/src/document/json/rich_text.ts @@ -0,0 +1,293 @@ +/* + * Copyright 2020 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { logger } from '../../util/logger'; +import { ActorID } from '../time/actor_id'; +import { LLRBTree } from '../../util/llrb_tree'; +import { TimeTicket } from '../time/ticket'; +import { RHT } from './rht'; +import { JSONElement } from './element'; +import { + Change, + ChangeType, + RGATreeSplit, + RGATreeSplitNodeRange, + RGATreeSplitNodePos, + RGATreeSplitNode, + Selection +} from './rga_tree_split'; + +export interface RichTextVal { + attributes: { [key: string]: string; }; + content: string; +} + +export class RichTextValue { + private attributes: RHT; + private content: string; + + constructor(content: string) { + this.attributes = RHT.create(); + this.content = content; + } + + public static create(content: string): RichTextValue { + return new RichTextValue(content); + } + + public get length(): number { + return this.content.length; + } + + public substring(offset: number): RichTextValue { + const value = this.content; + this.content = value.substring(0, offset); + return new RichTextValue( + value.substring(offset, value.length) + ); + } + + public setAttr(key: string, value: string, updatedAt: TimeTicket): void { + this.attributes.set(key, value, updatedAt); + } + + public toString(): string { + return this.content; + } + + public toJSON(): string { + return `{"attrs":${this.attributes.toJSON()},"content":${this.content}}`; + } + + public getAttributes(): { [key: string]: string } { + return this.attributes.toObject(); + } + + public getContent(): string { + return this.content; + } +} + +export class RichText extends JSONElement { + private onChangesHandler: (changes: Array) => void; + private rgaTreeSplit: RGATreeSplit; + private selectionMap: Map; + private remoteChangeLock: boolean; + + constructor(rgaTreeSplit: RGATreeSplit, createdAt: TimeTicket) { + super(createdAt); + this.rgaTreeSplit = rgaTreeSplit; + this.selectionMap = new Map(); + this.remoteChangeLock = false; + } + + public static create(rgaTreeSplit: RGATreeSplit, createdAt: TimeTicket): RichText { + const text = new RichText(rgaTreeSplit, createdAt); + const range = text.createRange(0, 0); + text.editInternal(range, '\n', null, null, createdAt); + return text; + } + + public edit(fromIdx: number, toIdx: number, content: string, attributes: { [key: string]: string; }): RichText { + logger.fatal( + `unsupported: this method should be called by proxy, ${fromIdx}-${toIdx} ${content}` + ); + return null; + } + + public setStyle(fromIdx: number, toIdx: number, key: string, value: string): RichText { + logger.fatal( + `unsupported: this method should be called by proxy, ${fromIdx}-${toIdx} ${key} ${value}` + ); + return null; + } + + public editInternal( + range: RGATreeSplitNodeRange, + content: string, + attributes: { [key: string]: string; }, + latestCreatedAtMapByActor: Map, + editedAt: TimeTicket + ): Map { + let value = content ? RichTextValue.create(content) : null; + if (content && attributes) { + for (const [k, v] of Object.entries(attributes)) { + value.setAttr(k, v, editedAt); + } + } + + const [caretPos, latestCreatedAtMap, changes] = this.rgaTreeSplit.edit( + range, + value, + latestCreatedAtMapByActor, + editedAt, + ); + if (content && attributes) { + const change = changes[changes.length - 1]; + change.attributes = attributes; + } + + const selectionChange = this.updateSelectionInternal([caretPos, caretPos], editedAt); + if (selectionChange) { + changes.push(selectionChange); + } + + if (this.onChangesHandler) { + this.remoteChangeLock = true; + this.onChangesHandler(changes); + this.remoteChangeLock = false; + } + + return latestCreatedAtMap; + } + + public setStyleInternal( + range: RGATreeSplitNodeRange, + attributes: { [key: string]: string; }, + editedAt: TimeTicket + ): void { + // 01. split nodes with from and to + const [toLeft, toRight] = this.rgaTreeSplit.findNodeWithSplit(range[1], editedAt); + const [fromLeft, fromRight] = this.rgaTreeSplit.findNodeWithSplit(range[0], editedAt); + + // 02. style nodes between from and to + const changes = []; + const nodes = this.rgaTreeSplit.findBetween(fromRight, toRight); + for (const node of nodes) { + if (node.isRemoved()) { + continue; + } + + const [fromIdx, toIdx] = this.rgaTreeSplit.findIndexesFromRange(node.createRange()); + changes.push({ + type: ChangeType.Style, + actor: editedAt.getActorID(), + from: fromIdx, + to: toIdx, + attributes: attributes + }); + + for (const [key, value] of Object.entries(attributes)) { + node.getValue().setAttr(key, value, editedAt); + } + } + + if (this.onChangesHandler) { + this.remoteChangeLock = true; + this.onChangesHandler(changes); + this.remoteChangeLock = false; + } + } + + public updateSelection(range: RGATreeSplitNodeRange, updatedAt: TimeTicket): void { + if (this.remoteChangeLock) { + return; + } + + const change = this.updateSelectionInternal(range, updatedAt); + if (this.onChangesHandler && change) { + this.remoteChangeLock = true; + this.onChangesHandler([change]); + this.remoteChangeLock = false; + } + } + + public hasRemoteChangeLock(): boolean { + return this.remoteChangeLock; + } + + public onChanges(handler: (changes: Array) => void): void { + this.onChangesHandler = handler; + } + + public createRange(fromIdx: number, toIdx: number): RGATreeSplitNodeRange { + const fromPos = this.rgaTreeSplit.findNodePos(fromIdx); + if (fromIdx === toIdx) { + return [fromPos, fromPos]; + } + + return [fromPos, this.rgaTreeSplit.findNodePos(toIdx)]; + } + + public toJSON(): string { + const json = []; + + for (const node of this.rgaTreeSplit) { + if (!node.isRemoved()) { + json.push(node.getValue().toJSON()); + } + } + + return `[${json.join(',')}]`; + } + + public toSortedJSON(): string { + return this.toJSON(); + } + + public getValue(): Array { + const values = []; + + for (const node of this.rgaTreeSplit) { + if (!node.isRemoved()) { + const value = node.getValue(); + values.push({ + attributes: value.getAttributes(), + content: value.getContent() + }); + } + } + + return values; + } + + public getRGATreeSplit(): RGATreeSplit { + return this.rgaTreeSplit; + } + + public getAnnotatedString(): string { + return this.rgaTreeSplit.getAnnotatedString(); + } + + public deepcopy(): RichText { + const text = new RichText( + this.rgaTreeSplit.deepcopy(), + this.getCreatedAt() + ); + text.remove(this.getRemovedAt()); + return text; + } + + private updateSelectionInternal(range: RGATreeSplitNodeRange, updatedAt: TimeTicket): Change { + if (!this.selectionMap.has(updatedAt.getActorID())) { + this.selectionMap.set(updatedAt.getActorID(), Selection.of(range, updatedAt)); + return null; + } + + const prevSelection = this.selectionMap.get(updatedAt.getActorID()); + if (updatedAt.after(prevSelection.getUpdatedAt())) { + this.selectionMap.set(updatedAt.getActorID(), Selection.of(range, updatedAt)); + + const [from, to] = this.rgaTreeSplit.findIndexesFromRange(range); + return { + type: ChangeType.Selection, + actor: updatedAt.getActorID(), + from, + to, + }; + } + } +} diff --git a/src/document/json/text.ts b/src/document/json/text.ts index 6fff4225b..3e728f0c1 100644 --- a/src/document/json/text.ts +++ b/src/document/json/text.ts @@ -16,563 +16,13 @@ import { logger } from '../../util/logger'; import { ActorID } from '../time/actor_id'; -import { Comparator } from '../../util/comparator'; -import { SplayNode, SplayTree } from '../../util/splay_tree'; import { LLRBTree } from '../../util/llrb_tree'; -import { InitialTimeTicket, MaxTimeTicket, TimeTicket } from '../time/ticket'; +import { TimeTicket } from '../time/ticket'; import { JSONElement } from './element'; - -enum ChangeType { - Content = 'content', - Selection = 'selection', -} - -export interface Change { - type: ChangeType; - actor: ActorID; - from: number; - to: number; - content?: T; -} - -interface TextNodeValue { - length: number; - substring(indexStart: number, indexEnd?: number): TextNodeValue; -} - -export class TextNodeID { - private createdAt: TimeTicket; - private offset: number; - - constructor(createdAt: TimeTicket, offset: number) { - this.createdAt = createdAt; - this.offset = offset; - } - - public static of(createdAt: TimeTicket, offset: number): TextNodeID { - return new TextNodeID(createdAt, offset); - } - - public getCreatedAt(): TimeTicket { - return this.createdAt; - } - - public getOffset(): number { - return this.offset; - } - - public equals(other: TextNodeID): boolean { - return this.createdAt.compare(other.createdAt) === 0 - && this.offset === other.offset; - } - - public hasSameCreatedAt(other: TextNodeID): boolean { - return this.createdAt.compare(other.createdAt) === 0; - } - - public split(offset: number): TextNodeID { - return new TextNodeID(this.createdAt, this.offset + offset); - } - - public getAnnotatedString(): string { - return `${this.createdAt.getAnnotatedString()}:${this.offset}`; - } -} - -const InitialTextNodeID = TextNodeID.of(InitialTimeTicket, 0); - -export class TextNodePos { - private id: TextNodeID; - private relativeOffset: number; - - constructor(id: TextNodeID, relativeOffset: number) { - this.id = id; - this.relativeOffset = relativeOffset; - } - - public static of(id: TextNodeID, relativeOffset: number): TextNodePos { - return new TextNodePos(id, relativeOffset); - } - - public getID(): TextNodeID { - return this.id; - } - - public getRelativeOffset(): number { - return this.relativeOffset; - } - - public getAbsoluteID(): TextNodeID { - return TextNodeID.of( - this.id.getCreatedAt(), - this.id.getOffset() + this.relativeOffset, - ); - } - - public getAnnotatedString(): string { - return `${this.id.getAnnotatedString()}:${this.relativeOffset}`; - } -} - -export type TextNodeRange = [TextNodePos, TextNodePos]; - -export class TextNode extends SplayNode { - private id: TextNodeID; - private removedAt: TimeTicket; - - private prev: TextNode; - private next: TextNode; - private insPrev: TextNode; - private insNext: TextNode; - - constructor(id: TextNodeID, value?: T, removedAt?: TimeTicket) { - super(value); - this.id = id; - this.removedAt = removedAt; - } - - public static create(id: TextNodeID, value?: T): TextNode { - return new TextNode(id, value); - } - - public static createComparator(): Comparator { - return (p1: TextNodeID, p2: TextNodeID): number => { - const compare = p1.getCreatedAt().compare(p2.getCreatedAt()); - if (compare !== 0) { - return compare; - } - - if (p1.getOffset() > p2.getOffset()) { - return 1; - } else if (p1.getOffset() < p2.getOffset()) { - return -1; - } - return 0; - }; - } - - public getID(): TextNodeID { - return this.id; - } - - public getCreatedAt(): TimeTicket { - return this.id.getCreatedAt(); - } - - public getLength(): number { - if (this.removedAt) { - return 0; - } - return this.getContentLength(); - } - - public getContentLength(): number { - return this.value && this.value.length || 0; - } - - public getNext(): TextNode { - return this.next; - } - - public getInsPrev(): TextNode { - return this.insPrev; - } - - public getInsNext(): TextNode { - return this.insNext; - } - - public getInsPrevID(): TextNodeID { - return this.insPrev.getID(); - } - - public setPrev(node: TextNode): void { - this.prev = node; - node.next = this; - } - - public setInsPrev(node: TextNode): void { - this.insPrev = node; - node.insNext = this; - } - - public hasNext(): boolean { - return !!this.next; - } - - public hasInsPrev(): boolean { - return !!this.insPrev; - } - - public isRemoved(): boolean { - return !!this.removedAt; - } - - public getRemovedAt(): TimeTicket { - return this.removedAt; - } - - public split(offset: number): TextNode { - return new TextNode( - this.id.split(offset), - this.splitContent(offset) - ); - } - - public canDelete(editedAt: TimeTicket, latestCreatedAt: TimeTicket): boolean { - return (!this.getCreatedAt().after(latestCreatedAt) && - (!this.removedAt || editedAt.after(this.removedAt))); - } - - public remove(editedAt: TimeTicket): void { - this.removedAt = editedAt; - } - - public createRange(): TextNodeRange { - return [ - TextNodePos.of(this.id, 0), - TextNodePos.of(this.id, this.getLength()) - ]; - } - - public deepcopy(): TextNode { - return new TextNode( - this.id, - this.value, - this.removedAt - ); - } - - public getAnnotatedString(): string { - return `${this.id.getAnnotatedString()} ${this.value ? this.value : ''}`; - } - - private splitContent(offset: number): T { - const value = this.value; - this.value = value.substring(0, offset) as T; - return value.substring(offset, value.length) as T; - } -} - -export class RGATreeSplit { - private head: TextNode; - private treeByIndex: SplayTree; - private treeByID: LLRBTree>; - - constructor() { - this.head = TextNode.create(InitialTextNodeID); - this.treeByIndex = new SplayTree(); - this.treeByID = new LLRBTree(TextNode.createComparator()); - - this.treeByIndex.insert(this.head); - this.treeByID.put(this.head.getID(), this.head); - } - - public static create(): RGATreeSplit { - return new RGATreeSplit(); - } - - public edit( - range: TextNodeRange, - content: T, - latestCreatedAtMapByActor: Map, - editedAt: TimeTicket - ): [TextNodePos, Map, Array>] { - // 01. split nodes with from and to - const [toLeft, toRight] = this.findTextNodeWithSplit(range[1], editedAt); - const [fromLeft, fromRight] = this.findTextNodeWithSplit(range[0], editedAt); - - // 02. delete between from and to - const nodesToDelete = this.findBetween(fromRight, toRight); - const [changes, latestCreatedAtMap] = this.deleteNodes( - nodesToDelete, latestCreatedAtMapByActor, editedAt - ); - - const caretID = toRight ? toRight.getID() : toLeft.getID(); - let caretPos = TextNodePos.of(caretID, 0); - - // 03. insert a new node - if (content) { - const idx = this.findIdxFromTextNodePos(fromLeft.createRange()[1], true); - - const inserted = this.insertAfter( - fromLeft, - TextNode.create(TextNodeID.of(editedAt, 0), content) - ); - - changes.push({ - type: ChangeType.Content, - actor: editedAt.getActorID(), - from: idx, - to: idx, - content: content - }); - - caretPos = TextNodePos.of(inserted.getID(), inserted.getContentLength()); - } - - return [caretPos, latestCreatedAtMap, changes]; - } - - public findTextNodePos(idx: number): TextNodePos { - const [node, offset] = this.treeByIndex.find(idx); - const textNode = node as TextNode; - return TextNodePos.of(textNode.getID(), offset); - } - - public findIndexesFromRange(range: TextNodeRange): [number, number] { - const [fromPos, toPos] = range; - return [ - this.findIdxFromTextNodePos(fromPos, false), - this.findIdxFromTextNodePos(toPos, true) - ]; - } - - public findIdxFromTextNodePos(pos: TextNodePos, preferToLeft: boolean): number { - const absoluteID = pos.getAbsoluteID(); - const textNode = preferToLeft ? - this.findFloorTextNodePreferToLeft(absoluteID) : this.findFloorTextNode(absoluteID); - const index = this.treeByIndex.indexOf(textNode); - if (!textNode) { - logger.fatal(`the node of the given id should be found: ${absoluteID.getAnnotatedString()}`); - } - const offset = textNode.isRemoved() ? 0 : absoluteID.getOffset() - textNode.getID().getOffset(); - return index + offset; - } - - public findTextNode(id: TextNodeID): TextNode { - return this.findFloorTextNode(id); - } - - public toJSON(): string { - const json = []; - - for (const node of this) { - if (!node.isRemoved()) { - json.push(node.getValue()); - } - } - - return json.join(''); - } - - public *[Symbol.iterator](): IterableIterator> { - let node = this.head; - while(node) { - yield node; - node = node.getNext(); - } - } - - public getHead(): TextNode { - return this.head; - } - - public deepcopy(): RGATreeSplit { - const clone = new RGATreeSplit(); - - let node = this.head.getNext(); - - let prev = clone.head; - let current - while (node) { - current = clone.insertAfter(prev, node.deepcopy()); - if (node.hasInsPrev()) { - const insPrevNode = clone.findTextNode(node.getInsPrevID()); - current.setInsPrev(insPrevNode); - } - - prev = current; - node = node.getNext(); - } - - return clone; - } - - public getAnnotatedString(): string { - const result = []; - - let node = this.head; - while(node) { - if (node.isRemoved()) { - result.push(`{${node.getAnnotatedString()}}`); - } else { - result.push(`[${node.getAnnotatedString()}]`); - } - - node = node.getNext(); - } - - return result.join(''); - } - - public insertAfter(prevNode: TextNode, newNode: TextNode): TextNode { - const next = prevNode.getNext(); - newNode.setPrev(prevNode); - if (next) { - next.setPrev(newNode); - } - - this.treeByID.put(newNode.getID(), newNode); - this.treeByIndex.insertAfter(prevNode, newNode); - - return newNode; - } - - private findTextNodeWithSplit(pos: TextNodePos, editedAt: TimeTicket): [TextNode, TextNode] { - const absoluteID = pos.getAbsoluteID(); - let node = this.findFloorTextNodePreferToLeft(absoluteID); - const relativeOffset = absoluteID.getOffset() - node.getID().getOffset(); - - this.splitTextNode(node, relativeOffset); - - while(node.hasNext() && node.getNext().getCreatedAt().after(editedAt)) { - node = node.getNext(); - } - - return [node, node.getNext()]; - } - - private findFloorTextNodePreferToLeft(id: TextNodeID): TextNode { - let node = this.findFloorTextNode(id); - if (!node) { - logger.fatal(`the node of the given id should be found: ${id.getAnnotatedString()}`); - } - - if (id.getOffset() > 0 && node.getID().getOffset() == id.getOffset()) { - if (!node.hasInsPrev()) { - logger.fatal('insPrev should be presence'); - } - node = node.getInsPrev() - } - - return node; - } - - private findFloorTextNode(id: TextNodeID): TextNode { - const entry = this.treeByID.floorEntry(id); - if (!entry) { - return null; - } - - if (!entry.key.equals(id) && !entry.key.hasSameCreatedAt(id)) { - return null; - } - - return entry.value; - } - - private findBetween(fromNode: TextNode, toNode: TextNode): Array> { - const nodes = []; - - let current = fromNode; - while (current && current !== toNode) { - nodes.push(current); - current = current.getNext(); - } - - return nodes; - } - - private splitTextNode(node: TextNode, offset: number): TextNode { - if (offset > node.getContentLength()) { - logger.fatal('offset should be less than or equal to length'); - } - - if (offset === 0) { - return node; - } else if (offset === node.getContentLength()) { - return node.getNext(); - } - - const splitNode = node.split(offset); - this.treeByIndex.updateSubtree(splitNode); - this.insertAfter(node, splitNode); - - const insNext = node.getInsNext(); - if (insNext) { - insNext.setInsPrev(splitNode); - } - splitNode.setInsPrev(node); - - return splitNode; - } - - private deleteNodes( - candidates: Array>, - latestCreatedAtMapByActor: Map, - editedAt: TimeTicket - ): [Array>, Map] { - const isRemote = !!latestCreatedAtMapByActor; - const changes: Array> = []; - const createdAtMapByActor = new Map(); - const nodesToDelete = []; - - // NOTE: We need to collect indexes for change first then delete the nodes. - for (const node of candidates) { - const actorID = node.getCreatedAt().getActorID(); - - const latestCreatedAt = isRemote ? ( - latestCreatedAtMapByActor.has(actorID) ? latestCreatedAtMapByActor.get(actorID) : InitialTimeTicket - ) : MaxTimeTicket; - - // Delete nodes created before the latest time remaining in the replica that performed the deletion. - if (node.canDelete(editedAt, latestCreatedAt)) { - nodesToDelete.push(node); - - const [fromIdx, toIdx] = this.findIndexesFromRange(node.createRange()); - const change = { - type: ChangeType.Content, - actor: editedAt.getActorID(), - from: fromIdx, - to: toIdx - }; - - // Reduce adjacent deletions: i.g) [(1, 2), (2, 3)] => [(1, 3)] - if (changes.length && changes[0].to === change.from) { - changes[0].to = change.to; - } else { - changes.unshift(change); - } - - if (!createdAtMapByActor.has(actorID) || - node.getID().getCreatedAt().after(createdAtMapByActor.get(actorID))) { - createdAtMapByActor.set(actorID, node.getID().getCreatedAt()); - } - } - } - - for (const node of nodesToDelete) { - node.remove(editedAt); - this.treeByIndex.splayNode(node); - } - - return [changes, createdAtMapByActor]; - } -} - -class Selection { - private from: TextNodePos; - private to: TextNodePos; - private updatedAt: TimeTicket; - - constructor(from: TextNodePos, to: TextNodePos, updatedAt: TimeTicket) { - this.from = from; - this.to = to; - this.updatedAt = updatedAt; - } - - public static of(range: TextNodeRange, updatedAt: TimeTicket): Selection { - return new Selection(range[0], range[1], updatedAt); - } - - public getUpdatedAt(): TimeTicket { - return this.updatedAt; - } -} +import { Change, ChangeType, RGATreeSplit, RGATreeSplitNodeRange, RGATreeSplitNodePos, Selection } from './rga_tree_split'; export class PlainText extends JSONElement { - private onChangesHandler: (changes: Array>) => void; + private onChangesHandler: (changes: Array) => void; private rgaTreeSplit: RGATreeSplit; private selectionMap: Map; private remoteChangeLock: boolean; @@ -596,15 +46,16 @@ export class PlainText extends JSONElement { } public editInternal( - range: TextNodeRange, + range: RGATreeSplitNodeRange, content: string, latestCreatedAtMapByActor: Map, editedAt: TimeTicket - ): [TextNodePos, Map] { + ): Map { const [caretPos, latestCreatedAtMap, changes] = this.rgaTreeSplit.edit( range, content, - latestCreatedAtMapByActor, editedAt, + latestCreatedAtMapByActor, + editedAt, ); const selectionChange = this.updateSelectionInternal([caretPos, caretPos], editedAt); @@ -618,10 +69,10 @@ export class PlainText extends JSONElement { this.remoteChangeLock = false; } - return [caretPos, latestCreatedAtMap]; + return latestCreatedAtMap; } - public updateSelection(range: TextNodeRange, updatedAt: TimeTicket): void { + public updateSelection(range: RGATreeSplitNodeRange, updatedAt: TimeTicket): void { if (this.remoteChangeLock) { return; } @@ -638,17 +89,17 @@ export class PlainText extends JSONElement { return this.remoteChangeLock; } - public onChanges(handler: (changes: Array>) => void): void { + public onChanges(handler: (changes: Array) => void): void { this.onChangesHandler = handler; } - public createRange(fromIdx: number, toIdx: number): TextNodeRange { - const fromPos = this.rgaTreeSplit.findTextNodePos(fromIdx); + public createRange(fromIdx: number, toIdx: number): RGATreeSplitNodeRange { + const fromPos = this.rgaTreeSplit.findNodePos(fromIdx); if (fromIdx === toIdx) { return [fromPos, fromPos]; } - return [fromPos, this.rgaTreeSplit.findTextNodePos(toIdx)]; + return [fromPos, this.rgaTreeSplit.findNodePos(toIdx)]; } public toJSON(): string { @@ -680,7 +131,7 @@ export class PlainText extends JSONElement { return text; } - private updateSelectionInternal(range: TextNodeRange, updatedAt: TimeTicket): Change { + private updateSelectionInternal(range: RGATreeSplitNodeRange, updatedAt: TimeTicket): Change { if (!this.selectionMap.has(updatedAt.getActorID())) { this.selectionMap.set(updatedAt.getActorID(), Selection.of(range, updatedAt)); return null; diff --git a/src/document/operation/edit_operation.ts b/src/document/operation/edit_operation.ts index c57a3b8ca..95057fa0e 100644 --- a/src/document/operation/edit_operation.ts +++ b/src/document/operation/edit_operation.ts @@ -17,20 +17,20 @@ import { logger } from '../../util/logger'; import { TimeTicket } from '../time/ticket'; import { JSONRoot } from '../json/root'; +import { RGATreeSplitNodePos } from '../json/rga_tree_split'; import { PlainText } from '../json/text'; -import { TextNodePos } from '../json/text'; import { Operation } from './operation'; export class EditOperation extends Operation { - private fromPos: TextNodePos; - private toPos: TextNodePos; + private fromPos: RGATreeSplitNodePos; + private toPos: RGATreeSplitNodePos; private maxCreatedAtMapByActor; private content: string; constructor( parentCreatedAt: TimeTicket, - fromPos: TextNodePos, - toPos: TextNodePos, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, maxCreatedAtMapByActor: Map, content: string, executedAt: TimeTicket @@ -44,8 +44,8 @@ export class EditOperation extends Operation { public static create( parentCreatedAt: TimeTicket, - fromPos: TextNodePos, - toPos: TextNodePos, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, maxCreatedAtMapByActor: Map, content: string, executedAt: TimeTicket @@ -78,11 +78,11 @@ export class EditOperation extends Operation { return `${parent}.EDIT(${fromPos},${toPos},${content})` } - public getFromPos(): TextNodePos { + public getFromPos(): RGATreeSplitNodePos { return this.fromPos; } - public getToPos(): TextNodePos { + public getToPos(): RGATreeSplitNodePos { return this.toPos; } diff --git a/src/document/operation/rich_edit_operation.ts b/src/document/operation/rich_edit_operation.ts new file mode 100644 index 000000000..5f19cea7d --- /dev/null +++ b/src/document/operation/rich_edit_operation.ts @@ -0,0 +1,111 @@ +/* + * Copyright 2020 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { logger } from '../../util/logger'; +import { TimeTicket } from '../time/ticket'; +import { JSONRoot } from '../json/root'; +import { RGATreeSplitNodePos } from '../json/rga_tree_split'; +import { RichText } from '../json/rich_text'; +import { Operation } from './operation'; + +export class RichEditOperation extends Operation { + private fromPos: RGATreeSplitNodePos; + private toPos: RGATreeSplitNodePos; + private maxCreatedAtMapByActor: Map; + private content: string; + private attributes: Map; + + constructor( + parentCreatedAt: TimeTicket, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, + maxCreatedAtMapByActor: Map, + content: string, + attributes: Map, + executedAt: TimeTicket + ) { + super(parentCreatedAt, executedAt); + this.fromPos = fromPos; + this.toPos = toPos; + this.maxCreatedAtMapByActor = maxCreatedAtMapByActor; + this.content = content; + this.attributes = attributes; + } + + public static create( + parentCreatedAt: TimeTicket, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, + maxCreatedAtMapByActor: Map, + content: string, + attributes: Map, + executedAt: TimeTicket + ): RichEditOperation { + return new RichEditOperation( + parentCreatedAt, + fromPos, + toPos, + maxCreatedAtMapByActor, + content, + attributes, + executedAt + ); + } + + public execute(root: JSONRoot): void { + const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); + if (parentObject instanceof RichText) { + const text = parentObject as RichText; + text.editInternal( + [this.fromPos, this.toPos], + this.content, + Object.fromEntries(this.attributes), + this.maxCreatedAtMapByActor, + this.getExecutedAt() + ); + } else { + logger.fatal(`fail to execute, only RichText can execute edit`); + } + } + + public getAnnotatedString(): string { + const parent = this.getParentCreatedAt().getAnnotatedString(); + const fromPos = this.fromPos.getAnnotatedString(); + const toPos = this.toPos.getAnnotatedString(); + const content = this.content; + return `${parent}.EDIT(${fromPos},${toPos},${content})` + } + + public getFromPos(): RGATreeSplitNodePos { + return this.fromPos; + } + + public getToPos(): RGATreeSplitNodePos { + return this.toPos; + } + + public getContent(): string { + return this.content; + } + + public getAttributes(): Map { + return this.attributes || new Map(); + } + + public getMaxCreatedAtMapByActor(): Map { + return this.maxCreatedAtMapByActor; + } +} diff --git a/src/document/operation/select_operation.ts b/src/document/operation/select_operation.ts index 5e2af0f0d..94f30c46e 100644 --- a/src/document/operation/select_operation.ts +++ b/src/document/operation/select_operation.ts @@ -17,18 +17,19 @@ import { logger } from '../../util/logger'; import { TimeTicket } from '../time/ticket'; import { JSONRoot } from '../json/root'; +import { RGATreeSplitNodePos } from '../json/rga_tree_split'; import { PlainText } from '../json/text'; -import { TextNodePos } from '../json/text'; +import { RichText } from '../json/rich_text'; import { Operation } from './operation'; export class SelectOperation extends Operation { - private fromPos: TextNodePos; - private toPos: TextNodePos; + private fromPos: RGATreeSplitNodePos; + private toPos: RGATreeSplitNodePos; constructor( parentCreatedAt: TimeTicket, - fromPos: TextNodePos, - toPos: TextNodePos, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, executedAt: TimeTicket ) { super(parentCreatedAt, executedAt); @@ -38,8 +39,8 @@ export class SelectOperation extends Operation { public static create( parentCreatedAt: TimeTicket, - fromPos: TextNodePos, - toPos: TextNodePos, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, executedAt: TimeTicket ): SelectOperation { return new SelectOperation( @@ -55,8 +56,11 @@ export class SelectOperation extends Operation { if (parentObject instanceof PlainText) { const text = parentObject as PlainText; text.updateSelection([this.fromPos, this.toPos], this.getExecutedAt()); + } else if (parentObject instanceof RichText) { + const text = parentObject as RichText; + text.updateSelection([this.fromPos, this.toPos], this.getExecutedAt()); } else { - logger.fatal(`fail to execute, only PlainText can execute select`); + logger.fatal(`fail to execute, only PlainText, RichText can execute select`); } } @@ -67,11 +71,11 @@ export class SelectOperation extends Operation { return `${parent}.SELT(${fromPos},${toPos})` } - public getFromPos(): TextNodePos { + public getFromPos(): RGATreeSplitNodePos { return this.fromPos; } - public getToPos(): TextNodePos { + public getToPos(): RGATreeSplitNodePos { return this.toPos; } } diff --git a/src/document/operation/style_operation.ts b/src/document/operation/style_operation.ts new file mode 100644 index 000000000..c93f3d4cc --- /dev/null +++ b/src/document/operation/style_operation.ts @@ -0,0 +1,91 @@ +/* + * Copyright 2020 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { logger } from '../../util/logger'; +import { TimeTicket } from '../time/ticket'; +import { JSONRoot } from '../json/root'; +import { RGATreeSplitNodePos } from '../json/rga_tree_split'; +import { RichText } from '../json/rich_text'; +import { Operation } from './operation'; + +export class StyleOperation extends Operation { + private fromPos: RGATreeSplitNodePos; + private toPos: RGATreeSplitNodePos; + private attributes: Map; + + constructor( + parentCreatedAt: TimeTicket, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, + attributes: Map, + executedAt: TimeTicket + ) { + super(parentCreatedAt, executedAt); + this.fromPos = fromPos; + this.toPos = toPos; + this.attributes = attributes; + } + + public static create( + parentCreatedAt: TimeTicket, + fromPos: RGATreeSplitNodePos, + toPos: RGATreeSplitNodePos, + attributes: Map, + executedAt: TimeTicket + ): StyleOperation { + return new StyleOperation( + parentCreatedAt, + fromPos, + toPos, + attributes, + executedAt + ); + } + + public execute(root: JSONRoot): void { + const parentObject = root.findByCreatedAt(this.getParentCreatedAt()); + if (parentObject instanceof RichText) { + const text = parentObject as RichText; + text.setStyleInternal( + [this.fromPos, this.toPos], + this.attributes ? Object.fromEntries(this.attributes) : {}, + this.getExecutedAt() + ); + } else { + logger.fatal(`fail to execute, only PlainText can execute edit`); + } + } + + public getAnnotatedString(): string { + const parent = this.getParentCreatedAt().getAnnotatedString(); + const fromPos = this.fromPos.getAnnotatedString(); + const toPos = this.toPos.getAnnotatedString(); + const attributes = this.attributes; + return `${parent}.STYL(${fromPos},${toPos},${JSON.stringify(attributes)})` + } + + public getFromPos(): RGATreeSplitNodePos { + return this.fromPos; + } + + public getToPos(): RGATreeSplitNodePos { + return this.toPos; + } + + public getAttributes(): Map { + return this.attributes; + } +} diff --git a/src/document/proxy/object_proxy.ts b/src/document/proxy/object_proxy.ts index c2fea9e63..2ff38b461 100644 --- a/src/document/proxy/object_proxy.ts +++ b/src/document/proxy/object_proxy.ts @@ -22,9 +22,12 @@ import { ChangeContext } from '../change/context'; import { JSONObject } from '../json/object'; import { JSONArray } from '../json/array'; import { JSONPrimitive } from '../json/primitive'; -import { PlainText, RGATreeSplit } from '../json/text'; +import { RGATreeSplit } from '../json/rga_tree_split'; +import { PlainText } from '../json/text'; +import { RichText } from '../json/rich_text'; import { ArrayProxy } from './array_proxy'; import { TextProxy } from './text_proxy'; +import { RichTextProxy } from './rich_text_proxy'; import { toProxy } from './proxy'; export class ObjectProxy { @@ -63,6 +66,13 @@ export class ObjectProxy { } return ObjectProxy.createText(context, target, key); }; + } else if (keyOrMethod === 'createRichText') { + return (key: string): RichText => { + if (logger.isEnabled(LogLevel.Trivial)) { + logger.trivial(`obj[${key}]=Text`); + } + return ObjectProxy.createRichText(context, target, key); + }; } return toProxy(context, target.get(keyOrMethod)); @@ -128,6 +138,15 @@ export class ObjectProxy { return TextProxy.create(context, text); } + public static createRichText(context: ChangeContext, target: JSONObject, key: string): RichText { + const ticket = context.issueTimeTicket(); + const text = RichText.create(RGATreeSplit.create(), ticket); + target.set(key, text); + context.registerElement(text); + context.push(SetOperation.create(key, text.deepcopy(), target.getCreatedAt(), ticket)); + return RichTextProxy.create(context, text); + } + public static deleteInternal(context: ChangeContext, target: JSONObject, key: string): void { const ticket = context.issueTimeTicket(); const deleted = target.deleteByKey(key, ticket); diff --git a/src/document/proxy/proxy.ts b/src/document/proxy/proxy.ts index f5c2769ab..ad45362f5 100644 --- a/src/document/proxy/proxy.ts +++ b/src/document/proxy/proxy.ts @@ -19,10 +19,12 @@ import { JSONElement } from '../json/element'; import { JSONObject } from '../json/object'; import { JSONArray } from '../json/array'; import { JSONPrimitive } from '../json/primitive'; +import { RichText } from '../json/rich_text'; import { PlainText } from '../json/text'; import { ObjectProxy } from './object_proxy'; import { ArrayProxy } from './array_proxy'; import { TextProxy } from './text_proxy'; +import { RichTextProxy } from './rich_text_proxy'; export function createProxy(context: ChangeContext, target: JSONObject): JSONObject { return ObjectProxy.create(context, target); @@ -41,6 +43,9 @@ export function toProxy(context: ChangeContext, elem: JSONElement): any { } else if (elem instanceof PlainText) { const text = elem as PlainText; return TextProxy.create(context, text); + } else if (elem instanceof RichText) { + const text = elem as RichText; + return RichTextProxy.create(context, text); } else if (elem === null) { return null; } else { diff --git a/src/document/proxy/rich_text_proxy.ts b/src/document/proxy/rich_text_proxy.ts new file mode 100644 index 000000000..f149c13dd --- /dev/null +++ b/src/document/proxy/rich_text_proxy.ts @@ -0,0 +1,151 @@ +/* + * Copyright 2020 The Yorkie Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { logger, LogLevel } from '../../util/logger'; +import { ChangeContext } from '../change/context'; +import { RGATreeSplitNodeRange, Change } from '../json/rga_tree_split'; +import { RichText, RichTextVal, RichTextValue } from '../json/rich_text'; +import { RichEditOperation } from '../operation/rich_edit_operation'; +import { StyleOperation } from '../operation/style_operation'; +import { SelectOperation } from '../operation/select_operation'; + +export class RichTextProxy { + private context: ChangeContext; + private handlers: any; + + constructor(context: ChangeContext) { + this.context = context; + this.handlers = { + get: (target: RichText, method: string): any => { + if (logger.isEnabled(LogLevel.Trivial)) { + logger.trivial(`obj[${method}]`); + } + + if (method === 'edit') { + return (fromIdx: number, toIdx: number, content: string, attributes: { [key: string]: string; }): boolean => { + this.edit(target, fromIdx, toIdx, content, attributes); + return true; + }; + } if (method === 'setStyle') { + return (fromIdx: number, toIdx: number, attributes: { [key: string]: string; }): boolean => { + this.setStyle(target, fromIdx, toIdx, attributes); + return true; + }; + } else if (method === 'updateSelection') { + return (fromIdx: number, toIdx: number): boolean => { + this.updateSelection(target, fromIdx, toIdx); + return true; + }; + } else if (method === 'getAnnotatedString') { + return (): string => { + return target.getAnnotatedString(); + }; + } else if (method === 'getValue') { + return (): Array => { + return target.getValue(); + }; + } else if (method === 'createRange') { + return (fromIdx: number, toIdx: number): RGATreeSplitNodeRange => { + return target.createRange(fromIdx, toIdx); + }; + } else if (method === 'onChanges') { + return (handler: (changes: Array) => void): void => { + target.onChanges(handler); + } + } + + logger.fatal(`unsupported method: ${method}`); + } + }; + } + + public static create(context: ChangeContext, target: RichText): RichText { + const textProxy = new RichTextProxy(context); + return new Proxy(target, textProxy.getHandlers()); + } + + public edit(target: RichText, fromIdx: number, toIdx: number, content: string, attributes: { [key: string]: string; }): void { + if (fromIdx > toIdx) { + logger.fatal('from should be less than or equal to to'); + } + + const range = target.createRange(fromIdx, toIdx); + if (logger.isEnabled(LogLevel.Debug)) { + logger.debug( + `EDIT: f:${fromIdx}->${range[0].getAnnotatedString()}, t:${toIdx}->${range[1].getAnnotatedString()} c:${content}` + ); + } + + const ticket = this.context.issueTimeTicket(); + const maxCreatedAtMapByActor = target.editInternal(range, content, attributes, null, ticket); + + this.context.push(new RichEditOperation( + target.getCreatedAt(), + range[0], + range[1], + maxCreatedAtMapByActor, + content, + attributes ? new Map(Object.entries(attributes)) : new Map(), + ticket + )); + } + + public setStyle(target: RichText, fromIdx: number, toIdx: number, attributes: { [key: string]: string; }): void { + if (fromIdx > toIdx) { + logger.fatal('from should be less than or equal to to'); + } + + const range = target.createRange(fromIdx, toIdx); + if (logger.isEnabled(LogLevel.Debug)) { + logger.debug( + `STYL: f:${fromIdx}->${range[0].getAnnotatedString()}, t:${toIdx}->${range[1].getAnnotatedString()} a:${JSON.stringify(attributes)}` + ); + } + + const ticket = this.context.issueTimeTicket(); + target.setStyleInternal(range, attributes, ticket); + + this.context.push(new StyleOperation( + target.getCreatedAt(), + range[0], + range[1], + new Map(Object.entries(attributes)), + ticket + )); + } + + public updateSelection(target: RichText, fromIdx: number, toIdx: number): void { + const range = target.createRange(fromIdx, toIdx); + if (logger.isEnabled(LogLevel.Debug)) { + logger.debug( + `SELT: f:${fromIdx}->${range[0].getAnnotatedString()}, t:${toIdx}->${range[1].getAnnotatedString()}` + ); + } + const ticket = this.context.issueTimeTicket(); + target.updateSelection(range, ticket); + + this.context.push(new SelectOperation( + target.getCreatedAt(), + range[0], + range[1], + ticket + )); + } + + public getHandlers(): any { + return this.handlers; + } +} diff --git a/src/document/proxy/text_proxy.ts b/src/document/proxy/text_proxy.ts index 68651a7fd..c0720f7a6 100644 --- a/src/document/proxy/text_proxy.ts +++ b/src/document/proxy/text_proxy.ts @@ -16,7 +16,8 @@ import { logger, LogLevel } from '../../util/logger'; import { ChangeContext } from '../change/context'; -import { PlainText, TextNodeRange, Change } from '../json/text'; +import { RGATreeSplitNodeRange, Change } from '../json/rga_tree_split'; +import { PlainText } from '../json/text'; import { EditOperation } from '../operation/edit_operation'; import { SelectOperation } from '../operation/select_operation'; @@ -51,11 +52,11 @@ export class TextProxy { return target.getValue(); }; } else if (method === 'createRange') { - return (fromIdx: number, toIdx: number): TextNodeRange => { + return (fromIdx: number, toIdx: number): RGATreeSplitNodeRange => { return target.createRange(fromIdx, toIdx); }; } else if (method === 'onChanges') { - return (handler: (changes: Array>) => void): void => { + return (handler: (changes: Array) => void): void => { target.onChanges(handler); } } @@ -83,7 +84,7 @@ export class TextProxy { } const ticket = this.context.issueTimeTicket(); - const [, maxCreatedAtMapByActor] = target.editInternal(range, content, null, ticket); + const maxCreatedAtMapByActor = target.editInternal(range, content, null, ticket); this.context.push(new EditOperation( target.getCreatedAt(), diff --git a/src/document/time/ticket.ts b/src/document/time/ticket.ts index 95fb418e5..feb81c98b 100644 --- a/src/document/time/ticket.ts +++ b/src/document/time/ticket.ts @@ -72,6 +72,10 @@ export class TimeTicket { return this.compare(other) > 0; } + public equals(other: TimeTicket): boolean { + return this.compare(other) === 0; + } + public compare(other: TimeTicket): number { if (this.lamport.greaterThan(other.lamport)) { return 1;