witten
/
luminotes
Archived
1
0
Fork 0

* Renamed existing controller.Notebooks.load_recent_notes method to just recent_notes().

* Implemented new controller.Notebooks.load_recent_updates() method.
 * Added new Wiki.js total_notes_count_updated signal
 * Added "more" and "less" links to "recent updates" table.
 * Updated Wiki.js Recent_notes to support new "more" and "less" links.
 * Commented out unfinished discussion forums unit test.
This commit is contained in:
Dan Helfman 2008-04-29 00:54:08 +00:00
parent f43d6b5573
commit 1d0867d776
7 changed files with 172 additions and 21 deletions

3
NEWS
View File

@ -1,3 +1,6 @@
1.3.6: April ??, 2008
* Can now click "more" link to display more than ten "recent updates".
1.3.5: April 24, 2008
* Reducing the number of links in the header by consolidating several into
one "support" link.

View File

@ -3,7 +3,7 @@ import cgi
import cherrypy
from datetime import datetime
from Expose import expose
from Validate import validate, Valid_string, Validation_error, Valid_bool
from Validate import validate, Valid_string, Validation_error, Valid_bool, Valid_int
from Database import Valid_id, Valid_revision, end_transaction
from Users import grab_user_id, Access_error
from Expire import strongly_expire
@ -1364,19 +1364,61 @@ class Notebooks( object ):
return dict()
def load_recent_notes( self, notebook_id, start = 0, count = 10, user_id = None ):
@expose( view = Json )
@strongly_expire
@end_transaction
@grab_user_id
@validate(
notebook_id = Valid_id(),
start = Valid_int( min = 0 ),
count = Valid_int( min = 1 ),
user_id = Valid_id( none_okay = True ),
)
def load_recent_updates( self, notebook_id, start, count, user_id = None ):
"""
Provide the information necessary to display the page for a particular notebook's most recent
notes.
Provide the information necessary to display a notebook's recent updated/created notes, in
reverse chronological order by update time.
@type notebook_id: unicode
@param notebook_id: id of the notebook to display
@param notebook_id: id of the notebook containing the notes
@type start: unicode or NoneType
@param start: index of recent note to start with (defaults to 0, the most recent note)
@type count: int or NoneType
@param count: number of recent notes to display (defaults to 10 notes)
@type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any)
@rtype: json dict
@return: { 'notes': recent_notes_list }
@raise Access_error: the current user doesn't have access to the given notebook or note
"""
if not self.__users.check_access( user_id, notebook_id ):
raise Access_error()
notebook = self.__database.load( Notebook, notebook_id )
if notebook is None:
raise Access_error()
recent_notes = self.__database.select_many( Note, notebook.sql_load_notes( start = start, count = count ) )
return dict(
notes = recent_notes,
)
def recent_notes( self, notebook_id, start = 0, count = 10, user_id = None ):
"""
Return the given notebook's recently updated notes in reverse chronological order by creation
time.
@type notebook_id: unicode
@param notebook_id: id of the notebook containing the notes
@type start: unicode or NoneType
@param start: index of recent note to start with (defaults to 0, the most recent note)
@type count: int or NoneType
@param count: number of recent notes to return (defaults to 10 notes)
@type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any)
@rtype: dict
@return: data for Main_page() constructor
@raise Access_error: the current user doesn't have access to the given notebook or note

View File

@ -230,7 +230,7 @@ class Root( object ):
result = self.__users.current( user_id )
blog_notebooks = [ nb for nb in result[ "notebooks" ] if nb.name == u"Luminotes blog" ]
result.update( self.__notebooks.load_recent_notes( blog_notebooks[ 0 ].object_id, start, count, user_id ) )
result.update( self.__notebooks.recent_notes( blog_notebooks[ 0 ].object_id, start, count, user_id ) )
# if a single note was requested, just return that one note
if note_id:

View File

@ -40,7 +40,7 @@ class Test_forums( Test_controller ):
self.database.save( self.anonymous )
self.database.execute( self.anonymous.sql_save_notebook( self.anon_notebook.object_id ) )
def test_index( self ):
def XXXtest_index( self ): # TODO
result = self.http_get( "/forums/" )
assert result

View File

@ -3210,7 +3210,7 @@ class Test_notebooks( Test_controller ):
assert u"access" in result[ u"error" ]
def test_recent_notes( self ):
result = cherrypy.root.notebooks.load_recent_notes(
result = cherrypy.root.notebooks.recent_notes(
self.notebook.object_id,
user_id = self.user.object_id,
)
@ -3239,7 +3239,7 @@ class Test_notebooks( Test_controller ):
assert user.storage_bytes == 0
def test_recent_notes_with_start( self ):
result = cherrypy.root.notebooks.load_recent_notes(
result = cherrypy.root.notebooks.recent_notes(
self.notebook.object_id,
start = 1,
user_id = self.user.object_id,
@ -3268,7 +3268,7 @@ class Test_notebooks( Test_controller ):
assert user.storage_bytes == 0
def test_recent_notes_with_count( self ):
result = cherrypy.root.notebooks.load_recent_notes(
result = cherrypy.root.notebooks.recent_notes(
self.notebook.object_id,
count = 1,
user_id = self.user.object_id,
@ -3298,14 +3298,14 @@ class Test_notebooks( Test_controller ):
@raises( Access_error )
def test_recent_notes_with_unknown_notebok( self ):
result = cherrypy.root.notebooks.load_recent_notes(
result = cherrypy.root.notebooks.recent_notes(
self.unknown_notebook_id,
user_id = self.user.object_id,
)
@raises( Access_error )
def test_recent_notes_with_incorrect_user( self ):
result = cherrypy.root.notebooks.load_recent_notes(
result = cherrypy.root.notebooks.recent_notes(
self.notebook.object_id,
user_id = self.anonymous.object_id,
)

View File

@ -18,8 +18,6 @@ function Wiki( invoker ) {
this.after_login = getElement( "after_login" ).value;
this.signup_plan = getElement( "signup_plan" ).value;
this.font_size = null;
this.note_tree = new Note_tree( this, this.notebook_id, this.invoker );
this.recent_notes = new Recent_notes( this, this.notebook_id );
var total_notes_count_node = getElement( "total_notes_count" );
if ( total_notes_count_node )
@ -27,6 +25,9 @@ function Wiki( invoker ) {
else
this.total_notes_count = null;
this.note_tree = new Note_tree( this, this.notebook_id, this.invoker );
this.recent_notes = new Recent_notes( this, this.notebook_id, this.invoker );
// grab the current notebook from the list of available notebooks
this.notebooks = evalJSON( getElement( "notebooks" ).value );
for ( var i in this.notebooks ) {
@ -1841,18 +1842,21 @@ Wiki.prototype.increment_total_notes_count = function () {
if ( this.total_notes_count == null ) return;
this.total_notes_count += 1;
replaceChildNodes( "total_notes_count", this.total_notes_count );
signal( this, "total_notes_count_updated", this.total_notes_count );
}
Wiki.prototype.decrement_total_notes_count = function () {
if ( this.total_notes_count == null ) return;
this.total_notes_count -= 1;
replaceChildNodes( "total_notes_count", this.total_notes_count );
signal( this, "total_notes_count_updated", this.total_notes_count );
}
Wiki.prototype.zero_total_notes_count = function () {
if ( this.total_notes_count == null ) return;
this.total_notes_count = 0;
replaceChildNodes( "total_notes_count", this.total_notes_count );
signal( this, "total_notes_count_updated", this.total_notes_count );
}
Wiki.prototype.start_notebook_rename = function () {
@ -2889,9 +2893,15 @@ Note_tree.prototype.display_child_links = function ( result, link, children_area
connect_expander( expander, note_id );
}
function Recent_notes( wiki, notebook_id ) {
function Recent_notes( wiki, notebook_id, invoker ) {
this.wiki = wiki;
this.notebook_id = notebook_id;
this.invoker = invoker;
this.INCREMENT = 10;
this.max_recent_notes_count = this.INCREMENT; // maximum increases when the user clicks "more"
this.total_notes_count = 0;
this.total_notes_count_updated( wiki.total_notes_count );
// if there's no recent notes table, there's nothing to do with recent notes!
if ( !getElement( "recent_notes_table" ) )
@ -2913,6 +2923,33 @@ function Recent_notes( wiki, notebook_id ) {
connect( wiki, "note_added", function ( editor ) { self.add_link( editor ); } );
connect( wiki, "note_removed", function ( id ) { self.remove_link( id ); } );
connect( wiki, "note_saved", function ( editor ) { self.update_link( editor ); } );
connect( wiki, "total_notes_count_updated", function ( count ) { self.total_notes_count_updated( count ); } );
// connect to the "more" navigation link
connect( "recent_notes_more_link", "onclick", function ( event ) { self.more_clicked( event ); } );
connect( "recent_notes_less_link", "onclick", function ( event ) { self.less_clicked( event ); } );
}
Recent_notes.prototype.links_count = function () {
var recent_links = getElementsByTagAndClassName( "a", "recent_note_link", "note_tree_area" );
return recent_links.length;
}
Recent_notes.prototype.total_notes_count_updated = function( count ) {
this.total_notes_count = count;
this.update_navigation_links();
}
Recent_notes.prototype.update_navigation_links = function() {
if ( this.total_notes_count > this.max_recent_notes_count )
removeElementClass( "recent_notes_more_link", "undisplayed" );
else
addElementClass( "recent_notes_more_link", "undisplayed" );
if ( this.max_recent_notes_count > this.INCREMENT )
removeElementClass( "recent_notes_less_link", "undisplayed" );
else
addElementClass( "recent_notes_less_link", "undisplayed" );
}
Recent_notes.prototype.link_clicked = function ( event ) {
@ -2928,16 +2965,76 @@ Recent_notes.prototype.link_clicked = function ( event ) {
event.stop();
}
Recent_notes.prototype.more_clicked = function ( event ) {
event.stop();
this.max_recent_notes_count += this.INCREMENT;
var self = this;
var links_count = this.links_count();
this.invoker.invoke(
"/notebooks/load_recent_updates", "GET", {
"notebook_id": this.notebook_id,
"start": links_count,
"count": this.max_recent_notes_count - links_count
},
function ( result ) { self.append_links( result ); }
);
}
Recent_notes.prototype.append_links = function ( result ) {
var self = this;
var table = getElement( "recent_notes_table" );
var links_count = this.links_count();
for ( var i in result.notes ) {
var note = result.notes[ i ];
var row = table.insertRow( links_count + 1 );
row.setAttribute( "id", "recent_note_item_" + note.object_id );
addElementClass( row, "recent_note_item" );
var expander_td = row.insertCell( 0 );
expander_td.innerHTML = '<div id="recent_note_expander_' + note.object_id + '" class="tree_expander_empty"';
var link_td = row.insertCell( 1 );
link_td.innerHTML =
'<a href="/notebooks/' + this.notebook_id + '?note_id=' + note.object_id +
'" id="recent_note_link_' + note.object_id + '" class="recent_note_link">' +
( note.title || 'untitled note' ) + '</a>';
connect( "recent_note_link_" + note.object_id, "onclick", function ( event ) { self.link_clicked( event ); } );
links_count += 1;
}
this.update_navigation_links();
}
Recent_notes.prototype.less_clicked = function ( event ) {
event.stop();
this.max_recent_notes_count -= this.INCREMENT;
var rows_to_remove_count = this.links_count() - this.max_recent_notes_count;
if ( rows_to_remove_count <= 0 )
return;
var rows = getElementsByTagAndClassName( "tr", "recent_note_item", "recent_notes_table" );
var row_count = rows.length;
for ( var i = 0; i < rows_to_remove_count; ++i ) {
removeElement( rows[ row_count - i - 1 ] );
}
this.update_navigation_links();
}
Recent_notes.prototype.add_link = function ( editor ) {
// if the link is already present in the recent notes list, bail
var item = getElement( "recent_note_item_" + editor.id )
if ( item ) return;
MAX_RECENT_NOTES_COUNT = 10;
// if there will be too many recent notes listed once another is added, then remove the last one
var recent_items = getElementsByTagAndClassName( "tr", "recent_note_item", "recent_notes_table" );
if ( recent_items && recent_items.length >= MAX_RECENT_NOTES_COUNT ) {
if ( recent_items && recent_items.length >= this.max_recent_notes_count ) {
var last_item = recent_items[ recent_items.length - 1 ];
removeElement( last_item );
}

View File

@ -46,6 +46,13 @@ class Note_tree_area( Div ):
root_note_id = note.object_id,
base_name = u"recent_note",
) for note in recent_notes ],
navigation = Tbody( Tr(
Td(),
Td(
A( u"more", href = u"#", id = u"recent_notes_more_link", class_ = u"undisplayed" ),
A( u"less", href = u"#", id = u"recent_notes_less_link", class_ = u"undisplayed" ),
),
), id = u"recent_notes_navigation" ),
tree_id = "recent_notes_table",
),
) or None,
@ -80,13 +87,15 @@ class Note_tree_area( Div ):
)
@staticmethod
def make_tree( items, other_node = None, tree_id = None ):
def make_tree( first_node, second_node = None, third_node = None, navigation = None, tree_id = None ):
return Table(
Tbody(
items,
other_node,
first_node,
second_node,
third_node,
id = tree_id and tree_id + "_body" or None,
),
navigation,
id = tree_id or None,
class_ = u"note_tree_table",
)