PageRenderTime 63ms CodeModel.GetById 30ms app.highlight 18ms RepoModel.GetById 12ms app.codeStats 0ms

/nav-div.js

http://github.com/yinwang0/ydiff
JavaScript | 282 lines | 192 code | 60 blank | 30 comment | 40 complexity | b4b18eb7e7f240f2ec3d87efe340a267 MD5 | raw file
  1// ydiff - a language-aware tool for comparing programs
  2// Copyright (C) 2011 Yin Wang (yinwang0@gmail.com)
  3
  4
  5// This program is free software: you can redistribute it and/or modify
  6// it under the terms of the GNU General Public License as published by
  7// the Free Software Foundation, either version 3 of the License, or
  8// (at your option) any later version.
  9
 10// This program is distributed in the hope that it will be useful,
 11// but WITHOUT ANY WARRANTY; without even the implied warranty of
 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13// GNU General Public License for more details.
 14
 15// You should have received a copy of the GNU General Public License
 16// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 17
 18
 19
 20// convenience function for document.getElementById().
 21window['$']=function(a){return document.getElementById(a)};
 22
 23
 24/////////////////////// debug flag ////////////////////////
 25var debug = false;
 26
 27
 28/////////////////////// adjustable parameters //////////////////
 29var minStep = 10;
 30var nSteps = 30;
 31var stepInterval = 10;
 32var blockRange = 5;                    // how far consider one page blocked
 33var nodeHLColor = 'yellow';
 34var lineHLColor = '#FFFF66';
 35var lineBlockedColor = '#E9AB17';
 36var bgColor = '';
 37var bodyBlockedColor = '#FAF0E6';
 38
 39
 40///////////////////////// globals ////////////////////////
 41var eventCount = { 'left' : 0, 'right' : 0};
 42var moving = false;
 43var matchId1 = 'leftstart';
 44var matchId2 = 'rightstart';
 45var matchLineId1 = -1;
 46var matchLineId2 = -1;
 47var cTimeout;
 48
 49
 50///////////////////////// utilities ///////////////////////
 51
 52// No Math.sign() in JS?
 53function sign(x) {
 54    if (x > 0) {
 55        return 1;
 56    } else if (x < 0) {
 57        return -1;
 58    } else {
 59        return 0;
 60    }
 61}
 62
 63
 64function log(msg) {
 65    if (debug) {
 66        console.log(msg);
 67    }
 68}
 69
 70
 71
 72function elementPosition(id) {
 73    obj = $(id);
 74    var curleft = 0, curtop = 0;
 75
 76    if (obj && obj.offsetParent) {
 77        curleft = obj.offsetLeft;
 78        curtop = obj.offsetTop;
 79
 80        while (obj = obj.offsetParent) {
 81            curleft += obj.offsetLeft;
 82            curtop += obj.offsetTop;
 83        }
 84    }
 85
 86    return { x: curleft, y: curtop };
 87}
 88
 89
 90/*
 91 * Scroll the window to relative position, detecting blocking positions.
 92 */
 93function scrollWithBlockCheck(container, distX, distY) {
 94    var oldTop = container.scrollTop;
 95    var oldLeft = container.scrollLeft;
 96
 97    container.scrollTop += distY;      // the ONLY place for actual scrolling
 98    container.scrollLeft += distX;
 99
100    var actualX = container.scrollLeft - oldLeft;
101    var actualY = container.scrollTop - oldTop;
102    log("distY=" + distY + ", actualY=" + actualY);
103    log("distX=" + distX + ", actualX=" + actualX);
104
105    // extra leewaw here because Chrome scrolling is horribly inacurate
106    if ((Math.abs(distX) > blockRange && actualX === 0)
107        || Math.abs(distY) > blockRange && actualY === 0) {
108        log("blocked");
109        container.style.backgroundColor = bodyBlockedColor;
110        return true;
111    } else {
112        eventCount[container.id] += 1;
113        container.style.backgroundColor = bgColor;
114        return false;
115    }
116}
117
118
119function getContainer(elm) {
120    while (elm && elm.tagName !== 'DIV') {
121        elm = elm.parentElement || elm.parentNode;
122    }
123    return elm;
124}
125
126
127/*
128 * timed animation function for scrolling the current window
129 */
130function matchWindow(linkId, targetId, n)
131{
132    moving = true;
133
134    var link = $(linkId);
135    var target = $(targetId);
136    var linkContainer = getContainer(link);
137    var targetContainer = getContainer(target);
138
139    var linkPos = elementPosition(linkId).y - linkContainer.scrollTop;
140    var targetPos = elementPosition(targetId).y - targetContainer.scrollTop;
141    var distY = targetPos - linkPos;
142    var distX = linkContainer.scrollLeft - targetContainer.scrollLeft;
143
144
145    log("matching window... " + n + " distY=" + distY + " distX=" + distX);
146
147    if (distY === 0 && distX === 0) {
148        clearTimeout(cTimeout);
149        moving = false;
150    } else if (n <= 1) {
151        scrollWithBlockCheck(targetContainer, distX, distY);
152        moving = false;
153    } else {
154        var stepSize = Math.floor(Math.abs(distY) / n);
155        actualMinStep = Math.min(minStep, Math.abs(distY));
156        if (Math.abs(stepSize) < minStep) {
157            var step = actualMinStep * sign(distY);
158        } else {
159            var step = stepSize * sign(distY);
160        }
161        var blocked = scrollWithBlockCheck(targetContainer, distX, step);
162        var rest = Math.floor(distY / step) - 1;
163        log("blocked?" + blocked + ", rest steps=" + rest);
164        if (!blocked) {
165            cTimeout = setTimeout(function () {
166                return matchWindow(linkId, targetId, rest);
167            }, stepInterval);
168        } else {
169            clearTimeout(cTimeout);
170            moving = false;
171        }
172    }
173}
174
175
176
177////////////////////////// highlighting /////////////////////////////
178
179var highlighted = []
180function putHighlight(id, color) {
181    var elm = $(id);
182    if (elm !== null) {
183        elm.style.backgroundColor = color;
184        if (color !== bgColor) {
185            highlighted.push(id);
186        }
187    }
188}
189
190
191function clearHighlight() {
192    for (i = 0; i < highlighted.length; i += 1) {
193        putHighlight(highlighted[i], bgColor);
194    }
195    highlighted = [];
196}
197
198
199
200/*
201 * Highlight the link, target nodes and their lines,
202 * then start animation to move the other window to match.
203 */
204function highlight(me, linkId, targetId, linkLineId, targetLineId, doMatch)
205{
206    if (me.id === 'left') {
207        matchId1 = linkId;
208        matchId2 = targetId;
209    } else {
210        matchId1 = targetId;
211        matchId2 = linkId;
212    }
213
214    clearHighlight();
215
216    putHighlight(linkId, nodeHLColor);
217    putHighlight(targetId, nodeHLColor);
218    putHighlight(linkLineId, lineHLColor);
219    putHighlight(targetLineId, lineHLColor);
220
221    if (doMatch) {
222        matchWindow(linkId, targetId, nSteps);
223    }
224}
225
226
227function instantMoveOtherWindow (me) {
228    log("me=" + me.id + ", eventcount=" + eventCount[me.id]);
229    log("matchId1=" + matchId1 + ", matchId2=" + matchId2);
230
231    me.style.backgroundColor = bgColor;
232
233    if (!moving && eventCount[me.id] === 0) {
234        if (me.id === 'left') {
235            matchWindow(matchId1, matchId2, 1);
236        } else {
237            matchWindow(matchId2, matchId1, 1);
238        }
239    }
240    if (eventCount[me.id] > 0) {
241        eventCount[me.id] -= 1;
242    }
243}
244
245
246function getTarget(x){
247    x = x || window.event;
248    return x.target || x.srcElement;
249}
250
251
252window.onload =
253    function (e) {
254        var tags = document.getElementsByTagName("A")
255        for (var i = 0; i < tags.length; i++) {
256            tags[i].onmouseover =
257                function (e) {
258                    var t = getTarget(e)
259                    var lid = t.id
260                    var tid = t.getAttribute('tid')
261                    var container = getContainer(t)
262                    highlight(container, lid, tid, 'ignore', 'ignore', false)
263                }
264            tags[i].onclick =
265                function (e) {
266                    var t = getTarget(e)
267                    var lid = t.id
268                    var tid = t.getAttribute('tid')
269                    var container = getContainer(t)
270                    highlight(container, lid, tid, 'ignore', 'ignore', true)
271                }
272        }
273
274        tags = document.getElementsByTagName("DIV")
275        for (var i = 0; i < tags.length; i++) {
276            tags[i].onscroll =
277                function (e) {
278                    instantMoveOtherWindow(getTarget(e))
279                }
280        }
281
282    }