123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- // Copyright (C) 2010 Ojan Vafai. All rights reserved.
- // Copyright (C) 2010 Adam Barth. All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are met:
- //
- // 1. Redistributions of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- //
- // 2. Redistributions in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- //
- // THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
- // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- // DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
- // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- // DAMAGE.
- WebKitCommitters = (function() {
- var COMMITTERS_URL = 'https://svn.webkit.org/repository/webkit/trunk/Tools/Scripts/webkitpy/common/config/contributors.json';
- var m_committers;
- function parseType(key, records, type) {
- for (var name in records) {
- var record = records[name];
- m_committers.push({
- name: name,
- emails: record.emails,
- irc: record.nicks,
- type: type,
- });
- }
- }
- function parseCommittersPy(text) {
- var parsedContributorsJSON = JSON.parse(text);
- m_committers = [];
- var records = text.split('\n');
- parseType('Committer', parsedContributorsJSON['Committers'], 'c');
- parseType('Reviewer', parsedContributorsJSON['Reviewers'], 'r');
- parseType('Contributor', parsedContributorsJSON['Contributors']);
- }
- function loadCommitters(callback) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', COMMITTERS_URL);
- xhr.onload = function() {
- parseCommittersPy(xhr.responseText);
- callback();
- };
- xhr.onerror = function() {
- console.log('Unable to load contributors.json');
- callback();
- };
- xhr.send();
- }
- function getCommitters(callback) {
- if (m_committers) {
- callback(m_committers);
- return;
- }
- loadCommitters(function() {
- callback(m_committers);
- });
- }
- return {
- "getCommitters": getCommitters
- };
- })();
- (function() {
- var SINGLE_EMAIL_INPUTS = ['email1', 'email2', 'requester', 'requestee', 'assigned_to'];
- var EMAIL_INPUTS = SINGLE_EMAIL_INPUTS.concat(['cc', 'newcc', 'new_watchedusers']);
- var m_menus = {};
- var m_focusedInput;
- var m_committers;
- var m_prefix;
- var m_selectedIndex;
- function contactsMatching(prefix) {
- var list = [];
- if (!prefix)
- return list;
- for (var i = 0; i < m_committers.length; i++) {
- if (isMatch(m_committers[i], prefix))
- list.push(m_committers[i]);
- }
- return list;
- }
- function startsWith(str, prefix) {
- return str.toLowerCase().indexOf(prefix.toLowerCase()) == 0;
- }
- function startsWithAny(arry, prefix) {
- for (var i = 0; i < arry.length; i++) {
- if (startsWith(arry[i], prefix))
- return true;
- }
- return false;
- }
- function isMatch(contact, prefix) {
- if (startsWithAny(contact.emails, prefix))
- return true;
- if (contact.irc && startsWithAny(contact.irc, prefix))
- return true;
- var names = contact.name.split(' ');
- for (var i = 0; i < names.length; i++) {
- if (startsWith(names[i], prefix))
- return true;
- }
-
- return false;
- }
- function isMenuVisible() {
- return getMenu().style.display != 'none';
- }
- function showMenu(shouldShow) {
- getMenu().style.display = shouldShow ? '' : 'none';
- }
- function updateMenu() {
- var newPrefix = m_focusedInput.value;
- if (newPrefix) {
- newPrefix = newPrefix.slice(getStart(), getEnd());
- newPrefix = newPrefix.replace(/^\s+/, '');
- newPrefix = newPrefix.replace(/\s+$/, '');
- }
- if (m_prefix == newPrefix)
- return;
- m_prefix = newPrefix;
- var contacts = contactsMatching(m_prefix);
- if (contacts.length == 0 || contacts.length == 1 && contacts[0].emails[0] == m_prefix) {
- showMenu(false);
- return;
- }
- var html = [];
- for (var i = 0; i < contacts.length; i++) {
- var contact = contacts[i];
- html.push('<div style="padding:1px 2px;" ' + 'email=' +
- contact.emails[0] + '>' + contact.name + ' - ' + contact.emails[0]);
- if (contact.irc)
- html.push(' (:' + contact.irc + ')');
- if (contact.type)
- html.push(' (' + contact.type + ')');
- html.push('</div>');
- }
- getMenu().innerHTML = html.join('');
- selectItem(0);
- showMenu(true);
- }
- function getIndex(item) {
- for (var i = 0; i < getMenu().childNodes.length; i++) {
- if (item == getMenu().childNodes[i])
- return i;
- }
- console.error("Couldn't find item.");
- }
- function getMenu() {
- return m_menus[m_focusedInput.name];
- }
- function createMenu(name, input) {
- if (!m_menus[name]) {
- var menu = document.createElement('div');
- menu.style.cssText =
- "position:absolute;border:1px solid black;background-color:white;-webkit-box-shadow:3px 3px 3px #888;";
- menu.style.minWidth = m_focusedInput.offsetWidth + 'px';
- m_focusedInput.parentNode.insertBefore(menu, m_focusedInput.nextSibling);
- menu.addEventListener('mousedown', function(e) {
- selectItem(getIndex(e.target));
- e.preventDefault();
- }, false);
- menu.addEventListener('mouseup', function(e) {
- if (m_selectedIndex == getIndex(e.target))
- insertSelectedItem();
- }, false);
-
- m_menus[name] = menu;
- }
- }
- function getStart() {
- var index = m_focusedInput.value.lastIndexOf(',', m_focusedInput.selectionStart - 1);
- if (index == -1)
- return 0;
- return index + 1;
- }
- function getEnd() {
- var index = m_focusedInput.value.indexOf(',', m_focusedInput.selectionStart);
- if (index == -1)
- return m_focusedInput.value.length;
- return index;
- }
- function getItem(index) {
- return getMenu().childNodes[index];
- }
- function selectItem(index) {
- if (index < 0 || index >= getMenu().childNodes.length)
- return;
- if (m_selectedIndex != undefined) {
- getItem(m_selectedIndex).style.backgroundColor = '';
- getItem(m_selectedIndex).style.color = '';
- }
- getItem(index).style.backgroundColor = '#039';
- getItem(index).style.color = 'white';
- m_selectedIndex = index;
- }
- function insertSelectedItem() {
- var selectedEmail = getItem(m_selectedIndex).getAttribute('email');
- var oldValue = m_focusedInput.value;
- var newValue = oldValue.slice(0, getStart()) + selectedEmail + oldValue.slice(getEnd());
- if (SINGLE_EMAIL_INPUTS.indexOf(m_focusedInput.name) == -1 &&
- newValue.charAt(newValue.length - 1) != ',')
- newValue = newValue + ',';
- m_focusedInput.value = newValue;
- showMenu(false);
- }
- function handleKeyDown(e) {
- if (!isMenuVisible())
- return;
- switch (e.keyIdentifier) {
- case 'Up':
- selectItem(m_selectedIndex - 1);
- e.preventDefault();
- break;
-
- case 'Down':
- selectItem(m_selectedIndex + 1);
- e.preventDefault();
- break;
-
- case 'Enter':
- insertSelectedItem();
- e.preventDefault();
- break;
- }
- }
- function handleKeyUp(e) {
- if (e.keyIdentifier == 'Enter')
- return;
- if (m_focusedInput.selectionStart == m_focusedInput.selectionEnd)
- updateMenu();
- else
- showMenu(false);
- }
- function enableAutoComplete(input) {
- m_focusedInput = input;
- if (!getMenu()) {
- createMenu(m_focusedInput.name);
- // Turn off autocomplete to avoid showing the browser's dropdown menu.
- m_focusedInput.setAttribute('autocomplete', 'off');
- m_focusedInput.addEventListener('keyup', handleKeyUp, false);
- m_focusedInput.addEventListener('keydown', handleKeyDown, false);
- m_focusedInput.addEventListener('blur', function() {
- showMenu(false);
- m_prefix = null;
- m_selectedIndex = 0;
- }, false);
- // Turn on autocomplete on submit to avoid breaking autofill on back/forward navigation.
- m_focusedInput.form.addEventListener("submit", function() {
- m_focusedInput.setAttribute("autocomplete", "on");
- }, false);
- }
-
- updateMenu();
- }
- for (var i = 0; i < EMAIL_INPUTS.length; i++) {
- var field = document.getElementsByName(EMAIL_INPUTS[i])[0];
- if (field)
- field.addEventListener("focus", function(e) { enableAutoComplete(e.target); }, false);
- }
- WebKitCommitters.getCommitters(function (committers) {
- m_committers = committers;
- });
- })();
|