Personal wiki notebook (not under development)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Main_page.py 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. from urllib import urlencode
  2. from cgi import escape
  3. from Page import Page
  4. from Header import Header
  5. from Tags import Link, Input, Div, Span, H2, H4, A, Br, Strong, Script, Img, P, Noscript, Table, Td, Tr
  6. from Note_tree_area import Note_tree_area
  7. from Link_area import Link_area
  8. from Toolbar import Toolbar
  9. from Json import Json
  10. from Rounded_div import Rounded_div
  11. from config.Version import VERSION
  12. from model.Notebook import Notebook
  13. from Page_navigation import Page_navigation
  14. class Main_page( Page ):
  15. def __init__(
  16. self,
  17. user,
  18. rate_plan,
  19. notebooks,
  20. notebook,
  21. parent_id = None,
  22. login_url = None,
  23. logout_url = None,
  24. startup_notes = None,
  25. total_notes_count = None,
  26. notes = None,
  27. note_read_write = True,
  28. start = None,
  29. count = None,
  30. http_url = None,
  31. conversion = None,
  32. rename = False,
  33. deleted_id = None,
  34. invites = None,
  35. invite_id = None,
  36. after_login = None,
  37. signup_plan = None,
  38. signup_yearly = None,
  39. recent_notes = None,
  40. groups = None,
  41. ):
  42. startup_note_ids = [ startup_note.object_id for startup_note in startup_notes ]
  43. def note_controls( note, read_write ):
  44. read_write_access = ( read_write == Notebook.READ_WRITE ) or \
  45. ( read_write == Notebook.READ_WRITE_FOR_OWN_NOTES and note.user_id == user.object_id )
  46. return Div(
  47. read_write_access and Input(
  48. type = "button",
  49. class_ = "note_button",
  50. id = "delete_note_%s" % note.object_id,
  51. value = "delete" + ( note.deleted_from_id and " forever" or "" ),
  52. title = "delete note [ctrl-d]"
  53. ) or None,
  54. read_write_access and note.deleted_from_id and Input(
  55. type = "button",
  56. class_ = "note_button",
  57. id = "undelete_note_%s" % note.object_id,
  58. value = "undelete",
  59. title = "undelete note"
  60. ) or None,
  61. ( read_write == Notebook.READ_WRITE ) and not note.deleted_from_id and Input(
  62. type = "button",
  63. class_ = "note_button",
  64. id = "changes_note_%s" % note.object_id,
  65. value = "changes",
  66. title = "previous revisions",
  67. ) or None,
  68. ( read_write == Notebook.READ_WRITE ) and not note.deleted_from_id and Input(
  69. type = "button",
  70. class_ = "note_button",
  71. id = "tools_note_%s" % note.object_id,
  72. value = "tools",
  73. title = "note tools",
  74. ) or None,
  75. ( read_write != Notebook.READ_ONLY or not note.startup ) and not note.deleted_from_id and \
  76. ( read_write != Notebook.READ_WRITE_FOR_OWN_NOTES ) and Input(
  77. type = "button",
  78. class_ = "note_button",
  79. id = "hide_note_%s" % note.object_id,
  80. value = "hide",
  81. title = "hide note [ctrl-h]",
  82. ) or None,
  83. id = u"note_controls_%s" % note.object_id,
  84. class_ = u"note_controls",
  85. )
  86. def static_note_divs( notes, read_write ):
  87. return [ Table(
  88. Tr( Td(
  89. note_controls( note, read_write ),
  90. ) ),
  91. Tr(
  92. Td(
  93. Div(
  94. Span(
  95. note.contents,
  96. class_ = u"static_note_contents",
  97. separator = "",
  98. ),
  99. id = "static_note_%s" % note.object_id,
  100. class_ = u"static_note_div",
  101. ),
  102. width = "100%",
  103. ),
  104. Td(
  105. u".....",
  106. id = u"note_grabber_%s" % note.object_id,
  107. class_ = u"note_grabber" + ( read_write != Notebook.READ_WRITE and " invisible" or "" ),
  108. ),
  109. ),
  110. Tr(
  111. Td(
  112. Div( class_ = "note_shadow_corner" ),
  113. id = u"note_shadow_%s" % note.object_id,
  114. class_ = u"note_shadow undisplayed",
  115. ),
  116. ),
  117. id = u"note_holder_%s" % note.object_id,
  118. class_ = u"note_holder",
  119. ) for note in notes ]
  120. static_notes = notes and static_note_divs( notes, note_read_write and notebook.read_write or Notebook.READ_ONLY ) or \
  121. static_note_divs( startup_notes, notebook.read_write )
  122. # Since the contents of these notes are included in the static_notes section below, don't
  123. # include them again in the hidden fields here. Accomplish this by making custom dicts for
  124. # sending to the client.
  125. startup_note_dicts = [ {
  126. u"object_id" : startup_note.object_id,
  127. u"revision" : startup_note.revision,
  128. u"deleted_from_id" : startup_note.deleted_from_id,
  129. u"user_id": startup_note.user_id,
  130. u"username": startup_note.username,
  131. } for startup_note in startup_notes ]
  132. note_dicts = [ {
  133. u"object_id" : note.object_id,
  134. u"revision" : note.revision,
  135. u"deleted_from_id" : note.deleted_from_id,
  136. u"user_id": note.user_id,
  137. u"username": note.username,
  138. u"creation" : note.creation,
  139. } for note in notes ]
  140. root_notes = startup_notes + ( notes and [ note for note in notes if note.object_id not in startup_note_ids ] or [] )
  141. def json( string ):
  142. return escape( unicode( Json( string ) ), quote = True )
  143. if len( notes ) == 1:
  144. title = notes[ 0 ].title
  145. else:
  146. title = notebook.name
  147. if rate_plan.get( u"notebook_sharing" ):
  148. updates_path = u"/notebooks/updates/%s?rss&%s" % (
  149. notebook.object_id,
  150. urlencode( [ ( u"notebook_name", notebook.name.encode( "utf8" ) ) ] ),
  151. )
  152. else:
  153. updates_path = None
  154. forum_tags = [ tag for tag in notebook.tags if tag.name == u"forum" ]
  155. forum_tag = None
  156. if notebook.name == u"Luminotes":
  157. notebook_path = u"/"
  158. updates_path = None # no RSS feed for the main notebook
  159. elif notebook.name == u"Luminotes user guide":
  160. notebook_path = u"/guide"
  161. elif forum_tags:
  162. forum_tag = forum_tags[ 0 ]
  163. if forum_tag.value == u"blog":
  164. notebook_path = u"/blog/%s" % notebook.friendly_id
  165. else:
  166. notebook_path = u"/forums/%s/%s" % ( forum_tag.value, notebook.object_id )
  167. else:
  168. notebook_path = u"/notebooks/%s" % notebook.object_id
  169. conversion_js = None
  170. if conversion:
  171. try:
  172. conversion_js = file( u"static/js/%s_conversion.js" % conversion ).read()
  173. except IOError:
  174. pass
  175. if notebook.read_write == Notebook.READ_WRITE:
  176. header_note_title = u"wiki"
  177. else:
  178. all_notes = startup_notes + notes
  179. header_note_title = ( notebook.name == "Luminotes" ) and all_notes and all_notes[ 0 ].title or notebook.name
  180. header_note_title = {
  181. "contact info": "contact",
  182. "meet the team": "team",
  183. "Luminotes user guide": "guide",
  184. "Luminotes privacy policy": "privacy",
  185. }.get( header_note_title, header_note_title )
  186. own_notebooks = [ nb for nb in notebooks if nb.read_write == Notebook.READ_WRITE ]
  187. header_notebook = own_notebooks and own_notebooks[ 0 ] or notebook
  188. Page.__init__(
  189. self,
  190. title,
  191. Link( rel = u"stylesheet", type = u"text/css", href = u"/static/css/header.css?%s" % VERSION ),
  192. updates_path and \
  193. Link( rel = u"alternate", type = u"application/rss+xml", title = notebook.name, href = updates_path ) or None,
  194. Script( type = u"text/javascript", src = u"/static/js/MochiKit.js?%s" % VERSION ) or None,
  195. Script( type = u"text/javascript", src = u"/static/js/Invoker.js?%s" % VERSION ) or None,
  196. Script( type = u"text/javascript", src = u"/static/js/Editor.js?%s" % VERSION ) or None,
  197. Script( type = u"text/javascript", src = u"/static/js/Wiki.js?%s" % VERSION ) or None,
  198. Input( type = u"hidden", name = u"user", id = u"user", value = json( user ) ),
  199. Input( type = u"hidden", name = u"rate_plan", id = u"rate_plan", value = json( rate_plan ) ),
  200. Input( type = u"hidden", name = u"yearly", id = u"yearly", value = json( signup_yearly ) ),
  201. Input( type = u"hidden", name = u"notebooks", id = u"notebooks", value = json( notebooks ) ),
  202. Input( type = u"hidden", name = u"notebook", id = u"notebook", value = json( notebook ) ),
  203. Input( type = u"hidden", name = u"parent_id", id = u"parent_id", value = parent_id or "" ),
  204. Input( type = u"hidden", name = u"startup_notes", id = u"startup_notes", value = json( startup_note_dicts ) ),
  205. Input( type = u"hidden", name = u"current_notes", id = u"current_notes", value = json( note_dicts ) ),
  206. Input( type = u"hidden", name = u"note_read_write", id = u"note_read_write", value = json( note_read_write ) ),
  207. Input( type = u"hidden", name = u"rename", id = u"rename", value = json( rename ) ),
  208. Input( type = u"hidden", name = u"deleted_id", id = u"deleted_id", value = deleted_id ),
  209. Input( type = u"hidden", name = u"invites", id = u"invites", value = json( invites ) ),
  210. Input( type = u"hidden", name = u"invite_id", id = u"invite_id", value = invite_id ),
  211. Input( type = u"hidden", name = u"after_login", id = u"after_login", value = after_login ),
  212. Input( type = u"hidden", name = u"signup_plan", id = u"signup_plan", value = signup_plan ),
  213. Input( type = u"hidden", name = u"groups", id = u"groups", value = json( groups ) ),
  214. Div(
  215. id = u"status_area",
  216. ),
  217. Header( user, header_notebook, login_url, logout_url, header_note_title, rate_plan ),
  218. Div(
  219. Div(
  220. Link_area(
  221. Toolbar(
  222. notebook,
  223. hide_toolbar = parent_id or notebook.read_write == Notebook.READ_ONLY,
  224. note_word = forum_tag and u"post" or u"note",
  225. ),
  226. notebooks, notebook, parent_id, notebook_path, updates_path, user, rate_plan,
  227. ),
  228. id = u"left_area",
  229. ),
  230. Div(
  231. ( notebook.read_write != Notebook.READ_ONLY ) and Noscript(
  232. P( Strong(
  233. u"""
  234. Luminotes requires JavaScript to be enabled in your web browser in order to edit
  235. your wiki. Please <a href="/enable_javascript">enable JavaScript</a> before continuing.
  236. """
  237. ) ),
  238. ) or None,
  239. Rounded_div(
  240. ( notebook.name == u"trash" ) and u"trash_notebook" or u"current_notebook",
  241. parent_id and Span(
  242. A( u"empty", href = u"/notebooks/%s" % notebook.object_id, id = u"empty_trash_link" ),
  243. u" | ",
  244. A( u"go back", href = u"/notebooks/%s" % parent_id ),
  245. id = u"notebook_header_links",
  246. ) or None,
  247. ( notebook.name == u"Luminotes" and title == u"source code" ) and \
  248. Strong( "%s %s" % ( notebook.name, VERSION ) ) or \
  249. Span(
  250. ( notebook.name == u"trash" or notebook.read_write != Notebook.READ_WRITE ) \
  251. and Strong( notebook.name ) \
  252. or Span( Strong( notebook.name ), id = u"notebook_header_name", title = "Rename this notebook." ),
  253. ),
  254. id = u"notebook_header_area",
  255. corners = ( u"tl", u"tr", u"br" ),
  256. ),
  257. Div(
  258. Rounded_div(
  259. ( notebook.name == u"trash" ) and u"trash_notebook_inner" or u"current_notebook_inner",
  260. Div(
  261. id = u"deleted_notebooks",
  262. ),
  263. Page_navigation(
  264. notebook_path, len( notes ), total_notes_count, start, count,
  265. ),
  266. Div(
  267. Span( id = u"notes_top" ),
  268. static_notes,
  269. id = u"notes",
  270. ),
  271. ( notebook.read_write == Notebook.READ_WRITE ) and Div(
  272. id = u"blank_note_stub",
  273. class_ = u"blank_note_stub_hidden_border",
  274. ) or None,
  275. ( forum_tag and user.username and user.username != u"anonymous" ) and \
  276. Span(
  277. ( forum_tag.value == "blog" ) and
  278. P( u"To write a comment, click that large \"+\" button to the left. To publish your comment, click the save button.",
  279. class_ = u"small_text" ) or
  280. P( u"To write a comment, click that large \"+\" button to the left. To publish your comment, click the save button. Or, ",
  281. A( u"start a new discussion", href = u"/forums/%s/create_thread" % forum_tag.value ), u".", separator = "",
  282. class_ = u"small_text" ),
  283. ) or None,
  284. ( forum_tag and ( not user.username or user.username == u"anonymous" ) ) and \
  285. P( u"To write a comment, please login first. No account?", A( u"Sign up", href = u"/pricing" ), u"to get a free account.", class_ = "small_text" ) or None,
  286. Page_navigation(
  287. notebook_path, len( notes ), total_notes_count, start, count,
  288. return_text = u"return to the discussion",
  289. ),
  290. Div(
  291. id = u"iframe_area",
  292. ),
  293. id = u"notebook_background",
  294. corners = ( u"tl", ),
  295. ),
  296. id = u"notebook_border",
  297. class_ = ( notebook.name == u"trash" ) and u"trash_notebook_color" or u"current_notebook_color",
  298. ),
  299. id = u"center_content_area",
  300. ),
  301. Div(
  302. Note_tree_area(
  303. notebook,
  304. root_notes,
  305. recent_notes,
  306. total_notes_count,
  307. user,
  308. ),
  309. id = u"right_area",
  310. ),
  311. id = u"everything_area",
  312. ),
  313. Span( id = "grabber_hover_preload" ),
  314. )