Factored out file upload methods from Notebooks to new Files controller.
Changed file link insertion code to reuse existing link creation code.
This commit is contained in:
parent
0cf2b5bda7
commit
e56503903b
|
@ -0,0 +1,224 @@
|
|||
import cgi
|
||||
import cherrypy
|
||||
from cherrypy.filters import basefilter
|
||||
from Expose import expose
|
||||
from Validate import validate
|
||||
from Database import Valid_id
|
||||
from Users import grab_user_id
|
||||
from Expire import strongly_expire
|
||||
from view.Upload_page import Upload_page
|
||||
|
||||
|
||||
class Access_error( Exception ):
|
||||
def __init__( self, message = None ):
|
||||
if message is None:
|
||||
message = u"Sorry, you don't have access to do that. Please make sure you're logged in as the correct user."
|
||||
|
||||
Exception.__init__( self, message )
|
||||
self.__message = message
|
||||
|
||||
def to_dict( self ):
|
||||
return dict(
|
||||
error = self.__message
|
||||
)
|
||||
|
||||
|
||||
class Upload_error( Exception ):
|
||||
def __init__( self, message = None ):
|
||||
if message is None:
|
||||
message = u"An error occurred when uploading the file."
|
||||
|
||||
Exception.__init__( self, message )
|
||||
self.__message = message
|
||||
|
||||
def to_dict( self ):
|
||||
return dict(
|
||||
error = self.__message
|
||||
)
|
||||
|
||||
|
||||
class File_upload_filter( basefilter.BaseFilter ):
|
||||
def before_request_body( self ):
|
||||
if cherrypy.request.path != "/files/upload_file":
|
||||
return
|
||||
|
||||
if cherrypy.request.method != "POST":
|
||||
raise Upload_error()
|
||||
|
||||
# tell CherryPy not to parse the POST data itself for this URL
|
||||
cherrypy.request.processRequestBody = False
|
||||
|
||||
|
||||
class Files( object ):
|
||||
_cpFilterList = [ File_upload_filter() ]
|
||||
|
||||
"""
|
||||
Controller for dealing with uploaded files, corresponding to the "/files" URL.
|
||||
"""
|
||||
def __init__( self, database, users ):
|
||||
"""
|
||||
Create a new Files object.
|
||||
|
||||
@type database: controller.Database
|
||||
@param database: database that files are stored in
|
||||
@type users: controller.Users
|
||||
@param users: controller for all users
|
||||
@rtype: Files
|
||||
@return: newly constructed Files
|
||||
"""
|
||||
self.__database = database
|
||||
self.__users = users
|
||||
|
||||
@expose( view = Upload_page )
|
||||
@validate(
|
||||
notebook_id = Valid_id(),
|
||||
note_id = Valid_id(),
|
||||
)
|
||||
def upload_page( self, notebook_id, note_id ):
|
||||
"""
|
||||
Provide the information necessary to display the file upload page.
|
||||
|
||||
@type notebook_id: unicode
|
||||
@param notebook_id: id of the notebook that the upload will be to
|
||||
@type note_id: unicode
|
||||
@param note_id: id of the note that the upload will be to
|
||||
@rtype: unicode
|
||||
@return: rendered HTML page
|
||||
"""
|
||||
return dict(
|
||||
notebook_id = notebook_id,
|
||||
note_id = note_id,
|
||||
)
|
||||
|
||||
@expose()
|
||||
@strongly_expire
|
||||
@grab_user_id
|
||||
@validate(
|
||||
user_id = Valid_id( none_okay = True ),
|
||||
)
|
||||
def upload_file( self, user_id ):
|
||||
"""
|
||||
Upload a file from the client for attachment to a particular note.
|
||||
|
||||
@type notebook_id: unicode
|
||||
@param notebook_id: id of the notebook that the upload is to
|
||||
@type note_id: unicode
|
||||
@param note_id: id of the note that the upload is to
|
||||
@raise Access_error: the current user doesn't have access to the given notebook or note
|
||||
@rtype: unicode
|
||||
@return: rendered HTML page
|
||||
"""
|
||||
cherrypy.server.max_request_body_size = 0 # remove file size limit of 100 MB
|
||||
cherrypy.response.timeout = 3600 # increase upload timeout to one hour (default is 5 min)
|
||||
cherrypy.server.socket_timeout = 60 # increase socket timeout to one minute (default is 10 sec)
|
||||
# TODO: increase to 8k
|
||||
CHUNK_SIZE = 1#8 * 1024 # 8 Kb
|
||||
|
||||
headers = {}
|
||||
for key, val in cherrypy.request.headers.iteritems():
|
||||
headers[ key.lower() ] = val
|
||||
|
||||
try:
|
||||
file_size = int( headers.get( "content-length", 0 ) )
|
||||
except ValueError:
|
||||
raise Upload_error()
|
||||
if file_size <= 0:
|
||||
raise Upload_error()
|
||||
|
||||
parsed_form = cgi.FieldStorage( fp = cherrypy.request.rfile, headers = headers, environ = { "REQUEST_METHOD": "POST" }, keep_blank_values = 1)
|
||||
upload = parsed_form[ u"file" ]
|
||||
notebook_id = parsed_form.getvalue( u"notebook_id" )
|
||||
note_id = parsed_form.getvalue( u"note_id" )
|
||||
filename = upload.filename.strip()
|
||||
|
||||
if not self.__users.check_access( user_id, notebook_id ):
|
||||
raise Access_error()
|
||||
|
||||
def process_upload():
|
||||
"""
|
||||
Process the file upload while streaming a progress meter as it uploads.
|
||||
"""
|
||||
progress_bytes = 0
|
||||
fraction_reported = 0.0
|
||||
progress_width_em = 20
|
||||
tick_increment = 0.01
|
||||
progress_bar = u'<img src="/static/images/tick.png" style="width: %sem; height: 1em;" id="progress_bar" />' % \
|
||||
( progress_width_em * tick_increment )
|
||||
|
||||
yield \
|
||||
u"""
|
||||
<html>
|
||||
<head>
|
||||
<link href="/static/css/upload.css" type="text/css" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/static/js/MochiKit.js"></script>
|
||||
<meta content="text/html; charset=UTF-8" http_equiv="content-type" />
|
||||
</head>
|
||||
<body>
|
||||
"""
|
||||
|
||||
if not filename:
|
||||
yield \
|
||||
u"""
|
||||
<div class="field_label">upload error: </div>
|
||||
Please check that the filename is valid.
|
||||
"""
|
||||
return
|
||||
|
||||
base_filename = filename.split( u"/" )[ -1 ].split( u"\\" )[ -1 ]
|
||||
yield \
|
||||
u"""
|
||||
<div class="field_label">uploading %s: </div>
|
||||
<table><tr>
|
||||
<td><div id="progress_border">
|
||||
%s
|
||||
</div></td>
|
||||
<td></td>
|
||||
<td><span id="status"></span></td>
|
||||
</tr></table>
|
||||
<script type="text/javascript">
|
||||
function tick( fraction ) {
|
||||
setElementDimensions(
|
||||
"progress_bar",
|
||||
{ "w": %s * fraction }, "em"
|
||||
);
|
||||
if ( fraction == 1.0 )
|
||||
replaceChildNodes( "status", "100%%" );
|
||||
else
|
||||
replaceChildNodes( "status", Math.floor( fraction * 100.0 ) + "%%" );
|
||||
}
|
||||
</script>
|
||||
""" % ( cgi.escape( base_filename ), progress_bar, progress_width_em )
|
||||
|
||||
import time
|
||||
while True:
|
||||
chunk = upload.file.read( CHUNK_SIZE )
|
||||
if not chunk: break
|
||||
progress_bytes += len( chunk )
|
||||
fraction_done = float( progress_bytes ) / float( file_size )
|
||||
|
||||
if fraction_done > fraction_reported + tick_increment:
|
||||
yield '<script type="text/javascript">tick(%s)</script>;' % fraction_reported
|
||||
fraction_reported += tick_increment
|
||||
time.sleep(0.025) # TODO: removeme
|
||||
|
||||
# TODO: write to the database
|
||||
|
||||
if fraction_reported == 0:
|
||||
yield "An error occurred when uploading the file."
|
||||
return
|
||||
|
||||
# the file finished uploading, so fill out the progress meter to 100%
|
||||
if fraction_reported < 1.0:
|
||||
yield '<script type="text/javascript">tick(1.0)</script>;'
|
||||
|
||||
yield \
|
||||
u"""
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
upload.file.close()
|
||||
cherrypy.request.rfile.close()
|
||||
|
||||
return process_upload()
|
|
@ -1,7 +1,5 @@
|
|||
import re
|
||||
import cgi
|
||||
import cherrypy
|
||||
from cherrypy.filters import basefilter
|
||||
from datetime import datetime
|
||||
from Expose import expose
|
||||
from Validate import validate, Valid_string, Validation_error, Valid_bool
|
||||
|
@ -17,7 +15,6 @@ from model.User_revision import User_revision
|
|||
from view.Main_page import Main_page
|
||||
from view.Json import Json
|
||||
from view.Html_file import Html_file
|
||||
from view.Upload_page import Upload_page
|
||||
|
||||
|
||||
class Access_error( Exception ):
|
||||
|
@ -34,36 +31,8 @@ class Access_error( Exception ):
|
|||
)
|
||||
|
||||
|
||||
class Upload_error( Exception ):
|
||||
def __init__( self, message = None ):
|
||||
if message is None:
|
||||
message = u"An error occurred when uploading the file."
|
||||
|
||||
Exception.__init__( self, message )
|
||||
self.__message = message
|
||||
|
||||
def to_dict( self ):
|
||||
return dict(
|
||||
error = self.__message
|
||||
)
|
||||
|
||||
|
||||
class File_upload_filter( basefilter.BaseFilter ):
|
||||
def before_request_body( self ):
|
||||
if cherrypy.request.path != "/notebooks/upload_file":
|
||||
return
|
||||
|
||||
if cherrypy.request.method != "POST":
|
||||
raise Upload_error()
|
||||
|
||||
# tell CherryPy not to parse the POST data itself for this URL
|
||||
cherrypy.request.processRequestBody = False
|
||||
|
||||
|
||||
class Notebooks( object ):
|
||||
WHITESPACE_PATTERN = re.compile( u"\s+" )
|
||||
_cpFilterList = [ File_upload_filter() ]
|
||||
|
||||
"""
|
||||
Controller for dealing with notebooks and their notes, corresponding to the "/notebooks" URL.
|
||||
"""
|
||||
|
@ -1125,149 +1094,3 @@ class Notebooks( object ):
|
|||
result[ "count" ] = count
|
||||
|
||||
return result
|
||||
|
||||
@expose( view = Upload_page )
|
||||
@validate(
|
||||
notebook_id = Valid_id(),
|
||||
note_id = Valid_id(),
|
||||
)
|
||||
def upload_page( self, notebook_id, note_id ):
|
||||
"""
|
||||
Provide the information necessary to display the file upload page.
|
||||
|
||||
@type notebook_id: unicode
|
||||
@param notebook_id: id of the notebook that the upload will be to
|
||||
@type note_id: unicode
|
||||
@param note_id: id of the note that the upload will be to
|
||||
@rtype: unicode
|
||||
@return: rendered HTML page
|
||||
"""
|
||||
return dict(
|
||||
notebook_id = notebook_id,
|
||||
note_id = note_id,
|
||||
)
|
||||
|
||||
@expose()
|
||||
@strongly_expire
|
||||
@grab_user_id
|
||||
@validate(
|
||||
user_id = Valid_id( none_okay = True ),
|
||||
)
|
||||
def upload_file( self, user_id ):
|
||||
"""
|
||||
Upload a file from the client for attachment to a particular note.
|
||||
|
||||
@type notebook_id: unicode
|
||||
@param notebook_id: id of the notebook that the upload is to
|
||||
@type note_id: unicode
|
||||
@param note_id: id of the note that the upload is to
|
||||
@raise Access_error: the current user doesn't have access to the given notebook or note
|
||||
@rtype: unicode
|
||||
@return: rendered HTML page
|
||||
"""
|
||||
cherrypy.server.max_request_body_size = 0 # remove file size limit of 100 MB
|
||||
cherrypy.response.timeout = 3600 # increase upload timeout to one hour (default is 5 min)
|
||||
cherrypy.server.socket_timeout = 60 # increase socket timeout to one minute (default is 10 sec)
|
||||
# TODO: increase to 8k
|
||||
CHUNK_SIZE = 1#8 * 1024 # 8 Kb
|
||||
|
||||
headers = {}
|
||||
for key, val in cherrypy.request.headers.iteritems():
|
||||
headers[ key.lower() ] = val
|
||||
|
||||
try:
|
||||
file_size = int( headers.get( "content-length", 0 ) )
|
||||
except ValueError:
|
||||
raise Upload_error()
|
||||
if file_size <= 0:
|
||||
raise Upload_error()
|
||||
|
||||
parsed_form = cgi.FieldStorage( fp = cherrypy.request.rfile, headers = headers, environ = { "REQUEST_METHOD": "POST" }, keep_blank_values = 1)
|
||||
upload = parsed_form[ u"file" ]
|
||||
notebook_id = parsed_form.getvalue( u"notebook_id" )
|
||||
note_id = parsed_form.getvalue( u"note_id" )
|
||||
filename = upload.filename.strip()
|
||||
|
||||
if not self.__users.check_access( user_id, notebook_id ):
|
||||
raise Access_error()
|
||||
|
||||
def process_upload():
|
||||
"""
|
||||
Process the file upload while streaming a progress meter as it uploads.
|
||||
"""
|
||||
progress_bytes = 0
|
||||
fraction_reported = 0.0
|
||||
progress_width_em = 20
|
||||
tick_increment = 0.01
|
||||
progress_bar = u'<img src="/static/images/tick.png" style="width: %sem; height: 1em;" id="progress_bar" />' % \
|
||||
( progress_width_em * tick_increment )
|
||||
|
||||
yield \
|
||||
u"""
|
||||
<html>
|
||||
<head>
|
||||
<link href="/static/css/upload.css" type="text/css" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/static/js/MochiKit.js"></script>
|
||||
<meta content="text/html; charset=UTF-8" http_equiv="content-type" />
|
||||
</head>
|
||||
<body>
|
||||
"""
|
||||
|
||||
if not filename:
|
||||
yield \
|
||||
u"""
|
||||
<div class="field_label">upload error: </div>
|
||||
Please check that the filename is valid.
|
||||
"""
|
||||
return
|
||||
|
||||
base_filename = filename.split( u"/" )[ -1 ].split( u"\\" )[ -1 ]
|
||||
yield \
|
||||
u"""
|
||||
<div class="field_label">uploading %s: </div>
|
||||
<div id="progress_border">
|
||||
%s
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
function tick( fraction ) {
|
||||
setElementDimensions(
|
||||
"progress_bar",
|
||||
{ "w": %s * fraction }, "em"
|
||||
);
|
||||
}
|
||||
</script>
|
||||
""" % ( cgi.escape( base_filename ), progress_bar, progress_width_em )
|
||||
|
||||
import time
|
||||
while True:
|
||||
chunk = upload.file.read( CHUNK_SIZE )
|
||||
if not chunk: break
|
||||
progress_bytes += len( chunk )
|
||||
fraction_done = float( progress_bytes ) / float( file_size )
|
||||
|
||||
if fraction_done > fraction_reported + tick_increment:
|
||||
yield '<script type="text/javascript">tick(%s)</script>;' % fraction_reported
|
||||
fraction_reported += tick_increment
|
||||
time.sleep(0.025) # TODO: removeme
|
||||
|
||||
# TODO: write to the database
|
||||
|
||||
if fraction_reported == 0:
|
||||
yield "An error occurred when uploading the file."
|
||||
return
|
||||
|
||||
# the file finished uploading, so fill out the progress meter to 100%
|
||||
if fraction_reported < 1.0:
|
||||
yield '<script type="text/javascript">tick(1.0)</script>;'
|
||||
|
||||
yield \
|
||||
u"""
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
upload.file.close()
|
||||
cherrypy.request.rfile.close()
|
||||
|
||||
return process_upload()
|
||||
|
|
|
@ -5,6 +5,7 @@ from Expire import strongly_expire
|
|||
from Validate import validate, Valid_int, Valid_string
|
||||
from Notebooks import Notebooks
|
||||
from Users import Users, grab_user_id
|
||||
from Files import Files
|
||||
from Database import Valid_id
|
||||
from model.Note import Note
|
||||
from model.Notebook import Notebook
|
||||
|
@ -43,6 +44,7 @@ class Root( object ):
|
|||
settings[ u"global" ].get( u"luminotes.rate_plans", [] ),
|
||||
)
|
||||
self.__notebooks = Notebooks( database, self.__users )
|
||||
self.__files = Files( database, self.__users )
|
||||
|
||||
@expose( Main_page )
|
||||
@grab_user_id
|
||||
|
@ -353,3 +355,4 @@ class Root( object ):
|
|||
database = property( lambda self: self.__database )
|
||||
notebooks = property( lambda self: self.__notebooks )
|
||||
users = property( lambda self: self.__users )
|
||||
files = property( lambda self: self.__files )
|
||||
|
|
|
@ -39,6 +39,10 @@ div {
|
|||
height: 1em;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#tick_preload {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -416,7 +416,7 @@ Editor.prototype.empty = function () {
|
|||
return ( scrapeText( this.document.body ).length == 0 );
|
||||
}
|
||||
|
||||
Editor.prototype.start_link = function () {
|
||||
Editor.prototype.insert_link = function ( url ) {
|
||||
// get the current selection, which is the link title
|
||||
if ( this.iframe.contentWindow && this.iframe.contentWindow.getSelection ) { // browsers such as Firefox
|
||||
var selection = this.iframe.contentWindow.getSelection();
|
||||
|
@ -428,7 +428,7 @@ Editor.prototype.start_link = function () {
|
|||
var placeholder = withDocument( this.document, function () { return getElement( "placeholder_title" ); } );
|
||||
selection.selectAllChildren( placeholder );
|
||||
|
||||
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
|
||||
this.exec_command( "createLink", url );
|
||||
selection.collapseToEnd();
|
||||
|
||||
// hack to prevent Firefox from erasing spaces before links that happen to be at the end of list items
|
||||
|
@ -443,7 +443,7 @@ Editor.prototype.start_link = function () {
|
|||
// otherwise, just create a link with the selected text as the link title
|
||||
} else {
|
||||
this.link_started = null;
|
||||
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
|
||||
this.exec_command( "createLink", url );
|
||||
return this.find_link_at_cursor();
|
||||
}
|
||||
} else if ( this.document.selection ) { // browsers such as IE
|
||||
|
@ -455,16 +455,24 @@ Editor.prototype.start_link = function () {
|
|||
range.text = " ";
|
||||
range.moveStart( "character", -1 );
|
||||
range.select();
|
||||
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
|
||||
this.exec_command( "createLink", url );
|
||||
this.link_started = this.find_link_at_cursor();
|
||||
} else {
|
||||
this.link_started = null;
|
||||
this.exec_command( "createLink", "/notebooks/" + this.notebook_id + "?note_id=new" );
|
||||
this.exec_command( "createLink", url );
|
||||
return this.find_link_at_cursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Editor.prototype.start_link = function () {
|
||||
return this.insert_link( "/notebooks/" + this.notebook_id + "?note_id=new" );
|
||||
}
|
||||
|
||||
Editor.prototype.start_file_link = function () {
|
||||
return this.insert_link( "/files/new" );
|
||||
}
|
||||
|
||||
Editor.prototype.end_link = function () {
|
||||
this.link_started = null;
|
||||
var link = this.find_link_at_cursor();
|
||||
|
@ -492,46 +500,6 @@ Editor.prototype.end_link = function () {
|
|||
return link;
|
||||
}
|
||||
|
||||
Editor.prototype.insert_file_link = function ( filename, file_id ) {
|
||||
// get the current selection, which is the link title
|
||||
if ( this.iframe.contentWindow && this.iframe.contentWindow.getSelection ) { // browsers such as Firefox
|
||||
var selection = this.iframe.contentWindow.getSelection();
|
||||
|
||||
// if no text is selected, then insert a link with the filename as the link title
|
||||
if ( selection.toString().length == 0 ) {
|
||||
this.insert_html( '<span id="placeholder_title">' + filename + '</span>' );
|
||||
var placeholder = withDocument( this.document, function () { return getElement( "placeholder_title" ); } );
|
||||
selection.selectAllChildren( placeholder );
|
||||
|
||||
this.exec_command( "createLink", "/files/" + file_id );
|
||||
selection.collapseToEnd();
|
||||
|
||||
// replace the placeholder title span with just the filename, yielding an unselected link
|
||||
var link = placeholder.parentNode;
|
||||
link.innerHTML = filename;
|
||||
link.target = "_new";
|
||||
// otherwise, just create a link with the selected text as the link title
|
||||
} else {
|
||||
this.exec_command( "createLink", "/files/" + file_id );
|
||||
var link = this.find_link_at_cursor();
|
||||
link.target = "_new";
|
||||
}
|
||||
} else if ( this.document.selection ) { // browsers such as IE
|
||||
var range = this.document.selection.createRange();
|
||||
|
||||
// if no text is selected, then insert a link with the filename as the link title
|
||||
if ( range.text.length == 0 ) {
|
||||
range.text = filename;
|
||||
range.moveStart( "character", -1 * filename.length );
|
||||
range.select();
|
||||
}
|
||||
|
||||
this.exec_command( "createLink", "/files/" + file_id );
|
||||
var link = this.find_link_at_cursor();
|
||||
link.target = "_new";
|
||||
}
|
||||
}
|
||||
|
||||
Editor.prototype.find_link_at_cursor = function () {
|
||||
if ( this.iframe.contentWindow && this.iframe.contentWindow.getSelection ) { // browsers such as Firefox
|
||||
var selection = this.iframe.contentWindow.getSelection();
|
||||
|
@ -582,18 +550,6 @@ Editor.prototype.find_link_at_cursor = function () {
|
|||
return null;
|
||||
}
|
||||
|
||||
Editor.prototype.node_at_cursor = function () {
|
||||
if ( this.iframe.contentWindow && this.iframe.contentWindow.getSelection ) { // browsers such as Firefox
|
||||
var selection = this.iframe.contentWindow.getSelection();
|
||||
return selection.anchorNode;
|
||||
} else if ( this.document.selection ) { // browsers such as IE
|
||||
var range = this.document.selection.createRange();
|
||||
return range.parentElement();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Editor.prototype.focus = function () {
|
||||
if ( /Opera/.test( navigator.userAgent ) )
|
||||
this.iframe.focus();
|
||||
|
|
|
@ -932,7 +932,21 @@ Wiki.prototype.update_toolbar = function() {
|
|||
this.update_button( "title", "h3", node_names );
|
||||
this.update_button( "insertUnorderedList", "ul", node_names );
|
||||
this.update_button( "insertOrderedList", "ol", node_names );
|
||||
this.update_button( "createLink", "a", node_names );
|
||||
|
||||
var link = this.focused_editor.find_link_at_cursor();
|
||||
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 ) {
|
||||
|
@ -975,7 +989,7 @@ Wiki.prototype.toggle_attach_button = function ( event ) {
|
|||
this.clear_messages();
|
||||
this.clear_pulldowns();
|
||||
|
||||
new Upload_pulldown( this, this.notebook_id, this.invoker, this.focused_editor, this.focused_editor.node_at_cursor() );
|
||||
new Upload_pulldown( this, this.notebook_id, this.invoker, this.focused_editor );
|
||||
}
|
||||
|
||||
event.stop();
|
||||
|
@ -2210,16 +2224,17 @@ Link_pulldown.prototype.shutdown = function () {
|
|||
this.link.pulldown = null;
|
||||
}
|
||||
|
||||
function Upload_pulldown( wiki, notebook_id, invoker, editor, anchor ) {
|
||||
this.anchor = anchor;
|
||||
function Upload_pulldown( wiki, notebook_id, invoker, editor ) {
|
||||
editor.start_file_link();
|
||||
this.link = editor.find_link_at_cursor();
|
||||
|
||||
Pulldown.call( this, wiki, notebook_id, "upload_" + editor.id, anchor, editor.iframe );
|
||||
Pulldown.call( this, wiki, notebook_id, "upload_" + editor.id, this.link, editor.iframe );
|
||||
wiki.down_image_button( "attachFile" );
|
||||
|
||||
this.invoker = invoker;
|
||||
this.editor = editor;
|
||||
this.iframe = createDOM( "iframe", {
|
||||
"src": "/notebooks/upload_page?notebook_id=" + notebook_id + "¬e_id=" + editor.id,
|
||||
"src": "/files/upload_page?notebook_id=" + notebook_id + "¬e_id=" + editor.id,
|
||||
"frameBorder": "0",
|
||||
"scrolling": "no",
|
||||
"id": "upload_frame",
|
||||
|
@ -2237,10 +2252,11 @@ Upload_pulldown.prototype.constructor = Upload_pulldown;
|
|||
|
||||
Upload_pulldown.prototype.init_frame = function () {
|
||||
var self = this;
|
||||
var doc = this.iframe.contentDocument || this.iframe.contentWindow.document;
|
||||
|
||||
withDocument( this.iframe.contentDocument, function () {
|
||||
withDocument( doc, function () {
|
||||
connect( "upload_button", "onclick", function ( event ) {
|
||||
withDocument( self.iframe.contentDocument, function () {
|
||||
withDocument( doc, function () {
|
||||
self.upload_started( getElement( "file" ).value );
|
||||
} );
|
||||
} );
|
||||
|
@ -2254,7 +2270,10 @@ Upload_pulldown.prototype.upload_started = function ( filename ) {
|
|||
pieces = filename.split( "\\" );
|
||||
filename = pieces[ pieces.length - 1 ];
|
||||
|
||||
this.editor.insert_file_link( filename );
|
||||
// the current title is blank, replace the title with the upload's filename
|
||||
if ( link_title( this.link ) == "" )
|
||||
replaceChildNodes( this.link, this.editor.document.createTextNode( filename ) );
|
||||
// TODO: set the link's href to the file
|
||||
}
|
||||
|
||||
Upload_pulldown.prototype.shutdown = function () {
|
||||
|
|
|
@ -16,7 +16,7 @@ class Upload_page( Html ):
|
|||
Input( type = u"submit", id = u"upload_button", class_ = u"button", value = u"upload" ),
|
||||
Input( type = u"hidden", id = u"notebook_id", name = u"notebook_id", value = notebook_id ),
|
||||
Input( type = u"hidden", id = u"note_id", name = u"note_id", value = note_id ),
|
||||
action = u"/notebooks/upload_file",
|
||||
action = u"/files/upload_file",
|
||||
method = u"post",
|
||||
enctype = u"multipart/form-data",
|
||||
),
|
||||
|
|
Reference in New Issue