Browse Source

You can now print an individual note.

Dan Helfman 9 years ago
parent
commit
7def0fe58c

+ 2
- 0
NEWS View File

@@ -1,6 +1,8 @@
1 1
 1.6.8: ?
2 2
  * You can now print your entire notebook. Just click the "print" link on the
3 3
    left side of the page.
4
+ * You can now print an individual note. Just click the "options" tab on a
5
+   note and then "print this note".
4 6
  * Changed the order of exported HTML and CSV notebooks so that after all the
5 7
    "startup" notes are included, the remaining notes are included in
6 8
    alphabetical order (instead of reverse chronological order).

+ 16
- 6
controller/Notebooks.py View File

@@ -1196,16 +1196,19 @@ class Notebooks( object ):
1196 1196
   @validate(
1197 1197
     notebook_id = Valid_id(),
1198 1198
     format = Valid_string( min = 1, max = 100 ),
1199
+    note_id = Valid_id( none_okay = True ),
1199 1200
     user_id = Valid_id( none_okay = True ),
1200 1201
   )
1201
-  def export( self, notebook_id, format, user_id ):
1202
+  def export( self, notebook_id, format, note_id = None, user_id = None ):
1202 1203
     """
1203 1204
     Download the entire contents of the given notebook as a stand-alone file.
1204 1205
 
1205 1206
     @type notebook_id: unicode
1206
-    @param notebook_id: id of notebook to download
1207
+    @param notebook_id: id of notebook to export
1207 1208
     @type format: unicode
1208 1209
     @param format: string indicating the export plugin to use, currently one of: "html", "csv"
1210
+    @type notebook_id: unicode
1211
+    @param note_id: id of single note within the notebook to export (optional)
1209 1212
     @type user_id: unicode
1210 1213
     @param user_id: id of current logged-in user (if any), determined by @grab_user_id
1211 1214
     @rtype: unicode or generator (for streaming files)
@@ -1221,9 +1224,16 @@ class Notebooks( object ):
1221 1224
     if not notebook:
1222 1225
       raise Access_error()
1223 1226
 
1224
-    startup_notes = self.__database.select_many( Note, notebook.sql_load_startup_notes() )
1225
-    other_notes = self.__database.select_many( Note, notebook.sql_load_non_startup_notes() )
1226
-    notes = startup_notes + other_notes
1227
+    if note_id:
1228
+      note = self.__database.load( Note, note_id )
1229
+      if not note:
1230
+        raise Access_error()
1231
+      notes = [ note ]
1232
+      notebook = None
1233
+    else:
1234
+      startup_notes = self.__database.select_many( Note, notebook.sql_load_startup_notes() )
1235
+      other_notes = self.__database.select_many( Note, notebook.sql_load_non_startup_notes() )
1236
+      notes = startup_notes + other_notes
1227 1237
 
1228 1238
     from plugins.Invoke import invoke
1229 1239
 
@@ -1233,7 +1243,7 @@ class Notebooks( object ):
1233 1243
         plugin_name = format,
1234 1244
         database = self.__database,
1235 1245
         notebook = notebook,
1236
-        notes = startup_notes + other_notes,
1246
+        notes = notes,
1237 1247
         response_headers = cherrypy.response.headerMap,
1238 1248
       )
1239 1249
     except ( ImportError, AttributeError ):

+ 39
- 0
controller/test/Test_notebooks.py View File

@@ -4801,6 +4801,45 @@ class Test_notebooks( Test_controller ):
4801 4801
 
4802 4802
     assert u"access" in result[ "body" ][ 0 ]
4803 4803
 
4804
+  def test_export_print_with_note_id( self ):
4805
+    self.login()
4806
+
4807
+    note3 = Note.create( "55", u"<h3>blah</h3>foo", notebook_id = self.notebook.object_id )
4808
+    self.database.save( note3 )
4809
+
4810
+    result = self.http_get(
4811
+      "/notebooks/export?notebook_id=%s&format=print&note_id=%s" % ( self.notebook.object_id, note3.object_id ),
4812
+      session_id = self.session_id,
4813
+    )
4814
+
4815
+    assert result.get( "notebook" ) == None
4816
+    assert result.get( "view" )
4817
+
4818
+    notes = result.get( "notes" )
4819
+    assert len( notes ) == 1
4820
+    note = notes[ 0 ]
4821
+
4822
+    assert note.object_id == note3.object_id
4823
+    assert note.revision == note3.revision
4824
+    assert note.title == note3.title
4825
+    assert note.contents == note3.contents
4826
+    assert note.notebook_id == note3.notebook_id
4827
+    assert note.startup == note3.startup
4828
+    assert note.deleted_from_id == note3.deleted_from_id
4829
+    assert note.rank == note3.rank
4830
+    assert note.user_id == note3.user_id
4831
+    assert note.creation == note3.creation
4832
+ 
4833
+  def test_export_print_with_unknown_note_id( self ):
4834
+    self.login()
4835
+
4836
+    result = self.http_get(
4837
+      "/notebooks/export?notebook_id=%s&format=print&note_id=%s" % ( self.notebook.object_id, self.unknown_note_id ),
4838
+      session_id = self.session_id,
4839
+    )
4840
+
4841
+    assert u"access" in result[ "body" ][ 0 ]
4842
+
4804 4843
   def test_create( self ):
4805 4844
     self.login()
4806 4845
 

+ 1
- 1
plugins/export_html/Html_file.py View File

@@ -18,7 +18,7 @@ class Html_file( Html ):
18 18
       contents = self.IMAGE_PATTERN.sub( '', contents )
19 19
       relinked_notes[ note.object_id ] = contents
20 20
 
21
-    response_headers[ u"Content-Disposition" ] = u"attachment; filename=%s.html" % notebook.friendly_id
21
+    response_headers[ u"Content-Disposition" ] = u"attachment; filename=%s.html" % notebook and notebook.friendly_id
22 22
 
23 23
     Html.__init__(
24 24
       self,

+ 2
- 2
plugins/export_print/Print_notes.py View File

@@ -19,11 +19,11 @@ class Print_notes( Html ):
19 19
         Style( file( u"static/css/download.css" ).read(), type = u"text/css" ),
20 20
         Style( file( u"static/css/print.css" ).read(), type = u"text/css" ),
21 21
         Meta( content = u"text/html; charset=UTF-8", http_equiv = u"content-type" ),
22
-        Title( notebook.name ),
22
+        Title( notebook and notebook.name or notes[ 0 ].title ),
23 23
       ),
24 24
       Body(
25 25
         Div(
26
-          H1( notebook.name ),
26
+          notebook and H1( notebook.name ) or None,
27 27
           [ Span(
28 28
             A( name = u"note_%s" % note.object_id ),
29 29
             Div(

+ 34
- 0
plugins/export_print/test/Test_export_print.py View File

@@ -73,3 +73,37 @@ class Test_export_html( object ):
73 73
       assert note.rank == expected_note.rank
74 74
       assert note.user_id == expected_note.user_id
75 75
       assert note.creation == expected_note.creation
76
+
77
+  def test_export_print_without_notebook( self ):
78
+    note3 = Note.create( "55", u"<h3>blah</h3>foo", notebook_id = self.notebook.object_id )
79
+    self.database.save( note3 )
80
+    response_headers = {}
81
+    expected_notes = ( self.note1, self.note2, note3 )
82
+
83
+    result = invoke(
84
+      "export",
85
+      "print",
86
+      self.database,
87
+      None,
88
+      expected_notes,
89
+      response_headers,
90
+    )
91
+
92
+    # response headers should be unchanged
93
+    assert response_headers == {}
94
+
95
+    notes = result.get( "notes" )
96
+    assert len( notes ) == len( expected_notes )
97
+
98
+    # assert that the notes are in the expected order
99
+    for ( note, expected_note ) in zip( notes, expected_notes ):
100
+      assert note.object_id == expected_note.object_id
101
+      assert note.revision == expected_note.revision
102
+      assert note.title == expected_note.title
103
+      assert note.contents == expected_note.contents
104
+      assert note.notebook_id == expected_note.notebook_id
105
+      assert note.startup == expected_note.startup
106
+      assert note.deleted_from_id == expected_note.deleted_from_id
107
+      assert note.rank == expected_note.rank
108
+      assert note.user_id == expected_note.user_id
109
+      assert note.creation == expected_note.creation

+ 12
- 2
static/js/Wiki.js View File

@@ -3217,9 +3217,19 @@ function Options_pulldown( wiki, notebook_id, invoker, editor ) {
3217 3217
   this.startup_label = createDOM( "label", { "for": "startup_checkbox", "class": "pulldown_label", "title": "Display this note whenever the notebook is loaded." },
3218 3218
     "show on startup"
3219 3219
   );
3220
+  this.print_checkbox = createDOM( "input", { "type": "checkbox", "class": "pulldown_checkbox invisible" } );
3221
+  this.print_link = createDOM( "a",
3222
+    {
3223
+      "href": "/notebooks/export?notebook_id=" + notebook_id + "&note_id=" + editor.id + "&format=print",
3224
+      "target": "_new",
3225
+      "class": "pulldown_link",
3226
+      "title": "Print this note by itself."
3227
+    },
3228
+    "print this note"
3229
+  );
3220 3230
 
3221
-  appendChildNodes( this.div, this.startup_checkbox );
3222
-  appendChildNodes( this.div, this.startup_label );
3231
+  appendChildNodes( this.div, createDOM( "div", {}, this.startup_checkbox, this.startup_label ) );
3232
+  appendChildNodes( this.div, createDOM( "div", {}, this.print_checkbox, this.print_link ) );
3223 3233
   this.startup_checkbox.checked = editor.startup;
3224 3234
 
3225 3235
   var self = this;