witten
/
luminotes
Archived
1
0
Fork 0

Now note reordering is saved to the server. Still to do: New unit tests for reordering. Re-rank all notes in notebook when necessary.

This commit is contained in:
Dan Helfman 2009-02-10 01:32:08 -08:00
parent 0c01d9143f
commit 4f3267b0f4
4 changed files with 91 additions and 81 deletions

View File

@ -672,9 +672,12 @@ class Notebooks( object ):
contents = Valid_string( min = 1, max = 50000, escape_html = False ),
startup = Valid_bool(),
previous_revision = Valid_revision( none_okay = True ),
position_after = Valid_id( none_okay = True ),
position_before = Valid_id( none_okay = True ),
user_id = Valid_id( none_okay = True ),
)
def save_note( self, notebook_id, note_id, contents, startup, previous_revision, user_id ):
def save_note( self, notebook_id, note_id, contents, startup, previous_revision = None,
position_after = None, position_before = None, user_id = None ):
"""
Save a new revision of the given note. This function will work both for creating a new note and
for updating an existing note. If the note exists and the given contents are identical to the
@ -692,6 +695,10 @@ class Notebooks( object ):
@type previous_revision: unicode or NoneType
@param previous_revision: previous known revision timestamp of the provided note, or None if
the note is new
@type position_after: unicode or NoneType
@param position_after: id of note to position the saved note after (optional)
@type position_before: unicode or NoneType
@param position_before: id of note to position the saved note before (optional)
@type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any), determined by @grab_user_id
@rtype: json dict
@ -699,7 +706,7 @@ class Notebooks( object ):
'new_revision': User_revision of saved note, or None if nothing was saved
'previous_revision': User_revision immediately before new_revision, or None if the note is new
'storage_bytes': current storage usage by user
'rank': integer rank of the saved note, or None
'rank': float rank of the saved note, or None
}
@raise Access_error: the current user doesn't have access to the given notebook
@raise Validation_error: one of the arguments is invalid
@ -717,22 +724,35 @@ class Notebooks( object ):
if notebook.read_write == Notebook.READ_WRITE_FOR_OWN_NOTES:
startup = True
def calculate_rank( position_after, position_before ):
after_note = position_after and self.__database.load( Note, position_after ) or None
before_note = position_before and self.__database.load( Note, position_before ) or None
if after_note and before_note:
return ( float( after_note.rank ) + float( before_note.rank ) ) / 2.0
elif after_note:
return float( after_note.rank ) + 1.0
elif before_note:
return max( float( before_note.rank ) - 1.0, 0.0 )
return 0.0
# check whether the provided note contents have been changed since the previous revision
def update_note( current_notebook, old_note, startup, user ):
# the note hasn't been changed, so bail without updating it
if contents.replace( u"\n", u"" ) == old_note.contents.replace( u"\n", "" ) and startup == old_note.startup:
if not position_after and not position_before and startup == old_note.startup and \
contents.replace( u"\n", u"" ) == old_note.contents.replace( u"\n", "" ):
new_revision = None
# the note has changed, so update it
else:
note.contents = contents
note.startup = startup
if startup:
if note.rank is None:
note.rank = self.__database.select_one( float, notebook.sql_highest_note_rank() ) + 1
else:
note.rank = None
note.user_id = user.object_id
if position_after or position_before:
note.rank = calculate_rank( position_after, position_before )
elif note.rank is None:
note.rank = self.__database.select_one( float, notebook.sql_highest_note_rank() ) + 1
note.user_id = user.object_id
new_revision = User_revision( note.revision, note.user_id, user.username )
self.__files.purge_unused( note )
@ -760,10 +780,10 @@ class Notebooks( object ):
new_revision = update_note( notebook, old_note, startup, user )
# otherwise, create a new note
else:
if startup:
rank = self.__database.select_one( float, notebook.sql_highest_note_rank() ) + 1
if position_after or position_before:
note.rank = calculate_rank( position_after, position_before )
else:
rank = None
rank = self.__database.select_one( float, notebook.sql_highest_note_rank() ) + 1
previous_revision = None
note = Note.create( note_id, contents, notebook_id = notebook.object_id, startup = startup, rank = rank, user_id = user_id )

View File

@ -1105,6 +1105,7 @@ class Test_notebooks( Test_controller ):
notebook_id = self.notebook.object_id,
note_id = self.note.object_id,
contents = new_note_contents,
startup = False,
), session_id = self.session_id )
# load the note by the old revision
@ -1122,7 +1123,7 @@ class Test_notebooks( Test_controller ):
assert note.title == previous_title
assert note.contents == previous_contents
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()
@ -1730,11 +1731,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
if startup:
assert result[ "rank" ] == 0.0
else:
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
# make sure the old title can no longer be loaded
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -1758,11 +1755,7 @@ class Test_notebooks( Test_controller ):
assert note.contents == new_note_contents
assert note.startup == startup
assert note.user_id == self.user.object_id
if startup:
assert note.rank == 0.0
else:
assert note.rank is None
assert note.rank == 0.0
# make sure that the correct revisions are returned and are in chronological order
result = self.http_post( "/notebooks/load_note_revisions/", dict(
@ -1872,7 +1865,7 @@ class Test_notebooks( Test_controller ):
assert result[ "previous_revision" ].revision == previous_revision
assert result[ "previous_revision" ].user_id == self.user.object_id
assert result[ "previous_revision" ].username == self.username
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
self.login()
@ -1898,11 +1891,7 @@ class Test_notebooks( Test_controller ):
assert note.contents == new_note_contents
assert note.startup == startup
assert note.user_id == self.user2.object_id
if startup:
assert note.rank == 0.0
else:
assert note.rank is None
assert note.rank == 0.0
# make sure that the correct revisions are returned and are in chronological order
result = self.http_post( "/notebooks/load_note_revisions/", dict(
@ -2004,7 +1993,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
# make sure the old title can no longer be loaded
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -2028,11 +2017,7 @@ class Test_notebooks( Test_controller ):
assert note.contents == new_note_contents.replace( u"<span>", "" )
assert note.startup == startup
assert note.user_id == self.user.object_id
if startup:
assert note.rank == 0.0
else:
assert note.rank is None
assert note.rank == 0.0
# make sure that the correct revisions are returned and are in chronological order
result = self.http_post( "/notebooks/load_note_revisions/", dict(
@ -2081,7 +2066,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
# make sure the old title can no longer be loaded
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -2155,7 +2140,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes == previous_storage_bytes
assert result[ "storage_bytes" ] == 0
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
result = self.http_post( "/notebooks/load_note_by_title/", dict(
notebook_id = self.notebook.object_id,
@ -2209,7 +2194,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes == previous_storage_bytes
assert result[ "storage_bytes" ] == 0
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
result = self.http_post( "/notebooks/load_note_by_title/", dict(
notebook_id = self.notebook.object_id,
@ -2325,7 +2310,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes == previous_storage_bytes
assert result[ "storage_bytes" ] == 0
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
result = self.http_post( "/notebooks/load_note_by_title/", dict(
notebook_id = self.notebook.object_id,
@ -2377,7 +2362,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
# make sure the first title can no longer be loaded
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -2450,11 +2435,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
if startup:
assert result[ "rank" ] == 0.0
else:
assert result[ "rank" ] is None
assert result[ "rank" ] == 0.0
# make sure the new title is now loadable
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -2469,11 +2450,7 @@ class Test_notebooks( Test_controller ):
assert note.contents == new_note.contents
assert note.startup == startup
assert note.user_id == self.user.object_id
if startup:
assert note.rank == 0.0
else:
assert note.rank is None
assert note.rank == 0.0
def test_save_new_startup_note( self ):
self.test_save_new_note( startup = True )
@ -2547,7 +2524,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
assert result[ "rank" ] == None
assert result[ "rank" ] == 0.0
# make sure the new title is now loadable
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -2588,7 +2565,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
assert result[ "rank" ] == None
assert result[ "rank" ] == 0.0
# make sure the new title is now loadable
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -2639,11 +2616,7 @@ class Test_notebooks( Test_controller ):
user = self.database.load( User, self.user.object_id )
assert user.storage_bytes > 0
assert result[ "storage_bytes" ] == user.storage_bytes
if startup:
assert result[ "rank" ] == 1.0
else:
assert result[ "rank" ] is None
assert result[ "rank" ] == 1.0
# make sure the new title is now loadable
result = self.http_post( "/notebooks/load_note_by_title/", dict(
@ -2658,11 +2631,7 @@ class Test_notebooks( Test_controller ):
assert note.contents == new_note.contents
assert note.startup == startup
assert note.user_id == self.user.object_id
if startup:
assert note.rank == 1 # one greater than the previous new note's rank
else:
assert note.rank is None
assert note.rank == 1.0 # one greater than the previous new note's rank
def test_save_two_new_startup_notes( self ):
self.test_save_two_new_notes( startup = True )

View File

@ -848,6 +848,7 @@ Editor.prototype.drop = function( event ) {
swapDOM( hover_drop_target, this.holder );
removeElement( "note_drag_source_area" );
this.highlight();
signal( this, "moved", this, this.previous_editor(), this.next_editor() );
}
var drop_targets = getElementsByTagAndClassName( "div", "note_drop_target" );
@ -863,6 +864,28 @@ Editor.prototype.drop = function( event ) {
}
}
Editor.prototype.previous_editor = function () {
var previous_holder = this.holder.previousSibling;
while ( previous_holder && previous_holder.nodeValue == "\n" )
previous_holder = previous_holder.previousSibling;
if ( !previous_holder || !hasElementClass( previous_holder, "note_holder" ) ) return null;
var div = getFirstElementByTagAndClassName( "div", "static_note_div", previous_holder );
if ( !div || !div.editor ) return null;
return div.editor;
}
Editor.prototype.next_editor = function () {
var next_holder = this.holder.nextSibling;
while ( next_holder && next_holder.nodeValue == "\n" )
next_holder = next_holder.nextSibling;
if ( !next_holder || !hasElementClass( next_holder, "note_holder" ) ) return null;
var div = getFirstElementByTagAndClassName( "div", "static_note_div", next_holder );
if ( !div || !div.editor ) return null;
return div.editor;
}
Editor.prototype.key_pressed = function ( event ) {
signal( this, "key_pressed", this, event );

View File

@ -849,6 +849,9 @@ Wiki.prototype.create_editor = function ( id, note_text, deleted_from_id, revisi
connect( editor, "focused", this, "editor_focused" );
connect( editor, "mouse_hovered", function ( target ) { self.editor_mouse_hovered( editor, target ) } );
connect( editor, "grabber_pressed", function ( event ) { self.editor_focused( null ); } );
connect( editor, "moved", function ( editor, position_after, position_before ) {
self.editor_moved( editor, position_after, position_before );
} );
}
connect( editor, "load_editor", this, "load_editor" );
@ -1038,6 +1041,10 @@ Wiki.prototype.editor_focused = function ( editor, synchronous ) {
this.update_toolbar();
}
Wiki.prototype.editor_moved = function ( editor, position_after, position_before ) {
this.save_editor( editor, false, null, null, null, position_after, position_before );
}
Wiki.prototype.make_byline = function ( username, creation, note_id ) {
if ( username == "anonymous" )
username = "admin";
@ -1205,15 +1212,9 @@ Wiki.prototype.focus_previous_editor = function () {
return;
}
var previous_holder = this.focused_editor.holder.previousSibling;
while ( previous_holder && previous_holder.nodeValue == "\n" )
previous_holder = previous_holder.previousSibling;
if ( !previous_holder || !hasElementClass( previous_holder, "note_holder" ) ) return;
var div = getFirstElementByTagAndClassName( "div", "static_note_div", previous_holder );
if ( !div || !div.editor ) return;
var previous_editor = this.focused_editor.previous_editor();
this.editor_focused( null );
div.editor.highlight();
previous_editor.highlight();
}
Wiki.prototype.focus_next_editor = function () {
@ -1224,15 +1225,9 @@ Wiki.prototype.focus_next_editor = function () {
return;
}
var next_holder = this.focused_editor.holder.nextSibling;
while ( next_holder && next_holder.nodeValue == "\n" )
next_holder = next_holder.nextSibling;
if ( !next_holder || !hasElementClass( next_holder, "note_holder" ) ) return;
var div = getFirstElementByTagAndClassName( "div", "static_note_div", next_holder );
if ( !div || !div.editor ) return;
var next_editor = this.focused_editor.next_editor();
this.editor_focused( null );
div.editor.highlight();
next_editor.highlight();
}
Wiki.prototype.get_toolbar_image_dir = function ( always_small ) {
@ -1694,12 +1689,13 @@ Wiki.prototype.compare_versions = function( event, editor, previous_revision ) {
this.load_editor( editor.title, editor.id, editor.revision, previous_revision, editor.closed ? null : editor.holder );
}
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, position_after, position_before ) {
if ( !editor )
editor = this.focused_editor;
var self = this;
if ( editor && editor.read_write && !editor.empty() && !editor.closed && editor.dirty() ) {
if ( editor && editor.read_write && !editor.empty() && !editor.closed &&
( editor.dirty() || position_after || position_before ) ) {
editor.scrape_title();
this.invoker.invoke( "/notebooks/save_note", "POST", {
@ -1707,7 +1703,9 @@ Wiki.prototype.save_editor = function ( editor, fire_and_forget, callback, synch
"note_id": editor.id,
"contents": editor.contents(),
"startup": editor.startup,
"previous_revision": editor.revision ? editor.revision : "None"
"previous_revision": editor.revision ? editor.revision : "None",
"position_after": position_after ? position_after.id : "None",
"position_before": position_before ? position_before.id : "None"
}, function ( result ) {
self.update_editor_revisions( result, editor );
self.display_storage_usage( result.storage_bytes );