From b58f5cb1a1c27f09744539f24867647ebabc4198 Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Thu, 2 Aug 2007 04:01:11 +0000 Subject: [PATCH] * tools/updatedb.py now takes an optional navigation note id parameter, so the titleless navigation note can be updated. * both tools/initdb.py and tools/updatedb.py set link ids appropriately, rather than just leaving them all as "new" * both tools/initdb.py and tools/updatedb.py set certain links to use https if configured as such in config/Common.py * tools/initdb.py no longer creates a default "witten" user * Added target="_top" to links that should replace the top-level window, and updated client code to ignore links with targets. * Removed form_base_url from Editor.js, as https URL is now tacked on by initdb.py/updatedb.py instead. --- INSTALL | 10 ++-- config/Common.py | 1 + static/html/features.html | 6 +-- static/html/login.html | 2 +- static/html/navigation.html | 4 +- static/html/supported browsers.html | 8 +-- static/js/Editor.js | 16 +++--- tools/__init__.py | 0 tools/initdb.py | 78 +++++++++++++++-------------- tools/updatedb.py | 64 +++++++++++++++-------- 10 files changed, 108 insertions(+), 81 deletions(-) create mode 100644 tools/__init__.py diff --git a/INSTALL b/INSTALL index c179822..80a75fd 100644 --- a/INSTALL +++ b/INSTALL @@ -17,7 +17,7 @@ changes, because it uses CherryPy's built-in web server with auto-reload enabled, so the server will automatically reload any modified source files as soon as they're modified. -To start the server in development mode: +To start the server in development mode, run: python2.5 luminotes.py -d @@ -35,10 +35,10 @@ mode doesn't support auto-reload, and logging goes to file (luminotes.log) instead of the console, but performance should be better than in development mode. -If you want to use SSL, Edit static/js/Editor.js and change the value of -form_base_url to the URL of your SSL server. For instance: +If you want to use SSL, edit config/Common.py and change the value of +luminotes.https_url to the URL of your SSL server. For instance: - form_base_url = "https://luminotes.com"; + "luminotes.https_url": "https://luminotes.com", Then you'll need to configure your web server to forward requests for non-static pages to CherryPy. These instructions are for Apache, but in @@ -57,7 +57,7 @@ installed. These rules cause Apache to serve static files itself, while passing through requests for dynamic pages to the CherryPy web server running locally. -To actually start the production mode server: +To actually start the production mode server, run: python2.5 luminotes.py diff --git a/config/Common.py b/config/Common.py index ab032aa..ff52354 100644 --- a/config/Common.py +++ b/config/Common.py @@ -15,5 +15,6 @@ settings = { "encoding_filter.encoding": "utf-8", "decoding_filter.on": True, "decoding_filter.encoding": "utf-8", + "luminotes.https_url": "", }, } diff --git a/static/html/features.html b/static/html/features.html index 93d5a76..5a29cd2 100644 --- a/static/html/features.html +++ b/static/html/features.html @@ -28,11 +28,11 @@ You're free to title your wiki notes as you see fit.
  • notebook change history
    -You can go back and review previous revisions of all your notes, so you never -lose a single word.
  • +Make updates without worry. You can always go back and view older versions of +your wiki.

    -Sound interesting? Then take a tour or try it out for yourself! +Sound interesting? Then take a tour or try it out for yourself!

    diff --git a/static/html/login.html b/static/html/login.html index 9b2baca..2ddf276 100644 --- a/static/html/login.html +++ b/static/html/login.html @@ -1,6 +1,6 @@

    login

    -No account yet? Want to make a wiki? You can try it out for free. +No account yet? Want to make a wiki? You can try it out for free.

    diff --git a/static/html/navigation.html b/static/html/navigation.html index acf0482..3d07bbd 100644 --- a/static/html/navigation.html +++ b/static/html/navigation.html @@ -1,5 +1,5 @@ about - features - take a tour - -try it out - -login +try it out - +login diff --git a/static/html/supported browsers.html b/static/html/supported browsers.html index e3e51dd..c99abb9 100644 --- a/static/html/supported browsers.html +++ b/static/html/supported browsers.html @@ -14,7 +14,8 @@ so not all browsers will work for editing your wiki. Supported browsers include:

    -The following web browsers are known not to work with Luminotes: +The following web browsers are known not to work with some or all +Luminotes features, at least currently:

    If you're looking for a personal wiki with more minimal browser requirements, -you might want to try TiddlyWiki. If you're looking for a more general-purpose -wiki for multiple users, check out MoinMoin. +you might want to try TiddlyWiki. And for a more general-purpose wiki, check out +MoinMoin. diff --git a/static/js/Editor.js b/static/js/Editor.js index 2f0ec8b..ce98d6d 100644 --- a/static/js/Editor.js +++ b/static/js/Editor.js @@ -1,4 +1,3 @@ -form_base_url = ""; note_titles = {} // map from note title to the open editor for that note function Editor( id, notebook_id, note_text, revisions_list, insert_after_iframe_id, read_write, startup, highlight, focus ) { @@ -140,7 +139,7 @@ Editor.prototype.finish_init = function () { if ( signup_button ) { var signup_form = withDocument( this.document, function () { return getElement( "signup_form" ); } ); connect( signup_button, "onclick", function ( event ) { - signal( self, "submit_form", form_base_url + "/users/signup", signup_form ); event.stop(); + signal( self, "submit_form", "/users/signup", signup_form ); event.stop(); } ); } @@ -148,7 +147,7 @@ Editor.prototype.finish_init = function () { if ( login_button ) { var login_form = withDocument( this.document, function () { return getElement( "login_form" ); } ); connect( login_button, "onclick", function ( event ) { - signal( self, "submit_form", form_base_url + "/users/login", login_form ); event.stop(); + signal( self, "submit_form", "/users/login", login_form ); event.stop(); } ); } @@ -256,9 +255,6 @@ Editor.prototype.mouse_clicked = function ( event ) { if ( event.mouse().button.middle || event.mouse().button.right ) return; - event.stop(); - signal( this, "state_changed", this ); - // search through the tree of elements containing the clicked target. if a link isn't found, bail var link = event.target() while ( link.nodeName != "A" ) { @@ -266,9 +262,15 @@ Editor.prototype.mouse_clicked = function ( event ) { if ( !link ) return; } - if ( !link.href ) + + // ignore external links pointing outside of this wiki (indicated by the presence of a link + // target), and let the browser handle them normally + if ( !link.href || link.target ) return; + event.stop(); + signal( this, "state_changed", this ); + // in case the link is to ourself, first grab the most recent version of our title this.scrape_title(); diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/initdb.py b/tools/initdb.py index dd1e678..79756fe 100644 --- a/tools/initdb.py +++ b/tools/initdb.py @@ -12,7 +12,7 @@ from model.User import User class Initializer( object ): HTML_PATH = u"static/html" - ENTRY_FILES = [ # the second element of the tuple is whether to show the note on startup + NOTE_FILES = [ # the second element of the tuple is whether to show the note on startup ( u"navigation.html", True ), ( u"about.html", True ), ( u"features.html", True ), @@ -29,15 +29,11 @@ class Initializer( object ): self.database = database self.main_notebook = None self.read_only_main_notebook = None - self.user_notebook = None - self.user = None self.anonymous = None threads = ( self.create_main_notebook(), self.create_anonymous_user(), - self.create_user_notebook(), - self.create_user(), ) for thread in threads: @@ -50,25 +46,28 @@ class Initializer( object ): main_notebook_id = ( yield Scheduler.SLEEP ) self.main_notebook = Notebook( main_notebook_id, u"Luminotes" ) - for ( filename, startup ) in self.ENTRY_FILES: - full_filename = os.path.join( self.HTML_PATH, filename ) - contents = file( full_filename ).read().replace( "%s", main_notebook_id ) + # create the read-only view of the main notebook + self.database.next_id( self.scheduler.thread ) + read_only_main_notebook_id = ( yield Scheduler.SLEEP ) + self.read_only_main_notebook = Read_only_notebook( read_only_main_notebook_id, self.main_notebook ) + # create an id for each note + note_ids = {} + for ( filename, startup ) in self.NOTE_FILES: self.database.next_id( self.scheduler.thread ) - note_id = ( yield Scheduler.SLEEP ) + note_ids[ filename ] = ( yield Scheduler.SLEEP ) - note = Note( note_id, contents ) + for ( filename, startup ) in self.NOTE_FILES: + full_filename = os.path.join( self.HTML_PATH, filename ) + contents = fix_note_contents( file( full_filename ).read(), read_only_main_notebook_id, note_ids ) + + note = Note( note_ids[ filename ], contents ) self.main_notebook.add_note( note ) if startup: self.main_notebook.add_startup_note( note ) self.database.save( self.main_notebook ) - - # create the read-only view of the main notebook - self.database.next_id( self.scheduler.thread ) - read_only_main_notebook_id = ( yield Scheduler.SLEEP ) - self.read_only_main_notebook = Read_only_notebook( read_only_main_notebook_id, self.main_notebook ) self.database.save( self.read_only_main_notebook ) def create_anonymous_user( self ): @@ -79,29 +78,6 @@ class Initializer( object ): self.anonymous = User( anonymous_user_id, u"anonymous", None, None, notebooks ) self.database.save( self.anonymous ) - def create_user_notebook( self ): - # create the user notebook along with a startup note - self.database.next_id( self.scheduler.thread ) - user_notebook_id = ( yield Scheduler.SLEEP ) - self.user_notebook = Notebook( user_notebook_id, u"my notebook" ) - - self.database.next_id( self.scheduler.thread ) - note_id = ( yield Scheduler.SLEEP ) - note = Note( note_id, u"

    " ) - self.user_notebook.add_note( note ) - self.user_notebook.add_startup_note( note ) - - self.database.save( self.user_notebook ) - - def create_user( self ): - # create the user - self.database.next_id( self.scheduler.thread ) - user_id = ( yield Scheduler.SLEEP ) - notebooks = [ self.user_notebook ] - self.user = User( user_id, u"witten", u"dev", u"witten@torsion.org", notebooks ) - - self.database.save( self.user ) - def main(): if os.path.exists( "data.db" ): @@ -113,5 +89,31 @@ def main(): scheduler.wait_until_idle() +def fix_note_contents( contents, notebook_id, note_ids ): + import re + from config.Common import settings + + LINK_PATTERN = re.compile( '(]*>)([^<]*)()' ) + + # plug in the notebook id where appropriate + contents = contents.replace( "%s", notebook_id ) + + # stitch together note links to use the actual note ids of the referenced notes. + # also, use the https URL for certain links if one is configured + def fix_link( match ): + title = match.group( 5 ) + https_url = u"" + + if title in ( u"try it out", u"login" ): + https_url = settings[ u"global" ].get( u"luminotes.https_url", u"" ) + + return u"".join( [ + match.group( 1 ), https_url, match.group( 2 ), note_ids[ title + ".html" ], match.group( 3 ), + match.group( 4 ), match.group( 5 ), match.group( 6 ), + ] ) + + return LINK_PATTERN.sub( fix_link, contents ) + + if __name__ == "__main__": main() diff --git a/tools/updatedb.py b/tools/updatedb.py index 644d08e..58b44b3 100755 --- a/tools/updatedb.py +++ b/tools/updatedb.py @@ -2,15 +2,16 @@ import os import os.path +from config.Common import settings from controller.Database import Database from controller.Scheduler import Scheduler from model.Note import Note +from tools.initdb import fix_note_contents class Initializer( object ): HTML_PATH = u"static/html" - ENTRY_FILES = [ # the second element of the tuple is whether to show the note on startup - #( u"navigation.html", True ), # skip for now, since the navigtaion note doesn't have a title + NOTE_FILES = [ # the second element of the tuple is whether to show the note on startup ( u"about.html", True ), ( u"features.html", True ), ( u"take a tour.html", False ), @@ -21,9 +22,10 @@ class Initializer( object ): ( u"advanced browser features.html", False ), ] - def __init__( self, scheduler, database ): + def __init__( self, scheduler, database, navigation_note_id = None ): self.scheduler = scheduler self.database = database + self.navigation_note_id = navigation_note_id threads = ( self.update_main_notebook(), @@ -36,29 +38,31 @@ class Initializer( object ): def update_main_notebook( self ): self.database.load( u"User anonymous", self.scheduler.thread ) anonymous = ( yield Scheduler.SLEEP ) + read_only_main_notebook = anonymous.notebooks[ 0 ] main_notebook = anonymous.notebooks[ 0 ]._Read_only_notebook__wrapped startup_notes = [] - # update all of the notes in the main notebook - for ( filename, startup ) in self.ENTRY_FILES: - full_filename = os.path.join( self.HTML_PATH, filename ) - contents = file( full_filename ).read().replace( "%s", main_notebook.object_id ) - + # get the id for each note + note_ids = {} + for ( filename, startup ) in self.NOTE_FILES: title = filename.replace( u".html", u"" ) note = main_notebook.lookup_note_by_title( title ) + note_ids[ filename ] = note.object_id - if note: - main_notebook.update_note( note, contents ) - # if for some reason the note isn't present, create it - else: - self.database.next_id( self.scheduler.thread ) - note_id = ( yield Scheduler.SLEEP ) - note = Note( note_id, contents ) - main_notebook.add_note( note ) + # update the navigation note if its id was given + if self.navigation_note_id: + self.database.next_id( self.scheduler.thread ) + next_id = ( yield Scheduler.SLEEP ) + note = main_notebook.lookup_note( self.navigation_note_id ) + self.update_note( "navigation.html", True, main_notebook, read_only_main_notebook, startup_notes, next_id, note_ids, note ) - main_notebook.remove_startup_note( note ) - if startup: - startup_notes.append( note ) + # update all of the notes in the main notebook + for ( filename, startup ) in self.NOTE_FILES: + self.database.next_id( self.scheduler.thread ) + next_id = ( yield Scheduler.SLEEP ) + title = filename.replace( u".html", u"" ) + note = main_notebook.lookup_note_by_title( title ) + self.update_note( filename, startup, main_notebook, read_only_main_notebook, startup_notes, next_id, note_ids, note ) for note in startup_notes: main_notebook.add_startup_note( note ) @@ -66,13 +70,29 @@ class Initializer( object ): main_notebook.name = u"Luminotes" self.database.save( main_notebook ) + def update_note( self, filename, startup, main_notebook, read_only_main_notebook, startup_notes, next_id, note_ids, note = None ): + full_filename = os.path.join( self.HTML_PATH, filename ) + contents = fix_note_contents( file( full_filename ).read(), read_only_main_notebook.object_id, note_ids ) -def main(): + if note: + main_notebook.update_note( note, contents ) + # if for some reason the note isn't present, create it + else: + note = Note( next_id, contents ) + main_notebook.add_note( note ) + + main_notebook.remove_startup_note( note ) + if startup: + startup_notes.append( note ) + + +def main( args ): scheduler = Scheduler() database = Database( scheduler, "data.db" ) - initializer = Initializer( scheduler, database ) + initializer = Initializer( scheduler, database, args and args[ 0 ] or None ) scheduler.wait_until_idle() if __name__ == "__main__": - main() + import sys + main( sys.argv[ 1: ] )