=== modified file 'examples/pykhtmlsite.py'
--- examples/pykhtmlsite.py 2007-02-05 22:39:48 +0000
+++ examples/pykhtmlsite.py 2007-02-11 15:51:11 +0000
@@ -9,24 +9,32 @@
PyKHTMLUrl = "http://localhost/PyKHTML/"
-browser = pykhtml.Browser()
-
-def extractBitsFromPage():
+def extractBitsFromPage(browser):
# getElementsByTagName returns a generator, so we convert
# to a list and access the first element
title = list(browser.document.getElementsByTagName("title"))[0]
print "Title:", title.text
+ # Get the navigation
navigation = []
for item in browser.document.getElementById("navigation").children:
- # if this child item is an element and its tag name
- # is 'li' (i.e if it's a list item)
+ # if this child item is an element (as opposed to
+ # a text node or whatever) and its tag name is 'li'
+ # (i.e if it's a list item)
if isinstance(item, pykhtml.dom.Element) and item.tagName == "li":
- navigation.append(item.children[0].text)
+ # Add the text contents of the list item's first
+ # child to our list
+ anchor = item.children[0]
+ navigation.append(anchor.text)
print "Navigation:", " | ".join(navigation)
+ # Stop here, we're done
pykhtml.stopEventLoop()
def main():
+ browser = pykhtml.Browser()
+ # the browser is passed as a parameter to extractBitsFromPage
+ # when it is called (when the page has loaded)
browser.load(PyKHTMLUrl, extractBitsFromPage)
+ # kick things off
pykhtml.startEventLoop()
=== modified file 'pykhtml/__init__.py'
--- pykhtml/__init__.py 2007-02-10 20:22:22 +0000
+++ pykhtml/__init__.py 2007-02-11 15:51:11 +0000
@@ -9,9 +9,26 @@
import dom
-### set to true to see what's happening visually
+# set to true to see what's happening visually
debugWithGUI = False
+class curry:
+ """ Partial application of parameters. This is used internally but is also very useful with [[Browser.load]] as it allows you to pass data to other functions.
+ EXAMPLE. """
+ def __init__(self, fun, *args, **kwargs):
+ self.fun = fun
+ self.pending = args[:]
+ self.kwargs = kwargs.copy()
+
+ def __call__(self, *args, **kwargs):
+ if kwargs and self.kwargs:
+ kw = self.kwargs.copy()
+ kw.update(kwargs)
+ else:
+ kw = kwargs or self.kwargs
+
+ return self.fun(*(self.pending + args), **kw)
+
class _Dummy(object):
pass
@@ -46,7 +63,6 @@
xvfb.display = data
-
path = os.environ["PATH"].split(os.pathsep)
def pathSearch(name):
""" Utility function to search for and get the full path of a file in $PATH """
@@ -105,10 +121,9 @@
#sys.exit(0)
def timer(time, func):
- """ Call the given function after the alloted time. Requires that the PyKHTML event loop is running """
+ """ Call the given function after the alloted time. The PyKHTML event loop needs to be running """
qt.QTimer.singleShot(int(time * 1000), func)
-
class Browser(object):
""" A Browser is the main class you use to navigate around and visit different pages. Have a look at Browser.load and Browser.document to access basic use. """
def __init__(self):
@@ -122,18 +137,26 @@
self.part.setJavaEnabled(False)
self.part.setPluginsEnabled(False)
self.part.setAutoloadImages(False)
- self.connect = self.part.connect # sore finger remedy
+ # sore finger remedy:
+ self.connect = self.part.connect
self.disconnect = self.part.disconnect
self.loadFunction = None
+ self._passReferenceToCallbacks = True
+
+ def _setPassReferenceToCallbacks(self, b):
+ self._referencelessCallbacks = b
+ def _getPassReferenceToCallbacks(self):
+ return self._referencelessCallbacks
+ passReferenceToCallbacks = property(_getPassReferenceToCallbacks, _setPassReferenceToCallbacks, None, "Set whether callbacks passed to functions such as [[Browser.load]] or [[dom.Document.visit]] will have a reference to this browser object passed as a parameter. Default is True")
def _setLocation(self, uri):
self.part.openURL(kdecore.KURL(uri))
def _getLocation(self):
return str(self.part.url().url())
- location = property(_getLocation, _setLocation, None, "Browse to a new location. You probably don't want to set this directly as you'll receive no notification when the page has loaded. Have a look at Browser.load instead")
+ location = property(_getLocation, _setLocation, None, "Browse to a new location. You probably don't want to set this directly as you'll receive no notification when the page has loaded. Have a look at [[Browser.load]] instead")
def load(self, uri, callback):
- """ Load a webpage in the browser. It takes as parameters the URI of the page to load, and a callable object to call when the page has loaded. """
+ """ Load a webpage in the browser. It takes as parameters the URI of the page to load, and a callable object to call when the page has loaded. This callback will be given the browser object as a reference unless you set [[Browser.referencelessCallbacks]] to True """
if self.loadFunction:
self.disconnect(self.part, qt.SIGNAL("docCreated()"). self._slotDocCreated)
self.loadFunction = callback
@@ -147,9 +170,12 @@
raise AttributeError("No load function callback present")
func = self.loadFunction
self.loadFunction = None
- # do this so the DOM loads fully. Huzzah
- doc = self.document
- dom.Element(doc._d).addEvent("load", func)
+ # If _passReferenceToCallbacks, bind this browser to the function
+ if self._passReferenceToCallbacks:
+ func = curry(func, self)
+ # do this so the DOM loads fully. Cast to an Element -- not strictly correct, but we just want to get to addEvent.
+ # XX why not just put addEvent in Node and make Document inherit from Node? Document IS meant to be a Node, after all.
+ docElement = dom.Element(self.document._d).addEvent("load", func)
@property
def source(self):