1010
1111class Query :
1212 """
13+ Encapsulates a query to match elements in the DOM.
14+
1315 A query must have one, and only one, of:
1416
1517 * id - a unique element id (e.g. "myElementId").
16- * tag - a tag name (e.g. "p").
1718 * classname - a class (e.g. "my-css-class").
19+ * tag - a tag name (e.g. "p").
1820 * css - a css selector (e.g "p.className").
1921
2022 These types of query relate to the four ways in which elements in an HTML
2123 document may be identified.
2224
25+ A Query is instantiated with a string using the following common syntax
26+ for identifying the different types of query:
27+
28+ * #id-name - Starting with a hash indicates an element's unique id.
29+ * .class-name - Starting with a full stop indicates a CSS class name.
30+ * p - A string of only alphabetical characters is treated as a tag name.
31+ * p.classname - Anything else is assumed to be a css selector.
32+
2333 E.g.
2434
25- q = Query(id=" myElementID")
35+ q = Query(". myElementID")
2636 """
2737
28- # Query type definitions
29- ID = "id"
30- TAG = "tag"
31- CLASSNAME = "classname"
32- CSS = "css"
33- QUERY_TYPES = (ID , TAG , CLASSNAME , CSS )
34-
35- def __init__ (self , ** kwargs ):
38+ def __init__ (self , query ):
3639 """
37- Raise a ValueError if it's not the case that one, and only one of the
38- expected types of query is given.
40+ Validate and interpret the query string.
3941 """
40- query_type = [key for key in kwargs if key in self .QUERY_TYPES ]
41- if len (query_type ) == 1 :
42- self .query_type = query_type [0 ]
43- setattr (self , self .query_type , kwargs [self .query_type ])
42+ self .raw_query = query
43+ target = None
44+ if query [:1 ] == "#" :
45+ # Unique id.
46+ target = query [1 :]
47+ if target :
48+ self .query_type = "id"
49+ else :
50+ raise ValueError ("Invalid id." )
51+ elif query [:1 ] == "." :
52+ # CSS class.
53+ target = query [1 :]
54+ if target :
55+ self .query_type = "classname"
56+ else :
57+ raise ValueError ("Invalid class." )
58+ elif query .isalpha ():
59+ # tagName.
60+ target = query
61+ self .query_type = "tag"
62+ else :
63+ # CSS selector.
64+ target = query
65+ self .query_type = "css"
66+
67+ if target :
68+ setattr (self , self .query_type , target )
4469 else :
4570 raise ValueError ("Bad query specification." )
4671
@@ -443,24 +468,24 @@ def find(self, selector):
443468 representing nodes that match "selector" string. The selector
444469 string understands:
445470
446- * . my-id - returns the first ElementNode with the id "my-id". Returns
471+ * # my-id - returns the first ElementNode with the id "my-id". Returns
447472 None if no match is found.
448- * # my-class - returns a list containing elements with the class
473+ * . my-class - returns a list containing elements with the class
449474 "my-class". Returns an empty list if no match is found.
450475 * li - returns a list containing elements with the tagName "li".
451476 Returns an empty list if no match is found.
452477 """
453478 # Validate selector.
454479 if not selector :
455480 raise ValueError ("Missing selector." )
456- if selector [0 ] == ". " :
481+ if selector [0 ] == "# " :
457482 # Select by unique id.
458483 target_id = selector [1 :]
459484 if target_id :
460485 return self ._find_by_id (target_id )
461486 else :
462487 raise ValueError ("Invalid id." )
463- elif selector [0 ] == "# " :
488+ elif selector [0 ] == ". " :
464489 # Select by css class.
465490 target_class = selector [1 :]
466491 if target_class :
@@ -615,7 +640,7 @@ def get_listener_id(query, event_type, listener):
615640 Given a query, event type and listener function, generate a unique id from
616641 this combination.
617642 """
618- raw = str ( query .as_dict ) + event_type + listener .__name__
643+ raw = query .raw_query + event_type + listener .__name__
619644 return binascii .hexlify (
620645 hashlib .sha256 (raw .encode ("utf-8" )).digest ()
621646 ).decode ("ascii" )
@@ -637,11 +662,12 @@ def update(query, target):
637662 Update the DOM so the node[s] matching the query are mutated to the state
638663 defined by the target node.
639664 """
665+ q = Query (query )
640666 builtins .print (
641667 json .dumps (
642668 {
643669 "type" : "updateDOM" ,
644- "query" : query .as_dict ,
670+ "query" : q .as_dict ,
645671 "target" : target .as_dict ,
646672 }
647673 )
@@ -653,13 +679,14 @@ def remove(query, event_type, listener):
653679 Remove the referenced listener from handling the event_type from the
654680 node[s] matching the query.
655681 """
656- listener_id = get_listener_id (query , event_type , listener )
682+ q = Query (query )
683+ listener_id = get_listener_id (q , event_type , listener )
657684 del LISTENERS [listener_id ]
658685 builtins .print (
659686 json .dumps (
660687 {
661688 "type" : "removeEvent" ,
662- "query" : query .as_dict ,
689+ "query" : q .as_dict ,
663690 "eventType" : event_type ,
664691 }
665692 )
@@ -679,6 +706,7 @@ def plug(query, event_type):
679706 This decorator wrapper function creates a closure in which various
680707 contextual aspects are contained and run.
681708 """
709+ q = Query (query )
682710
683711 def decorator (fn ):
684712 """
@@ -688,12 +716,12 @@ def decorator(fn):
688716 def wrapper (event ):
689717 return fn (event )
690718
691- listener_id = get_listener_id (query , event_type , wrapper )
719+ listener_id = get_listener_id (q , event_type , wrapper )
692720 builtins .print (
693721 json .dumps (
694722 {
695723 "type" : "registerEvent" ,
696- "query" : query .as_dict ,
724+ "query" : q .as_dict ,
697725 "eventType" : event_type ,
698726 "listener" : listener_id ,
699727 }
0 commit comments