##// END OF EJS Templates
thirdparty: vendor zope.interface 4.4.3...
thirdparty: vendor zope.interface 4.4.3 I've been trying to formalize interfaces for various components of Mercurial. So far, we've been using the "abc" package. This package is "good enough" for a lot of tasks. But it quickly falls over. For example, if you declare an @abc.abstractproperty, you must implement that attribute with a @property or the class compile time checking performed by abc will complain. This often forces you to implement dumb @property wrappers to return a _ prefixed attribute of the sane name. That's ugly. I've also wanted to implement automated checking that classes conform to various interfaces and don't expose other "public" attributes. After doing a bit of research and asking around, the general consensus seems to be that zope.interface is the best package for doing interface-based programming in Python. It has built-in support for verifying classes and objects conform to interfaces. It allows an interface's properties to be defined during __init__. There's even an "adapter registry" that allow you to register interfaces and look up which classes implement them. That could potentially be useful for places where our custom registry.py modules currently facilitates central registrations, but at a type level. Imagine extensions providing alternate implementations of things like the local repository interface to allow opening repositories with custom requirements. Anyway, this commit vendors zope.interface 4.4.3. The contents of the source tarball have been copied into mercurial/thirdparty/zope/ without modifications. Test modules have been removed because they are not interesting to us. The LICENSE.txt file has been copied so it lives next to the source. The Python modules don't use relative imports. zope/__init__.py defines a namespace package. So we'll need to modify the source code before this package is usable inside Mercurial. This will be done in subsequent commits. # no-check-commit for various style failures Differential Revision: https://phab.mercurial-scm.org/D2928

File last commit:

r35157:9f44d446 default
r37193:943d77fc default
Show More
followlines.js
286 lines | 10.6 KiB | application/javascript | JavascriptLexer
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // followlines.js - JavaScript utilities for followlines UI
//
// Copyright 2017 Logilab SA <contact@logilab.fr>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
//** Install event listeners for line block selection and followlines action */
document.addEventListener('DOMContentLoaded', function() {
var sourcelines = document.getElementsByClassName('sourcelines')[0];
if (typeof sourcelines === 'undefined') {
return;
}
// URL to complement with "linerange" query parameter
var targetUri = sourcelines.dataset.logurl;
av6
hgweb: use strict equals, remove non-breaking space in followlines.js...
r35157 if (typeof targetUri === 'undefined') {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return;
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // Tag of children of "sourcelines" element on which to add "line
// selection" style.
var selectableTag = sourcelines.dataset.selectabletag;
if (typeof selectableTag === 'undefined') {
return;
}
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 var isHead = parseInt(sourcelines.dataset.ishead || "0");
Denis Laxalde
hgweb: position the "followlines" box close to latest cursor position
r31849 //* position "element" on top-right of cursor */
function positionTopRight(element, event) {
var x = (event.clientX + 10) + 'px',
y = (event.clientY - 20) + 'px';
element.style.top = y;
element.style.left = x;
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // retrieve all direct *selectable* children of class="sourcelines"
// element
var selectableElements = Array.prototype.filter.call(
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 sourcelines.children,
av6
hgweb: add missing semicolons to followlines.js...
r35027 function(x) { return x.tagName === selectableTag; });
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var btnTitleStart = 'start following lines history from here';
var btnTitleEnd = 'terminate line block selection here';
//** return a <button> element with +/- spans */
function createButton() {
var btn = document.createElement('button');
btn.title = btnTitleStart;
btn.classList.add('btn-followlines');
var plusSpan = document.createElement('span');
plusSpan.classList.add('followlines-plus');
plusSpan.textContent = '+';
btn.appendChild(plusSpan);
var br = document.createElement('br');
btn.appendChild(br);
var minusSpan = document.createElement('span');
minusSpan.classList.add('followlines-minus');
minusSpan.textContent = '−';
btn.appendChild(minusSpan);
return btn;
}
// extend DOM with CSS class for selection highlight and action buttons
av6
hgweb: add missing semicolons to followlines.js...
r35027 var followlinesButtons = [];
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 for (var i = 0; i < selectableElements.length; i++) {
selectableElements[i].classList.add('followlines-select');
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var btn = createButton();
followlinesButtons.push(btn);
// insert the <button> as child of `selectableElements[i]` unless the
// latter has itself a child with a "followlines-btn-parent" class
// (annotate view)
var btnSupportElm = selectableElements[i];
var childSupportElms = btnSupportElm.getElementsByClassName(
'followlines-btn-parent');
if ( childSupportElms.length > 0 ) {
btnSupportElm = childSupportElms[0];
}
var refNode = btnSupportElm.children[0]; // node to insert <button> before
btnSupportElm.insertBefore(btn, refNode);
}
// ** re-initialize followlines buttons */
function resetButtons() {
for (var i = 0; i < followlinesButtons.length; i++) {
var btn = followlinesButtons[i];
btn.title = btnTitleStart;
btn.classList.remove('btn-followlines-end');
btn.classList.remove('btn-followlines-hidden');
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
var lineSelectedCSSClass = 'followlines-selected';
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 //** add CSS class on selectable elements in `from`-`to` line range */
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 function addSelectedCSSClass(from, to) {
for (var i = from; i <= to; i++) {
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 selectableElements[i].classList.add(lineSelectedCSSClass);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
}
//** remove CSS class from previously selected lines */
function removeSelectedCSSClass() {
var elements = sourcelines.getElementsByClassName(
lineSelectedCSSClass);
while (elements.length) {
elements[0].classList.remove(lineSelectedCSSClass);
}
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // ** return the element of type "selectableTag" parent of `element` */
function selectableParent(element) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var parent = element.parentElement;
if (parent === null) {
return null;
}
av6
hgweb: use strict equals, remove non-breaking space in followlines.js...
r35157 if (element.tagName === selectableTag && parent.isSameNode(sourcelines)) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return element;
}
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 return selectableParent(parent);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // ** update buttons title and style upon first click */
function updateButtons(selectable) {
for (var i = 0; i < followlinesButtons.length; i++) {
var btn = followlinesButtons[i];
btn.title = btnTitleEnd;
btn.classList.add('btn-followlines-end');
}
// on clicked button, change title to "cancel"
var clicked = selectable.getElementsByClassName('btn-followlines')[0];
clicked.title = 'cancel';
clicked.classList.remove('btn-followlines-end');
}
//** add `listener` on "click" event for all `followlinesButtons` */
function buttonsAddEventListener(listener) {
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].addEventListener('click', listener);
}
}
//** remove `listener` on "click" event for all `followlinesButtons` */
function buttonsRemoveEventListener(listener) {
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].removeEventListener('click', listener);
}
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 //** event handler for "click" on the first line of a block */
function lineSelectStart(e) {
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var startElement = selectableParent(e.target.parentElement);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 if (startElement === null) {
Denis Laxalde
hgweb: parameterize the tag name of elements holding followlines selection...
r32993 // not a "selectable" element (maybe <a>): abort, keeping event
// listener registered for other click with a "selectable" target
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return;
}
Denis Laxalde
hgweb: add a floating tooltip to invite on followlines action...
r31848
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // update button tooltip text and CSS
updateButtons(startElement);
Denis Laxalde
hgweb: add a floating tooltip to invite on followlines action...
r31848
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var startId = parseInt(startElement.id.slice(1));
startElement.classList.add(lineSelectedCSSClass); // CSS
// remove this event listener
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsRemoveEventListener(lineSelectStart);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
//** event handler for "click" on the last line of the block */
function lineSelectEnd(e) {
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 var endElement = selectableParent(e.target.parentElement);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 if (endElement === null) {
// not a <span> (maybe <a>): abort, keeping event listener
// registered for other click with <span> target
return;
}
// remove this event listener
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsRemoveEventListener(lineSelectEnd);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // reset button tooltip text
resetButtons();
Denis Laxalde
hgweb: add a floating tooltip to invite on followlines action...
r31848
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // compute line range (startId, endId)
var endId = parseInt(endElement.id.slice(1));
av6
hgweb: use strict equals, remove non-breaking space in followlines.js...
r35157 if (endId === startId) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // clicked twice the same line, cancel and reset initial state
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // (CSS, event listener for selection start)
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 removeSelectedCSSClass();
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectStart);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 return;
}
var inviteElement = endElement;
if (endId < startId) {
var tmp = endId;
endId = startId;
startId = tmp;
inviteElement = startElement;
}
addSelectedCSSClass(startId - 1, endId -1); // CSS
// append the <div id="followlines"> element to last line of the
// selection block
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 var divAndButton = followlinesBox(targetUri, startId, endId, isHead);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var div = divAndButton[0],
button = divAndButton[1];
inviteElement.appendChild(div);
Denis Laxalde
hgweb: position the "followlines" box close to latest cursor position
r31849 // set position close to cursor (top-right)
positionTopRight(div, e);
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 // hide all buttons
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].classList.add('btn-followlines-hidden');
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
//** event handler for cancelling selection */
function cancel() {
// remove invite box
div.parentNode.removeChild(div);
// restore initial event listeners
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectStart);
buttonsRemoveEventListener(cancel);
for (var i = 0; i < followlinesButtons.length; i++) {
followlinesButtons[i].classList.remove('btn-followlines-hidden');
}
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // remove styles on selected lines
removeSelectedCSSClass();
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 resetButtons();
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
// bind cancel event to click on <button>
button.addEventListener('click', cancel);
// as well as on an click on any source line
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(cancel);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 }
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectEnd);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
}
Denis Laxalde
hgweb: re-implement followlines UI selection using buttons...
r33390 buttonsAddEventListener(lineSelectStart);
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785
//** return a <div id="followlines"> and inner cancel <button> elements */
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 function followlinesBox(targetUri, fromline, toline, isHead) {
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 // <div id="followlines">
var div = document.createElement('div');
div.id = 'followlines';
// <div class="followlines-cancel">
var buttonDiv = document.createElement('div');
buttonDiv.classList.add('followlines-cancel');
// <button>x</button>
var button = document.createElement('button');
button.textContent = 'x';
buttonDiv.appendChild(button);
div.appendChild(buttonDiv);
// <div class="followlines-link">
var aDiv = document.createElement('div');
aDiv.classList.add('followlines-link');
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940 aDiv.textContent = 'follow history of lines ' + fromline + ':' + toline + ':';
var linesep = document.createElement('br');
aDiv.appendChild(linesep);
// link to "ascending" followlines
var aAsc = document.createElement('a');
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 var url = targetUri + '?patch=&linerange=' + fromline + ':' + toline;
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940 aAsc.setAttribute('href', url);
Denis Laxalde
hgweb: change text of followlines links to "older / newer"...
r32071 aAsc.textContent = 'older';
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940 aDiv.appendChild(aAsc);
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070
if (!isHead) {
var sep = document.createTextNode(' / ');
aDiv.appendChild(sep);
// link to "descending" followlines
var aDesc = document.createElement('a');
aDesc.setAttribute('href', url + '&descend=');
Denis Laxalde
hgweb: change text of followlines links to "older / newer"...
r32071 aDesc.textContent = 'newer';
Denis Laxalde
hgweb: do not show "descending" link in followlines UI for filelog heads...
r32070 aDiv.appendChild(aDesc);
}
Denis Laxalde
hgweb: add a link to followlines in descending direction...
r31940
Denis Laxalde
hgweb: rename linerangelog.js as followlines.js...
r31785 div.appendChild(aDiv);
return [div, button];
}
}, false);