* 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:
parent
f43d6b5573
commit
1d0867d776
3
NEWS
3
NEWS
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
|
|
Reference in New Issue