1# Copyright (c) 2004 Divmod. 2# See LICENSE for details. 3 4 5""" 6Easy to use box layout model. Works cross-browser on IE 6, Safari, Opera, and Mozilla (using Evil Hack(tm)). 7Until a known bug in Mozilla is fixed, the Evil Hack will be in place. This evil hack prevents text inside of a Block from 8being selected. 9 10 - line: a horizontal box grouping 11 - block: a vertical, flowing box grouping 12 13Example:: 14 15 text = "Hello lots of text " * 20 16 17 line(width='100%')[ 18 box(width='50%')[text], 19 box(width='50%')[text]] 20 # Note there is a mozilla bug right now where the second, flowing percentage is calculated using only 21 # the empty space, so the second value here would have to be 100%; This module will soon add browser 22 # sniffing to detect if mozilla is being used and adjust percentages accordingly. For now, use pixel, em, or 23 # point values instead. 24 25Experimental feature: Keyword arguments to the line and box protos are converted into css styles: 26box(color='red') => <span style="color: red" /> 27 28Known Mozilla bugs 29================== 30 31If you use border, padding, or margin, mozilla shows weird rendering artifacts. background color and 32background images generally appear to be safe. 33 34It doesn't appear to be possible to set the vertical-align in some cases in mozilla. 35""" 36 37from zope.interface import implements 38 39from nevow import static 40from nevow import inevow 41from nevow import tags 42 43boxStyle = tags.xml(""" 44span.nevow-blocks-block { 45 display: inline-block; 46 -moz-binding: url('/mozbinding#inlineblock'); } 47 48div.nevow-blocks-line { 49 margin: 0px; padding: 0px } 50 51.expanded { 52 display: block; } 53 54.collapsed { 55 display: none; } 56 57.visibilityImage { 58 margin-right: 5px; } 59""") 60 61js = tags.xml( """ 62function collapse(node, collapsedText, expandedText) { 63 for (var i = 0; i < node.childNodes.length; i++) { 64 var childNode = node.childNodes[i] 65 if (childNode.className == 'visibilityImage') { 66 var img = childNode; 67 } else if (childNode.className == 'headText') { 68 var head = childNode; 69 } 70 } 71 for (var i = 0; i < node.parentNode.childNodes.length; i++) { 72 var childNode = node.parentNode.childNodes[i] 73 if (childNode.className == 'collapsed' || childNode.className == 'expanded') { 74 var next = childNode; 75 } 76 } 77 if (next.className == 'collapsed') { 78 img.src = '/images/outline-expanded.png'; 79 next.className = 'expanded'; 80 head.innerHTML = expandedText; 81 } else { 82 img.src = '/images/outline-collapsed.png'; 83 next.className = 'collapsed'; 84 head.innerHTML = collapsedText; 85 } 86}//""") 87 88blocks_glue = [ 89 tags.style(type="text/css")[ boxStyle ], 90 tags.script(type="text/javascript")[ tags.comment[js] ]] 91 92 93mozBinding = """<?xml version="1.0"?> 94 95<bindings xmlns="http://www.mozilla.org/xbl" 96 xmlns:xbl="http://www.mozilla.org/xbl" 97 xmlns:html="http://www.w3.org/1999/xhtml" 98 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 99 100<binding id="inlineblock"> 101 <content> 102 <html:style type="text/css"> 103 .nevow-inline-table { display: inline-table; } 104 .nevow-inline-table-row { display: table-row; } 105 .nevow-inline-table-cell { display: table-cell; } 106 </html:style> 107 <html:span class="nevow-inline-table"> 108 <html:span class="nevow-inline-table-row"> 109 <html:span class="nevow-inline-table-cell" xbl:inherits="style"> 110 <children/> 111 </html:span> 112 </html:span> 113 </html:span> 114 </content> 115</binding> 116 117</bindings> 118""" 119 120blocks_child = static.Data(mozBinding, 'text/xml; name="inline-block.xml"') 121 122 123class _Blocks(object): 124 def __init__(self, tag, className): 125 self.tag = tag 126 self.className = className 127 128 def __call__(self, **kw): 129 """Make and return a new block. If height or width is specified, they may be 130 of any css-supported measurement format, such as '200px' or '50%'. 131 132 If height or width is not specified, the block will "shrink wrap". 133 134 Interesting experiment: kw arguments to __call__ are treated like css style key 135 value pairs. For example, block(color='blue', background_color='red') will translate 136 to style="color: blue; background-color: red". _ is mapped to -. Not sure if this will 137 work but it will be interesting to see if it is useful to use. 138 """ 139 return self.tag( 140 _class=self.className, 141 style='; '.join( 142 [': '.join((k.replace('_', '-'), v)) 143 for (k, v) in kw.items()])) 144 145 146block = _Blocks(tags.span, 'nevow-blocks-block') 147line = _Blocks(tags.div, 'nevow-blocks-line') 148 149 150class collapser(object): 151 """Render a fragment of html with a head and a body. 152 The body can be in two states, expanded and collapsed. 153 When the body is in collapsed state, it is not visible in the browser. 154 Clicking on the head area causes the visibility state of the body 155 to toggle. 156 157 TODO: This should be rewritten to check for patterns and slots so you 158 could have it use table or paragraph tags or whatever instead of a span 159 and a div, and you can omit the visibility image if desired (js would have 160 to change too) 161 """ 162 implements(inevow.IRenderer) 163 164 def __init__(self, headCollapsed, headExpanded, body, collapsed=True): 165 self.headCollapsed = headCollapsed 166 self.headExpanded = headExpanded 167 self.body = body 168 if collapsed: 169 self.collapsed = 'collapsed' 170 else: 171 self.collapsed = 'expanded' 172 173 def rend(self, ctx, data): 174 return (tags.span( 175 _class="collapser-line", 176 onclick=( 177 "collapse(this, '", 178 self.headCollapsed, 179 "', '", 180 self.headExpanded, 181 "');"))[ 182 tags.img(_class="visibilityImage", src="/images/outline-%s.png" % self.collapsed), 183 tags.span(_class="headText", style="color: blue; text-decoration: underline; cursor: pointer;")[ 184 self.collapsed == 'collapsed' and self.headCollapsed or self.headExpanded ] 185 ], 186 tags.xml(' '), 187 tags.div(_class=self.collapsed)[ 188 self.body 189 ]) 190 191