diff --git a/controller/Notebooks.py b/controller/Notebooks.py
index 1a709df..a87591f 100644
--- a/controller/Notebooks.py
+++ b/controller/Notebooks.py
@@ -128,6 +128,11 @@ class Notebooks( object ):
if revision:
result[ "note_read_write" ] = False
+ notebook = self.__database.load( Notebook, notebook_id )
+ if not notebook:
+ raise Access_error()
+ result[ "recent_notes" ] = self.__database.select_many( Note, notebook.sql_load_recent_notes( start = 0, count = 10 ) )
+
# if the user doesn't have any storage bytes yet, they're a new user, so see what type of
# conversion this is (demo or signup)
if result[ "user" ].storage_bytes == 0:
diff --git a/static/css/style.css b/static/css/style.css
index b2e15de..097c1eb 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -270,6 +270,11 @@ img {
font-size: 90%;
}
+#recent_notes_table {
+ margin-bottom: 1em;
+ font-size: 90%;
+}
+
.note_tree_table {
border-collapse: collapse;
}
@@ -299,6 +304,11 @@ img {
padding-left: 19px;
}
+.recent_note_link {
+ background: url(/static/images/note_icon.png) left center no-repeat;
+ padding-left: 19px;
+}
+
.note_tree_loading {
background: url(/static/images/loading.gif) left center no-repeat;
padding-left: 20px;
@@ -582,6 +592,10 @@ img {
padding: 0.25em 0.25em 0.25em 0;
}
+.recent_note_item {
+ padding: 0.25em 0.25em 0.25em 0;
+}
+
.tree_expander {
float: left;
width: 11px;
diff --git a/static/js/Wiki.js b/static/js/Wiki.js
index b8b1e10..69f4b7e 100644
--- a/static/js/Wiki.js
+++ b/static/js/Wiki.js
@@ -19,6 +19,7 @@ function Wiki( invoker ) {
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 )
@@ -2578,7 +2579,7 @@ function Note_tree( wiki, notebook_id, invoker ) {
var self = this;
function connect_expander( note_id ) {
- connect( "note_tree_expander_" + note_id, "onclick", function ( event ) { self.expand_link( event, note_id ); } );
+ connect( "note_tree_expander_" + note_id, "onclick", function ( event ) { self.expand_collapse_link( event, note_id ); } );
}
for ( var i in links ) {
@@ -2643,7 +2644,7 @@ Note_tree.prototype.add_root_link = function ( editor ) {
) );
var self = this;
- connect( expander, "onclick", function ( event ) { self.expand_link( event, editor.id ); } );
+ connect( expander, "onclick", function ( event ) { self.expand_collapse_link( event, editor.id ); } );
connect( link, "onclick", function ( event ) { self.link_clicked( event ); } );
var instructions = getElement( "note_tree_instructions" );
@@ -2667,11 +2668,8 @@ Note_tree.prototype.remove_link = function ( note_id ) {
Note_tree.prototype.rename_link = function ( editor, new_title ) {
var link = getElement( "note_tree_link_" + editor.id );
-
- if ( !link )
- return;
-
- replaceChildNodes( link, new_title || "untitled note" );
+ if ( link )
+ replaceChildNodes( link, new_title || "untitled note" );
}
Note_tree.prototype.update_link = function ( editor ) {
@@ -2711,7 +2709,7 @@ Note_tree.prototype.update_link = function ( editor ) {
}
}
-Note_tree.prototype.expand_link = function ( event, note_id ) {
+Note_tree.prototype.expand_collapse_link = function ( event, note_id ) {
var expander = event.target();
if ( !expander || hasElementClass( expander, "tree_expander_empty" ) )
@@ -2765,14 +2763,11 @@ Note_tree.prototype.expand_link = function ( event, note_id ) {
}
}
-Note_tree.prototype.collapse_link = function ( event, note_id ) {
-}
-
Note_tree.prototype.display_child_links = function ( result, link, children_area ) {
var self = this;
function connect_expander( expander, note_id ) {
- connect( expander, "onclick", function ( event ) { self.expand_link( event, note_id ); } );
+ connect( expander, "onclick", function ( event ) { self.expand_collapse_link( event, note_id ); } );
}
var span = createDOM( "span" );
@@ -2827,3 +2822,99 @@ Note_tree.prototype.display_child_links = function ( result, link, children_area
var note_id = parse_query( link )[ "note_id" ];
connect_expander( expander, note_id );
}
+
+function Recent_notes( wiki, notebook_id ) {
+ this.wiki = wiki;
+ this.notebook_id = notebook_id;
+
+ // if there's no recent notes table, there's nothing to do with recent notes!
+ if ( !getElement( "recent_notes_table" ) )
+ return;
+
+ // add onclick handlers to the recent note links as well
+ var self = this;
+ var recent_links = getElementsByTagAndClassName( "a", "recent_note_link", "note_tree_area" );
+
+ for ( var i in recent_links ) {
+ var link = recent_links[ i ];
+ var query = parse_query( link );
+ var note_id = query[ "note_id" ];
+
+ connect( link, "onclick", function ( event ) { self.link_clicked( event ); } );
+ }
+
+ // connect to the wiki note events
+ 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 ); } );
+}
+
+Recent_notes.prototype.link_clicked = function ( event ) {
+ var link = event.target();
+ var query = parse_query( link );
+ var note_id = query[ "note_id" ];
+ var title = query[ "title" ];
+
+ if ( !note_id )
+ return;
+
+ this.wiki.load_editor( title, note_id );
+ event.stop();
+}
+
+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 ) {
+ var last_item = recent_items[ recent_items.length - 1 ];
+ removeElement( last_item );
+ }
+
+ // add a new recent note link at the top of the list
+ var expander = createDOM( "td", { "class": "tree_expander_empty", "id": "recent_note_expander_" + editor.id } );
+
+ var link = createDOM( "a", {
+ "href": "/notebooks/" + this.notebook_id + "?note_id=" + editor.id,
+ "id": "recent_note_link_" + editor.id,
+ "class": "recent_note_link"
+ }, editor.title || "untitled note" );
+
+ insertSiblingNodesAfter( "recent_notes_top", createDOM(
+ "tr",
+ { "id": "recent_note_item_" + editor.id, "class": "recent_note_item" },
+ expander,
+ createDOM( "td", {}, link )
+ ) );
+
+ var self = this;
+ connect( link, "onclick", function ( event ) { self.link_clicked( event ); } );
+}
+
+Recent_notes.prototype.remove_link = function ( note_id ) {
+ var item = getElement( "recent_note_item_" + note_id );
+ if ( !item ) return;
+
+ removeElement( item );
+}
+
+Recent_notes.prototype.update_link = function ( editor ) {
+ var item = getElement( "recent_note_item_" + editor.id );
+ var link = getElement( "recent_note_link_" + editor.id );
+
+ // the link isn't in the recent notes list, so add it
+ if ( !item || !link ) {
+ this.add_link( editor );
+ return;
+ }
+
+ // the link is already in the recent notes list, so just move it to the top of the list
+ removeElement( item );
+ replaceChildNodes( link, editor.title );
+ insertSiblingNodesAfter( "recent_notes_top", item );
+}
diff --git a/view/Main_page.py b/view/Main_page.py
index efc17f2..e30cc2c 100644
--- a/view/Main_page.py
+++ b/view/Main_page.py
@@ -33,6 +33,7 @@ class Main_page( Page ):
invite_id = None,
after_login = None,
signup_plan = None,
+ recent_notes = None,
):
startup_note_ids = [ startup_note.object_id for startup_note in startup_notes ]
@@ -141,6 +142,7 @@ class Main_page( Page ):
),
notebook,
startup_notes + ( notes and notes or [] ),
+ recent_notes,
total_notes_count,
),
id = u"left_area",
diff --git a/view/Note_tree_area.py b/view/Note_tree_area.py
index 69432d1..03ddde0 100644
--- a/view/Note_tree_area.py
+++ b/view/Note_tree_area.py
@@ -5,7 +5,7 @@ from Tags import Div, Span, H4, A, Table, Tr, Td
class Note_tree_area( Div ):
LINK_PATTERN = re.compile( u']+\s)?href="[^"]+"[^>]*>', re.IGNORECASE )
- def __init__( self, toolbar, notebook, root_notes, total_notes_count ):
+ def __init__( self, toolbar, notebook, root_notes, recent_notes, total_notes_count ):
Div.__init__(
self,
toolbar,
@@ -32,20 +32,24 @@ class Note_tree_area( Div ):
) or None,
tree_id = "note_tree_root_table",
),
- ( notebook.name != u"trash" ) and Span(
+ ( recent_notes and notebook.name != u"trash" ) and Span(
H4( u"recent notes",
id = u"recent_notes_area_title",
),
+ self.make_tree(
+ Tr( id = "recent_notes_top" ),
+ [ self.make_item(
+ title = note.title,
+ link_attributes = u'href="/notebooks/%s?note_id=%s"' % ( notebook.object_id, note.object_id ),
+ link_class = u"recent_note_link",
+ has_children = False,
+ root_note_id = note.object_id,
+ base_name = u"recent_note",
+ ) for note in recent_notes ],
+ tree_id = "recent_notes_table",
+ ),
) or None,
- self.make_tree(
- [ self.make_item(
- title = note.title,
- link_attributes = u'href="/notebooks/%s?note_id=%s"' % ( notebook.object_id, note.object_id ),
- link_class = u"note_tree_link",
- has_children = False,
- ) for note in []],#recent_notes ],
- ),
- id = u"recent_notes_area_holder",
+ id = u"note_tree_area_holder",
),
Span( id = "tree_arrow_hover_preload" ),
Span( id = "tree_arrow_down_preload" ),
@@ -54,22 +58,25 @@ class Note_tree_area( Div ):
)
@staticmethod
- def make_item( title, link_attributes, link_class, has_children = False, root_note_id = None, target = None ):
+ def make_item( title, link_attributes, link_class, has_children = False, root_note_id = None, target = None, base_name = None ):
+ if base_name is None:
+ base_name = u"note_tree"
+
return Tr(
has_children and \
- Td( id = root_note_id and u"note_tree_expander_" + root_note_id or None, class_ = u"tree_expander" ) or
- Td( id = root_note_id and u"note_tree_expander_" + root_note_id or None, class_ = u"tree_expander_empty" ),
+ Td( id = root_note_id and u"%s_expander_%s" % ( base_name, root_note_id ) or None, class_ = u"tree_expander" ) or
+ Td( id = root_note_id and u"%s_expander_%s" % ( base_name, root_note_id ) or None, class_ = u"tree_expander_empty" ),
Td(
u"%s" % (
link_attributes,
- root_note_id and u' id="note_tree_link_%s"' % root_note_id or "",
+ root_note_id and u' id="%s_link_%s"' % ( base_name, root_note_id ) or "",
target and u' target="%s"' % target or "",
link_class,
title or u"untitled note",
),
),
- id = root_note_id and u"note_tree_item_" + root_note_id or None,
- class_ = u"note_tree_item",
+ id = root_note_id and u"%s_item_%s" % ( base_name, root_note_id ) or None,
+ class_ = u"%s_item" % base_name,
)
@staticmethod