##// END OF EJS Templates
tooltip updates, added display layout managment inspired by jQuerys tipsy.
marcink -
r292:d7aeae23 default
parent child Browse files
Show More
@@ -1,271 +1,295 b''
1 """Helper functions
1 """Helper functions
2
2
3 Consists of functions to typically be used within templates, but also
3 Consists of functions to typically be used within templates, but also
4 available to Controllers. This module is available to both as 'h'.
4 available to Controllers. This module is available to both as 'h'.
5 """
5 """
6 from pygments.formatters import HtmlFormatter
6 from pygments.formatters import HtmlFormatter
7 from pygments import highlight as code_highlight
7 from pygments import highlight as code_highlight
8 from pylons import url, app_globals as g
8 from pylons import url, app_globals as g
9 from pylons.i18n.translation import _, ungettext
9 from pylons.i18n.translation import _, ungettext
10 from vcs.utils.annotate import annotate_highlight
10 from vcs.utils.annotate import annotate_highlight
11 from webhelpers.html import literal, HTML, escape
11 from webhelpers.html import literal, HTML, escape
12 from webhelpers.html.tools import *
12 from webhelpers.html.tools import *
13 from webhelpers.html.builder import make_tag
13 from webhelpers.html.builder import make_tag
14 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
14 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
15 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
15 end_form, file, form, hidden, image, javascript_link, link_to, link_to_if, \
16 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
16 link_to_unless, ol, required_legend, select, stylesheet_link, submit, text, \
17 password, textarea, title, ul, xml_declaration, radio
17 password, textarea, title, ul, xml_declaration, radio
18 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
18 from webhelpers.html.tools import auto_link, button_to, highlight, js_obfuscate, \
19 mail_to, strip_links, strip_tags, tag_re
19 mail_to, strip_links, strip_tags, tag_re
20 from webhelpers.number import format_byte_size, format_bit_size
20 from webhelpers.number import format_byte_size, format_bit_size
21 from webhelpers.pylonslib import Flash as _Flash
21 from webhelpers.pylonslib import Flash as _Flash
22 from webhelpers.pylonslib.secure_form import secure_form
22 from webhelpers.pylonslib.secure_form import secure_form
23 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
23 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
24 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
24 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
25 replace_whitespace, urlify, truncate, wrap_paragraphs
25 replace_whitespace, urlify, truncate, wrap_paragraphs
26
26
27
27
28 #Custom helpers here :)
28 #Custom helpers here :)
29 class _Link(object):
29 class _Link(object):
30 '''
30 '''
31 Make a url based on label and url with help of url_for
31 Make a url based on label and url with help of url_for
32 @param label:name of link if not defined url is used
32 @param label:name of link if not defined url is used
33 @param url: the url for link
33 @param url: the url for link
34 '''
34 '''
35
35
36 def __call__(self, label='', *url_, **urlargs):
36 def __call__(self, label='', *url_, **urlargs):
37 if label is None or '':
37 if label is None or '':
38 label = url
38 label = url
39 link_fn = link_to(label, url(*url_, **urlargs))
39 link_fn = link_to(label, url(*url_, **urlargs))
40 return link_fn
40 return link_fn
41
41
42 link = _Link()
42 link = _Link()
43
43
44 class _GetError(object):
44 class _GetError(object):
45
45
46 def __call__(self, field_name, form_errors):
46 def __call__(self, field_name, form_errors):
47 tmpl = """<span class="error_msg">%s</span>"""
47 tmpl = """<span class="error_msg">%s</span>"""
48 if form_errors and form_errors.has_key(field_name):
48 if form_errors and form_errors.has_key(field_name):
49 return literal(tmpl % form_errors.get(field_name))
49 return literal(tmpl % form_errors.get(field_name))
50
50
51 get_error = _GetError()
51 get_error = _GetError()
52
52
53 def recursive_replace(str, replace=' '):
53 def recursive_replace(str, replace=' '):
54 """
54 """
55 Recursive replace of given sign to just one instance
55 Recursive replace of given sign to just one instance
56 @param str: given string
56 @param str: given string
57 @param replace:char to find and replace multiple instances
57 @param replace:char to find and replace multiple instances
58
58
59 Examples::
59 Examples::
60 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
60 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
61 'Mighty-Mighty-Bo-sstones'
61 'Mighty-Mighty-Bo-sstones'
62 """
62 """
63
63
64 if str.find(replace * 2) == -1:
64 if str.find(replace * 2) == -1:
65 return str
65 return str
66 else:
66 else:
67 str = str.replace(replace * 2, replace)
67 str = str.replace(replace * 2, replace)
68 return recursive_replace(str, replace)
68 return recursive_replace(str, replace)
69
69
70 class _ToolTip(object):
70 class _ToolTip(object):
71
71
72 def __call__(self, tooltip_title, trim_at=50):
72 def __call__(self, tooltip_title, trim_at=50):
73 """
73 """
74 Special function just to wrap our text into nice formatted autowrapped
74 Special function just to wrap our text into nice formatted autowrapped
75 text
75 text
76 @param tooltip_title:
76 @param tooltip_title:
77 """
77 """
78
78
79 return literal(wrap_paragraphs(tooltip_title, trim_at)\
79 return literal(wrap_paragraphs(tooltip_title, trim_at)\
80 .replace('\n', '<br/>'))
80 .replace('\n', '<br/>'))
81
81
82 def activate(self):
82 def activate(self):
83 """
83 """
84 Adds tooltip mechanism to the given Html all tooltips have to have
84 Adds tooltip mechanism to the given Html all tooltips have to have
85 set class tooltip and set attribute tooltip_title.
85 set class tooltip and set attribute tooltip_title.
86 Then a tooltip will be generated based on that
86 Then a tooltip will be generated based on that
87 All with yui js tooltip
87 All with yui js tooltip
88 """
88 """
89
89
90 js = '''
90 js = '''
91 YAHOO.util.Event.onDOMReady(function(){
91 YAHOO.util.Event.onDOMReady(function(){
92 function toolTipsId(){
92 function toolTipsId(){
93 var ids = [];
93 var ids = [];
94 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
94 var tts = YAHOO.util.Dom.getElementsByClassName('tooltip');
95
95
96 for (var i = 0; i < tts.length; i++) {
96 for (var i = 0; i < tts.length; i++) {
97 //if element doesn not have and id autgenerate one for tooltip
97 //if element doesn not have and id autgenerate one for tooltip
98
98
99 if (!tts[i].id){
99 if (!tts[i].id){
100 tts[i].id='tt'+i*100;
100 tts[i].id='tt'+i*100;
101 }
101 }
102 ids.push(tts[i].id);
102 ids.push(tts[i].id);
103 }
103 }
104 return ids
104 return ids
105 };
105 };
106 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
106 var myToolTips = new YAHOO.widget.Tooltip("tooltip", {
107 context: toolTipsId(),
107 context: toolTipsId(),
108 monitorresize:false,
108 monitorresize:false,
109 xyoffset :[0,0],
109 xyoffset :[0,0],
110 autodismissdelay:300000,
110 autodismissdelay:300000,
111 hidedelay:5,
111 hidedelay:5,
112 showdelay:20,
112 showdelay:20,
113 });
113 });
114
114
115 //Mouse Over event disabled for new repositories since they dont
115 //Mouse Over event disabled for new repositories since they dont
116 //have last commit message
116 //have last commit message
117 myToolTips.contextMouseOverEvent.subscribe(
117 myToolTips.contextMouseOverEvent.subscribe(
118 function(type, args) {
118 function(type, args) {
119 var context = args[0];
119 var context = args[0];
120 var txt = context.getAttribute('tooltip_title');
120 var txt = context.getAttribute('tooltip_title');
121 if(txt){
121 if(txt){
122 this.cfg.config.x.value = 0;
123 this.cfg.config.y.value = 0;
124
125 return true;
122 return true;
126 }
123 }
127 else{
124 else{
128 return false;
125 return false;
129 }
126 }
130 });
127 });
131
128
132
129
133 // Set the text for the tooltip just before we display it. Lazy method
130 // Set the text for the tooltip just before we display it. Lazy method
134 myToolTips.contextTriggerEvent.subscribe(
131 myToolTips.contextTriggerEvent.subscribe(
135 function(type, args) {
132 function(type, args) {
133
134
136 var context = args[0];
135 var context = args[0];
136
137 var txt = context.getAttribute('tooltip_title');
137 var txt = context.getAttribute('tooltip_title');
138 this.cfg.setProperty("text", txt);
138 this.cfg.setProperty("text", txt);
139 //autocenter
139
140 var w = this.element.clientWidth;
140
141 var h = this.element.clientHeight;
141 // positioning of tooltip
142 var cur_x = this.pageX - (w / 2);
142 var tt_w = this.element.clientWidth;
143 var cur_y = this.pageY - h - 10;
143 var tt_h = this.element.clientHeight;
144
145 var context_w = context.offsetWidth;
146 var context_h = context.offsetHeight;
147
148 var pos_x = YAHOO.util.Dom.getX(context);
149 var pos_y = YAHOO.util.Dom.getY(context);
144
150
145 this.cfg.setProperty("xy",[cur_x,cur_y]);
151 var display_strategy = 'top';
152 var xy_pos= [0,0]
153 switch (display_strategy){
154
155 case 'top':
156 var cur_x = (pos_x+context_w/2)-(tt_w/2);
157 var cur_y = pos_y-tt_h-4;
158 xy_pos = [cur_x,cur_y];
159 break;
160 case 'bottom':
161 var cur_x = (pos_x+context_w/2)-(tt_w/2);
162 var cur_y = pos_y+context_h+4;
163 xy_pos = [cur_x,cur_y];
164 break;
165 case 'left':
166 var cur_x = (pos_x-tt_w-4);
167 var cur_y = pos_y-((tt_h/2)-context_h/2);
168 xy_pos = [cur_x,cur_y];
169 break;
170 case 'right':
171 var cur_x = (pos_x+context_w+4);
172 var cur_y = pos_y-((tt_h/2)-context_h/2);
173 xy_pos = [cur_x,cur_y];
174 break;
175
176 }
177
178 this.cfg.setProperty("xy",xy_pos);
146
179
147 });
180 });
181
148 //Mouse out
182 //Mouse out
149 myToolTips.contextMouseOutEvent.subscribe(
183 myToolTips.contextMouseOutEvent.subscribe(
150 function(type, args) {
184 function(type, args) {
151 var context = args[0];
185 var context = args[0];
152
186
153 //console.log(this.cfg.config.x.value);
154 //console.log(this.cfg.config.y.value);
155 //console.log(this.cfg.config.xy.value);
156 //console.log(this.cfg.config);
157 //this.cfg.config.xy = [0,0];
158 //this.cfg.config.xyoffset = [0,0];
159
160
161
162 });
187 });
163
164 });
188 });
165 '''
189 '''
166 return literal(js)
190 return literal(js)
167
191
168 tooltip = _ToolTip()
192 tooltip = _ToolTip()
169
193
170 class _FilesBreadCrumbs(object):
194 class _FilesBreadCrumbs(object):
171
195
172 def __call__(self, repo_name, rev, paths):
196 def __call__(self, repo_name, rev, paths):
173 url_l = [link_to(repo_name, url('files_home',
197 url_l = [link_to(repo_name, url('files_home',
174 repo_name=repo_name,
198 repo_name=repo_name,
175 revision=rev, f_path=''))]
199 revision=rev, f_path=''))]
176 paths_l = paths.split('/')
200 paths_l = paths.split('/')
177
201
178 for cnt, p in enumerate(paths_l, 1):
202 for cnt, p in enumerate(paths_l, 1):
179 if p != '':
203 if p != '':
180 url_l.append(link_to(p, url('files_home',
204 url_l.append(link_to(p, url('files_home',
181 repo_name=repo_name,
205 repo_name=repo_name,
182 revision=rev,
206 revision=rev,
183 f_path='/'.join(paths_l[:cnt]))))
207 f_path='/'.join(paths_l[:cnt]))))
184
208
185 return literal(' / '.join(url_l))
209 return literal(' / '.join(url_l))
186
210
187 files_breadcrumbs = _FilesBreadCrumbs()
211 files_breadcrumbs = _FilesBreadCrumbs()
188
212
189 def pygmentize(filenode, **kwargs):
213 def pygmentize(filenode, **kwargs):
190 """
214 """
191 pygmentize function using pygments
215 pygmentize function using pygments
192 @param filenode:
216 @param filenode:
193 """
217 """
194 return literal(code_highlight(filenode.content, filenode.lexer, HtmlFormatter(**kwargs)))
218 return literal(code_highlight(filenode.content, filenode.lexer, HtmlFormatter(**kwargs)))
195
219
196 def pygmentize_annotation(filenode, **kwargs):
220 def pygmentize_annotation(filenode, **kwargs):
197 """
221 """
198 pygmentize function for annotation
222 pygmentize function for annotation
199 @param filenode:
223 @param filenode:
200 """
224 """
201
225
202 color_dict = g.changeset_annotation_colors
226 color_dict = g.changeset_annotation_colors
203 def gen_color():
227 def gen_color():
204 import random
228 import random
205 return [str(random.randrange(10, 235)) for _ in xrange(3)]
229 return [str(random.randrange(10, 235)) for _ in xrange(3)]
206 def get_color_string(cs):
230 def get_color_string(cs):
207 if color_dict.has_key(cs):
231 if color_dict.has_key(cs):
208 col = color_dict[cs]
232 col = color_dict[cs]
209 else:
233 else:
210 color_dict[cs] = gen_color()
234 color_dict[cs] = gen_color()
211 col = color_dict[cs]
235 col = color_dict[cs]
212 return "color: rgb(%s) ! important;" % (', '.join(col))
236 return "color: rgb(%s) ! important;" % (', '.join(col))
213
237
214 def url_func(changeset):
238 def url_func(changeset):
215 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b> %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
239 tooltip_html = "<div style='font-size:0.8em'><b>Author:</b> %s<br/><b>Date:</b> %s</b><br/><b>Message:</b> %s<br/></div>"
216
240
217 tooltip_html = tooltip_html % (changeset.author,
241 tooltip_html = tooltip_html % (changeset.author,
218 changeset.date,
242 changeset.date,
219 tooltip(changeset.message))
243 tooltip(changeset.message))
220 lnk_format = 'r%s:%s' % (changeset.revision,
244 lnk_format = 'r%s:%s' % (changeset.revision,
221 changeset.raw_id)
245 changeset.raw_id)
222 uri = link_to(
246 uri = link_to(
223 lnk_format,
247 lnk_format,
224 url('changeset_home', repo_name='test',
248 url('changeset_home', repo_name='test',
225 revision=changeset.raw_id),
249 revision=changeset.raw_id),
226 style=get_color_string(changeset.raw_id),
250 style=get_color_string(changeset.raw_id),
227 class_='tooltip',
251 class_='tooltip',
228 tooltip_title=tooltip_html
252 tooltip_title=tooltip_html
229 )
253 )
230
254
231 uri += '\n'
255 uri += '\n'
232 return uri
256 return uri
233 return literal(annotate_highlight(filenode, url_func, **kwargs))
257 return literal(annotate_highlight(filenode, url_func, **kwargs))
234
258
235 def repo_name_slug(value):
259 def repo_name_slug(value):
236 """
260 """
237 Return slug of name of repository
261 Return slug of name of repository
238 """
262 """
239 slug = urlify(value)
263 slug = urlify(value)
240 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|:""":
264 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|:""":
241 slug = slug.replace(c, '-')
265 slug = slug.replace(c, '-')
242 slug = recursive_replace(slug, '-')
266 slug = recursive_replace(slug, '-')
243 return slug
267 return slug
244
268
245 flash = _Flash()
269 flash = _Flash()
246
270
247
271
248 #===============================================================================
272 #===============================================================================
249 # MERCURIAL FILTERS available via h.
273 # MERCURIAL FILTERS available via h.
250 #===============================================================================
274 #===============================================================================
251
275
252
276
253 from mercurial import util
277 from mercurial import util
254 from mercurial.templatefilters import age as _age, person as _person
278 from mercurial.templatefilters import age as _age, person as _person
255
279
256 age = lambda x:_age(x)
280 age = lambda x:_age(x)
257 capitalize = lambda x: x.capitalize()
281 capitalize = lambda x: x.capitalize()
258 date = lambda x: util.datestr(x)
282 date = lambda x: util.datestr(x)
259 email = util.email
283 email = util.email
260 person = lambda x: _person(x)
284 person = lambda x: _person(x)
261 hgdate = lambda x: "%d %d" % x
285 hgdate = lambda x: "%d %d" % x
262 isodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2')
286 isodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M %1%2')
263 isodatesec = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2')
287 isodatesec = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2')
264 localdate = lambda x: (x[0], util.makedate()[1])
288 localdate = lambda x: (x[0], util.makedate()[1])
265 rfc822date = lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2")
289 rfc822date = lambda x: util.datestr(x, "%a, %d %b %Y %H:%M:%S %1%2")
266 rfc3339date = lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2")
290 rfc3339date = lambda x: util.datestr(x, "%Y-%m-%dT%H:%M:%S%1:%2")
267 time_ago = lambda x: util.datestr(_age(x), "%a, %d %b %Y %H:%M:%S %1%2")
291 time_ago = lambda x: util.datestr(_age(x), "%a, %d %b %Y %H:%M:%S %1%2")
268
292
269
293
270
294
271
295
General Comments 0
You need to be logged in to leave comments. Login now