Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(434)

Side by Side Diff: third_party/twisted_8_1/twisted/web/woven/controller.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.web.test.test_woven -*-
2 #
3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
4 # See LICENSE for details.
5
6
7 from __future__ import nested_scopes
8
9 __version__ = "$Revision: 1.67 $"[11:-2]
10
11 import os
12 import cgi
13 import types
14
15 from twisted.python import log
16 from twisted.python import components
17 from twisted.python import failure
18 from zope.interface import implements
19 from twisted.web import resource, server, static
20 from twisted.web.woven import interfaces, utils
21 from twisted.web import woven
22 from twisted.web import microdom
23 from twisted.web.static import redirectTo, addSlash
24
25 import warnings
26 from time import time as now
27
28 def controllerFactory(controllerClass):
29 return lambda request, node, model: controllerClass(model)
30
31 def controllerMethod(controllerClass):
32 return lambda self, request, node, model: controllerClass(model)
33
34
35 class Controller(resource.Resource):
36 """
37 A Controller which handles to events from the user. Such events
38 are `web request', `form submit', etc.
39
40 I should be the IResource implementor for your Models (and
41 L{registerControllerForModel} makes this so).
42 """
43
44 implements(interfaces.IController)
45 setupStacks = 1
46 addSlash = 1 # Should this controller add a slash to the url automatically?
47 controllerLibraries = []
48 viewFactory = None
49 templateDirectory = ""
50 def __init__(self, m, inputhandlers=None, view=None, controllers=None, templ ateDirectory = None):
51 #self.start = now()
52 resource.Resource.__init__(self)
53 self.model = m
54 # It's the responsibility of the calling code to make sure setView is
55 # called on this controller before it's rendered.
56 self.view = None
57 self.subcontrollers = []
58 if self.setupStacks:
59 self.setupControllerStack()
60 if inputhandlers is None and controllers is None:
61 self._inputhandlers = []
62 elif inputhandlers:
63 print "The inputhandlers arg is deprecated, please use controllers i nstead"
64 self._inputhandlers = inputhandlers
65 else:
66 self._inputhandlers = controllers
67 if templateDirectory is not None:
68 self.templateDirectory = templateDirectory
69 self._valid = {}
70 self._invalid = {}
71 self._process = {}
72 self._parent = None
73
74 def setupControllerStack(self):
75 self.controllerStack = utils.Stack([])
76 from twisted.web.woven import input
77 if input not in self.controllerLibraries:
78 self.controllerLibraries.append(input)
79 for library in self.controllerLibraries:
80 self.importControllerLibrary(library)
81 self.controllerStack.push(self)
82
83 def importControllerLibrary(self, namespace):
84 if not hasattr(namespace, 'getSubcontroller'):
85 namespace.getSubcontroller = utils.createGetFunction(namespace)
86 self.controllerStack.push(namespace)
87
88 def getSubcontroller(self, request, node, model, controllerName):
89 controller = None
90 cm = getattr(self, 'wcfactory_' +
91 controllerName, None)
92 if cm is None:
93 cm = getattr(self, 'factory_' +
94 controllerName, None)
95 if cm is not None:
96 warnings.warn("factory_ methods are deprecated; please use "
97 "wcfactory_ instead", DeprecationWarning)
98 if cm:
99 if cm.func_code.co_argcount == 1 and not type(cm) == types.LambdaTyp e:
100 warnings.warn("A Controller Factory takes "
101 "(request, node, model) "
102 "now instead of (model)", DeprecationWarning)
103 controller = controllerFactory(model)
104 else:
105 controller = cm(request, node, model)
106 return controller
107
108 def setSubcontrollerFactory(self, name, factory, setup=None):
109 setattr(self, "wcfactory_" + name, lambda request, node, m:
110 factory(m))
111
112 def setView(self, view):
113 self.view = view
114
115 def setNode(self, node):
116 self.node = node
117
118 def setUp(self, request, *args):
119 """
120 @type request: L{twisted.web.server.Request}
121 """
122 pass
123
124 def getChild(self, name, request):
125 """
126 Look for a factory method to create the object to handle the
127 next segment of the URL. If a wchild_* method is found, it will
128 be called to produce the Resource object to handle the next
129 segment of the path. If a wchild_* method is not found,
130 getDynamicChild will be called with the name and request.
131
132 @param name: The name of the child being requested.
133 @type name: string
134 @param request: The HTTP request being handled.
135 @type request: L{twisted.web.server.Request}
136 """
137 if not name:
138 method = "index"
139 else:
140 method = name.replace('.', '_')
141 f = getattr(self, "wchild_%s" % method, None)
142 if f:
143 return f(request)
144 else:
145 child = self.getDynamicChild(name, request)
146 if child is None:
147 return resource.Resource.getChild(self, name, request)
148 else:
149 return child
150
151 def getDynamicChild(self, name, request):
152 """
153 This method is called when getChild cannot find a matching wchild_*
154 method in the Controller. Override me if you wish to have dynamic
155 handling of child pages. Should return a Resource if appropriate.
156 Return None to indicate no resource found.
157
158 @param name: The name of the child being requested.
159 @type name: string
160 @param request: The HTTP request being handled.
161 @type request: L{twisted.web.server.Request}
162 """
163 pass
164
165 def wchild_index(self, request):
166 """By default, we return ourself as the index.
167 Override this to provide different behavior
168 for a URL that ends in a slash.
169 """
170 self.addSlash = 0
171 return self
172
173 def render(self, request):
174 """
175 Trigger any inputhandlers that were passed in to this Page,
176 then delegate to the View for traversing the DOM. Finally,
177 call gatheredControllers to deal with any InputHandlers that
178 were constructed from any controller= tags in the
179 DOM. gatheredControllers will render the page to the browser
180 when it is done.
181 """
182 if self.addSlash and request.uri.split('?')[0][-1] != '/':
183 return redirectTo(addSlash(request), request)
184 # Handle any inputhandlers that were passed in to the controller first
185 for ih in self._inputhandlers:
186 ih._parent = self
187 ih.handle(request)
188 self._inputhandlers = []
189 for key, value in self._valid.items():
190 key.commit(request, None, value)
191 self._valid = {}
192 return self.renderView(request)
193
194 def makeView(self, model, templateFile=None, parentCount=0):
195 if self.viewFactory is None:
196 self.viewFactory = self.__class__
197 v = self.viewFactory(model, templateFile=templateFile, templateDirectory =self.templateDirectory)
198 v.parentCount = parentCount
199 v.tapestry = self
200 v.importViewLibrary(self)
201 return v
202
203 def renderView(self, request):
204 if self.view is None:
205 if self.viewFactory is not None:
206 self.setView(self.makeView(self.model, None))
207 else:
208 self.setView(interfaces.IView(self.model, None))
209 self.view.setController(self)
210 return self.view.render(request, doneCallback=self.gatheredControllers)
211
212 def gatheredControllers(self, v, d, request):
213 process = {}
214 request.args = {}
215 for key, value in self._valid.items():
216 key.commit(request, None, value)
217 process[key.submodel] = value
218 self.process(request, **process)
219 #log.msg("Sending page!")
220 self.pageRenderComplete(request)
221 utils.doSendPage(v, d, request)
222 #v.unlinkViews()
223
224 #print "Page time: ", now() - self.start
225 #return view.View.render(self, request, block=0)
226
227 def aggregateValid(self, request, input, data):
228 self._valid[input] = data
229
230 def aggregateInvalid(self, request, input, data):
231 self._invalid[input] = data
232
233 def process(self, request, **kwargs):
234 if kwargs:
235 log.msg("Processing results: ", kwargs)
236
237 def setSubmodel(self, submodel):
238 self.submodel = submodel
239
240 def handle(self, request):
241 """
242 By default, we don't do anything
243 """
244 pass
245
246 def exit(self, request):
247 """We are done handling the node to which this controller was attached.
248 """
249 pass
250
251 def domChanged(self, request, widget, node):
252 parent = getattr(self, '_parent', None)
253 if parent is not None:
254 parent.domChanged(request, widget, node)
255
256 def pageRenderComplete(self, request):
257 """Override this to recieve notification when the view rendering
258 process is complete.
259 """
260 pass
261
262 WOVEN_PATH = os.path.split(woven.__file__)[0]
263
264 class LiveController(Controller):
265 """A Controller that encapsulates logic that makes it possible for this
266 page to be "Live". A live page can have it's content updated after the
267 page has been sent to the browser, and can translate client-side
268 javascript events into server-side events.
269 """
270 pageSession = None
271 def render(self, request):
272 """First, check to see if this request is attempting to hook up the
273 output conduit. If so, do it. Otherwise, unlink the current session's
274 View from the MVC notification infrastructure, then render the page
275 normally.
276 """
277 # Check to see if we're hooking up an output conduit
278 sess = request.getSession(interfaces.IWovenLivePage)
279 #print "REQUEST.ARGS", request.args
280 if request.args.has_key('woven_hookupOutputConduitToThisFrame'):
281 sess.hookupOutputConduit(request)
282 return server.NOT_DONE_YET
283 if request.args.has_key('woven_clientSideEventName'):
284 try:
285 request.d = microdom.parseString('<xml/>', caseInsensitive=0, pr eserveCase=0)
286 eventName = request.args['woven_clientSideEventName'][0]
287 eventTarget = request.args['woven_clientSideEventTarget'][0]
288 eventArgs = request.args.get('woven_clientSideEventArguments', [ ])
289 #print "EVENT", eventName, eventTarget, eventArgs
290 return self.clientToServerEvent(request, eventName, eventTarget, eventArgs)
291 except:
292 fail = failure.Failure()
293 self.view.renderFailure(fail, request)
294 return server.NOT_DONE_YET
295
296 # Unlink the current page in this user's session from MVC notifications
297 page = sess.getCurrentPage()
298 #request.currentId = getattr(sess, 'currentId', 0)
299 if page is not None:
300 page.view.unlinkViews()
301 sess.setCurrentPage(None)
302 #print "PAGE SESSION IS NONE"
303 self.pageSession = None
304 return Controller.render(self, request)
305
306 def clientToServerEvent(self, request, eventName, eventTarget, eventArgs):
307 """The client sent an asynchronous event to the server.
308 Locate the View object targeted by this event and attempt
309 to call onEvent on it.
310 """
311 sess = request.getSession(interfaces.IWovenLivePage)
312 self.view = sess.getCurrentPage().view
313 #request.d = self.view.d
314 print "clientToServerEvent", eventTarget
315 target = self.view.subviews[eventTarget]
316 print "target, parent", target, target.parent
317 #target.parent = self.view
318 #target.controller._parent = self
319
320 ## From the time we call onEvent until it returns, we want all
321 ## calls to IWovenLivePage.sendScript to be appended to this
322 ## list so we can spit them out in the response, immediately
323 ## below.
324 scriptOutput = []
325 orig = sess.sendScript
326 sess.sendScript = scriptOutput.append
327 target.onEvent(request, eventName, *eventArgs)
328 sess.sendScript = orig
329
330 scriptOutput.append('parent.woven_clientToServerEventComplete()')
331
332 #print "GATHERED JS", scriptOutput
333
334 return '''<html>
335 <body>
336 <script language="javascript">
337 %s
338 </script>
339 %s event sent to %s (%s) with arguments %s.
340 </body>
341 </html>''' % ('\n'.join(scriptOutput), eventName, cgi.escape(str(target)), event Target, eventArgs)
342
343 def gatheredControllers(self, v, d, request):
344 Controller.gatheredControllers(self, v, d, request)
345 sess = request.getSession(interfaces.IWovenLivePage)
346 self.pageSession = sess
347 sess.setCurrentPage(self)
348 sess.currentId = request.currentId
349
350 def domChanged(self, request, widget, node):
351 sess = request.getSession(interfaces.IWovenLivePage)
352 print "domchanged"
353 if sess is not None:
354 if not hasattr(node, 'getAttribute'):
355 return
356 page = sess.getCurrentPage()
357 if page is None:
358 return
359 nodeId = node.getAttribute('id')
360 #logger.warn("DOM for %r is changing to %s", nodeId, node.toprettyxm l())
361 nodeXML = node.toxml()
362 nodeXML = nodeXML.replace("\\", "\\\\")
363 nodeXML = nodeXML.replace("'", "\\'")
364 nodeXML = nodeXML.replace('"', '\\"')
365 nodeXML = nodeXML.replace('\n', '\\n')
366 nodeXML = nodeXML.replace('\r', ' ')
367 nodeXML = nodeXML.replace('\b', ' ')
368 nodeXML = nodeXML.replace('\t', ' ')
369 nodeXML = nodeXML.replace('\000', ' ')
370 nodeXML = nodeXML.replace('\v', ' ')
371 nodeXML = nodeXML.replace('\f', ' ')
372
373 js = "parent.woven_replaceElement('%s', '%s')" % (nodeId, nodeXML)
374 #for key in widget.subviews.keys():
375 # view.subviews[key].unlinkViews()
376 oldNode = page.view.subviews[nodeId]
377 for id, subview in oldNode.subviews.items():
378 subview.unlinkViews()
379 topSubviews = page.view.subviews
380 #print "Widgetid, subviews", id(widget), widget.subviews
381 if widget.subviews:
382 def recurseSubviews(w):
383 #print "w.subviews", w.subviews
384 topSubviews.update(w.subviews)
385 for id, sv in w.subviews.items():
386 recurseSubviews(sv)
387 #print "recursing"
388 recurseSubviews(widget)
389 #page.view.subviews.update(widget.subviews)
390 sess.sendScript(js)
391
392 def wchild_WebConduit2_js(self, request):
393 #print "returning js file"
394 h = request.getHeader("user-agent")
395 if h.count("MSIE"):
396 fl = "WebConduit2_msie.js"
397 else:
398 fl = "WebConduit2_mozilla.js"
399
400 return static.File(os.path.join(WOVEN_PATH, fl))
401
402 def wchild_FlashConduit_swf(self, request):
403 #print "returning flash file"
404 h = request.getHeader("user-agent")
405 if h.count("MSIE"):
406 fl = "FlashConduit.swf"
407 else:
408 fl = "FlashConduit.swf"
409 return static.File(os.path.join(WOVEN_PATH, fl))
410
411 def wchild_input_html(self, request):
412 return BlankPage()
413
414
415 class BlankPage(resource.Resource):
416 def render(self, request):
417 return "<html>This space intentionally left blank</html>"
418
419
420 WController = Controller
421
422 def registerControllerForModel(controller, model):
423 """
424 Registers `controller' as an adapter of `model' for IController, and
425 optionally registers it for IResource, if it implements it.
426
427 @param controller: A class that implements L{interfaces.IController}, usuall y a
428 L{Controller} subclass. Optionally it can implement
429 L{resource.IResource}.
430 @param model: Any class, but probably a L{twisted.web.woven.model.Model}
431 subclass.
432 """
433 components.registerAdapter(controller, model, interfaces.IController)
434 if resource.IResource.implementedBy(controller):
435 components.registerAdapter(controller, model, resource.IResource)
436
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/web/woven/__init__.py ('k') | third_party/twisted_8_1/twisted/web/woven/dirlist.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698