Show More
@@ -23,23 +23,25 b'' | |||||
23 | # You should have received a copy of the GNU General Public License |
|
23 | # You should have received a copy of the GNU General Public License | |
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 |
|
25 | |||
|
26 | import traceback | |||
26 | import calendar |
|
27 | import calendar | |
27 | import logging |
|
28 | import logging | |
28 | from time import mktime |
|
29 | from time import mktime | |
29 |
from datetime import |
|
30 | from datetime import timedelta, date | |
|
31 | from itertools import product | |||
30 |
|
32 | |||
31 | from vcs.exceptions import ChangesetError |
|
33 | from vcs.exceptions import ChangesetError, EmptyRepositoryError, \ | |
|
34 | NodeDoesNotExistError | |||
32 |
|
35 | |||
33 | from pylons import tmpl_context as c, request, url |
|
36 | from pylons import tmpl_context as c, request, url | |
34 | from pylons.i18n.translation import _ |
|
37 | from pylons.i18n.translation import _ | |
35 |
|
38 | |||
36 |
from rhodecode.model.db import Statistics |
|
39 | from rhodecode.model.db import Statistics | |
37 | from rhodecode.model.repo import RepoModel |
|
40 | from rhodecode.lib import ALL_READMES, ALL_EXTS | |
38 |
|
||||
39 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
41 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
40 | from rhodecode.lib.base import BaseRepoController, render |
|
42 | from rhodecode.lib.base import BaseRepoController, render | |
41 | from rhodecode.lib.utils import EmptyChangeset |
|
43 | from rhodecode.lib.utils import EmptyChangeset | |
42 |
|
44 | from rhodecode.lib.markup_renderer import MarkupRenderer | ||
43 | from rhodecode.lib.celerylib import run_task |
|
45 | from rhodecode.lib.celerylib import run_task | |
44 | from rhodecode.lib.celerylib.tasks import get_commits_stats, \ |
|
46 | from rhodecode.lib.celerylib.tasks import get_commits_stats, \ | |
45 | LANGUAGES_EXTENSIONS_MAP |
|
47 | LANGUAGES_EXTENSIONS_MAP | |
@@ -48,6 +50,9 b' from rhodecode.lib.compat import json, O' | |||||
48 |
|
50 | |||
49 | log = logging.getLogger(__name__) |
|
51 | log = logging.getLogger(__name__) | |
50 |
|
52 | |||
|
53 | README_FILES = [''.join([x[0][0], x[1][0]]) for x in | |||
|
54 | sorted(list(product(ALL_READMES, ALL_EXTS)), | |||
|
55 | key=lambda y:y[0][1] + y[1][1])] | |||
51 |
|
56 | |||
52 | class SummaryController(BaseRepoController): |
|
57 | class SummaryController(BaseRepoController): | |
53 |
|
58 | |||
@@ -161,8 +166,33 b' class SummaryController(BaseRepoControll' | |||||
161 | if c.enable_downloads: |
|
166 | if c.enable_downloads: | |
162 | c.download_options = self._get_download_links(c.rhodecode_repo) |
|
167 | c.download_options = self._get_download_links(c.rhodecode_repo) | |
163 |
|
168 | |||
|
169 | c.readme_data,c.readme_file = self.__get_readme_data() | |||
164 | return render('summary/summary.html') |
|
170 | return render('summary/summary.html') | |
165 |
|
171 | |||
|
172 | def __get_readme_data(self): | |||
|
173 | readme_data = None | |||
|
174 | readme_file = None | |||
|
175 | ||||
|
176 | try: | |||
|
177 | cs = c.rhodecode_repo.get_changeset('tip') | |||
|
178 | renderer = MarkupRenderer() | |||
|
179 | for f in README_FILES: | |||
|
180 | try: | |||
|
181 | readme = cs.get_node(f) | |||
|
182 | readme_file = f | |||
|
183 | readme_data = renderer.render(readme.content, f) | |||
|
184 | break | |||
|
185 | except NodeDoesNotExistError: | |||
|
186 | continue | |||
|
187 | except ChangesetError: | |||
|
188 | pass | |||
|
189 | except EmptyRepositoryError: | |||
|
190 | pass | |||
|
191 | except Exception: | |||
|
192 | log.error(traceback.format_exc()) | |||
|
193 | ||||
|
194 | return readme_data, readme_file | |||
|
195 | ||||
166 | def _get_download_links(self, repo): |
|
196 | def _get_download_links(self, repo): | |
167 |
|
197 | |||
168 | download_l = [] |
|
198 | download_l = [] | |
@@ -181,3 +211,4 b' class SummaryController(BaseRepoControll' | |||||
181 | download_l.append(tags_group) |
|
211 | download_l.append(tags_group) | |
182 |
|
212 | |||
183 | return download_l |
|
213 | return download_l | |
|
214 |
@@ -66,6 +66,34 b" ADDITIONAL_MAPPINGS = {'xaml': 'XAML'}" | |||||
66 |
|
66 | |||
67 | LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS) |
|
67 | LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS) | |
68 |
|
68 | |||
|
69 | # list of readme files to search in file tree and display in summary | |||
|
70 | # attached weights defines the search order lower is first | |||
|
71 | ALL_READMES = [ | |||
|
72 | ('readme', 0), ('README', 0), ('Readme', 0), | |||
|
73 | ('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1), | |||
|
74 | ('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2), | |||
|
75 | ('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2), | |||
|
76 | ('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2), | |||
|
77 | ] | |||
|
78 | ||||
|
79 | # extension together with weights to search lower is first | |||
|
80 | RST_EXTS = [ | |||
|
81 | ('', 0), ('.rst', 1),('.rest', 1), | |||
|
82 | ('.RST', 2) ,('.REST', 2), | |||
|
83 | ('.txt', 3), ('.TXT', 3) | |||
|
84 | ] | |||
|
85 | ||||
|
86 | MARKDOWN_EXTS = [ | |||
|
87 | ('.md', 1), ('.MD', 1), | |||
|
88 | ('.mkdn', 2), ('.MKDN', 2), | |||
|
89 | ('.mdown', 3), ('.MDOWN', 3), | |||
|
90 | ('.markdown', 4), ('.MARKDOWN', 4) | |||
|
91 | ] | |||
|
92 | ||||
|
93 | PLAIN_EXTS = [('.text', 2),('.TEXT', 2)] | |||
|
94 | ||||
|
95 | ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS | |||
|
96 | ||||
69 |
|
97 | |||
70 | def str2bool(_str): |
|
98 | def str2bool(_str): | |
71 | """ |
|
99 | """ |
@@ -3011,4 +3011,96 b' div#legend_container table td,div#legend' | |||||
3011 | border: 0px solid #545454; |
|
3011 | border: 0px solid #545454; | |
3012 | color: #AAAAAA; |
|
3012 | color: #AAAAAA; | |
3013 | padding-left: 3px; |
|
3013 | padding-left: 3px; | |
3014 | } No newline at end of file |
|
3014 | } | |
|
3015 | ||||
|
3016 | /*README STYLE*/ | |||
|
3017 | ||||
|
3018 | div.readme { | |||
|
3019 | padding:0px; | |||
|
3020 | } | |||
|
3021 | ||||
|
3022 | div.readme h2 { | |||
|
3023 | font-weight: normal; | |||
|
3024 | } | |||
|
3025 | ||||
|
3026 | div.readme .readme_box { | |||
|
3027 | background-color: #fafafa; | |||
|
3028 | } | |||
|
3029 | ||||
|
3030 | div.readme .readme_box { | |||
|
3031 | clear:both; | |||
|
3032 | overflow:hidden; | |||
|
3033 | margin:0; | |||
|
3034 | padding:0 20px 10px; | |||
|
3035 | } | |||
|
3036 | ||||
|
3037 | div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 { | |||
|
3038 | border-bottom: 0 !important; | |||
|
3039 | margin: 0 !important; | |||
|
3040 | padding: 0 !important; | |||
|
3041 | line-height: 1.5em !important; | |||
|
3042 | } | |||
|
3043 | ||||
|
3044 | ||||
|
3045 | div.readme .readme_box h1:first-child { | |||
|
3046 | padding-top: .25em !important; | |||
|
3047 | } | |||
|
3048 | ||||
|
3049 | div.readme .readme_box h2, div.readme .readme_box h3 { | |||
|
3050 | margin: 1em 0 !important; | |||
|
3051 | } | |||
|
3052 | ||||
|
3053 | div.readme .readme_box h2 { | |||
|
3054 | margin-top: 1.5em !important; | |||
|
3055 | border-top: 4px solid #e0e0e0 !important; | |||
|
3056 | padding-top: .5em !important; | |||
|
3057 | } | |||
|
3058 | ||||
|
3059 | div.readme .readme_box p { | |||
|
3060 | color: black !important; | |||
|
3061 | margin: 1em 0 !important; | |||
|
3062 | line-height: 1.5em !important; | |||
|
3063 | } | |||
|
3064 | ||||
|
3065 | div.readme .readme_box ul { | |||
|
3066 | list-style: disc !important; | |||
|
3067 | margin: 1em 0 1em 2em !important; | |||
|
3068 | } | |||
|
3069 | ||||
|
3070 | div.readme .readme_box ol { | |||
|
3071 | list-style: decimal; | |||
|
3072 | margin: 1em 0 1em 2em !important; | |||
|
3073 | } | |||
|
3074 | ||||
|
3075 | div.readme .readme_box pre, code { | |||
|
3076 | font: 12px "Bitstream Vera Sans Mono","Courier",monospace; | |||
|
3077 | } | |||
|
3078 | ||||
|
3079 | div.readme .readme_box code { | |||
|
3080 | font-size: 12px !important; | |||
|
3081 | background-color: ghostWhite !important; | |||
|
3082 | color: #444 !important; | |||
|
3083 | padding: 0 .2em !important; | |||
|
3084 | border: 1px solid #dedede !important; | |||
|
3085 | } | |||
|
3086 | ||||
|
3087 | div.readme .readme_box pre code { | |||
|
3088 | padding: 0 !important; | |||
|
3089 | font-size: 12px !important; | |||
|
3090 | background-color: #eee !important; | |||
|
3091 | border: none !important; | |||
|
3092 | } | |||
|
3093 | ||||
|
3094 | div.readme .readme_box pre { | |||
|
3095 | margin: 1em 0; | |||
|
3096 | font-size: 12px; | |||
|
3097 | background-color: #eee; | |||
|
3098 | border: 1px solid #ddd; | |||
|
3099 | padding: 5px; | |||
|
3100 | color: #444; | |||
|
3101 | overflow: auto; | |||
|
3102 | -webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset; | |||
|
3103 | -webkit-border-radius: 3px; | |||
|
3104 | -moz-border-radius: 3px; | |||
|
3105 | border-radius: 3px; | |||
|
3106 | } |
This diff has been collapsed as it changes many lines, (940 lines changed) Show them Hide them | |||||
@@ -64,29 +64,22 b'' | |||||
64 | ##FORK |
|
64 | ##FORK | |
65 | %if c.dbrepo.fork: |
|
65 | %if c.dbrepo.fork: | |
66 | <div style="margin-top:5px;clear:both""> |
|
66 | <div style="margin-top:5px;clear:both""> | |
67 | <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"> |
|
67 | <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}"><img class="icon" alt="${_('public')}" title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" src="${h.url('/images/icons/arrow_divide.png')}"/> | |
68 | <img class="icon" alt="${_('public')}" |
|
68 | ${_('Fork of')} ${c.dbrepo.fork.repo_name} | |
69 | title="${_('Fork of')} ${c.dbrepo.fork.repo_name}" |
|
|||
70 | src="${h.url('/images/icons/arrow_divide.png')}"/> |
|
|||
71 | ${_('Fork of')} ${c.dbrepo.fork.repo_name} |
|
|||
72 | </a> |
|
69 | </a> | |
73 | </div> |
|
70 | </div> | |
74 | %endif |
|
71 | %endif | |
75 | ##REMOTE |
|
72 | ##REMOTE | |
76 | %if c.dbrepo.clone_uri: |
|
73 | %if c.dbrepo.clone_uri: | |
77 | <div style="margin-top:5px;clear:both"> |
|
74 | <div style="margin-top:5px;clear:both"> | |
78 | <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"> |
|
75 | <a href="${h.url(str(h.hide_credentials(c.dbrepo.clone_uri)))}"><img class="icon" alt="${_('remote clone')}" title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" src="${h.url('/images/icons/connect.png')}"/> | |
79 | <img class="icon" alt="${_('remote clone')}" |
|
76 | ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)} | |
80 | title="${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)}" |
|
|||
81 | src="${h.url('/images/icons/connect.png')}"/> |
|
|||
82 | ${_('Clone from')} ${h.hide_credentials(c.dbrepo.clone_uri)} |
|
|||
83 | </a> |
|
77 | </a> | |
84 | </div> |
|
78 | </div> | |
85 | %endif |
|
79 | %endif | |
86 | </div> |
|
80 | </div> | |
87 | </div> |
|
81 | </div> | |
88 |
|
82 | |||
89 |
|
||||
90 | <div class="field"> |
|
83 | <div class="field"> | |
91 | <div class="label"> |
|
84 | <div class="label"> | |
92 | <label>${_('Description')}:</label> |
|
85 | <label>${_('Description')}:</label> | |
@@ -94,7 +87,6 b'' | |||||
94 | <div class="input-short desc">${h.urlify_text(c.dbrepo.description)}</div> |
|
87 | <div class="input-short desc">${h.urlify_text(c.dbrepo.description)}</div> | |
95 | </div> |
|
88 | </div> | |
96 |
|
89 | |||
97 |
|
||||
98 | <div class="field"> |
|
90 | <div class="field"> | |
99 | <div class="label"> |
|
91 | <div class="label"> | |
100 | <label>${_('Contact')}:</label> |
|
92 | <label>${_('Contact')}:</label> | |
@@ -119,7 +111,6 b'' | |||||
119 | <span class="tooltip" title="${c.rhodecode_repo.last_change}"> |
|
111 | <span class="tooltip" title="${c.rhodecode_repo.last_change}"> | |
120 | ${h.age(c.rhodecode_repo.last_change)}</span><br/> |
|
112 | ${h.age(c.rhodecode_repo.last_change)}</span><br/> | |
121 | ${_('by')} ${h.get_changeset_safe(c.rhodecode_repo,'tip').author} |
|
113 | ${_('by')} ${h.get_changeset_safe(c.rhodecode_repo,'tip').author} | |
122 |
|
||||
123 | </div> |
|
114 | </div> | |
124 | </div> |
|
115 | </div> | |
125 |
|
116 | |||
@@ -187,123 +178,6 b'' | |||||
187 | </div> |
|
178 | </div> | |
188 | </div> |
|
179 | </div> | |
189 | </div> |
|
180 | </div> | |
190 | <script type="text/javascript"> |
|
|||
191 | YUE.onDOMReady(function(e){ |
|
|||
192 | id = 'clone_url'; |
|
|||
193 | YUE.on(id,'click',function(e){ |
|
|||
194 | if(YUD.hasClass(id,'selected')){ |
|
|||
195 | return |
|
|||
196 | } |
|
|||
197 | else{ |
|
|||
198 | YUD.addClass(id,'selected'); |
|
|||
199 | YUD.get(id).select(); |
|
|||
200 | } |
|
|||
201 |
|
||||
202 | }) |
|
|||
203 | }) |
|
|||
204 | var data = ${c.trending_languages|n}; |
|
|||
205 | var total = 0; |
|
|||
206 | var no_data = true; |
|
|||
207 | for (k in data){ |
|
|||
208 | total += data[k].count; |
|
|||
209 | no_data = false; |
|
|||
210 | } |
|
|||
211 | var tbl = document.createElement('table'); |
|
|||
212 | tbl.setAttribute('class','trending_language_tbl'); |
|
|||
213 | var cnt = 0; |
|
|||
214 | for (k in data){ |
|
|||
215 | cnt += 1; |
|
|||
216 | var hide = cnt>2; |
|
|||
217 | var tr = document.createElement('tr'); |
|
|||
218 | if (hide){ |
|
|||
219 | tr.setAttribute('style','display:none'); |
|
|||
220 | tr.setAttribute('class','stats_hidden'); |
|
|||
221 | } |
|
|||
222 | var percentage = Math.round((data[k].count/total*100),2); |
|
|||
223 | var value = data[k].count; |
|
|||
224 | var td1 = document.createElement('td'); |
|
|||
225 | td1.width = 150; |
|
|||
226 | var trending_language_label = document.createElement('div'); |
|
|||
227 | trending_language_label.innerHTML = data[k].desc+" ("+k+")"; |
|
|||
228 | td1.appendChild(trending_language_label); |
|
|||
229 |
|
||||
230 | var td2 = document.createElement('td'); |
|
|||
231 | td2.setAttribute('style','padding-right:14px !important'); |
|
|||
232 | var trending_language = document.createElement('div'); |
|
|||
233 | var nr_files = value+" ${_('files')}"; |
|
|||
234 |
|
||||
235 | trending_language.title = k+" "+nr_files; |
|
|||
236 |
|
||||
237 | if (percentage>22){ |
|
|||
238 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>"; |
|
|||
239 | } |
|
|||
240 | else{ |
|
|||
241 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>"; |
|
|||
242 | } |
|
|||
243 |
|
||||
244 | trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner'); |
|
|||
245 | trending_language.style.width=percentage+"%"; |
|
|||
246 | td2.appendChild(trending_language); |
|
|||
247 |
|
||||
248 | tr.appendChild(td1); |
|
|||
249 | tr.appendChild(td2); |
|
|||
250 | tbl.appendChild(tr); |
|
|||
251 | if(cnt == 3){ |
|
|||
252 | var show_more = document.createElement('tr'); |
|
|||
253 | var td = document.createElement('td'); |
|
|||
254 | lnk = document.createElement('a'); |
|
|||
255 |
|
||||
256 | lnk.href='#'; |
|
|||
257 | lnk.innerHTML = "${_('show more')}"; |
|
|||
258 | lnk.id='code_stats_show_more'; |
|
|||
259 | td.appendChild(lnk); |
|
|||
260 |
|
||||
261 | show_more.appendChild(td); |
|
|||
262 | show_more.appendChild(document.createElement('td')); |
|
|||
263 | tbl.appendChild(show_more); |
|
|||
264 | } |
|
|||
265 |
|
||||
266 | } |
|
|||
267 | if(no_data){ |
|
|||
268 | var tr = document.createElement('tr'); |
|
|||
269 | var td1 = document.createElement('td'); |
|
|||
270 | td1.innerHTML = "${c.no_data_msg}"; |
|
|||
271 | tr.appendChild(td1); |
|
|||
272 | tbl.appendChild(tr); |
|
|||
273 | } |
|
|||
274 | YUD.get('lang_stats').appendChild(tbl); |
|
|||
275 | YUE.on('code_stats_show_more','click',function(){ |
|
|||
276 | l = YUD.getElementsByClassName('stats_hidden') |
|
|||
277 | for (e in l){ |
|
|||
278 | YUD.setStyle(l[e],'display',''); |
|
|||
279 | }; |
|
|||
280 | YUD.setStyle(YUD.get('code_stats_show_more'), |
|
|||
281 | 'display','none'); |
|
|||
282 | }) |
|
|||
283 |
|
||||
284 | var tmpl_links = {} |
|
|||
285 | %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()): |
|
|||
286 | tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'], |
|
|||
287 | h.url('files_archive_home',repo_name=c.dbrepo.repo_name, |
|
|||
288 | fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_="archive_icon")}'; |
|
|||
289 | %endfor |
|
|||
290 |
|
||||
291 | YUE.on(['download_options','archive_subrepos'],'change',function(e){ |
|
|||
292 | var sm = YUD.get('download_options'); |
|
|||
293 | var new_cs = sm.options[sm.selectedIndex]; |
|
|||
294 |
|
||||
295 | for(k in tmpl_links){ |
|
|||
296 | var s = YUD.get(k+'_link'); |
|
|||
297 | title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}"; |
|
|||
298 | s.title = title_tmpl.replace('__CS_NAME__',new_cs.text); |
|
|||
299 | s.title = s.title.replace('__CS_EXT__',k); |
|
|||
300 | var url = tmpl_links[k].replace('__CS__',new_cs.value); |
|
|||
301 | var subrepos = YUD.get('archive_subrepos').checked |
|
|||
302 | url = url.replace('__SUB__',subrepos); |
|
|||
303 | s.innerHTML = url |
|
|||
304 | } |
|
|||
305 | }); |
|
|||
306 | </script> |
|
|||
307 | </div> |
|
181 | </div> | |
308 |
|
182 | |||
309 | <div class="box box-right" style="min-height:455px"> |
|
183 | <div class="box box-right" style="min-height:455px"> | |
@@ -319,7 +193,6 b'' | |||||
319 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): |
|
193 | %if h.HasPermissionAll('hg.admin')('enable stats on from summary'): | |
320 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-button-small")} |
|
194 | ${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name),class_="ui-button-small")} | |
321 | %endif |
|
195 | %endif | |
322 |
|
||||
323 | %else: |
|
196 | %else: | |
324 | ${_('Loaded in')} ${c.stats_percentage} % |
|
197 | ${_('Loaded in')} ${c.stats_percentage} % | |
325 | %endif |
|
198 | %endif | |
@@ -331,333 +204,9 b'' | |||||
331 | <div id="legend_data" style="clear:both;margin-top:10px;"> |
|
204 | <div id="legend_data" style="clear:both;margin-top:10px;"> | |
332 | <div id="legend_container"></div> |
|
205 | <div id="legend_container"></div> | |
333 | <div id="legend_choices"> |
|
206 | <div id="legend_choices"> | |
334 | <table id="legend_choices_tables" style="font-size:smaller;color:#545454"></table> |
|
207 | <table id="legend_choices_tables" class="noborder" style="font-size:smaller;color:#545454"></table> | |
335 | </div> |
|
208 | </div> | |
336 | </div> |
|
209 | </div> | |
337 | <script type="text/javascript"> |
|
|||
338 | /** |
|
|||
339 | * Plots summary graph |
|
|||
340 | * |
|
|||
341 | * @class SummaryPlot |
|
|||
342 | * @param {from} initial from for detailed graph |
|
|||
343 | * @param {to} initial to for detailed graph |
|
|||
344 | * @param {dataset} |
|
|||
345 | * @param {overview_dataset} |
|
|||
346 | */ |
|
|||
347 | function SummaryPlot(from,to,dataset,overview_dataset) { |
|
|||
348 | var initial_ranges = { |
|
|||
349 | "xaxis":{ |
|
|||
350 | "from":from, |
|
|||
351 | "to":to, |
|
|||
352 | }, |
|
|||
353 | }; |
|
|||
354 | var dataset = dataset; |
|
|||
355 | var overview_dataset = [overview_dataset]; |
|
|||
356 | var choiceContainer = YUD.get("legend_choices"); |
|
|||
357 | var choiceContainerTable = YUD.get("legend_choices_tables"); |
|
|||
358 | var plotContainer = YUD.get('commit_history'); |
|
|||
359 | var overviewContainer = YUD.get('overview'); |
|
|||
360 |
|
||||
361 | var plot_options = { |
|
|||
362 | bars: {show:true,align:'center',lineWidth:4}, |
|
|||
363 | legend: {show:true, container:"legend_container"}, |
|
|||
364 | points: {show:true,radius:0,fill:false}, |
|
|||
365 | yaxis: {tickDecimals:0,}, |
|
|||
366 | xaxis: { |
|
|||
367 | mode: "time", |
|
|||
368 | timeformat: "%d/%m", |
|
|||
369 | min:from, |
|
|||
370 | max:to, |
|
|||
371 | }, |
|
|||
372 | grid: { |
|
|||
373 | hoverable: true, |
|
|||
374 | clickable: true, |
|
|||
375 | autoHighlight:true, |
|
|||
376 | color: "#999" |
|
|||
377 | }, |
|
|||
378 | //selection: {mode: "x"} |
|
|||
379 | }; |
|
|||
380 | var overview_options = { |
|
|||
381 | legend:{show:false}, |
|
|||
382 | bars: {show:true,barWidth: 2,}, |
|
|||
383 | shadowSize: 0, |
|
|||
384 | xaxis: {mode: "time", timeformat: "%d/%m/%y",}, |
|
|||
385 | yaxis: {ticks: 3, min: 0,tickDecimals:0,}, |
|
|||
386 | grid: {color: "#999",}, |
|
|||
387 | selection: {mode: "x"} |
|
|||
388 | }; |
|
|||
389 |
|
||||
390 | /** |
|
|||
391 | *get dummy data needed in few places |
|
|||
392 | */ |
|
|||
393 | function getDummyData(label){ |
|
|||
394 | return {"label":label, |
|
|||
395 | "data":[{"time":0, |
|
|||
396 | "commits":0, |
|
|||
397 | "added":0, |
|
|||
398 | "changed":0, |
|
|||
399 | "removed":0, |
|
|||
400 | }], |
|
|||
401 | "schema":["commits"], |
|
|||
402 | "color":'#ffffff', |
|
|||
403 | } |
|
|||
404 | } |
|
|||
405 |
|
||||
406 | /** |
|
|||
407 | * generate checkboxes accordindly to data |
|
|||
408 | * @param keys |
|
|||
409 | * @returns |
|
|||
410 | */ |
|
|||
411 | function generateCheckboxes(data) { |
|
|||
412 | //append checkboxes |
|
|||
413 | var i = 0; |
|
|||
414 | choiceContainerTable.innerHTML = ''; |
|
|||
415 | for(var pos in data) { |
|
|||
416 |
|
||||
417 | data[pos].color = i; |
|
|||
418 | i++; |
|
|||
419 | if(data[pos].label != ''){ |
|
|||
420 | choiceContainerTable.innerHTML += '<tr><td>'+ |
|
|||
421 | '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />' |
|
|||
422 | +data[pos].label+ |
|
|||
423 | '</td></tr>'; |
|
|||
424 | } |
|
|||
425 | } |
|
|||
426 | } |
|
|||
427 |
|
||||
428 | /** |
|
|||
429 | * ToolTip show |
|
|||
430 | */ |
|
|||
431 | function showTooltip(x, y, contents) { |
|
|||
432 | var div=document.getElementById('tooltip'); |
|
|||
433 | if(!div) { |
|
|||
434 | div = document.createElement('div'); |
|
|||
435 | div.id="tooltip"; |
|
|||
436 | div.style.position="absolute"; |
|
|||
437 | div.style.border='1px solid #fdd'; |
|
|||
438 | div.style.padding='2px'; |
|
|||
439 | div.style.backgroundColor='#fee'; |
|
|||
440 | document.body.appendChild(div); |
|
|||
441 | } |
|
|||
442 | YUD.setStyle(div, 'opacity', 0); |
|
|||
443 | div.innerHTML = contents; |
|
|||
444 | div.style.top=(y + 5) + "px"; |
|
|||
445 | div.style.left=(x + 5) + "px"; |
|
|||
446 |
|
||||
447 | var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2); |
|
|||
448 | anim.animate(); |
|
|||
449 | } |
|
|||
450 |
|
||||
451 | /** |
|
|||
452 | * This function will detect if selected period has some changesets |
|
|||
453 | for this user if it does this data is then pushed for displaying |
|
|||
454 | Additionally it will only display users that are selected by the checkbox |
|
|||
455 | */ |
|
|||
456 | function getDataAccordingToRanges(ranges) { |
|
|||
457 |
|
||||
458 | var data = []; |
|
|||
459 | var new_dataset = {}; |
|
|||
460 | var keys = []; |
|
|||
461 | var max_commits = 0; |
|
|||
462 | for(var key in dataset){ |
|
|||
463 |
|
||||
464 | for(var ds in dataset[key].data){ |
|
|||
465 | commit_data = dataset[key].data[ds]; |
|
|||
466 | if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){ |
|
|||
467 |
|
||||
468 | if(new_dataset[key] === undefined){ |
|
|||
469 | new_dataset[key] = {data:[],schema:["commits"],label:key}; |
|
|||
470 | } |
|
|||
471 | new_dataset[key].data.push(commit_data); |
|
|||
472 | } |
|
|||
473 | } |
|
|||
474 | if (new_dataset[key] !== undefined){ |
|
|||
475 | data.push(new_dataset[key]); |
|
|||
476 | } |
|
|||
477 | } |
|
|||
478 |
|
||||
479 | if (data.length > 0){ |
|
|||
480 | return data; |
|
|||
481 | } |
|
|||
482 | else{ |
|
|||
483 | //just return dummy data for graph to plot itself |
|
|||
484 | return [getDummyData('')]; |
|
|||
485 | } |
|
|||
486 | } |
|
|||
487 |
|
||||
488 | /** |
|
|||
489 | * redraw using new checkbox data |
|
|||
490 | */ |
|
|||
491 | function plotchoiced(e,args){ |
|
|||
492 | var cur_data = args[0]; |
|
|||
493 | var cur_ranges = args[1]; |
|
|||
494 |
|
||||
495 | var new_data = []; |
|
|||
496 | var inputs = choiceContainer.getElementsByTagName("input"); |
|
|||
497 |
|
||||
498 | //show only checked labels |
|
|||
499 | for(var i=0; i<inputs.length; i++) { |
|
|||
500 | var checkbox_key = inputs[i].name; |
|
|||
501 |
|
||||
502 | if(inputs[i].checked){ |
|
|||
503 | for(var d in cur_data){ |
|
|||
504 | if(cur_data[d].label == checkbox_key){ |
|
|||
505 | new_data.push(cur_data[d]); |
|
|||
506 | } |
|
|||
507 | } |
|
|||
508 | } |
|
|||
509 | else{ |
|
|||
510 | //push dummy data to not hide the label |
|
|||
511 | new_data.push(getDummyData(checkbox_key)); |
|
|||
512 | } |
|
|||
513 | } |
|
|||
514 |
|
||||
515 | var new_options = YAHOO.lang.merge(plot_options, { |
|
|||
516 | xaxis: { |
|
|||
517 | min: cur_ranges.xaxis.from, |
|
|||
518 | max: cur_ranges.xaxis.to, |
|
|||
519 | mode:"time", |
|
|||
520 | timeformat: "%d/%m", |
|
|||
521 | }, |
|
|||
522 | }); |
|
|||
523 | if (!new_data){ |
|
|||
524 | new_data = [[0,1]]; |
|
|||
525 | } |
|
|||
526 | // do the zooming |
|
|||
527 | plot = YAHOO.widget.Flot(plotContainer, new_data, new_options); |
|
|||
528 |
|
||||
529 | plot.subscribe("plotselected", plotselected); |
|
|||
530 |
|
||||
531 | //resubscribe plothover |
|
|||
532 | plot.subscribe("plothover", plothover); |
|
|||
533 |
|
||||
534 | // don't fire event on the overview to prevent eternal loop |
|
|||
535 | overview.setSelection(cur_ranges, true); |
|
|||
536 |
|
||||
537 | } |
|
|||
538 |
|
||||
539 | /** |
|
|||
540 | * plot only selected items from overview |
|
|||
541 | * @param ranges |
|
|||
542 | * @returns |
|
|||
543 | */ |
|
|||
544 | function plotselected(ranges,cur_data) { |
|
|||
545 | //updates the data for new plot |
|
|||
546 | var data = getDataAccordingToRanges(ranges); |
|
|||
547 | generateCheckboxes(data); |
|
|||
548 |
|
||||
549 | var new_options = YAHOO.lang.merge(plot_options, { |
|
|||
550 | xaxis: { |
|
|||
551 | min: ranges.xaxis.from, |
|
|||
552 | max: ranges.xaxis.to, |
|
|||
553 | mode:"time", |
|
|||
554 | timeformat: "%d/%m", |
|
|||
555 | }, |
|
|||
556 | }); |
|
|||
557 | // do the zooming |
|
|||
558 | plot = YAHOO.widget.Flot(plotContainer, data, new_options); |
|
|||
559 |
|
||||
560 | plot.subscribe("plotselected", plotselected); |
|
|||
561 |
|
||||
562 | //resubscribe plothover |
|
|||
563 | plot.subscribe("plothover", plothover); |
|
|||
564 |
|
||||
565 | // don't fire event on the overview to prevent eternal loop |
|
|||
566 | overview.setSelection(ranges, true); |
|
|||
567 |
|
||||
568 | //resubscribe choiced |
|
|||
569 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]); |
|
|||
570 | } |
|
|||
571 |
|
||||
572 | var previousPoint = null; |
|
|||
573 |
|
||||
574 | function plothover(o) { |
|
|||
575 | var pos = o.pos; |
|
|||
576 | var item = o.item; |
|
|||
577 |
|
||||
578 | //YUD.get("x").innerHTML = pos.x.toFixed(2); |
|
|||
579 | //YUD.get("y").innerHTML = pos.y.toFixed(2); |
|
|||
580 | if (item) { |
|
|||
581 | if (previousPoint != item.datapoint) { |
|
|||
582 | previousPoint = item.datapoint; |
|
|||
583 |
|
||||
584 | var tooltip = YUD.get("tooltip"); |
|
|||
585 | if(tooltip) { |
|
|||
586 | tooltip.parentNode.removeChild(tooltip); |
|
|||
587 | } |
|
|||
588 | var x = item.datapoint.x.toFixed(2); |
|
|||
589 | var y = item.datapoint.y.toFixed(2); |
|
|||
590 |
|
||||
591 | if (!item.series.label){ |
|
|||
592 | item.series.label = 'commits'; |
|
|||
593 | } |
|
|||
594 | var d = new Date(x*1000); |
|
|||
595 | var fd = d.toDateString() |
|
|||
596 | var nr_commits = parseInt(y); |
|
|||
597 |
|
||||
598 | var cur_data = dataset[item.series.label].data[item.dataIndex]; |
|
|||
599 | var added = cur_data.added; |
|
|||
600 | var changed = cur_data.changed; |
|
|||
601 | var removed = cur_data.removed; |
|
|||
602 |
|
||||
603 | var nr_commits_suffix = " ${_('commits')} "; |
|
|||
604 | var added_suffix = " ${_('files added')} "; |
|
|||
605 | var changed_suffix = " ${_('files changed')} "; |
|
|||
606 | var removed_suffix = " ${_('files removed')} "; |
|
|||
607 |
|
||||
608 |
|
||||
609 | if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";} |
|
|||
610 | if(added==1){added_suffix=" ${_('file added')} ";} |
|
|||
611 | if(changed==1){changed_suffix=" ${_('file changed')} ";} |
|
|||
612 | if(removed==1){removed_suffix=" ${_('file removed')} ";} |
|
|||
613 |
|
||||
614 | showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd |
|
|||
615 | +'<br/>'+ |
|
|||
616 | nr_commits + nr_commits_suffix+'<br/>'+ |
|
|||
617 | added + added_suffix +'<br/>'+ |
|
|||
618 | changed + changed_suffix + '<br/>'+ |
|
|||
619 | removed + removed_suffix + '<br/>'); |
|
|||
620 | } |
|
|||
621 | } |
|
|||
622 | else { |
|
|||
623 | var tooltip = YUD.get("tooltip"); |
|
|||
624 |
|
||||
625 | if(tooltip) { |
|
|||
626 | tooltip.parentNode.removeChild(tooltip); |
|
|||
627 | } |
|
|||
628 | previousPoint = null; |
|
|||
629 | } |
|
|||
630 | } |
|
|||
631 |
|
||||
632 | /** |
|
|||
633 | * MAIN EXECUTION |
|
|||
634 | */ |
|
|||
635 |
|
||||
636 | var data = getDataAccordingToRanges(initial_ranges); |
|
|||
637 | generateCheckboxes(data); |
|
|||
638 |
|
||||
639 | //main plot |
|
|||
640 | var plot = YAHOO.widget.Flot(plotContainer,data,plot_options); |
|
|||
641 |
|
||||
642 | //overview |
|
|||
643 | var overview = YAHOO.widget.Flot(overviewContainer, |
|
|||
644 | overview_dataset, overview_options); |
|
|||
645 |
|
||||
646 | //show initial selection on overview |
|
|||
647 | overview.setSelection(initial_ranges); |
|
|||
648 |
|
||||
649 | plot.subscribe("plotselected", plotselected); |
|
|||
650 | plot.subscribe("plothover", plothover) |
|
|||
651 |
|
||||
652 | overview.subscribe("plotselected", function (ranges) { |
|
|||
653 | plot.setSelection(ranges); |
|
|||
654 | }); |
|
|||
655 |
|
||||
656 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]); |
|
|||
657 | } |
|
|||
658 | SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n}); |
|
|||
659 | </script> |
|
|||
660 |
|
||||
661 | </div> |
|
210 | </div> | |
662 | </div> |
|
211 | </div> | |
663 |
|
212 | |||
@@ -669,32 +218,461 b'' | |||||
669 | <div id="shortlog_data"> |
|
218 | <div id="shortlog_data"> | |
670 | <%include file='../shortlog/shortlog_data.html'/> |
|
219 | <%include file='../shortlog/shortlog_data.html'/> | |
671 | </div> |
|
220 | </div> | |
672 | ##%if c.repo_changesets: |
|
221 | </div> | |
673 | ## ${h.link_to(_('show more'),h.url('changelog_home',repo_name=c.repo_name))} |
|
222 | </div> | |
674 | ##%endif |
|
223 | ||
|
224 | %if c.readme_data: | |||
|
225 | <div class="box" style="background-color: #FAFAFA"> | |||
|
226 | <div class="title"> | |||
|
227 | <div class="breadcrumbs"><a href="${h.url('files_home',repo_name=c.repo_name,revision='tip',f_path=c.readme_file)}">${c.readme_file}</a></div> | |||
|
228 | </div> | |||
|
229 | <div class="readme"> | |||
|
230 | <div class="readme_box"> | |||
|
231 | ${c.readme_data|n} | |||
|
232 | </div> | |||
675 | </div> |
|
233 | </div> | |
676 | </div> |
|
234 | </div> | |
677 | <div class="box"> |
|
235 | %endif | |
678 | <div class="title"> |
|
236 | ||
679 | <div class="breadcrumbs">${h.link_to(_('Tags'),h.url('tags_home',repo_name=c.repo_name))}</div> |
|
237 | <script type="text/javascript"> | |
680 | </div> |
|
238 | YUE.onDOMReady(function(e){ | |
681 | <div class="table"> |
|
239 | id = 'clone_url'; | |
682 | <%include file='../tags/tags_data.html'/> |
|
240 | YUE.on(id,'click',function(e){ | |
683 | %if c.repo_changesets: |
|
241 | if(YUD.hasClass(id,'selected')){ | |
684 | ${h.link_to(_('show more'),h.url('tags_home',repo_name=c.repo_name))} |
|
242 | return | |
685 | %endif |
|
243 | } | |
686 | </div> |
|
244 | else{ | |
687 | </div> |
|
245 | YUD.addClass(id,'selected'); | |
688 | <div class="box"> |
|
246 | YUD.get(id).select(); | |
689 | <div class="title"> |
|
247 | } | |
690 | <div class="breadcrumbs">${h.link_to(_('Branches'),h.url('branches_home',repo_name=c.repo_name))}</div> |
|
248 | ||
691 | </div> |
|
249 | }) | |
692 | <div class="table"> |
|
250 | }) | |
693 | <%include file='../branches/branches_data.html'/> |
|
251 | var data = ${c.trending_languages|n}; | |
694 | %if c.repo_changesets: |
|
252 | var total = 0; | |
695 | ${h.link_to(_('show more'),h.url('branches_home',repo_name=c.repo_name))} |
|
253 | var no_data = true; | |
696 | %endif |
|
254 | for (k in data){ | |
697 | </div> |
|
255 | total += data[k].count; | |
698 | </div> |
|
256 | no_data = false; | |
|
257 | } | |||
|
258 | var tbl = document.createElement('table'); | |||
|
259 | tbl.setAttribute('class','trending_language_tbl'); | |||
|
260 | var cnt = 0; | |||
|
261 | for (k in data){ | |||
|
262 | cnt += 1; | |||
|
263 | var hide = cnt>2; | |||
|
264 | var tr = document.createElement('tr'); | |||
|
265 | if (hide){ | |||
|
266 | tr.setAttribute('style','display:none'); | |||
|
267 | tr.setAttribute('class','stats_hidden'); | |||
|
268 | } | |||
|
269 | var percentage = Math.round((data[k].count/total*100),2); | |||
|
270 | var value = data[k].count; | |||
|
271 | var td1 = document.createElement('td'); | |||
|
272 | td1.width = 150; | |||
|
273 | var trending_language_label = document.createElement('div'); | |||
|
274 | trending_language_label.innerHTML = data[k].desc+" ("+k+")"; | |||
|
275 | td1.appendChild(trending_language_label); | |||
|
276 | ||||
|
277 | var td2 = document.createElement('td'); | |||
|
278 | td2.setAttribute('style','padding-right:14px !important'); | |||
|
279 | var trending_language = document.createElement('div'); | |||
|
280 | var nr_files = value+" ${_('files')}"; | |||
|
281 | ||||
|
282 | trending_language.title = k+" "+nr_files; | |||
|
283 | ||||
|
284 | if (percentage>22){ | |||
|
285 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"% "+nr_files+ "</b>"; | |||
|
286 | } | |||
|
287 | else{ | |||
|
288 | trending_language.innerHTML = "<b style='font-size:0.8em'>"+percentage+"%</b>"; | |||
|
289 | } | |||
|
290 | ||||
|
291 | trending_language.setAttribute("class", 'trending_language top-right-rounded-corner bottom-right-rounded-corner'); | |||
|
292 | trending_language.style.width=percentage+"%"; | |||
|
293 | td2.appendChild(trending_language); | |||
|
294 | ||||
|
295 | tr.appendChild(td1); | |||
|
296 | tr.appendChild(td2); | |||
|
297 | tbl.appendChild(tr); | |||
|
298 | if(cnt == 3){ | |||
|
299 | var show_more = document.createElement('tr'); | |||
|
300 | var td = document.createElement('td'); | |||
|
301 | lnk = document.createElement('a'); | |||
|
302 | ||||
|
303 | lnk.href='#'; | |||
|
304 | lnk.innerHTML = "${_('show more')}"; | |||
|
305 | lnk.id='code_stats_show_more'; | |||
|
306 | td.appendChild(lnk); | |||
|
307 | ||||
|
308 | show_more.appendChild(td); | |||
|
309 | show_more.appendChild(document.createElement('td')); | |||
|
310 | tbl.appendChild(show_more); | |||
|
311 | } | |||
|
312 | ||||
|
313 | } | |||
|
314 | if(no_data){ | |||
|
315 | var tr = document.createElement('tr'); | |||
|
316 | var td1 = document.createElement('td'); | |||
|
317 | td1.innerHTML = "${c.no_data_msg}"; | |||
|
318 | tr.appendChild(td1); | |||
|
319 | tbl.appendChild(tr); | |||
|
320 | } | |||
|
321 | YUD.get('lang_stats').appendChild(tbl); | |||
|
322 | YUE.on('code_stats_show_more','click',function(){ | |||
|
323 | l = YUD.getElementsByClassName('stats_hidden') | |||
|
324 | for (e in l){ | |||
|
325 | YUD.setStyle(l[e],'display',''); | |||
|
326 | }; | |||
|
327 | YUD.setStyle(YUD.get('code_stats_show_more'), | |||
|
328 | 'display','none'); | |||
|
329 | }) | |||
|
330 | ||||
|
331 | var tmpl_links = {} | |||
|
332 | %for cnt,archive in enumerate(c.rhodecode_repo._get_archives()): | |||
|
333 | tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'], | |||
|
334 | h.url('files_archive_home',repo_name=c.dbrepo.repo_name, | |||
|
335 | fname='__CS__'+archive['extension'],subrepos='__SUB__'),class_="archive_icon")}'; | |||
|
336 | %endfor | |||
|
337 | ||||
|
338 | YUE.on(['download_options','archive_subrepos'],'change',function(e){ | |||
|
339 | var sm = YUD.get('download_options'); | |||
|
340 | var new_cs = sm.options[sm.selectedIndex]; | |||
|
341 | ||||
|
342 | for(k in tmpl_links){ | |||
|
343 | var s = YUD.get(k+'_link'); | |||
|
344 | title_tmpl = "${_('Download %s as %s') % ('__CS_NAME__','__CS_EXT__')}"; | |||
|
345 | s.title = title_tmpl.replace('__CS_NAME__',new_cs.text); | |||
|
346 | s.title = s.title.replace('__CS_EXT__',k); | |||
|
347 | var url = tmpl_links[k].replace('__CS__',new_cs.value); | |||
|
348 | var subrepos = YUD.get('archive_subrepos').checked | |||
|
349 | url = url.replace('__SUB__',subrepos); | |||
|
350 | s.innerHTML = url | |||
|
351 | } | |||
|
352 | }); | |||
|
353 | </script> | |||
|
354 | <script type="text/javascript"> | |||
|
355 | /** | |||
|
356 | * Plots summary graph | |||
|
357 | * | |||
|
358 | * @class SummaryPlot | |||
|
359 | * @param {from} initial from for detailed graph | |||
|
360 | * @param {to} initial to for detailed graph | |||
|
361 | * @param {dataset} | |||
|
362 | * @param {overview_dataset} | |||
|
363 | */ | |||
|
364 | function SummaryPlot(from,to,dataset,overview_dataset) { | |||
|
365 | var initial_ranges = { | |||
|
366 | "xaxis":{ | |||
|
367 | "from":from, | |||
|
368 | "to":to, | |||
|
369 | }, | |||
|
370 | }; | |||
|
371 | var dataset = dataset; | |||
|
372 | var overview_dataset = [overview_dataset]; | |||
|
373 | var choiceContainer = YUD.get("legend_choices"); | |||
|
374 | var choiceContainerTable = YUD.get("legend_choices_tables"); | |||
|
375 | var plotContainer = YUD.get('commit_history'); | |||
|
376 | var overviewContainer = YUD.get('overview'); | |||
|
377 | ||||
|
378 | var plot_options = { | |||
|
379 | bars: {show:true,align:'center',lineWidth:4}, | |||
|
380 | legend: {show:true, container:"legend_container"}, | |||
|
381 | points: {show:true,radius:0,fill:false}, | |||
|
382 | yaxis: {tickDecimals:0,}, | |||
|
383 | xaxis: { | |||
|
384 | mode: "time", | |||
|
385 | timeformat: "%d/%m", | |||
|
386 | min:from, | |||
|
387 | max:to, | |||
|
388 | }, | |||
|
389 | grid: { | |||
|
390 | hoverable: true, | |||
|
391 | clickable: true, | |||
|
392 | autoHighlight:true, | |||
|
393 | color: "#999" | |||
|
394 | }, | |||
|
395 | //selection: {mode: "x"} | |||
|
396 | }; | |||
|
397 | var overview_options = { | |||
|
398 | legend:{show:false}, | |||
|
399 | bars: {show:true,barWidth: 2,}, | |||
|
400 | shadowSize: 0, | |||
|
401 | xaxis: {mode: "time", timeformat: "%d/%m/%y",}, | |||
|
402 | yaxis: {ticks: 3, min: 0,tickDecimals:0,}, | |||
|
403 | grid: {color: "#999",}, | |||
|
404 | selection: {mode: "x"} | |||
|
405 | }; | |||
|
406 | ||||
|
407 | /** | |||
|
408 | *get dummy data needed in few places | |||
|
409 | */ | |||
|
410 | function getDummyData(label){ | |||
|
411 | return {"label":label, | |||
|
412 | "data":[{"time":0, | |||
|
413 | "commits":0, | |||
|
414 | "added":0, | |||
|
415 | "changed":0, | |||
|
416 | "removed":0, | |||
|
417 | }], | |||
|
418 | "schema":["commits"], | |||
|
419 | "color":'#ffffff', | |||
|
420 | } | |||
|
421 | } | |||
|
422 | ||||
|
423 | /** | |||
|
424 | * generate checkboxes accordindly to data | |||
|
425 | * @param keys | |||
|
426 | * @returns | |||
|
427 | */ | |||
|
428 | function generateCheckboxes(data) { | |||
|
429 | //append checkboxes | |||
|
430 | var i = 0; | |||
|
431 | choiceContainerTable.innerHTML = ''; | |||
|
432 | for(var pos in data) { | |||
|
433 | ||||
|
434 | data[pos].color = i; | |||
|
435 | i++; | |||
|
436 | if(data[pos].label != ''){ | |||
|
437 | choiceContainerTable.innerHTML += '<tr><td>'+ | |||
|
438 | '<input type="checkbox" name="' + data[pos].label +'" checked="checked" />' | |||
|
439 | +data[pos].label+ | |||
|
440 | '</td></tr>'; | |||
|
441 | } | |||
|
442 | } | |||
|
443 | } | |||
|
444 | ||||
|
445 | /** | |||
|
446 | * ToolTip show | |||
|
447 | */ | |||
|
448 | function showTooltip(x, y, contents) { | |||
|
449 | var div=document.getElementById('tooltip'); | |||
|
450 | if(!div) { | |||
|
451 | div = document.createElement('div'); | |||
|
452 | div.id="tooltip"; | |||
|
453 | div.style.position="absolute"; | |||
|
454 | div.style.border='1px solid #fdd'; | |||
|
455 | div.style.padding='2px'; | |||
|
456 | div.style.backgroundColor='#fee'; | |||
|
457 | document.body.appendChild(div); | |||
|
458 | } | |||
|
459 | YUD.setStyle(div, 'opacity', 0); | |||
|
460 | div.innerHTML = contents; | |||
|
461 | div.style.top=(y + 5) + "px"; | |||
|
462 | div.style.left=(x + 5) + "px"; | |||
|
463 | ||||
|
464 | var anim = new YAHOO.util.Anim(div, {opacity: {to: 0.8}}, 0.2); | |||
|
465 | anim.animate(); | |||
|
466 | } | |||
|
467 | ||||
|
468 | /** | |||
|
469 | * This function will detect if selected period has some changesets | |||
|
470 | for this user if it does this data is then pushed for displaying | |||
|
471 | Additionally it will only display users that are selected by the checkbox | |||
|
472 | */ | |||
|
473 | function getDataAccordingToRanges(ranges) { | |||
|
474 | ||||
|
475 | var data = []; | |||
|
476 | var new_dataset = {}; | |||
|
477 | var keys = []; | |||
|
478 | var max_commits = 0; | |||
|
479 | for(var key in dataset){ | |||
|
480 | ||||
|
481 | for(var ds in dataset[key].data){ | |||
|
482 | commit_data = dataset[key].data[ds]; | |||
|
483 | if (commit_data.time >= ranges.xaxis.from && commit_data.time <= ranges.xaxis.to){ | |||
|
484 | ||||
|
485 | if(new_dataset[key] === undefined){ | |||
|
486 | new_dataset[key] = {data:[],schema:["commits"],label:key}; | |||
|
487 | } | |||
|
488 | new_dataset[key].data.push(commit_data); | |||
|
489 | } | |||
|
490 | } | |||
|
491 | if (new_dataset[key] !== undefined){ | |||
|
492 | data.push(new_dataset[key]); | |||
|
493 | } | |||
|
494 | } | |||
|
495 | ||||
|
496 | if (data.length > 0){ | |||
|
497 | return data; | |||
|
498 | } | |||
|
499 | else{ | |||
|
500 | //just return dummy data for graph to plot itself | |||
|
501 | return [getDummyData('')]; | |||
|
502 | } | |||
|
503 | } | |||
|
504 | ||||
|
505 | /** | |||
|
506 | * redraw using new checkbox data | |||
|
507 | */ | |||
|
508 | function plotchoiced(e,args){ | |||
|
509 | var cur_data = args[0]; | |||
|
510 | var cur_ranges = args[1]; | |||
|
511 | ||||
|
512 | var new_data = []; | |||
|
513 | var inputs = choiceContainer.getElementsByTagName("input"); | |||
|
514 | ||||
|
515 | //show only checked labels | |||
|
516 | for(var i=0; i<inputs.length; i++) { | |||
|
517 | var checkbox_key = inputs[i].name; | |||
|
518 | ||||
|
519 | if(inputs[i].checked){ | |||
|
520 | for(var d in cur_data){ | |||
|
521 | if(cur_data[d].label == checkbox_key){ | |||
|
522 | new_data.push(cur_data[d]); | |||
|
523 | } | |||
|
524 | } | |||
|
525 | } | |||
|
526 | else{ | |||
|
527 | //push dummy data to not hide the label | |||
|
528 | new_data.push(getDummyData(checkbox_key)); | |||
|
529 | } | |||
|
530 | } | |||
|
531 | ||||
|
532 | var new_options = YAHOO.lang.merge(plot_options, { | |||
|
533 | xaxis: { | |||
|
534 | min: cur_ranges.xaxis.from, | |||
|
535 | max: cur_ranges.xaxis.to, | |||
|
536 | mode:"time", | |||
|
537 | timeformat: "%d/%m", | |||
|
538 | }, | |||
|
539 | }); | |||
|
540 | if (!new_data){ | |||
|
541 | new_data = [[0,1]]; | |||
|
542 | } | |||
|
543 | // do the zooming | |||
|
544 | plot = YAHOO.widget.Flot(plotContainer, new_data, new_options); | |||
|
545 | ||||
|
546 | plot.subscribe("plotselected", plotselected); | |||
|
547 | ||||
|
548 | //resubscribe plothover | |||
|
549 | plot.subscribe("plothover", plothover); | |||
|
550 | ||||
|
551 | // don't fire event on the overview to prevent eternal loop | |||
|
552 | overview.setSelection(cur_ranges, true); | |||
|
553 | ||||
|
554 | } | |||
|
555 | ||||
|
556 | /** | |||
|
557 | * plot only selected items from overview | |||
|
558 | * @param ranges | |||
|
559 | * @returns | |||
|
560 | */ | |||
|
561 | function plotselected(ranges,cur_data) { | |||
|
562 | //updates the data for new plot | |||
|
563 | var data = getDataAccordingToRanges(ranges); | |||
|
564 | generateCheckboxes(data); | |||
|
565 | ||||
|
566 | var new_options = YAHOO.lang.merge(plot_options, { | |||
|
567 | xaxis: { | |||
|
568 | min: ranges.xaxis.from, | |||
|
569 | max: ranges.xaxis.to, | |||
|
570 | mode:"time", | |||
|
571 | timeformat: "%d/%m", | |||
|
572 | }, | |||
|
573 | }); | |||
|
574 | // do the zooming | |||
|
575 | plot = YAHOO.widget.Flot(plotContainer, data, new_options); | |||
|
576 | ||||
|
577 | plot.subscribe("plotselected", plotselected); | |||
|
578 | ||||
|
579 | //resubscribe plothover | |||
|
580 | plot.subscribe("plothover", plothover); | |||
|
581 | ||||
|
582 | // don't fire event on the overview to prevent eternal loop | |||
|
583 | overview.setSelection(ranges, true); | |||
|
584 | ||||
|
585 | //resubscribe choiced | |||
|
586 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, ranges]); | |||
|
587 | } | |||
|
588 | ||||
|
589 | var previousPoint = null; | |||
|
590 | ||||
|
591 | function plothover(o) { | |||
|
592 | var pos = o.pos; | |||
|
593 | var item = o.item; | |||
|
594 | ||||
|
595 | //YUD.get("x").innerHTML = pos.x.toFixed(2); | |||
|
596 | //YUD.get("y").innerHTML = pos.y.toFixed(2); | |||
|
597 | if (item) { | |||
|
598 | if (previousPoint != item.datapoint) { | |||
|
599 | previousPoint = item.datapoint; | |||
|
600 | ||||
|
601 | var tooltip = YUD.get("tooltip"); | |||
|
602 | if(tooltip) { | |||
|
603 | tooltip.parentNode.removeChild(tooltip); | |||
|
604 | } | |||
|
605 | var x = item.datapoint.x.toFixed(2); | |||
|
606 | var y = item.datapoint.y.toFixed(2); | |||
|
607 | ||||
|
608 | if (!item.series.label){ | |||
|
609 | item.series.label = 'commits'; | |||
|
610 | } | |||
|
611 | var d = new Date(x*1000); | |||
|
612 | var fd = d.toDateString() | |||
|
613 | var nr_commits = parseInt(y); | |||
|
614 | ||||
|
615 | var cur_data = dataset[item.series.label].data[item.dataIndex]; | |||
|
616 | var added = cur_data.added; | |||
|
617 | var changed = cur_data.changed; | |||
|
618 | var removed = cur_data.removed; | |||
|
619 | ||||
|
620 | var nr_commits_suffix = " ${_('commits')} "; | |||
|
621 | var added_suffix = " ${_('files added')} "; | |||
|
622 | var changed_suffix = " ${_('files changed')} "; | |||
|
623 | var removed_suffix = " ${_('files removed')} "; | |||
|
624 | ||||
|
625 | ||||
|
626 | if(nr_commits == 1){nr_commits_suffix = " ${_('commit')} ";} | |||
|
627 | if(added==1){added_suffix=" ${_('file added')} ";} | |||
|
628 | if(changed==1){changed_suffix=" ${_('file changed')} ";} | |||
|
629 | if(removed==1){removed_suffix=" ${_('file removed')} ";} | |||
|
630 | ||||
|
631 | showTooltip(item.pageX, item.pageY, item.series.label + " on " + fd | |||
|
632 | +'<br/>'+ | |||
|
633 | nr_commits + nr_commits_suffix+'<br/>'+ | |||
|
634 | added + added_suffix +'<br/>'+ | |||
|
635 | changed + changed_suffix + '<br/>'+ | |||
|
636 | removed + removed_suffix + '<br/>'); | |||
|
637 | } | |||
|
638 | } | |||
|
639 | else { | |||
|
640 | var tooltip = YUD.get("tooltip"); | |||
|
641 | ||||
|
642 | if(tooltip) { | |||
|
643 | tooltip.parentNode.removeChild(tooltip); | |||
|
644 | } | |||
|
645 | previousPoint = null; | |||
|
646 | } | |||
|
647 | } | |||
|
648 | ||||
|
649 | /** | |||
|
650 | * MAIN EXECUTION | |||
|
651 | */ | |||
|
652 | ||||
|
653 | var data = getDataAccordingToRanges(initial_ranges); | |||
|
654 | generateCheckboxes(data); | |||
|
655 | ||||
|
656 | //main plot | |||
|
657 | var plot = YAHOO.widget.Flot(plotContainer,data,plot_options); | |||
|
658 | ||||
|
659 | //overview | |||
|
660 | var overview = YAHOO.widget.Flot(overviewContainer, | |||
|
661 | overview_dataset, overview_options); | |||
|
662 | ||||
|
663 | //show initial selection on overview | |||
|
664 | overview.setSelection(initial_ranges); | |||
|
665 | ||||
|
666 | plot.subscribe("plotselected", plotselected); | |||
|
667 | plot.subscribe("plothover", plothover) | |||
|
668 | ||||
|
669 | overview.subscribe("plotselected", function (ranges) { | |||
|
670 | plot.setSelection(ranges); | |||
|
671 | }); | |||
|
672 | ||||
|
673 | YUE.on(choiceContainer.getElementsByTagName("input"), "click", plotchoiced, [data, initial_ranges]); | |||
|
674 | } | |||
|
675 | SummaryPlot(${c.ts_min},${c.ts_max},${c.commit_data|n},${c.overview_data|n}); | |||
|
676 | </script> | |||
699 |
|
677 | |||
700 | </%def> |
|
678 | </%def> |
@@ -24,7 +24,9 b' requirements = [' | |||||
24 | "python-dateutil>=1.5.0,<2.0.0", |
|
24 | "python-dateutil>=1.5.0,<2.0.0", | |
25 | "dulwich>=0.8.0,<0.9.0", |
|
25 | "dulwich>=0.8.0,<0.9.0", | |
26 | "vcs>=0.2.3.dev", |
|
26 | "vcs>=0.2.3.dev", | |
27 | "webob==1.0.8" |
|
27 | "webob==1.0.8", | |
|
28 | "markdown==2.0.3", | |||
|
29 | "docutils==0.8.1", | |||
28 | ] |
|
30 | ] | |
29 |
|
31 | |||
30 | dependency_links = [ |
|
32 | dependency_links = [ |
General Comments 0
You need to be logged in to leave comments.
Login now