Fossil SCM

Allow the timeline graph to be customized using CSS.

joel 2015-05-06 20:55 trunk
Commit 1f1e199a20d7f57bf2ba959ecea8ae62a768b58e
--- skins/aht/details.txt
+++ skins/aht/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/aht/details.txt
+++ skins/aht/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/aht/details.txt
+++ skins/aht/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/black_and_white/details.txt
+++ skins/black_and_white/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/black_and_white/details.txt
+++ skins/black_and_white/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/black_and_white/details.txt
+++ skins/black_and_white/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/blitz/css.txt
+++ skins/blitz/css.txt
@@ -1102,10 +1102,49 @@
11021102
11031103
span.timelineComment {
11041104
padding: 0px 5px;
11051105
}
11061106
1107
+
1108
+/* Timeline graph
1109
+––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1110
+/* commit node */
1111
+.tl-node {
1112
+ width: 10px;
1113
+ height: 10px;
1114
+ border: 1px solid #000;
1115
+ border-radius: 50%;
1116
+ background: #fff;
1117
+ cursor: pointer;
1118
+}
1119
+/* leaf commit marker */
1120
+.tl-node.leaf:after {
1121
+ content: '';
1122
+ position: absolute;
1123
+ top: 3px;
1124
+ left: 3px;
1125
+ width: 4px;
1126
+ height: 4px;
1127
+ border-radius: 50%;
1128
+ background: #000;
1129
+}
1130
+/* selected commit node marker */
1131
+.tl-node.sel:after {
1132
+ content: '';
1133
+ position: absolute;
1134
+ top: 2px;
1135
+ left: 2px;
1136
+ width: 6px;
1137
+ height: 6px;
1138
+ border-radius: 50%;
1139
+ background: red;
1140
+}
1141
+/* up arrow */
1142
+.tl-arrow.u {
1143
+ display: none;
1144
+}
1145
+
11071146
11081147
/* Login/Loguot
11091148
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
11101149
table.login_out {
11111150
}
11121151
--- skins/blitz/css.txt
+++ skins/blitz/css.txt
@@ -1102,10 +1102,49 @@
1102
1103 span.timelineComment {
1104 padding: 0px 5px;
1105 }
1106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1107
1108 /* Login/Loguot
1109 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1110 table.login_out {
1111 }
1112
--- skins/blitz/css.txt
+++ skins/blitz/css.txt
@@ -1102,10 +1102,49 @@
1102
1103 span.timelineComment {
1104 padding: 0px 5px;
1105 }
1106
1107
1108 /* Timeline graph
1109 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1110 /* commit node */
1111 .tl-node {
1112 width: 10px;
1113 height: 10px;
1114 border: 1px solid #000;
1115 border-radius: 50%;
1116 background: #fff;
1117 cursor: pointer;
1118 }
1119 /* leaf commit marker */
1120 .tl-node.leaf:after {
1121 content: '';
1122 position: absolute;
1123 top: 3px;
1124 left: 3px;
1125 width: 4px;
1126 height: 4px;
1127 border-radius: 50%;
1128 background: #000;
1129 }
1130 /* selected commit node marker */
1131 .tl-node.sel:after {
1132 content: '';
1133 position: absolute;
1134 top: 2px;
1135 left: 2px;
1136 width: 6px;
1137 height: 6px;
1138 border-radius: 50%;
1139 background: red;
1140 }
1141 /* up arrow */
1142 .tl-arrow.u {
1143 display: none;
1144 }
1145
1146
1147 /* Login/Loguot
1148 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1149 table.login_out {
1150 }
1151
--- skins/blitz/details.txt
+++ skins/blitz/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 0
2
-timeline-circle-nodes: 1
31
timeline-color-graph-lines: 1
42
white-foreground: 0
53
--- skins/blitz/details.txt
+++ skins/blitz/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 0
2 timeline-circle-nodes: 1
3 timeline-color-graph-lines: 1
4 white-foreground: 0
5
--- skins/blitz/details.txt
+++ skins/blitz/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 1
2 white-foreground: 0
3
--- skins/blitz_no_logo/css.txt
+++ skins/blitz_no_logo/css.txt
@@ -1102,10 +1102,49 @@
11021102
11031103
span.timelineComment {
11041104
padding: 0px 5px;
11051105
}
11061106
1107
+
1108
+/* Timeline graph
1109
+––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1110
+/* commit node */
1111
+.tl-node {
1112
+ width: 10px;
1113
+ height: 10px;
1114
+ border: 1px solid #000;
1115
+ border-radius: 50%;
1116
+ background: #fff;
1117
+ cursor: pointer;
1118
+}
1119
+/* leaf commit marker */
1120
+.tl-node.leaf:after {
1121
+ content: '';
1122
+ position: absolute;
1123
+ top: 3px;
1124
+ left: 3px;
1125
+ width: 4px;
1126
+ height: 4px;
1127
+ border-radius: 50%;
1128
+ background: #000;
1129
+}
1130
+/* selected commit node marker */
1131
+.tl-node.sel:after {
1132
+ content: '';
1133
+ position: absolute;
1134
+ top: 2px;
1135
+ left: 2px;
1136
+ width: 6px;
1137
+ height: 6px;
1138
+ border-radius: 50%;
1139
+ background: red;
1140
+}
1141
+/* up arrow */
1142
+.tl-arrow.u {
1143
+ display: none;
1144
+}
1145
+
11071146
11081147
/* Login/Loguot
11091148
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
11101149
table.login_out {
11111150
}
11121151
--- skins/blitz_no_logo/css.txt
+++ skins/blitz_no_logo/css.txt
@@ -1102,10 +1102,49 @@
1102
1103 span.timelineComment {
1104 padding: 0px 5px;
1105 }
1106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1107
1108 /* Login/Loguot
1109 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1110 table.login_out {
1111 }
1112
--- skins/blitz_no_logo/css.txt
+++ skins/blitz_no_logo/css.txt
@@ -1102,10 +1102,49 @@
1102
1103 span.timelineComment {
1104 padding: 0px 5px;
1105 }
1106
1107
1108 /* Timeline graph
1109 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1110 /* commit node */
1111 .tl-node {
1112 width: 10px;
1113 height: 10px;
1114 border: 1px solid #000;
1115 border-radius: 50%;
1116 background: #fff;
1117 cursor: pointer;
1118 }
1119 /* leaf commit marker */
1120 .tl-node.leaf:after {
1121 content: '';
1122 position: absolute;
1123 top: 3px;
1124 left: 3px;
1125 width: 4px;
1126 height: 4px;
1127 border-radius: 50%;
1128 background: #000;
1129 }
1130 /* selected commit node marker */
1131 .tl-node.sel:after {
1132 content: '';
1133 position: absolute;
1134 top: 2px;
1135 left: 2px;
1136 width: 6px;
1137 height: 6px;
1138 border-radius: 50%;
1139 background: red;
1140 }
1141 /* up arrow */
1142 .tl-arrow.u {
1143 display: none;
1144 }
1145
1146
1147 /* Login/Loguot
1148 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– */
1149 table.login_out {
1150 }
1151
--- skins/blitz_no_logo/details.txt
+++ skins/blitz_no_logo/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 0
2
-timeline-circle-nodes: 1
31
timeline-color-graph-lines: 1
42
white-foreground: 0
53
--- skins/blitz_no_logo/details.txt
+++ skins/blitz_no_logo/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 0
2 timeline-circle-nodes: 1
3 timeline-color-graph-lines: 1
4 white-foreground: 0
5
--- skins/blitz_no_logo/details.txt
+++ skins/blitz_no_logo/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 1
2 white-foreground: 0
3
--- skins/default/details.txt
+++ skins/default/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/default/details.txt
+++ skins/default/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/default/details.txt
+++ skins/default/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -168,10 +168,58 @@
168168
}
169169
170170
tr.timelineSelected {
171171
background-color: #7EA2D9;
172172
}
173
+
174
+/* commit node */
175
+.tl-node {
176
+ width: 10px;
177
+ height: 10px;
178
+ border: 1px solid #fff;
179
+ background: #485D7B;
180
+ cursor: pointer;
181
+}
182
+
183
+/* leaf commit marker */
184
+.tl-node.leaf:after {
185
+ content: '';
186
+ position: absolute;
187
+ top: 3px;
188
+ left: 3px;
189
+ width: 4px;
190
+ height: 4px;
191
+ background: #fff;
192
+}
193
+
194
+/* up arrow */
195
+.tl-arrow.u {
196
+ margin-top: -1px;
197
+ border-width: 0 3px;
198
+ border-bottom: 7px solid #fff;
199
+}
200
+
201
+/* small up arrow */
202
+.tl-arrow.u.sm {
203
+ border-bottom: 5px solid #fff;
204
+}
205
+
206
+/* line */
207
+.tl-line {
208
+ background: #fff;
209
+ width: 2px;
210
+}
211
+
212
+/* left merge arrow */
213
+.tl-arrow.merge.l {
214
+ border-right: 3px solid #fff;
215
+}
216
+
217
+/* right merge arrow */
218
+.tl-arrow.merge.r {
219
+ border-left: 3px solid #fff;
220
+}
173221
174222
/* Side-by-side diff */
175223
table.sbsdiff {
176224
background-color: #485D7B;
177225
font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@@ -264,14 +312,10 @@
264312
/* line numbers in a diff */
265313
span.diffln {
266314
color: white;
267315
}
268316
269
-#canvas {
270
- background-color: #485D7B;
271
-}
272
-
273317
.fileage tr:hover {
274318
background-color: #7EA2D9;
275319
}
276320
277321
.fileage td {
278322
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -168,10 +168,58 @@
168 }
169
170 tr.timelineSelected {
171 background-color: #7EA2D9;
172 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
174 /* Side-by-side diff */
175 table.sbsdiff {
176 background-color: #485D7B;
177 font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@@ -264,14 +312,10 @@
264 /* line numbers in a diff */
265 span.diffln {
266 color: white;
267 }
268
269 #canvas {
270 background-color: #485D7B;
271 }
272
273 .fileage tr:hover {
274 background-color: #7EA2D9;
275 }
276
277 .fileage td {
278
--- skins/eagle/css.txt
+++ skins/eagle/css.txt
@@ -168,10 +168,58 @@
168 }
169
170 tr.timelineSelected {
171 background-color: #7EA2D9;
172 }
173
174 /* commit node */
175 .tl-node {
176 width: 10px;
177 height: 10px;
178 border: 1px solid #fff;
179 background: #485D7B;
180 cursor: pointer;
181 }
182
183 /* leaf commit marker */
184 .tl-node.leaf:after {
185 content: '';
186 position: absolute;
187 top: 3px;
188 left: 3px;
189 width: 4px;
190 height: 4px;
191 background: #fff;
192 }
193
194 /* up arrow */
195 .tl-arrow.u {
196 margin-top: -1px;
197 border-width: 0 3px;
198 border-bottom: 7px solid #fff;
199 }
200
201 /* small up arrow */
202 .tl-arrow.u.sm {
203 border-bottom: 5px solid #fff;
204 }
205
206 /* line */
207 .tl-line {
208 background: #fff;
209 width: 2px;
210 }
211
212 /* left merge arrow */
213 .tl-arrow.merge.l {
214 border-right: 3px solid #fff;
215 }
216
217 /* right merge arrow */
218 .tl-arrow.merge.r {
219 border-left: 3px solid #fff;
220 }
221
222 /* Side-by-side diff */
223 table.sbsdiff {
224 background-color: #485D7B;
225 font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
@@ -264,14 +312,10 @@
312 /* line numbers in a diff */
313 span.diffln {
314 color: white;
315 }
316
 
 
 
 
317 .fileage tr:hover {
318 background-color: #7EA2D9;
319 }
320
321 .fileage td {
322
--- skins/eagle/details.txt
+++ skins/eagle/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 1
53
--- skins/eagle/details.txt
+++ skins/eagle/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 1
5
--- skins/eagle/details.txt
+++ skins/eagle/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 1
3
--- skins/enhanced1/details.txt
+++ skins/enhanced1/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/enhanced1/details.txt
+++ skins/enhanced1/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/enhanced1/details.txt
+++ skins/enhanced1/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/khaki/details.txt
+++ skins/khaki/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/khaki/details.txt
+++ skins/khaki/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/khaki/details.txt
+++ skins/khaki/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/original/details.txt
+++ skins/original/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/original/details.txt
+++ skins/original/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/original/details.txt
+++ skins/original/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/plain_gray/details.txt
+++ skins/plain_gray/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/plain_gray/details.txt
+++ skins/plain_gray/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/plain_gray/details.txt
+++ skins/plain_gray/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/rounded1/details.txt
+++ skins/rounded1/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/rounded1/details.txt
+++ skins/rounded1/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/rounded1/details.txt
+++ skins/rounded1/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -700,15 +700,10 @@
700700
701701
/**************************************
702702
* Timeline
703703
*/
704704
705
-#canvas {
706
- color: #000;
707
- background-color: #fff;
708
-}
709
-
710705
div.divider {
711706
color: #ee0;
712707
font-size: 1.2rem;
713708
font-weight: bold;
714709
margin-top: 1rem;
715710
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -700,15 +700,10 @@
700
701 /**************************************
702 * Timeline
703 */
704
705 #canvas {
706 color: #000;
707 background-color: #fff;
708 }
709
710 div.divider {
711 color: #ee0;
712 font-size: 1.2rem;
713 font-weight: bold;
714 margin-top: 1rem;
715
--- skins/xekri/css.txt
+++ skins/xekri/css.txt
@@ -700,15 +700,10 @@
700
701 /**************************************
702 * Timeline
703 */
704
 
 
 
 
 
705 div.divider {
706 color: #ee0;
707 font-size: 1.2rem;
708 font-weight: bold;
709 margin-top: 1rem;
710
--- skins/xekri/details.txt
+++ skins/xekri/details.txt
@@ -1,4 +1,2 @@
1
-timeline-arrowheads: 1
2
-timeline-circle-nodes: 0
31
timeline-color-graph-lines: 0
42
white-foreground: 0
53
--- skins/xekri/details.txt
+++ skins/xekri/details.txt
@@ -1,4 +1,2 @@
1 timeline-arrowheads: 1
2 timeline-circle-nodes: 0
3 timeline-color-graph-lines: 0
4 white-foreground: 0
5
--- skins/xekri/details.txt
+++ skins/xekri/details.txt
@@ -1,4 +1,2 @@
 
 
1 timeline-color-graph-lines: 0
2 white-foreground: 0
3
+2 -7
--- src/finfo.c
+++ src/finfo.c
@@ -403,12 +403,10 @@
403403
if( fShowId ) blob_appendf(&title, " (%d)", fnid);
404404
}
405405
@ <h2>%b(&title)</h2>
406406
blob_reset(&title);
407407
pGraph = graph_init();
408
- @ <div id="canvas" style="position:relative;width:1px;height:1px;"
409
- @ onclick="clickOnGraph(event)"></div>
410408
@ <table id="timelineTable" class="timelineTable">
411409
while( db_step(&q)==SQLITE_ROW ){
412410
const char *zDate = db_column_text(&q, 0);
413411
const char *zCom = db_column_text(&q, 1);
414412
const char *zUser = db_column_text(&q, 2);
@@ -459,11 +457,11 @@
459457
}
460458
memcpy(zTime, &zDate[11], 5);
461459
zTime[5] = 0;
462460
@ <tr><td class="timelineTime">
463461
@ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
464
- @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
462
+ @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div></td>
465463
if( zBgClr && zBgClr[0] ){
466464
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
467465
}else{
468466
@ <td class="timelineTableCell">
469467
}
@@ -536,15 +534,12 @@
536534
graph_finish(pGraph, 1);
537535
if( pGraph->nErr ){
538536
graph_free(pGraph);
539537
pGraph = 0;
540538
}else{
541
- int w = pGraph->mxRail*pGraph->iRailPitch + 28;
542
- @ <tr><td></td><td>
543
- @ <div id="grbtm" style="width:%d(w)px;"></div>
544
- @ </td><td></td></tr>
539
+ @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
545540
}
546541
}
547542
@ </table>
548543
timeline_output_graph_javascript(pGraph, 0, 1);
549544
style_footer();
550545
}
551546
--- src/finfo.c
+++ src/finfo.c
@@ -403,12 +403,10 @@
403 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
404 }
405 @ <h2>%b(&title)</h2>
406 blob_reset(&title);
407 pGraph = graph_init();
408 @ <div id="canvas" style="position:relative;width:1px;height:1px;"
409 @ onclick="clickOnGraph(event)"></div>
410 @ <table id="timelineTable" class="timelineTable">
411 while( db_step(&q)==SQLITE_ROW ){
412 const char *zDate = db_column_text(&q, 0);
413 const char *zCom = db_column_text(&q, 1);
414 const char *zUser = db_column_text(&q, 2);
@@ -459,11 +457,11 @@
459 }
460 memcpy(zTime, &zDate[11], 5);
461 zTime[5] = 0;
462 @ <tr><td class="timelineTime">
463 @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
464 @ <td class="timelineGraph"><div id="m%d(gidx)"></div></td>
465 if( zBgClr && zBgClr[0] ){
466 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
467 }else{
468 @ <td class="timelineTableCell">
469 }
@@ -536,15 +534,12 @@
536 graph_finish(pGraph, 1);
537 if( pGraph->nErr ){
538 graph_free(pGraph);
539 pGraph = 0;
540 }else{
541 int w = pGraph->mxRail*pGraph->iRailPitch + 28;
542 @ <tr><td></td><td>
543 @ <div id="grbtm" style="width:%d(w)px;"></div>
544 @ </td><td></td></tr>
545 }
546 }
547 @ </table>
548 timeline_output_graph_javascript(pGraph, 0, 1);
549 style_footer();
550 }
551
--- src/finfo.c
+++ src/finfo.c
@@ -403,12 +403,10 @@
403 if( fShowId ) blob_appendf(&title, " (%d)", fnid);
404 }
405 @ <h2>%b(&title)</h2>
406 blob_reset(&title);
407 pGraph = graph_init();
 
 
408 @ <table id="timelineTable" class="timelineTable">
409 while( db_step(&q)==SQLITE_ROW ){
410 const char *zDate = db_column_text(&q, 0);
411 const char *zCom = db_column_text(&q, 1);
412 const char *zUser = db_column_text(&q, 2);
@@ -459,11 +457,11 @@
457 }
458 memcpy(zTime, &zDate[11], 5);
459 zTime[5] = 0;
460 @ <tr><td class="timelineTime">
461 @ %z(href("%R/timeline?c=%t",zDate))%s(zTime)</a></td>
462 @ <td class="timelineGraph"><div id="m%d(gidx)" class="tl-nodemark"></div></td>
463 if( zBgClr && zBgClr[0] ){
464 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
465 }else{
466 @ <td class="timelineTableCell">
467 }
@@ -536,15 +534,12 @@
534 graph_finish(pGraph, 1);
535 if( pGraph->nErr ){
536 graph_free(pGraph);
537 pGraph = 0;
538 }else{
539 @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
 
 
 
540 }
541 }
542 @ </table>
543 timeline_output_graph_javascript(pGraph, 0, 1);
544 style_footer();
545 }
546
+8 -15
--- src/graph.c
+++ src/graph.c
@@ -47,11 +47,11 @@
4747
u8 isDup; /* True if this is duplicate of a prior entry */
4848
u8 isLeaf; /* True if this is a leaf node */
4949
u8 timeWarp; /* Child is earlier in time */
5050
u8 bDescender; /* True if riser from bottom of graph to here. */
5151
i8 iRail; /* Which rail this check-in appears on. 0-based.*/
52
- i8 mergeOut; /* Merge out on rail mergeOut/4. -1 for none */
52
+ i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
5353
u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
5454
int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
5555
int mergeUpto; /* Draw the mergeOut rail up to this level */
5656
u64 mergeDown; /* Draw merge lines up from bottom of graph */
5757
@@ -61,11 +61,10 @@
6161
/* Context while building a graph
6262
*/
6363
struct GraphContext {
6464
int nErr; /* Number of errors encountered */
6565
int mxRail; /* Number of rails required to render the graph */
66
- int iRailPitch; /* Pixels between rail centers */
6766
GraphRow *pFirst; /* First row in the list */
6867
GraphRow *pLast; /* Last row in the list */
6968
int nBranch; /* Number of distinct branches */
7069
char **azBranch; /* Names of the branches */
7170
int nRow; /* Number of rows */
@@ -294,28 +293,27 @@
294293
u = pParent->aiRiser[pParent->iRail];
295294
if( u>=0 && u<pChild->idx ){
296295
/* The thick arrow up to the next primary child of pDesc goes
297296
** further up than the thin merge arrow riser, so draw them both
298297
** on the same rail. */
299
- pParent->mergeOut = pParent->iRail*4;
300
- if( pParent->iRail<pChild->iRail ) pParent->mergeOut += 2;
298
+ pParent->mergeOut = pParent->iRail;
301299
pParent->mergeUpto = pChild->idx;
302300
}else{
303301
/* The thin merge arrow riser is taller than the thick primary
304302
** child riser, so use separate rails. */
305303
int iTarget = pParent->iRail;
306304
pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
307
- 0, iTarget)*4 + 1;
305
+ 0, iTarget);
308306
pParent->mergeUpto = pChild->idx;
309
- mask = BIT(pParent->mergeOut/4);
307
+ mask = BIT(pParent->mergeOut);
310308
for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
311309
pLoop=pLoop->pNext){
312310
pLoop->railInUse |= mask;
313311
}
314312
}
315313
}
316
- pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1;
314
+ pChild->mergeIn[pParent->mergeOut] = 1;
317315
}
318316
319317
/*
320318
** Compute the maximum rail number.
321319
*/
@@ -322,11 +320,11 @@
322320
static void find_max_rail(GraphContext *p){
323321
GraphRow *pRow;
324322
p->mxRail = 0;
325323
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
326324
if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
327
- if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4;
325
+ if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
328326
while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>(BIT(p->mxRail+1)-1) ){
329327
p->mxRail++;
330328
}
331329
}
332330
}
@@ -540,11 +538,11 @@
540538
if( pDesc==0 ){
541539
/* Merge from a node that is off-screen */
542540
int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
543541
if( p->mxRail>=GR_MAX_RAIL ) return;
544542
mask = BIT(iMrail);
545
- pRow->mergeIn[iMrail] = 2;
543
+ pRow->mergeIn[iMrail] = 1;
546544
pRow->mergeDown |= mask;
547545
for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
548546
pLoop->railInUse |= mask;
549547
}
550548
}else{
@@ -569,11 +567,11 @@
569567
if( !pRow->isDup ) continue;
570568
pRow->iRail = dupRail;
571569
pDesc = hashFind(p, pRow->rid);
572570
assert( pDesc!=0 && pDesc!=pRow );
573571
createMergeRiser(p, pDesc, pRow);
574
- if( pDesc->mergeOut/4>mxRail ) mxRail = pDesc->mergeOut/4;
572
+ if( pDesc->mergeOut>mxRail ) mxRail = pDesc->mergeOut;
575573
}
576574
if( dupRail<=mxRail ){
577575
dupRail = mxRail+1;
578576
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
579577
if( pRow->isDup ) pRow->iRail = dupRail;
@@ -584,12 +582,7 @@
584582
585583
/*
586584
** Find the maximum rail number.
587585
*/
588586
find_max_rail(p);
589
- p->iRailPitch = atoi(PD("railpitch","0"));
590
- if( p->iRailPitch<=0 ){
591
- p->iRailPitch = 18 - (p->mxRail/3);
592
- if( p->iRailPitch<11 ) p->iRailPitch = 11;
593
- }
594587
p->nErr = 0;
595588
}
596589
--- src/graph.c
+++ src/graph.c
@@ -47,11 +47,11 @@
47 u8 isDup; /* True if this is duplicate of a prior entry */
48 u8 isLeaf; /* True if this is a leaf node */
49 u8 timeWarp; /* Child is earlier in time */
50 u8 bDescender; /* True if riser from bottom of graph to here. */
51 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
52 i8 mergeOut; /* Merge out on rail mergeOut/4. -1 for none */
53 u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
54 int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
55 int mergeUpto; /* Draw the mergeOut rail up to this level */
56 u64 mergeDown; /* Draw merge lines up from bottom of graph */
57
@@ -61,11 +61,10 @@
61 /* Context while building a graph
62 */
63 struct GraphContext {
64 int nErr; /* Number of errors encountered */
65 int mxRail; /* Number of rails required to render the graph */
66 int iRailPitch; /* Pixels between rail centers */
67 GraphRow *pFirst; /* First row in the list */
68 GraphRow *pLast; /* Last row in the list */
69 int nBranch; /* Number of distinct branches */
70 char **azBranch; /* Names of the branches */
71 int nRow; /* Number of rows */
@@ -294,28 +293,27 @@
294 u = pParent->aiRiser[pParent->iRail];
295 if( u>=0 && u<pChild->idx ){
296 /* The thick arrow up to the next primary child of pDesc goes
297 ** further up than the thin merge arrow riser, so draw them both
298 ** on the same rail. */
299 pParent->mergeOut = pParent->iRail*4;
300 if( pParent->iRail<pChild->iRail ) pParent->mergeOut += 2;
301 pParent->mergeUpto = pChild->idx;
302 }else{
303 /* The thin merge arrow riser is taller than the thick primary
304 ** child riser, so use separate rails. */
305 int iTarget = pParent->iRail;
306 pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
307 0, iTarget)*4 + 1;
308 pParent->mergeUpto = pChild->idx;
309 mask = BIT(pParent->mergeOut/4);
310 for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
311 pLoop=pLoop->pNext){
312 pLoop->railInUse |= mask;
313 }
314 }
315 }
316 pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1;
317 }
318
319 /*
320 ** Compute the maximum rail number.
321 */
@@ -322,11 +320,11 @@
322 static void find_max_rail(GraphContext *p){
323 GraphRow *pRow;
324 p->mxRail = 0;
325 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
326 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
327 if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4;
328 while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>(BIT(p->mxRail+1)-1) ){
329 p->mxRail++;
330 }
331 }
332 }
@@ -540,11 +538,11 @@
540 if( pDesc==0 ){
541 /* Merge from a node that is off-screen */
542 int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
543 if( p->mxRail>=GR_MAX_RAIL ) return;
544 mask = BIT(iMrail);
545 pRow->mergeIn[iMrail] = 2;
546 pRow->mergeDown |= mask;
547 for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
548 pLoop->railInUse |= mask;
549 }
550 }else{
@@ -569,11 +567,11 @@
569 if( !pRow->isDup ) continue;
570 pRow->iRail = dupRail;
571 pDesc = hashFind(p, pRow->rid);
572 assert( pDesc!=0 && pDesc!=pRow );
573 createMergeRiser(p, pDesc, pRow);
574 if( pDesc->mergeOut/4>mxRail ) mxRail = pDesc->mergeOut/4;
575 }
576 if( dupRail<=mxRail ){
577 dupRail = mxRail+1;
578 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
579 if( pRow->isDup ) pRow->iRail = dupRail;
@@ -584,12 +582,7 @@
584
585 /*
586 ** Find the maximum rail number.
587 */
588 find_max_rail(p);
589 p->iRailPitch = atoi(PD("railpitch","0"));
590 if( p->iRailPitch<=0 ){
591 p->iRailPitch = 18 - (p->mxRail/3);
592 if( p->iRailPitch<11 ) p->iRailPitch = 11;
593 }
594 p->nErr = 0;
595 }
596
--- src/graph.c
+++ src/graph.c
@@ -47,11 +47,11 @@
47 u8 isDup; /* True if this is duplicate of a prior entry */
48 u8 isLeaf; /* True if this is a leaf node */
49 u8 timeWarp; /* Child is earlier in time */
50 u8 bDescender; /* True if riser from bottom of graph to here. */
51 i8 iRail; /* Which rail this check-in appears on. 0-based.*/
52 i8 mergeOut; /* Merge out to this rail. -1 if no merge-out */
53 u8 mergeIn[GR_MAX_RAIL]; /* Merge in from non-zero rails */
54 int aiRiser[GR_MAX_RAIL]; /* Risers from this node to a higher row. */
55 int mergeUpto; /* Draw the mergeOut rail up to this level */
56 u64 mergeDown; /* Draw merge lines up from bottom of graph */
57
@@ -61,11 +61,10 @@
61 /* Context while building a graph
62 */
63 struct GraphContext {
64 int nErr; /* Number of errors encountered */
65 int mxRail; /* Number of rails required to render the graph */
 
66 GraphRow *pFirst; /* First row in the list */
67 GraphRow *pLast; /* Last row in the list */
68 int nBranch; /* Number of distinct branches */
69 char **azBranch; /* Names of the branches */
70 int nRow; /* Number of rows */
@@ -294,28 +293,27 @@
293 u = pParent->aiRiser[pParent->iRail];
294 if( u>=0 && u<pChild->idx ){
295 /* The thick arrow up to the next primary child of pDesc goes
296 ** further up than the thin merge arrow riser, so draw them both
297 ** on the same rail. */
298 pParent->mergeOut = pParent->iRail;
 
299 pParent->mergeUpto = pChild->idx;
300 }else{
301 /* The thin merge arrow riser is taller than the thick primary
302 ** child riser, so use separate rails. */
303 int iTarget = pParent->iRail;
304 pParent->mergeOut = findFreeRail(p, pChild->idx, pParent->idx-1,
305 0, iTarget);
306 pParent->mergeUpto = pChild->idx;
307 mask = BIT(pParent->mergeOut);
308 for(pLoop=pChild->pNext; pLoop && pLoop->rid!=pParent->rid;
309 pLoop=pLoop->pNext){
310 pLoop->railInUse |= mask;
311 }
312 }
313 }
314 pChild->mergeIn[pParent->mergeOut] = 1;
315 }
316
317 /*
318 ** Compute the maximum rail number.
319 */
@@ -322,11 +320,11 @@
320 static void find_max_rail(GraphContext *p){
321 GraphRow *pRow;
322 p->mxRail = 0;
323 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
324 if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail;
325 if( pRow->mergeOut>p->mxRail ) p->mxRail = pRow->mergeOut;
326 while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>(BIT(p->mxRail+1)-1) ){
327 p->mxRail++;
328 }
329 }
330 }
@@ -540,11 +538,11 @@
538 if( pDesc==0 ){
539 /* Merge from a node that is off-screen */
540 int iMrail = findFreeRail(p, pRow->idx, p->nRow, 0, 0);
541 if( p->mxRail>=GR_MAX_RAIL ) return;
542 mask = BIT(iMrail);
543 pRow->mergeIn[iMrail] = 1;
544 pRow->mergeDown |= mask;
545 for(pLoop=pRow->pNext; pLoop; pLoop=pLoop->pNext){
546 pLoop->railInUse |= mask;
547 }
548 }else{
@@ -569,11 +567,11 @@
567 if( !pRow->isDup ) continue;
568 pRow->iRail = dupRail;
569 pDesc = hashFind(p, pRow->rid);
570 assert( pDesc!=0 && pDesc!=pRow );
571 createMergeRiser(p, pDesc, pRow);
572 if( pDesc->mergeOut>mxRail ) mxRail = pDesc->mergeOut;
573 }
574 if( dupRail<=mxRail ){
575 dupRail = mxRail+1;
576 for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
577 if( pRow->isDup ) pRow->iRail = dupRail;
@@ -584,12 +582,7 @@
582
583 /*
584 ** Find the maximum rail number.
585 */
586 find_max_rail(p);
 
 
 
 
 
587 p->nErr = 0;
588 }
589
--- src/skins.c
+++ src/skins.c
@@ -75,12 +75,10 @@
7575
*/
7676
static struct SkinDetail {
7777
const char *zName; /* Name of the detail */
7878
char *zValue; /* Value of the detail */
7979
} aSkinDetail[] = {
80
- { "timeline-arrowheads", "1" },
81
- { "timeline-circle-nodes", "0" },
8280
{ "timeline-color-graph-lines", "0" },
8381
{ "white-foreground", "0" },
8482
};
8583
8684
/*
8785
--- src/skins.c
+++ src/skins.c
@@ -75,12 +75,10 @@
75 */
76 static struct SkinDetail {
77 const char *zName; /* Name of the detail */
78 char *zValue; /* Value of the detail */
79 } aSkinDetail[] = {
80 { "timeline-arrowheads", "1" },
81 { "timeline-circle-nodes", "0" },
82 { "timeline-color-graph-lines", "0" },
83 { "white-foreground", "0" },
84 };
85
86 /*
87
--- src/skins.c
+++ src/skins.c
@@ -75,12 +75,10 @@
75 */
76 static struct SkinDetail {
77 const char *zName; /* Name of the detail */
78 char *zValue; /* Value of the detail */
79 } aSkinDetail[] = {
 
 
80 { "timeline-color-graph-lines", "0" },
81 { "white-foreground", "0" },
82 };
83
84 /*
85
+124 -15
--- src/style.c
+++ src/style.c
@@ -701,15 +701,108 @@
701701
@ vertical-align: top;
702702
@ text-align: right;
703703
@ white-space: nowrap;
704704
},
705705
{ "td.timelineGraph",
706
- "the format for the grap placeholder cells in timelines",
706
+ "the format for the graph placeholder cells in timelines",
707707
@ width: 20px;
708708
@ text-align: left;
709709
@ vertical-align: top;
710710
},
711
+ { ".tl-canvas",
712
+ "timeline graph canvas",
713
+ @ margin: 0 6px 0 10px;
714
+ },
715
+ { ".tl-rail",
716
+ "maximum rail spacing",
717
+ @ width: 18px;
718
+ },
719
+ { ".tl-mergeoffset",
720
+ "maximum spacing between merge risers and primary child risers",
721
+ @ width: 2px;
722
+ },
723
+ { ".tl-nodemark",
724
+ "adjusts the vertical position of graph nodes",
725
+ @ margin-top: 5px;
726
+ },
727
+ { ".tl-node",
728
+ "commit node",
729
+ @ width: 10px;
730
+ @ height: 10px;
731
+ @ border: 1px solid #000;
732
+ @ background: #fff;
733
+ @ cursor: pointer;
734
+ },
735
+ { ".tl-node.leaf:after",
736
+ "leaf commit marker",
737
+ @ content: '';
738
+ @ position: absolute;
739
+ @ top: 3px;
740
+ @ left: 3px;
741
+ @ width: 4px;
742
+ @ height: 4px;
743
+ @ background: #000;
744
+ },
745
+ { ".tl-node.sel:after",
746
+ "selected commit node marker",
747
+ @ content: '';
748
+ @ position: absolute;
749
+ @ top: 2px;
750
+ @ left: 2px;
751
+ @ width: 6px;
752
+ @ height: 6px;
753
+ @ background: red;
754
+ },
755
+ { ".tl-arrow",
756
+ "arrow",
757
+ @ width: 0;
758
+ @ height: 0;
759
+ @ transform: scale(.999);
760
+ @ border: 0 solid transparent;
761
+ },
762
+ { ".tl-arrow.u",
763
+ "up arrow",
764
+ @ margin-top: -1px;
765
+ @ border-width: 0 3px;
766
+ @ border-bottom: 7px solid #000;
767
+ },
768
+ { ".tl-arrow.u.sm",
769
+ "small up arrow",
770
+ @ border-bottom: 5px solid #000;
771
+ },
772
+ { ".tl-line",
773
+ "line",
774
+ @ background: #000;
775
+ @ width: 2px;
776
+ },
777
+ { ".tl-arrow.merge",
778
+ "merge arrow",
779
+ @ height: 1px;
780
+ @ border-width: 2px 0;
781
+ },
782
+ { ".tl-arrow.merge.l",
783
+ "left merge arrow",
784
+ @ border-right: 3px solid #000;
785
+ },
786
+ { ".tl-arrow.merge.r",
787
+ "right merge arrow",
788
+ @ border-left: 3px solid #000;
789
+ },
790
+ { ".tl-line.merge",
791
+ "merge line",
792
+ @ width: 1px;
793
+ },
794
+ { ".tl-arrow.warp",
795
+ "timewarp arrow",
796
+ @ margin-left: 1px;
797
+ @ border-width: 3px 0;
798
+ @ border-left: 7px solid #600000;
799
+ },
800
+ { ".tl-line.warp",
801
+ "timewarp line",
802
+ @ background: #600000;
803
+ },
711804
{ "a.tagLink",
712805
"the format for the tag links",
713806
@
714807
},
715808
{ "span.tagDsp",
@@ -1226,14 +1319,10 @@
12261319
},
12271320
{ "#usetupEditCapability",
12281321
"format for capabilities string, mentioned on the user edit page",
12291322
@ font-weight: bold;
12301323
},
1231
- { "#canvas", "timeline graph node colors",
1232
- @ color: black;
1233
- @ background-color: white;
1234
- },
12351324
{ "table.adminLogTable",
12361325
"Class for the /admin_log table",
12371326
@ text-align: left;
12381327
},
12391328
{ ".adminLogTable .adminTime",
@@ -1336,30 +1425,50 @@
13361425
}
13371426
}
13381427
}
13391428
13401429
/*
1341
-** Search string zHaystack for zNeedle. zNeedle must be an isolated
1342
-** word with space or punctuation on either size.
1430
+** Search string zCss for zSelector.
13431431
**
13441432
** Return true if found. Return false if not found
13451433
*/
1346
-static int containsString(const char *zHaystack, const char *zNeedle){
1434
+static int containsSelector(const char *zCss, const char *zSelector){
13471435
char *z;
13481436
int n;
1437
+ int selectorLen = (int)strlen(zSelector);
13491438
1350
- while( zHaystack[0] ){
1351
- z = strstr(zHaystack, zNeedle);
1439
+ for( z=zCss; *z; z+=selectorLen ){
1440
+ z = strstr(z, zSelector);
13521441
if( z==0 ) return 0;
1353
- n = (int)strlen(zNeedle);
1354
- if( (z==zHaystack || !fossil_isalnum(z[-1])) && !fossil_isalnum(z[n]) ){
1355
- return 1;
1442
+ if( z!=zCss ){
1443
+ for( n=-1; z+n!=zCss && fossil_isspace(z[n]); n--);
1444
+ if( z+n!=zCss && z[n]!=',' && z[n]!= '}' && z[n]!='/' ) continue;
13561445
}
1357
- zHaystack = z + n;
1446
+ for( n=selectorLen; z[n] && fossil_isspace(z[n]); n++ );
1447
+ if( z[n]==',' || z[n]=='{' || z[n]=='/' ) return 1;
13581448
}
13591449
return 0;
13601450
}
1451
+
1452
+/*
1453
+** COMMAND: test-contains-selector
1454
+**
1455
+** Usage: %fossil test-contains-selector FILENAME SELECTOR
1456
+**
1457
+** Determine if the CSS stylesheet FILENAME contains SELECTOR.
1458
+*/
1459
+void contains_selector_cmd(void){
1460
+ int found;
1461
+ char *zSelector;
1462
+ Blob css;
1463
+ if( g.argc!=4 ) usage("FILENAME SELECTOR");
1464
+ blob_read_from_file(&css, g.argv[2]);
1465
+ zSelector = g.argv[3];
1466
+ found = containsSelector(blob_str(&css), zSelector);
1467
+ fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
1468
+ blob_reset(&css);
1469
+}
13611470
13621471
13631472
/*
13641473
** WEBPAGE: style.css
13651474
**
@@ -1373,11 +1482,11 @@
13731482
blob_init(&css,skin_get("css"),-1);
13741483
13751484
/* add special missing definitions */
13761485
for(i=1; cssDefaultList[i].elementClass; i++){
13771486
char *z = blob_str(&css);
1378
- if( !containsString(z, cssDefaultList[i].elementClass) ){
1487
+ if( !containsSelector(z, cssDefaultList[i].elementClass) ){
13791488
blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
13801489
cssDefaultList[i].comment,
13811490
cssDefaultList[i].elementClass,
13821491
cssDefaultList[i].value);
13831492
}
13841493
--- src/style.c
+++ src/style.c
@@ -701,15 +701,108 @@
701 @ vertical-align: top;
702 @ text-align: right;
703 @ white-space: nowrap;
704 },
705 { "td.timelineGraph",
706 "the format for the grap placeholder cells in timelines",
707 @ width: 20px;
708 @ text-align: left;
709 @ vertical-align: top;
710 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
711 { "a.tagLink",
712 "the format for the tag links",
713 @
714 },
715 { "span.tagDsp",
@@ -1226,14 +1319,10 @@
1226 },
1227 { "#usetupEditCapability",
1228 "format for capabilities string, mentioned on the user edit page",
1229 @ font-weight: bold;
1230 },
1231 { "#canvas", "timeline graph node colors",
1232 @ color: black;
1233 @ background-color: white;
1234 },
1235 { "table.adminLogTable",
1236 "Class for the /admin_log table",
1237 @ text-align: left;
1238 },
1239 { ".adminLogTable .adminTime",
@@ -1336,30 +1425,50 @@
1336 }
1337 }
1338 }
1339
1340 /*
1341 ** Search string zHaystack for zNeedle. zNeedle must be an isolated
1342 ** word with space or punctuation on either size.
1343 **
1344 ** Return true if found. Return false if not found
1345 */
1346 static int containsString(const char *zHaystack, const char *zNeedle){
1347 char *z;
1348 int n;
 
1349
1350 while( zHaystack[0] ){
1351 z = strstr(zHaystack, zNeedle);
1352 if( z==0 ) return 0;
1353 n = (int)strlen(zNeedle);
1354 if( (z==zHaystack || !fossil_isalnum(z[-1])) && !fossil_isalnum(z[n]) ){
1355 return 1;
1356 }
1357 zHaystack = z + n;
 
1358 }
1359 return 0;
1360 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1361
1362
1363 /*
1364 ** WEBPAGE: style.css
1365 **
@@ -1373,11 +1482,11 @@
1373 blob_init(&css,skin_get("css"),-1);
1374
1375 /* add special missing definitions */
1376 for(i=1; cssDefaultList[i].elementClass; i++){
1377 char *z = blob_str(&css);
1378 if( !containsString(z, cssDefaultList[i].elementClass) ){
1379 blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
1380 cssDefaultList[i].comment,
1381 cssDefaultList[i].elementClass,
1382 cssDefaultList[i].value);
1383 }
1384
--- src/style.c
+++ src/style.c
@@ -701,15 +701,108 @@
701 @ vertical-align: top;
702 @ text-align: right;
703 @ white-space: nowrap;
704 },
705 { "td.timelineGraph",
706 "the format for the graph placeholder cells in timelines",
707 @ width: 20px;
708 @ text-align: left;
709 @ vertical-align: top;
710 },
711 { ".tl-canvas",
712 "timeline graph canvas",
713 @ margin: 0 6px 0 10px;
714 },
715 { ".tl-rail",
716 "maximum rail spacing",
717 @ width: 18px;
718 },
719 { ".tl-mergeoffset",
720 "maximum spacing between merge risers and primary child risers",
721 @ width: 2px;
722 },
723 { ".tl-nodemark",
724 "adjusts the vertical position of graph nodes",
725 @ margin-top: 5px;
726 },
727 { ".tl-node",
728 "commit node",
729 @ width: 10px;
730 @ height: 10px;
731 @ border: 1px solid #000;
732 @ background: #fff;
733 @ cursor: pointer;
734 },
735 { ".tl-node.leaf:after",
736 "leaf commit marker",
737 @ content: '';
738 @ position: absolute;
739 @ top: 3px;
740 @ left: 3px;
741 @ width: 4px;
742 @ height: 4px;
743 @ background: #000;
744 },
745 { ".tl-node.sel:after",
746 "selected commit node marker",
747 @ content: '';
748 @ position: absolute;
749 @ top: 2px;
750 @ left: 2px;
751 @ width: 6px;
752 @ height: 6px;
753 @ background: red;
754 },
755 { ".tl-arrow",
756 "arrow",
757 @ width: 0;
758 @ height: 0;
759 @ transform: scale(.999);
760 @ border: 0 solid transparent;
761 },
762 { ".tl-arrow.u",
763 "up arrow",
764 @ margin-top: -1px;
765 @ border-width: 0 3px;
766 @ border-bottom: 7px solid #000;
767 },
768 { ".tl-arrow.u.sm",
769 "small up arrow",
770 @ border-bottom: 5px solid #000;
771 },
772 { ".tl-line",
773 "line",
774 @ background: #000;
775 @ width: 2px;
776 },
777 { ".tl-arrow.merge",
778 "merge arrow",
779 @ height: 1px;
780 @ border-width: 2px 0;
781 },
782 { ".tl-arrow.merge.l",
783 "left merge arrow",
784 @ border-right: 3px solid #000;
785 },
786 { ".tl-arrow.merge.r",
787 "right merge arrow",
788 @ border-left: 3px solid #000;
789 },
790 { ".tl-line.merge",
791 "merge line",
792 @ width: 1px;
793 },
794 { ".tl-arrow.warp",
795 "timewarp arrow",
796 @ margin-left: 1px;
797 @ border-width: 3px 0;
798 @ border-left: 7px solid #600000;
799 },
800 { ".tl-line.warp",
801 "timewarp line",
802 @ background: #600000;
803 },
804 { "a.tagLink",
805 "the format for the tag links",
806 @
807 },
808 { "span.tagDsp",
@@ -1226,14 +1319,10 @@
1319 },
1320 { "#usetupEditCapability",
1321 "format for capabilities string, mentioned on the user edit page",
1322 @ font-weight: bold;
1323 },
 
 
 
 
1324 { "table.adminLogTable",
1325 "Class for the /admin_log table",
1326 @ text-align: left;
1327 },
1328 { ".adminLogTable .adminTime",
@@ -1336,30 +1425,50 @@
1425 }
1426 }
1427 }
1428
1429 /*
1430 ** Search string zCss for zSelector.
 
1431 **
1432 ** Return true if found. Return false if not found
1433 */
1434 static int containsSelector(const char *zCss, const char *zSelector){
1435 char *z;
1436 int n;
1437 int selectorLen = (int)strlen(zSelector);
1438
1439 for( z=zCss; *z; z+=selectorLen ){
1440 z = strstr(z, zSelector);
1441 if( z==0 ) return 0;
1442 if( z!=zCss ){
1443 for( n=-1; z+n!=zCss && fossil_isspace(z[n]); n--);
1444 if( z+n!=zCss && z[n]!=',' && z[n]!= '}' && z[n]!='/' ) continue;
1445 }
1446 for( n=selectorLen; z[n] && fossil_isspace(z[n]); n++ );
1447 if( z[n]==',' || z[n]=='{' || z[n]=='/' ) return 1;
1448 }
1449 return 0;
1450 }
1451
1452 /*
1453 ** COMMAND: test-contains-selector
1454 **
1455 ** Usage: %fossil test-contains-selector FILENAME SELECTOR
1456 **
1457 ** Determine if the CSS stylesheet FILENAME contains SELECTOR.
1458 */
1459 void contains_selector_cmd(void){
1460 int found;
1461 char *zSelector;
1462 Blob css;
1463 if( g.argc!=4 ) usage("FILENAME SELECTOR");
1464 blob_read_from_file(&css, g.argv[2]);
1465 zSelector = g.argv[3];
1466 found = containsSelector(blob_str(&css), zSelector);
1467 fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
1468 blob_reset(&css);
1469 }
1470
1471
1472 /*
1473 ** WEBPAGE: style.css
1474 **
@@ -1373,11 +1482,11 @@
1482 blob_init(&css,skin_get("css"),-1);
1483
1484 /* add special missing definitions */
1485 for(i=1; cssDefaultList[i].elementClass; i++){
1486 char *z = blob_str(&css);
1487 if( !containsSelector(z, cssDefaultList[i].elementClass) ){
1488 blob_appendf(&css, "/* %s */\n%s {\n%s}\n",
1489 cssDefaultList[i].comment,
1490 cssDefaultList[i].elementClass,
1491 cssDefaultList[i].value);
1492 }
1493
+229 -276
--- src/timeline.c
+++ src/timeline.c
@@ -241,23 +241,17 @@
241241
dateFormat = db_get_int("timeline-date-format", 0);
242242
zDateFmt = P("datefmt");
243243
if( zDateFmt ) dateFormat = atoi(zDateFmt);
244244
if( tmFlags & TIMELINE_GRAPH ){
245245
pGraph = graph_init();
246
- /* style is not moved to css, because this is
247
- ** a technical div for the timeline graph
248
- */
249
- @ <div id="canvas" style="position:relative;height:0px;width:0px;"
250
- @ onclick="clickOnGraph(event)"></div>
251246
}
252247
db_static_prepare(&qbranch,
253248
"SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
254249
TAG_BRANCH
255250
);
256251
257
- @ <table id="timelineTable" class="timelineTable"
258
- @ onclick="clickOnGraph(event)">
252
+ @ <table id="timelineTable" class="timelineTable">
259253
blob_zero(&comment);
260254
while( db_step(pQuery)==SQLITE_ROW ){
261255
int rid = db_column_int(pQuery, 0);
262256
const char *zUuid = db_column_text(pQuery, 1);
263257
int isLeaf = db_column_int(pQuery, 5);
@@ -391,11 +385,11 @@
391385
}
392386
db_reset(&qparent);
393387
gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
394388
zUuid, isLeaf);
395389
db_reset(&qbranch);
396
- @ <div id="m%d(gidx)"></div>
390
+ @ <div id="m%d(gidx)" class="tl-nodemark"></div>
397391
}
398392
@</td>
399393
if( zBgClr && zBgClr[0] && rid!=selectedRid ){
400394
@ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
401395
}else{
@@ -589,18 +583,11 @@
589583
graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
590584
if( pGraph->nErr ){
591585
graph_free(pGraph);
592586
pGraph = 0;
593587
}else{
594
- int w;
595
- /* style is not moved to css, because this is
596
- ** a technical div for the timeline graph
597
- */
598
- w = pGraph->mxRail*pGraph->iRailPitch + 28;
599
- @ <tr class="timelineBottom"><td></td><td>
600
- @ <div id="grbtm" style="width:%d(w)px;"></div>
601
- @ </td><td></td></tr>
588
+ @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
602589
}
603590
}
604591
@ </table>
605592
if( fchngQueryInit ) db_finalize(&fchngQuery);
606593
timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0, 0);
@@ -648,31 +635,18 @@
648635
){
649636
if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
650637
GraphRow *pRow;
651638
int i;
652639
char cSep;
653
- int mergeOffset; /* Pixel offset from rail to merge riser */
654640
int iRailPitch; /* Pixels between consecutive rails */
655
- int showArrowheads; /* True to draw arrowheads. False to omit. */
656
- int circleNodes; /* True for circle nodes. False for square nodes */
657641
int colorGraph; /* Use colors for graph lines */
658642
659
- iRailPitch = pGraph->iRailPitch;
660
- showArrowheads = skin_detail_boolean("timeline-arrowheads");
661
- circleNodes = skin_detail_boolean("timeline-circle-nodes");
643
+ iRailPitch = atoi(PD("railpitch","0"));
662644
colorGraph = skin_detail_boolean("timeline-color-graph-lines");
663645
664
- /* Number of pixels that the thin merge lines are offset from the
665
- ** the center of the think rail lines. If zero, then the vertical
666
- ** merge lines overlap with the thicker rail lines.
667
- */
668
- mergeOffset = iRailPitch>=14 ? 4 : iRailPitch>=13 ? 3 : 0;
669
- if( PB("nomo") ) mergeOffset = 0;
670
-
671
- @ <script>
672
- @ var railPitch=%d(iRailPitch);
673
-
646
+ @ <script>(function(){
647
+ @ "use strict";
674648
/* the rowinfo[] array contains all the information needed to generate
675649
** the graph. Each entry contains information for a single row:
676650
**
677651
** id: The id of the <div> element for the row. This is an integer.
678652
** to get an actual id, prepend "m" to the integer. The top node
@@ -680,13 +654,13 @@
680654
** bg: The background color for this row
681655
** r: The "rail" that the node for this row sits on. The left-most
682656
** rail is 0 and the number increases to the right.
683657
** d: True if there is a "descender" - an arrow coming from the bottom
684658
** of the page straight up to this node.
685
- ** mo: "merge-out". If non-zero, this is one more than the x-coordinate
659
+ ** mo: "merge-out". If non-negative, this is the rail position
686660
** for the upward portion of a merge arrow. The merge arrow goes up
687
- ** to the row identified by mu:. If this value is zero then
661
+ ** to the row identified by mu:. If this value is negative then
688662
** node has no merge children and no merge-out line is drawn.
689663
** mu: The id of the row which is the top of the merge-out arrow.
690664
** u: Draw a thick child-line out of the top of this node and up to
691665
** the node with an id equal to this value. 0 if it is straight to
692666
** the top of the page, -1 if there is no thick-line riser.
@@ -693,37 +667,25 @@
693667
** f: 0x01: a leaf node.
694668
** au: An array of integers that define thick-line risers for branches.
695669
** The integers are in pairs. For each pair, the first integer is
696670
** is the rail on which the riser should run and the second integer
697671
** is the id of the node upto which the riser should run.
698
- ** mi: "merge-in". An array of integer x-coordinates from which
672
+ ** mi: "merge-in". An array of integer rail positions from which
699673
** merge arrows should be drawn into this node. If the value is
700
- ** negative, then the x-coordinate is the absolute value of mi[]
674
+ ** negative, then the rail position is the absolute value of mi[]
701675
** and a thin merge-arrow descender is drawn to the bottom of
702676
** the screen.
703677
** h: The SHA1 hash of the object being graphed
704678
*/
705679
cgi_printf("var rowinfo = [\n");
706680
for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
707
- int mo = pRow->mergeOut;
708
- if( mo<0 ){
709
- mo = 0;
710
- }else{
711
- int x = (mo/4)*iRailPitch;
712
- switch( mo&3 ){
713
- case 0: x -= mergeOffset-2; break;
714
- case 1: x += 1; break;
715
- case 2: x += mergeOffset+1; break;
716
- }
717
- mo = x;
718
- }
719681
cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
720682
pRow->idx, /* id */
721683
pRow->zBgClr, /* bg */
722684
pRow->iRail, /* r */
723685
pRow->bDescender, /* d */
724
- mo, /* mo */
686
+ pRow->mergeOut, /* mo */
725687
pRow->mergeUpto, /* mu */
726688
pRow->aiRiser[pRow->iRail], /* u */
727689
pRow->isLeaf ? 1 : 0 /* f */
728690
);
729691
/* u */
@@ -743,13 +705,11 @@
743705
/* mi */
744706
cgi_printf("mi:");
745707
cSep = '[';
746708
for(i=0; i<GR_MAX_RAIL; i++){
747709
if( pRow->mergeIn[i] ){
748
- int mi = i*iRailPitch;
749
- if( pRow->mergeIn[i]==1 ) mi -= mergeOffset-1;
750
- if( pRow->mergeIn[i]==3 ) mi += mergeOffset;
710
+ int mi = i;
751711
if( pRow->mergeDown & (1<<i) ) mi = -mi;
752712
cgi_printf("%c%d", cSep, mi);
753713
cSep = ',';
754714
}
755715
}
@@ -756,246 +716,238 @@
756716
if( cSep=='[' ) cgi_printf("[");
757717
cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
758718
}
759719
cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
760720
graph_free(pGraph);
761
- @ var cDiv = gebi("canvas");
762
- @ var csty = window.getComputedStyle && window.getComputedStyle(cDiv,null);
763
- @ var lineClr = (csty && csty.getPropertyValue('color')) || 'black';
764
- @ var bgClr = (csty && csty.getPropertyValue('background-color')) ||'white';
765
- @ if( bgClr=='transparent' ) bgClr = 'white';
766
- @ var boxColor = lineClr;
767
- @ function drawBox(color,x0,y0,x1,y1){
721
+ @ var canvasDiv;
722
+ @ var railPitch;
723
+ @ var mergeOffset;
724
+ @ var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine;
725
+ @ function initGraph(){
726
+ @ var parent = gebi("timelineTable").rows[0].cells[1];
727
+ @ parent.style.verticalAlign = "top";
728
+ @ canvasDiv = document.createElement("div");
729
+ @ canvasDiv.className = "tl-canvas";
730
+ @ canvasDiv.style.position = "absolute";
731
+ @ parent.appendChild(canvasDiv);
732
+ @
733
+ @ var elems = {};
734
+ @ var elemClasses = [
735
+ @ "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
736
+ @ "arrow merge r", "line merge", "arrow warp", "line warp"
737
+ @ ];
738
+ @ for( var i=0; i<elemClasses.length; i++ ){
739
+ @ var cls = elemClasses[i];
740
+ @ var elem = document.createElement("div");
741
+ @ elem.className = "tl-" + cls;
742
+ @ if( cls.indexOf("line")==0 ) elem.className += " v";
743
+ @ canvasDiv.appendChild(elem);
744
+ @ var k = cls.replace(/\s/g, "_");
745
+ @ var r = elem.getBoundingClientRect();
746
+ @ var w = Math.ceil(r.right - r.left);
747
+ @ var h = Math.ceil(r.bottom - r.top);
748
+ @ elems[k] = {w: w, h: h, cls: cls};
749
+ @ }
750
+ @ node = elems.node;
751
+ @ arrow = elems.arrow_u;
752
+ @ arrowSmall = elems.arrow_u_sm;
753
+ @ line = elems.line;
754
+ @ mArrow = elems.arrow_merge_r;
755
+ @ mLine = elems.line_merge;
756
+ @ wArrow = elems.arrow_warp;
757
+ @ wLine = elems.line_warp;
758
+ @
759
+ @ var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
760
+ if( iRailPitch ){
761
+ @ railPitch = %d(iRailPitch);
762
+ }else{
763
+ @ railPitch = elems.rail.w;
764
+ @ railPitch -= Math.floor((nrail-1)*(railPitch-minRailPitch)/21);
765
+ }
766
+ @ railPitch = Math.max(railPitch, minRailPitch);
767
+ @
768
+ if( PB("nomo") ){
769
+ @ mergeOffset = 0;
770
+ }else{
771
+ @ mergeOffset = railPitch-minRailPitch-mLine.w;
772
+ @ mergeOffset = Math.min(mergeOffset, elems.mergeoffset.w);
773
+ @ mergeOffset = mergeOffset>0 ? mergeOffset + line.w/2 : 0;
774
+ }
775
+ @
776
+ @ var canvasWidth = (nrail-1)*railPitch + node.w;
777
+ @ canvasDiv.style.width = canvasWidth + "px";
778
+ @ canvasDiv.style.position = "relative";
779
+ @ }
780
+ @ function drawBox(cls,color,x0,y0,x1,y1){
768781
@ var n = document.createElement("div");
782
+ @ x0 = Math.floor(x0);
783
+ @ y0 = Math.floor(y0);
784
+ @ x1 = x1 || x1===0 ? Math.floor(x1) : x0;
785
+ @ y1 = y1 || y1===0 ? Math.floor(y1) : y0;
769786
@ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
770787
@ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
771
- @ var w = x1-x0+1;
772
- @ var h = y1-y0+1;
788
+ @ var w = x1-x0;
789
+ @ var h = y1-y0;
773790
@ n.style.position = "absolute";
774
- @ n.style.overflow = "hidden";
775791
@ n.style.left = x0+"px";
776792
@ n.style.top = y0+"px";
777
- @ n.style.width = w+"px";
778
- @ n.style.height = h+"px";
779
- @ n.style.backgroundColor = color;
780
- @ cDiv.appendChild(n);
793
+ @ if( w ) n.style.width = w+"px";
794
+ @ if( h ) n.style.height = h+"px";
795
+ @ if( color ) n.style.backgroundColor = color;
796
+ @ n.className = "tl-"+cls;
797
+ @ canvasDiv.appendChild(n);
781798
@ return n;
782799
@ }
783
- @ function absoluteY(id){
784
- @ var obj = gebi(id);
785
- @ if( !obj ) return;
800
+ @ function absoluteY(obj){
786801
@ var top = 0;
787802
@ if( obj.offsetParent ){
788803
@ do{
789804
@ top += obj.offsetTop;
790805
@ }while( obj = obj.offsetParent );
791806
@ }
792807
@ return top;
793808
@ }
794
- @ function absoluteX(id){
795
- @ var obj = gebi(id);
796
- @ if( !obj ) return;
797
- @ var left = 0;
798
- @ if( obj.offsetParent ){
799
- @ do{
800
- @ left += obj.offsetLeft;
801
- @ }while( obj = obj.offsetParent );
802
- @ }
803
- @ return left;
804
- @ }
805
- if( showArrowheads ){
806
- @ function drawUpArrow(x,y0,y1,clr){
807
- @ drawBox(clr,x,y0+4,x+1,y1);
808
- @ var n = document.createElement("div"),
809
- @ l = x-2,
810
- @ t = y0;
811
- @ n.style.position = "absolute";
812
- @ n.style.left = l+"px";
813
- @ n.style.top = t+"px";
814
- @ n.style.width = 0;
815
- @ n.style.height = 0;
816
- @ n.style.transform = "scale(.999)";
817
- @ n.style.borderWidth = 0;
818
- @ n.style.borderStyle = "solid";
819
- @ n.style.borderColor = "transparent";
820
- @ n.style.borderRightWidth = "3px";
821
- @ n.style.borderBottomColor = clr;
822
- @ n.style.borderLeftWidth = "3px";
823
- @ if( y0+10>=y1 ){
824
- @ n.style.borderBottomWidth = "5px";
825
- @ } else {
826
- @ n.style.borderBottomWidth = "7px";
827
- @ }
828
- @ cDiv.appendChild(n);
829
- @ }
830
- }else{
831
- @ function drawUpArrow(x,y0,y1,clr){
832
- @ drawBox(clr,x,y0+1,x+1,y1);
833
- @ }
834
- }
835
- @ function drawThinArrow(y,xFrom,xTo){
836
- @ var n = document.createElement("div"),
837
- @ t = y-2;
838
- @ n.style.position = "absolute";
839
- @ n.style.top = t+"px";
840
- @ n.style.width = 0;
841
- @ n.style.height = "1px";
842
- @ n.style.transform = "scale(.999)";
843
- @ n.style.borderWidth = 0;
844
- @ n.style.borderStyle = "solid";
845
- @ n.style.borderColor = "transparent";
846
- @ n.style.borderTopWidth = "2px";
847
- @ n.style.borderBottomWidth = "2px";
848
- @ if( xFrom<xTo ){
849
- @ drawBox(lineClr,xFrom,y,xTo-3,y);
850
- @ n.style.left = xTo-3+"px";
851
- @ n.style.borderLeftWidth = "3px";
852
- @ n.style.borderLeftColor = lineClr;
853
- @ }else{
854
- @ drawBox(lineClr,xTo+3,y,xFrom,y);
855
- @ n.style.left = xTo+1+"px";
856
- @ n.style.borderRightWidth = "3px";
857
- @ n.style.borderRightColor = lineClr;
858
- @ }
859
- @ cDiv.appendChild(n);
860
- @ }
861
- @ function drawThinLine(x0,y0,x1,y1){
862
- @ drawBox(lineClr,x0,y0,x1,y1);
863
- @ }
864
- @ function drawNodeBox(color,x0,y0,x1,y1){
865
- @ var n = drawBox(color,x0,y0,x1,y1);
866
- @ n.style.cursor = "pointer";
867
- if( circleNodes ){
868
- @ n.style.borderRadius = "6px";
869
- }
870
- @ }
871
- @ function drawNode(p, left, btm){
872
- @ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6);
873
- @ drawNodeBox(p.bg||bgClr,p.x-4,p.y-4,p.x+5,p.y+5);
874
- @ if( p.u>0 ) drawUpArrow(p.x,rowinfo[p.u-1].y+6,p.y-6,p.fg||lineClr);
875
- @ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2);
876
- if( !omitDescenders ){
877
- @ if( p.u==0 ) drawUpArrow(p.x,0,p.y-6,p.fg||lineClr);
878
- @ if( p.d ) drawUpArrow(p.x,p.y+6,btm,p.fg||lineClr);
879
- }
880
- @ if( p.mo>0 ){
881
- @ var x1 = p.mo + left - 1;
882
- @ var y1 = p.y-3;
883
- @ var x0 = x1>p.x ? p.x+7 : p.x-6;
884
- @ var u = rowinfo[p.mu-1];
885
- @ var y0 = u.y+5;
886
- @ if( x1>=p.x-5 && x1<=p.x+5 ){
887
- @ y1 = p.y-5;
888
- @ }else{
889
- @ drawThinLine(x0,y1,x1,y1);
890
- @ }
891
- if( mergeOffset==0 ) cgi_printf("if( p.mo!=p.u-1 ) ");
892
- @ drawThinLine(x1,y0,x1,y1);
893
- @ }
894
- @ var n = p.au.length;
895
- @ for(var i=0; i<n; i+=2){
896
- @ var x1 = p.au[i]*railPitch + left;
897
- @ var x0 = x1>p.x ? p.x+7 : p.x-6;
898
- @ var u = rowinfo[p.au[i+1]-1];
899
- @ if(u.id<p.id){
900
- @ drawBox(u.fg||lineClr,x0,p.y,x1+1,p.y+1);
901
- @ drawUpArrow(x1,u.y+6,p.y,u.fg||lineClr);
902
- @ }else{
903
- @ drawBox("#600000",x0,p.y,x1,p.y+1);
904
- @ drawBox("#600000",x1-1,p.y,x1,u.y+1);
905
- @ drawBox("#600000",x1,u.y,u.x-10,u.y+1);
906
- @ var n = document.createElement("div"),
907
- @ t = u.y-2,
908
- @ l = u.x-11;
909
- @ n.style.position = "absolute";
910
- @ n.style.top = t+"px";
911
- @ n.style.left = l+"px";
912
- @ n.style.width = 0;
913
- @ n.style.height = 0;
914
- @ n.style.transform = "scale(.999)";
915
- @ n.style.borderWidth = 0;
916
- @ n.style.borderStyle = "solid";
917
- @ n.style.borderColor = "transparent";
918
- @ n.style.borderTopWidth = "3px";
919
- @ n.style.borderBottomWidth = "3px";
920
- @ n.style.borderLeftWidth = "7px";
921
- @ n.style.borderLeftColor = "#600000";
922
- @ cDiv.appendChild(n);
923
- @ }
924
- @ }
925
- @ for(var j in p.mi){
926
- @ var y0 = p.y+5;
927
- @ var mx = p.mi[j];
928
- @ if( mx<0 ){
929
- @ mx = left-mx;
930
- @ drawThinLine(mx,y0,mx,btm);
931
- @ }else{
932
- @ mx += left;
933
- @ }
934
- @ if( mx>p.x ){
935
- @ drawThinArrow(y0,mx,p.x+6);
936
- @ }else{
937
- @ drawThinArrow(y0,mx,p.x-5);
938
- @ }
939
- @ }
940
- @ }
941
- @ var selBox = null;
942
- @ var selRow = null;
943
- @ function renderGraph(){
944
- @ var canvasDiv = gebi("canvas");
945
- @ while( canvasDiv.hasChildNodes() ){
946
- @ canvasDiv.removeChild(canvasDiv.firstChild);
947
- @ }
948
- @ var canvasY = absoluteY("timelineTable");
949
- @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
950
- @ for(var i in rowinfo){
951
- @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
952
- @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
953
- @ }
954
- @ var btm = absoluteY("grbtm") + 10 - canvasY;
955
- @ for(var i in rowinfo){
956
- @ drawNode(rowinfo[i], left, btm);
957
- @ }
958
- @ if( selRow!=null ) clickOnRow(selRow);
959
- @ }
960
- @ function clickOnGraph(event){
961
- @ var x=event.clientX-absoluteX("canvas");
962
- @ var y=event.clientY-absoluteY("canvas");
963
- @ if(window.pageXOffset!=null){
964
- @ x += window.pageXOffset;
965
- @ y += window.pageYOffset;
966
- @ }else{
967
- @ var d = window.document.documentElement;
968
- @ if(document.compatMode!="CSS1Compat") d = d.body;
969
- @ x += d.scrollLeft;
970
- @ y += d.scrollTop;
971
- @ }
972
- if( P("clicktest")!=0 ){
973
- @ alert("click at "+x+","+y)
974
- }
975
- @ for(var i in rowinfo){
976
- @ p = rowinfo[i];
977
- @ if( p.y<y-11 ) continue;
978
- @ if( p.y>y+9 ) break;
979
- @ if( p.x>x-11 && p.x<x+9 ){
980
- @ clickOnRow(p);
981
- @ break;
982
- @ }
983
- @ }
984
- @ }
985
- @ function clickOnRow(p){
986
- @ if( selRow==null ){
987
- @ selBox = drawBox("red",p.x-2,p.y-2,p.x+3,p.y+3);
988
- if( circleNodes ){
989
- @ selBox.style.borderRadius="6px";
990
- }
991
- @ selRow = p;
992
- @ }else if( selRow==p ){
993
- @ var canvasDiv = gebi("canvas");
994
- @ canvasDiv.removeChild(selBox);
995
- @ selBox = null;
996
- @ selRow = null;
809
+ @ function miLineY(p){
810
+ @ return p.y + node.h - mLine.w - 1;
811
+ @ }
812
+ @ function drawLine(elem,color,x0,y0,x1,y1){
813
+ @ var cls = elem.cls + " ";
814
+ @ if( x1===null ){
815
+ @ x1 = x0+elem.w;
816
+ @ cls += "v";
817
+ @ }else{
818
+ @ y1 = y0+elem.w;
819
+ @ cls += "h";
820
+ @ }
821
+ @ drawBox(cls,color,x0,y0,x1,y1);
822
+ @ }
823
+ @ function drawUpArrow(from,to,color){
824
+ @ var y = to.y + node.h;
825
+ @ var arrowSpace = from.y - y + (!from.id || from.r!=to.r ? node.h/2 : 0);
826
+ @ var arw = arrowSpace < arrow.h*1.5 ? arrowSmall : arrow;
827
+ @ var x = to.x + (node.w-line.w)/2;
828
+ @ var y0 = from.y + node.h/2;
829
+ @ var y1 = Math.ceil(to.y + node.h + arw.h/2);
830
+ @ drawLine(line,color,x,y0,null,y1);
831
+ @ x = to.x + (node.w-arw.w)/2;
832
+ @ var n = drawBox(arw.cls,null,x,y);
833
+ @ n.style.borderBottomColor = color;
834
+ @ }
835
+ @ function drawMergeLine(x0,y0,x1,y1){
836
+ @ drawLine(mLine,null,x0,y0,x1,y1);
837
+ @ }
838
+ @ function drawMergeArrow(p,rail){
839
+ @ var x0 = rail*railPitch + node.w/2;
840
+ @ if( rail in mergeLines ){
841
+ @ x0 += mergeLines[rail];
842
+ @ if( p.r<rail ) x0 += mLine.w;
843
+ @ }else{
844
+ @ x0 += (p.r<rail ? -1 : 1)*line.w/2;
845
+ @ }
846
+ @ var x1 = mArrow.w ? mArrow.w/2 : -node.w/2;
847
+ @ x1 = p.x + (p.r<rail ? node.w + Math.ceil(x1) : -x1);
848
+ @ var y = miLineY(p);
849
+ @ drawMergeLine(x0,y,x1,null);
850
+ @ var x = p.x + (p.r<rail ? node.w : -mArrow.w);
851
+ @ var cls = "arrow merge " + (p.r<rail ? "l" : "r");
852
+ @ drawBox(cls,null,x,y+(mLine.w-mArrow.h)/2);
853
+ @ }
854
+ @ function drawNode(p, btm){
855
+ @ if( p.u>0 ) drawUpArrow(p,rowinfo[p.u-1],p.fg);
856
+ @ var cls = node.cls;
857
+ @ if( p.mi.length ) cls += " merge";
858
+ @ if( p.f&1 ) cls += " leaf";
859
+ @ var n = drawBox(cls,p.bg,p.x,p.y);
860
+ @ n.id = "tln"+p.id;
861
+ @ n.onclick = clickOnNode;
862
+ @ n.style.zIndex = 10;
863
+ if( !omitDescenders ){
864
+ @ if( p.u==0 ) drawUpArrow(p,{x: p.x, y: -node.h},p.fg);
865
+ @ if( p.d ) drawUpArrow({x: p.x, y: btm-node.h/2},p,p.fg);
866
+ }
867
+ @ if( p.mo>=0 ){
868
+ @ var x0 = p.x + node.w/2;
869
+ @ var x1 = p.mo*railPitch + node.w/2;
870
+ @ var u = rowinfo[p.mu-1];
871
+ @ var y1 = miLineY(u);
872
+ @ if( p.u<0 || p.mo!=p.r ){
873
+ @ x1 += mergeLines[p.mo] = -mLine.w/2;
874
+ @ var y0 = p.y+2;
875
+ @ if( p.r!=p.mo ) drawMergeLine(x0,y0,x1+(x0<x1 ? mLine.w : 0),null);
876
+ @ drawMergeLine(x1,y0+mLine.w,null,y1);
877
+ @ }else if( mergeOffset ){
878
+ @ mergeLines[p.mo] = u.r<p.r ? -mergeOffset-mLine.w : mergeOffset;
879
+ @ x1 += mergeLines[p.mo];
880
+ @ drawMergeLine(x1,p.y+node.h/2,null,y1);
881
+ @ }else{
882
+ @ delete mergeLines[p.mo];
883
+ @ }
884
+ @ }
885
+ @ for( var i=0; i<p.au.length; i+=2 ){
886
+ @ var rail = p.au[i];
887
+ @ var x0 = p.x + node.w/2;
888
+ @ var x1 = rail*railPitch + (node.w-line.w)/2;
889
+ @ if( x0<x1 ){
890
+ @ x0 = Math.ceil(x0);
891
+ @ x1 += line.w;
892
+ @ }
893
+ @ var y0 = p.y + (node.h-line.w)/2;
894
+ @ var u = rowinfo[p.au[i+1]-1];
895
+ @ if( u.id<p.id ){
896
+ @ drawLine(line,u.fg,x0,y0,x1,null);
897
+ @ drawUpArrow(p,u,u.fg);
898
+ @ }else{
899
+ @ var y1 = u.y + (node.h-line.w)/2;
900
+ @ drawLine(wLine,u.fg,x0,y0,x1,null);
901
+ @ drawLine(wLine,u.fg,x1-line.w,y0,null,y1+line.w);
902
+ @ drawLine(wLine,u.fg,x1,y1,u.x-wArrow.w/2,null);
903
+ @ var x = u.x-wArrow.w;
904
+ @ var y = u.y+(node.h-wArrow.h)/2;
905
+ @ var n = drawBox(wArrow.cls,null,x,y);
906
+ @ if( u.fg ) n.style.borderLeftColor = u.fg;
907
+ @ }
908
+ @ }
909
+ @ for( var i=0; i<p.mi.length; i++ ){
910
+ @ var rail = p.mi[i];
911
+ @ if( rail<0 ){
912
+ @ rail = -rail;
913
+ @ mergeLines[rail] = -mLine.w/2;
914
+ @ var x = rail*railPitch + (node.w-mLine.w)/2;
915
+ @ drawMergeLine(x,miLineY(p),null,btm);
916
+ @ }
917
+ @ drawMergeArrow(p,rail);
918
+ @ }
919
+ @ }
920
+ @ var mergeLines;
921
+ @ function renderGraph(){
922
+ @ mergeLines = {};
923
+ @ canvasDiv.innerHTML = "";
924
+ @ var canvasY = absoluteY(canvasDiv);
925
+ @ for( var i=0; i<rowinfo.length; i++ ){
926
+ @ rowinfo[i].y = absoluteY(gebi("m"+rowinfo[i].id)) - canvasY;
927
+ @ rowinfo[i].x = rowinfo[i].r*railPitch;
928
+ @ }
929
+ @ var tlBtm = document.querySelector(".timelineBottom");
930
+ @ if( tlBtm.offsetHeight<node.h ){
931
+ @ tlBtm.style.height = node.h + "px";
932
+ @ }
933
+ @ var btm = absoluteY(tlBtm) - canvasY + tlBtm.offsetHeight;
934
+ @ for( var i=rowinfo.length-1; i>=0; i-- ){
935
+ @ drawNode(rowinfo[i], btm);
936
+ @ }
937
+ @ }
938
+ @ var selRow;
939
+ @ function clickOnNode(){
940
+ @ var p = rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-1];
941
+ @ if( !selRow ){
942
+ @ selRow = p;
943
+ @ this.className += " sel";
944
+ @ canvasDiv.className += " sel";
945
+ @ }else if( selRow==p ){
946
+ @ selRow = null;
947
+ @ this.className = this.className.replace(" sel", "");
948
+ @ canvasDiv.className = canvasDiv.className.replace(" sel", "");
997949
@ }else{
998950
if( fileDiff ){
999951
@ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
1000952
}else{
1001953
if( db_get_boolean("show-version-diffs", 0)==0 ){
@@ -1004,22 +956,23 @@
1004956
@ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
1005957
}
1006958
}
1007959
@ }
1008960
@ }
1009
- @ var lastId = "m"+rowinfo[rowinfo.length-1].id;
961
+ @ var lastRow = gebi("m"+rowinfo[rowinfo.length-1].id);
1010962
@ var lastY = 0;
1011963
@ function checkHeight(){
1012
- @ var h = absoluteY(lastId);
964
+ @ var h = absoluteY(lastRow);
1013965
@ if( h!=lastY ){
1014966
@ renderGraph();
1015967
@ lastY = h;
1016968
@ }
1017
- @ setTimeout("checkHeight();", 1000);
969
+ @ setTimeout(checkHeight, 1000);
1018970
@ }
971
+ @ initGraph();
1019972
@ checkHeight();
1020
- @ </script>
973
+ @ }())</script>
1021974
}
1022975
}
1023976
1024977
/*
1025978
** Create a temporary table suitable for storing timeline data.
1026979
1027980
ADDED test/contains-selector.test
--- src/timeline.c
+++ src/timeline.c
@@ -241,23 +241,17 @@
241 dateFormat = db_get_int("timeline-date-format", 0);
242 zDateFmt = P("datefmt");
243 if( zDateFmt ) dateFormat = atoi(zDateFmt);
244 if( tmFlags & TIMELINE_GRAPH ){
245 pGraph = graph_init();
246 /* style is not moved to css, because this is
247 ** a technical div for the timeline graph
248 */
249 @ <div id="canvas" style="position:relative;height:0px;width:0px;"
250 @ onclick="clickOnGraph(event)"></div>
251 }
252 db_static_prepare(&qbranch,
253 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
254 TAG_BRANCH
255 );
256
257 @ <table id="timelineTable" class="timelineTable"
258 @ onclick="clickOnGraph(event)">
259 blob_zero(&comment);
260 while( db_step(pQuery)==SQLITE_ROW ){
261 int rid = db_column_int(pQuery, 0);
262 const char *zUuid = db_column_text(pQuery, 1);
263 int isLeaf = db_column_int(pQuery, 5);
@@ -391,11 +385,11 @@
391 }
392 db_reset(&qparent);
393 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
394 zUuid, isLeaf);
395 db_reset(&qbranch);
396 @ <div id="m%d(gidx)"></div>
397 }
398 @</td>
399 if( zBgClr && zBgClr[0] && rid!=selectedRid ){
400 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
401 }else{
@@ -589,18 +583,11 @@
589 graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
590 if( pGraph->nErr ){
591 graph_free(pGraph);
592 pGraph = 0;
593 }else{
594 int w;
595 /* style is not moved to css, because this is
596 ** a technical div for the timeline graph
597 */
598 w = pGraph->mxRail*pGraph->iRailPitch + 28;
599 @ <tr class="timelineBottom"><td></td><td>
600 @ <div id="grbtm" style="width:%d(w)px;"></div>
601 @ </td><td></td></tr>
602 }
603 }
604 @ </table>
605 if( fchngQueryInit ) db_finalize(&fchngQuery);
606 timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0, 0);
@@ -648,31 +635,18 @@
648 ){
649 if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
650 GraphRow *pRow;
651 int i;
652 char cSep;
653 int mergeOffset; /* Pixel offset from rail to merge riser */
654 int iRailPitch; /* Pixels between consecutive rails */
655 int showArrowheads; /* True to draw arrowheads. False to omit. */
656 int circleNodes; /* True for circle nodes. False for square nodes */
657 int colorGraph; /* Use colors for graph lines */
658
659 iRailPitch = pGraph->iRailPitch;
660 showArrowheads = skin_detail_boolean("timeline-arrowheads");
661 circleNodes = skin_detail_boolean("timeline-circle-nodes");
662 colorGraph = skin_detail_boolean("timeline-color-graph-lines");
663
664 /* Number of pixels that the thin merge lines are offset from the
665 ** the center of the think rail lines. If zero, then the vertical
666 ** merge lines overlap with the thicker rail lines.
667 */
668 mergeOffset = iRailPitch>=14 ? 4 : iRailPitch>=13 ? 3 : 0;
669 if( PB("nomo") ) mergeOffset = 0;
670
671 @ <script>
672 @ var railPitch=%d(iRailPitch);
673
674 /* the rowinfo[] array contains all the information needed to generate
675 ** the graph. Each entry contains information for a single row:
676 **
677 ** id: The id of the <div> element for the row. This is an integer.
678 ** to get an actual id, prepend "m" to the integer. The top node
@@ -680,13 +654,13 @@
680 ** bg: The background color for this row
681 ** r: The "rail" that the node for this row sits on. The left-most
682 ** rail is 0 and the number increases to the right.
683 ** d: True if there is a "descender" - an arrow coming from the bottom
684 ** of the page straight up to this node.
685 ** mo: "merge-out". If non-zero, this is one more than the x-coordinate
686 ** for the upward portion of a merge arrow. The merge arrow goes up
687 ** to the row identified by mu:. If this value is zero then
688 ** node has no merge children and no merge-out line is drawn.
689 ** mu: The id of the row which is the top of the merge-out arrow.
690 ** u: Draw a thick child-line out of the top of this node and up to
691 ** the node with an id equal to this value. 0 if it is straight to
692 ** the top of the page, -1 if there is no thick-line riser.
@@ -693,37 +667,25 @@
693 ** f: 0x01: a leaf node.
694 ** au: An array of integers that define thick-line risers for branches.
695 ** The integers are in pairs. For each pair, the first integer is
696 ** is the rail on which the riser should run and the second integer
697 ** is the id of the node upto which the riser should run.
698 ** mi: "merge-in". An array of integer x-coordinates from which
699 ** merge arrows should be drawn into this node. If the value is
700 ** negative, then the x-coordinate is the absolute value of mi[]
701 ** and a thin merge-arrow descender is drawn to the bottom of
702 ** the screen.
703 ** h: The SHA1 hash of the object being graphed
704 */
705 cgi_printf("var rowinfo = [\n");
706 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
707 int mo = pRow->mergeOut;
708 if( mo<0 ){
709 mo = 0;
710 }else{
711 int x = (mo/4)*iRailPitch;
712 switch( mo&3 ){
713 case 0: x -= mergeOffset-2; break;
714 case 1: x += 1; break;
715 case 2: x += mergeOffset+1; break;
716 }
717 mo = x;
718 }
719 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
720 pRow->idx, /* id */
721 pRow->zBgClr, /* bg */
722 pRow->iRail, /* r */
723 pRow->bDescender, /* d */
724 mo, /* mo */
725 pRow->mergeUpto, /* mu */
726 pRow->aiRiser[pRow->iRail], /* u */
727 pRow->isLeaf ? 1 : 0 /* f */
728 );
729 /* u */
@@ -743,13 +705,11 @@
743 /* mi */
744 cgi_printf("mi:");
745 cSep = '[';
746 for(i=0; i<GR_MAX_RAIL; i++){
747 if( pRow->mergeIn[i] ){
748 int mi = i*iRailPitch;
749 if( pRow->mergeIn[i]==1 ) mi -= mergeOffset-1;
750 if( pRow->mergeIn[i]==3 ) mi += mergeOffset;
751 if( pRow->mergeDown & (1<<i) ) mi = -mi;
752 cgi_printf("%c%d", cSep, mi);
753 cSep = ',';
754 }
755 }
@@ -756,246 +716,238 @@
756 if( cSep=='[' ) cgi_printf("[");
757 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
758 }
759 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
760 graph_free(pGraph);
761 @ var cDiv = gebi("canvas");
762 @ var csty = window.getComputedStyle && window.getComputedStyle(cDiv,null);
763 @ var lineClr = (csty && csty.getPropertyValue('color')) || 'black';
764 @ var bgClr = (csty && csty.getPropertyValue('background-color')) ||'white';
765 @ if( bgClr=='transparent' ) bgClr = 'white';
766 @ var boxColor = lineClr;
767 @ function drawBox(color,x0,y0,x1,y1){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
768 @ var n = document.createElement("div");
 
 
 
 
769 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
770 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
771 @ var w = x1-x0+1;
772 @ var h = y1-y0+1;
773 @ n.style.position = "absolute";
774 @ n.style.overflow = "hidden";
775 @ n.style.left = x0+"px";
776 @ n.style.top = y0+"px";
777 @ n.style.width = w+"px";
778 @ n.style.height = h+"px";
779 @ n.style.backgroundColor = color;
780 @ cDiv.appendChild(n);
 
781 @ return n;
782 @ }
783 @ function absoluteY(id){
784 @ var obj = gebi(id);
785 @ if( !obj ) return;
786 @ var top = 0;
787 @ if( obj.offsetParent ){
788 @ do{
789 @ top += obj.offsetTop;
790 @ }while( obj = obj.offsetParent );
791 @ }
792 @ return top;
793 @ }
794 @ function absoluteX(id){
795 @ var obj = gebi(id);
796 @ if( !obj ) return;
797 @ var left = 0;
798 @ if( obj.offsetParent ){
799 @ do{
800 @ left += obj.offsetLeft;
801 @ }while( obj = obj.offsetParent );
802 @ }
803 @ return left;
804 @ }
805 if( showArrowheads ){
806 @ function drawUpArrow(x,y0,y1,clr){
807 @ drawBox(clr,x,y0+4,x+1,y1);
808 @ var n = document.createElement("div"),
809 @ l = x-2,
810 @ t = y0;
811 @ n.style.position = "absolute";
812 @ n.style.left = l+"px";
813 @ n.style.top = t+"px";
814 @ n.style.width = 0;
815 @ n.style.height = 0;
816 @ n.style.transform = "scale(.999)";
817 @ n.style.borderWidth = 0;
818 @ n.style.borderStyle = "solid";
819 @ n.style.borderColor = "transparent";
820 @ n.style.borderRightWidth = "3px";
821 @ n.style.borderBottomColor = clr;
822 @ n.style.borderLeftWidth = "3px";
823 @ if( y0+10>=y1 ){
824 @ n.style.borderBottomWidth = "5px";
825 @ } else {
826 @ n.style.borderBottomWidth = "7px";
827 @ }
828 @ cDiv.appendChild(n);
829 @ }
830 }else{
831 @ function drawUpArrow(x,y0,y1,clr){
832 @ drawBox(clr,x,y0+1,x+1,y1);
833 @ }
834 }
835 @ function drawThinArrow(y,xFrom,xTo){
836 @ var n = document.createElement("div"),
837 @ t = y-2;
838 @ n.style.position = "absolute";
839 @ n.style.top = t+"px";
840 @ n.style.width = 0;
841 @ n.style.height = "1px";
842 @ n.style.transform = "scale(.999)";
843 @ n.style.borderWidth = 0;
844 @ n.style.borderStyle = "solid";
845 @ n.style.borderColor = "transparent";
846 @ n.style.borderTopWidth = "2px";
847 @ n.style.borderBottomWidth = "2px";
848 @ if( xFrom<xTo ){
849 @ drawBox(lineClr,xFrom,y,xTo-3,y);
850 @ n.style.left = xTo-3+"px";
851 @ n.style.borderLeftWidth = "3px";
852 @ n.style.borderLeftColor = lineClr;
853 @ }else{
854 @ drawBox(lineClr,xTo+3,y,xFrom,y);
855 @ n.style.left = xTo+1+"px";
856 @ n.style.borderRightWidth = "3px";
857 @ n.style.borderRightColor = lineClr;
858 @ }
859 @ cDiv.appendChild(n);
860 @ }
861 @ function drawThinLine(x0,y0,x1,y1){
862 @ drawBox(lineClr,x0,y0,x1,y1);
863 @ }
864 @ function drawNodeBox(color,x0,y0,x1,y1){
865 @ var n = drawBox(color,x0,y0,x1,y1);
866 @ n.style.cursor = "pointer";
867 if( circleNodes ){
868 @ n.style.borderRadius = "6px";
869 }
870 @ }
871 @ function drawNode(p, left, btm){
872 @ drawNodeBox(boxColor,p.x-5,p.y-5,p.x+6,p.y+6);
873 @ drawNodeBox(p.bg||bgClr,p.x-4,p.y-4,p.x+5,p.y+5);
874 @ if( p.u>0 ) drawUpArrow(p.x,rowinfo[p.u-1].y+6,p.y-6,p.fg||lineClr);
875 @ if( p.f&1 ) drawNodeBox(boxColor,p.x-1,p.y-1,p.x+2,p.y+2);
876 if( !omitDescenders ){
877 @ if( p.u==0 ) drawUpArrow(p.x,0,p.y-6,p.fg||lineClr);
878 @ if( p.d ) drawUpArrow(p.x,p.y+6,btm,p.fg||lineClr);
879 }
880 @ if( p.mo>0 ){
881 @ var x1 = p.mo + left - 1;
882 @ var y1 = p.y-3;
883 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
884 @ var u = rowinfo[p.mu-1];
885 @ var y0 = u.y+5;
886 @ if( x1>=p.x-5 && x1<=p.x+5 ){
887 @ y1 = p.y-5;
888 @ }else{
889 @ drawThinLine(x0,y1,x1,y1);
890 @ }
891 if( mergeOffset==0 ) cgi_printf("if( p.mo!=p.u-1 ) ");
892 @ drawThinLine(x1,y0,x1,y1);
893 @ }
894 @ var n = p.au.length;
895 @ for(var i=0; i<n; i+=2){
896 @ var x1 = p.au[i]*railPitch + left;
897 @ var x0 = x1>p.x ? p.x+7 : p.x-6;
898 @ var u = rowinfo[p.au[i+1]-1];
899 @ if(u.id<p.id){
900 @ drawBox(u.fg||lineClr,x0,p.y,x1+1,p.y+1);
901 @ drawUpArrow(x1,u.y+6,p.y,u.fg||lineClr);
902 @ }else{
903 @ drawBox("#600000",x0,p.y,x1,p.y+1);
904 @ drawBox("#600000",x1-1,p.y,x1,u.y+1);
905 @ drawBox("#600000",x1,u.y,u.x-10,u.y+1);
906 @ var n = document.createElement("div"),
907 @ t = u.y-2,
908 @ l = u.x-11;
909 @ n.style.position = "absolute";
910 @ n.style.top = t+"px";
911 @ n.style.left = l+"px";
912 @ n.style.width = 0;
913 @ n.style.height = 0;
914 @ n.style.transform = "scale(.999)";
915 @ n.style.borderWidth = 0;
916 @ n.style.borderStyle = "solid";
917 @ n.style.borderColor = "transparent";
918 @ n.style.borderTopWidth = "3px";
919 @ n.style.borderBottomWidth = "3px";
920 @ n.style.borderLeftWidth = "7px";
921 @ n.style.borderLeftColor = "#600000";
922 @ cDiv.appendChild(n);
923 @ }
924 @ }
925 @ for(var j in p.mi){
926 @ var y0 = p.y+5;
927 @ var mx = p.mi[j];
928 @ if( mx<0 ){
929 @ mx = left-mx;
930 @ drawThinLine(mx,y0,mx,btm);
931 @ }else{
932 @ mx += left;
933 @ }
934 @ if( mx>p.x ){
935 @ drawThinArrow(y0,mx,p.x+6);
936 @ }else{
937 @ drawThinArrow(y0,mx,p.x-5);
938 @ }
939 @ }
940 @ }
941 @ var selBox = null;
942 @ var selRow = null;
943 @ function renderGraph(){
944 @ var canvasDiv = gebi("canvas");
945 @ while( canvasDiv.hasChildNodes() ){
946 @ canvasDiv.removeChild(canvasDiv.firstChild);
947 @ }
948 @ var canvasY = absoluteY("timelineTable");
949 @ var left = absoluteX("m"+rowinfo[0].id) - absoluteX("canvas") + 15;
950 @ for(var i in rowinfo){
951 @ rowinfo[i].y = absoluteY("m"+rowinfo[i].id) + 10 - canvasY;
952 @ rowinfo[i].x = left + rowinfo[i].r*railPitch;
953 @ }
954 @ var btm = absoluteY("grbtm") + 10 - canvasY;
955 @ for(var i in rowinfo){
956 @ drawNode(rowinfo[i], left, btm);
957 @ }
958 @ if( selRow!=null ) clickOnRow(selRow);
959 @ }
960 @ function clickOnGraph(event){
961 @ var x=event.clientX-absoluteX("canvas");
962 @ var y=event.clientY-absoluteY("canvas");
963 @ if(window.pageXOffset!=null){
964 @ x += window.pageXOffset;
965 @ y += window.pageYOffset;
966 @ }else{
967 @ var d = window.document.documentElement;
968 @ if(document.compatMode!="CSS1Compat") d = d.body;
969 @ x += d.scrollLeft;
970 @ y += d.scrollTop;
971 @ }
972 if( P("clicktest")!=0 ){
973 @ alert("click at "+x+","+y)
974 }
975 @ for(var i in rowinfo){
976 @ p = rowinfo[i];
977 @ if( p.y<y-11 ) continue;
978 @ if( p.y>y+9 ) break;
979 @ if( p.x>x-11 && p.x<x+9 ){
980 @ clickOnRow(p);
981 @ break;
982 @ }
983 @ }
984 @ }
985 @ function clickOnRow(p){
986 @ if( selRow==null ){
987 @ selBox = drawBox("red",p.x-2,p.y-2,p.x+3,p.y+3);
988 if( circleNodes ){
989 @ selBox.style.borderRadius="6px";
990 }
991 @ selRow = p;
992 @ }else if( selRow==p ){
993 @ var canvasDiv = gebi("canvas");
994 @ canvasDiv.removeChild(selBox);
995 @ selBox = null;
996 @ selRow = null;
997 @ }else{
998 if( fileDiff ){
999 @ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
1000 }else{
1001 if( db_get_boolean("show-version-diffs", 0)==0 ){
@@ -1004,22 +956,23 @@
1004 @ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
1005 }
1006 }
1007 @ }
1008 @ }
1009 @ var lastId = "m"+rowinfo[rowinfo.length-1].id;
1010 @ var lastY = 0;
1011 @ function checkHeight(){
1012 @ var h = absoluteY(lastId);
1013 @ if( h!=lastY ){
1014 @ renderGraph();
1015 @ lastY = h;
1016 @ }
1017 @ setTimeout("checkHeight();", 1000);
1018 @ }
 
1019 @ checkHeight();
1020 @ </script>
1021 }
1022 }
1023
1024 /*
1025 ** Create a temporary table suitable for storing timeline data.
1026
1027 DDED test/contains-selector.test
--- src/timeline.c
+++ src/timeline.c
@@ -241,23 +241,17 @@
241 dateFormat = db_get_int("timeline-date-format", 0);
242 zDateFmt = P("datefmt");
243 if( zDateFmt ) dateFormat = atoi(zDateFmt);
244 if( tmFlags & TIMELINE_GRAPH ){
245 pGraph = graph_init();
 
 
 
 
 
246 }
247 db_static_prepare(&qbranch,
248 "SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0 AND rid=:rid",
249 TAG_BRANCH
250 );
251
252 @ <table id="timelineTable" class="timelineTable">
 
253 blob_zero(&comment);
254 while( db_step(pQuery)==SQLITE_ROW ){
255 int rid = db_column_int(pQuery, 0);
256 const char *zUuid = db_column_text(pQuery, 1);
257 int isLeaf = db_column_int(pQuery, 5);
@@ -391,11 +385,11 @@
385 }
386 db_reset(&qparent);
387 gidx = graph_add_row(pGraph, rid, nParent, aParent, zBr, zBgClr,
388 zUuid, isLeaf);
389 db_reset(&qbranch);
390 @ <div id="m%d(gidx)" class="tl-nodemark"></div>
391 }
392 @</td>
393 if( zBgClr && zBgClr[0] && rid!=selectedRid ){
394 @ <td class="timelineTableCell" style="background-color: %h(zBgClr);">
395 }else{
@@ -589,18 +583,11 @@
583 graph_finish(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0);
584 if( pGraph->nErr ){
585 graph_free(pGraph);
586 pGraph = 0;
587 }else{
588 @ <tr class="timelineBottom"><td></td><td></td><td></td></tr>
 
 
 
 
 
 
 
589 }
590 }
591 @ </table>
592 if( fchngQueryInit ) db_finalize(&fchngQuery);
593 timeline_output_graph_javascript(pGraph, (tmFlags & TIMELINE_DISJOINT)!=0, 0);
@@ -648,31 +635,18 @@
635 ){
636 if( pGraph && pGraph->nErr==0 && pGraph->nRow>0 ){
637 GraphRow *pRow;
638 int i;
639 char cSep;
 
640 int iRailPitch; /* Pixels between consecutive rails */
 
 
641 int colorGraph; /* Use colors for graph lines */
642
643 iRailPitch = atoi(PD("railpitch","0"));
 
 
644 colorGraph = skin_detail_boolean("timeline-color-graph-lines");
645
646 @ <script>(function(){
647 @ "use strict";
 
 
 
 
 
 
 
 
648 /* the rowinfo[] array contains all the information needed to generate
649 ** the graph. Each entry contains information for a single row:
650 **
651 ** id: The id of the <div> element for the row. This is an integer.
652 ** to get an actual id, prepend "m" to the integer. The top node
@@ -680,13 +654,13 @@
654 ** bg: The background color for this row
655 ** r: The "rail" that the node for this row sits on. The left-most
656 ** rail is 0 and the number increases to the right.
657 ** d: True if there is a "descender" - an arrow coming from the bottom
658 ** of the page straight up to this node.
659 ** mo: "merge-out". If non-negative, this is the rail position
660 ** for the upward portion of a merge arrow. The merge arrow goes up
661 ** to the row identified by mu:. If this value is negative then
662 ** node has no merge children and no merge-out line is drawn.
663 ** mu: The id of the row which is the top of the merge-out arrow.
664 ** u: Draw a thick child-line out of the top of this node and up to
665 ** the node with an id equal to this value. 0 if it is straight to
666 ** the top of the page, -1 if there is no thick-line riser.
@@ -693,37 +667,25 @@
667 ** f: 0x01: a leaf node.
668 ** au: An array of integers that define thick-line risers for branches.
669 ** The integers are in pairs. For each pair, the first integer is
670 ** is the rail on which the riser should run and the second integer
671 ** is the id of the node upto which the riser should run.
672 ** mi: "merge-in". An array of integer rail positions from which
673 ** merge arrows should be drawn into this node. If the value is
674 ** negative, then the rail position is the absolute value of mi[]
675 ** and a thin merge-arrow descender is drawn to the bottom of
676 ** the screen.
677 ** h: The SHA1 hash of the object being graphed
678 */
679 cgi_printf("var rowinfo = [\n");
680 for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
 
 
 
 
 
 
 
 
 
 
 
 
681 cgi_printf("{id:%d,bg:\"%s\",r:%d,d:%d,mo:%d,mu:%d,u:%d,f:%d,au:",
682 pRow->idx, /* id */
683 pRow->zBgClr, /* bg */
684 pRow->iRail, /* r */
685 pRow->bDescender, /* d */
686 pRow->mergeOut, /* mo */
687 pRow->mergeUpto, /* mu */
688 pRow->aiRiser[pRow->iRail], /* u */
689 pRow->isLeaf ? 1 : 0 /* f */
690 );
691 /* u */
@@ -743,13 +705,11 @@
705 /* mi */
706 cgi_printf("mi:");
707 cSep = '[';
708 for(i=0; i<GR_MAX_RAIL; i++){
709 if( pRow->mergeIn[i] ){
710 int mi = i;
 
 
711 if( pRow->mergeDown & (1<<i) ) mi = -mi;
712 cgi_printf("%c%d", cSep, mi);
713 cSep = ',';
714 }
715 }
@@ -756,246 +716,238 @@
716 if( cSep=='[' ) cgi_printf("[");
717 cgi_printf("],h:\"%s\"}%s", pRow->zUuid, pRow->pNext ? ",\n" : "];\n");
718 }
719 cgi_printf("var nrail = %d\n", pGraph->mxRail+1);
720 graph_free(pGraph);
721 @ var canvasDiv;
722 @ var railPitch;
723 @ var mergeOffset;
724 @ var node, arrow, arrowSmall, line, mArrow, mLine, wArrow, wLine;
725 @ function initGraph(){
726 @ var parent = gebi("timelineTable").rows[0].cells[1];
727 @ parent.style.verticalAlign = "top";
728 @ canvasDiv = document.createElement("div");
729 @ canvasDiv.className = "tl-canvas";
730 @ canvasDiv.style.position = "absolute";
731 @ parent.appendChild(canvasDiv);
732 @
733 @ var elems = {};
734 @ var elemClasses = [
735 @ "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
736 @ "arrow merge r", "line merge", "arrow warp", "line warp"
737 @ ];
738 @ for( var i=0; i<elemClasses.length; i++ ){
739 @ var cls = elemClasses[i];
740 @ var elem = document.createElement("div");
741 @ elem.className = "tl-" + cls;
742 @ if( cls.indexOf("line")==0 ) elem.className += " v";
743 @ canvasDiv.appendChild(elem);
744 @ var k = cls.replace(/\s/g, "_");
745 @ var r = elem.getBoundingClientRect();
746 @ var w = Math.ceil(r.right - r.left);
747 @ var h = Math.ceil(r.bottom - r.top);
748 @ elems[k] = {w: w, h: h, cls: cls};
749 @ }
750 @ node = elems.node;
751 @ arrow = elems.arrow_u;
752 @ arrowSmall = elems.arrow_u_sm;
753 @ line = elems.line;
754 @ mArrow = elems.arrow_merge_r;
755 @ mLine = elems.line_merge;
756 @ wArrow = elems.arrow_warp;
757 @ wLine = elems.line_warp;
758 @
759 @ var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
760 if( iRailPitch ){
761 @ railPitch = %d(iRailPitch);
762 }else{
763 @ railPitch = elems.rail.w;
764 @ railPitch -= Math.floor((nrail-1)*(railPitch-minRailPitch)/21);
765 }
766 @ railPitch = Math.max(railPitch, minRailPitch);
767 @
768 if( PB("nomo") ){
769 @ mergeOffset = 0;
770 }else{
771 @ mergeOffset = railPitch-minRailPitch-mLine.w;
772 @ mergeOffset = Math.min(mergeOffset, elems.mergeoffset.w);
773 @ mergeOffset = mergeOffset>0 ? mergeOffset + line.w/2 : 0;
774 }
775 @
776 @ var canvasWidth = (nrail-1)*railPitch + node.w;
777 @ canvasDiv.style.width = canvasWidth + "px";
778 @ canvasDiv.style.position = "relative";
779 @ }
780 @ function drawBox(cls,color,x0,y0,x1,y1){
781 @ var n = document.createElement("div");
782 @ x0 = Math.floor(x0);
783 @ y0 = Math.floor(y0);
784 @ x1 = x1 || x1===0 ? Math.floor(x1) : x0;
785 @ y1 = y1 || y1===0 ? Math.floor(y1) : y0;
786 @ if( x0>x1 ){ var t=x0; x0=x1; x1=t; }
787 @ if( y0>y1 ){ var t=y0; y0=y1; y1=t; }
788 @ var w = x1-x0;
789 @ var h = y1-y0;
790 @ n.style.position = "absolute";
 
791 @ n.style.left = x0+"px";
792 @ n.style.top = y0+"px";
793 @ if( w ) n.style.width = w+"px";
794 @ if( h ) n.style.height = h+"px";
795 @ if( color ) n.style.backgroundColor = color;
796 @ n.className = "tl-"+cls;
797 @ canvasDiv.appendChild(n);
798 @ return n;
799 @ }
800 @ function absoluteY(obj){
 
 
801 @ var top = 0;
802 @ if( obj.offsetParent ){
803 @ do{
804 @ top += obj.offsetTop;
805 @ }while( obj = obj.offsetParent );
806 @ }
807 @ return top;
808 @ }
809 @ function miLineY(p){
810 @ return p.y + node.h - mLine.w - 1;
811 @ }
812 @ function drawLine(elem,color,x0,y0,x1,y1){
813 @ var cls = elem.cls + " ";
814 @ if( x1===null ){
815 @ x1 = x0+elem.w;
816 @ cls += "v";
817 @ }else{
818 @ y1 = y0+elem.w;
819 @ cls += "h";
820 @ }
821 @ drawBox(cls,color,x0,y0,x1,y1);
822 @ }
823 @ function drawUpArrow(from,to,color){
824 @ var y = to.y + node.h;
825 @ var arrowSpace = from.y - y + (!from.id || from.r!=to.r ? node.h/2 : 0);
826 @ var arw = arrowSpace < arrow.h*1.5 ? arrowSmall : arrow;
827 @ var x = to.x + (node.w-line.w)/2;
828 @ var y0 = from.y + node.h/2;
829 @ var y1 = Math.ceil(to.y + node.h + arw.h/2);
830 @ drawLine(line,color,x,y0,null,y1);
831 @ x = to.x + (node.w-arw.w)/2;
832 @ var n = drawBox(arw.cls,null,x,y);
833 @ n.style.borderBottomColor = color;
834 @ }
835 @ function drawMergeLine(x0,y0,x1,y1){
836 @ drawLine(mLine,null,x0,y0,x1,y1);
837 @ }
838 @ function drawMergeArrow(p,rail){
839 @ var x0 = rail*railPitch + node.w/2;
840 @ if( rail in mergeLines ){
841 @ x0 += mergeLines[rail];
842 @ if( p.r<rail ) x0 += mLine.w;
843 @ }else{
844 @ x0 += (p.r<rail ? -1 : 1)*line.w/2;
845 @ }
846 @ var x1 = mArrow.w ? mArrow.w/2 : -node.w/2;
847 @ x1 = p.x + (p.r<rail ? node.w + Math.ceil(x1) : -x1);
848 @ var y = miLineY(p);
849 @ drawMergeLine(x0,y,x1,null);
850 @ var x = p.x + (p.r<rail ? node.w : -mArrow.w);
851 @ var cls = "arrow merge " + (p.r<rail ? "l" : "r");
852 @ drawBox(cls,null,x,y+(mLine.w-mArrow.h)/2);
853 @ }
854 @ function drawNode(p, btm){
855 @ if( p.u>0 ) drawUpArrow(p,rowinfo[p.u-1],p.fg);
856 @ var cls = node.cls;
857 @ if( p.mi.length ) cls += " merge";
858 @ if( p.f&1 ) cls += " leaf";
859 @ var n = drawBox(cls,p.bg,p.x,p.y);
860 @ n.id = "tln"+p.id;
861 @ n.onclick = clickOnNode;
862 @ n.style.zIndex = 10;
863 if( !omitDescenders ){
864 @ if( p.u==0 ) drawUpArrow(p,{x: p.x, y: -node.h},p.fg);
865 @ if( p.d ) drawUpArrow({x: p.x, y: btm-node.h/2},p,p.fg);
866 }
867 @ if( p.mo>=0 ){
868 @ var x0 = p.x + node.w/2;
869 @ var x1 = p.mo*railPitch + node.w/2;
870 @ var u = rowinfo[p.mu-1];
871 @ var y1 = miLineY(u);
872 @ if( p.u<0 || p.mo!=p.r ){
873 @ x1 += mergeLines[p.mo] = -mLine.w/2;
874 @ var y0 = p.y+2;
875 @ if( p.r!=p.mo ) drawMergeLine(x0,y0,x1+(x0<x1 ? mLine.w : 0),null);
876 @ drawMergeLine(x1,y0+mLine.w,null,y1);
877 @ }else if( mergeOffset ){
878 @ mergeLines[p.mo] = u.r<p.r ? -mergeOffset-mLine.w : mergeOffset;
879 @ x1 += mergeLines[p.mo];
880 @ drawMergeLine(x1,p.y+node.h/2,null,y1);
881 @ }else{
882 @ delete mergeLines[p.mo];
883 @ }
884 @ }
885 @ for( var i=0; i<p.au.length; i+=2 ){
886 @ var rail = p.au[i];
887 @ var x0 = p.x + node.w/2;
888 @ var x1 = rail*railPitch + (node.w-line.w)/2;
889 @ if( x0<x1 ){
890 @ x0 = Math.ceil(x0);
891 @ x1 += line.w;
892 @ }
893 @ var y0 = p.y + (node.h-line.w)/2;
894 @ var u = rowinfo[p.au[i+1]-1];
895 @ if( u.id<p.id ){
896 @ drawLine(line,u.fg,x0,y0,x1,null);
897 @ drawUpArrow(p,u,u.fg);
898 @ }else{
899 @ var y1 = u.y + (node.h-line.w)/2;
900 @ drawLine(wLine,u.fg,x0,y0,x1,null);
901 @ drawLine(wLine,u.fg,x1-line.w,y0,null,y1+line.w);
902 @ drawLine(wLine,u.fg,x1,y1,u.x-wArrow.w/2,null);
903 @ var x = u.x-wArrow.w;
904 @ var y = u.y+(node.h-wArrow.h)/2;
905 @ var n = drawBox(wArrow.cls,null,x,y);
906 @ if( u.fg ) n.style.borderLeftColor = u.fg;
907 @ }
908 @ }
909 @ for( var i=0; i<p.mi.length; i++ ){
910 @ var rail = p.mi[i];
911 @ if( rail<0 ){
912 @ rail = -rail;
913 @ mergeLines[rail] = -mLine.w/2;
914 @ var x = rail*railPitch + (node.w-mLine.w)/2;
915 @ drawMergeLine(x,miLineY(p),null,btm);
916 @ }
917 @ drawMergeArrow(p,rail);
918 @ }
919 @ }
920 @ var mergeLines;
921 @ function renderGraph(){
922 @ mergeLines = {};
923 @ canvasDiv.innerHTML = "";
924 @ var canvasY = absoluteY(canvasDiv);
925 @ for( var i=0; i<rowinfo.length; i++ ){
926 @ rowinfo[i].y = absoluteY(gebi("m"+rowinfo[i].id)) - canvasY;
927 @ rowinfo[i].x = rowinfo[i].r*railPitch;
928 @ }
929 @ var tlBtm = document.querySelector(".timelineBottom");
930 @ if( tlBtm.offsetHeight<node.h ){
931 @ tlBtm.style.height = node.h + "px";
932 @ }
933 @ var btm = absoluteY(tlBtm) - canvasY + tlBtm.offsetHeight;
934 @ for( var i=rowinfo.length-1; i>=0; i-- ){
935 @ drawNode(rowinfo[i], btm);
936 @ }
937 @ }
938 @ var selRow;
939 @ function clickOnNode(){
940 @ var p = rowinfo[parseInt(this.id.match(/\d+$/)[0], 10)-1];
941 @ if( !selRow ){
942 @ selRow = p;
943 @ this.className += " sel";
944 @ canvasDiv.className += " sel";
945 @ }else if( selRow==p ){
946 @ selRow = null;
947 @ this.className = this.className.replace(" sel", "");
948 @ canvasDiv.className = canvasDiv.className.replace(" sel", "");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
949 @ }else{
950 if( fileDiff ){
951 @ location.href="%R/fdiff?v1="+selRow.h+"&v2="+p.h+"&sbs=1";
952 }else{
953 if( db_get_boolean("show-version-diffs", 0)==0 ){
@@ -1004,22 +956,23 @@
956 @ location.href="%R/vdiff?from="+selRow.h+"&to="+p.h+"&sbs=1";
957 }
958 }
959 @ }
960 @ }
961 @ var lastRow = gebi("m"+rowinfo[rowinfo.length-1].id);
962 @ var lastY = 0;
963 @ function checkHeight(){
964 @ var h = absoluteY(lastRow);
965 @ if( h!=lastY ){
966 @ renderGraph();
967 @ lastY = h;
968 @ }
969 @ setTimeout(checkHeight, 1000);
970 @ }
971 @ initGraph();
972 @ checkHeight();
973 @ }())</script>
974 }
975 }
976
977 /*
978 ** Create a temporary table suitable for storing timeline data.
979
980 DDED test/contains-selector.test
--- a/test/contains-selector.test
+++ b/test/contains-selector.test
@@ -0,0 +1,43 @@
1
+#
2
+# Copyright (c) 2015 D. Richard Hipp
3
+#
4
+# This program is free software; you can redistribute it and/or
5
+# modify it under the terms of the Simplified BSD License (also
6
+# known as the "2-Clause License" or "FreeBSD License".)
7
+#
8
+# This program is distributed in the hope that it will be useful,
9
+# but without any warranty; without even the implied warranty of
10
+# merchantability or fitness for a particular purpose.
11
+#
12
+# Author contact information:
13
+# [email protected]
14
+# http://www.hwaci.com/drh/
15
+#
16
+############################################################################
17
+#
18
+# Test containsSelector() proc contains-selector {testId css selectorResultMap} {
19
+ set css [string trim $css]
20
+ set filename [file join $::tempPath compare-selector.css]
21
+ set fh [open $filename w]
22
+ puts -nonewline $fh $css
23
+ close $fh
24
+ foreach {selector found} $selectorResultMap {
25
+ set expected "$selector [expr {$found ? "found" : "not found"}]"
26
+ set result [fossil test-contains-selector $filename $selector]
27
+ test "contains-selector $testId $selector" {$result eq $expected}
28
+ }
29
+ file delete $filename
30
+}
31
+
32
+contains-selector 1 {
33
+ .a.b {}
34
+ .c .de {}
35
+ /* comment */
36
+ .c .d, .e /* comment */ {}
37
+} {
38
+ .a 0
39
+ .b 0
40
+ .a.b 1
41
+ .c 0
42
+ .d 0
43
+ {.c
--- a/test/contains-selector.test
+++ b/test/contains-selector.test
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/test/contains-selector.test
+++ b/test/contains-selector.test
@@ -0,0 +1,43 @@
1 #
2 # Copyright (c) 2015 D. Richard Hipp
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the Simplified BSD License (also
6 # known as the "2-Clause License" or "FreeBSD License".)
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but without any warranty; without even the implied warranty of
10 # merchantability or fitness for a particular purpose.
11 #
12 # Author contact information:
13 # [email protected]
14 # http://www.hwaci.com/drh/
15 #
16 ############################################################################
17 #
18 # Test containsSelector() proc contains-selector {testId css selectorResultMap} {
19 set css [string trim $css]
20 set filename [file join $::tempPath compare-selector.css]
21 set fh [open $filename w]
22 puts -nonewline $fh $css
23 close $fh
24 foreach {selector found} $selectorResultMap {
25 set expected "$selector [expr {$found ? "found" : "not found"}]"
26 set result [fossil test-contains-selector $filename $selector]
27 test "contains-selector $testId $selector" {$result eq $expected}
28 }
29 file delete $filename
30 }
31
32 contains-selector 1 {
33 .a.b {}
34 .c .de {}
35 /* comment */
36 .c .d, .e /* comment */ {}
37 } {
38 .a 0
39 .b 0
40 .a.b 1
41 .c 0
42 .d 0
43 {.c

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button