witten
/
luminotes
Archived
1
0
Fork 0

Began implementing note tree control on the left side of the page:

* Added a fixed list of startup links.
  * When link in list is clicked, open corresponding note editor.
  * When a startup note is added/deleted, update the list.

Still much more work to do on this before it's complete.
This commit is contained in:
Dan Helfman 2008-04-09 23:31:30 +00:00
parent 272dd3e157
commit a56536ee5e
15 changed files with 208 additions and 184 deletions

View File

@ -4,13 +4,20 @@
#toolbar {
position: absolute;
float: none;
width: auto;
width: expression( eval( document.all.center_area && ( document.all.center_area.offsetLeft - 50 ) || 0 ) );
text-align: right;
}
#note_tree_area {
left: 0;
width: expression( eval( document.all.center_area && ( document.all.center_area.offsetLeft - 50 ) || 0 ) );
position: absolute;
top: expression( eval( document.compatMode && document.compatMode == 'CSS1Compat' ) ? documentElement.scrollTop + 80 : document.body.scrollTop + 80 );
margin-left: expression(
document.body.clientWidth < ( 900 / 12 ) *
parseInt( document.body.currentStyle.fontSize ) ? "-120px": "-80px"
);
}
#note_tree_area_holder {
overflow: auto;
height: expression( eval( documentElement.offsetHeight - 100 ) );
}
#status_area {
@ -27,23 +34,15 @@
#everything_area {
width:expression(
document.body.clientWidth < ( 1300 / 12 ) *
parseInt( document.body.currentStyle.fontSize ) ? "100%": "78em"
parseInt( document.body.currentStyle.fontSize ) ? "100%": "80em"
);
}
#toolbar_area {
width:expression(
document.body.clientWidth < ( 1300 / 12 ) *
parseInt( document.body.currentStyle.fontSize ) ? "18%": "15em"
);
text-align: right;
}
#center_area {
float: right;
width:expression(
document.body.clientWidth < ( 1300 / 12 ) *
parseInt( document.body.currentStyle.fontSize ) ? "60%": "45em"
parseInt( document.body.currentStyle.fontSize ) ? "56%": "45em"
);
}
@ -51,17 +50,6 @@
width: 100%;
}
#link_area {
width:expression(
document.body.clientWidth < ( 1300 / 12 ) *
parseInt( document.body.currentStyle.fontSize ) ? "17%": "15em"
);
}
#link_area_wrapper {
margin-left: 1.5em;
}
.pulldown {
height: expression( this.scrollHeight > 200 ? "200px" : "auto" );
width: expression( this.scrollHeight > 200 ? "12em" : "auto" );

View File

@ -1,7 +1,19 @@
#toolbar {
left: 2em;
#note_tree_area {
float: right;
margin-left: -6em;
}
#note_tree_area_holder {
overflow: auto;
height: expression( eval( documentElement.offsetHeight - 100 ) );
}
#center_area {
float: right;
max-width: 59%;
}
#this_notebook_area_title {
margin-top: 1.5em;
}

View File

@ -28,26 +28,24 @@ img {
#everything_area {
margin: 0 auto;
text-align: center;
width: 78em;
max-width: 100%;
max-width: 80em;
}
#toolbar_area {
#left_area {
float: left;
width: 15em;
max-width: 18%;
width: 17em;
max-width: 20%;
}
#toolbar {
width: 15em;
max-width: 18%;
position: fixed;
text-align: right;
z-index: 1;
}
#toolbar .button_wrapper {
float: right;
margin-left: 15px;
margin-right: 15px;
}
#toolbar .image_button {
@ -232,17 +230,43 @@ img {
background-image: url(/static/images/arrow_down_hover.png);
}
#note_tree_area {
position: fixed;
width: 17em;
max-width: 20%;
text-align: left;
line-height: 140%;
top: 80px;
bottom: 1em;
overflow-y: visible;
}
#note_tree_area_holder {
height: 100%;
overflow-y: auto;
padding-left: 1em;
margin-right: 1em;
}
#note_tree_area_title {
margin-top: 0.5em;
margin-bottom: 0.25em;
}
#link_area {
float: right;
text-align: left;
line-height: 140%;
width: 20%;
}
#link_area_holder {
padding-left: 1em;
padding-right: 1em;
line-height: 100%;
width: 15em;
max-width: 17%;
}
#this_notebook_area_title {
margin-top: 0.5em;
margin-top: 0;
margin-bottom: 0.25em;
}
@ -500,8 +524,19 @@ img {
}
.link_area_item {
margin-top: 0.25em;
padding: 0.25em 0.25em 0.25em 0.5em;
padding: 0.2em 0.25em 0.2em 0.5em;
}
.tree_expander {
float: left;
width: 20px;
height: 1.5em;
background: url(/static/images/tree_arrow.png) no-repeat center center;
}
.tree_expander:hover {
background: url(/static/images/tree_arrow_hover.png) no-repeat center center;
cursor: pointer;
}
#storage_usage_area {
@ -607,6 +642,7 @@ img {
.small_text {
font-size: 90%;
font-weight: normal;
}
.new_feature_text {

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

View File

@ -9,7 +9,6 @@ function Wiki( invoker ) {
this.parent_id = getElement( "parent_id" ).value; // id of the notebook containing this one
this.startup_notes = new Array(); // map of startup notes: note id to bool
this.open_editors = new Array(); // map of open notes: note title to editor
this.all_notes_editor = null; // editor for display of list of all notes
this.search_results_editor = null; // editor for display of search results
this.invoker = invoker;
this.rate_plan = evalJSON( getElement( "rate_plan" ).value );
@ -19,6 +18,7 @@ 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 );
var total_notes_count_node = getElement( "total_notes_count" );
if ( total_notes_count_node )
@ -312,14 +312,6 @@ Wiki.prototype.populate = function ( startup_notes, current_notes, note_read_wri
);
}
var all_notes_link = getElement( "all_notes_link" );
if ( all_notes_link ) {
connect( all_notes_link, "onclick", function ( event ) {
self.load_editor( "all notes", "null", null, null, getElement( "notes_top" ) );
event.stop();
} );
}
var download_html_link = getElement( "download_html_link" );
if ( download_html_link ) {
connect( download_html_link, "onclick", function ( event ) {
@ -398,8 +390,7 @@ Wiki.prototype.create_blank_editor = function ( event ) {
var editor = this.create_editor( undefined, undefined, undefined, undefined, undefined, this.notebook.read_write, true, true );
this.increment_total_notes_count();
this.blank_editor_id = editor.id;
this.add_all_notes_link( editor.id, "" );
signal( this, "note_added", editor );
}
Wiki.prototype.load_editor = function ( note_title, note_id, revision, link, position_after ) {
@ -443,13 +434,6 @@ Wiki.prototype.load_editor = function ( note_title, note_id, revision, link, pos
var self = this;
if ( pulldown_title || note_id == undefined || note_id == "new" || note_id == "null" ) {
// if the note_title corresponds to a "magic" note's title, then dynamically highlight or create the note
if ( note_title == "all notes" ) {
this.invoker.invoke(
"/notebooks/all_notes", "GET", { "notebook_id": this.notebook.object_id },
function( result ) { self.display_all_notes_list( result ); }
);
return;
}
if ( note_title == "search results" ) {
var editor = this.open_editors[ note_title ];
if ( editor ) {
@ -513,14 +497,12 @@ Wiki.prototype.resolve_link = function ( note_title, link, callback ) {
if ( link && link.target )
link.removeAttribute( "target" );
if ( note_title == "all notes" || note_title == "search results" || note_title == "share this notebook" ) {
if ( note_title == "search results" || note_title == "share this notebook" ) {
link.href = "/notebooks/" + this.notebook_id + "?" + queryString(
[ "title", "note_id" ],
[ note_title, "null" ]
);
if ( callback ) {
if ( note_title == "all notes" )
callback( "list of all notes in this notebook" );
if ( note_title == "search results" )
callback( "current search results" );
else
@ -751,7 +733,7 @@ Wiki.prototype.editor_title_changed = function ( editor, old_title, new_title )
if ( new_title != null && !editor.empty() ) {
this.open_editors[ new_title ] = editor;
this.add_all_notes_link( editor.id, new_title );
signal( this, "note_renamed", editor, new_title );
}
}
@ -804,7 +786,7 @@ Wiki.prototype.editor_focused = function ( editor, synchronous ) {
// if the formerly focused editor is completely empty, then remove it as the user leaves it and switches to this editor
if ( this.focused_editor.id == this.blank_editor_id && this.focused_editor.empty() ) {
this.remove_all_notes_link( this.focused_editor.id );
signal( this, "note_removed", this.focused_editor.id );
this.focused_editor.shutdown();
this.decrement_total_notes_count();
this.display_empty_message();
@ -1081,7 +1063,7 @@ Wiki.prototype.hide_editor = function ( event, editor ) {
// if the editor to hide is completely empty, then simply remove it
if ( editor.id == this.blank_editor_id && editor.empty() ) {
this.remove_all_notes_link( editor.id );
signal( this, "note_removed", editor.id );
editor.shutdown();
this.decrement_total_notes_count();
} else {
@ -1090,10 +1072,9 @@ Wiki.prototype.hide_editor = function ( event, editor ) {
this.save_editor( editor );
editor.shutdown();
Highlight( "all_notes_link" );
}
this.display_empty_message( id == "all_notes" );
this.display_empty_message();
}
event.stop();
@ -1142,7 +1123,7 @@ Wiki.prototype.delete_editor = function ( event, editor ) {
connect( undo_button, "onclick", function ( event ) { self.undelete_editor_via_undo( event, editor, message_div ); } );
}
self.remove_all_notes_link( editor.id );
signal( self, "note_removed", editor.id );
editor.shutdown();
self.decrement_total_notes_count();
@ -1176,7 +1157,7 @@ Wiki.prototype.undelete_editor_via_trash = function ( event, editor ) {
if ( editor == this.focused_editor )
this.focused_editor = null;
this.remove_all_notes_link( editor.id );
signal( this, "note_removed", editor.id );
editor.shutdown();
this.decrement_total_notes_count();
@ -1199,6 +1180,7 @@ Wiki.prototype.undelete_editor_via_undo = function( event, editor, position_afte
this.startup_notes[ editor.id ] = true;
this.increment_total_notes_count();
this.load_editor( "Note not found.", editor.id, null, null, position_after );
signal( this, "note_added", editor );
}
event.stop();
@ -1216,6 +1198,7 @@ Wiki.prototype.undelete_editor_via_undelete = function( event, note_id, position
this.startup_notes[ note_id ] = true;
this.increment_total_notes_count();
this.load_editor( "Note not found.", note_id, null, null, position_after );
signal( this, "note_removed", editor.id );
event.stop();
}
@ -1371,40 +1354,6 @@ Wiki.prototype.display_search_results = function ( result ) {
this.search_results_editor = this.create_editor( "search_results", "<h3>search results</h3>" + list.innerHTML, undefined, undefined, undefined, false, true, true, getElement( "notes_top" ) );
}
Wiki.prototype.display_all_notes_list = function ( result ) {
this.clear_messages();
this.clear_pulldowns();
if ( this.display_empty_message( true ) == true )
return;
if ( this.all_notes_editor )
this.all_notes_editor.shutdown();
// build up a list of all notes in this notebook, one link per note
var list = createDOM( "ul", { "id": "notes_list" } );
if ( this.focused_editor ) {
var focused_title = this.focused_editor.title;
if ( focused_title != "all notes" && focused_title != "search results" && focused_title != "share this notebook" )
appendChildNodes( list, this.create_all_notes_link( this.focused_editor.id, this.focused_editor.title || "untitled note" ) );
}
for ( var i in result.notes ) {
var note_tuple = result.notes[ i ]
var note_id = note_tuple[ 0 ];
var note_title = note_tuple[ 1 ];
if ( this.focused_editor && note_id == this.focused_editor.id )
continue;
if ( !note_title )
note_title = "untitled note";
appendChildNodes( list, this.create_all_notes_link( note_id, note_title ) );
}
var list_holder = createDOM( "div", {}, list );
this.all_notes_editor = this.create_editor( "all_notes", "<h3>all notes</h3>" + list_holder.innerHTML, undefined, undefined, undefined, false, true, true, getElement( "notes_top" ) );
}
Wiki.prototype.share_notebook = function () {
this.clear_pulldowns();
@ -1792,11 +1741,7 @@ Wiki.prototype.display_empty_message = function ( replace_messages ) {
}
if ( !replace_messages ) {
var self = this;
this.invoker.invoke(
"/notebooks/all_notes", "GET", { "notebook_id": this.notebook.object_id },
function( result ) { self.display_all_notes_list( result ); }
);
// TODO: display a message about the note tree, or some way for the user to get back to their notes
return true;
}
@ -1837,55 +1782,6 @@ Wiki.prototype.zero_total_notes_count = function () {
replaceChildNodes( "total_notes_count", this.total_notes_count );
}
Wiki.prototype.remove_all_notes_link = function ( note_id ) {
if ( !this.all_notes_editor ) return;
withDocument( this.all_notes_editor.document, function () {
var note_link = getElement( "note_link_" + note_id );
if ( note_link )
removeElement( note_link );
} );
this.all_notes_editor.resize();
}
Wiki.prototype.add_all_notes_link = function ( note_id, note_title ) {
if ( !this.all_notes_editor ) return;
if ( note_title == "all notes" || note_title == "search results" || note_title == "share this notebook" ) return;
if ( !note_title || note_title.length == 0 )
note_title = "untitled note";
var self = this;
withDocument( this.all_notes_editor.document, function () {
// if the note link already exists, update its title and bail
var note_link = getElement( "note_link_" + note_id );
if ( note_link ) {
replaceChildNodes( note_link.firstChild, note_title );
self.all_notes_editor.resize();
return;
}
var notes_list = getElement( "notes_list" );
if ( !notes_list ) return;
var first_note_link = notes_list.firstChild;
var new_note_link = self.create_all_notes_link( note_id, note_title );
if ( first_note_link )
insertSiblingNodesBefore( first_note_link, new_note_link );
else
appendChildNodes( notes_list, new_note_link );
} );
this.all_notes_editor.resize();
}
Wiki.prototype.create_all_notes_link = function ( note_id, note_title ) {
return createDOM( "li", { "id": "note_link_" + note_id },
createDOM( "a", { "href": "/notebooks/" + this.notebook_id + "?note_id=" + note_id }, note_title )
);
}
Wiki.prototype.start_notebook_rename = function () {
this.clear_pulldowns();
@ -2257,12 +2153,6 @@ function Link_pulldown( wiki, notebook_id, invoker, editor, link ) {
// if the note has no destination note id set, try loading the note from the server by title
if ( ( id == undefined || id == "new" || id == "null" ) && title.length > 0 ) {
if ( title == "all notes" ) {
this.title_field.value = title;
this.display_summary( title, "list of all notes in this notebook" );
return;
}
if ( title == "search results" ) {
this.title_field.value = title;
this.display_summary( title, "current search results" );
@ -2663,3 +2553,76 @@ File_link_pulldown.prototype.shutdown = function () {
this.link.pulldown = null;
}
function Note_tree( wiki, notebook_id, invoker ) {
this.wiki = wiki;
this.notebook_id = notebook_id;
this.invoker = invoker;
// add onclick handlers to the initial note links within the tree
var links = getElementsByTagAndClassName( "a", "note_tree_link", "note_tree_area" );
var self = this;
for ( var i in links ) {
var link = links[ i ];
// TODO: connect expander as well
connect( link, "onclick", function ( event ) { self.link_clicked( event ); } );
}
// connect to the wiki note events
connect( wiki, "note_renamed", function ( editor, new_title ) { self.rename_link( editor, new_title ); } );
connect( wiki, "note_added", function ( editor ) { self.add_link( editor ); } );
connect( wiki, "note_removed", function ( id ) { self.remove_link( id ); } );
connect( wiki, "note_updated", function ( editor ) { self.update_child_links( editor ); } );
}
Note_tree.prototype.link_clicked = function ( event ) {
var link = event.target();
var query = parse_query( link );
var note_id = query[ "note_id" ];
if ( !note_id )
return;
this.wiki.load_editor( null, note_id );
event.stop();
}
Note_tree.prototype.add_link = function ( editor ) {
// for now, only add startup notes to the note tree
if ( !editor.startup )
return;
var expander = createDOM( "div", { "class": "tree_expander" } );
var link = createDOM( "a", {
"href": "/notebooks/" + this.notebook_id + "?note_id=" + editor.id,
"id": "note_tree_link_" + editor.id,
"class": "note_tree_link"
}, editor.title );
appendChildNodes( "note_tree_area_holder", createDOM(
"div",
{ "id": "note_tree_item_" + editor.id, "class": "link_area_item" },
expander,
link
) );
var self = this;
// TODO: connect expander as well
connect( link, "onclick", function ( event ) { self.link_clicked( event ); } );
}
Note_tree.prototype.remove_link = function ( id ) {
removeElement( "note_tree_item_" + id );
}
Note_tree.prototype.rename_link = function ( editor, new_title ) {
}
Note_tree.prototype.expand_link = function ( id ) {
}
Note_tree.prototype.collapse_link = function ( id ) {
}
Note_tree.prototype.update_child_links = function ( editor ) {
}

View File

@ -4,7 +4,7 @@ from Search_form import Search_form
class Link_area( Div ):
def __init__( self, notebooks, notebook, total_notes_count, parent_id, notebook_path, user ):
def __init__( self, notebooks, notebook, parent_id, notebook_path, user ):
linked_notebooks = [ nb for nb in notebooks if
( nb.read_write or not nb.name.startswith( u"Luminotes" ) ) and
nb.name not in ( u"trash" ) and
@ -20,19 +20,6 @@ class Link_area( Div ):
Search_form(),
class_ = u"link_area_item",
),
( parent_id is None ) and Div(
A(
u"all notes",
href = u"#",
id = u"all_notes_link",
title = u"View a list of all notes in this notebook.",
),
Span(
Span( total_notes_count, id = u"total_notes_count" ), u"total",
class_ = u"small_text",
),
class_ = u"link_area_item",
) or None,
( notebook.name != u"Luminotes" ) and Div(
A(
@ -156,7 +143,7 @@ class Link_area( Div ):
Div(
id = u"storage_usage_area",
),
id = u"link_area_wrapper",
id = u"link_area_holder",
),
id = u"link_area",
)

View File

@ -2,6 +2,7 @@ from cgi import escape
from Page import Page
from Header import Header
from Tags import Link, Input, Div, Span, H2, H4, A, Br, Strong, Script, Img
from Note_tree_area import Note_tree_area
from Link_area import Link_area
from Toolbar import Toolbar
from Json import Json
@ -134,11 +135,17 @@ class Main_page( Page ):
Header( user, header_notebook, login_url, logout_url, header_note_title ),
Div(
Div(
Br(),
Toolbar( hide_toolbar = parent_id or not notebook.read_write ),
id = u"toolbar_area",
Note_tree_area(
Toolbar(
hide_toolbar = parent_id or not notebook.read_write
),
notebook,
startup_notes, # TODO: pass root_notes, not startup_notes
total_notes_count,
),
id = u"left_area",
),
Link_area( notebooks, notebook, total_notes_count, parent_id, notebook_path, user ),
Link_area( notebooks, notebook, parent_id, notebook_path, user ),
Div(
Rounded_div(
( notebook.name == u"trash" ) and u"trash_notebook" or u"current_notebook",

31
view/Note_tree_area.py Normal file
View File

@ -0,0 +1,31 @@
from Tags import Div, Span, H4, A
class Note_tree_area( Div ):
def __init__( self, toolbar, notebook, root_notes, total_notes_count ):
Div.__init__(
self,
toolbar,
Div(
H4( u"notes",
Span(
Span( total_notes_count, id = u"total_notes_count" ), u"total",
class_ = u"small_text link_area_item",
),
id = u"note_tree_area_title",
),
[ Div(
Div( class_ = u"tree_expander" ),
A(
note.title,
href = u"/notebooks/%s?note_id=%s" % ( notebook.object_id, note.object_id ),
id = u"note_tree_link_" + note.object_id,
class_ = u"note_tree_link",
),
id = u"note_tree_item_" + note.object_id,
class_ = u"link_area_item",
) for note in root_notes ],
id = u"note_tree_area_holder",
),
id = u"note_tree_area",
)