witten
/
luminotes
Archived
1
0
Fork 0
This repository has been archived on 2023-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
luminotes/static/js/Wiki.js

5542 lines
187 KiB
JavaScript
Raw Normal View History

IMAGE_DIR = "/static/images/";
NOTEBOOK_READ_ONLY = 0;
NOTEBOOK_READ_WRITE = 1;
NOTEBOOK_READ_WRITE_FOR_OWN_NOTES = 2;
function Wiki( invoker ) {
this.next_id = null;
this.focused_editor = null;
this.notebook = evalJSON( getElement( "notebook" ).value );
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: lowercase note title to editor
this.search_results_editor = null; // editor for display of search results
this.invoker = invoker;
this.user = evalJSON( getElement( "user" ).value );
this.rate_plan = evalJSON( getElement( "rate_plan" ).value );
this.yearly = evalJSON( getElement( "yearly" ).value );
this.storage_usage_high = false;
this.invites = evalJSON( getElement( "invites" ).value );
this.invite_id = getElement( "invite_id" ).value;
this.after_login = getElement( "after_login" ).value;
this.signup_plan = getElement( "signup_plan" ).value;
this.groups = evalJSON( getElement( "groups" ).value );
this.font_size = null;
this.small_toolbar = false;
this.theme = "default";
this.large_toolbar_bottom = 0;
2008-10-30 22:26:27 +00:00
this.autosaver = null;
var total_notes_count_node = getElement( "total_notes_count" );
if ( total_notes_count_node )
this.total_notes_count = parseInt( scrapeText( total_notes_count_node ) );
else
this.total_notes_count = null;
2008-10-27 23:23:27 +00:00
if ( getElement( "note_tree_root_table" ) )
this.note_tree = new Note_tree( this, this.notebook.object_id, this.invoker );
this.recent_notes = new Recent_notes( this, this.notebook.object_id, this.invoker );
this.notebooks = evalJSON( getElement( "notebooks" ).value );
this.notebooks_by_id = {};
for ( var i in this.notebooks ) {
var notebook = this.notebooks[ i ];
if ( !this.notebooks_by_id[ notebook.object_id ] )
this.notebooks_by_id[ notebook.object_id ] = notebook;
}
if ( this.notebook && this.notebook.read_write != NOTEBOOK_READ_ONLY ) {
var unsupported_agent = null;
var beta_agent = null;
if ( OPERA )
unsupported_agent = "Opera";
2009-01-27 23:54:11 +00:00
else if ( MSIE6 )
unsupported_agent = "Microsoft Internet Explorer version 6";
if ( unsupported_agent )
this.display_message( "Luminotes does not currently support the " + unsupported_agent + " web browser for editing. If possible, please use a recent version of Firefox, Internet Explorer, Chrome, or Safari instead. Sorry for the inconvenience." );
else if ( beta_agent )
this.display_message( "Luminotes support for your web browser (" + beta_agent + ") is currently in beta. If you encounter any problems, please contact support so that they can be fixed!" );
}
if ( !this.notebook_has_tag( this.notebook, "forum" ) )
2008-10-30 22:26:27 +00:00
this.autosaver = Autosaver( this );
var deleted_id = getElement( "deleted_id" ).value;
var skip_empty_message = deleted_id ? true : false;
// populate the wiki with startup notes
this.populate(
evalJSON( getElement( "startup_notes" ).value || "null" ),
evalJSON( getElement( "current_notes" ).value || "null" ),
evalJSON( getElement( "note_read_write" ).value || "true" ),
skip_empty_message
);
this.display_storage_usage( this.user.storage_bytes || "0" );
connect( this.invoker, "error_message", this, "display_error" );
connect( this.invoker, "message", this, "display_message" );
connect( "search_form", "onsubmit", this, "search" );
connect( "search_text", "onfocus", this, "search_focused" );
connect( "search_text", "onblur", this, "search_blurred" );
connect( "search_text", "onkeyup", this, "search_key_released" );
connect( "html", "onclick", this, "background_clicked" );
connect( "html", "onkeydown", this, "key_pressed" );
2009-01-22 21:05:18 +00:00
connect( window, "onresize", this, "resize_editor" );
connect( window, "onresize", this, "resize_toolbar" );
connect( document, "onmouseover", this, "detect_font_resize" );
var blank_note_stub = getElement( "blank_note_stub" );
if ( blank_note_stub ) {
connect( blank_note_stub, "onmouseover", function ( event ) {
addElementClass( blank_note_stub, "blank_note_stub_border" );
removeElementClass( blank_note_stub, "blank_note_stub_hidden_border" );
} );
connect( blank_note_stub, "onmouseout", function ( event ) {
addElementClass( blank_note_stub, "blank_note_stub_hidden_border" );
removeElementClass( blank_note_stub, "blank_note_stub_border" );
} );
connect( blank_note_stub, "onclick", this, "create_blank_editor" );
}
var self = this;
var top_window = window;
var logout_link = getElement( "logout_link" );
if ( logout_link ) {
connect( "logout_link", "onclick", function ( event ) {
self.save_editor( null, false, function () {
top_window.location = "/users/logout";
} );
event.stop();
} );
}
var rename = evalJSON( getElement( "rename" ).value );
if ( rename && this.notebook.read_write == NOTEBOOK_READ_WRITE )
this.start_notebook_rename();
// if a notebook was just deleted, show a message with an undo button
if ( deleted_id && this.notebook.read_write == NOTEBOOK_READ_WRITE ) {
var undo_button = createDOM( "input", {
"type": "button",
"class": "message_button",
"value": "undo",
"title": "undo deletion"
} );
var trash_link = createDOM( "a", {
"href": "/notebooks/" + this.notebook.trash_id + "?parent_id=" + this.notebook.object_id
}, "trash" );
var message_div = this.display_message( "The notebook has been moved to the", [ trash_link, ". ", undo_button ], "notes_top" );
connect( undo_button, "onclick", function ( event ) { self.undelete_notebook( event, deleted_id ); } );
}
var current_notebook_up = getElement( "current_notebook_up" );
if ( current_notebook_up ) {
connect( current_notebook_up, "onmouseover", function ( event ) { current_notebook_up.src = IMAGE_DIR + "up_arrow_hover.png"; } );
connect( current_notebook_up, "onmouseout", function ( event ) { current_notebook_up.src = IMAGE_DIR + "up_arrow.png"; } );
connect( current_notebook_up, "onclick", function ( event ) {
current_notebook_up.src = IMAGE_DIR + "up_arrow.png";
self.move_current_notebook_up( event );
} );
}
var current_notebook_down = getElement( "current_notebook_down" );
if ( current_notebook_down ) {
connect( current_notebook_down, "onmouseover", function ( event ) { current_notebook_down.src = IMAGE_DIR + "down_arrow_hover.png"; } );
connect( current_notebook_down, "onmouseout", function ( event ) { current_notebook_down.src = IMAGE_DIR + "down_arrow.png"; } );
connect( current_notebook_down, "onclick", function ( event ) {
current_notebook_down.src = IMAGE_DIR + "down_arrow.png";
self.move_current_notebook_down( event );
} );
}
this.resize_toolbar();
}
Wiki.prototype.update_next_id = function ( result ) {
this.next_id = result.next_id;
}
var KILOBYTE = 1024;
var MEGABYTE = 1024 * KILOBYTE;
function bytes_to_megabytes( bytes, choose_units ) {
if ( choose_units ) {
if ( bytes < KILOBYTE )
return bytes + " bytes";
if ( bytes < MEGABYTE )
return Math.round( bytes / KILOBYTE ) + " KB";
}
return Math.round( bytes / MEGABYTE ) + " MB";
}
Wiki.prototype.display_storage_usage = function( storage_bytes ) {
if ( !storage_bytes )
return;
// display the user's current storage usage
var quota_bytes = this.rate_plan.storage_quota_bytes;
if ( !quota_bytes )
return;
var usage_percent = Math.round( storage_bytes / quota_bytes * 100.0 );
2007-09-20 23:30:09 +00:00
if ( usage_percent > 90 ) {
var storage_usage_class = "storage_usage_high";
if ( this.storage_usage_high == false )
this.display_message(
"You are currently using " +
usage_percent +
"% of your available storage space. Please delete some notes or files, empty the trash, or",
[ createDOM( "a", { "href": "/upgrade" }, "upgrade" ), " your account." ]
);
this.storage_usage_high = true;
} else if ( usage_percent > 75 ) {
var storage_usage_class = "storage_usage_medium";
this.storage_usage_high = false;
} else {
var storage_usage_class = "storage_usage_low";
this.storage_usage_high = false;
}
var storage_usage_area = getElement( "storage_usage_area" );
if ( !storage_usage_area )
return;
replaceChildNodes(
storage_usage_area,
createDOM( "div", { "class": storage_usage_class },
bytes_to_megabytes( storage_bytes ) + " (" + usage_percent + "%) of " + bytes_to_megabytes( quota_bytes ) )
);
}
Wiki.prototype.populate = function ( startup_notes, current_notes, note_read_write, skip_empty_message ) {
var self = this;
// if this is the trash and the user has owner-level access, then display a list of all deleted notebooks
if ( this.notebook.owner && this.notebook.name == "trash" ) {
var heading_shown = false;
var deleted_notebooks = getElement( "deleted_notebooks" );
for ( var i in this.notebooks ) {
var notebook = this.notebooks[ i ];
if ( !notebook.deleted )
continue;
if ( !heading_shown ) {
appendChildNodes( deleted_notebooks, createDOM( "h4", {}, "deleted notebooks" ) );
heading_shown = true;
}
delete_button = createDOM( "input", {
"type": "button",
"class": "note_button",
"id": "delete_notebook_" + notebook.object_id,
"value": "delete forever",
"title": "delete notebook"
} );
function connect_delete( notebook_id ) {
connect( delete_button, "onclick", function ( event ) { self.delete_notebook_forever( event, notebook_id ); } );
}
connect_delete( notebook.object_id );
undelete_button = createDOM( "input", {
"type": "button",
"class": "note_button",
"id": "undelete_notebook_" + notebook.object_id,
"value": "undelete",
"title": "undelete notebook"
} );
function connect_undelete( notebook_id ) {
connect( undelete_button, "onclick", function ( event ) { self.undelete_notebook( event, notebook_id ); } );
}
connect_undelete( notebook.object_id );
appendChildNodes( deleted_notebooks, createDOM( "div",
{ "id": "deleted_notebook_" + notebook.object_id, "class": "deleted_notebook_item" },
createDOM( "span", {}, delete_button ),
createDOM( "span", {}, undelete_button ),
createDOM( "span", {}, notebook.name )
) );
}
}
// create an editor for each startup note in the received notebook, focusing the first one
var focus = true;
for ( var i in startup_notes ) {
var startup_note = startup_notes[ i ];
this.startup_notes[ startup_note.object_id ] = true;
// don't actually create an editor if a particular list of notes was provided in the result
if ( current_notes.length == 0 ) {
var static_note = getElement( "static_note_" + startup_note.object_id );
if ( !static_note ) continue;
var static_contents = getFirstElementByTagAndClassName( "span", "static_note_contents", static_note );
if ( !static_contents ) continue;
var contents_text = static_contents.innerHTML;
var editor = this.create_editor(
startup_note.object_id,
// grab this note's contents from the static notes area
contents_text,
startup_note.deleted_from_id,
startup_note.revision,
startup_note.creation,
this.notebook.read_write, false, focus, null,
startup_note.user_id,
startup_note.username
);
if ( startup_note.title )
this.open_editors[ startup_note.title.toLowerCase() ] = editor;
focus = false;
}
}
// if particular notes were provided, then display editors for them
var focus = true;
for ( var i in current_notes ) {
var note = current_notes[ i ];
2008-10-30 22:26:27 +00:00
if ( !note_read_write )
var read_write = NOTEBOOK_READ_ONLY;
else
var read_write = this.notebook.read_write;
var static_note = getElement( "static_note_" + note.object_id );
if ( !static_note ) continue;
var static_contents = getFirstElementByTagAndClassName( "span", "static_note_contents", static_note );
if ( !static_contents ) continue;
var contents_text = static_contents.innerHTML;
this.create_editor(
note.object_id,
contents_text,
note.deleted_from_id,
note.revision,
note.creation,
2008-10-30 22:26:27 +00:00
read_write, false, focus, null,
note.user_id,
note.username
);
focus = false;
}
if ( startup_notes.length == 0 && current_notes.length == 0 && !skip_empty_message )
this.display_empty_message();
var empty_trash_link = getElement( "empty_trash_link" );
if ( empty_trash_link )
connect( empty_trash_link, "onclick", function ( event ) { self.delete_all_editors( event ); } );
if ( this.notebook.read_write != NOTEBOOK_READ_ONLY ) {
connect( window, "onunload", function ( event ) { self.editor_focused( null, true ); } );
2008-10-30 22:26:27 +00:00
connect( "newNote", "onclick", this, "create_blank_editor" );
connect( "createLink", "onclick", this, "toggle_link_button" );
2008-10-27 23:23:27 +00:00
if ( this.notebook.read_write == NOTEBOOK_READ_WRITE )
connect( "attachFile", "onclick", this, "toggle_attach_button" );
connect( "bold", "onclick", function ( event ) { self.toggle_button( event, "bold" ); } );
connect( "italic", "onclick", function ( event ) { self.toggle_button( event, "italic" ); } );
connect( "underline", "onclick", function ( event ) { self.toggle_button( event, "underline" ); } );
2008-05-14 00:07:02 +00:00
connect( "strikethrough", "onclick", function ( event ) { self.toggle_button( event, "strikethrough" ); } );
connect( "color", "onclick", this, "toggle_color_button" );
connect( "font", "onclick", this, "toggle_font_button" );
connect( "title", "onclick", function ( event ) { self.toggle_button( event, "title" ); } );
connect( "insertUnorderedList", "onclick", function ( event ) { self.toggle_button( event, "insertUnorderedList" ); } );
connect( "insertOrderedList", "onclick", function ( event ) { self.toggle_button( event, "insertOrderedList" ); } );
this.make_image_button( "newNote" );
this.make_image_button( "createLink" );
2008-10-27 23:23:27 +00:00
if ( this.notebook.read_write == NOTEBOOK_READ_WRITE )
this.make_image_button( "attachFile" );
this.make_image_button( "bold" );
this.make_image_button( "italic" );
this.make_image_button( "underline" );
2008-05-14 00:07:02 +00:00
this.make_image_button( "strikethrough" );
this.make_image_button( "color" );
this.make_image_button( "font" );
this.make_image_button( "title" );
this.make_image_button( "insertUnorderedList" );
this.make_image_button( "insertOrderedList" );
// grab the next available object id
this.invoker.invoke( "/next_id", "POST", null,
function( result ) { self.update_next_id( result ); }
);
}
var save_button = getElement( "save_button" );
if ( save_button ) {
connect( save_button, "onclick", function ( event ) {
self.save_editor( null );
} );
save_button.disabled = true;
}
var export_link = getElement( "export_link" );
if ( export_link ) {
connect( export_link, "onclick", function ( event ) {
self.save_editor( null );
self.export_clicked();
event.stop();
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
} );
}
var import_link = getElement( "import_link" );
if ( import_link ) {
connect( import_link, "onclick", function ( event ) {
self.import_clicked();
event.stop();
} );
}
var rename_notebook_link = getElement( "rename_notebook_link" );
if ( rename_notebook_link ) {
connect( rename_notebook_link, "onclick", function ( event ) {
self.start_notebook_rename();
event.stop();
} );
}
var notebook_header_name = getElement( "notebook_header_name" );
if ( notebook_header_name ) {
connect( notebook_header_name, "onclick", function ( event ) {
self.start_notebook_rename();
event.stop();
} );
}
var delete_notebook_link = getElement( "delete_notebook_link" );
if ( delete_notebook_link ) {
connect( delete_notebook_link, "onclick", function ( event ) {
self.delete_notebook();
event.stop();
} );
}
var share_notebook_link = getElement( "share_notebook_link" );
if ( share_notebook_link ) {
connect( share_notebook_link, "onclick", function ( event ) {
self.load_editor( "share this notebook", "null", null, null, null, getElement( "notes_top" ) );
event.stop();
} );
}
var print_notebook_link = getElement( "print_notebook_link" );
if ( print_notebook_link ) {
connect( print_notebook_link, "onclick", function ( event ) {
self.editor_focused( null, true );
} );
}
var settings_link = getElement( "settings_link" );
if ( settings_link ) {
connect( settings_link, "onclick", function ( event ) {
self.load_editor( "account settings", "null", null, null, null, getElement( "notes_top" ) );
event.stop();
} );
}
var declutter_link = getElement( "declutter_link" );
if ( declutter_link ) {
connect( declutter_link, "onclick", function ( event ) {
self.declutter_clicked();
event.stop();
} );
}
var new_notebook_button = getElement( "new_notebook_button" );
if ( new_notebook_button ) {
connect( new_notebook_button, "onclick", function ( event ) {
self.invoker.invoke( "/notebooks/create", "POST" );
event.stop();
} );
}
var new_note_tree_link_button = getElement( "new_note_tree_link_button" );
if ( new_note_tree_link_button ) {
connect( new_note_tree_link_button, "onclick", function ( event ) {
self.clear_pulldowns();
if ( self.note_tree )
self.note_tree.start_link_add();
event.stop();
} );
}
}
Wiki.prototype.background_clicked = function ( event ) {
2009-02-06 23:01:46 +00:00
if ( !event.target().tagName )
return;
var tag_name = event.target().tagName.toLowerCase();
if ( tag_name == "input" || tag_name == "label" )
return;
this.clear_pulldowns();
}
Wiki.prototype.create_blank_editor = function ( event ) {
if ( event ) event.stop();
2008-10-30 22:26:27 +00:00
if ( this.notebook.read_write == NOTEBOOK_READ_WRITE_FOR_OWN_NOTES &&
( !this.user.username || this.user.username == "anonymous" ) ) {
this.display_message( 'Please login first. No account? Click "sign up" to get a free account.' );
2008-10-30 22:26:27 +00:00
return;
}
this.clear_messages();
this.clear_pulldowns();
// if we're within the trash, don't allow new note creation
if ( this.notebook.name == "trash" ) {
this.display_error( "You can't create notes in the trash." );
return;
}
// if there is already a blank editor, then highlight it and bail
if ( Editor.shared_iframe && Editor.shared_iframe.editor() && Editor.shared_iframe.editor().empty() ) {
Editor.shared_iframe.editor().highlight();
return;
}
var editor = this.create_editor( undefined, undefined, undefined, undefined, undefined, this.notebook.read_write, true, true, null, this.user.object_id, this.user.username );
this.increment_total_notes_count();
signal( this, "note_added", editor );
}
Wiki.prototype.load_editor = function ( note_title, note_id, revision, previous_revision, link, position_after ) {
if ( this.notebook.name == "trash" && !revision ) {
this.display_message( "If you'd like to use this note, try undeleting it first.", undefined, position_after );
return;
}
// if a link is given with an open link pulldown, then ignore the note title given and use the
// one from the pulldown instead
if ( link ) {
var pulldown = link.pulldown;
var pulldown_title = undefined;
if ( pulldown && pulldown.title_field ) {
pulldown_title = strip( pulldown.title_field.value );
if ( pulldown_title )
note_title = pulldown_title;
// only use the pulldown title if it has changed from the note's original title
if ( pulldown_title == note_title )
pulldown_title = undefined;
}
if ( link.target )
link.removeAttribute( "target" );
}
// 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 editor = editor_by_id( note_id, revision );
if ( editor ) {
editor.highlight();
if ( link )
link.href = "/notebooks/" + this.notebook.object_id + "?note_id=" + note_id;
return;
}
}
// if there's not a valid destination note id, then load by title instead of by id
var self = this;
if ( pulldown_title || note_id == undefined || note_id == "new" || note_id == "null" ) {
var lower_note_title = note_title.toLowerCase();
// if the note_title corresponds to a "magic" note's title, then dynamically highlight or create the note
if ( lower_note_title == "search results" ) {
var editor = this.open_editors[ lower_note_title ];
if ( editor ) {
editor.highlight();
return;
}
this.display_search_results();
return;
}
if ( lower_note_title == "share this notebook" ) {
var editor = this.open_editors[ lower_note_title ];
if ( editor ) {
editor.highlight();
return;
}
this.share_notebook();
return;
}
if ( lower_note_title == "account settings" ) {
var editor = this.open_editors[ lower_note_title ];
if ( editor ) {
editor.highlight();
return;
}
this.display_settings();
return;
}
// but if the note corresponding to the link's title is already open, highlight it and bail
if ( !revision ) {
var editor = this.open_editors[ lower_note_title ];
if ( editor ) {
editor.highlight();
if ( link )
link.href = "/notebooks/" + this.notebook.object_id + "?note_id=" + editor.id;
return;
}
}
// if the notebook is a forum, then instead of opening a new post, display an error message
if ( this.notebook_has_tag( this.notebook, "forum" ) ) {
2008-10-30 22:26:27 +00:00
this.display_message( "No such forum post! (A forum link must point to another post in this discussion or an external web page.)" );
return;
}
this.invoker.invoke(
"/notebooks/load_note_by_title", "GET", {
"notebook_id": this.notebook.object_id,
"note_title": note_title,
"revision": revision
},
function ( result ) { self.parse_loaded_editor( result, note_title, revision, link, position_after ); }
);
return;
}
// if the notebook is a forum, maintain displayed note order by opening an existing note on its own page
if ( this.notebook_has_tag( this.notebook, "forum" ) ) {
2008-10-30 22:26:27 +00:00
window.location = window.location.protocol + '//' + window.location.host + window.location.pathname + '?note_id=' + note_id;
return;
}
this.invoker.invoke(
"/notebooks/load_note", "GET", {
"notebook_id": this.notebook.object_id,
"note_id": note_id,
"revision": revision,
"previous_revision": previous_revision
},
function ( result ) { self.parse_loaded_editor( result, note_title, revision, link, position_after ); }
);
}
Wiki.prototype.resolve_link = function ( note_title, link, force, callback ) {
// if the title looks like a URL, then make it a link to an external site
if ( /^\w+:\/\//.test( note_title ) || /^mailto:/.test( note_title ) )
var title_looks_like_url = true;
else
var title_looks_like_url = false;
if ( link && link.target )
link.removeAttribute( "target" );
if ( note_title == "search results" || note_title == "share this notebook" || note_title == "account settings" ) {
link.href = "/notebooks/" + this.notebook.object_id + "?" + queryString(
[ "title", "note_id" ],
[ note_title, "null" ]
);
if ( callback ) {
if ( note_title == "search results" )
callback( "current search results" );
else if ( note_title == "share this notebook" )
callback( "share this notebook with others" );
else
callback( "account settings" );
}
return;
}
var id = parse_query( link ).note_id;
// if the link already has a valid-looking id, it's already resolved, so bail
if ( !force && id != undefined && id != "new" && id != "null" ) {
if ( callback )
callback( 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.toLowerCase() ];
if ( editor ) {
if ( link )
link.href = "/notebooks/" + this.notebook.object_id + "?note_id=" + editor.id;
if ( callback )
callback( editor.summarize() );
return;
}
var self = this;
if ( callback ) {
this.invoker.invoke(
"/notebooks/load_note_by_title", "GET", {
"notebook_id": this.notebook.object_id,
"note_title": note_title,
"summarize": true
},
function ( result ) {
if ( result && result.note ) {
link.href = "/notebooks/" + self.notebook.object_id + "?note_id=" + result.note.object_id;
} else if ( title_looks_like_url ) {
link.target = "_new";
link.href = note_title;
callback( "web link" );
return;
} else {
link.href = "/notebooks/" + self.notebook.object_id + "?" + queryString(
[ "title", "note_id" ],
[ note_title, "null" ]
);
}
callback( ( result && result.note ) ? result.note.summary : null );
}
);
return;
}
this.invoker.invoke(
"/notebooks/lookup_note_id", "GET", {
"notebook_id": this.notebook.object_id,
"note_title": note_title
},
function ( result ) {
if ( result && result.note_id ) {
link.href = "/notebooks/" + self.notebook.object_id + "?note_id=" + result.note_id;
} else if ( title_looks_like_url ) {
link.target = "_new";
link.href = note_title;
} else {
link.href = "/notebooks/" + self.notebook.object_id + "?" + queryString(
[ "title", "note_id" ],
[ note_title, "null" ]
);
}
}
);
}
Wiki.prototype.parse_loaded_editor = function ( result, note_title, requested_revision, link, position_after ) {
if ( result.note_id_in_trash ) {
var undelete_button = createDOM( "input", {
"type": "button",
"class": "message_button",
"value": "undelete",
"title": "undelete note"
} );
var trash_link = createDOM( "a", {
"href": "/notebooks/" + this.notebook.trash_id + "?parent_id=" + this.notebook.object_id
}, "trash" );
var message_div = this.display_message( "That note is in the", [ trash_link, ". ", undelete_button ], position_after )
var self = this;
connect( undelete_button, "onclick", function ( event ) { self.undelete_editor_via_undelete( event, result.note_id_in_trash, message_div ); } );
return;
}
if ( result.note ) {
var id = result.note.object_id;
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
if ( requested_revision )
id += " " + requested_revision;
var actual_revision = result.note.revision;
var actual_creation = result.note.creation;
var note_text = result.note.contents;
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
var deleted_from_id = result.note.deleted;
var user_id = result.note.user_id;
var username = result.note.username;
} else {
// if the title looks like a URL, then make it a link to an external site
if ( /^\w+:\/\//.test( note_title ) || /^mailto:/.test( note_title ) ) {
link.target = "_new";
link.href = note_title;
window.open( link.href );
return;
}
var id = null;
var note_text = "<h3>" + note_title;
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
var deleted_from_id = null;
var actual_revision = null;
var actual_creation = null;
var user_id = null;
var username = null;
this.increment_total_notes_count();
}
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
if ( requested_revision )
var read_write = false; // show previous revisions as read-only
else
var read_write = this.notebook.read_write;
var self = this;
2009-01-12 22:49:45 +00:00
var editor = this.create_editor( id, note_text, deleted_from_id, actual_revision, actual_creation, read_write, true, true, position_after, user_id, username );
if ( !requested_revision )
connect( editor, "init_complete", function () { signal( self, "note_added", editor ); } );
id = editor.id;
// if a link that launched this editor was provided, update it with the created note's id
if ( link && id )
link.href = "/notebooks/" + this.notebook.object_id + "?note_id=" + id;
}
Wiki.prototype.create_editor = function ( id, note_text, deleted_from_id, revision, creation, read_write, highlight, focus, position_after, user_id, username ) {
var self = this;
var dirty = false;
2008-10-27 23:34:12 +00:00
var own_notes_only = false;
if ( read_write == NOTEBOOK_READ_ONLY )
read_write = false;
else if ( read_write == NOTEBOOK_READ_WRITE )
read_write = true;
else if ( read_write == NOTEBOOK_READ_WRITE_FOR_OWN_NOTES ) {
2008-10-27 23:23:27 +00:00
own_notes_only = true;
if ( user_id == this.user.object_id && this.user.username && this.user.username != "anonymous" )
read_write = true;
else
read_write = false;
}
if ( isUndefinedOrNull( id ) ) {
if ( this.notebook.read_write ) {
id = this.next_id;
dirty = true;
this.invoker.invoke( "/next_id", "POST", null,
function( result ) { self.update_next_id( result ); }
);
} else {
id = 0;
}
}
// for read-only notes within read-write notebooks, tack the revision timestamp onto the start of the note text
if ( !read_write && this.notebook.read_write == NOTEBOOK_READ_WRITE && revision ) {
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
var short_revision = this.brief_revision( revision );
2008-07-11 21:41:48 +00:00
var note_id = id.split( ' ' )[ 0 ];
note_text = '<p>Previous revision from ' + short_revision + '</p>' +
'<form id="revert_form" target="/notebooks/revert_note">' +
'<input type="hidden" name="notebook_id" value="' + this.notebook.object_id + '">' +
2008-07-11 21:41:48 +00:00
'<input type="hidden" name="note_id" value="' + note_id + '">' +
'<input type="hidden" name="revision" value="' + revision + '">' +
2008-07-12 00:12:52 +00:00
'<input type="submit" class="button" value="revert to this revision" title="Roll back to this earlier version of the note.">' +
2008-07-11 21:41:48 +00:00
'</form>' + note_text;
}
var startup = this.startup_notes[ id ];
var editor = new Editor( id, this.notebook.object_id, note_text, deleted_from_id, revision, read_write, startup, highlight, focus, position_after, dirty, own_notes_only );
2009-01-07 00:20:04 +00:00
if ( focus )
this.editor_focused( editor );
else if ( !read_write )
this.editor_focused( null );
if ( creation && note_text != "<h3></h3>" ) {
var note_id = id.split( ' ' )[ 0 ];
appendChildNodes( editor.holder, this.make_byline( username, creation, note_id ) );
}
if ( this.notebook.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 ) } );
connect( editor, "changes_clicked", function ( event ) { self.toggle_editor_changes( event, editor ) } );
2009-03-03 03:39:02 +00:00
connect( editor, "tools_clicked", function ( event ) { self.toggle_editor_tools( event, editor ) } );
connect( editor, "focused", this, "editor_focused" );
connect( editor, "mouse_hovered", function ( target ) { self.editor_mouse_hovered( editor, target ) } );
connect( editor, "grabber_pressed", function ( event ) { self.editor_focused( null, false, false ); } );
connect( editor, "moved", function ( editor, position_after, position_before ) {
self.editor_moved( editor, position_after, position_before );
} );
}
connect( editor, "load_editor", this, "load_editor" );
connect( editor, "hide_clicked", function ( event ) { self.hide_editor( event, editor ) } );
connect( editor, "submit_form", function ( form ) { self.submit_form( form ); } );
connect( editor, "button_clicked", function ( editor, button ) { self.editor_button_clicked( editor, button ); } );
this.clear_pulldowns();
return editor;
}
2009-01-22 21:05:18 +00:00
Wiki.prototype.resize_editor = function () {
if ( Editor.shared_iframe && Editor.shared_iframe.editor() )
Editor.shared_iframe.editor().resize();
}
Wiki.prototype.resize_toolbar = function () {
this.clear_pulldowns();
var last_toolbar_button = getElement( "insertOrderedList" );
var current_toolbar_bottom = getElementPosition( last_toolbar_button ).y + getElementDimensions( last_toolbar_button ).h;
var viewport_size = getViewportDimensions();
var VIEWPORT_WIDTH_THRESHOLD = 1000;
// if the toolbar is large and the bottom of the toolbar is outside of the viewport or the
// viewport is too narrow, then make the toolbar smaller
if ( !this.small_toolbar && ( current_toolbar_bottom > viewport_size.h || viewport_size.w < VIEWPORT_WIDTH_THRESHOLD ) ) {
this.large_toolbar_bottom = current_toolbar_bottom;
this.small_toolbar = true;
this.update_toolbar();
// otherwise, if the toolbar is small and making the toolbar large would still fit within the
// viewport and the viewport is wide, then make the toolbar large again
} else if ( this.small_toolbar && this.large_toolbar_bottom <= viewport_size.h && viewport_size.w >= VIEWPORT_WIDTH_THRESHOLD ) {
if ( !this.small_toolbar ) return; // it's already big, so bail
this.small_toolbar = false;
this.update_toolbar();
}
}
Wiki.prototype.detect_font_resize = function () {
if ( !window.getComputedStyle ) return;
var style = window.getComputedStyle( getElement( "content" ), null );
if ( !style ) return;
if ( style.fontSize == this.font_size )
return;
this.font_size = style.fontSize;
2009-01-22 21:05:18 +00:00
this.resize_editor();
}
Wiki.prototype.editor_state_changed = function ( editor, link_clicked ) {
this.update_toolbar();
if ( !link_clicked )
this.display_link_pulldown( editor );
2008-05-13 22:52:20 +00:00
if ( editor.dirty() ) {
var save_button = getElement( "save_button" );
if ( save_button && save_button.disabled ) {
save_button.disabled = false;
save_button.value = "save";
}
}
2008-05-13 22:52:20 +00:00
signal( this, "note_state_changed", editor );
}
Wiki.prototype.editor_title_changed = function ( editor, old_title, new_title ) {
if ( old_title )
delete this.open_editors[ old_title.toLowerCase() ];
if ( new_title != null && !editor.empty() ) {
if ( new_title )
this.open_editors[ new_title.toLowerCase() ] = editor;
signal( this, "note_renamed", editor, new_title );
}
}
Wiki.prototype.display_link_pulldown = function ( editor, link, ephemeral ) {
this.clear_messages();
if ( !editor.read_write ) {
this.clear_pulldowns();
return;
}
if ( !link )
link = editor.find_link_at_cursor();
// if there's no link at the current cursor location, bail
if ( !link ) {
this.clear_pulldowns();
return;
}
var pulldown = link.pulldown;
var query = parse_query( link );
var title = link_title( link, query );
// display a Suggest_pulldown once something is typed for the link title, as long as the link
// doesn't yet have a note_id
if ( !pulldown && title.length > 0 && query.note_id == "new" ) {
this.clear_pulldowns();
var self = this;
var suggest_pulldown = new Suggest_pulldown( this, this.notebook.object_id, this.invoker, link, editor.iframe, title, editor.document );
connect( suggest_pulldown, "suggestion_selected", function ( note ) {
self.update_link_with_suggestion( editor, link, note )
} );
return;
}
// if there is a link but it was just started, bail
if ( link == editor.link_started && !pulldown ) {
this.clear_pulldowns();
return;
}
if ( pulldown ) {
// if a Suggest_pulldown is open for the link, update the pulldown and bail
if ( pulldown.update_suggestions ) {
pulldown.update_suggestions( title );
return;
// otherwise, just update the pulldown's position
} else {
pulldown.update_position();
}
}
var link_contains_image = getElementsByTagAndClassName( "img", null, link );
// if the cursor is now on a link, display a link pulldown if there isn't already one open
if ( link_title( link ).length > 0 || link_contains_image ) {
if ( !pulldown ) {
this.clear_pulldowns();
// display a different pulldown depending on whether the link is a note link or a file link
if ( link.target || !/\/files\//.test( link.href ) )
new Link_pulldown( this, this.notebook.object_id, this.invoker, editor, link, ephemeral );
else {
if ( /\/files\/new$/.test( link.href ) )
new Upload_pulldown( this, this.notebook.object_id, this.invoker, editor, link, null );
else
new File_link_pulldown( this, this.notebook.object_id, this.invoker, editor, link, ephemeral );
}
}
}
}
Wiki.prototype.update_link_with_suggestion = function ( editor, link, note ) {
link.innerHTML = note.title;
// manually position the text cursor at the end of the link title
editor.position_cursor_after( link );
link.href = "/notebooks/" + this.notebook.object_id + "?note_id=" + note.object_id;
link.pulldown.shutdown();
link.pulldown = null;
editor.focus();
editor.end_link();
this.display_link_pulldown( editor, link );
}
Wiki.prototype.editor_focused = function ( editor, synchronous, remove_empty, save_blurred ) {
if ( remove_empty == undefined )
remove_empty = true;
if ( save_blurred == undefined )
save_blurred = true;
if ( this.focused_editor && this.focused_editor != editor ) {
this.focused_editor.blur();
this.clear_pulldowns();
// if there is no focused editor anymore, release the iframe of the previously focused editor
if ( editor == null )
this.focused_editor.release_iframe();
// 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.empty() && remove_empty ) {
signal( this, "note_removed", this.focused_editor.id );
this.focused_editor.shutdown();
this.decrement_total_notes_count();
this.display_empty_message();
} else if ( save_blurred ) {
// when switching editors, save the one being left
this.save_editor( null, null, null, synchronous );
}
}
this.focused_editor = editor;
this.update_toolbar();
}
Wiki.prototype.editor_moved = function ( editor, position_after, position_before ) {
this.save_editor( editor, false, null, null, null, position_after, position_before );
if ( this.note_tree )
this.note_tree.move_link( editor, position_after, position_before );
// reset the revision for each open editor. this is because the server is updating the revisions
// on the server while reordering the ntoes. and we don't want to have a stale idea of what the
// current revision is for a given editor
var divs = getElementsByTagAndClassName( "div", "static_note_div" );
for ( var i in divs ) {
var editor = divs[ i ].editor;
editor.revision = null;
editor.user_revisions = new Array();
}
}
Wiki.prototype.make_byline = function ( username, creation, note_id ) {
if ( username == "anonymous" )
username = "admin";
if ( username )
var by = ' by ' + username;
else
var by = '';
if ( creation )
var timestamp = ' on ' + this.brief_revision( creation );
else
var timestamp = '';
return createDOM(
"span",
{ "class": "byline small_text" },
'Posted' + by + timestamp + ' | ',
createDOM( "a", {
"href": window.location.pathname + '?note_id=' + note_id,
"target": "_top"
}, "permalink" )
);
}
Wiki.prototype.editor_mouse_hovered = function ( editor, target ) {
var pulldowns = getElementsByTagAndClassName( "div", "pulldown" );
// if the mouse is hovering over a link, and no pulldowns are open, open a link pulldown
if ( target.nodeName == "A" && pulldowns.length == 0 )
this.display_link_pulldown( editor, target, true );
// the mouse is hovering over something else, so clear all ephemeral pulldowns
else
this.clear_pulldowns( true );
}
Wiki.prototype.key_pressed = function ( event ) {
if ( this.notebook.read_write == NOTEBOOK_READ_ONLY )
return;
var code = event.key().code;
if ( event.modifier().ctrl && !event.modifier().alt ) {
// ctrl-m: make a new note
if ( code == 77 ) {
this.create_blank_editor( event );
// ctrl-slash: start a search
} else if ( code == 191 ) {
var search_text = getElement( "search_text" );
if ( search_text )
search_text.focus();
// ctrl-space: save the current editor
} else if ( code == 32 ) {
this.save_editor();
}
return;
}
// page up: previous note
if ( code == 33 ) {
event.stop();
this.focus_previous_editor();
// page down: next note
} else if ( code == 34 ) {
event.stop();
this.focus_next_editor();
}
}
Wiki.prototype.editor_key_pressed = function ( editor, event ) {
var code = event.key().code;
if ( event.modifier().ctrl && !event.modifier().alt ) {
// ctrl-backtick: message with frame HTML contents (for debugging)
if ( code == 192 || code == 96 ) {
this.display_message( editor.contents() );
event.stop();
// ctrl-b: bold
} else if ( code == 66 ) {
this.toggle_button( event, "bold" );
// ctrl-i: italic
} else if ( code == 73 ) {
this.toggle_button( event, "italic" );
// ctrl-u: underline
} else if ( code == 85 ) {
this.toggle_button( event, "underline" );
2008-05-14 00:07:02 +00:00
// ctrl-s: strikethrough
} else if ( code == 83 ) {
this.toggle_button( event, "strikethrough" );
// ctrl-period: unordered list
} else if ( code == 190 ) {
this.toggle_button( event, "insertUnorderedList" );
// ctrl-1: ordered list
} else if ( code == 49 ) {
this.toggle_button( event, "insertOrderedList" );
// ctrl-l: link
} else if ( code == 76 ) {
this.toggle_link_button( event );
// ctrl-m: make a new note
} else if ( code == 77 ) {
this.create_blank_editor( event );
// ctrl-h: hide note
} else if ( code == 72 ) {
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
if ( !editor.deleted_from_id )
2007-09-05 18:57:50 +00:00
this.hide_editor( event );
// ctrl-d: delete note
} else if ( code == 68 ) {
this.delete_editor( event );
// ctrl-slash: start a search
} else if ( code == 191 ) {
var search_text = getElement( "search_text" );
if ( search_text )
search_text.focus();
// ctrl-space: save the current editor
} else if ( code == 32 ) {
this.save_editor();
}
// shift-tab: outdent
} else if ( event.modifier().shift && code == 9 ) {
// ignore shift-tab here if a Suggest_pulldown is open
var link = editor.find_link_at_cursor();
if ( link && link.pulldown && link.pulldown.visible && link.pulldown.visible() )
return;
editor.exec_command( "outdent" );
event.stop();
// tab: outdent
} else if ( code == 9 ) {
// ignore tab here if a Suggest_pulldown is open
var link = editor.find_link_at_cursor();
if ( link && link.pulldown && link.pulldown.visible && link.pulldown.visible() )
return;
editor.exec_command( "indent" );
event.stop();
// page up: previous note
} else if ( code == 33 ) {
event.stop();
this.focus_previous_editor();
// page down: next note
} else if ( code == 34 ) {
event.stop();
this.focus_next_editor();
// IE: hitting space while making a link shouldn't end the link
} else if ( code == 32 && editor.document.selection && editor.state_enabled( "a" ) ) {
var range = editor.document.selection.createRange();
range.text = " ";
event.stop();
// IE: hitting backspace while making a link shouldn't end the link
} else if ( code == 8 && editor.document.selection ) {
var range = editor.document.selection.createRange();
range.moveStart( "character", -1 );
if ( range.text != "" ) {
range.text = "";
event.stop();
}
}
}
Wiki.prototype.focus_previous_editor = function () {
if ( !this.focused_editor ) {
var div = getFirstElementByTagAndClassName( "div", "static_note_div" );
if ( !div || !div.editor ) return;
div.editor.highlight();
return;
}
var previous_editor = this.focused_editor.previous_editor();
if ( !previous_editor ) return;
this.editor_focused( null );
previous_editor.highlight();
}
Wiki.prototype.focus_next_editor = function () {
if ( !this.focused_editor ) {
var div = getFirstElementByTagAndClassName( "div", "static_note_div" );
if ( !div || !div.editor ) return;
div.editor.highlight();
return;
}
var next_editor = this.focused_editor.next_editor();
if ( !next_editor ) return;
this.editor_focused( null );
next_editor.highlight();
}
Wiki.prototype.resize_toolbar_button = function ( button ) {
var SMALL_BUTTON_SIZE = 20;
var LARGE_BUTTON_SIZE = 40;
var button_size = getElementDimensions( button );
2009-04-24 00:46:06 +00:00
var offsets = this.button_offsets();
if ( this.small_toolbar || button.always_small ) {
if ( button_size.w == SMALL_BUTTON_SIZE ) return false;
2009-04-24 00:46:06 +00:00
setElementDimensions( button.parentNode, { "w": SMALL_BUTTON_SIZE, "h": SMALL_BUTTON_SIZE } );
setElementDimensions( button, { "w": SMALL_BUTTON_SIZE, "h": SMALL_BUTTON_SIZE } );
2009-04-24 00:46:06 +00:00
addElementClass( button.parentNode, "button_background_small" );
addElementClass( button, "image_button_small" );
addElementClass( button, button.name + "_small" );
removeElementClass( button, button.name + "_large" );
} else {
if ( button_size.w == LARGE_BUTTON_SIZE ) return false;
2009-04-24 00:46:06 +00:00
setElementDimensions( button.parentNode, { "w": LARGE_BUTTON_SIZE, "h": LARGE_BUTTON_SIZE } );
setElementDimensions( button, { "w": LARGE_BUTTON_SIZE, "h": LARGE_BUTTON_SIZE } );
2009-04-24 00:46:06 +00:00
removeElementClass( button.parentNode, "button_background_small" );
removeElementClass( button, "image_button_small" );
addElementClass( button, button.name + "_large" );
removeElementClass( button, button.name + "_small" );
}
return true;
}
Wiki.prototype.make_image_button = function ( name, always_small ) {
var button = getElement( name );
button.name = name;
button.always_small = always_small;
this.resize_toolbar_button( button );
this.connect_image_button( button );
}
2009-04-24 00:46:06 +00:00
var LARGE_BUTTON_OFFSETS = {
"UP": "40px 0px",
"HOVER_UP": "80px 0px",
"DOWN": "120px 0px",
"HOVER_DOWN": "160px 0px",
"DOWN_FG_OFFSET": 2
};
var SMALL_BUTTON_OFFSETS = {
"UP": "20px 0px",
"HOVER_UP": "40px 0px",
"DOWN": "60px 0px",
"HOVER_DOWN": "80px 0px",
"DOWN_FG_OFFSET": 1
};
Wiki.prototype.button_offsets = function () {
return this.small_toolbar ? SMALL_BUTTON_OFFSETS : LARGE_BUTTON_OFFSETS;
}
Wiki.prototype.connect_image_button = function ( button ) {
var self = this;
connect( button, "onmouseover", function ( event ) {
2009-04-24 00:46:06 +00:00
var offsets = self.button_offsets();
var bg_pos = getStyle( button.parentNode, "background-position" );
2009-04-24 00:46:06 +00:00
if ( bg_pos == offsets.DOWN || bg_pos == offsets.HOVER_DOWN ) {
setStyle( button.parentNode, { "background-position": offsets.HOVER_DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.HOVER_UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
}
} );
connect( button, "onmouseout", function ( event ) {
2009-04-24 00:46:06 +00:00
var offsets = self.button_offsets();
var bg_pos = getStyle( button.parentNode, "background-position" );
2009-04-24 00:46:06 +00:00
if ( bg_pos == offsets.DOWN || bg_pos == offsets.HOVER_DOWN ) {
setStyle( button.parentNode, { "background-position": offsets.DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
}
} );
function stateless_button( button ) {
return ( button.name == "newNote" );
}
connect( button, "onmousedown", function ( event ) {
event.stop(); // prevents button outline from being shown
// bail if there is no focused editor on which to act
if ( !self.focused_editor && !stateless_button( button ) )
return;
2009-04-24 00:46:06 +00:00
var offsets = self.button_offsets();
var bg_pos = getStyle( button.parentNode, "background-position" );
2009-04-24 00:46:06 +00:00
if ( bg_pos == offsets.HOVER_UP || bg_pos == offsets.HOVER_DOWN ) {
setStyle( button.parentNode, { "background-position": offsets.HOVER_DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
}
} );
if ( stateless_button( button ) ) {
connect( button, "onmouseup", function ( event ) {
2009-04-24 00:46:06 +00:00
var offsets = self.button_offsets();
var bg_pos = getStyle( button.parentNode, "background-position" );
2009-04-24 00:46:06 +00:00
if ( bg_pos == offsets.HOVER_UP || bg_pos == offsets.HOVER_DOWN ) {
setStyle( button.parentNode, { "background-position": offsets.HOVER_UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
}
} );
}
}
Wiki.prototype.down_image_button = function ( name ) {
var button = getElement( name );
if ( !button )
2008-10-27 23:23:27 +00:00
return;
2009-04-24 00:46:06 +00:00
var offsets = this.button_offsets();
var bg_pos = getStyle( button.parentNode, "background-position" );
2009-04-24 00:46:06 +00:00
var resized = this.resize_toolbar_button( button );
2009-04-24 00:46:06 +00:00
if ( !resized && ( bg_pos == offsets.DOWN || bg_pos == offsets.HOVER_DOWN ) )
return;
2009-04-24 00:46:06 +00:00
offsets = this.button_offsets();
2009-04-24 00:46:06 +00:00
if ( !resized && ( bg_pos == offsets.HOVER_UP || bg_pos == offsets.HOVER_DOWN ) ) {
setStyle( button.parentNode, { "background-position": offsets.HOVER_DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
}
}
Wiki.prototype.up_image_button = function ( name ) {
var button = getElement( name );
if ( !button )
2008-10-27 23:23:27 +00:00
return;
2009-04-24 00:46:06 +00:00
var offsets = this.button_offsets();
var bg_pos = getStyle( button.parentNode, "background-position" );
2009-04-24 00:46:06 +00:00
var resized = this.resize_toolbar_button( button );
2009-04-24 00:46:06 +00:00
if ( !resized && ( bg_pos == offsets.UP || bg_pos == offsets.HOVER_UP ) )
return;
2009-04-24 00:46:06 +00:00
offsets = this.button_offsets();
2009-04-24 00:46:06 +00:00
if ( !resized && ( bg_pos == offsets.HOVER_UP || bg_pos == offsets.HOVER_DOWN ) ) {
setStyle( button.parentNode, { "background-position": offsets.HOVER_UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
}
}
Wiki.prototype.toggle_image_button = function ( name ) {
var button = getElement( name );
if ( !button )
2008-10-27 23:23:27 +00:00
return;
2009-04-24 00:46:06 +00:00
var offsets = this.button_offsets();
var bg_pos = getStyle( button.parentNode, "background-position" );
2009-04-24 00:46:06 +00:00
if ( bg_pos == offsets.DOWN || bg_pos == offsets.HOVER_DOWN ) {
if ( bg_pos == offsets.HOVER_DOWN ) {
setStyle( button.parentNode, { "background-position": offsets.HOVER_UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.UP } );
setElementPosition( button, { "x": 0, "y": 0 } );
}
this.resize_toolbar_button( button );
return false;
} else {
2009-04-24 00:46:06 +00:00
if ( bg_pos == offsets.HOVER_UP ) {
setStyle( button.parentNode, { "background-position": offsets.HOVER_DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
} else {
2009-04-24 00:46:06 +00:00
setStyle( button.parentNode, { "background-position": offsets.DOWN } );
setElementPosition( button, { "x": offsets.DOWN_FG_OFFSET, "y": offsets.DOWN_FG_OFFSET } );
}
this.resize_toolbar_button( button );
return true;
}
}
Wiki.prototype.toggle_button = function ( event, button_id ) {
this.clear_messages();
this.clear_pulldowns();
if ( this.focused_editor && this.focused_editor.read_write ) {
this.focused_editor.focus();
if ( button_id == "title" )
this.focused_editor.exec_command( "h3" );
else
this.focused_editor.exec_command( button_id );
this.focused_editor.resize();
this.toggle_image_button( button_id );
}
event.stop();
}
Wiki.prototype.update_button = function ( button_id, state_name, node_names ) {
if ( state_name && node_names && this.focused_editor.state_enabled( state_name, node_names ) ) {
this.down_image_button( button_id );
return 1;
}
this.up_image_button( button_id );
return 0;
}
Wiki.prototype.update_toolbar = function() {
var node_names = null;
var link = null;
// a read-only notebook doesn't have a visible toolbar
if ( this.notebook.read_write == NOTEBOOK_READ_ONLY )
return;
if ( this.focused_editor ) {
node_names = this.focused_editor.current_node_names();
link = this.focused_editor.find_link_at_cursor();
}
var enabled = 0;
this.update_button( "newNote" );
enabled += this.update_button( "bold", "b", node_names );
enabled += this.update_button( "italic", "i", node_names );
enabled += this.update_button( "underline", "u", node_names );
enabled += this.update_button( "strikethrough", "strike", node_names );
enabled += this.update_button( "color", "color", node_names );
enabled += this.update_button( "font", "fontface", node_names );
enabled += this.update_button( "title", "h3", node_names );
enabled += this.update_button( "insertUnorderedList", "ul", node_names );
enabled += this.update_button( "insertOrderedList", "ol", node_names );
if ( this.focused_editor && enabled == 0 )
this.focused_editor.cleanup_range();
if ( link ) {
// determine whether the link is a note link or a file link
if ( link.target || !/\/files\//.test( link.href ) ) {
this.down_image_button( "createLink" );
this.up_image_button( "attachFile" );
} else {
this.up_image_button( "createLink" );
this.down_image_button( "attachFile" );
}
} else {
this.up_image_button( "createLink" );
this.up_image_button( "attachFile" );
}
}
Wiki.prototype.toggle_link_button = function ( event ) {
this.clear_messages();
this.clear_pulldowns();
var link = null;
if ( this.focused_editor && this.focused_editor.read_write ) {
this.focused_editor.focus();
if ( this.toggle_image_button( "createLink" ) )
link = this.focused_editor.start_link();
else
link = this.focused_editor.end_link();
if ( link && link.parentNode != null ) {
var self = this;
this.resolve_link( link_title( link ), link, false, function ( summary ) {
self.display_link_pulldown( self.focused_editor, link );
} );
} else {
this.display_link_pulldown( this.focused_editor );
}
}
event.stop();
}
Wiki.prototype.toggle_attach_button = function ( event ) {
if ( this.focused_editor && this.focused_editor.read_write ) {
this.focused_editor.focus();
if ( this.toggle_image_button( "attachFile" ) )
var link = this.focused_editor.start_file_link();
else
var link = this.focused_editor.end_link();
// if a pulldown is already open, then just close it
var pulldown_id = "upload_" + this.focused_editor.id;
var existing_div = getElement( pulldown_id );
if ( !existing_div ) {
pulldown_id = "file_link_" + this.focused_editor.id;
existing_div = getElement( pulldown_id );
}
if ( existing_div ) {
existing_div.pulldown.shutdown();
existing_div.pulldown = null;
return;
}
this.clear_messages();
this.clear_pulldowns();
new Upload_pulldown( this, this.notebook.object_id, this.invoker, this.focused_editor, link, null );
}
event.stop();
}
Wiki.prototype.toggle_color_button = function ( event ) {
if ( this.focused_editor && this.focused_editor.read_write ) {
this.focused_editor.focus();
var existing_div = getElement( "color_pulldown" );
if ( existing_div ) {
if ( hasElementClass( existing_div, "invisible" ) ) {
this.down_image_button( "color" );
existing_div.pulldown.show();
} else {
this.up_image_button( "color" );
existing_div.pulldown.hide();
}
return;
}
this.clear_messages();
this.clear_pulldowns();
this.down_image_button( "color" );
new Color_pulldown( this, this.notebook.object_id, this.invoker, event.target(), this.focused_editor );
}
event.stop();
}
Wiki.prototype.toggle_font_button = function ( event ) {
if ( this.focused_editor && this.focused_editor.read_write ) {
this.focused_editor.focus();
// if a pulldown is already open, then just close it
var existing_div = getElement( "font_pulldown" );
if ( existing_div ) {
this.up_image_button( "font" );
existing_div.pulldown.shutdown();
existing_div.pulldown = null;
return;
}
this.down_image_button( "font" );
this.clear_messages();
this.clear_pulldowns();
new Font_pulldown( this, this.notebook.object_id, this.invoker, event.target(), this.focused_editor );
}
event.stop();
}
Wiki.prototype.hide_editor = function ( event, editor ) {
this.clear_messages();
this.clear_pulldowns();
if ( this.focused_editor )
this.editor_focused( null, false, true, false );
if ( !editor ) {
editor = this.focused_editor;
this.focused_editor = null;
}
if ( editor ) {
var id = editor.id;
// if the editor to hide is completely empty, then simply remove it
if ( editor.empty() ) {
signal( this, "note_removed", editor.id );
editor.shutdown();
this.decrement_total_notes_count();
this.display_empty_message();
} else {
// before hiding an editor, save it
if ( this.notebook.read_write != NOTEBOOK_READ_ONLY && editor.read_write ) {
var self = this;
this.save_editor( editor, false, function () {
editor.shutdown();
self.display_empty_message();
} );
} else {
editor.shutdown();
this.display_empty_message();
}
}
}
event.stop();
}
Wiki.prototype.delete_editor = function ( event, editor ) {
this.clear_messages();
this.clear_pulldowns();
if ( this.focused_editor )
this.editor_focused( null, false, true, false );
if ( !editor ) {
editor = this.focused_editor;
this.focused_editor = null;
}
if ( !editor ) {
event.stop();
return;
}
if ( this.startup_notes[ editor.id ] )
delete this.startup_notes[ editor.id ];
var self = this;
this.save_editor( editor, false, function () {
if ( self.notebook.read_write != NOTEBOOK_READ_ONLY && editor.read_write ) {
self.invoker.invoke( "/notebooks/delete_note", "POST", {
"notebook_id": self.notebook.object_id,
"note_id": editor.id
}, function ( result ) { self.display_storage_usage( result.storage_bytes ); } );
}
if ( editor == self.focused_editor )
self.focused_editor = null;
if ( self.notebook.trash_id && !editor.empty() ) {
var undo_button = createDOM( "input", {
"type": "button",
"class": "message_button",
"value": "undo",
"title": "undo deletion"
} );
var trash_link = createDOM( "a", {
"href": "/notebooks/" + self.notebook.trash_id + "?parent_id=" + self.notebook.object_id
}, "trash" );
var message_div = self.display_message( "The note has been moved to the", [ trash_link, ". ", undo_button ], editor.holder );
connect( undo_button, "onclick", function ( event ) { self.undelete_editor_via_undo( event, editor, message_div ); } );
}
signal( self, "note_removed", editor.id );
editor.shutdown();
self.decrement_total_notes_count();
self.display_empty_message();
}, false, true );
event.stop();
}
Wiki.prototype.undelete_editor_via_trash = function ( event, editor ) {
this.clear_messages();
this.clear_pulldowns();
if ( !editor ) {
editor = this.focused_editor;
this.focused_editor = null;
}
if ( editor ) {
if ( this.startup_notes[ editor.id ] )
delete this.startup_notes[ editor.id ];
if ( this.notebook.read_write != NOTEBOOK_READ_ONLY && editor.read_write ) {
var self = this;
this.invoker.invoke( "/notebooks/undelete_note", "POST", {
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
"notebook_id": editor.deleted_from_id,
"note_id": editor.id
}, function ( result ) { self.display_storage_usage( result.storage_bytes ); } );
}
if ( editor == this.focused_editor )
this.focused_editor = null;
signal( this, "note_removed", editor.id );
editor.shutdown();
this.decrement_total_notes_count();
this.display_empty_message();
}
event.stop();
}
Wiki.prototype.undelete_editor_via_undo = function( event, editor, position_after ) {
if ( editor ) {
if ( this.notebook.read_write != NOTEBOOK_READ_ONLY && editor.read_write ) {
var self = this;
this.invoker.invoke( "/notebooks/undelete_note", "POST", {
"notebook_id": this.notebook.object_id,
"note_id": editor.id
}, function ( result ) {
self.display_storage_usage( result.storage_bytes );
self.clear_messages();
self.clear_pulldowns();
self.startup_notes[ editor.id ] = true;
self.increment_total_notes_count();
self.load_editor( "Note not found.", editor.id, null, null, null, position_after );
} );
}
}
event.stop();
}
2007-11-09 06:54:45 +00:00
Wiki.prototype.undelete_editor_via_undelete = function( event, note_id, position_after ) {
if ( this.notebook.read_write != NOTEBOOK_READ_ONLY ) {
var self = this;
this.invoker.invoke( "/notebooks/undelete_note", "POST", {
"notebook_id": this.notebook.object_id,
"note_id": note_id
}, function ( result ) {
self.display_storage_usage( result.storage_bytes );
self.clear_messages();
self.clear_pulldowns();
self.startup_notes[ note_id ] = true;
self.increment_total_notes_count();
self.load_editor( "Note not found.", note_id, null, null, null, position_after );
} );
}
event.stop();
}
Wiki.prototype.undelete_notebook = function( event, notebook_id ) {
this.invoker.invoke( "/notebooks/undelete", "POST", {
2007-11-17 04:31:19 +00:00
"notebook_id": notebook_id
} );
event.stop();
}
Wiki.prototype.compare_versions = function( event, editor, previous_revision ) {
this.clear_pulldowns();
// display a diff between the two revisions for examination by the user
this.load_editor( editor.title, editor.id, editor.revision, previous_revision, editor.closed ? null : editor.holder );
}
Wiki.prototype.save_editor = function ( editor, fire_and_forget, callback, synchronous, suppress_save_signal, position_after, position_before ) {
if ( !editor )
editor = this.focused_editor;
var self = this;
if ( editor && editor.read_write && !editor.closed &&
( ( !editor.empty() && editor.dirty() ) || position_after || position_before ) ) {
editor.scrape_title();
this.invoker.invoke( "/notebooks/save_note", "POST", {
"notebook_id": this.notebook.object_id,
"note_id": editor.id,
"contents": editor.contents(),
"startup": editor.startup,
"previous_revision": editor.revision ? editor.revision : "None",
"position_after": position_after ? position_after.id : "None",
"position_before": position_before ? position_before.id : "None"
}, function ( result ) {
self.update_editor_revisions( result, editor );
self.display_storage_usage( result.storage_bytes );
editor.mark_clean();
var save_button = getElement( "save_button" );
if ( save_button && self.focused_editor && !self.focused_editor.dirty() ) {
save_button.disabled = true;
save_button.value = "saved";
}
if ( editor.startup )
self.startup_notes[ editor.id ] = true;
else if ( self.startup_notes[ editor.id ] )
delete self.startup_notes[ editor.id ];
// special case to rename a forum notebook when its first note is renamed
2008-11-18 06:59:57 +00:00
if ( result.rank == 0 && self.notebook_has_tag( self.notebook, "forum" ) )
2008-10-30 22:26:27 +00:00
self.end_notebook_rename( editor.title, true );
if ( callback )
callback();
if ( !suppress_save_signal )
signal( self, "note_saved", editor );
}, null, synchronous, fire_and_forget );
} else {
var save_button = getElement( "save_button" );
if ( save_button && this.focused_editor && !this.focused_editor.dirty() ) {
save_button.disabled = true;
save_button.value = "saved";
}
if ( callback )
callback();
}
}
Wiki.prototype.update_editor_revisions = function ( result, editor ) {
// if there's not a newly saved revision, then the contents are unchanged, so bail
if ( !result.new_revision )
return;
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
var client_previous_revision = editor.revision;
editor.revision = result.new_revision.revision;
// if the server's idea of the previous revision doesn't match the client's, then someone has
// gone behind our back and saved the editor's note from another window
if ( result.previous_revision && client_previous_revision &&
result.previous_revision.revision != client_previous_revision ) {
var compare_button = createDOM( "input", {
"type": "button",
"class": "message_button",
"value": "compare versions",
"title": "compare your version with the modified version"
} );
this.display_error(
'Your changes to the note titled "' + editor.title +
'" have overwritten changes made in another window by ' + ( result.previous_revision.username || 'you' ) + '.',
[ compare_button ], editor.holder
);
var self = this;
connect( compare_button, "onclick", function ( event ) {
self.compare_versions( event, editor, result.previous_revision.revision );
} );
if ( !editor.user_revisions || editor.user_revisions.length == 0 )
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
return;
editor.user_revisions.push( result.previous_revision );
}
// add the new revision to the editor's revisions list
if ( !editor.user_revisions || editor.user_revisions.length == 0 )
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
return;
editor.user_revisions.push( result.new_revision );
}
Wiki.prototype.submit_form = function ( form ) {
this.clear_messages();
this.clear_pulldowns();
var self = this;
var args = {}
var url = form.getAttribute( "target" );
var callback = null;
if ( url == "/users/signup" ) {
args[ "invite_id" ] = this.invite_id;
args[ "rate_plan" ] = this.signup_plan;
args[ "yearly" ] = this.yearly;
} else if ( url == "/users/login" ) {
args[ "invite_id" ] = this.invite_id;
args[ "after_login" ] = this.after_login;
} else if ( url == "/users/send_invites" ) {
callback = function ( result ) {
if ( !result.invites ) return;
self.invites = result.invites;
self.share_notebook();
}
} else if ( url == "/users/update_settings" ) {
callback = function ( result ) {
self.user.email_address = result.email_address || "";
self.display_message( "Your account settings have been updated." );
}
} else if ( url == "/users/signup_group_member" ) {
callback = function ( result ) {
var group_id = getFirstElementByTagAndClassName( "input", "group_id", form ).value;
self.invoker.invoke( "/groups/load_users", "GET", {
"group_id": group_id
}, function ( result ) {
self.display_group_settings( result );
} );
}
2008-07-11 21:41:48 +00:00
} else if ( url == "/notebooks/revert_note" ) {
callback = function ( result ) {
var editor = editor_by_id( form.note_id.value );
2008-07-11 21:41:48 +00:00
if ( editor ) {
2008-07-11 21:41:48 +00:00
self.update_editor_revisions( result, editor );
editor.mark_clean();
if ( result.new_revision ) {
if ( editor.document && editor.document.body )
editor.document.body.innerHTML = result.contents;
else if ( editor.div )
editor.div.innerHTML = result.contents;
2008-07-11 21:41:48 +00:00
editor.resize();
2008-07-12 00:12:52 +00:00
editor.scrape_title();
2008-07-11 21:41:48 +00:00
}
editor.highlight();
2008-07-11 21:41:48 +00:00
signal( self, "note_saved", editor );
}
if ( result.new_revision )
self.display_message( "The note has been reverted to an earlier revision.", [],
editor && editor.holder || null );
else
self.display_message( "The note is already at that revision.", [],
editor && editor.holder || null );
2008-07-11 21:41:48 +00:00
self.display_storage_usage( result.storage_bytes );
}
}
this.invoker.invoke( url, "POST", args, callback, form );
}
Wiki.prototype.editor_button_clicked = function ( editor, button ) {
this.clear_messages();
this.clear_pulldowns();
var self = this;
if ( hasElementClass( button, "revoke_button" ) ) {
var invite_id = button.id.split( "_" ).pop();
this.invoker.invoke( "/users/revoke_invite", "POST", {
"notebook_id": this.notebook.object_id,
"invite_id": invite_id
}, function ( result ) {
if ( !result.invites ) return;
self.invites = result.invites;
self.share_notebook();
} );
} else if ( hasElementClass( button, "admin_button" ) ) {
var group_id = button.id.split( "_" ).pop();
this.invoker.invoke( "/groups/load_users", "GET", {
"group_id": group_id
}, function ( result ) {
self.display_group_settings( result );
} );
} else if ( hasElementClass( button, "remove_user_button" ) ) {
var id_pieces = button.id.split( "_" );
var group_id = id_pieces.pop();
var user_id = id_pieces.pop();
this.invoker.invoke( "/users/remove_group", "POST", {
"user_id_to_remove": user_id,
"group_id": group_id
}, function ( result ) {
self.invoker.invoke( "/groups/load_users", "GET", {
"group_id": group_id
}, function ( result ) {
self.display_group_settings( result );
} );
} );
}
}
Wiki.prototype.search = function ( event ) {
this.clear_messages();
this.clear_pulldowns();
var self = this;
this.invoker.invoke( "/notebooks/search", "GET", {
"notebook_id": this.notebook.object_id
},
function( result ) { self.display_search_results( result ); },
"search_form"
);
event.stop();
}
Wiki.prototype.search_focused = function ( event ) {
var search_text = getElement( "search_text" );
if ( search_text.value == 'search' )
search_text.value = '';
}
Wiki.prototype.search_blurred = function ( event ) {
var search_text = getElement( "search_text" );
if ( search_text.value == '' )
search_text.value = 'search';
}
Wiki.prototype.search_key_released = function ( event ) {
var search_text = getElement( "search_text" );
var self = this;
if ( search_text.pulldown ) {
search_text.pulldown.update_suggestions( search_text.value );
} else if ( event.key().code != 13 ) {
search_text.pulldown = new Suggest_pulldown( this.wiki, this.notebook.object_id, this.invoker, search_text, null, search_text.value, search_text );
connect( search_text.pulldown, "suggestion_selected", function ( note ) {
self.load_search_suggestion( note )
} );
}
}
Wiki.prototype.load_search_suggestion = function ( note ) {
var search_text = getElement( "search_text" );
search_text.value = note.title;
this.load_editor( note.title, note.object_id );
if ( search_text.pulldown ) {
search_text.pulldown.shutdown();
search_text.pulldown = null;
}
}
Wiki.prototype.notebook_has_tag = function ( notebook, tag_name, tag_value ) {
// determine whether the given notebook has a tag with tag_name, and (optionally) tag_value
for ( var i in notebook.tags ) {
var tag = notebook.tags[ i ];
if ( tag.name == tag_name ) {
if ( tag_value && tag.value != tag_value )
return false;
return true;
}
}
return false;
}
Wiki.prototype.display_search_results = function ( result ) {
// if there are no search results, indicate that and bail
if ( !result || result.notes.length == 0 ) {
if ( this.search_results_editor )
this.search_results_editor.shutdown();
this.display_message( "No matching notes.", undefined, getElement( "notes_top" ) );
return;
}
// create a "magic" search results note
if ( this.notebook_has_tag( this.notebook, "forum" ) )
var notebook_word = "discussion";
else
var notebook_word = "notebook";
var list = createDOM( "span", {} );
var other_notebooks_section = false;
for ( var i in result.notes ) {
var note = result.notes[ i ]
if ( !note.title ) continue;
if ( note.contents.length == 0 ) {
var summary = "empty note";
} else {
var summary = note.summary;
// if the summary appears not to end with a complete sentence, add "..."
if ( !/[?!.]\s*$/.test( summary ) )
summary = summary + " <b>...</b>";
}
var summary_span = createDOM( "span" );
2008-04-29 20:53:39 +00:00
summary_span.setAttribute( "class", "search_results_summary" );
summary_span.innerHTML = summary;
// when a link is clicked for a note from a notebook other than the current one, open it in a
// new window
var link_attributes = { "href": "/notebooks/" + note.notebook_id + "?note_id=" + note.object_id };
if ( note.notebook_id != this.notebook.object_id ) {
link_attributes[ "target" ] = "_new";
if ( !other_notebooks_section ) {
other_notebooks_section = true;
if ( i == 0 )
appendChildNodes( list, createDOM( "p", {}, "No matching notes in this " + notebook_word + "." ) );
appendChildNodes( list, createDOM( "hr" ), createDOM( "h4", {}, "other " + notebook_word + "s" ) );
}
}
var notebook = this.notebooks_by_id[ note.notebook_id ];
appendChildNodes( list,
createDOM( "p", {},
createDOM( "a", link_attributes, note.title ),
other_notebooks_section && notebook && createDOM( "span", { "class": "small_text" }, " (", notebook.name, ")" ) || null,
createDOM( "br" ),
summary_span
)
);
}
this.search_results_editor = this.create_editor( "search_results", "<h3>search results</h3>" + list.innerHTML, undefined, undefined, undefined, false, true, false, getElement( "notes_top" ) );
}
Wiki.prototype.share_notebook = function () {
this.clear_pulldowns();
var share_notebook_frame = getElement( "note_share_notebook" );
if ( share_notebook_frame )
share_notebook_frame.editor.shutdown();
var collaborators_label = createDOM( "label",
{ "for": "collaborators_radio", "class": "radio_label", "title": "Collaborators may view and edit this notebook." },
"collaborators"
);
var viewers_label = createDOM( "label",
{ "for": "viewers_radio", "class": "radio_label", "title": "Viewers may only view this notebook." },
"viewers"
);
var owners_label = createDOM( "label",
{ "for": "owners_radio", "class": "radio_label", "title": "Owners may view, edit, rename, delete, and invite people to this notebook." },
"owners"
);
var collaborators_radio = createDOM( "input",
{ "type": "radio", "id": "collaborators_radio", "name": "access", "value": "collaborator", "checked": "true" }
);
var viewers_radio = createDOM( "input",
{ "type": "radio", "id": "viewers_radio", "name": "access", "value": "viewer" }
);
var owners_radio = createDOM( "input",
{ "type": "radio", "id": "owners_radio", "name": "access", "value": "owner" }
)
if ( this.rate_plan.notebook_collaboration ) {
var access_area = createDOM( "p", { "id": "access_choices" },
createDOM( "p", {}, "Invite these people as:" ),
createDOM( "table" , { "id": "access_table", "class": "radio_table" },
createDOM( "tr", {},
createDOM( "td", {}, collaborators_radio, collaborators_label ),
createDOM( "td", {}, viewers_radio, viewers_label ),
createDOM( "td", {}, owners_radio, owners_label )
)
)
);
} else {
var access_area = createDOM( "p", {},
createDOM( "b", {}, "Note: " ),
"These people will only be able to ", createDOM( "i", "view" ), " your notebook. ",
"If you'd like them to be able to ", createDOM( "i", "edit" ),
" your notebook as well, please ",
createDOM( "a", { "href": "/upgrade", "target": "_new" }, "upgrade" ),
" your account.",
createDOM( "input", { "type": "hidden", "name": "access", "value": "viewer" } )
);
}
var invite_area = createDOM( "p", { "id": "invite_area" } );
2007-12-13 22:29:57 +00:00
this.display_invites( invite_area );
var div = createDOM( "div", {},
createDOM( "form", { "id": "invite_form", "target": "/users/send_invites" },
createDOM( "input", { "type": "hidden", "name": "notebook_id", "value": this.notebook.object_id } ),
createDOM( "p", {},
createDOM( "b", {}, "people to invite" ),
createDOM( "br", {} ),
createDOM( "textarea",
{ "name": "email_addresses", "class": "textarea_field", "cols": "40", "rows": "4", "wrap": "off" }
)
),
createDOM( "p", {}, "Please separate email addresses with commas, spaces, or the enter key." ),
access_area,
createDOM( "p", {},
createDOM( "input",
{ "type": "submit", "name": "invite_button", "id": "invite_button", "class": "button", "value": "send invites" }
)
),
invite_area
),
createDOM( "div", {},
createDOM(
"a", { "href": "/notebooks/" + this.notebook.object_id + "?preview=viewer", "target": "_new" },
"Preview this notebook as a viewer."
)
),
this.rate_plan.notebook_collaboration ? createDOM( "div", {},
createDOM(
"a", { "href": "/notebooks/" + this.notebook.object_id + "?preview=collaborator", "target": "_new" },
"Preview this notebook as a collaborator."
)
) : null
);
this.create_editor( "share_notebook", "<h3>share this notebook</h3>" + div.innerHTML, undefined, undefined, undefined, false, true, false, getElement( "notes_top" ) );
}
2007-12-13 22:29:57 +00:00
Wiki.prototype.display_invites = function ( invite_area ) {
if ( !this.invites || this.invites.length == 0 )
return;
2007-12-13 22:29:57 +00:00
var collaborators = createDOM( "div", { "id": "collaborators" } );
var viewers = createDOM( "div", { "id": "viewers" } );
var owners = createDOM( "div", { "id": "owners" } );
var self = this;
var addresses = new Array();
for ( var i in this.invites ) {
var invite = this.invites[ i ];
// if there are multiple invites for a given email address, only display those that are
// redeemed
if ( addresses[ invite.email_address ] == true && !invite.redeemed_user_id )
continue;
2007-12-13 22:29:57 +00:00
var revoke_button = createDOM( "input", {
"type": "button",
"id": "revoke_" + invite.object_id,
"class": "revoke_button button",
2007-12-13 22:29:57 +00:00
"value": " x ",
"title": "revoke this person's notebook access"
} );
var add_invite_to = null;
if ( invite.owner ) {
add_invite_to = owners;
} else {
if ( invite.read_write )
add_invite_to = collaborators;
else
add_invite_to = viewers;
}
appendChildNodes(
add_invite_to, createDOM( "div", { "class": "invite indented" },
invite.email_address, " ",
createDOM( "span", { "class": "invite_status" },
invite.redeemed_username ? "(invite accepted by " + invite.redeemed_username + ")" : "(waiting for invite to be accepted)"
),
" ", revoke_button,
!invite.redeemed_username && createDOM( "span", {},
createDOM( "br" ),
createDOM( "span", { "class": "invite_link_area" },
"invite link: " + location.protocol + "//" + location.host + "/i/" + invite.object_id
)
) || ""
)
);
addresses[ invite.email_address ] = true;
}
var div = createDOM( "div" );
if ( collaborators.childNodes.length > 0 ) {
2007-12-13 22:29:57 +00:00
var p = createDOM( "p" );
appendChildNodes( p, createDOM( "b", {}, "collaborators" ) );
appendChildNodes( p, collaborators );
appendChildNodes( div, p );
}
if ( viewers.childNodes.length > 0 ) {
2007-12-13 22:29:57 +00:00
var p = createDOM( "p" );
appendChildNodes( p, createDOM( "b", {}, "viewers" ) );
appendChildNodes( p, viewers );
appendChildNodes( div, p );
}
if ( owners.childNodes.length > 0 ) {
2007-12-13 22:29:57 +00:00
var p = createDOM( "p" );
appendChildNodes( p, createDOM( "b", {}, "owners" ) );
appendChildNodes( p, owners );
appendChildNodes( div, p );
}
replaceChildNodes( invite_area, div );
}
Wiki.prototype.display_settings = function () {
this.clear_pulldowns();
var settings_frame = getElement( "note_settings" );
if ( settings_frame ) {
settings_frame.editor.highlight();
return;
}
var group_list = createDOM( "div" );
var div = createDOM( "div", {},
createDOM( "form", { "id": "settings_form", "target": "/users/update_settings" },
createDOM( "p", {},
createDOM( "b", {}, "email address" ),
createDOM( "br", {} ),
createDOM( "input",
{ "type": "text", "name": "email_address", "id": "email_address", "class": "text_field",
"size": "30", "maxlength": "60", "value": this.user.email_address || "" }
)
),
createDOM( "p", {},
createDOM( "input",
{ "type": "submit", "name": "settings_button", "id": "settings_button", "class": "button", "value": "save settings" }
)
),
createDOM( "p", { "class": "small_text" },
"Your email address will ",
createDOM( "a", { "href": "/privacy", "target": "_new" }, "never be shared" ),
". It will only be used for password resets, contacting you about account problems, and the from address in any invite emails you send."
)
),
createDOM( "p", {},
createDOM( "b", {}, "group membership" ),
createDOM( "br", {} ),
group_list
),
createDOM( "p", {},
createDOM(
"a", { "href": "/pricing", "target": "_top" },
"Upgrade, downgrade, or cancel your account."
)
)
);
for ( var i in this.groups ) {
var group = this.groups[ i ];
var item = createDOM( "div", { "class": "indented" } );
appendChildNodes( group_list, item );
appendChildNodes( item, group.name );
if ( group.admin ) {
appendChildNodes( item, createDOM( "input", {
"id": "admin_" + group.object_id,
"class": "admin_button button",
"type": "button",
"value": "admin",
"title": "administer this group's users"
} ) );
}
}
if ( this.groups.length == 0 ) {
var item = createDOM( "div", { "class": "indented" }, "You're not a member of any groups." );
appendChildNodes( group_list, item );
}
this.create_editor( "settings", "<h3>account settings</h3>" + div.innerHTML, undefined, undefined, undefined, false, true, false, getElement( "notes_top" ) );
}
Wiki.prototype.display_group_settings = function ( result ) {
this.clear_pulldowns();
var group_frame = getElement( "note_group_" + result.group.object_id );
if ( group_frame )
group_frame.editor.shutdown();
var admin_list = createDOM( "div" );
var user_list = createDOM( "div" );
var div = createDOM( "div", {},
createDOM( "form", { "id": "group_settings_form", "target": "/groups/update_settings" },
createDOM( "input",
{ "type": "hidden", "name": "group_id", "class": "group_id", "value": result.group.object_id }
),
createDOM( "p", {},
createDOM( "b", {}, "group name" ),
createDOM( "br", {} ),
createDOM( "input",
{ "type": "text", "name": "group_name", "id": "group_name", "class": "text_field",
"size": "30", "maxlength": "100", "value": result.group.name }
)
),
createDOM( "p", {},
createDOM( "input",
{ "type": "submit", "name": "group_settings_button", "id": "group_settings_button", "class": "button", "value": "save settings" }
)
)
),
createDOM( "h3", {}, "create group member" ),
createDOM( "form", { "id": "create_user_form", "target": "/users/signup_group_member" },
createDOM( "input",
{ "type": "hidden", "name": "group_id", "class": "group_id", "value": result.group.object_id }
),
createDOM( "p", {},
createDOM( "b", {}, "new username" ),
createDOM( "br", {} ),
createDOM( "input",
{ "type": "text", "name": "username", "id": "username", "class": "text_field",
"size": "30", "maxlength": "60" }
)
),
createDOM( "p", {},
createDOM( "b", {}, "password" ),
createDOM( "br", {} ),
createDOM( "input",
{ "type": "password", "name": "password", "id": "password", "class": "text_field",
"size": "30", "maxlength": "60" }
)
),
createDOM( "p", {},
createDOM( "b", {}, "password" ), " (again)",
createDOM( "br", {} ),
createDOM( "input",
{ "type": "password", "name": "password_repeat", "id": "password_repeat", "class": "text_field",
"size": "30", "maxlength": "60" }
)
),
createDOM( "p", {},
createDOM( "b", {}, "email address" ),
createDOM( "br", {} ),
createDOM( "input",
{ "type": "text", "name": "email_address", "id": "email_address", "class": "text_field",
"size": "30", "maxlength": "60" }
)
),
createDOM( "p", {},
createDOM( "input",
{ "type": "submit", "name": "create_user_button", "id": "create_user_button", "class": "button", "value": "create member" }
)
)
),
createDOM( "h3", {}, "group members" ),
createDOM( "p", {},
createDOM( "b", {}, "admins" ),
createDOM( "br", {} ),
admin_list
),
createDOM( "p", {},
createDOM( "b", {}, "members" ),
createDOM( "br", {} ),
user_list
)
);
for ( var i in result.admin_users ) {
var user = result.admin_users[ i ];
appendChildNodes( admin_list, createDOM( "div", { "class": "indented" }, user.username ) );
}
if ( result.admin_users.length == 0 )
appendChildNodes( admin_list, createDOM( "div", { "class": "indented" }, "This group has no admin users." ) );
for ( var i in result.other_users ) {
var user = result.other_users[ i ];
appendChildNodes( user_list, createDOM( "div", { "class": "indented" }, user.username,
createDOM( "input", {
"type": "button",
"id": "remove_user_" + user.object_id + "_" + result.group.object_id,
"class": "remove_user_button button",
"value": " x ",
"title": "remove this user from the group"
} )
) );
}
if ( result.other_users.length == 0 )
appendChildNodes( user_list, createDOM( "div", { "class": "indented" }, "This group has no members." ) );
this.create_editor( "group_" + result.group.object_id, "<h3>group admin settings</h3>" + div.innerHTML, undefined, undefined, undefined, false, true, false, getElement( "note_settings" ) );
}
Wiki.prototype.display_import_notebook = function ( result ) {
this.clear_messages();
this.clear_pulldowns();
var import_frame = getElement( "note_import" );
if ( import_frame )
import_frame.editor.shutdown();
var form = createDOM( "form", { "id": "import_notebook_form", "target": "/notebooks/import_csv" },
createDOM( "input",
{ "type": "hidden", "name": "file_id", "value": result.file_id }
)
);
appendChildNodes( form, createDOM( "p", {}, "Here are the first few lines of the file:" ) );
var tbody = createDOM( "tbody", {} );
var table = createDOM( "table" , { "id": "import_notebook_table" }, tbody );
appendChildNodes( form, table );
for ( var i in result.rows ) {
var row = result.rows[ i ];
var row_node = createDOM( "tr", {} );
for ( var j in row ) {
var element = row[ j ];
appendChildNodes( row_node, createDOM( "td", {}, element ) );
}
appendChildNodes( tbody, row_node );
}
var contents_select = createDOM( "select", { "name": "content_column" } );
var column_number = 1;
for ( i in result.rows[ 0 ] ) {
var element = result.rows[ 0 ][ i ];
appendChildNodes( contents_select, createDOM( "option", { "value": i }, "column " + column_number + " - " + element ) );
column_number += 1;
}
appendChildNodes( form, createDOM( "p", { "target": "/notebooks/import" },
createDOM( "b", {}, "Which column contains the note contents text?" ),
createDOM( "br", {} ),
contents_select
) );
var titles_select = createDOM( "select", { "name": "title_column" } );
column_number = 1;
appendChildNodes( titles_select, createDOM( "option", { "value": "None" }, "There is no title column." ) );
for ( i in result.rows[ 0 ] ) {
var element = result.rows[ 0 ][ i ];
appendChildNodes( titles_select, createDOM( "option", { "value": i }, "column " + column_number + " - " + element ) );
column_number += 1;
}
appendChildNodes( form, createDOM( "p", {},
createDOM( "b", {}, "Which column contains the note titles (if any)?" ),
createDOM( "br", {} ),
titles_select
) );
var plaintext_label = createDOM( "label",
{ "for": "plaintext_radio", "class": "radio_label", "title": "The note contents are just plain text." },
"plain text"
);
var html_label = createDOM( "label",
{ "for": "html_radio", "class": "radio_label", "title": "The note contents are formatted as HTML." },
"HTML"
);
var plaintext_radio = createDOM( "input",
{ "type": "radio", "id": "plaintext_radio", "name": "plaintext", "value": "True", "checked": "true" }
);
var html_radio = createDOM( "input",
{ "type": "radio", "id": "html_radio", "name": "plaintext", "value": "False" }
);
appendChildNodes( form, createDOM( "p", {},
createDOM( "b", {}, "Should the note contents be treated as plain text or HTML?" ),
createDOM( "br", {} ),
createDOM( "table" , { "id": "plaintext_table", "class": "radio_table" },
createDOM( "tr", {},
createDOM( "td", {}, plaintext_radio, plaintext_label ),
createDOM( "td", {}, html_radio, html_label )
)
)
) );
appendChildNodes( form, createDOM( "p", {},
createDOM( "input",
{ "type": "submit", "name": "import_button", "id": "import_button", "class": "button", "value": "import notebook" }
)
) );
var div = createDOM( "div", {},
createDOM( "p", {}, "Almost done. I just need a little information about your file before I can complete the import and create a new notebook." ),
form,
createDOM( "p", {}, "Once you begin the import, it may take several seconds to complete." )
);
this.create_editor( "import", "<h3>import a notebook</h3>" + div.innerHTML, undefined, undefined, undefined, false, true, false, undefined );
}
Wiki.prototype.declutter_clicked = function () {
var header = getElement( "header" );
if ( header )
addElementClass( header, "undisplayed" );
var link_area_holder = getElement( "link_area_holder" );
if ( link_area_holder )
addElementClass( link_area_holder, "undisplayed" );
var note_tree_area = getElement( "note_tree_area" );
if ( note_tree_area )
addElementClass( note_tree_area, "undisplayed" );
var clutter_link = getElement( "clutter_link" );
if ( clutter_link ) {
removeElementClass( clutter_link, "undisplayed" );
} else {
clutter_link = createDOM(
"a",
{ "href": "#", "id": "clutter_link", "title": "Return to the full view of your notebook." },
"show it all"
);
appendChildNodes( "link_area", createDOM( "div", { "class": "link_area_item" }, clutter_link ) );
var self = this;
connect( clutter_link, "onclick", function ( event ) {
self.clutter_clicked();
event.stop();
} );
}
}
Wiki.prototype.clutter_clicked = function () {
var header = getElement( "header" );
if ( header )
removeElementClass( header, "undisplayed" );
var link_area_holder = getElement( "link_area_holder" );
if ( link_area_holder )
removeElementClass( link_area_holder, "undisplayed" );
var note_tree_area = getElement( "note_tree_area" );
if ( note_tree_area )
removeElementClass( note_tree_area, "undisplayed" );
var clutter_link = getElement( "clutter_link" );
if ( clutter_link )
addElementClass( clutter_link, "undisplayed" );
}
Wiki.prototype.move_current_notebook_up = function ( event ) {
var current_notebook = getElement( "current_notebook_wrapper" );
var sibling_notebook = current_notebook;
// find the previous sibling notebook node
do {
var sibling_notebook = sibling_notebook.previousSibling;
} while ( sibling_notebook && sibling_notebook.className != "link_area_item" );
removeElement( current_notebook );
if ( sibling_notebook )
// move the current notebook up before the previous notebook node
insertSiblingNodesBefore( sibling_notebook, current_notebook );
// if the current notebook is the first one, wrap it around to the bottom of the list
else {
var notebooks_area = getElement( "notebooks_area" );
appendChildNodes( notebooks_area, current_notebook );
}
var self = this;
this.invoker.invoke( "/notebooks/move_up", "POST", {
"notebook_id": this.notebook.object_id
} );
}
Wiki.prototype.move_current_notebook_down = function ( event ) {
var current_notebook = getElement( "current_notebook_wrapper" );
var sibling_notebook = current_notebook;
// find the next sibling notebook node
do {
var sibling_notebook = sibling_notebook.nextSibling;
} while ( sibling_notebook && sibling_notebook.className != "link_area_item" );
removeElement( current_notebook );
if ( sibling_notebook )
// move the current notebook down after the previous notebook node
insertSiblingNodesAfter( sibling_notebook, current_notebook );
// if the current notebook is the last one, wrap it around to the top of the list
else {
var notebooks_area_title = getElement( "notebooks_area_title" );
insertSiblingNodesAfter( notebooks_area_title, current_notebook );
}
var self = this;
this.invoker.invoke( "/notebooks/move_down", "POST", {
"notebook_id": this.notebook.object_id
} );
}
Wiki.prototype.display_message = function ( text, nodes, position_after ) {
var self = this;
this.clear_messages();
this.clear_pulldowns();
var inner_div = DIV( { "class": "message_inner" }, text + " " );
for ( var i in nodes )
appendChildNodes( inner_div, nodes[ i ] );
2007-12-13 22:29:57 +00:00
var ok_button = createDOM( "input", {
"type": "button",
"class": "message_button",
"value": "ok",
2007-09-20 23:34:34 +00:00
"title": "dismiss this message"
} );
appendChildNodes( inner_div, ok_button );
connect( ok_button, "onclick", function () { self.clear_messages(); } );
var div = DIV( { "class": "message" }, inner_div );
div.nodes = nodes;
div.init_time = new Date();
if ( position_after )
insertSiblingNodesAfter( position_after, div )
else if ( this.focused_editor )
insertSiblingNodesAfter( this.focused_editor.holder, div )
else
insertSiblingNodesAfter( "notes_top", div );
this.scroll_to( div );
this.resize_editor();
return div;
}
Wiki.prototype.display_error = function ( text, nodes, position_after ) {
var self = this;
this.clear_messages();
this.clear_pulldowns();
var inner_div = DIV( { "class": "error_inner" }, text + " " );
for ( var i in nodes )
appendChildNodes( inner_div, nodes[ i ] );
ok_button = createDOM( "input", {
"type": "button",
"class": "message_button",
"value": "ok",
2007-09-20 23:34:34 +00:00
"title": "dismiss this message"
} );
appendChildNodes( inner_div, ok_button );
connect( ok_button, "onclick", function () { self.clear_messages(); } );
var div = DIV( { "class": "error" }, inner_div );
div.nodes = nodes;
div.init_time = new Date();
if ( position_after )
insertSiblingNodesAfter( position_after, div )
else if ( this.focused_editor )
insertSiblingNodesAfter( this.focused_editor.holder, div )
else
insertSiblingNodesAfter( "notes_top", div );
this.scroll_to( div );
this.resize_editor();
return div;
}
Wiki.prototype.scroll_to = function ( node ) {
// if the message is already completely on-screen, then there's no need to scroll
var viewport_position = getViewportPosition();
if ( getElementPosition( node ).y < viewport_position.y ||
getElementPosition( node ).y + getElementDimensions( node ).h > viewport_position.y + getViewportDimensions().h )
new ScrollTo( node, { "duration": 0.25 } );
}
Wiki.prototype.clear_messages = function () {
var message_results = getElementsByTagAndClassName( "div", "message" );
var error_results = getElementsByTagAndClassName( "div", "error" );
for ( var i in message_results ) {
var result = message_results[ i ];
// only close the message if it's been open at least a quarter second
if ( new Date() - result.init_time < 250 )
continue
blindUp( result, options = { "duration": 0.25, afterFinish: function () {
try {
for ( var j in result.nodes )
disconnectAll( result.nodes[ j ] );
removeElement( result );
} catch ( e ) { }
} } );
}
for ( var i in error_results ) {
var result = error_results[ i ];
if ( new Date() - result.init_time < 250 )
continue
blindUp( result, options = { "duration": 0.25, afterFinish: function () {
try {
removeElement( result );
} catch ( e ) { }
} } );
}
if ( message_results.length || error_results.length )
this.resize_editor();
}
Wiki.prototype.clear_pulldowns = function ( ephemeral_only ) {
var results = getElementsByTagAndClassName( "div", "pulldown" );
for ( var i in results ) {
var result = results[ i ];
if ( !result.pulldown )
continue;
// only close the pulldown if it's been open at least a quarter second
if ( new Date() - result.pulldown.init_time < 250 )
continue;
if ( ephemeral_only && !result.pulldown.ephemeral )
continue;
if ( result.pulldown.shutdown() )
result.pulldown = null;
}
}
Wiki.prototype.delete_all_editors = function ( event ) {
this.clear_messages();
this.clear_pulldowns();
this.editor_focused( null );
this.startup_notes = new Array();
if ( this.notebook.read_write == NOTEBOOK_READ_WRITE ) {
var self = this;
this.invoker.invoke( "/notebooks/delete_all_notes", "POST", {
"notebook_id": this.notebook.object_id
}, function ( result ) { self.display_storage_usage( result.storage_bytes ); } );
}
this.focused_editor = null;
var divs = getElementsByTagAndClassName( "div", "static_note_div" );
for ( var i in divs ) {
var editor = divs[ i ].editor;
if ( editor )
editor.shutdown();
}
this.zero_total_notes_count();
2008-10-27 23:23:27 +00:00
var note_tree_root_table = getElement( "note_tree_root_table" );
if ( note_tree_root_table )
removeElement( note_tree_root_table );
this.display_empty_message( true );
event.stop();
}
Wiki.prototype.display_empty_message = function ( replace_messages ) {
if ( !replace_messages ) {
// if there are any messages already open, bail
var messages = getElementsByTagAndClassName( "div", "message" );
if ( messages.length > 0 ) return false;
// if there are any errors open, bail
var errors = getElementsByTagAndClassName( "div", "error" );
if ( errors.length > 0 ) return false;
}
// if there are any open editors, bail
if ( Editor.shared_frame && Editor.shared_frame.editor && !Editor.shared_frame.editor.closed )
return false;
var divs = getElementsByTagAndClassName( "div", "static_note_div" );
for ( var i in divs ) {
var editor = divs[ i ].editor;
if ( editor && !editor.closed )
return;
}
if ( !this.total_notes_count ) {
if ( this.parent_id )
this.display_message( "There are no notes in the trash." )
else
this.display_message( "This notebook is empty." );
return true;
}
if ( !replace_messages )
return true;
return false;
}
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
DATE_PATTERN = /(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d).(\d+)[+-](\d\d:?\d\d)/;
Wiki.prototype.brief_revision = function ( revision ) {
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
var matches = DATE_PATTERN.exec( revision );
return new Date( Date.UTC(
matches[ 1 ], // year
matches[ 2 ] - 1, // month (zero-based)
matches[ 3 ], // day
matches[ 4 ], // hour
matches[ 5 ], // minute
matches[ 6 ], // second
matches[ 7 ] * 0.001 // milliseconds
) ).toLocaleString();
}
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 );
}
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
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.export_clicked = function () {
var pulldown_id = "export_pulldown";
var existing_div = getElement( pulldown_id );
if ( existing_div ) {
existing_div.pulldown.shutdown();
existing_div.pulldown = null;
return;
}
new Export_pulldown( this, this.notebook.object_id, this.invoker, getElement( "export_link" ) );
}
Wiki.prototype.import_clicked = function () {
var pulldown_id = "upload_import";
var existing_div = getElement( pulldown_id );
if ( existing_div ) {
existing_div.pulldown.shutdown();
existing_div.pulldown = null;
return;
}
new Upload_pulldown( this, this.notebook.object_id, this.invoker, null, null, getElement( "import_link" ) );
}
Wiki.prototype.start_notebook_rename = function () {
this.clear_pulldowns();
// if a renaming is already in progress, end the renaming instead of starting one
var notebook_name_field = getElement( "notebook_name_field" );
if ( notebook_name_field ) {
this.end_notebook_rename();
return;
}
var div = createDOM( "div" );
div.innerHTML = this.notebook.name;
var notebook_name = scrapeText( div );
notebook_name_field = createDOM(
"input", {
"type": "text",
2007-12-05 22:55:23 +00:00
"value": notebook_name,
"id": "notebook_name_field",
"name": "notebook_name_field",
"size": "30",
"maxlength": "100",
"class": "text_field"
}
);
var ok_button = createDOM(
"input", {
"type": "button",
"class": "message_button",
"value": "rename",
"title": "rename this notebook"
}
);
var rename_form = createDOM(
"form", { "id": "rename_form" }, notebook_name_field, ok_button
);
replaceChildNodes( "notebook_header_name", rename_form );
var self = this;
connect( rename_form, "onsubmit", function ( event ) {
self.end_notebook_rename();
event.stop();
} );
connect( ok_button, "onclick", function ( event ) {
self.end_notebook_rename();
event.stop();
} );
connect( notebook_name_field, "onclick", function ( event ) {
event.stop();
} );
notebook_name_field.focus();
notebook_name_field.select();
}
2008-10-30 22:26:27 +00:00
Wiki.prototype.end_notebook_rename = function ( new_notebook_name, prevent_rename_on_click ) {
if ( !new_notebook_name )
new_notebook_name = getElement( "notebook_name_field" ).value;
// if the new name is blank or reserved, don't actually rename the notebook
if ( /^\s*$/.test( new_notebook_name ) )
new_notebook_name = this.notebook.name;
if ( /^\s*Luminotes/.test( new_notebook_name ) || /^\s*trash\s*$/.test( new_notebook_name ) ) {
new_notebook_name = this.notebook.name;
this.display_error( "That notebook name is not available. Please try a different one." );
}
// rename the notebook in the header
2008-10-30 22:26:27 +00:00
if ( prevent_rename_on_click ) {
var notebook_header_name = createDOM(
"span", {},
createDOM( "strong", {}, new_notebook_name )
);
replaceChildNodes( "notebook_header_area", notebook_header_name );
} else {
var notebook_header_name = createDOM(
"span",
{ "id": "notebook_header_name", "title": "Rename this notebook." },
createDOM( "strong", {}, new_notebook_name )
);
replaceChildNodes( "notebook_header_area", notebook_header_name );
2008-10-30 22:26:27 +00:00
var self = this;
connect( notebook_header_name, "onclick", function ( event ) {
self.start_notebook_rename();
event.stop();
} );
}
// rename the notebook link on the right side of the page
2008-10-30 22:26:27 +00:00
var notebook_link = getElement( "notebook_" + this.notebook.object_id );
if ( notebook_link ) {
replaceChildNodes( notebook_link, document.createTextNode( new_notebook_name ) );
}
// rename the notebook within the rss link (if any)
var notebook_rss_link = getElement( "notebook_rss_link" );
if ( notebook_rss_link ) {
divider = "?rss&notebook_name=";
pieces = notebook_rss_link.href.split( divider );
notebook_rss_link.href = pieces[ 0 ] + divider + escape( new_notebook_name );
}
// if the name has changed, then send the new name to the server
if ( new_notebook_name == this.notebook.name )
return;
this.notebook.name = new_notebook_name;
this.invoker.invoke( "/notebooks/rename", "POST", {
"notebook_id": this.notebook.object_id,
"name": new_notebook_name
} );
}
Wiki.prototype.delete_notebook = function () {
if ( this.focused_editor ) {
var self = this;
this.save_editor( this.focused_editor, false, function () {
self.invoker.invoke( "/notebooks/delete", "POST", {
"notebook_id": self.notebook.object_id
} );
} )
return;
}
this.invoker.invoke( "/notebooks/delete", "POST", {
"notebook_id": this.notebook.object_id
} );
}
Wiki.prototype.delete_notebook_forever = function ( event, notebook_id ) {
var deleted_notebook_node = getElement( "deleted_notebook_" + notebook_id );
if ( !deleted_notebook_node ) return;
for ( var i in deleted_notebook_node.childNodes ) {
var child = deleted_notebook_node.childNodes[ i ];
disconnectAll( child );
}
removeElement( deleted_notebook_node );
var items = getElementsByTagAndClassName( "div", "deleted_notebook_item" );
if ( items.length == 0 )
removeElement( "deleted_notebooks" );
var self = this;
this.invoker.invoke( "/notebooks/delete_forever", "POST", {
"notebook_id": notebook_id
}, function ( result ) { self.display_storage_usage( result.storage_bytes ); } );
event.stop();
}
Wiki.prototype.toggle_editor_changes = function ( event, editor ) {
// if the pulldown is already open, then just close it
var pulldown_id = "changes_" + editor.id;
var existing_div = getElement( pulldown_id );
if ( existing_div ) {
existing_div.pulldown.shutdown();
existing_div.pulldown = null;
return;
}
event.stop();
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
// if there's already a cached revision list, then display the changes pulldown and bail
if ( ( editor.user_revisions && editor.user_revisions.length > 0 ) ) {
new Changes_pulldown( this, this.notebook.object_id, this.invoker, editor );
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
return;
}
// otherwise, load the revision list for this note from the server
var self = this;
this.invoker.invoke(
"/notebooks/load_note_revisions", "GET", {
"notebook_id": this.notebook.object_id,
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
"note_id": editor.id
},
function ( result ) {
editor.user_revisions = result.revisions;
new Changes_pulldown( self, self.notebook.object_id, self.invoker, editor );
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
}
);
}
2009-03-03 03:39:02 +00:00
Wiki.prototype.toggle_editor_tools = function ( event, editor ) {
// if the pulldown is already open, then just close it
2009-03-03 03:39:02 +00:00
var pulldown_id = "tools_" + editor.id;
var existing_div = getElement( pulldown_id );
if ( existing_div ) {
existing_div.pulldown.shutdown();
existing_div.pulldown = null;
return;
}
2009-03-03 03:39:02 +00:00
new Tools_pulldown( this, this.notebook.object_id, this.invoker, editor );
event.stop();
}
connect( window, "onload", function ( event ) { new Wiki( new Invoker() ); } );
function Pulldown( wiki, notebook_id, pulldown_id, anchor, relative_to, ephemeral, cache ) {
this.wiki = wiki;
this.notebook_id = notebook_id;
this.div = createDOM( "div", { "id": pulldown_id, "class": "pulldown" } );
this.div.pulldown = this;
this.init_time = new Date();
this.anchor = anchor;
this.relative_to = relative_to;
this.ephemeral = ephemeral;
this.cache = cache || false;
addElementClass( this.div, "invisible" );
appendChildNodes( document.body, this.div );
var self = this;
if ( this.ephemeral ) {
// when the mouse cursor is moved into the pulldown, it becomes non-ephemeral (in other words,
// it will no longer disappear in a few seconds). but as soon as the mouse leaves, it becomes
// ephemeral again
connect( this.div, "onmouseover", function ( event ) {
self.ephemeral = false;
} );
connect( this.div, "onmouseout", function ( event ) {
self.ephemeral = true;
} );
}
// prevent clicks on the pulldown's background from closing the pulldown
connect( this.div, "onclick", function ( event ) {
var name = event.target().tagName.toLowerCase();
if ( name == "div" || name == "span" )
event.stop();
} );
}
Pulldown.prototype.finish_init = function () {
Pulldown.prototype.update_position.call( this );
removeElementClass( this.div, "invisible" );
}
function calculate_position( node, anchor, relative_to, always_left_align ) {
var anchor_dimensions = getElementDimensions( anchor );
// if the anchor's first child is larger (vertically) than its parent, then use it as the anchor
if ( anchor.firstChild ) {
try{
var child_dimensions = getElementDimensions( anchor.firstChild );
if ( child_dimensions.h > anchor_dimensions.h + 4 ) {
anchor = anchor.firstChild;
anchor_dimensions = child_dimensions;
}
} catch ( e ) {}
}
var parent_node = anchor.parentNode;
var fixed_parent = null;
// determine whether this node has an ancentor node that has a fixed position
while ( parent_node && parent_node.nodeName != "#document" ) {
if ( getStyle( parent_node, "position" ) == "fixed" ) {
fixed_parent = parent_node;
break;
}
parent_node = parent_node.parentNode;
}
// position the pulldown under the anchor relative to the fixed ancestor (if any)
var position = getElementPosition( anchor, fixed_parent );
if ( fixed_parent ) {
position.x += fixed_parent.offsetLeft;
position.y += fixed_parent.offsetTop;
setStyle( node, { "position": "fixed" } )
}
if ( relative_to ) {
var relative_pos = getElementPosition( relative_to );
if ( relative_pos ) {
position.x += relative_pos.x;
position.y += relative_pos.y;
// adjust the vertical position based on how far the page has scrolled
position.y -= getElement( "html" ).scrollTop;
}
}
var node_dimensions = getElementDimensions( node );
// if the position is on the right half of the page, then align the right edge of the node with
// the right edge of the anchor
if ( !always_left_align && position.x > getViewportDimensions().w * 0.5 ) {
if ( node_dimensions )
position.x = position.x - node_dimensions.w + anchor_dimensions.w;
}
// if we still don't have a height, move the position down a bit by an arbitrary amount
if ( anchor_dimensions.h == 0 )
position.y += 8;
else
position.y += anchor_dimensions.h + 4;
return position;
}
Pulldown.prototype.update_position = function ( always_left_align ) {
var position = calculate_position( this.div, this.anchor, this.relative_to, always_left_align );
setElementPosition( this.div, position );
var div_height = getElementDimensions( this.div ).h;
var viewport_bottom = getViewportPosition().y + getViewportDimensions().h;
// if the pulldown is now partially off the bottom of the window, move it up until it isn't
if ( position.y + div_height > viewport_bottom )
new Move( this.div, { "x": position.x, "y": viewport_bottom - div_height, "mode": "absolute", "duration": 0.25 } );
}
Pulldown.prototype.show = function () {
// implemented in derived object
}
Pulldown.prototype.hide = function () {
// implemented in derived object
}
Pulldown.prototype.shutdown = function () {
// if this pulldown is to be cached, then simply hide it rather than shutting it down completely
if ( this.cache ) {
this.hide();
return false;
}
disconnectAll( this.div );
if ( this.div && this.div.parentNode )
removeElement( this.div );
return true;
}
2009-03-03 03:39:02 +00:00
function Tools_pulldown( wiki, notebook_id, invoker, editor ) {
Pulldown.call( this, wiki, notebook_id, "tools_" + editor.id, editor.tools_button );
this.invoker = invoker;
this.editor = editor;
this.startup_checkbox = createDOM( "input", { "type": "checkbox", "class": "pulldown_checkbox", "id": "startup_checkbox" } );
this.startup_label = createDOM( "label", { "for": "startup_checkbox", "class": "pulldown_label", "title": "Display this note whenever the notebook is loaded." },
"show on startup"
);
2009-03-03 01:16:15 +00:00
appendChildNodes( this.div, createDOM( "div", {}, this.startup_checkbox, this.startup_label ) );
this.unformat_checkbox = createDOM( "input", { "type": "checkbox", "class": "pulldown_checkbox invisible" } );
this.unformat_link = createDOM( "a",
{
"href": "#",
"class": "pulldown_link",
"title": "Remove formatting from the currently selected text."
},
"remove formatting"
);
appendChildNodes( this.div, createDOM( "div", {}, this.unformat_checkbox, this.unformat_link ) );
if ( !editor.empty() ) {
this.print_checkbox = createDOM( "input", { "type": "checkbox", "class": "pulldown_checkbox invisible" } );
this.print_link = createDOM( "a",
{
"href": "/notebooks/export?notebook_id=" + notebook_id + "&note_id=" + editor.id + "&format=print",
"target": "_new",
"class": "pulldown_link",
"title": "Print this note by itself."
},
"print this note"
);
appendChildNodes( this.div, createDOM( "div", {}, this.print_checkbox, this.print_link ) );
}
this.startup_checkbox.checked = editor.startup;
var self = this;
connect( this.startup_checkbox, "onclick", function ( event ) { self.startup_clicked( event ); } );
connect( this.unformat_link, "onclick", function ( event ) { self.unformat_clicked( event ); } );
if ( this.print_link )
connect( this.print_link, "onclick", function ( event ) { self.print_clicked( event ); } );
Pulldown.prototype.finish_init.call( this );
}
2009-03-03 03:39:02 +00:00
Tools_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Tools_pulldown.prototype.constructor = Tools_pulldown;
Pulldown.prototype.hide = function () {
Pulldown.prototype.hide.call( this );
}
Pulldown.prototype.show = function () {
Pulldown.prototype.show.call( this );
}
Pulldown.prototype.toggle_hidden = function () {
Pulldown.prototype.toggle_hidden.call( this );
}
2009-03-03 03:39:02 +00:00
Tools_pulldown.prototype.startup_clicked = function ( event ) {
this.editor.startup = this.startup_checkbox.checked;
this.editor.mark_dirty();
// save this note along with its toggled startup state
this.wiki.save_editor( this.editor );
}
Tools_pulldown.prototype.unformat_clicked = function ( event ) {
event.stop();
if ( !this.editor.unformat_selection() )
this.wiki.display_message( "To remove the formatting from some text in this note, first highlight the text that you'd like to be unformatted." );
this.shutdown();
}
Tools_pulldown.prototype.print_clicked = function ( event ) {
this.wiki.editor_focused( null, true );
}
2009-03-03 03:39:02 +00:00
Tools_pulldown.prototype.shutdown = function () {
Pulldown.prototype.shutdown.call( this );
disconnectAll( this.startup_checkbox );
if ( this.print_link )
disconnectAll( this.print_link );
}
function Changes_pulldown( wiki, notebook_id, invoker, editor ) {
Pulldown.call( this, wiki, notebook_id, "changes_" + editor.id, editor.changes_button );
this.invoker = invoker;
this.editor = editor;
this.links = new Array();
if ( !editor.user_revisions || editor.user_revisions.length == 0 ) {
appendChildNodes( this.div, createDOM( "span", "This note has no previous changes." ) );
Pulldown.prototype.finish_init.call( this );
return;
}
Merged revisions 401-446 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/branches/postgres ................ r402 | witten | 2007-10-04 00:48:49 -0700 (Thu, 04 Oct 2007) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-401" from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ................ r404 | witten | 2007-10-04 01:17:07 -0700 (Thu, 04 Oct 2007) | 2 lines Beginning a conversion from bsddb to postgres. ................ r405 | witten | 2007-10-04 01:18:58 -0700 (Thu, 04 Oct 2007) | 9 lines Merged revisions 402-404 via svnmerge from svn+ssh://torsion.org/home/luminotes/repos/luminotes/trunk ........ r403 | witten | 2007-10-04 01:14:45 -0700 (Thu, 04 Oct 2007) | 2 lines Yay, no more stupid deprecation warnings from simplejson about the sre module. ........ ................ r406 | witten | 2007-10-04 15:34:39 -0700 (Thu, 04 Oct 2007) | 4 lines * Switched back to Python 2.4 because many Python modules in Debian are not packaged to work with Python 2.5 * Began removal of all references to Scheduler, @async, yield, and so on. * Converted Database.py to support PostgreSQL and updated its unit tests accordingly. ................ r407 | witten | 2007-10-04 16:34:01 -0700 (Thu, 04 Oct 2007) | 2 lines All unit tests for the new model classes now pass. ................ r409 | witten | 2007-10-05 00:53:56 -0700 (Fri, 05 Oct 2007) | 2 lines Reordering some columns and adding some indices. ................ r410 | witten | 2007-10-05 16:08:37 -0700 (Fri, 05 Oct 2007) | 4 lines Now adding trash notebooks to user_notebook table. Also switching db conversion/verification tools back to require Python 2.5, since they still use the old Scheduler, which requires 2.5 generator features. ................ r411 | witten | 2007-10-06 16:26:56 -0700 (Sat, 06 Oct 2007) | 2 lines Lots more unit tests passing. Most of the recent work was on controller.Users and related stuff. ................ r412 | witten | 2007-10-07 01:52:12 -0700 (Sun, 07 Oct 2007) | 2 lines controller.Users unit tests now finally pass! ................ r413 | witten | 2007-10-07 02:14:10 -0700 (Sun, 07 Oct 2007) | 3 lines Got controller.Root unit tests passing. Moved fake sql_* function shenanigans from Test_users.py to Test_controller.py, for use by other controller unit tests. ................ r414 | witten | 2007-10-08 23:11:11 -0700 (Mon, 08 Oct 2007) | 2 lines All unit tests pass! Fuck yeah! ................ r415 | witten | 2007-10-08 23:13:07 -0700 (Mon, 08 Oct 2007) | 2 lines Removing all references to Scheduler from luminotes.py ................ r416 | witten | 2007-10-08 23:54:51 -0700 (Mon, 08 Oct 2007) | 3 lines Converted deleted_from to deleted_from_id in a few more places. Fixed bug in Users.contents(). ................ r417 | witten | 2007-10-09 00:11:59 -0700 (Tue, 09 Oct 2007) | 3 lines Typo fix in Note sql method. Adding autocommit flag to Database.next_id() method. ................ r418 | witten | 2007-10-09 00:13:19 -0700 (Tue, 09 Oct 2007) | 2 lines Updating unit test for new auto commit flag. ................ r419 | witten | 2007-10-09 00:14:09 -0700 (Tue, 09 Oct 2007) | 2 lines Removing debugging print. ................ r420 | witten | 2007-10-09 00:20:55 -0700 (Tue, 09 Oct 2007) | 2 lines More sql fixes. I really need some funtional tests that hit the database and exercise the SQL. ................ r421 | witten | 2007-10-09 00:51:34 -0700 (Tue, 09 Oct 2007) | 3 lines Fixed controller.Database handling of tuple as an Object_type. Made SQL for user storage calculation better at handling null values and also more succinct. ................ r422 | witten | 2007-10-09 13:32:16 -0700 (Tue, 09 Oct 2007) | 2 lines Converting Wiki.js to trash_id notebook member instead of trash object. ................ r423 | witten | 2007-10-09 13:42:10 -0700 (Tue, 09 Oct 2007) | 2 lines No longer displaying "download as html" on the front page, as people see "download" and think they're downloading the software. ................ r424 | witten | 2007-10-09 14:24:40 -0700 (Tue, 09 Oct 2007) | 2 lines Notebooks.contents() now returns notebooks with correct read-write status. ................ r425 | witten | 2007-10-09 14:32:25 -0700 (Tue, 09 Oct 2007) | 2 lines Fixed reporting of validation errors to the user. Now says "The blah is missing." instead of just "is missing" ................ r426 | witten | 2007-10-09 17:05:22 -0700 (Tue, 09 Oct 2007) | 2 lines No longer redirecting to trash notebook upon login. ................ r427 | witten | 2007-10-09 17:20:33 -0700 (Tue, 09 Oct 2007) | 2 lines Made controller.Database use a connection pool. ................ r429 | witten | 2007-10-09 20:13:30 -0700 (Tue, 09 Oct 2007) | 2 lines Converted initdb.py and updatedb.py to Postgres from bsddb. ................ r430 | witten | 2007-10-09 20:37:14 -0700 (Tue, 09 Oct 2007) | 2 lines Changing error message to remove underscores from variable names. ................ r431 | witten | 2007-10-10 13:23:30 -0700 (Wed, 10 Oct 2007) | 2 lines Removing unused note_title parameter from Wiki.create_editor(). ................ r432 | witten | 2007-10-10 13:25:16 -0700 (Wed, 10 Oct 2007) | 2 lines Revision regular expression now supports timezone notation. ................ r433 | witten | 2007-10-10 14:43:47 -0700 (Wed, 10 Oct 2007) | 2 lines Finished implementing ranked ordering for startup notes. (However, there's no way to change the rank from the client yet.) ................ r434 | witten | 2007-10-10 16:25:19 -0700 (Wed, 10 Oct 2007) | 4 lines More strict access checking. Fixed oversight in Postgres DB conversion where, in certain controller.Notebook methods, access was only checked at the notebook level, not at the note level as well. ................ r435 | witten | 2007-10-10 17:45:18 -0700 (Wed, 10 Oct 2007) | 3 lines Now loading revisions on demand from client when the "changes" button is clicked. Also caching loading revisions so subsequent clicks don't have to reload. ................ r436 | witten | 2007-10-10 21:31:20 -0700 (Wed, 10 Oct 2007) | 2 lines Tweaking some of the error handling in Expose and Root so that unhandled errors give a generic error message to the client. ................ r437 | witten | 2007-10-10 21:33:49 -0700 (Wed, 10 Oct 2007) | 2 lines The release script no longer runs initdb.py, because the default database is no longer a single file included in the tarball. ................ r438 | witten | 2007-10-10 21:40:11 -0700 (Wed, 10 Oct 2007) | 2 lines Updated install instructuctions to include use of initdb.py. ................ r439 | witten | 2007-10-10 21:56:42 -0700 (Wed, 10 Oct 2007) | 3 lines Made initdb.py only nuke (drop tables/views) when given a command-line flag. Also made install directions more correct. ................ r440 | witten | 2007-10-10 21:58:48 -0700 (Wed, 10 Oct 2007) | 2 lines IE 6 doesn't like commas. ................ r441 | witten | 2007-10-10 22:08:50 -0700 (Wed, 10 Oct 2007) | 4 lines load your notebook. without clicking on "changes", edit a note that has previous revisions. click on "changes". it'll only show the most recent revision. fixed by not appending to changes as a result of a save unless the client-side revisions list cache has something in it ................ r442 | witten | 2007-10-10 23:30:41 -0700 (Wed, 10 Oct 2007) | 2 lines Forgot to actually save off the new revision as editor.revision. ................ r443 | witten | 2007-10-11 01:35:54 -0700 (Thu, 11 Oct 2007) | 13 lines More intelligent datetime handling: * convertdb.py assumes old bsddb database timestamps are Pacific, and then converts them to UTC before inserting them into the new PostgreSQL database. * No longer using naked timezoneless datetime objects in model/controller code, except in unit tests that need compatability with pysqlite. Now using UTC everwhere. * Asking PostgreSQL to give us all timestamps back in UTC. * New dependency on python-tz (pytz) package, noted in INSTALL doc. * Client now responsible for converting UTC timestamps to local time for display. ................ r444 | witten | 2007-10-11 01:46:09 -0700 (Thu, 11 Oct 2007) | 2 lines Tweak to prevent potential race in IE. ................ r445 | witten | 2007-10-11 01:49:58 -0700 (Thu, 11 Oct 2007) | 2 lines Got JavaScript "unit" tests passing again. ................ r446 | witten | 2007-10-11 01:53:58 -0700 (Thu, 11 Oct 2007) | 2 lines Noting that js tests require the Luminotes server on localhost. ................
2007-10-11 09:03:43 +00:00
// display list of revision timestamps in reverse chronological order
var user_revisions = clone( editor.user_revisions );
user_revisions.reverse();
var self = this;
for ( var i = 0; i < user_revisions.length - 1; ++i ) { // -1 to skip the oldest revision
var user_revision = user_revisions[ i ];
var previous_revision = user_revisions[ i + 1 ];
var short_revision = this.wiki.brief_revision( user_revision.revision );
var href = "/notebooks/" + this.notebook_id + "?" + queryString(
[ "note_id", "revision", "previous_revision" ],
[ this.editor.id, user_revision.revision, previous_revision.revision ]
);
var link = createDOM(
"a",
{ "href": href, "class": "pulldown_link" },
short_revision + ( ( user_revision.username && user_revision.username != "desktopuser" )
? " by " + user_revision.username : "" )
);
this.links.push( link );
link.revision = user_revision.revision;
link.previous_revision = previous_revision.revision;
connect( link, "onclick", function ( event ) { self.link_clicked( event, self.editor.id ); } );
appendChildNodes( this.div, link );
appendChildNodes( this.div, createDOM( "br" ) );
}
Pulldown.prototype.finish_init.call( this );
}
Changes_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Changes_pulldown.prototype.constructor = Changes_pulldown;
Changes_pulldown.prototype.link_clicked = function( event, note_id ) {
var revision = event.target().revision;
var previous_revision = event.target().previous_revision;
this.wiki.load_editor( "Revision not found.", note_id, revision, previous_revision, null, this.editor.holder );
event.stop();
}
Changes_pulldown.prototype.shutdown = function () {
Pulldown.prototype.shutdown.call( this );
for ( var i in this.links )
disconnectAll( this.links[ i ] );
}
function Link_pulldown( wiki, notebook_id, invoker, editor, link, ephemeral ) {
link.pulldown = this;
this.link = link;
Pulldown.call( this, wiki, notebook_id, "link_" + editor.id, link, editor.iframe, ephemeral );
this.invoker = invoker;
this.editor = editor;
this.title_field = createDOM( "input", { "class": "text_field", "size": "30", "maxlength": "256" } );
this.note_summary = createDOM( "span", {} );
this.previous_title = "";
this.suggest_pulldown = null;
var self = this;
connect( this.title_field, "onclick", function ( event ) { self.title_field_clicked( event ); } );
connect( this.title_field, "onfocus", function ( event ) { self.title_field_focused( event ); } );
connect( this.title_field, "onkeydown", function ( event ) { self.title_field_key_pressed( event ); } );
connect( this.title_field, "onkeyup", function ( event ) { self.title_field_key_released( event ); } );
// the timeout prevents a race condition between these handlers and a suggesting being clicked
connect( this.title_field, "onchange", function ( event ) {
setTimeout( function () { self.title_field_changed( event ); }, 250 );
} );
connect( this.title_field, "onblur", function ( event ) {
setTimeout( function () { self.title_field_changed( event ); }, 250 );
} );
appendChildNodes( this.div, createDOM( "span", { "class": "field_label" }, "links to: " ) );
appendChildNodes( this.div, this.title_field );
appendChildNodes( this.div, this.note_summary );
// links with targets are considered links to external sites
if ( link.target ) {
this.title_field.value = link.href;
replaceChildNodes( this.note_summary, "web link" );
Pulldown.prototype.finish_init.call( this );
return;
}
var query = parse_query( link );
var title = link_title( link, query );
var id = query.note_id;
// 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 == "search results" ) {
this.title_field.value = title;
this.display_summary( title, "current search results" );
Pulldown.prototype.finish_init.call( this );
return;
}
if ( title == "share this notebook" ) {
this.title_field.value = title;
this.display_summary( title, "share this notebook with others" );
Pulldown.prototype.finish_init.call( this );
return;
}
if ( title == "account settings" ) {
this.title_field.value = title;
this.display_summary( title, "account settings" );
Pulldown.prototype.finish_init.call( this );
return;
}
this.invoker.invoke(
"/notebooks/load_note_by_title", "GET", {
"notebook_id": this.notebook_id,
"note_title": title,
"summarize": true
},
function ( result ) {
// if the user has already started typing something, don't overwrite it
if ( self.title_field.value.length != 0 ) {
Pulldown.prototype.finish_init.call( self );
return;
}
if ( result.note ) {
self.title_field.value = result.note.title;
self.display_summary( result.note.title, result.note.summary );
} else {
self.title_field.value = title;
replaceChildNodes( self.note_summary, "empty note" );
}
}
);
Pulldown.prototype.finish_init.call( this );
return;
}
// if this link has an actual destination note id set, then see if that note is already open. if
// so, display its title and a summary of its contents
var destination_editor = editor_by_id( id );
if ( destination_editor ) {
this.title_field.value = destination_editor.title;
this.display_summary( destination_editor.title, destination_editor.summarize() );
Pulldown.prototype.finish_init.call( this );
return;
}
// otherwise, load the destination note from the server, displaying its title and a summary of
// its contents
this.invoker.invoke(
"/notebooks/load_note", "GET", {
"notebook_id": this.notebook_id,
"note_id": id,
"summarize": true
},
function ( result ) {
// if the user has already started typing something, don't overwrite it
if ( self.title_field.value.length != 0 ) {
Pulldown.prototype.finish_init.call( self );
return;
}
if ( result.note ) {
self.title_field.value = result.note.title;
self.display_summary( result.note.title, result.note.summary );
} else {
self.title_field.value = title;
replaceChildNodes( self.note_summary, "empty note" );
}
}
);
Pulldown.prototype.finish_init.call( this );
}
Link_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Link_pulldown.prototype.constructor = Link_pulldown;
Link_pulldown.prototype.display_summary = function ( title, summary ) {
if ( !summary )
replaceChildNodes( this.note_summary, "empty note" );
else if ( summary.length == 0 )
replaceChildNodes( this.note_summary, "empty note" );
else
replaceChildNodes( this.note_summary, summary );
}
Link_pulldown.prototype.title_field_clicked = function ( event ) {
disconnectAll( this.div );
this.ephemeral = false;
event.stop();
}
Link_pulldown.prototype.title_field_focused = function ( event ) {
disconnectAll( this.div );
this.ephemeral = false;
this.title_field.select();
}
Link_pulldown.prototype.update_title_field_with_suggestion = function ( note ) {
this.title_field.value = note.title;
this.title_field_changed( null, note );
if ( this.suggest_pulldown ) {
this.suggest_pulldown.shutdown();
this.suggest_pulldown = null;
}
}
Link_pulldown.prototype.title_field_changed = function ( event, note ) {
// if the title is actually unchanged, then bail
var title = strip( this.title_field.value );
if ( title == this.previous_title )
return;
replaceChildNodes( this.note_summary, "" );
this.previous_title = title;
var self = this;
// if a destination note is given, then update the link to point to it
if ( note ) {
this.link.href = "/notebooks/" + this.notebook_id + "?note_id=" + note.object_id;
this.suggest_pulldown.shutdown();
this.suggest_pulldown = null;
this.display_summary( note.title, summarize_html( note.contents, note.title ) );
// otherwise, try to resolve the link title
} else {
this.wiki.resolve_link( title, this.link, true, function ( summary ) {
self.display_summary( title, summary );
} );
}
}
Link_pulldown.prototype.title_field_key_pressed = function ( event ) {
// if enter is pressed, consider the title field altered. this is necessary because IE neglects
// to issue an onchange event when enter is pressed in an input field
if ( event.key().code == 13 &&
( this.suggest_pulldown == null || this.suggest_pulldown.something_selected() == false ) ) {
this.title_field_changed();
event.stop();
}
}
Link_pulldown.prototype.title_field_key_released = function ( event ) {
var self = this;
if ( this.suggest_pulldown ) {
this.suggest_pulldown.update_suggestions( this.title_field.value );
} else if ( event.key().code != 13 ) {
this.suggest_pulldown = new Suggest_pulldown( this.wiki, this.notebook_id, this.invoker, this.title_field, null, this.title_field.value, this.title_field );
connect( this.suggest_pulldown, "suggestion_selected", function ( note ) {
self.update_title_field_with_suggestion( note )
} );
}
}
Link_pulldown.prototype.update_position = function ( always_left_align ) {
Pulldown.prototype.update_position.call( this, always_left_align );
if ( this.suggest_pulldown )
this.suggest_pulldown.update_position( always_left_align );
}
Link_pulldown.prototype.shutdown = function () {
if ( this.suggest_pulldown )
this.suggest_pulldown.shutdown();
Pulldown.prototype.shutdown.call( this );
disconnectAll( this.title_field );
if ( this.link )
this.link.pulldown = null;
}
function base_upload_filename() {
// get the basename of the file
var filename = getElement( "upload" ).value;
var pieces = filename.split( "/" );
filename = pieces[ pieces.length - 1 ];
pieces = filename.split( "\\" );
filename = pieces[ pieces.length - 1 ];
return filename;
}
function Upload_pulldown( wiki, notebook_id, invoker, editor, link, anchor ) {
this.link = link || ( editor ? editor.find_link_at_cursor() : null );
if ( this.link )
this.link.pulldown = this;
Pulldown.call(
this, wiki, notebook_id,
"upload_" + ( editor ? editor.id : "import" ),
this.link || anchor,
editor ? editor.iframe : null,
false
);
wiki.down_image_button( "attachFile" );
this.invoker = invoker;
this.editor = editor;
this.iframe = createDOM( "iframe", {
"src": "about:blank",
"id": "upload_frame",
"name": "upload_frame",
"class": "upload_frame undisplayed"
} );
2008-02-01 22:44:01 +00:00
this.iframe.pulldown = this;
this.file_id = null;
this.uploading = false;
this.poller = null;
this.poll_interval = 250; // in milliseconds, expontentially backing off. see update_progress()
this.starting_count = 0;
var self = this;
appendChildNodes( this.div, this.iframe );
this.upload_area = createDOM( "span" );
this.upload_button = createDOM( "input", { "id": "upload_button", "type": "submit", "class": "button", "value": "upload" } );
appendChildNodes( this.upload_area, createDOM( "form",
{
"target": "upload_frame",
"action": "/files/upload?X-Progress-ID=new&file_id=new",
"method": "post",
"enctype": "multipart/form-data",
"id": "upload_form"
},
createDOM( "span", { "class": "field_label" }, this.link ? "attach file: " : "import file: " ),
createDOM( "input", { "name": "notebook_id", "id": "notebook_id", "type": "hidden", "value": notebook_id } ),
createDOM( "input", { "name": "note_id", "id": "note_id", "type": "hidden", "value": editor ? editor.id : "" } ),
createDOM( "input", { "name": "upload", "id": "upload", "type": "file", "class": "text_field", "size": "30" } ),
this.upload_button
) );
this.upload_button.disabled = true;
appendChildNodes( this.upload_area, createDOM( "div", { "class": "upload_instructions" },
this.link ? "Please select a file to upload." : "Please select a CSV file of notes to import into a new notebook." ) );
appendChildNodes( this.upload_area, createDOM( "span", { "id": "tick_preload" } ) );
appendChildNodes( this.upload_area, createDOM( "input", { "name": "file_id", "id": "file_id", "type": "hidden", "value": "new" } ) );
appendChildNodes( this.div, this.upload_area );
// for the benefit of Internet Explorer
getElement( "upload_form" ).encoding = "multipart/form-data";
connect( this.upload_button, "onclick", function ( event ) {
self.upload_started();
} );
// grab the next available file id
this.invoker.invoke( "/files/upload_id", "POST",
{ "notebook_id": notebook_id, "note_id": editor ? editor.id : "" },
function( result ) { self.update_file_id( result ); }
);
Pulldown.prototype.finish_init.call( this );
}
Upload_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Upload_pulldown.prototype.constructor = Upload_pulldown;
Upload_pulldown.prototype.update_file_id = function ( result ) {
this.file_id = result.file_id;
var upload_form = getElement( "upload_form" )
if ( upload_form )
upload_form.action = "/files/upload?X-Progress-ID=" + this.file_id;
var file_id_node = getElement( "file_id" );
if ( file_id_node )
file_id_node.value = this.file_id;
this.upload_button.disabled = false;
}
Upload_pulldown.prototype.upload_started = function ( file_id ) {
this.uploading = true;
var filename = base_upload_filename();
// if the current title is blank, replace the title with the upload's filename
if ( this.link ) {
var title = link_title( this.link );
if ( title == "" )
this.link.innerHTML = filename;
}
this.cancel_button = createDOM( "input", { "type": "submit", "id": "cancel_button", "class": "button", "value": "cancel" } );
var progress_area = createDOM( "table", {},
createDOM( "tbody", {},
createDOM( "tr", {},
createDOM( "td", { "class": "field_label", "colspan": "2" }, "uploading " + filename + ": " )
),
createDOM( "tr", { "id": "progress_row" },
createDOM( "td", {},
createDOM( "div", { "id": "progress_border" },
createDOM( "img", { "src": "/static/images/tick.png", "id": "progress_bar" } )
)
),
createDOM( "td", { "class": "progress_right" },
createDOM( "span", { "id": "progress_percent" }, "0%" ),
this.cancel_button
)
)
)
);
2008-02-19 00:47:59 +00:00
disconnectAll( this.upload_button );
addElementClass( this.upload_area, "undisplayed" );
appendChildNodes( this.div, progress_area );
this.upload_button = null;
var self = this;
connect( this.cancel_button, "onclick", function ( event ) {
self.cancel_due_to_click();
} );
// start polling for the upload progress
this.poller = setTimeout( function () { self.update_progress(); }, this.poll_interval );
}
Upload_pulldown.prototype.update_progress = function () {
var self = this;
var BAR_WIDTH_EM = 20.0;
this.invoker.invoke( "/files/progress", "GET",
{ "X-Progress-ID": this.file_id },
function( result ) {
var fraction_done = 0.0;
if ( !self.uploading )
return;
if ( result.state == "starting" )
self.starting_count += 1;
else
self.starting_count = 0;
// if ten consecutive "starting" states in a row, bail
if ( self.starting_count >= 15 ) {
self.cancel_due_to_error( "A timeout error occurred when uploading the file." );
return
}
if ( result.state == "error" ) {
if ( result.status == 413 )
self.cancel_due_to_quota();
else
self.cancel_due_to_error( "An error occurred when uploading the file." );
return;
}
if ( result.state == "uploading" && result.size > 0 ) {
fraction_done = Math.min( result.received / result.size, 1.0 );
if ( fraction_done > 0.99 )
fraction_done = 0.99;
} else if ( result.state == "done" ) {
fraction_done = 1.0;
}
if ( fraction_done > 0.0 ) {
var percent = fraction_done * 100.0;
setElementDimensions( "progress_bar", { "w": fraction_done * BAR_WIDTH_EM }, "em" );
replaceChildNodes( "progress_percent", parseInt( percent ) + "%" );
}
// the brief delay gives a brief moment for the progress bar to appear at 100%
if ( result.state == "done" )
setTimeout( function () { self.upload_complete(); }, 1 );
else {
// capped exponential back-off
var CAP = 2000;
if ( self.poll_interval < CAP ) {
self.poll_interval *= 1.1;
if ( self.poll_interval > CAP )
self.poll_interval = CAP;
}
this.poller = setTimeout( function () { self.update_progress(); }, self.poll_interval );
}
}
);
};
Upload_pulldown.prototype.upload_complete = function () {
if ( /MSIE/.test( navigator.userAgent ) )
var quote_filename = true;
else
var quote_filename = false;
// now that the upload is done, the file link should point to the uploaded file
this.uploading = false;
if ( this.link ) {
this.link.href = "/files/download?file_id=" + this.file_id + "&quote_filename=" + quote_filename;
new File_link_pulldown( this.wiki, this.notebook_id, this.invoker, this.editor, this.link );
// if there's no link, then assume a CSV file was imported, so display it
} else {
var wiki = this.wiki;
this.invoker.invoke(
"/files/csv_head", "GET", {
"file_id": this.file_id
},
function ( result ) { wiki.display_import_notebook( result ); }
);
}
this.shutdown();
}
Upload_pulldown.prototype.update_position = function ( always_left_align ) {
Pulldown.prototype.update_position.call( this, always_left_align );
}
Upload_pulldown.prototype.cancel_due_to_click = function () {
// when the uploading iframe closes, that should effectively cancel the upload
this.uploading = false;
this.wiki.display_message( "The file upload has been cancelled." )
this.shutdown();
}
Upload_pulldown.prototype.cancel_due_to_quota = function () {
this.uploading = false;
this.shutdown();
this.wiki.display_error(
"That file is too large for your available storage space. Before uploading, please delete some notes or files, empty the trash, or",
[ createDOM( "a", { "href": "/pricing" }, "upgrade" ), " your account." ]
);
}
Upload_pulldown.prototype.cancel_due_to_error = function ( message ) {
this.uploading = false;
this.wiki.display_error( message )
this.shutdown();
}
Upload_pulldown.prototype.shutdown = function () {
if ( this.uploading )
return;
if ( this.poller )
clearTimeout( this.poller );
if ( this.upload_button )
disconnectAll( this.upload_button );
if ( this.cancel_button )
disconnectAll( this.cancel_button );
// in Internet Explorer, the upload won't actually cancel without an explicit Stop command
if ( !this.iframe.contentDocument && this.iframe.contentWindow )
this.iframe.contentWindow.document.execCommand( 'Stop' );
Pulldown.prototype.shutdown.call( this );
if ( this.link )
this.link.pulldown = null;
}
function Export_pulldown( wiki, notebook_id, invoker, anchor ) {
Pulldown.call( this, wiki, notebook_id, "export_pulldown", anchor, null, false );
this.invoker = invoker;
this.html_link = createDOM( "a", {
"href": "/notebooks/export?notebook_id=" + notebook_id + "&format=html",
"class": "pulldown_label",
"title": "Download this notebook as a stand-alone HTML web page."
},
"HTML web page"
);
this.csv_link = createDOM( "a", {
"href": "/notebooks/export?notebook_id=" + notebook_id + "&format=csv",
"class": "pulldown_label",
"title": "Download this notebook as a CSV spreadsheet file."
},
"CSV spreadsheet"
);
appendChildNodes( this.div, createDOM( "div", {}, this.html_link ) );
appendChildNodes( this.div, createDOM( "div", {}, this.csv_link ) );
Pulldown.prototype.finish_init.call( this );
}
Export_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Export_pulldown.prototype.constructor = Export_pulldown;
Export_pulldown.prototype.shutdown = function () {
Pulldown.prototype.shutdown.call( this );
}
SMALL_MAX_IMAGE_SIZE = 125;
MEDIUM_MAX_IMAGE_SIZE = 300;
LARGE_MAX_IMAGE_SIZE = 500;
function File_link_pulldown( wiki, notebook_id, invoker, editor, link, ephemeral ) {
link.pulldown = this;
this.link = link;
Pulldown.call( this, wiki, notebook_id, "file_link_" + editor.id, link, editor.iframe, ephemeral );
this.invoker = invoker;
this.editor = editor;
this.filename_field = createDOM( "input", { "class": "text_field", "size": "30", "maxlength": "256" } );
this.file_size = createDOM( "span", {} );
this.previous_filename = "";
this.link_title = null;
2008-02-01 22:44:01 +00:00
var self = this;
connect( this.filename_field, "onclick", function ( event ) { self.filename_field_clicked( event ); } );
connect( this.filename_field, "onfocus", function ( event ) { self.filename_field_focused( event ); } );
connect( this.filename_field, "onchange", function ( event ) { self.filename_field_changed( event ); } );
connect( this.filename_field, "onblur", function ( event ) { self.filename_field_changed( event ); } );
connect( this.filename_field, "onkeydown", function ( event ) { self.filename_field_key_pressed( event ); } );
2008-02-01 22:44:01 +00:00
this.delete_button = createDOM( "input", {
"type": "button",
"class": "button",
"value": "delete",
"title": "delete file"
} );
var query = parse_query( link );
this.file_id = query.file_id;
if ( /MSIE/.test( navigator.userAgent ) )
var quote_filename = true;
else
var quote_filename = false;
this.thumbnail_span = createDOM( "span", {},
createDOM( "a", { href: "/files/download?file_id=" + this.file_id + "&quote_filename=" + quote_filename, target: "_new" },
createDOM( "img", { "src": "/files/thumbnail?file_id=" + this.file_id, "class": "file_thumbnail" } )
)
);
appendChildNodes( this.div, this.thumbnail_span );
// if the link is an image thumbnail link, update the contents of the file link pulldown accordingly
var image = getFirstElementByTagAndClassName( "img", null, this.link );
var embed_attributes = { "type": "checkbox", "class": "pulldown_checkbox", "id": "embed_checkbox" };
var small_size_attributes = { "type": "radio", "id": "small_size_radio", "name": "size", "value": "small" };
var medium_size_attributes = { "type": "radio", "id": "medium_size_radio", "name": "size", "value": "medium" };
var large_size_attributes = { "type": "radio", "id": "large_size_radio", "name": "size", "value": "large" };
var left_justify_attributes = { "type": "radio", "id": "left_justify_radio", "name": "justify", "value": "left" };
var center_justify_attributes = { "type": "radio", "id": "center_justify_radio", "name": "justify", "value": "center" };
var right_justify_attributes = { "type": "radio", "id": "right_justify_radio", "name": "justify", "value": "right" };
if ( image ) {
addElementClass( this.thumbnail_span, "undisplayed" );
embed_attributes[ "checked" ] = "true";
var src = parseQueryString( image.src.split( "?" ).pop() );
var max_size = src[ "max_size" ];
if ( max_size == LARGE_MAX_IMAGE_SIZE )
large_size_attributes[ "checked" ] = "true";
else if ( max_size == MEDIUM_MAX_IMAGE_SIZE )
medium_size_attributes[ "checked" ] = "true";
else
small_size_attributes[ "checked" ] = "true";
if ( hasElementClass( image, "center_justified" ) )
center_justify_attributes[ "checked" ] = "true";
else if ( hasElementClass( image, "right_justified" ) )
right_justify_attributes[ "checked" ] = "true";
else
left_justify_attributes[ "checked" ] = "true";
} else {
small_size_attributes[ "checked" ] = "true";
left_justify_attributes[ "checked" ] = "true";
}
this.embed_checkbox = createDOM( "input", embed_attributes );
this.small_size_radio = createDOM( "input", small_size_attributes );
this.medium_size_radio = createDOM( "input", medium_size_attributes );
this.large_size_radio = createDOM( "input", large_size_attributes );
this.left_justify_radio = createDOM( "input", left_justify_attributes );
this.center_justify_radio = createDOM( "input", center_justify_attributes );
this.right_justify_radio = createDOM( "input", right_justify_attributes );
var embed_label = createDOM( "label", { "for": "embed_checkbox", "class": "pulldown_label", "title": "Embed this image within the note itself." },
"show image within note"
);
var small_size_label = createDOM( "label",
{ "for": "small_size_radio", "class": "radio_label", "title": "Display a small thumbnail of this image." },
"small"
);
var medium_size_label = createDOM( "label",
{ "for": "medium_size_radio", "class": "radio_label", "title": "Display a medium thumbnail of this image." },
"medium"
);
var large_size_label = createDOM( "label",
{ "for": "large_size_radio", "class": "radio_label", "title": "Display a large thumbnail of this image." },
"large"
);
var left_justify_label = createDOM( "label",
{ "for": "left_justify_radio", "class": "radio_label", "title": "Left justify this image within the note." },
"left"
);
var center_justify_label = createDOM( "label",
{ "for": "center_justify_radio", "class": "radio_label", "title": "Center this image horizontally within the note." },
"center"
);
var right_justify_label = createDOM( "label",
{ "for": "right_justify_radio", "class": "radio_label", "title": "Right justify this image within the note." },
"right"
);
this.image_settings_area = createDOM( "div", { "class": "undisplayed" },
createDOM( "table" , { "id": "image_settings_table" },
createDOM( "tbody", {},
createDOM( "tr", {},
createDOM( "td", { "class": "field_label" }, "size: " ),
createDOM( "td", {}, this.small_size_radio, small_size_label ),
createDOM( "td", {}, this.medium_size_radio, medium_size_label ),
createDOM( "td", {}, this.large_size_radio, large_size_label )
),
createDOM( "tr", {},
createDOM( "td", { "class": "field_label" }, "position: " ),
createDOM( "td", {}, this.left_justify_radio, left_justify_label ),
createDOM( "td", {}, this.center_justify_radio, center_justify_label ),
createDOM( "td", {}, this.right_justify_radio, right_justify_label )
)
)
)
);
if ( image )
removeElementClass( this.image_settings_area, "undisplayed" );
appendChildNodes( this.div, createDOM( "span", { "class": "field_label" }, "filename: " ) );
appendChildNodes( this.div, this.filename_field );
appendChildNodes( this.div, this.file_size );
appendChildNodes( this.div, " " );
appendChildNodes( this.div, this.delete_button );
appendChildNodes( this.div, createDOM( "div", {}, this.embed_checkbox, embed_label ) );
appendChildNodes( this.div, this.image_settings_area );
// get the file's name and size from the server
this.invoker.invoke(
"/files/stats", "GET", {
"file_id": this.file_id
},
function ( result ) {
// if the user has already started typing something, don't overwrite it
if ( self.filename_field.value.length == 0 ) {
self.filename_field.value = result.filename;
self.previous_filename = result.filename;
}
replaceChildNodes( self.file_size, bytes_to_megabytes( result.size_bytes, true ) );
self.wiki.display_storage_usage( result.storage_bytes );
}
);
2008-02-19 00:47:59 +00:00
connect( this.delete_button, "onclick", function ( event ) { self.delete_button_clicked( event ); } );
connect( this.embed_checkbox, "onclick", function ( event ) { self.embed_clicked( event ); } );
connect( this.small_size_radio, "onclick", function ( event ) { self.resize_image( event, "small" ); } );
connect( this.medium_size_radio, "onclick", function ( event ) { self.resize_image( event, "medium" ); } );
connect( this.large_size_radio, "onclick", function ( event ) { self.resize_image( event, "large" ); } );
connect( this.left_justify_radio, "onclick", function ( event ) { self.justify_image( event, "left" ); } );
connect( this.center_justify_radio, "onclick", function ( event ) { self.justify_image( event, "center" ); } );
connect( this.right_justify_radio, "onclick", function ( event ) { self.justify_image( event, "right" ); } );
2008-02-19 00:47:59 +00:00
editor.focus();
Pulldown.prototype.finish_init.call( this );
}
File_link_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
File_link_pulldown.prototype.constructor = File_link_pulldown;
File_link_pulldown.prototype.filename_field_clicked = function ( event ) {
event.stop();
}
File_link_pulldown.prototype.filename_field_focused = function ( event ) {
this.filename_field.select();
}
File_link_pulldown.prototype.filename_field_changed = function ( event ) {
// if the filename is actually unchanged, then bail
var filename = strip( this.filename_field.value );
if ( filename == "" || filename == this.previous_filename )
return;
var title = link_title( this.link );
if ( title == this.previous_filename )
replaceChildNodes( this.link, this.editor.document.createTextNode( filename ) );
this.previous_filename = filename;
this.invoker.invoke(
"/files/rename", "POST", {
"file_id": this.file_id,
"filename": filename
}
);
}
File_link_pulldown.prototype.filename_field_key_pressed = function ( event ) {
// if enter is pressed, consider the title field altered. this is necessary because IE neglects
// to issue an onchange event when enter is pressed in an input field
if ( event.key().code == 13 ) {
this.filename_field_changed();
event.stop();
}
}
File_link_pulldown.prototype.delete_button_clicked = function ( event ) {
var self = this;
// change the embedded image (if any) back into a plain file link before deletion
if ( getFirstElementByTagAndClassName( "img", null, this.link ) )
this.link.innerHTML = this.link_title || this.filename_field.value || this.previous_filename;
this.invoker.invoke(
"/files/delete", "POST", {
"file_id": this.file_id
},
function ( result ) { self.wiki.display_storage_usage( result.storage_bytes ); }
);
this.link.href = "/files/new";
this.editor.focus();
this.wiki.display_message( 'The file "' + strip( this.filename_field.value ) + '" has been deleted.' );
}
File_link_pulldown.prototype.embed_clicked = function ( event ) {
if ( this.embed_checkbox.checked ) {
var image = createDOM( "img", { "src": "/files/thumbnail?file_id=" + this.file_id + "&max_size=" + SMALL_MAX_IMAGE_SIZE, "class": "left_justified" } );
var image_span = createDOM( "span", {}, image );
this.link_title = link_title( this.link );
this.link.innerHTML = image_span.innerHTML;
addElementClass( this.thumbnail_span, "undisplayed" );
removeElementClass( this.image_settings_area, "undisplayed" );
} else {
this.justify_image( "left" );
this.left_justify_radio.checked = true;
this.small_size_radio.checked = true;
removeElementClass( this.thumbnail_span, "undisplayed" );
addElementClass( this.image_settings_area, "undisplayed" );
this.link.innerHTML = this.link_title || this.filename_field.value || this.previous_filename;
}
this.update_position();
this.editor.resize();
}
File_link_pulldown.prototype.resize_image = function ( event, position ) {
var image = getFirstElementByTagAndClassName( "img", null, this.link );
if ( !image )
return;
if ( position == "large" ) {
var max_size = LARGE_MAX_IMAGE_SIZE;
} else if ( position == "medium" ) {
var max_size = MEDIUM_MAX_IMAGE_SIZE;
} else {
var max_size = SMALL_MAX_IMAGE_SIZE;
}
// when the newly resized image finishes loading, update the pulldown position and resize the
// editor
var self = this;
connect( image, "onload", function () {
self.update_position();
self.editor.resize();
} );
image.setAttribute( "src", "/files/thumbnail?file_id=" + this.file_id + "&max_size=" + max_size );
}
File_link_pulldown.prototype.justify_image = function ( event, position ) {
var image = getFirstElementByTagAndClassName( "img", null, this.link );
if ( !image )
return;
removeElementClass( image, "left_justified" );
removeElementClass( image, "center_justified" );
removeElementClass( image, "right_justified" );
addElementClass( image, position + "_justified" );
this.update_position();
this.editor.resize();
}
File_link_pulldown.prototype.update_position = function ( always_left_align ) {
Pulldown.prototype.update_position.call( this, always_left_align );
}
File_link_pulldown.prototype.shutdown = function () {
Pulldown.prototype.shutdown.call( this );
disconnectAll( this.filename_field );
if ( this.link )
this.link.pulldown = null;
disconnectAll( this.delete_button );
disconnectAll( this.embed_checkbox );
disconnectAll( this.left_justify_radio );
disconnectAll( this.center_justify_radio );
disconnectAll( this.right_justify_radio );
}
function Suggest_pulldown( wiki, notebook_id, invoker, anchor, relative_to, search_text, key_press_node ) {
anchor.pulldown = this;
this.anchor = anchor;
this.previous_search_text = "";
this.sequence_number = 0;
Pulldown.call( this, wiki, notebook_id, "suggest_pulldown", anchor, relative_to );
this.invoker = invoker;
this.update_suggestions( search_text );
var self = this;
this.key_handler = connect( key_press_node, "onkeydown", function ( event ) { self.key_pressed( event ); } );
Pulldown.prototype.update_position.call( this, true );
}
Suggest_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Suggest_pulldown.prototype.constructor = Suggest_pulldown;
Suggest_pulldown.prototype.update_suggestions = function ( search_text ) {
// if the search text hasn't changed since last time, bail
if ( this.previous_search_text == search_text )
return;
// if there is no search text, hide the pulldown and bail
if ( !search_text ) {
addElementClass( this.div, "invisible" );
this.previous_search_text = "";
return;
}
var self = this;
this.previous_search_text = search_text;
this.sequence_number += 1;
var sequence_number = this.sequence_number;
this.invoker.invoke( "/notebooks/search_titles", "GET", {
"notebook_id": this.notebook_id,
"search_text": search_text
},
function( result ) {
// if the sequence number is not what we expect, then this must not be most recent suggests
// update, so bail without displaying the result
if ( self.sequence_number != sequence_number )
return;
self.display_suggestions( result, search_text );
}
);
}
Suggest_pulldown.prototype.display_suggestions = function ( result, search_text ) {
if ( result.notes.length == 0 ) {
addElementClass( this.div, "invisible" );
return;
}
removeElementClass( this.div, "invisible" );
var results_list = createDOM( "div" );
var self = this;
function connect_link( suggest_link, note ) {
connect( suggest_link, "onclick", function ( event ) { self.suggestion_selected( event, note ); } );
}
for ( var i in result.notes ) {
var note = result.notes[ i ];
if ( !note.title ) continue;
var suggest_link = createDOM( "a", { "href": "#", "class": "pulldown_link" } );
suggest_link.innerHTML = note.summary;
suggest_link.note = note;
appendChildNodes( results_list, createDOM( "div", { "class": "suggestion" }, suggest_link ) );
connect_link( suggest_link, note );
}
replaceChildNodes( this.div, results_list );
}
Suggest_pulldown.prototype.suggestion_selected = function ( event, note ) {
event.stop();
signal( this, "suggestion_selected", note );
}
Suggest_pulldown.prototype.key_pressed = function ( event ) {
// an invisible Suggest_pulldown shouldn't grab keypresses
if ( hasElementClass( this.div, "invisible" ) )
return;
var code = event.key().code;
var selected = getFirstElementByTagAndClassName( "div", "selected_suggestion", this.div );
// up arrow or shift-tab: move up to the previous suggestion
if ( code == 38 || ( code == 9 && event.modifier().shift ) ) {
this.previous_suggestion( selected );
// down arrow or tab: move down to the previous suggestion
} else if ( code == 40 || code == 9 ) {
this.next_suggestion( selected );
// enter: select current suggestion
} else if ( code == 13 ) {
var suggest_link = getFirstElementByTagAndClassName( "a", "pulldown_link", selected );
if ( selected )
this.suggestion_selected( event, suggest_link.note );
else // if nothing is selected, don't handle enter
return;
// escape: hide the suggestions
} else if ( code == 27 ) {
addElementClass( this.div, "invisible" );
// otherwise, not a key this method handles
} else {
return;
}
event.stop();
}
Suggest_pulldown.prototype.previous_suggestion = function ( selected ) {
// if something is selected and there's a previous suggestion in the list, move the selection up
if ( selected && selected.previousSibling ) {
removeElementClass( selected, "selected_suggestion" );
addElementClass( selected.previousSibling, "selected_suggestion" );
// otherwise, hide the Suggest_pulldown
} else {
addElementClass( this.div, "invisible" );
}
}
Suggest_pulldown.prototype.next_suggestion = function ( selected ) {
// if something is selected and there's a next suggestion in the list, move the selection down
if ( selected ) {
if ( selected.nextSibling ) {
removeElementClass( selected, "selected_suggestion" );
addElementClass( selected.nextSibling, "selected_suggestion" );
}
// if nothing is selected yet, then just select the first link
} else {
var suggest_link = getFirstElementByTagAndClassName( "a", "pulldown_link", this.div );
addElementClass( suggest_link.parentNode, "selected_suggestion" );
}
}
Suggest_pulldown.prototype.update_position = function ( always_left_align ) {
// ignore the requested always_left_align value and force it to true, since Suggest_pulldown
// looks better that way
Pulldown.prototype.update_position.call( this, true );
}
Suggest_pulldown.prototype.something_selected = function () {
if ( hasElementClass( this.div, "invisible" ) )
return false;
var selected = getFirstElementByTagAndClassName( "div", "selected_suggestion", this.div );
if ( selected )
return true;
return false;
}
Suggest_pulldown.prototype.visible = function () {
return !hasElementClass( this.div, "invisible" );
}
Suggest_pulldown.prototype.shutdown = function () {
Pulldown.prototype.shutdown.call( this );
this.anchor.pulldown = null;
disconnectAll( this );
disconnect( this.key_handler );
}
NAMED_COLORS = [
[ "#000000", "black" ],
[ "#333333", "steel gray" ],
[ "#696969", "dim gray" ],
[ "#808080", "gray" ],
[ "#a9a9a9", "dark gray" ],
[ "#d3d3d3", "light gray" ],
[ "#f5f5f5", "white smoke" ],
[ "#ffffff", "white" ],
[ "#800000", "maroon" ],
[ "#8b0000", "dark red" ],
[ "#b22222", "fire brick" ],
[ "#dc143c", "crimson" ],
[ "#ff0000", "red" ],
[ "#ff4500", "orange red" ],
[ "#ff6347", "tomato" ],
[ "#ffa07a", "light salmon" ],
[ "#8b4513", "saddle brown" ],
[ "#a52a2a", "brown" ],
[ "#a0522d", "sienna" ],
[ "#d2691e", "chocolate" ],
[ "#ff8c00", "dark orange" ],
[ "#ffa500", "orange" ],
[ "#ffd700", "gold" ],
[ "#ffff00", "yellow" ],
[ "#556b2f", "dark olive green" ],
[ "#006400", "dark green" ],
[ "#008000", "green" ],
[ "#2e8b57", "sea green" ],
[ "#32cd32", "lime green" ],
[ "#00ff00", "lime" ],
[ "#7cfc00", "lawn green" ],
[ "#98fb98", "pale green" ],
[ "#008b8b", "dark cyan" ],
[ "#20b2aa", "light sea green" ],
[ "#00ced1", "dark turquoise" ],
[ "#66cdaa", "medium aquamarine" ],
[ "#40e0d0", "turquoise" ],
[ "#00ffff", "cyan" ],
[ "#7fffd4", "aquamarine" ],
[ "#afeeee", "pale turquoise" ],
[ "#191970", "midnight blue" ],
[ "#000080", "navy" ],
[ "#0000ff", "blue" ],
[ "#4169e1", "royal blue" ],
[ "#4682b4", "steel blue" ],
[ "#6495ed", "cornflower blue" ],
[ "#87ceeb", "sky blue" ],
[ "#add8e6", "light blue" ],
[ "#4b0082", "indigo" ],
[ "#800080", "purple" ],
[ "#9400d3", "dark violet" ],
[ "#8a2be2", "blue violet" ],
[ "#ba55d3", "medium orchid" ],
[ "#da70d6", "orchid" ],
[ "#ee82ee", "violet" ],
[ "#dda0dd", "plum" ],
[ "#c71585", "medium violet red" ],
[ "#ff1493", "deep pink" ],
[ "#db7093", "pale violet red" ],
[ "#ff69b4", "hot pink" ],
[ "#ffb6c1", "light pink" ],
[ "#ffc0cb", "pink" ],
[ "#ffdab9", "peach puff" ],
[ "#ffe4e1", "misty rose" ],
]
function Color_pulldown( wiki, notebook_id, invoker, anchor, editor ) {
anchor.pulldown = this;
this.anchor = anchor;
this.editor = editor;
this.selected_color_box = null;
Pulldown.call( this, wiki, notebook_id, "color_pulldown", anchor, null, false, true );
this.invoker = invoker;
this.detect_colors();
var foreground_attributes = { "type": "radio", "id": "foreground_color_radio", "name": "color_type", "value": "foreground" };
this.foreground_radio = createDOM( "input", foreground_attributes );
// using a button here instead of a <label> to make IE happy: when a <label> is used, clicking
// on the label steals focus from the editor iframe and prevents the color from being changed
this.foreground_label = createDOM( "input",
{ "type": "button", "class": "radio_label small_button", "value": "text", "title": "Set the current text color." }
);
var background_attributes = { "type": "radio", "id": "background_color_radio", "name": "color_type", "value": "background" };
this.background_radio = createDOM( "input", background_attributes );
this.background_label = createDOM( "input",
{ "type": "button", "class": "radio_label small_button", "value": "background", "title": "Set the current background color." }
);
var radio_area = createDOM( "div", {},
this.foreground_radio, this.foreground_label,
2009-05-15 23:03:51 +00:00
createDOM( "span", { "class": "radio_spacer" } ),
this.background_radio, this.background_label
);
var tbody = createDOM( "tbody", {} );
this.table = createDOM( "table" , { "id": "color_table" }, tbody );
var color_index = 0;
for ( var i = 0; i < 8; ++i ) {
var row_node = createDOM( "tr", {} );
for ( var j = 0; j < 8; ++j ) {
if ( color_index >= NAMED_COLORS.length )
break;
var color_pair = NAMED_COLORS[ color_index ];
var color_code = color_pair[ 0 ];
var color_name = color_pair[ 1 ];
var color_box = createDOM( "td", {},
createDOM( "input", {
"type": "button", "class": "color_box",
"id": "color_" + color_code.substring( 1 ),
"style": "background-color: " + color_code + ";", "title": color_name
} )
);
appendChildNodes( row_node, color_box );
++color_index;
}
appendChildNodes( tbody, row_node );
}
this.done_button = createDOM(
"input", {
"type": "button",
"class": "button",
"value": "done",
"title": "done changing colors"
}
);
this.preview_area = createDOM( "span", { "class": "color_preview_text" }, "Preview" );
var bottom_area = createDOM( "div", {}, this.preview_area, this.done_button );
var div = createDOM( "div", {}, radio_area, this.table, bottom_area );
appendChildNodes( this.div, div );
this.update_colors();
var self = this;
connect( this.table, "onmousedown", function ( event ) { self.color_mouse_pressed( event ); } );
connect( this.table, "onmouseup", function ( event ) { self.color_mouse_released( event ); } );
connect( this.table, "onmouseover", function ( event ) { self.color_mouse_hovered( event ); } );
connect( this.table, "onmouseout", function ( event ) { self.color_mouse_left( event ); } );
connect( this.foreground_radio, "onclick", function ( event ) { self.foreground_radio_clicked( event ); } );
2009-05-15 23:03:51 +00:00
connect( this.foreground_label, "onclick", function ( event ) { self.foreground_radio_clicked( event ); event.stop(); } );
connect( this.background_radio, "onclick", function ( event ) { self.background_radio_clicked( event ); } );
2009-05-15 23:03:51 +00:00
connect( this.background_label, "onclick", function ( event ) { self.background_radio_clicked( event ); event.stop(); } );
connect( this.done_button, "onclick", function ( event ) { self.shutdown(); } );
Pulldown.prototype.finish_init.call( this );
}
Color_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Color_pulldown.prototype.constructor = Color_pulldown;
Color_pulldown.prototype.detect_colors = function () {
var current_colors = this.editor.current_colors();
this.foreground_code = current_colors[ 0 ];
if ( this.foreground_code == DEFAULT_FOREGROUND_CODE )
this.foreground_code = null;
this.background_code = current_colors[ 1 ];
if ( this.background_code == DEFAULT_BACKGROUND_CODE )
this.background_code = null;
}
Color_pulldown.prototype.update_colors = function () {
if ( this.foreground_code || !this.background_code ) {
this.foreground_code = this.foreground_code || DEFAULT_FOREGROUND_CODE;
this.background_code = this.background_code || DEFAULT_BACKGROUND_CODE;
this.foreground_radio_clicked();
} else {
this.foreground_code = this.foreground_code || DEFAULT_FOREGROUND_CODE;
this.background_code = this.background_code || DEFAULT_BACKGROUND_CODE;
this.background_radio_clicked();
}
}
Color_pulldown.prototype.show = function () {
this.editor = this.wiki.focused_editor;
this.detect_colors();
this.update_colors();
Pulldown.prototype.update_position.call( this );
removeElementClass( this.div, "invisible" );
}
Color_pulldown.prototype.hide = function () {
addElementClass( this.div, "invisible" );
}
Color_pulldown.prototype.color_mouse_pressed = function ( event ) {
var color_box = event.target();
if ( !hasElementClass( color_box, "color_box" ) )
return;
this.select_color_box( color_box );
event.stop();
}
Color_pulldown.prototype.color_mouse_released = function ( event ) {
event.stop();
}
Color_pulldown.prototype.color_mouse_hovered = function ( event ) {
var color_box = event.target();
if ( !hasElementClass( color_box, "color_box" ) )
return;
var color_code = getStyle( color_box, "background-color" );
if ( this.background_radio.checked )
setStyle( this.preview_area, { "background-color": color_code } );
else
setStyle( this.preview_area, { "color": color_code } );
}
Color_pulldown.prototype.color_mouse_left = function ( event ) {
setStyle( this.preview_area, { "color": this.foreground_code } );
setStyle( this.preview_area, { "background-color": this.background_code } );
}
Color_pulldown.prototype.select_color = function ( color_code, skip_set ) {
var color_box = getElement( "color_" + color_code.substring( 1 ) );
if ( color_box )
this.select_color_box( color_box, color_code );
}
Color_pulldown.prototype.select_color_box = function ( color_box, color_code ) {
if ( this.selected_color_box ) {
this.selected_color_box.value = " ";
removeElementClass( this.selected_color_box, "color_box_light_selected" );
removeElementClass( this.selected_color_box, "color_box_dark_selected" );
}
if ( color_code == undefined || color_code == null )
color_code = getStyle( color_box, "background-color" );
var LIGHT_DARK_THRESHOLD = 0.45;
if ( Color.fromString( color_code ).asHSL().l >= LIGHT_DARK_THRESHOLD )
addElementClass( color_box, "color_box_light_selected" );
else
addElementClass( color_box, "color_box_dark_selected" );
color_box.value = "x";
this.selected_color_box = color_box;
if ( this.background_radio.checked )
this.background_code = color_code;
else
this.foreground_code = color_code;
setStyle( this.preview_area, { "color": this.foreground_code } );
setStyle( this.preview_area, { "background-color": this.background_code } );
}
Color_pulldown.prototype.foreground_radio_clicked = function ( event ) {
this.foreground_radio.checked = true;
this.select_color( this.foreground_code, true );
}
Color_pulldown.prototype.background_radio_clicked = function ( event ) {
this.background_radio.checked = true;
this.select_color( this.background_code, true );
}
Color_pulldown.prototype.shutdown = function () {
if ( !hasElementClass( this.div, "invisible" ) ) {
this.editor.focus();
if ( this.foreground_code )
this.editor.set_foreground_color( this.foreground_code );
if ( this.background_code )
this.editor.set_background_color( this.background_code );
this.editor.collapse_cursor();
}
if ( !Pulldown.prototype.shutdown.call( this ) )
return; // "real" shutdown vetoed
this.anchor.pulldown = null;
disconnectAll( this.table );
disconnectAll( this.done_button );
disconnectAll( this );
}
function Font_pulldown( wiki, notebook_id, invoker, anchor, editor ) {
anchor.pulldown = this;
this.anchor = anchor;
this.editor = editor;
this.initial_selected_mark = null;
Pulldown.call( this, wiki, notebook_id, "font_pulldown", anchor );
this.invoker = invoker;
var fonts = [
[ "Arial", "arial,sans-serif" ],
[ "Times New Roman", "times new roman,serif" ],
[ "Courier", "courier new,monospace" ],
[ "Comic Sans", "comic sans ms,sans-serif" ],
[ "Garamond", "garamond,serif" ],
[ "Georgia", "georgia,serif" ],
[ "Tahoma", "tahoma,sans-serif" ],
[ "Trebuchet", "trebuchet ms,sans-serif" ],
[ "Verdana", "verdana,sans-serif" ]
];
var self = this;
var current_font_family = editor.query_command_value( "fontname" );
2008-12-23 07:26:01 +00:00
if ( current_font_family ) {
current_font_family = current_font_family.toLowerCase();
current_font_family = current_font_family.replace( /'/g, "" ).replace( /-webkit-/, "" );
current_font_family = current_font_family.split( ',' )[ 0 ];
2008-12-23 07:26:01 +00:00
}
for ( var i in fonts ) {
var font = fonts[ i ];
var font_name = font[ 0 ];
var font_family = font[ 1 ];
// using a button here instead of a <label> to make IE happy: when a <label> is used, clicking
// on the label steals focus from the editor iframe and prevents the font from being changed
var label = createDOM( "input", { "type": "button", "value": font_name, "class": "pulldown_label font_label_button", "style": "font-family: " + font_family + ";" } );
var selected_mark_char = document.createTextNode( "\u25cf" );
if ( current_font_family && font_family.search( current_font_family ) == 0 ) {
var selected_mark = createDOM( "span", { "class": "selected_mark" }, selected_mark_char );
this.initial_selected_mark = selected_mark;
} else {
var selected_mark = createDOM( "span", { "class": "selected_mark invisible" }, selected_mark_char );
}
var div = createDOM( "div", {}, selected_mark, " ", label );
label.font_family = font_family;
label.selected_mark = selected_mark;
appendChildNodes( this.div, div );
connect( label, "onclick", function ( event ) { self.font_name_clicked( event ); } );
}
Pulldown.prototype.finish_init.call( this );
}
Font_pulldown.prototype = new function () { this.prototype = Pulldown.prototype; };
Font_pulldown.prototype.constructor = Font_pulldown;
Font_pulldown.prototype.font_name_clicked = function ( event ) {
var label = event.src();
if ( this.initial_selected_mark )
addElementClass( this.initial_selected_mark, "invisible" );
removeElementClass( label.selected_mark, "invisible" );
var self = this;
setTimeout( function () {
self.editor.focus();
self.editor.exec_command( "fontname", label.font_family );
self.shutdown();
}, 100 );
}
Font_pulldown.prototype.shutdown = function () {
Pulldown.prototype.shutdown.call( this );
this.anchor.pulldown = null;
disconnectAll( this );
}
function Note_tree( wiki, notebook_id, invoker ) {
this.wiki = wiki;
this.notebook_id = notebook_id;
this.invoker = invoker;
this.suggest_pulldown = null;
// add onclick handlers to the initial note links within the tree
var links = getElementsByTagAndClassName( "a", "note_tree_link", "note_tree_area" );
var self = this;
function connect_expander( note_id ) {
connect( "note_tree_expander_" + note_id, "onclick", function ( event ) { self.expand_collapse_link( event, note_id ); } );
}
for ( var i in links ) {
var link = links[ i ];
var query = parse_query( link );
var note_id = query[ "note_id" ];
if ( note_id )
connect_expander( note_id );
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_root_link( editor.id, editor.title, editor.contents(), editor.startup ); } );
connect( wiki, "note_removed", function ( id ) { self.remove_link( id ); } );
connect( wiki, "note_saved", function ( editor ) { self.update_link( editor ); } );
}
Note_tree.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();
}
LINK_PATTERN = /<a\s+([^>]+\s)?href="[^"]+"[^>]*>/i;
Note_tree.prototype.add_root_link = function ( note_id, title, contents, startup ) {
// for now, only add startup notes to the note tree
if ( !startup )
return;
// if the root note is already present in the tree, no need to add it again
var item = getElement( "note_tree_item_" + note_id );
if ( item ) {
new Highlight( item, { "endcolor": "#fafafa" } );
return;
}
// display the tree expander arrow if the given note's contents contains any outgoing links
if ( LINK_PATTERN.exec( contents ) )
var expander = createDOM( "div", { "class": "tree_expander", "id": "note_tree_expander_" + note_id } );
else
var expander = createDOM( "div", { "class": "tree_expander_empty", "id": "note_tree_expander_" + note_id } );
var link = createDOM( "a", {
"href": "/notebooks/" + this.notebook_id + "?note_id=" + note_id,
"id": "note_tree_link_" + note_id,
"class": "note_tree_link"
}, normalize_title( title ) );
insertSiblingNodesBefore( "new_note_tree_link_row", createDOM(
"tr",
{ "id": "note_tree_item_" + note_id, "class": "note_tree_item" },
createDOM( "td", {}, expander ),
createDOM( "td", {}, link )
) );
var self = this;
connect( expander, "onclick", function ( event ) { self.expand_collapse_link( event, note_id ); } );
connect( link, "onclick", function ( event ) { self.link_clicked( event ); } );
}
Note_tree.prototype.remove_link = function ( note_id ) {
var item = getElement( "note_tree_item_" + note_id );
if ( item )
removeElement( item );
if ( getFirstElementByTagAndClassName( "a", null, "note_tree_root_table" ) )
return;
}
Note_tree.prototype.rename_link = function ( editor, new_title ) {
var link = getElement( "note_tree_link_" + editor.id );
if ( link )
replaceChildNodes( link, normalize_title( new_title ) );
}
Note_tree.prototype.update_link = function ( editor ) {
var link = getElement( "note_tree_link_" + editor.id );
if ( !link && editor.startup ) {
this.add_root_link( editor.id, editor.title, editor.contents(), editor.startup );
return;
}
if ( link && !editor.startup )
this.remove_link( editor.id );
// if the tree has any expanded links to the given editor's note, then update the children of
// those links
function update_links( note_tree, notebook_id, note_id, link, children_area ) {
note_tree.invoker.invoke(
"/notebooks/load_note_links", "GET", {
"notebook_id": notebook_id,
"note_id": note_id
},
function ( result ) { note_tree.display_child_links( result, link, children_area ); }
);
}
var links = getElementsByTagAndClassName( "a", null, "note_tree_root_table" );
for ( var i in links ) {
var link = links[ i ]
var note_id = parse_query( link )[ "note_id" ];
var children_area = getFirstElementByTagAndClassName( "div", "note_tree_children_area", link.parentNode );
if ( note_id != editor.id )
continue;
update_links( this, this.notebook_id, editor.id, link, children_area );
}
}
Note_tree.prototype.expand_collapse_link = function ( event, note_id ) {
var expander = event.target();
if ( !expander || hasElementClass( expander, "tree_expander_empty" ) )
return;
// if it's collapsed, expand it
if ( hasElementClass( expander, "tree_expander" ) ) {
// first check if the expander is for a link to a parent/grandparent/etc. if so, just highlight
// the containing table instead of performing an expansion
var parent_node = expander.parentNode.parentNode;
while ( !hasElementClass( parent_node, "note_tree_root_table" ) ) {
parent_node = parent_node.parentNode;
if ( !parent_node ) break;
var parent_link = parent_node.previousSibling;
if ( !parent_link || !hasElementClass( parent_link, "note_tree_link" ) ) continue;
var parent_note_id = parse_query( parent_link )[ "note_id" ];
if ( note_id == parent_note_id ) {
new Highlight( parent_node.parentNode, { "endcolor": "#fafafa" } );
return;
}
}
var children_area = createDOM( "div", { "class": "note_tree_children_area" },
createDOM( "span", { "class": "note_tree_loading" }, "loading..." )
);
swapElementClass( expander, "tree_expander", "tree_expander_expanded" );
var link = getFirstElementByTagAndClassName( "a", null, expander.parentNode.parentNode );
insertSiblingNodesAfter( link, children_area );
var self = this;
this.invoker.invoke(
"/notebooks/load_note_links", "GET", {
"notebook_id": this.notebook_id,
"note_id": note_id
},
function ( result ) { self.display_child_links( result, link, children_area ); }
);
return;
}
// if it's expanded, collapse it
if ( hasElementClass( expander, "tree_expander_expanded" ) ) {
swapElementClass( expander, "tree_expander_expanded", "tree_expander" );
var children = getFirstElementByTagAndClassName( "div", "note_tree_children_area", expander.parentNode.parentNode );
if ( children )
removeElement( children );
}
}
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_collapse_link( event, note_id ); } );
}
var span = createDOM( "span" );
span.innerHTML = result.tree_html;
// if there's a children area, replace its contents and add an onclick handler for each newly
// loaded expander and each note link
if ( children_area ) {
replaceChildNodes( children_area, span );
var child_links = getElementsByTagAndClassName( "a", null, children_area );
for ( var i in child_links ) {
var child_link = child_links[ i ];
connect( child_link, "onclick", function ( event ) { self.link_clicked( event ); } );
var expander = getFirstElementByTagAndClassName( "div", "tree_expander", child_link.parentNode.parentNode );
if ( expander ) {
var note_id = parse_query( child_link )[ "note_id" ];
if ( note_id )
connect_expander( expander, note_id );
}
}
} else {
var child_links = getElementsByTagAndClassName( "a", null, span );
}
// if the parent has no children anymore, remove its expander arrow
if ( child_links.length == 0 ) {
if ( children_area )
removeElement( children_area );
var expander = getFirstElementByTagAndClassName( "div", "tree_expander", link.parentNode.parentNode );
if ( expander && link.parentNode.parentNode == expander.parentNode.parentNode ) {
swapElementClass( expander, "tree_expander", "tree_expander_empty" );
disconnectAll( expander );
return;
}
expander = getFirstElementByTagAndClassName( "div", "tree_expander_expanded", link.parentNode.parentNode );
if ( expander && link.parentNode.parentNode == expander.parentNode.parentNode ) {
swapElementClass( expander, "tree_expander_expanded", "tree_expander_empty" );
disconnectAll( expander );
return
}
return;
}
// if a note without an expander arrow now has children, add an expander arrow for it
var expander = getFirstElementByTagAndClassName( "div", "tree_expander_empty", link.parentNode.parentNode );
if ( !expander || link.parentNode.parentNode != expander.parentNode.parentNode ) return;
swapElementClass( expander, "tree_expander_empty", "tree_expander" );
var note_id = parse_query( link )[ "note_id" ];
disconnectAll( expander );
connect_expander( expander, note_id );
}
Note_tree.prototype.move_link = function ( editor, position_after, position_before ) {
var item = getElement( "note_tree_item_" + editor.id );
if ( position_after ) {
var after_item = getElement( "note_tree_item_" + position_after.id );
insertSiblingNodesAfter( after_item, item );
} else if ( position_before ) {
var before_item = getElement( "note_tree_item_" + position_before.id );
insertSiblingNodesBefore( before_item, item );
}
}
Note_tree.prototype.start_link_add = function () {
// if the add is already in progress, end the add instead of starting one
var new_note_tree_link_field = getElement( "new_note_tree_link_field" );
if ( new_note_tree_link_field ) {
this.end_link_add();
return;
}
addElementClass( "new_note_tree_link_button", "undisplayed" );
link_field = createDOM(
"input", {
"type": "text",
"value": "",
"id": "new_note_tree_link_field",
"name": "new_note_tree_link_field",
"title": "Enter the title of an existing note.",
"size": "10",
"autocomplete": "off",
"class": "text_field"
}
);
var ok_button = createDOM(
"input", {
"type": "button",
"class": "message_button",
"value": "add",
"title": "add the note"
}
);
var form = createDOM(
"form", { "id": "new_note_tree_link_form", "class": "inline" }, link_field, ok_button
);
replaceChildNodes( "new_note_tree_link_area", form );
// add a suggest pulldown beneath the link name text field
var self = this;
this.suggest_pulldown = new Suggest_pulldown(
this.wiki, this.notebook_id, this.invoker, link_field, null, "", link_field
);
connect( this.suggest_pulldown, "suggestion_selected", function ( note ) {
self.end_link_add( note );
} );
connect( form, "onsubmit", function ( event ) {
self.end_link_add();
event.stop();
} );
connect( form, "onkeyup", function ( event ) {
self.suggest_pulldown.update_suggestions( link_field.value );
} );
connect( ok_button, "onclick", function ( event ) {
self.end_link_add();
event.stop();
} );
link_field.focus();
link_field.select();
}
Note_tree.prototype.end_link_add = function ( note ) {
removeElementClass( "new_note_tree_link_button", "undisplayed" );
// if no note is provided, load it based on the title
if ( !note ) {
var note_name = getElement( "new_note_tree_link_field" ).value;
replaceChildNodes( "new_note_tree_link_area", "" );
// if the new name is blank, bail
if ( /^\s*$/.test( note_name ) )
return;
// load the requested note by title and add it as a root link
var self = this;
this.invoker.invoke( "/notebooks/load_note_by_title", "GET", {
"notebook_id": this.notebook_id,
"note_title": note_name
}, function ( result ) {
self.save_and_display_startup_note( result.note );
} );
// otherwise, a note is provided
} else {
replaceChildNodes( "new_note_tree_link_area", "" );
this.save_and_display_startup_note( note );
}
if ( this.suggest_pulldown ) {
this.suggest_pulldown.shutdown();
this.suggest_pulldown = null;
}
}
Note_tree.prototype.save_and_display_startup_note = function ( note ) {
if ( !note ) {
this.wiki.display_message( "Sorry, a note by that title doesn't exist. (If you're trying to create a new note, then simply click that large \"+\" button on the left.)" );
return;
}
// if it's already a startup note, just highlight it and bail
if ( note.startup ) {
this.add_root_link( note.object_id, note.title, note.contents, true );
return;
}
// mark the note as a startup note on the client
this.wiki.startup_notes[ note.object_id ] = true;
var editor = editor_by_id( note.object_id );
if ( editor )
editor.startup = true;
// save the note as a startup note on the server, and then add it to the note tree
var self = this;
this.invoker.invoke( "/notebooks/save_note", "POST", {
"notebook_id": this.notebook_id,
"note_id": note.object_id,
"contents": note.contents,
"startup": true,
"previous_revision": note.revision
}, function ( result ) {
self.add_root_link( note.object_id, note.title, note.contents, true );
} );
}
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" ) )
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 ); } );
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() {
var more_link = getElement( "recent_notes_more_link" );
if ( more_link ) {
if ( this.total_notes_count > this.max_recent_notes_count )
removeElementClass( more_link, "undisplayed" );
else
addElementClass( more_link, "undisplayed" );
}
var less_link = getElement( "recent_notes_less_link" );
if ( less_link ) {
if ( this.max_recent_notes_count > this.INCREMENT )
removeElementClass( less_link, "undisplayed" );
else
addElementClass( less_link, "undisplayed" );
}
}
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.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">' +
( normalize_title( note.title ) ) + '</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;
// 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 >= this.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( "div", { "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"
}, normalize_title( editor.title ) );
insertSiblingNodesAfter( "recent_notes_top", createDOM(
"tr",
{ "id": "recent_note_item_" + editor.id, "class": "recent_note_item" },
createDOM( "td", {}, 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, normalize_title( editor.title ) );
insertSiblingNodesAfter( "recent_notes_top", item );
}
2008-05-13 22:52:20 +00:00
function Autosaver( wiki ) {
this.wiki = wiki;
this.last_state_change_time = null;
this.timer = null;
var INTERVAL_MILLISECONDS = 10000; // 10 seconds
function save_if_idle() {
// if the note state has changed in the last few seconds (e.g. due to typing), don't save,
// but do reschedule a new timer
if ( this.last_state_change_time + INTERVAL_MILLISECONDS > ( new Date() ).getTime() ) {
if ( this.timer ) clearTimeout( this.timer );
this.timer = setTimeout( save_if_idle, INTERVAL_MILLISECONDS );
return;
}
this.wiki.save_editor();
}
// whenever the focused editor's state changes, record the current time, cancel any current
// timer, and schedule a timer to save the editor in several seconds from now
var self = this;
connect( wiki, "note_state_changed", function ( editor ) {
self.last_state_change_time = ( new Date() ).getTime();
if ( self.timer ) clearTimeout( self.timer );
self.timer = setTimeout( save_if_idle, INTERVAL_MILLISECONDS );
} );
}