Page MenuHomeWickedGov Phorge

ve.collab.js
No OneTemporary

Size
5 KB
Referenced Files
None
Subscribers
None

ve.collab.js

/*!
* VisualEditor collab extensions.
*
* @copyright See AUTHORS.txt
*/
/* global Peer */
ve.collab = {};
/**
* Recursively serialize objects into plain data.
*
* Non-plain objects must have a .serialize or .toJSON method.
*
* @param {Object|Array} value The value to serialize
* @return {Object|Array} The serialized version
*/
ve.collab.serialize = function ( value ) {
if ( Array.isArray( value ) ) {
return value.map( ( item ) => ve.collab.serialize( item ) );
} else if ( value === null || typeof value !== 'object' ) {
return value;
} else if ( value.constructor === Object ) {
const serialized = {};
for ( const property in value ) {
serialized[ property ] = ve.collab.serialize( value[ property ] );
}
return serialized;
} else if ( typeof value.serialize === 'function' ) {
return ve.collab.serialize( value.serialize() );
} else if ( typeof value.toJSON === 'function' ) {
return ve.collab.serialize( value.toJSON() );
}
throw new Error( 'Cannot serialize ' + value );
};
ve.collab.newPeer = function () {
// To use the public PeerJS server:
return new Peer();
// To use a local PeerJS server:
// return new Peer( undefined, { host: 'localhost', port: 9000, path: '/myapp' } );
// To use a ve.FakePeer (for debugging):
// return new ve.FakePeer();
};
ve.collab.initPeerServer = function ( userName ) {
const surface = ve.init.target.surface,
completeHistory = surface.model.documentModel.completeHistory;
ve.collab.peerServer = new ve.dm.CollabTransportServer( completeHistory.getLength() );
if ( completeHistory.getLength() > 0 ) {
completeHistory.transactions[ 0 ].authorId = 1;
}
ve.collab.peerServer.protocolServer.rebaseServer.updateDocState(
// The doc name is arbitrary since the in-browser server only serves one doc
've-collab-doc',
1,
ve.dm.Change.static.deserialize( completeHistory.serialize(), true ),
completeHistory,
{}
);
ve.collab.peerServer.peer = ve.collab.newPeer();
ve.collab.peerServer.peer.on( 'open', ( id ) => {
/* eslint-disable-next-line no-console */
console.log( 'Open. Now in another browser window, do:\nve.collab.initPeerClient( \'' + id + '\' );' );
ve.collab.initPeerClient( id, true, userName );
} );
ve.collab.peerServer.peer.on( 'connection', ( conn ) => {
ve.collab.peerServer.onConnection( conn );
} );
};
ve.collab.initPeerClient = function ( serverId, isMain, userName ) {
const surface = ve.init.target.surface,
completeHistory = surface.model.documentModel.completeHistory,
peerClient = ve.collab.newPeer();
if ( completeHistory.getLength() > 0 ) {
completeHistory.transactions[ 0 ].authorId = 1;
}
// HACK: Disable redo command until supported (T185706)
ve.ui.commandRegistry.unregister( 'redo' );
if ( !isMain ) {
ve.ui.commandRegistry.unregister( 'showSave' );
}
ve.init.target.constructor.static.toolbarGroups = ve.copy( ve.init.target.constructor.static.toolbarGroups );
ve.init.target.constructor.static.toolbarGroups.unshift( {
name: 'authorList',
include: [ 'authorList' ],
align: 'after'
} );
peerClient.on( 'open', ( /* id */ ) => {
const conn = peerClient.connect( serverId );
// On old js-BinaryPack (before https://github.com/peers/js-binarypack/pull/10 ),
// you need JSON serialization, else it crashes on Unicode code points over U+FFFF
// var conn = peerClient.connect( serverId, { serialization: 'json' } );
conn.on( 'open', () => {
surface.model.createSynchronizer( 'foo', { peerConnection: conn } );
surface.model.synchronizer.commitLength = completeHistory.getLength();
surface.model.synchronizer.sentLength = completeHistory.getLength();
surface.model.synchronizer.once( 'initDoc', ( error ) => {
if ( error ) {
OO.ui.alert(
// eslint-disable-next-line no-jquery/no-append-html
$( '<p>' ).append(
ve.htmlMsg( 'visualeditor-rebase-corrupted-document-error', $( '<pre>' ).text( error.stack ) )
),
{ title: ve.msg( 'visualeditor-rebase-corrupted-document-title' ), size: 'large' }
);
return;
}
const toolbar = ve.init.target.getToolbar();
toolbar.setup(
ve.init.target.constructor.static.toolbarGroups,
ve.init.target.surface
);
toolbar.onWindowResize();
if ( !isMain ) {
// eslint-disable-next-line no-jquery/no-global-selector
$( '.ve-ui-toolbar-saveButton' ).css( 'text-decoration', 'line-through' );
}
} );
ve.collab.connectModelSynchronizer();
surface.model.synchronizer.changeAuthor( { name: userName } );
} );
} );
};
ve.collab.connectModelSynchronizer = function () {
const ceSurface = ve.init.target.surface.view;
ceSurface.model.synchronizer.connect( ceSurface, {
authorSelect: 'onSynchronizerAuthorUpdate',
authorChange: 'onSynchronizerAuthorUpdate',
authorDisconnect: 'onSynchronizerAuthorDisconnect',
wrongDoc: 'onSynchronizerWrongDoc',
pause: 'onSynchronizerPause'
} );
};
ve.collab.join = function () {
const serverId = new URLSearchParams( location.search ).get( 'collabSession' );
if ( serverId ) {
// Valid session URL
ve.collab.start( serverId );
}
};
/**
* Top-level function to host or join a collab session
*
* @param {string} [serverId] Id of session to join; undefined means host a new session
*/
ve.collab.start = function ( serverId ) {
if ( serverId ) {
// Join an existing session
ve.init.target.surface.dialogs.openWindow( 'joinCollabDialog' ).closing.then( ( data ) => {
if ( !( data && data.action === 'accept' ) ) {
return;
}
ve.collab.initPeerClient( serverId, false, data.userName );
} );
return;
}
// Else host a new session
ve.init.target.surface.dialogs.openWindow( 'hostCollabDialog' );
};

File Metadata

Mime Type
text/plain
Expires
Wed, Aug 19, 00:30 (4 d, 21 h ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
9b/d6/e0dd836bdfe57116fbe8b8ea61c5
Default Alt Text
ve.collab.js (5 KB)

Event Timeline