* 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.
This commit is contained in:
parent
a5694d3661
commit
b58f5cb1a1
10
INSTALL
10
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
|
||||
|
||||
|
|
|
@ -15,5 +15,6 @@ settings = {
|
|||
"encoding_filter.encoding": "utf-8",
|
||||
"decoding_filter.on": True,
|
||||
"decoding_filter.encoding": "utf-8",
|
||||
"luminotes.https_url": "",
|
||||
},
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@ You're free to title your wiki notes as you see fit.</li>
|
|||
|
||||
<li><b>notebook change history</b><br />
|
||||
|
||||
You can go back and review previous revisions of all your notes, so you never
|
||||
lose a single word.</li>
|
||||
Make updates without worry. You can always go back and view older versions of
|
||||
your wiki.</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Sound interesting? Then <a href="/notebooks/%s?note_id=new">take a tour</a> or <a href="/notebooks/%s?note_id=new">try it out</a> for yourself!
|
||||
Sound interesting? Then <a href="/notebooks/%s?note_id=new">take a tour</a> or <a href="/notebooks/%s?note_id=new" target="_top">try it out</a> for yourself!
|
||||
</p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<h3>login</h3>
|
||||
|
||||
No account yet? Want to make a wiki? You can <a href="/notebooks/%s?note_id=new">try it out</a> for free.
|
||||
No account yet? Want to make a wiki? You can <a href="/notebooks/%s?note_id=new" target="_top">try it out</a> for free.
|
||||
|
||||
<form id="login_form">
|
||||
<p>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<a href="/notebooks/%s?note_id=new">about</a> -
|
||||
<a href="/notebooks/%s?note_id=new">features</a> -
|
||||
<a href="/notebooks/%s?note_id=new">take a tour</a> -
|
||||
<a href="/notebooks/%s?note_id=new">try it out</a> -
|
||||
<a href="/notebooks/%s?note_id=new">login</a>
|
||||
<a href="/notebooks/%s?note_id=new" target="_top">try it out</a> -
|
||||
<a href="/notebooks/%s?note_id=new" target="_top">login</a>
|
||||
|
|
|
@ -14,7 +14,8 @@ so not all browsers will work for editing your wiki. Supported browsers include:
|
|||
</ul>
|
||||
|
||||
<p>
|
||||
The following web browsers are known <i>not</i> to work with Luminotes:
|
||||
The following web browsers are known <i>not</i> to work with some or all
|
||||
Luminotes features, at least currently:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
|
@ -25,5 +26,6 @@ The following web browsers are known <i>not</i> to work with Luminotes:
|
|||
</ul>
|
||||
|
||||
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 <a href="http://tiddlywiki.com/"
|
||||
target="_top">TiddlyWiki</a>. And for a more general-purpose wiki, check out
|
||||
<a href="http://moinmoin.wikiwikiweb.de/" target="_top">MoinMoin</a>.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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"<h3>" )
|
||||
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( '(<a href=")([^"]+?note_id=)([^"]*)("[^>]*>)([^<]*)(</a>)' )
|
||||
|
||||
# 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()
|
||||
|
|
|
@ -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: ] )
|
||||
|
|
Reference in New Issue