witten
/
luminotes
Archived
1
0
Fork 0

* Rewrote all wiki note links to be of the form: /notebooks/notebookid?note_id=noteid

* Refactored some of validator decorator to use clearer variable names internally.
 * Validator decorator now supports treating arguments with default values as optional.
 * controller.Notebooks.default() takes an optional note_id argument.
 * controller.Notebooks.contents() takes an optional note_id argument.
 * Wiki.js now makes use of these new controller APIs.
 * Editor.js now takes a notebook_id argument to its constructor so it can properly make links.
This commit is contained in:
Dan Helfman 2007-07-28 04:22:44 +00:00
parent f81707ea2f
commit 2c20d60f9e
6 changed files with 82 additions and 49 deletions

View File

@ -134,7 +134,7 @@ class Valid_bool( object ):
raise ValueError()
def validate( **kwarg_types ):
def validate( **expected ):
"""
validate() can be used to require that the arguments of the decorated method successfully pass
through particular validators. The validate() method itself is evaluated where it is used as a
@ -177,64 +177,62 @@ def validate( **kwarg_types ):
args = list( args )
args_index = 1 # skip the self argument
for ( arg_name, arg_type ) in kwarg_types.items():
if arg_name == u"kwargs":
key_type = kwarg_types[ u"kwargs" ].keys()[ 0 ]
value_type = kwarg_types[ u"kwargs" ].values()[ 0 ]
# determine the expected argument names from the decorated function itself
code = function.func_code
expected_names = code.co_varnames[ : code.co_argcount ]
for ( key, value ) in kwargs.items():
if key not in kwarg_types:
del( kwargs[ key ] )
try:
kwargs[ str( key_type( key ) ) ] = value_type( value )
except ( ValueError, TypeError ):
raise Validation_error( key, value, value_type )
# validate each of the expected arguments
for expected_name in expected_names:
if expected_name == u"self": continue
expected_type = expected.get( expected_name )
continue
# look for arg_name in kwargs and store the validated value there
if arg_name in kwargs:
value = kwargs.get( arg_name )
# if there's a tuple of multiple validators for this arg_name, use all of them
if isinstance( arg_type, tuple ):
for validator in arg_type:
# look for expected_name in kwargs and store the validated value there
if expected_name in kwargs:
value = kwargs.get( expected_name )
# if there's a tuple of multiple validators for this expected_name, use all of them
if isinstance( expected_type, tuple ):
for validator in expected_type:
try:
value = validator( value )
except ( ValueError, TypeError ):
raise Validation_error( arg_name, value, validator )
kwargs[ str( arg_name ) ] = value
raise Validation_error( expected_name, value, validator )
kwargs[ str( expected_name ) ] = value
# otherwise, there's just a single validator
else:
try:
kwargs[ str( arg_name ) ] = arg_type( value )
kwargs[ str( expected_name ) ] = expected_type( value )
except ( ValueError, TypeError ):
raise Validation_error( arg_name, value, arg_type )
raise Validation_error( expected_name, value, expected_type )
continue
# arg_name wasn't found in kwargs, so use args instead
# expected_name wasn't found in kwargs, so look for it in args. if it's not there either,
# raise unless there's a default value for the argument in the decorated function
if args_index >= len( args ):
raise Validation_error( arg_name, None, arg_type, message = u"is required" )
if function.func_defaults and args_index >= len( args ) - len( function.func_defaults ):
continue
raise Validation_error( expected_name, None, expected_type, message = u"is required" )
value = args[ args_index ]
# if there's a tuple of multiple validators for this arg_name, use all of them
if isinstance( arg_type, tuple ):
for validator in arg_type:
# if there's a tuple of multiple validators for this expected_name, use all of them
if isinstance( expected_type, tuple ):
for validator in expected_type:
try:
value = validator( value )
except ( ValueError, TypeError ):
raise Validation_error( arg_name, value, validator )
raise Validation_error( expected_name, value, validator )
args[ args_index ] = value
# otherwise, there's just a single validator
else:
try:
args[ args_index ] = arg_type( value )
args[ args_index ] = expected_type( value )
except ( ValueError, TypeError ):
raise Validation_error( arg_name, value, arg_type )
raise Validation_error( expected_name, value, expected_type )
args_index += 1
# if there are any unexpected arguments, raise
for ( arg_name, arg_value ) in kwargs.items():
if not arg_name in kwarg_types:
print arg_name, kwarg_types
if not arg_name in expected_names:
print arg_name, expected
raise Validation_error( arg_name, arg_value, None, message = u"is an unknown argument" )
return function( *args, **kwargs )

View File

@ -62,6 +62,12 @@ class Test_notebooks( Test_controller ):
assert result.get( u"notebook_id" ) == self.notebook.object_id
def test_default_with_note( self ):
result = self.http_get( "/notebooks/%s?note_id=%s" % ( self.notebook.object_id, self.note.object_id ) )
assert result.get( u"notebook_id" ) == self.notebook.object_id
assert result.get( u"note_id" ) == self.note.object_id
def test_contents( self ):
self.login()
@ -76,6 +82,24 @@ class Test_notebooks( Test_controller ):
assert len( notebook.startup_notes ) == 1
assert notebook.startup_notes[ 0 ] == self.note
def test_contents_with_note( self ):
self.login()
result = self.http_get(
"/notebooks/contents?notebook_id=%s&note_id=%s" % ( self.notebook.object_id, self.note.object_id ),
session_id = self.session_id,
)
notebook = result[ "notebook" ]
assert notebook.object_id == self.notebook.object_id
assert len( notebook.startup_notes ) == 1
assert notebook.startup_notes[ 0 ] == self.note
note = result[ "note" ]
assert note.object_id == self.note.object_id
def test_contents_without_login( self ):
result = self.http_get(
"/notebooks/contents?notebook_id=%s" % self.notebook.object_id,

View File

@ -1,7 +1,8 @@
note_titles = {} // map from note title to the open editor for that note
function Editor( id, note_text, revisions_list, insert_after_iframe_id, read_write, startup, highlight, focus ) {
function Editor( id, notebook_id, note_text, revisions_list, insert_after_iframe_id, read_write, startup, highlight, focus ) {
this.id = id;
this.notebook_id;
this.initial_text = note_text;
this.revisions_list = revisions_list;
this.read_write = read_write;
@ -273,11 +274,11 @@ Editor.prototype.mouse_clicked = function ( event ) {
var id;
var link_title = scrapeText( link );
var editor = note_titles[ link_title ];
var href_leaf = link.href.split( "/" ).pop();
var href_leaf = link.href.split( "?note_id=" ).pop();
// if the link's title corresponds to an open note id, set that as the link's destination
if ( editor ) {
id = editor.id;
link.href = "/notes/" + id;
link.href = "/notebooks/" + this.notebook_id + "?note_id=" + id;
// if this is a new link, get a new note id and set it for the link's destination
} else if ( href_leaf == "new" ) {
signal( this, "load_editor_by_title", link_title, this.iframe.id );
@ -363,7 +364,7 @@ Editor.prototype.start_link = function () {
range.setStart( container, range.startOffset - 1 );
}
this.exec_command( "createLink", "/notes/new" );
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
var links = getElementsByTagAndClassName( "a", null, parent = this.document );
for ( var i in links ) {
@ -382,7 +383,7 @@ Editor.prototype.start_link = function () {
}
// otherwise, just create a link with the selected text as the link title
} else {
this.exec_command( "createLink", "/notes/new" );
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
}
} else if ( this.document.selection ) { // browsers such as IE
var range = this.document.selection.createRange();
@ -395,7 +396,7 @@ Editor.prototype.start_link = function () {
range.select();
}
this.exec_command( "createLink", "/notes/new" );
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
}
}

View File

@ -16,7 +16,8 @@ function Wiki() {
if ( this.notebook_id ) {
this.invoker.invoke(
"/notebooks/contents", "GET", {
"notebook_id": this.notebook_id
"notebook_id": this.notebook_id,
"note_id": getElement( "note_id" ).value
},
function( result ) { self.populate( result ); }
);
@ -121,9 +122,17 @@ Wiki.prototype.populate = function ( result ) {
var note = this.notebook.startup_notes[ i ];
if ( !note ) continue;
this.startup_notes[ note.object_id ] = true;
var focus = ( i == 0 );
this.create_editor( note.object_id, note.contents, note.revisions_list, undefined, undefined, false, focus );
// don't actually create an editor if a particular note was provided in the result
if ( !result.note ) {
var focus = ( i == 0 );
this.create_editor( note.object_id, note.contents, note.revisions_list, undefined, undefined, false, focus );
}
}
// if one particular note was provided, then just display an editor for that note
if ( result.note )
this.create_editor( result.note.object_id, result.note.contents, result.note.revisions_list, undefined, undefined, false, true );
}
Wiki.prototype.background_clicked = function ( event ) {
@ -214,7 +223,7 @@ Wiki.prototype.create_editor = function ( id, note_text, revisions_list, insert_
for ( var i in links ) {
// a link matches if its contained text is the same as this note's title
if ( scrapeText( links[ i ] ) == note_title )
links[ i ].href = "/notes/" + id;
links[ i ].href = "/notebooks/" + this.notebook_id + "?note_id=" + id;
}
}
@ -232,7 +241,7 @@ Wiki.prototype.create_editor = function ( id, note_text, revisions_list, insert_
}
var startup = this.startup_notes[ id ];
var editor = new Editor( id, note_text, revisions_list, undefined, this.read_write, startup, highlight, focus );
var editor = new Editor( id, this.notebook_id, note_text, revisions_list, undefined, this.read_write, startup, highlight, focus );
if ( this.read_write ) {
connect( editor, "state_changed", this, "editor_state_changed" );
@ -575,7 +584,7 @@ Pulldown.prototype.shutdown = function () {
}
Options_pulldown = function ( notebook_id, invoker, editor ) {
function Options_pulldown( notebook_id, invoker, editor ) {
Pulldown.call( this, notebook_id, "options_" + editor.id, editor.options_button );
this.invoker = invoker;
@ -620,7 +629,7 @@ Options_pulldown.prototype.shutdown = function () {
}
Changes_pulldown = function ( notebook_id, invoker, editor ) {
function Changes_pulldown( notebook_id, invoker, editor ) {
Pulldown.call( this, notebook_id, "changes_" + editor.id, editor.changes_button );
this.invoker = invoker;

View File

@ -4,7 +4,7 @@ from Tags import Html, Head, Title, Style, Meta, Body, H1, Div, Span, Hr, A
class Html_file( Html ):
NOTE_LINK_PATTERN = re.compile( u'<a\s+href="\/notes\/([a-z0-9]*)"\s*>', re.IGNORECASE )
NOTE_LINK_PATTERN = re.compile( u'<a\s+href="\/notebooks\/[a-z0-9]*\?note_id=([a-z0-9]*)"\s*>', re.IGNORECASE )
def __init__( self, notebook_name, notes ):
relinked_notes = {} # map from note id to relinked note contents

View File

@ -6,13 +6,14 @@ from Toolbar import Toolbar
class Main_page( Page ):
def __init__( self, notebook_id = None ):
def __init__( self, notebook_id = None, note_id = None ):
title = None
Page.__init__(
self,
title,
Input( type = u"hidden", name = u"notebook_id", id = u"notebook_id", value = notebook_id or "" ),
Input( type = u"hidden", name = u"note_id", id = u"note_id", value = note_id or "" ),
Div(
id = u"status_area",
),