* Added replace_contents() to model.Note to set the contents without updating the revision or anything else.
* Added new optional previous_revision params to default(), contents() and load_note() in controller.Notebooks. These use Html_differ() to generate and return diffs. * Updated Wiki.js: * provide previous_revision when a revision is opened in a new window/tab * call load_note() when two revisions when a revision is clicked in Changes_pulldown * update compare_versions() to display a diff instead of opening the two revisions separately * update load_editor(): * update all invocations of load_editor(), including in Editor.js, to accept a new previous_revision argument * modify load_editor() to use the previous_revision argument (when supplied) to load a diff
This commit is contained in:
parent
42ae3e0ba1
commit
97c373561d
5
NEWS
5
NEWS
|
@ -1,3 +1,8 @@
|
||||||
|
1.3.9: May 2, 2008
|
||||||
|
* When viewing a note's revision, changes since the previous revision are now
|
||||||
|
shown in red strikeout (deletions/modifications) and green text
|
||||||
|
(additions/modifications).
|
||||||
|
|
||||||
1.3.8: April 29, 2008
|
1.3.8: April 29, 2008
|
||||||
* Can now load children links for a note that's in the trash.
|
* Can now load children links for a note that's in the trash.
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ from Database import Valid_id, Valid_revision, end_transaction
|
||||||
from Users import grab_user_id, Access_error
|
from Users import grab_user_id, Access_error
|
||||||
from Expire import strongly_expire
|
from Expire import strongly_expire
|
||||||
from Html_nuker import Html_nuker
|
from Html_nuker import Html_nuker
|
||||||
|
from Html_differ import Html_differ
|
||||||
from model.Notebook import Notebook
|
from model.Notebook import Notebook
|
||||||
from model.Note import Note
|
from model.Note import Note
|
||||||
from model.Invite import Invite
|
from model.Invite import Invite
|
||||||
|
@ -59,13 +60,15 @@ class Notebooks( object ):
|
||||||
note_id = Valid_id(),
|
note_id = Valid_id(),
|
||||||
parent_id = Valid_id(),
|
parent_id = Valid_id(),
|
||||||
revision = Valid_revision(),
|
revision = Valid_revision(),
|
||||||
|
previous_revision = Valid_revision( none_okay = True ),
|
||||||
rename = Valid_bool(),
|
rename = Valid_bool(),
|
||||||
deleted_id = Valid_id(),
|
deleted_id = Valid_id(),
|
||||||
preview = Valid_string(),
|
preview = Valid_string(),
|
||||||
user_id = Valid_id( none_okay = True ),
|
user_id = Valid_id( none_okay = True ),
|
||||||
)
|
)
|
||||||
def default( self, notebook_id, note_id = None, parent_id = None, revision = None, rename = False,
|
def default( self, notebook_id, note_id = None, parent_id = None, revision = None,
|
||||||
deleted_id = None, preview = None, user_id = None ):
|
previous_revision = None, rename = False, deleted_id = None, preview = None,
|
||||||
|
user_id = None ):
|
||||||
"""
|
"""
|
||||||
Provide the information necessary to display the page for a particular notebook. If a
|
Provide the information necessary to display the page for a particular notebook. If a
|
||||||
particular note id is given without a revision, then the most recent version of that note is
|
particular note id is given without a revision, then the most recent version of that note is
|
||||||
|
@ -79,6 +82,8 @@ class Notebooks( object ):
|
||||||
@param parent_id: id of parent notebook to this notebook (optional)
|
@param parent_id: id of parent notebook to this notebook (optional)
|
||||||
@type revision: unicode or NoneType
|
@type revision: unicode or NoneType
|
||||||
@param revision: revision timestamp of the provided note (optional)
|
@param revision: revision timestamp of the provided note (optional)
|
||||||
|
@type previous_revision: unicode or NoneType
|
||||||
|
@param previous_revision: older revision timestamp to diff with the given revision (optional)
|
||||||
@type rename: bool or NoneType
|
@type rename: bool or NoneType
|
||||||
@param rename: whether this is a new notebook and should be renamed (optional, defaults to False)
|
@param rename: whether this is a new notebook and should be renamed (optional, defaults to False)
|
||||||
@type deleted_id: unicode or NoneType
|
@type deleted_id: unicode or NoneType
|
||||||
|
@ -115,7 +120,7 @@ class Notebooks( object ):
|
||||||
else:
|
else:
|
||||||
raise Access_error()
|
raise Access_error()
|
||||||
|
|
||||||
result.update( self.contents( notebook_id, note_id, revision, read_write, owner, user_id ) )
|
result.update( self.contents( notebook_id, note_id, revision, previous_revision, read_write, owner, user_id ) )
|
||||||
result[ "parent_id" ] = parent_id
|
result[ "parent_id" ] = parent_id
|
||||||
if revision:
|
if revision:
|
||||||
result[ "note_read_write" ] = False
|
result[ "note_read_write" ] = False
|
||||||
|
@ -138,7 +143,8 @@ class Notebooks( object ):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def contents( self, notebook_id, note_id = None, revision = None, read_write = True, owner = True, user_id = None ):
|
def contents( self, notebook_id, note_id = None, revision = None, previous_revision = None,
|
||||||
|
read_write = True, owner = True, user_id = None ):
|
||||||
"""
|
"""
|
||||||
Return the startup notes for the given notebook. Optionally include a single requested note as
|
Return the startup notes for the given notebook. Optionally include a single requested note as
|
||||||
well.
|
well.
|
||||||
|
@ -149,6 +155,8 @@ class Notebooks( object ):
|
||||||
@param note_id: id of single note in this notebook to return (optional)
|
@param note_id: id of single note in this notebook to return (optional)
|
||||||
@type revision: unicode or NoneType
|
@type revision: unicode or NoneType
|
||||||
@param revision: revision timestamp of the provided note (optional)
|
@param revision: revision timestamp of the provided note (optional)
|
||||||
|
@type previous_revision: unicode or NoneType
|
||||||
|
@param previous_revision: older revision timestamp to diff with the given revision (optional)
|
||||||
@type read_write: bool or NoneType
|
@type read_write: bool or NoneType
|
||||||
@param read_write: whether the notebook should be returned as read-write (optional, defaults to True)
|
@param read_write: whether the notebook should be returned as read-write (optional, defaults to True)
|
||||||
@type owner: bool or NoneType
|
@type owner: bool or NoneType
|
||||||
|
@ -190,6 +198,12 @@ class Notebooks( object ):
|
||||||
note = None
|
note = None
|
||||||
else:
|
else:
|
||||||
raise Access_error()
|
raise Access_error()
|
||||||
|
|
||||||
|
# if two revisions were provided, then make the returned note's contents into a diff
|
||||||
|
if note and revision and previous_revision:
|
||||||
|
previous_note = self.__database.load( Note, note_id, previous_revision )
|
||||||
|
if previous_note and previous_note.contents:
|
||||||
|
note.replace_contents( Html_differ().diff( previous_note.contents, note.contents ) )
|
||||||
else:
|
else:
|
||||||
note = None
|
note = None
|
||||||
|
|
||||||
|
@ -281,10 +295,11 @@ class Notebooks( object ):
|
||||||
notebook_id = Valid_id(),
|
notebook_id = Valid_id(),
|
||||||
note_id = Valid_id(),
|
note_id = Valid_id(),
|
||||||
revision = Valid_revision(),
|
revision = Valid_revision(),
|
||||||
|
previous_revision = Valid_revision( none_okay = True ),
|
||||||
summarize = Valid_bool(),
|
summarize = Valid_bool(),
|
||||||
user_id = Valid_id( none_okay = True ),
|
user_id = Valid_id( none_okay = True ),
|
||||||
)
|
)
|
||||||
def load_note( self, notebook_id, note_id, revision = None, summarize = False, user_id = None ):
|
def load_note( self, notebook_id, note_id, revision = None, previous_revision = None, summarize = False, user_id = None ):
|
||||||
"""
|
"""
|
||||||
Return the information on a particular note by its id.
|
Return the information on a particular note by its id.
|
||||||
|
|
||||||
|
@ -294,6 +309,8 @@ class Notebooks( object ):
|
||||||
@param note_id: id of note to return
|
@param note_id: id of note to return
|
||||||
@type revision: unicode or NoneType
|
@type revision: unicode or NoneType
|
||||||
@param revision: revision timestamp of the note (optional)
|
@param revision: revision timestamp of the note (optional)
|
||||||
|
@type previous_revision: unicode or NoneType
|
||||||
|
@param previous_revision: older revision timestamp to diff with the given revision (optional)
|
||||||
@type summarize: bool or NoneType
|
@type summarize: bool or NoneType
|
||||||
@param summarize: True to return a summary of the note's contents, False to return full text
|
@param summarize: True to return a summary of the note's contents, False to return full text
|
||||||
(optional, defaults to False)
|
(optional, defaults to False)
|
||||||
|
@ -330,6 +347,11 @@ class Notebooks( object ):
|
||||||
|
|
||||||
raise Access_error()
|
raise Access_error()
|
||||||
|
|
||||||
|
if note and revision and previous_revision:
|
||||||
|
previous_note = self.__database.load( Note, note_id, previous_revision )
|
||||||
|
if previous_note and previous_note.contents:
|
||||||
|
note.replace_contents( Html_differ().diff( previous_note.contents, note.contents ) )
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
note = summarize and self.summarize_note( note ) or note,
|
note = summarize and self.summarize_note( note ) or note,
|
||||||
)
|
)
|
||||||
|
|
|
@ -428,6 +428,56 @@ class Test_notebooks( Test_controller ):
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes == 0
|
assert user.storage_bytes == 0
|
||||||
|
|
||||||
|
def test_default_with_note_and_previous_revision( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
previous_revision = self.note.revision
|
||||||
|
self.note.contents = u"<h3>my title</h3>foo blah"
|
||||||
|
self.database.save( self.note )
|
||||||
|
|
||||||
|
result = self.http_get(
|
||||||
|
"/notebooks/%s?note_id=%s&revision=%s&previous_revision=%s" % (
|
||||||
|
self.notebook.object_id,
|
||||||
|
self.note.object_id,
|
||||||
|
quote( unicode( self.note.revision ) ),
|
||||||
|
quote( unicode( previous_revision ) ),
|
||||||
|
),
|
||||||
|
session_id = self.session_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.get( u"user" ).object_id == self.user.object_id
|
||||||
|
assert len( result.get( u"notebooks" ) ) == 3
|
||||||
|
assert result.get( u"notebooks" )[ 0 ].object_id == self.notebook.object_id
|
||||||
|
assert result.get( u"notebooks" )[ 0 ].read_write == True
|
||||||
|
assert result.get( u"notebooks" )[ 0 ].owner == True
|
||||||
|
assert result.get( u"login_url" ) is None
|
||||||
|
assert result.get( u"logout_url" )
|
||||||
|
assert result.get( u"rate_plan" )
|
||||||
|
assert result.get( u"notebook" ).object_id == self.notebook.object_id
|
||||||
|
assert result.get( u"notebook" ).read_write == True
|
||||||
|
assert result.get( u"notebook" ).owner == True
|
||||||
|
assert len( result.get( u"startup_notes" ) ) == 1
|
||||||
|
assert result[ "total_notes_count" ] == 2
|
||||||
|
|
||||||
|
assert result.get( "notes" )
|
||||||
|
assert len( result.get( "notes" ) ) == 1
|
||||||
|
assert result.get( u"notes" )[ 0 ].object_id == self.note.object_id
|
||||||
|
assert result.get( u"notes" )[ 0 ].revision == self.note.revision
|
||||||
|
assert result.get( u"notes" )[ 0 ].contents == u'<h3>my title</h3><ins class="diff">foo </ins>blah'
|
||||||
|
assert result.get( u"parent_id" ) == None
|
||||||
|
assert result.get( u"note_read_write" ) == False
|
||||||
|
assert len( result.get( "recent_notes" ) ) == 2
|
||||||
|
assert result.get( "recent_notes" )[ 0 ].object_id == self.note.object_id
|
||||||
|
assert result.get( "recent_notes" )[ 1 ].object_id == self.note2.object_id
|
||||||
|
|
||||||
|
invites = result[ "invites" ]
|
||||||
|
assert len( invites ) == 1
|
||||||
|
invite = invites[ 0 ]
|
||||||
|
assert invite.object_id == self.invite.object_id
|
||||||
|
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.storage_bytes == 0
|
||||||
|
|
||||||
def test_default_with_parent( self ):
|
def test_default_with_parent( self ):
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
|
@ -604,6 +654,46 @@ class Test_notebooks( Test_controller ):
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes == 0
|
assert user.storage_bytes == 0
|
||||||
|
|
||||||
|
def test_contents_with_note_and_previous_revision( self ):
|
||||||
|
previous_revision = self.note.revision
|
||||||
|
self.note.contents = u"<h3>my title</h3>foo blah"
|
||||||
|
self.database.save( self.note )
|
||||||
|
|
||||||
|
result = cherrypy.root.notebooks.contents(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
note_id = self.note.object_id,
|
||||||
|
revision = unicode( self.note.revision ),
|
||||||
|
previous_revision = unicode( previous_revision ),
|
||||||
|
user_id = self.user.object_id,
|
||||||
|
)
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
notebook = result[ "notebook" ]
|
||||||
|
startup_notes = result[ "startup_notes" ]
|
||||||
|
assert result[ "total_notes_count" ] == 2
|
||||||
|
|
||||||
|
invites = result[ "invites" ]
|
||||||
|
assert len( invites ) == 1
|
||||||
|
invite = invites[ 0 ]
|
||||||
|
assert invite.object_id == self.invite.object_id
|
||||||
|
|
||||||
|
assert notebook.object_id == self.notebook.object_id
|
||||||
|
assert notebook.read_write == True
|
||||||
|
assert notebook.owner == True
|
||||||
|
assert len( startup_notes ) == 1
|
||||||
|
assert startup_notes[ 0 ].object_id == self.note.object_id
|
||||||
|
|
||||||
|
notes = result[ "notes" ]
|
||||||
|
|
||||||
|
assert notes
|
||||||
|
assert len( notes ) == 1
|
||||||
|
note = notes[ 0 ]
|
||||||
|
assert note.object_id == self.note.object_id
|
||||||
|
assert note.revision == self.note.revision
|
||||||
|
assert note.contents == u'<h3>my title</h3><ins class="diff">foo </ins>blah'
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.storage_bytes == 0
|
||||||
|
|
||||||
def test_contents_with_different_invites( self ):
|
def test_contents_with_different_invites( self ):
|
||||||
# create an invite with a different email address from the previous
|
# create an invite with a different email address from the previous
|
||||||
invite = Invite.create(
|
invite = Invite.create(
|
||||||
|
@ -870,6 +960,42 @@ class Test_notebooks( Test_controller ):
|
||||||
user = self.database.load( User, self.user.object_id )
|
user = self.database.load( User, self.user.object_id )
|
||||||
assert user.storage_bytes == 0
|
assert user.storage_bytes == 0
|
||||||
|
|
||||||
|
def test_load_note_with_previous_revision( self ):
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
# update the note to generate a new revision
|
||||||
|
previous_revision = self.note.revision
|
||||||
|
previous_title = self.note.title
|
||||||
|
previous_contents = self.note.contents
|
||||||
|
new_note_contents = u"<h3>my title</h3>foo blah"
|
||||||
|
result = self.http_post( "/notebooks/save_note/", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
note_id = self.note.object_id,
|
||||||
|
contents = new_note_contents,
|
||||||
|
startup = False,
|
||||||
|
previous_revision = self.note.revision,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
new_revision = result[ "new_revision" ].revision
|
||||||
|
|
||||||
|
# load the note by the new revision, providing the previous revision as well
|
||||||
|
result = self.http_post( "/notebooks/load_note/", dict(
|
||||||
|
notebook_id = self.notebook.object_id,
|
||||||
|
note_id = self.note.object_id,
|
||||||
|
revision = unicode( new_revision ),
|
||||||
|
previous_revision = previous_revision,
|
||||||
|
), session_id = self.session_id )
|
||||||
|
|
||||||
|
note = result[ "note" ]
|
||||||
|
|
||||||
|
# assert that we get a composite diff of the two revisions
|
||||||
|
assert note.object_id == self.note.object_id
|
||||||
|
assert note.revision == new_revision
|
||||||
|
assert note.title == previous_title
|
||||||
|
assert note.contents == u'<h3>my title</h3><ins class="diff">foo </ins>blah'
|
||||||
|
user = self.database.load( User, self.user.object_id )
|
||||||
|
assert user.storage_bytes > 0
|
||||||
|
|
||||||
def test_load_note_without_login( self ):
|
def test_load_note_without_login( self ):
|
||||||
result = self.http_post( "/notebooks/load_note/", dict(
|
result = self.http_post( "/notebooks/load_note/", dict(
|
||||||
notebook_id = self.notebook.object_id,
|
notebook_id = self.notebook.object_id,
|
||||||
|
|
|
@ -96,6 +96,9 @@ class Note( Persistent ):
|
||||||
else:
|
else:
|
||||||
self.__title = None
|
self.__title = None
|
||||||
|
|
||||||
|
def replace_contents( self, contents ):
|
||||||
|
self.__contents = contents
|
||||||
|
|
||||||
def __set_summary( self, summary ):
|
def __set_summary( self, summary ):
|
||||||
self.__summary = summary
|
self.__summary = summary
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,25 @@ class Test_note( object ):
|
||||||
assert self.note.user_id == self.user_id
|
assert self.note.user_id == self.user_id
|
||||||
assert self.note.creation == self.creation
|
assert self.note.creation == self.creation
|
||||||
|
|
||||||
|
def test_replace_contents( self ):
|
||||||
|
new_contents = u"<h3>new</h3>new blah"
|
||||||
|
original_revision = self.note.revision
|
||||||
|
original_title = self.note.title
|
||||||
|
|
||||||
|
self.note.replace_contents( new_contents )
|
||||||
|
|
||||||
|
# nothing should change but the contents itself
|
||||||
|
assert self.note.revision == original_revision
|
||||||
|
assert self.note.contents == new_contents
|
||||||
|
assert self.note.summary == None
|
||||||
|
assert self.note.title == original_title
|
||||||
|
assert self.note.notebook_id == self.notebook_id
|
||||||
|
assert self.note.startup == self.startup
|
||||||
|
assert self.note.deleted_from_id == None
|
||||||
|
assert self.note.rank == self.rank
|
||||||
|
assert self.note.user_id == self.user_id
|
||||||
|
assert self.note.creation == self.creation
|
||||||
|
|
||||||
def test_set_summary( self ):
|
def test_set_summary( self ):
|
||||||
summary = u"summary goes here..."
|
summary = u"summary goes here..."
|
||||||
original_revision = self.note.revision
|
original_revision = self.note.revision
|
||||||
|
|
|
@ -392,7 +392,7 @@ Editor.prototype.mouse_clicked = function ( event ) {
|
||||||
var query = parse_query( link );
|
var query = parse_query( link );
|
||||||
var title = link_title( link, query );
|
var title = link_title( link, query );
|
||||||
var id = query.note_id;
|
var id = query.note_id;
|
||||||
signal( self, "load_editor", title, id, null, link, self.iframe );
|
signal( self, "load_editor", title, id, null, null, link, self.iframe );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,7 @@ Wiki.prototype.populate = function ( startup_notes, current_notes, note_read_wri
|
||||||
var share_notebook_link = getElement( "share_notebook_link" );
|
var share_notebook_link = getElement( "share_notebook_link" );
|
||||||
if ( share_notebook_link ) {
|
if ( share_notebook_link ) {
|
||||||
connect( share_notebook_link, "onclick", function ( event ) {
|
connect( share_notebook_link, "onclick", function ( event ) {
|
||||||
self.load_editor( "share this notebook", "null", null, null, getElement( "notes_top" ) );
|
self.load_editor( "share this notebook", "null", null, null, null, getElement( "notes_top" ) );
|
||||||
event.stop();
|
event.stop();
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ Wiki.prototype.create_blank_editor = function ( event ) {
|
||||||
signal( this, "note_added", editor );
|
signal( this, "note_added", editor );
|
||||||
}
|
}
|
||||||
|
|
||||||
Wiki.prototype.load_editor = function ( note_title, note_id, revision, link, position_after ) {
|
Wiki.prototype.load_editor = function ( note_title, note_id, revision, previous_revision, link, position_after ) {
|
||||||
if ( this.notebook.name == "trash" && !revision ) {
|
if ( this.notebook.name == "trash" && !revision ) {
|
||||||
this.display_message( "If you'd like to use this note, try undeleting it first.", undefined, position_after );
|
this.display_message( "If you'd like to use this note, try undeleting it first.", undefined, position_after );
|
||||||
return;
|
return;
|
||||||
|
@ -495,7 +495,8 @@ Wiki.prototype.load_editor = function ( note_title, note_id, revision, link, pos
|
||||||
"/notebooks/load_note", "GET", {
|
"/notebooks/load_note", "GET", {
|
||||||
"notebook_id": this.notebook_id,
|
"notebook_id": this.notebook_id,
|
||||||
"note_id": note_id,
|
"note_id": note_id,
|
||||||
"revision": revision
|
"revision": revision,
|
||||||
|
"previous_revision": previous_revision
|
||||||
},
|
},
|
||||||
function ( result ) { self.parse_loaded_editor( result, note_title, revision, link, position_after ); }
|
function ( result ) { self.parse_loaded_editor( result, note_title, revision, link, position_after ); }
|
||||||
);
|
);
|
||||||
|
@ -1200,7 +1201,7 @@ Wiki.prototype.undelete_editor_via_undo = function( event, editor, position_afte
|
||||||
|
|
||||||
this.startup_notes[ editor.id ] = true;
|
this.startup_notes[ editor.id ] = true;
|
||||||
this.increment_total_notes_count();
|
this.increment_total_notes_count();
|
||||||
this.load_editor( "Note not found.", editor.id, null, null, position_after );
|
this.load_editor( "Note not found.", editor.id, null, null, null, position_after );
|
||||||
}
|
}
|
||||||
|
|
||||||
event.stop();
|
event.stop();
|
||||||
|
@ -1221,7 +1222,7 @@ Wiki.prototype.undelete_editor_via_undelete = function( event, note_id, position
|
||||||
|
|
||||||
this.startup_notes[ note_id ] = true;
|
this.startup_notes[ note_id ] = true;
|
||||||
this.increment_total_notes_count();
|
this.increment_total_notes_count();
|
||||||
this.load_editor( "Note not found.", note_id, null, null, position_after );
|
this.load_editor( "Note not found.", note_id, null, null, null, position_after );
|
||||||
|
|
||||||
event.stop();
|
event.stop();
|
||||||
}
|
}
|
||||||
|
@ -1237,9 +1238,8 @@ Wiki.prototype.undelete_notebook = function( event, notebook_id ) {
|
||||||
Wiki.prototype.compare_versions = function( event, editor, previous_revision ) {
|
Wiki.prototype.compare_versions = function( event, editor, previous_revision ) {
|
||||||
this.clear_pulldowns();
|
this.clear_pulldowns();
|
||||||
|
|
||||||
// display the two revisions for comparison by the user
|
// display a diff between the two revisions for examination by the user
|
||||||
this.load_editor( editor.title, editor.id, previous_revision, null, editor.closed ? null : editor.iframe );
|
this.load_editor( editor.title, editor.id, editor.revision, previous_revision, editor.closed ? null : editor.iframe );
|
||||||
this.load_editor( editor.title, editor.id, null, null, editor.closed ? null : editor.iframe );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Wiki.prototype.save_editor = function ( editor, fire_and_forget, callback, synchronous, suppress_save_signal ) {
|
Wiki.prototype.save_editor = function ( editor, fire_and_forget, callback, synchronous, suppress_save_signal ) {
|
||||||
|
@ -2167,10 +2167,12 @@ function Changes_pulldown( wiki, notebook_id, invoker, editor ) {
|
||||||
var self = this;
|
var self = this;
|
||||||
for ( var i = 0; i < user_revisions.length - 1; ++i ) { // -1 to skip the oldest revision
|
for ( var i = 0; i < user_revisions.length - 1; ++i ) { // -1 to skip the oldest revision
|
||||||
var user_revision = user_revisions[ i ];
|
var user_revision = user_revisions[ i ];
|
||||||
|
var previous_revision = user_revisions[ i + 1 ];
|
||||||
|
|
||||||
var short_revision = this.wiki.brief_revision( user_revision.revision );
|
var short_revision = this.wiki.brief_revision( user_revision.revision );
|
||||||
var href = "/notebooks/" + this.notebook_id + "?" + queryString(
|
var href = "/notebooks/" + this.notebook_id + "?" + queryString(
|
||||||
[ "note_id", "revision" ],
|
[ "note_id", "revision", "previous_revision" ],
|
||||||
[ this.editor.id, user_revision.revision ]
|
[ this.editor.id, user_revision.revision, previous_revision.revision ]
|
||||||
);
|
);
|
||||||
|
|
||||||
var link = createDOM(
|
var link = createDOM(
|
||||||
|
@ -2181,6 +2183,7 @@ function Changes_pulldown( wiki, notebook_id, invoker, editor ) {
|
||||||
|
|
||||||
this.links.push( link );
|
this.links.push( link );
|
||||||
link.revision = user_revision.revision;
|
link.revision = user_revision.revision;
|
||||||
|
link.previous_revision = previous_revision.revision;
|
||||||
connect( link, "onclick", function ( event ) { self.link_clicked( event, self.editor.id ); } );
|
connect( link, "onclick", function ( event ) { self.link_clicked( event, self.editor.id ); } );
|
||||||
appendChildNodes( this.div, link );
|
appendChildNodes( this.div, link );
|
||||||
appendChildNodes( this.div, createDOM( "br" ) );
|
appendChildNodes( this.div, createDOM( "br" ) );
|
||||||
|
@ -2192,7 +2195,8 @@ Changes_pulldown.prototype.constructor = Changes_pulldown;
|
||||||
|
|
||||||
Changes_pulldown.prototype.link_clicked = function( event, note_id ) {
|
Changes_pulldown.prototype.link_clicked = function( event, note_id ) {
|
||||||
var revision = event.target().revision;
|
var revision = event.target().revision;
|
||||||
this.wiki.load_editor( "Revision not found.", note_id, revision, null, this.editor.iframe );
|
var previous_revision = event.target().previous_revision;
|
||||||
|
this.wiki.load_editor( "Revision not found.", note_id, revision, previous_revision, null, this.editor.iframe );
|
||||||
event.stop();
|
event.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue