witten
/
luminotes
Archived
1
0
Fork 0

Some refactoring of the new link resolving and launching code, because, well,

it was just plain broken:

 * Setting link hrefs is no longer done in quite so many places to prevent
   conflicts. Still could be more centralized though.
 * Editor is no longer responsible for tracking note titles. It now issues
   signals for title changes, and Wiki takes care of tracking titles for all
   open editors.
 * A few places in Editor weren't making use of the new link_title()
   convenience function. Now they are.
 * They way Wiki was associating link pulldowns with their links was
   completely broken, because Javascript Arrays can't use DOM objects as keys.
   At least not if you want them to work. Now just setting a "pulldown" member
   on each link node directly.
 * Moved some of the "if you click a link and the target editor is already
   open, just highlight it" logic out of Editor and into Wiki. (Both
   load_note() and resolve_link(), unfortunately.)
 * Made Link_pulldown.title_field_changed just rely on resolve_link() instead
   of doing all the link resolving itself.
This commit is contained in:
Dan Helfman 2007-08-16 01:29:18 +00:00
parent e87eee87c8
commit 3424e6ad12
2 changed files with 87 additions and 95 deletions

View File

@ -1,5 +1,3 @@
note_titles = {} // map from note title to the open editor for that note
function Editor( id, notebook_id, note_text, deleted_from, revisions_list, insert_after_iframe_id, read_write, startup, highlight, focus ) {
this.id = id;
this.notebook_id = notebook_id;
@ -246,24 +244,6 @@ Editor.prototype.resize = function () {
setElementDimensions( this.iframe, dimensions );
}
Editor.prototype.resolve_link = function ( link ) {
// in case the link is to ourself, first grab the most recent version of our title
this.scrape_title();
var id;
var title = link_title( link );
var editor = note_titles[ title ];
// if the link's title corresponds to an open note id, set that as the link's destination
if ( editor ) {
id = editor.id;
link.href = "/notebooks/" + this.notebook_id + "?note_id=" + id;
// otherwise, resolve the link by looking up the link's title on the server
} else {
signal( this, "resolve_link", title, link );
return;
}
}
Editor.prototype.key_pressed = function ( event ) {
signal( this, "key_pressed", this, event );
@ -304,22 +284,10 @@ Editor.prototype.mouse_clicked = function ( event ) {
event.stop();
// if the note corresponding to the link's id or title is already open, highlight it
// load the note corresponding to the clicked link
var query = parse_query( link );
var title = link_title( link, query );
var id = query.note_id;
var iframe = getElement( "note_" + id );
if ( iframe ) {
iframe.editor.highlight();
return;
}
var editor = note_titles[ title ];
if ( editor ) {
editor.highlight();
return;
}
// otherwise, load the note for that id
signal( this, "load_editor", title, this.iframe.id, id, null, link );
}
@ -329,13 +297,9 @@ Editor.prototype.scrape_title = function () {
if ( !heading ) return;
var title = scrapeText( heading );
// delete the previous title (if any) from the note_titles map
if ( this.title )
delete note_titles[ this.title ];
// record the new title in note_titles
// issue a signal that the title has changed and save off the new title
signal( this, "title_changed", this, this.title, title );
this.title = title;
note_titles[ this.title ] = this;
}
Editor.prototype.focused = function () {
@ -353,6 +317,13 @@ Editor.prototype.empty = function () {
return ( scrapeText( this.document.body ).length == 0 );
}
Editor.prototype.contents = function () {
if ( !this.document.body )
return ""
return scrapeText( this.document.body );
}
Editor.prototype.start_link = function () {
// get the current selection, which is the link title
if ( this.iframe.contentWindow && this.iframe.contentWindow.getSelection ) { // browsers such as Firefox
@ -405,7 +376,7 @@ Editor.prototype.start_link = function () {
} else {
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
var link = this.find_link_at_cursor();
signal( this, "resolve_link", strip( scrapeText( link ) ), link );
signal( this, "resolve_link", link_title( link ), link );
}
} else if ( this.document.selection ) { // browsers such as IE
var range = this.document.selection.createRange();
@ -420,7 +391,7 @@ Editor.prototype.start_link = function () {
} else {
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
var link = this.find_link_at_cursor();
signal( this, "resolve_link", strip( scrapeText( link ) ), link );
signal( this, "resolve_link", link_title( link ), link );
}
}
}
@ -448,9 +419,7 @@ Editor.prototype.end_link = function () {
range.pasteHTML( "" );
}
var query = parse_query( link );
var link_title = query.title || strip( scrapeText( link ) );
signal( this, "resolve_link", link_title, link );
signal( this, "resolve_link", link_title( link ), link );
}
Editor.prototype.find_link_at_cursor = function () {
@ -545,9 +514,7 @@ Editor.prototype.contents = function () {
}
Editor.prototype.shutdown = function( event ) {
if ( this.title )
delete note_titles[ this.title ];
signal( this, "title_changed", this, this.title, null );
var iframe = this.iframe;
var note_controls = this.note_controls;
disconnectAll( this );

View File

@ -5,8 +5,8 @@ function Wiki() {
this.notebook = null;
this.notebook_id = getElement( "notebook_id" ).value;
this.read_write = false;
this.startup_notes = new Array(); // map of startup notes: note id to bool
this.link_pulldowns = new Array(); // map of link pulldowns: link object to pulldown
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.invoker = new Invoker();
connect( this.invoker, "error_message", this, "display_error" );
@ -175,11 +175,10 @@ Wiki.prototype.create_blank_editor = function ( event ) {
}
Wiki.prototype.load_editor = function ( note_title, from_iframe_id, note_id, revision, link ) {
var self = this;
// if a link is given with an open link pulldown, then ignore the note title given and use the
// one from the pulldown instead
var pulldown = this.link_pulldowns[ link ];
var pulldown = link.pulldown;
var pulldown_title = undefined;
if ( pulldown ) {
pulldown_title = strip( pulldown.title_field.value );
if ( pulldown_title )
@ -188,7 +187,27 @@ Wiki.prototype.load_editor = function ( note_title, from_iframe_id, note_id, rev
pulldown.title_field.value = note_title;
}
// if the note corresponding to the link's id is already open, highlight it and bail, but only if
// we didn't pull a title from an open link pulldown
if ( !pulldown_title ) {
var iframe = getElement( "note_" + note_id );
if ( iframe ) {
iframe.editor.highlight();
link.href = "/notebooks/" + this.notebook_id + "?note_id=" + note_id;
return;
}
}
// if the note corresponding to the link's title is already open, highlight it and bail
var editor = this.open_editors[ note_title ];
if ( editor ) {
editor.highlight();
link.href = "/notebooks/" + this.notebook_id + "?note_id=" + editor.id;
return;
}
// if there's not a valid destination note id, then load by title instead of by id
var self = this;
if ( note_id == "new" || note_id == "null" ) {
this.invoker.invoke(
"/notebooks/load_note_by_title", "GET", {
@ -211,25 +230,43 @@ Wiki.prototype.load_editor = function ( note_title, from_iframe_id, note_id, rev
);
}
Wiki.prototype.resolve_link = function ( note_title, link ) {
// if the link already has an id, then the link is already resolved so we can just bail
if ( link.href ) {
var id = parse_query( link ).note_id;
if ( id != "new" && id != "null" )
return;
}
Wiki.prototype.resolve_link = function ( note_title, link, callback ) {
var id = parse_query( link ).note_id;
if ( !id ) return;
// if the link already has a valid-looking id, it's already resolved, so bail
if ( !callback && id != "new" && id != "null" )
return;
if ( note_title.length == 0 )
return;
// if the note corresponding to the link's title is already open, resolve the link and bail
var editor = this.open_editors[ note_title ];
if ( editor ) {
link.href = "/notebooks/" + this.notebook_id + "?note_id=" + editor.id;
if ( callback )
callback( editor.contents() );
return;
}
var self = this;
this.invoker.invoke(
"/notebooks/lookup_note_id", "GET", {
"/notebooks/" + ( callback ? "load_note_by_title" : "lookup_note_id" ), "GET", {
"notebook_id": this.notebook_id,
"note_title": note_title
},
function ( result ) {
link.href = "/notebooks/" + self.notebook_id + "?note_id=" + result.note_id;
if ( result && ( result.note || result.note_id ) ) {
link.href = "/notebooks/" + self.notebook_id + "?note_id=" + ( result.note ? result.note.object_id : result.note_id );
} else {
link.href = "/notebooks/" + self.notebook_id + "?" + queryString(
[ "title", "note_id" ],
[ note_title, "null" ]
);
}
if ( callback )
callback( ( result && result.note ) ? result.note.contents : null );
}
);
}
@ -275,16 +312,6 @@ Wiki.prototype.create_editor = function ( id, note_text, deleted_from, revisions
}
}
// update any matching links in from_iframe_id with the id of this new editor
if ( from_iframe_id ) {
var links = getElementsByTagAndClassName( "a", null, getElement( from_iframe_id ).editor.document );
for ( var i in links ) {
// a link matches if its contained text is the same as this note's title
if ( link_title( links[ i ] ) == note_title )
links[ i ].href = "/notebooks/" + this.notebook_id + "?note_id=" + id;
}
}
// for read-only notes within read-write notebooks, tack the revision timestamp onto the start of the note text
if ( !read_write && this.read_write && revisions_list && revisions_list.length ) {
var short_revision = this.brief_revision( revisions_list[ revisions_list.length - 1 ] );
@ -296,6 +323,7 @@ Wiki.prototype.create_editor = function ( id, note_text, deleted_from, revisions
if ( this.read_write ) {
connect( editor, "state_changed", this, "editor_state_changed" );
connect( editor, "title_changed", this, "editor_title_changed" );
connect( editor, "key_pressed", this, "editor_key_pressed" );
connect( editor, "delete_clicked", function ( event ) { self.delete_editor( event, editor ) } );
connect( editor, "undelete_clicked", function ( event ) { self.undelete_editor_via_trash( event, editor ) } );
@ -319,6 +347,13 @@ Wiki.prototype.editor_state_changed = function ( editor ) {
this.display_link_pulldown( editor );
}
Wiki.prototype.editor_title_changed = function ( editor, old_title, new_title ) {
delete this.open_editors[ old_title ];
if ( new_title != null )
this.open_editors[ new_title ] = editor;
}
Wiki.prototype.display_link_pulldown = function ( editor ) {
var link = editor.find_link_at_cursor();
@ -327,7 +362,7 @@ Wiki.prototype.display_link_pulldown = function ( editor ) {
return;
}
var pulldown = this.link_pulldowns[ link ];
var pulldown = link.pulldown;
if ( pulldown )
pulldown.update_position();
@ -876,7 +911,7 @@ Changes_pulldown.prototype.shutdown = function () {
function Link_pulldown( wiki, notebook_id, invoker, editor, link ) {
wiki.link_pulldowns[ link ] = this;
link.pulldown = this;
this.link = link;
Pulldown.call( this, wiki, notebook_id, "link_" + editor.id, link, editor.iframe );
@ -910,8 +945,8 @@ function Link_pulldown( wiki, notebook_id, invoker, editor, link ) {
// so, display its title and a preview of its contents
var iframe = getElement( "note_" + id );
if ( iframe ) {
self.title_field.value = iframe.editor.title;
self.display_preview( iframe.editor.title, iframe.editor.document );
this.title_field.value = iframe.editor.title;
this.display_preview( iframe.editor.title, iframe.editor.document );
return;
}
@ -938,6 +973,11 @@ Link_pulldown.prototype = Pulldown;
Link_pulldown.prototype.constructor = Link_pulldown;
Link_pulldown.prototype.display_preview = function ( title, contents ) {
if ( !contents ) {
replaceChildNodes( this.note_preview, "empty note" );
return;
}
// if contents is a DOM node, just scrape its text
if ( contents.nodeType ) {
contents = strip( scrapeText( contents ) );
@ -970,29 +1010,14 @@ Link_pulldown.prototype.title_field_changed = function ( event ) {
if ( this.title_field.value == this.previous_title )
return;
var self = this;
replaceChildNodes( this.note_preview, "" );
var title = strip( this.title_field.value );
this.previous_title = title;
this.invoker.invoke(
"/notebooks/load_note_by_title", "GET", {
"notebook_id": this.notebook_id,
"note_title": title
},
function ( result ) {
if ( result.note ) {
self.link.href = "/notebooks/" + self.notebook_id + "?note_id=" + result.note.object_id;
self.display_preview( result.note.title, result.note.contents );
} else {
self.link.href = "/notebooks/" + self.notebook_id + "?" + queryString(
[ "title", "note_id" ],
[ title, "null" ]
);
replaceChildNodes( self.note_preview, "empty note" );
}
}
);
var self = this;
this.wiki.resolve_link( title, this.link, function ( contents ) {
self.display_preview( title, contents );
} );
}
Link_pulldown.prototype.title_field_key_pressed = function ( event ) {
@ -1013,5 +1038,5 @@ Link_pulldown.prototype.shutdown = function () {
disconnectAll( this.title_field );
if ( this.link )
delete this.wiki.link_pulldowns[ this.link ];
this.link.pulldown = null;
}