зеркало из https://github.com/mozilla/phonebook.git
First round of massive refactoring
git-svn-id: http://svn.mozilla.org/projects/phonebook/trunk@50675 4eb1ac78-321c-0410-a911-ec516a8615a5
This commit is contained in:
Родитель
26709f8724
Коммит
fff2cad47f
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$tree_config = array(
|
||||||
|
"ldap" => array(
|
||||||
|
"search_base" => "o=com, dc=mozilla",
|
||||||
|
"search_filter" => "mail=*",
|
||||||
|
"search_attributes" => array(
|
||||||
|
"cn", "manager", "title", "mail", "employeeType"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
function tree_view_process_entry($person) {
|
||||||
|
return array(
|
||||||
|
"title" => !empty($person["title"][0]) ? $person["title"][0] : null,
|
||||||
|
"name" => !empty($person["cn"][0]) ? $person["cn"][0] : null,
|
||||||
|
"disabled" => isset($person["employeetype"]) ?
|
||||||
|
strpos($person["employeetype"][0], 'D') !== FALSE:
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tree_view_roots() {
|
||||||
|
return array(
|
||||||
|
"mitchell@mozilla.com", "lilly@mozilla.com"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tree_view_item($email, $leaf=FALSE) {
|
||||||
|
global $everyone;
|
||||||
|
$email = htmlspecialchars($email);
|
||||||
|
$id = str_replace('@', "-at-", $email);
|
||||||
|
$name = htmlspecialchars($everyone[$email]["name"]);
|
||||||
|
$title = htmlspecialchars($everyone[$email]["title"]);
|
||||||
|
$leaf = $leaf ? " leaf" : '';
|
||||||
|
$disabled = $everyone[$email]["disabled"] ? " disabled" : '';
|
||||||
|
return "<li id=\"$id\" class=\"hr-node expanded$leaf$disabled\">".
|
||||||
|
"<a href=\"#search/$email\" class=\"hr-link\">$name</a> ".
|
||||||
|
"<span class=\"title\">$title</span>".
|
||||||
|
"</li>";
|
||||||
|
}
|
||||||
|
|
|
@ -178,17 +178,16 @@ a:hover {
|
||||||
/* Card view */
|
/* Card view */
|
||||||
|
|
||||||
#results {
|
#results {
|
||||||
overflow: auto;
|
margin: 0 1em 1em;
|
||||||
width: 62em;
|
text-align: center;
|
||||||
margin: 0 auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vcard {
|
.vcard {
|
||||||
display: block;
|
text-align: left;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 31em;
|
width: 31em;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
margin-top: 1em;
|
margin: 1em 1em 0 1em;
|
||||||
}
|
}
|
||||||
.vcard .header,
|
.vcard .header,
|
||||||
.vcard .body,
|
.vcard .body,
|
||||||
|
@ -345,14 +344,6 @@ a:hover {
|
||||||
/* Editing view */
|
/* Editing view */
|
||||||
|
|
||||||
form#edit {
|
form#edit {
|
||||||
/*width: 85%;
|
|
||||||
margin: 0 auto 1em auto;
|
|
||||||
padding: 1em;
|
|
||||||
background-color: #FFF;
|
|
||||||
border-radius: 0.5em;
|
|
||||||
-moz-border-radius: 0.5em;
|
|
||||||
-webkit-border-radius: 0.5em;
|
|
||||||
font-size: 0.75em;*/
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
edit.php
2
edit.php
|
@ -97,6 +97,6 @@ if (!empty($_POST)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$user_data = clean_userdata($user_data);
|
$user_data = clean_userdata($user_data);
|
||||||
$managerlist = manager_list($ldapconn);
|
$managerlist = everyone_list($ldapconn);
|
||||||
|
|
||||||
require_once 'templates/edit.php';
|
require_once 'templates/edit.php';
|
||||||
|
|
148
face.php
148
face.php
|
@ -1,148 +0,0 @@
|
||||||
<?php
|
|
||||||
require_once('templates/header.php'); ?>
|
|
||||||
<div id="results">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="overlay">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
Function.prototype.lazify = function() {
|
|
||||||
var cache = {};
|
|
||||||
return this.wrap(function(original, x) {
|
|
||||||
return cache[x] ? cache[x] : (cache[x] = original(x));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
String.toInt = parseInt.methodize();
|
|
||||||
|
|
||||||
Number.emToPx = function(x) {
|
|
||||||
var div = new Element("div").setStyle({
|
|
||||||
position: "absolute", margin: "0", padding: "0", visibility: "none",
|
|
||||||
width: x + "em", height: "9px", top: "-100000em", left: "-100000em"
|
|
||||||
});
|
|
||||||
$(document.body).insert(div);
|
|
||||||
var px = div.getWidth();
|
|
||||||
div.remove();
|
|
||||||
return px;
|
|
||||||
}.lazify();
|
|
||||||
|
|
||||||
$(document).observe("keypress", function(e) {
|
|
||||||
if ((e.charCode || e.keyCode) == 47) { // KEY_SLASH
|
|
||||||
$("text").focus(); e.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).observe("dom:loaded", function() {
|
|
||||||
$("phonebook-search").addClassName("large");
|
|
||||||
|
|
||||||
var adjustLayout = function() {
|
|
||||||
var img = $$("img.wall-photo");
|
|
||||||
img = img.length ? img[0] : null;
|
|
||||||
var width = 140;
|
|
||||||
if (img) {
|
|
||||||
width = img.width +
|
|
||||||
$w("paddingLeft marginLeft paddingRight marginRight").map(function(x) {
|
|
||||||
return img.getStyle(x).replace("px", '').toInt();
|
|
||||||
}).inject(function(x, y) { return x + y; });
|
|
||||||
} else {
|
|
||||||
width += Number.emToPx(5);
|
|
||||||
}
|
|
||||||
var photos = 4;
|
|
||||||
Event.observe(Prototype.resizeTarget, "resize", readjust);
|
|
||||||
function readjust() {
|
|
||||||
var c = Math.floor(document.viewport.getWidth() / width);
|
|
||||||
console.log(c);
|
|
||||||
if (photos != c && c != 0) {
|
|
||||||
$("results").setStyle({width: ((photos = c) * width) + "px"});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
adjustLayout();
|
|
||||||
$("results").setStyle({width: "880px"});
|
|
||||||
$("menu").down("a.wall").addClassName("selected");
|
|
||||||
|
|
||||||
$(document).observe("hash:changed", function(e) {
|
|
||||||
$("text").value = e.memo.hash.replace("search/", '');
|
|
||||||
startSearch();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("phonebook-search").observe("submit", function(e) {
|
|
||||||
window.location.hash = "#search/" + $F("text");
|
|
||||||
e.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("overlay").observe("click", function(e) {
|
|
||||||
if (e.element() == this) {
|
|
||||||
$(document.body).removeClassName("lightbox");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Event.observe(Prototype.resizeTarget, "resize", function() {
|
|
||||||
$$("div.vcard").invoke("verticallyCenter");
|
|
||||||
});
|
|
||||||
|
|
||||||
var stoppedResizing = false;
|
|
||||||
if (window.location.hash.startsWith("#search/")) {
|
|
||||||
$(document).fire("hash:changed", {hash: window.location.hash.substring(1)});
|
|
||||||
} else {
|
|
||||||
$("header").verticallyCenter();
|
|
||||||
Event.observe(Prototype.resizeTarget, "resize", centralize);
|
|
||||||
$("text").focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function centralize() {
|
|
||||||
if (!arguments.callee.stop) {
|
|
||||||
$("header").verticallyCenter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startSearch() {
|
|
||||||
if (!stoppedResizing) {
|
|
||||||
centralize.stop = true;
|
|
||||||
stoppedResizing = true;
|
|
||||||
$("header").stopVerticallyCentering();
|
|
||||||
$("phonebook-search").removeClassName("large");
|
|
||||||
}
|
|
||||||
$("phonebook-search").request({
|
|
||||||
parameters: {format: "json"},
|
|
||||||
onSuccess: function onSuccess(r) {
|
|
||||||
$("text").releaseFocus();
|
|
||||||
$("results").update('');
|
|
||||||
r.responseText.evalJSON().each(function(person) {
|
|
||||||
var container = new Element("div").addClassName("photo-frame");
|
|
||||||
var face = new Element("img", {
|
|
||||||
src: person.picture + "&type=thumb", "class": "wall-photo"
|
|
||||||
}).observe("click", function() { showPerson(person.dn); });
|
|
||||||
var name = new Element("span").update(person.cn);
|
|
||||||
container.insert(name).insert(face);
|
|
||||||
if (person.employeetype.indexOf("DISABLED") != -1) {
|
|
||||||
container.addClassName("disabled");
|
|
||||||
}
|
|
||||||
$("results").insert(container);
|
|
||||||
});
|
|
||||||
adjustLayout();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPerson(dn) {
|
|
||||||
$("phonebook-search").request({
|
|
||||||
parameters: {format: "html", query: dn.dnToEmail()},
|
|
||||||
onSuccess: function onSuccess(r) {
|
|
||||||
$(document.body).addClassName("lightbox");
|
|
||||||
var close = new Element("div").observe("click", function(e) {
|
|
||||||
$(document.body).removeClassName("lightbox");
|
|
||||||
}).addClassName("close-button").writeAttribute("title", "Close");
|
|
||||||
$("overlay").update('').update(r.responseText).
|
|
||||||
down("div.vcard").verticallyCenter().
|
|
||||||
down("div.header").insert(close);
|
|
||||||
$("overlay").down(".vcard p.manager a").observe("click", function() {
|
|
||||||
$(document.body).removeClassName("lightbox");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<?php require_once('templates/footer.php'); ?>
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
require_once('templates/header.php'); ?>
|
||||||
|
<div id="results">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="overlay">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="js/view-faces.js"></script>
|
||||||
|
|
||||||
|
<?php require_once('templates/footer.php'); ?>
|
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function get_filters() {
|
||||||
|
return array(
|
||||||
|
"employeetype" => "employee_status",
|
||||||
|
"manager" => "get_manager",
|
||||||
|
"physicaldeliveryofficename" => "location_formatter",
|
||||||
|
"mobile" => "mobile_normalizer",
|
||||||
|
"im" => "mobile_normalizer",
|
||||||
|
"description" => "wikilinks",
|
||||||
|
"other" => "wikilinks"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function employee_status($status) {
|
||||||
|
global $orgs, $emp_type;
|
||||||
|
$current_org = $current_emp_type = "";
|
||||||
|
if ($status != "") {
|
||||||
|
$current_org = $status[0];
|
||||||
|
$current_emp_type = $status[1];
|
||||||
|
}
|
||||||
|
if ($status == "DISABLED") {
|
||||||
|
return array('DISABLED');
|
||||||
|
} else {
|
||||||
|
if (array_key_exists($current_org, $orgs) &&
|
||||||
|
array_key_exists($current_emp_type, $emp_type)) {
|
||||||
|
return array($orgs[$current_org], $emp_type[$current_emp_type]);
|
||||||
|
} else {
|
||||||
|
return array('Unknown');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_manager($manager_dn) {
|
||||||
|
global $ldapconn, $memcache_on, $memcache;
|
||||||
|
if ($memcache_on && ($manager = $memcache->get($manager_dn))) {
|
||||||
|
return $manager;
|
||||||
|
}
|
||||||
|
$manager_search = @ldap_search($ldapconn, $manager_dn, '(mail=*)', array('cn','mail'));
|
||||||
|
if (ldap_errno($ldapconn) == 32) { // No manager found
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ($manager_search) {
|
||||||
|
$entry = ldap_first_entry($ldapconn, $manager_search);
|
||||||
|
if ($entry) {
|
||||||
|
$attrs = ldap_get_attributes($ldapconn, $entry);
|
||||||
|
$manager = array(
|
||||||
|
"cn" => $attrs['cn'][0],
|
||||||
|
"dn" => $manager_dn
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$manager = null;
|
||||||
|
}
|
||||||
|
if ($memcache_on) {
|
||||||
|
$memcache->set($manager_dn, $manager);
|
||||||
|
}
|
||||||
|
return $manager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function location_formatter($location) {
|
||||||
|
return str_replace(":::", "/", $location);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mobile_normalizer($m) {
|
||||||
|
if (!is_array($m)) {
|
||||||
|
$m = array($m);
|
||||||
|
}
|
||||||
|
return array_map("wikilinks", $m);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wikilinks($string) {
|
||||||
|
$matches = array();
|
||||||
|
$string = nl2br(htmlspecialchars($string));
|
||||||
|
if (preg_match_all('/\[(.+?)(?:\s(.+?))?\]/', $string, $matches)) {
|
||||||
|
foreach ($matches[1] as $key => $value) {
|
||||||
|
if (!empty($matches[2][$key])) {
|
||||||
|
$title = $matches[2][$key];
|
||||||
|
} else {
|
||||||
|
$title = $value;
|
||||||
|
}
|
||||||
|
$string = str_replace(
|
||||||
|
$matches[0][$key],
|
||||||
|
'<a href="'. $value .'">'. $title .'</a>',
|
||||||
|
$string
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,83 +57,6 @@ function search_users($ldapconn, $search) {
|
||||||
return ldap_get_entries($ldapconn, $search);
|
return ldap_get_entries($ldapconn, $search);
|
||||||
}
|
}
|
||||||
|
|
||||||
function employee_status($status) {
|
|
||||||
global $orgs, $emp_type;
|
|
||||||
$current_org = $current_emp_type = "";
|
|
||||||
if ($status != "") {
|
|
||||||
$current_org = $status[0];
|
|
||||||
$current_emp_type = $status[1];
|
|
||||||
}
|
|
||||||
if ($status == "DISABLED") {
|
|
||||||
return array('DISABLED');
|
|
||||||
} else {
|
|
||||||
if (array_key_exists($current_org, $orgs) &&
|
|
||||||
array_key_exists($current_emp_type, $emp_type)) {
|
|
||||||
return array($orgs[$current_org], $emp_type[$current_emp_type]);
|
|
||||||
} else {
|
|
||||||
return array('Unknown');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_manager($manager_dn) {
|
|
||||||
global $ldapconn, $memcache_on, $memcache;
|
|
||||||
if ($memcache_on && ($manager = $memcache->get($manager_dn))) {
|
|
||||||
return $manager;
|
|
||||||
}
|
|
||||||
$manager_search = @ldap_search($ldapconn, $manager_dn, '(mail=*)', array('cn','mail'));
|
|
||||||
if (ldap_errno($ldapconn) == 32) { // No manager found
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if ($manager_search) {
|
|
||||||
$entry = ldap_first_entry($ldapconn, $manager_search);
|
|
||||||
if ($entry) {
|
|
||||||
$attrs = ldap_get_attributes($ldapconn, $entry);
|
|
||||||
$manager = array(
|
|
||||||
"cn" => $attrs['cn'][0],
|
|
||||||
"dn" => $manager_dn
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$manager = null;
|
|
||||||
}
|
|
||||||
if ($memcache_on) {
|
|
||||||
$memcache->set($manager_dn, $manager);
|
|
||||||
}
|
|
||||||
return $manager;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function wikilinks($string) {
|
|
||||||
$matches = array();
|
|
||||||
$string = nl2br(htmlspecialchars($string));
|
|
||||||
if (preg_match_all('/\[(.+?)(?:\s(.+?))?\]/', $string, $matches)) {
|
|
||||||
foreach ($matches[1] as $key => $value) {
|
|
||||||
if (!empty($matches[2][$key])) {
|
|
||||||
$title = $matches[2][$key];
|
|
||||||
} else {
|
|
||||||
$title = $value;
|
|
||||||
}
|
|
||||||
$string = str_replace(
|
|
||||||
$matches[0][$key],
|
|
||||||
'<a href="'. $value .'">'. $title .'</a>',
|
|
||||||
$string
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function location_formatter($location) {
|
|
||||||
return str_replace(":::", "/", $location);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mobile_normalizer($m) {
|
|
||||||
if (!is_array($m)) {
|
|
||||||
$m = array($m);
|
|
||||||
}
|
|
||||||
return array_map("wikilinks", $m);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The logic here is that failure to find out who has permissions to edit
|
// The logic here is that failure to find out who has permissions to edit
|
||||||
// someone else's entry implies that you aren't one of them.
|
// someone else's entry implies that you aren't one of them.
|
||||||
function is_phonebook_admin($ldapconn, $mail) {
|
function is_phonebook_admin($ldapconn, $mail) {
|
||||||
|
@ -176,7 +99,7 @@ function clean_userdata($user_data) {
|
||||||
return $user_data;
|
return $user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function manager_list($ldapconn) {
|
function everyone_list($ldapconn) {
|
||||||
$search = ldap_search($ldapconn, 'o=com,dc=mozilla', 'objectClass=mozComPerson');
|
$search = ldap_search($ldapconn, 'o=com,dc=mozilla', 'objectClass=mozComPerson');
|
||||||
ldap_sort($ldapconn, $search, 'cn');
|
ldap_sort($ldapconn, $search, 'cn');
|
||||||
return ldap_get_entries($ldapconn, $search);
|
return ldap_get_entries($ldapconn, $search);
|
||||||
|
|
191
index-json.html
191
index-json.html
|
@ -1,191 +0,0 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<title>Phonebook</title>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
|
|
||||||
<script src="./js/prototype.js" type="text/javascript"></script>
|
|
||||||
<!--<script src="./js/jquery-1.3.2.min.js" type="text/javascript"></script>-->
|
|
||||||
<link rel="stylesheet" type="text/css" href="./css/style.css"/>
|
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="./favicon.ico" />
|
|
||||||
|
|
||||||
<script type='text/javascript'>
|
|
||||||
// jQuery.noConflict();
|
|
||||||
if (!window.console) {
|
|
||||||
window.console = {};
|
|
||||||
window.console.log = Prototype.emptyFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a dn to an email address
|
|
||||||
String.prototype.toEmail = function String_toEmail() {
|
|
||||||
var m = this.match(/mail=(\w+@mozilla.*),o=/);
|
|
||||||
return (m ? m[1] : null);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implement onhashchange support
|
|
||||||
(function() {
|
|
||||||
var hash = window.location.hash;
|
|
||||||
var fire = function(str) {
|
|
||||||
$(document).fire("hash:changed", { hash: str.substring(1) });
|
|
||||||
};
|
|
||||||
var pe = new PeriodicalExecuter(function() {
|
|
||||||
var newHash = window.location.hash;
|
|
||||||
if (newHash != hash) {
|
|
||||||
fire(newHash);
|
|
||||||
hash = newHash;
|
|
||||||
}
|
|
||||||
}, 1);
|
|
||||||
})();
|
|
||||||
|
|
||||||
$(document).observe("keypress", function(e) {
|
|
||||||
if ((e.charCode || e.keyCode) == 47) { // KEY_SLASH
|
|
||||||
$("text").focus();
|
|
||||||
e.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).observe("dom:loaded", function() {
|
|
||||||
Prototype.Browser.WebKit && $("text").writeAttribute({
|
|
||||||
type: "search", results: 5
|
|
||||||
}) && $("search").hide(); // Just this one special treatment, Safari
|
|
||||||
|
|
||||||
var fillAndSearch = function() {
|
|
||||||
$("text").value = window.location.hash.replace("#search/", '');
|
|
||||||
startSearch();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (window.location.hash.startsWith("#search/")) {
|
|
||||||
fillAndSearch();
|
|
||||||
} else {
|
|
||||||
$("text").focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).observe("hash:changed", fillAndSearch);
|
|
||||||
|
|
||||||
$("phonebook-search").observe("submit", function(e) {
|
|
||||||
window.location.hash = "#search/" + $F("text");
|
|
||||||
startSearch(); e.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
var listify = function(a) {
|
|
||||||
return $A(a).map(function(x) {
|
|
||||||
return "<li>" + x + "</li>";
|
|
||||||
}).join('');
|
|
||||||
};
|
|
||||||
var emailLinkify = function(s) {
|
|
||||||
return '<li><a class="value" href="mailto:#{s}">#{s}</a></li>'.interpolate({s: s});
|
|
||||||
};
|
|
||||||
var processors = $H({
|
|
||||||
"email": emailLinkify,
|
|
||||||
"emailalias": emailLinkify.wrap(function(original, email) {
|
|
||||||
email = Object.isString(email) ? [email] : $A(email);
|
|
||||||
return email.map(original);
|
|
||||||
}),
|
|
||||||
"employeetype": function(l) { return l.join(", "); },
|
|
||||||
"im": listify.wrap(function(original, im) {
|
|
||||||
return im ? ('<ul class="im">' + original(im) + '</ul>') : '';
|
|
||||||
}),
|
|
||||||
"mobile": listify.wrap(function(original, list) {
|
|
||||||
return '<ul class="telecommunications">' +
|
|
||||||
original(list).replace(/<li>/, '<li class="tel">') + '</ul>';
|
|
||||||
}),
|
|
||||||
"description": function(s) {
|
|
||||||
return '<div class="note">I work on: #{s}</div>'.interpolate({s: s});
|
|
||||||
},
|
|
||||||
"other": function(s) {
|
|
||||||
return '<div class="other">' + s + '</div>';
|
|
||||||
},
|
|
||||||
"manager": function(m) {
|
|
||||||
return '<p class="manager">Manager: <a href="#search/#{email}">#{name}</a></p>'.interpolate({
|
|
||||||
email: m.dn.toEmail(),
|
|
||||||
name: m.cn
|
|
||||||
});
|
|
||||||
},
|
|
||||||
"telephonenumber": function(x) { return "ext. " + x; },
|
|
||||||
"bugzillaemail": function(s) {
|
|
||||||
return '<ul class="bugmail"><li><a title="Bugmail">#{s}</a></li></ul>'.interpolate({s: s});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function startSearch() {
|
|
||||||
$("phonebook-search").request({onSuccess: function onSuccess(r) {
|
|
||||||
$("results").update('');
|
|
||||||
var results = r.responseText.evalJSON().each(function entryEach(e) {
|
|
||||||
var code = process(e);
|
|
||||||
var vcard = new Element("div", {"class":"vcard"}).update(code);
|
|
||||||
$("results").insert(vcard);
|
|
||||||
});
|
|
||||||
$("text").blur();
|
|
||||||
if (results.length == 0) {
|
|
||||||
$("results").update(
|
|
||||||
'<div style="text-align: center; margin-top: 5em;">' +
|
|
||||||
'<img src="./img/ohnoes.jpg" />' +
|
|
||||||
'<h2>OH NOES! No ones were foundz.</h2>' +
|
|
||||||
'</div>'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}});
|
|
||||||
};
|
|
||||||
|
|
||||||
function process(entry) {
|
|
||||||
entry.email = [entry.dn.toEmail()];
|
|
||||||
entry.picture = '<a href="#{url}" class="photo" target="_blank"><img class="photo" src="#{url}&type=thumb" alt="Photo of #{name}" /></a>'.interpolate({
|
|
||||||
url: entry.picture,
|
|
||||||
name: entry.cn
|
|
||||||
});
|
|
||||||
console.log("JSON preprocessing done");
|
|
||||||
|
|
||||||
processors.each(function processorEach(pair) {
|
|
||||||
if (entry[pair.key])
|
|
||||||
entry[pair.key] = pair.value(entry[pair.key]);
|
|
||||||
});
|
|
||||||
console.log("JSON postprocessing done");
|
|
||||||
return template(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
function template(person) {
|
|
||||||
return [
|
|
||||||
'<div class="header"><h2 class="fn">#{cn}</h2></div>',
|
|
||||||
'<div class="body">#{picture}',
|
|
||||||
'<div class="employee">',
|
|
||||||
'<p class="title">#{title}</p>',
|
|
||||||
'<p class="employee-type">#{employeetype}</p>',
|
|
||||||
'#{manager}',
|
|
||||||
'</div>',
|
|
||||||
'<ul class="adr"><li>#{telephonenumber} @ ',
|
|
||||||
'<span class="locality">#{physicaldeliveryofficename}</span>',
|
|
||||||
'</li></ul>',
|
|
||||||
'#{mobile}',
|
|
||||||
'<ul class="email">#{email}#{emailalias}</ul>',
|
|
||||||
'#{bugzillaemail}',
|
|
||||||
'#{im}',
|
|
||||||
'#{description}',
|
|
||||||
'#{other}',
|
|
||||||
'</div><div class="footer"></div>'
|
|
||||||
].join('').interpolate(person);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="header">
|
|
||||||
<form action="search.php" method="get" id="phonebook-search">
|
|
||||||
<h1>Phonebook</h1>
|
|
||||||
<div id="search-region">
|
|
||||||
<input type="text" name="query" id="text" />
|
|
||||||
<input type="submit" value="Search" id="search" />
|
|
||||||
</div>
|
|
||||||
<ul id="menu">
|
|
||||||
<li><a href="./#search/*">Everyone</a></li>
|
|
||||||
<li><a href="https://intranet.mozilla.org/">Intranet</a></li>
|
|
||||||
<li><a href="https://intranet.mozilla.org/OfficeLocations">Offices</a></li>
|
|
||||||
<li class="edit"><a href="edit.php" id="edit-entry">Edit My Entry</a></li>
|
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div id="results">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
86
index.php
86
index.php
|
@ -6,89 +6,5 @@ require_once('templates/header.php');
|
||||||
<div id="results">
|
<div id="results">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript" src="js/view-cards.js"></script>
|
||||||
Function.prototype.lazify = function() {
|
|
||||||
var cache = {};
|
|
||||||
return this.wrap(function(original, x) {
|
|
||||||
return cache[x] ? cache[x] : (cache[x] = original(x));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Number.emToPx = function(x) {
|
|
||||||
var div = new Element("div").setStyle({
|
|
||||||
position: "absolute", margin: "0", padding: "0", visibility: "none",
|
|
||||||
width: x + "em", height: "9px", top: "-100000em", left: "-100000em"
|
|
||||||
});
|
|
||||||
$(document.body).insert(div);
|
|
||||||
var px = div.getWidth();
|
|
||||||
div.remove();
|
|
||||||
return px;
|
|
||||||
}.lazify();
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var cards = 2;
|
|
||||||
Event.observe(Prototype.resizeTarget, "resize", function() {
|
|
||||||
var c = Math.floor(document.viewport.getWidth() / Number.emToPx(1) / 31);
|
|
||||||
if (cards != c && c != 0) {
|
|
||||||
$("results").setStyle({width: ((cards = c) * 31) + "em"});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
$(document).observe("keypress", function(e) {
|
|
||||||
if ((e.charCode || e.keyCode) == 47) { // KEY_SLASH
|
|
||||||
$("text").focus(); e.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).observe("dom:loaded", function() {
|
|
||||||
$("menu").down("a.card").addClassName("selected");
|
|
||||||
$(document).observe("hash:changed", function(e) {
|
|
||||||
$("text").value = e.memo.hash.replace("search/", '');
|
|
||||||
startSearch();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("phonebook-search").observe("submit", function(e) {
|
|
||||||
e.stop();
|
|
||||||
window.location.hash = "#search/" + $F("text");
|
|
||||||
});
|
|
||||||
|
|
||||||
var stoppedResizing = false;
|
|
||||||
if (window.location.hash.startsWith("#search/")) {
|
|
||||||
$(document).fire("hash:changed", {hash: window.location.hash.substring(1)});
|
|
||||||
} else {
|
|
||||||
$("phonebook-search").addClassName("large");
|
|
||||||
$("header").verticallyCenter();
|
|
||||||
Event.observe(Prototype.resizeTarget, "resize", centralize);
|
|
||||||
$("text").focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function centralize() {
|
|
||||||
if (!arguments.callee.stop) {
|
|
||||||
$("header").verticallyCenter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startSearch() {
|
|
||||||
if (!$F("text").strip()) {
|
|
||||||
window.location = "./";
|
|
||||||
}
|
|
||||||
if (!stoppedResizing) {
|
|
||||||
centralize.stop = true;
|
|
||||||
stoppedResizing = true;
|
|
||||||
$("header").stopVerticallyCentering();
|
|
||||||
$("phonebook-search").removeClassName("large");
|
|
||||||
}
|
|
||||||
$("phonebook-search").request({onSuccess: function onSuccess(r) {
|
|
||||||
$("results").update('').update(r.responseText ||
|
|
||||||
'<div style="text-align: center; margin-top: 5em;">' +
|
|
||||||
'<img src="./img/ohnoes.jpg" />' +
|
|
||||||
'<h2>OH NOES! No ones were foundz.</h2>' +
|
|
||||||
'</div>'
|
|
||||||
);
|
|
||||||
$("text").releaseFocus();
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<?php require_once('templates/footer.php'); ?>
|
<?php require_once('templates/footer.php'); ?>
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
|
||||||
|
if (!window.console) {
|
||||||
|
window.console = {log: Prototype.emptyFunction};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement onhashchange support
|
||||||
|
(function() {
|
||||||
|
var hash = window.location.hash;
|
||||||
|
var fire = function(str) {
|
||||||
|
$(document).fire("hash:changed", { hash: str.substring(1) });
|
||||||
|
};
|
||||||
|
var pe = new PeriodicalExecuter(function() {
|
||||||
|
var newHash = window.location.hash;
|
||||||
|
if (newHash != hash) {
|
||||||
|
fire(newHash);
|
||||||
|
hash = newHash;
|
||||||
|
}
|
||||||
|
}, 1);
|
||||||
|
})();
|
||||||
|
|
||||||
|
Element.addMethods({
|
||||||
|
verticallyCenter: function(element, percentage) {
|
||||||
|
element = $(element);
|
||||||
|
if (!element.retrieve("originalMarginTop")) {
|
||||||
|
element.store("originalMarginTop", element.getStyle("marginTop"));
|
||||||
|
}
|
||||||
|
var offset = $(document).viewport.getHeight() - element.getHeight();
|
||||||
|
return element.setStyle({marginTop: (offset * (percentage || 0.4)) + "px"});
|
||||||
|
},
|
||||||
|
|
||||||
|
stopVerticallyCentering: function(element) {
|
||||||
|
element = $(element);
|
||||||
|
var original = element.getStorage().unset("originalMarginTop");
|
||||||
|
return element.setStyle({marginTop: original});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Force Gecko to redraw the blinking cursor
|
||||||
|
Element.addMethods("input", {
|
||||||
|
releaseFocus: function(element) {
|
||||||
|
$w("blur focus blur").each(function(method) { $(element)[method](); });
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Prototype.resizeTarget = document.onresize ? document : window;
|
||||||
|
|
||||||
|
Array.prototype.find = function find(selector) {
|
||||||
|
return this.filter(function(x) {
|
||||||
|
return x.match ? x.match(selector) : false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Show / hide throbbers accoring to Ajax requests
|
||||||
|
Ajax.Responders.register({
|
||||||
|
onCreate: function() { $("throbber").addClassName("loading"); },
|
||||||
|
onComplete: function() { $("throbber").removeClassName("loading"); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Search keyword persistence between different views
|
||||||
|
$(document).observe("dom:loaded", function() {
|
||||||
|
$$("#menu a.persist").each(function(link) {
|
||||||
|
link.store("originalLink", link.readAttribute("href"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(document).observe("hash:changed", function(e) {
|
||||||
|
$$("#menu a.persist").each(function(link) {
|
||||||
|
link.writeAttribute("href", link.retrieve("originalLink") + "#" + e.memo.hash);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Function.prototype.lazify = function() {
|
||||||
|
var cache = {};
|
||||||
|
return this.wrap(function(original, x) {
|
||||||
|
return cache[x] ? cache[x] : (cache[x] = original(x));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Number.emToPx = function(x) {
|
||||||
|
var div = new Element("div").setStyle({
|
||||||
|
position: "absolute", margin: "0", padding: "0", visibility: "none",
|
||||||
|
width: x + "em", height: "9px", top: "-100000em", left: "-100000em"
|
||||||
|
});
|
||||||
|
$(document.body).insert(div);
|
||||||
|
var px = div.getWidth();
|
||||||
|
div.remove();
|
||||||
|
return px;
|
||||||
|
}.lazify();
|
||||||
|
|
||||||
|
Number.prototype.emToPx = Number.emToPx.methodize();
|
||||||
|
String.prototype.toInt = window.parseInt.methodize();
|
||||||
|
|
||||||
|
// BehaviorManager allows encapsulation of event handlers that frequently need
|
||||||
|
// to be enabled or disabled due to change of state. Behaviors must be first
|
||||||
|
// registered with BehaviorManager.register().
|
||||||
|
var BehaviorManager = {
|
||||||
|
behaviors: {},
|
||||||
|
|
||||||
|
// `behaviors' is an object that must support three methods at minimal:
|
||||||
|
// `enable', `disable', and `fire'.
|
||||||
|
// * `enable' is called when a behavior is switched on.
|
||||||
|
// * `disable' is called when a behavior is switched off.
|
||||||
|
// * `fire' is called when the behavior must be executed immediately.
|
||||||
|
// If `fire' is not present, BehaviorManager assumes that a function called
|
||||||
|
// `observer' is present and calls it.
|
||||||
|
// Although not enforced by BehaviorManager, it is customary to name the
|
||||||
|
// event handler `observer".
|
||||||
|
// The `behaviors' object must not manipulate `_enabled', as it is used
|
||||||
|
// internally by BehaviorManager.
|
||||||
|
register: function(name, behaviors) {
|
||||||
|
this.behaviors[name] = behaviors;
|
||||||
|
this.behaviors[name]._enabled = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
enable: function(behavior, immediatelyFire) {
|
||||||
|
var name = behavior;
|
||||||
|
behavior = this.behaviors[behavior];
|
||||||
|
(behavior._enabled = true) && behavior.enable();
|
||||||
|
if (immediatelyFire) {
|
||||||
|
this.fire(name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Returns false if the behavior has already been disabled, otherwise true.
|
||||||
|
disable: function(behavior) {
|
||||||
|
behavior = this.behaviors[behavior];
|
||||||
|
if (behavior._enabled) {
|
||||||
|
behavior.disable();
|
||||||
|
behavior._enabled = false;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fire: function(behavior) {
|
||||||
|
behavior = this.behaviors[behavior];
|
||||||
|
(behavior.fire || behavior.observer).bind(behavior)();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If o is a string, it will be treated as an id.
|
||||||
|
// If o is an element, make sure the DOM is loaded.
|
||||||
|
// If o is a Selector, it will be a live set of nodes.
|
||||||
|
Function.prototype.toBehavior = function(o, event) {
|
||||||
|
return {
|
||||||
|
observer: this,
|
||||||
|
enable: o instanceof Selector ? function() {
|
||||||
|
o.findElements().uniq().invoke("observe", event, this.observer);
|
||||||
|
} : function() { Event.observe(o, event, this.observer); },
|
||||||
|
disable: o instanceof Selector ? function() {
|
||||||
|
o.findElements().uniq().invoke("stopObserving", event, this.observer);
|
||||||
|
} : function() { Event.stopObserving(o, event, this.observer); }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
BehaviorManager.register("slashSearch", function(e) {
|
||||||
|
if (e.findElement().identify() == "text") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((e.which || e.keyCode) == 47) { // KEY_SLASH
|
||||||
|
$("text").focus(); e.stop();
|
||||||
|
}
|
||||||
|
}.toBehavior(document, "keypress"));
|
||||||
|
|
||||||
|
BehaviorManager.register("submitOnEnter", function(e) {
|
||||||
|
e.stop();
|
||||||
|
window.location.hash = "#search/" + $F("text");
|
||||||
|
}.toBehavior("phonebook-search", "submit"));
|
||||||
|
|
||||||
|
BehaviorManager.register("centerHeader", {
|
||||||
|
attached: false, fire: function() {
|
||||||
|
this.observer.adjust = true;
|
||||||
|
this.observer();
|
||||||
|
},
|
||||||
|
|
||||||
|
observer: function(e) {
|
||||||
|
if (arguments.callee.adjust) { $("header").verticallyCenter(); }
|
||||||
|
},
|
||||||
|
|
||||||
|
enable: function() {
|
||||||
|
this.observer.adjust = true;
|
||||||
|
if (!this.attached) {
|
||||||
|
Event.observe(Prototype.resizeTarget, "resize", this.observer);
|
||||||
|
this.attached = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
this.observer.adjust = false;
|
||||||
|
$("header").stopVerticallyCentering();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Normally, you should simply mix in a method called `startSearch' and then
|
||||||
|
// call SearchManager.initialize() when DOM is loaded. For advanced examples,
|
||||||
|
// take a look at tree.js, which overrides everything but `initialize'.
|
||||||
|
var SearchManager = {
|
||||||
|
enabledBehaviorsOnInit: ["submitOnEnter"],
|
||||||
|
initialize: function() {
|
||||||
|
$(document).observe("hash:changed", this.onHashChange.bind(this));
|
||||||
|
this.onLoad();
|
||||||
|
this.enabledBehaviorsOnInit.each(function(b) {
|
||||||
|
BehaviorManager.enable(b);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onHashChange: function(e) {
|
||||||
|
console.log("hash");
|
||||||
|
console.log(this);
|
||||||
|
$("text").value = e.memo.hash.replace("search/", '');
|
||||||
|
this.startSearch.bind(this)();
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad: function() {
|
||||||
|
if (window.location.hash.startsWith("#search/")) {
|
||||||
|
$(document).fire("hash:changed", {
|
||||||
|
hash: window.location.hash.substring(1)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("phonebook-search").addClassName("large");
|
||||||
|
BehaviorManager.enable("centerHeader", true);
|
||||||
|
$("text").focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.dnToEmail = function() {
|
||||||
|
var m = this.match(/mail=(\w+@mozilla.*),o=/);
|
||||||
|
return (m ? m[1] : null);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
BehaviorManager.enable("slashSearch");
|
||||||
|
|
||||||
|
$(document).observe("dom:loaded", function() {
|
||||||
|
|
||||||
|
$("edit-entry").addClassName("selected").removeAttribute("href");
|
||||||
|
if (window.location.search.toQueryParams().edit_mail) {
|
||||||
|
$("edit-entry").update("Edit Entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
$("phonebook-search").observe("submit", function(e) {
|
||||||
|
e.stop();
|
||||||
|
window.location = "./#search/" + $F("text");
|
||||||
|
});
|
||||||
|
|
||||||
|
var countryMap = {
|
||||||
|
'Mountain View': 'US',
|
||||||
|
'Auckland': 'NZ',
|
||||||
|
'Beijing': 'CN',
|
||||||
|
'Denmark': 'DK',
|
||||||
|
'Paris': 'FR',
|
||||||
|
'Toronto': 'CA',
|
||||||
|
'Tokyo': 'JP'
|
||||||
|
};
|
||||||
|
$("office-city-select").observe("change", function(e) {
|
||||||
|
var city = $F(this);
|
||||||
|
$("office-city-text")[city == "Other" ? "show" : "hide"]();
|
||||||
|
if (countryMap[city]) {
|
||||||
|
$("office-country-select").value = countryMap[city];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var remover = function(e) {
|
||||||
|
e.element().up().remove();
|
||||||
|
e.stop();
|
||||||
|
};
|
||||||
|
var adder = function(name, title) {
|
||||||
|
title = "Remove " + title;
|
||||||
|
return function(e) {
|
||||||
|
var div = new Element("div");
|
||||||
|
var input = new Element("input", {type: "text", name: name});
|
||||||
|
var a = new Element("a", {href: '#', title: title});
|
||||||
|
div.insert(input).insert(a);
|
||||||
|
a.observe("click", remover).addClassName("remove-link");
|
||||||
|
e.element().insert({before: div}); e.stop();
|
||||||
|
input.focus();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
$("email-alias-add").observe("click", adder("emailAlias[]", "e-mail"));
|
||||||
|
$("phone-number-add").observe("click", adder("mobile[]", "number"));
|
||||||
|
$("im-add").observe("click", adder("im[]", "account"));
|
||||||
|
|
||||||
|
$w("email-aliases phone-numbers im-accounts").map(function(x) {
|
||||||
|
return $(x).descendants().find("input + a");
|
||||||
|
}).flatten().compact().invoke("observe", "click", remover).each(function(x) {
|
||||||
|
x.writeAttribute("title", x.innerHTML).update('');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Replace dumb combobox with an autocomplete textbox
|
||||||
|
var manager = new Element("input", {type: "text", id: "manager-text"});
|
||||||
|
$("select-manager").hide().insert({before: manager});
|
||||||
|
manager.value = $$("option[value='#{dn}']".interpolate({
|
||||||
|
dn: $F("select-manager")
|
||||||
|
}))[0].innerHTML;
|
||||||
|
|
||||||
|
new Autocomplete(manager, {
|
||||||
|
serviceUrl: "./search.php?format=autocomplete",
|
||||||
|
minChars: 2,
|
||||||
|
onSelect: function(value, data) {
|
||||||
|
$("select-manager").value = data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
BehaviorManager.enable("slashSearch");
|
||||||
|
SearchManager.startSearch = function() {
|
||||||
|
if (!$F("text").strip()) {
|
||||||
|
window.location = "./";
|
||||||
|
}
|
||||||
|
BehaviorManager.disable("centerHeader") &&
|
||||||
|
$("phonebook-search").removeClassName("large");
|
||||||
|
$("phonebook-search").request({onSuccess: function onSuccess(r) {
|
||||||
|
$("results").update('').update(r.responseText ||
|
||||||
|
'<div style="text-align: center; margin-top: 5em;">' +
|
||||||
|
'<img src="./img/ohnoes.jpg" />' +
|
||||||
|
'<h2>OH NOES! No ones were foundz.</h2>' +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
$("text").releaseFocus();
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document).observe("dom:loaded", function() {
|
||||||
|
$("menu").down("a.card").addClassName("selected");
|
||||||
|
SearchManager.initialize();
|
||||||
|
});
|
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
BehaviorManager.register("centerVCard", {
|
||||||
|
observer: function() { $$("div.vcard").invoke("verticallyCenter"); },
|
||||||
|
enable: function() {
|
||||||
|
Event.observe(Prototype.resizeTarget, "resize", this.observer);
|
||||||
|
},
|
||||||
|
disable: Prototype.emptyFunction
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.extend(SearchManager, {
|
||||||
|
startSearch: function() {
|
||||||
|
BehaviorManager.disable("centerHeader") &&
|
||||||
|
$("phonebook-search").removeClassName("large");
|
||||||
|
$("phonebook-search").request({
|
||||||
|
parameters: {format: "json"},
|
||||||
|
onSuccess: function onSuccess(r) {
|
||||||
|
$("text").releaseFocus();
|
||||||
|
$("results").update('');
|
||||||
|
r.responseText.evalJSON().each(function(person) {
|
||||||
|
var container = new Element("div").addClassName("photo-frame");
|
||||||
|
var face = new Element("img", {
|
||||||
|
src: person.picture + "&type=thumb", "class": "wall-photo"
|
||||||
|
}).observe("click", function() {
|
||||||
|
this.showPerson(person.dn);
|
||||||
|
}.bind(this));
|
||||||
|
var name = new Element("span").update(person.cn);
|
||||||
|
container.insert(name).insert(face);
|
||||||
|
if (person.employeetype.indexOf("DISABLED") != -1) {
|
||||||
|
container.addClassName("disabled");
|
||||||
|
}
|
||||||
|
$("results").insert(container);
|
||||||
|
}.bind(this));
|
||||||
|
}.bind(this)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
showPerson: function(dn) {
|
||||||
|
$("phonebook-search").request({
|
||||||
|
parameters: {format: "html", query: dn.dnToEmail()},
|
||||||
|
onSuccess: function onSuccess(r) {
|
||||||
|
$(document.body).addClassName("lightbox");
|
||||||
|
var close = new Element("div").observe("click", function(e) {
|
||||||
|
$(document.body).removeClassName("lightbox");
|
||||||
|
}).addClassName("close-button").writeAttribute("title", "Close");
|
||||||
|
$("overlay").update('').update(r.responseText).
|
||||||
|
down("div.vcard").verticallyCenter().
|
||||||
|
down("div.header").insert(close);
|
||||||
|
$("overlay").down(".vcard p.manager a").observe("click", function() {
|
||||||
|
$(document.body).removeClassName("lightbox");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BehaviorManager.enable("slashSearch");
|
||||||
|
|
||||||
|
$(document).observe("dom:loaded", function() {
|
||||||
|
$("menu").down("a.wall").addClassName("selected");
|
||||||
|
|
||||||
|
BehaviorManager.enable("centerVCard");
|
||||||
|
BehaviorManager.enable("submitOnEnter");
|
||||||
|
|
||||||
|
$("overlay").observe("click", function(e) {
|
||||||
|
if (e.element() == this) {
|
||||||
|
$(document.body).removeClassName("lightbox");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SearchManager.initialize();
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
|
||||||
|
Element.addMethods("li", {
|
||||||
|
childTree: function(element) {
|
||||||
|
var next = $(element).next();
|
||||||
|
return (next && next.match("ul")) ? next : undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
collapse: function(element) {
|
||||||
|
var child = $(element).childTree();
|
||||||
|
child && child.hide();
|
||||||
|
return $(element).addClassName("collapsed").removeClassName("expanded");
|
||||||
|
},
|
||||||
|
|
||||||
|
expand: function(element) {
|
||||||
|
var child = $(element).childTree();
|
||||||
|
child && child.show();
|
||||||
|
return $(element).addClassName("expanded").removeClassName("collapsed");
|
||||||
|
},
|
||||||
|
|
||||||
|
collapsed: function(element) {
|
||||||
|
return $(element).hasClassName("collapsed");
|
||||||
|
},
|
||||||
|
|
||||||
|
expanded: function(element) {
|
||||||
|
return !$(element).collapsed();
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleTree: function(element) {
|
||||||
|
element = $(element);
|
||||||
|
return element[element.collapsed() ? "expand" : "collapse"]();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BehaviorManager.register("scrollSnap", function() {
|
||||||
|
var card = $("person").down("div.vcard");
|
||||||
|
var tree = $("orgchart");
|
||||||
|
if (!card || !tree) { return; }
|
||||||
|
if (!card.retrieve("originalTop")) {
|
||||||
|
card.store("originalTop", card.getStyle("marginTop"));
|
||||||
|
}
|
||||||
|
var refTop = tree.viewportOffset().top;
|
||||||
|
card[refTop >= 5 ? "removeClassName" : "addClassName"]("snap-to-top");
|
||||||
|
}.toBehavior(document, "scroll"));
|
||||||
|
|
||||||
|
BehaviorManager.register("treeNodeToggling", function(e) {
|
||||||
|
!e.element().match("a") && $(this).toggleTree();
|
||||||
|
Tree.select(this);
|
||||||
|
e.stop();
|
||||||
|
}.toBehavior(new Selector("div li.hr-node"), "click"));
|
||||||
|
|
||||||
|
BehaviorManager.register("treeNodeSelecting", function(e) {
|
||||||
|
Tree.select($(this).up().addClassName("selected"));
|
||||||
|
e.stop();
|
||||||
|
}.toBehavior(new Selector("div li.hr-node span.title"), "click"));
|
||||||
|
|
||||||
|
BehaviorManager.register("stopFilteringOnEsc", function(e) {
|
||||||
|
console.log(e.which || e.keyCode);
|
||||||
|
if ((e.which || e.keyCode) == Event.KEY_ESC) {
|
||||||
|
(function() { $(this).clear(); }).bind(this).defer();
|
||||||
|
Tree.stopFiltering();
|
||||||
|
}
|
||||||
|
}.toBehavior("text", "keyup"));
|
||||||
|
|
||||||
|
BehaviorManager.register("filterOnSubmit", function(e) {
|
||||||
|
e.stop();
|
||||||
|
Tree.stopFiltering();
|
||||||
|
$("text").blur();
|
||||||
|
if (!$F("text").strip()) {
|
||||||
|
$$("#orgchart li:not(.leaf)").invoke("expand");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Tree.filter();
|
||||||
|
}.toBehavior("phonebook-search", "submit"));
|
||||||
|
|
||||||
|
var Tree = {
|
||||||
|
selected: null,
|
||||||
|
select: function(node, changeHash) {
|
||||||
|
this.selected && this.selected.removeClassName("selected");
|
||||||
|
this.selected = $(node).addClassName("selected");
|
||||||
|
window.location.hash = "#search/" + this.selected.id.replace("-at-", '@');
|
||||||
|
},
|
||||||
|
|
||||||
|
stopFiltering: function() {
|
||||||
|
$("orgchart").removeClassName("filter-view");
|
||||||
|
$$("#orgchart li.highlighted").invoke("removeClassName", "highlighted");
|
||||||
|
$$("#orgchart li:not(.leaf)").invoke("expand");
|
||||||
|
},
|
||||||
|
|
||||||
|
showPerson: function(email) {
|
||||||
|
new Ajax.Request("search.php", {
|
||||||
|
method: "get",
|
||||||
|
parameters: {query: email, format: "html"},
|
||||||
|
onSuccess: function(r) {
|
||||||
|
$("person").update(r.responseText).down(".vcard");
|
||||||
|
BehaviorManager.fire("scrollSnap");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
filter: function() {
|
||||||
|
$("phonebook-search").request({
|
||||||
|
parameters: {format: "json"},
|
||||||
|
onSuccess: function onSuccess(r) {
|
||||||
|
var people = r.responseText.evalJSON();
|
||||||
|
people = people.pluck("dn").map(this.dnToEmail).compact();
|
||||||
|
people.sort(function(a, b) {
|
||||||
|
return a.cumulativeOffset().top - b.cumulativeOffset().top;
|
||||||
|
});
|
||||||
|
console.log("Post-eval");
|
||||||
|
|
||||||
|
var allowedToShow = people.map(function(x) {
|
||||||
|
console.log(" " + x.id);
|
||||||
|
var rootwards = x.ancestors().find("ul").compact().invoke("previous", "li");
|
||||||
|
console.log(" Post rootwards");
|
||||||
|
var leafwards = [];
|
||||||
|
console.log(" Post leafwards");
|
||||||
|
console.log(" Post leafing");
|
||||||
|
return [x].concat(rootwards).concat(leafwards).compact();
|
||||||
|
});
|
||||||
|
|
||||||
|
$$("#orgchart li:not(.leaf)").invoke("collapse");
|
||||||
|
console.log("Post-collapsing");
|
||||||
|
allowedToShow.flatten().uniq().find(":not(.leaf)").invoke("expand");
|
||||||
|
console.log("Post-expansion");
|
||||||
|
people.invoke("addClassName", "highlighted").first().scrollTo();
|
||||||
|
$("orgchart").addClassName("filter-view");
|
||||||
|
}.bind(this)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.extend(SearchManager, {
|
||||||
|
enabledBehaviorsOnInit: ["filterOnSubmit"],
|
||||||
|
onHashChange: function(e) {
|
||||||
|
var email = e.memo.hash.replace("search/", '');
|
||||||
|
Tree.showPerson(email);
|
||||||
|
Tree.select($(email.replace('@', "-at-")));
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad: function() {
|
||||||
|
var hash = window.location.hash;
|
||||||
|
if (hash.startsWith("#search/")) {
|
||||||
|
$(document).fire("hash:changed", {hash: hash.substring(1)});
|
||||||
|
var search = $("text").value = hash.replace(/^#search\//, '');
|
||||||
|
if (!search.strip()) { return; }
|
||||||
|
Tree.filter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).observe("dom:loaded", function() {
|
||||||
|
$("search").update("Filter");
|
||||||
|
$("menu").down("a.tree").addClassName("selected");
|
||||||
|
|
||||||
|
BehaviorManager.enable("scrollSnap");
|
||||||
|
BehaviorManager.enable("treeNodeToggling");
|
||||||
|
BehaviorManager.enable("slashSearch");
|
||||||
|
BehaviorManager.enable("stopFilteringOnEsc");
|
||||||
|
|
||||||
|
SearchManager.initialize();
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.extend(Tree, {
|
||||||
|
dnToEmail: function(x) {
|
||||||
|
var m = x.match(/mail=(\w+@mozilla.*),o=/);
|
||||||
|
return m ? $(m[1].replace('@', "-at-")) : null;
|
||||||
|
}
|
||||||
|
});
|
14
search.php
14
search.php
|
@ -1,23 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
require_once("init.php");
|
require_once("init.php");
|
||||||
|
require_once("filters.inc");
|
||||||
|
|
||||||
$keyword = isset($_GET["query"]) ? $_GET["query"] : '*';
|
$keyword = isset($_GET["query"]) ? $_GET["query"] : '*';
|
||||||
$entries = normalize(search_users($ldapconn, $keyword));
|
$entries = normalize(search_users($ldapconn, $keyword));
|
||||||
$filters = array(
|
$filters = get_filters();
|
||||||
"description" => "wikilinks",
|
|
||||||
"other" => "wikilinks",
|
|
||||||
"employeetype" => "employee_status",
|
|
||||||
"physicaldeliveryofficename" => "location_formatter",
|
|
||||||
"mobile" => "mobile_normalizer",
|
|
||||||
"im" => "mobile_normalizer",
|
|
||||||
"manager" => "get_manager"
|
|
||||||
);
|
|
||||||
foreach ($entries as &$entry) {
|
foreach ($entries as &$entry) {
|
||||||
foreach ($entry as $name => $attribute) {
|
foreach ($entry as $name => $attribute) {
|
||||||
if (isset($filters[$name]) && function_exists($filter = $filters[$name])) {
|
if (isset($filters[$name]) && function_exists($filter = $filters[$name])) {
|
||||||
$entry[$name] = call_user_func($filter, $attribute);
|
$entry[$name] = call_user_func($filter, $attribute);
|
||||||
} else {
|
|
||||||
# $attribute = htmlspecialchars($entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (preg_match("/mail=(\w+@mozilla.*),o=/", $entry["dn"], $m)) {
|
if (preg_match("/mail=(\w+@mozilla.*),o=/", $entry["dn"], $m)) {
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td><label>Office Country</label></td>
|
<td><label>Office Country</label></td>
|
||||||
<td>
|
<td>
|
||||||
<select id="office_country_select" name="office_country">
|
<select id="office-country-select" name="office_country">
|
||||||
<option value=""></option>
|
<option value=""></option>
|
||||||
<?php
|
<?php
|
||||||
foreach($country_codes as $country_name => $code) {
|
foreach($country_codes as $country_name => $code) {
|
||||||
|
@ -170,86 +170,7 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="js/autocomplete.js" type="text/javascript"></script>
|
<script type="text/javascript" src="js/autocomplete.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript" src="js/edit.js"></script>
|
||||||
var countryMap = {
|
|
||||||
'Mountain View': 'US',
|
|
||||||
'Auckland': 'NZ',
|
|
||||||
'Beijing': 'CN',
|
|
||||||
'Denmark': 'DK',
|
|
||||||
'Paris': 'FR',
|
|
||||||
'Toronto': 'CA',
|
|
||||||
'Tokyo': 'JP'
|
|
||||||
};
|
|
||||||
|
|
||||||
$(document).observe("keypress", function(e) {
|
|
||||||
if ((e.charCode || e.keyCode) == 47) { // KEY_SLASH
|
|
||||||
$("text").focus();
|
|
||||||
e.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).observe("dom:loaded", function() {
|
|
||||||
|
|
||||||
$("phonebook-search").observe("submit", function(e) {
|
|
||||||
e.stop();
|
|
||||||
window.location = "./#search/" + $F("text");
|
|
||||||
});
|
|
||||||
|
|
||||||
$("edit-entry").addClassName("selected").removeAttribute("href");
|
|
||||||
if (window.location.search.toQueryParams().edit_mail) {
|
|
||||||
$("edit-entry").update("Edit Entry");
|
|
||||||
}
|
|
||||||
|
|
||||||
$("office-city-select").observe("change", function(e) {
|
|
||||||
var city = $F("office-city-select");
|
|
||||||
$("office-city-text")[city == "Other" ? "show" : "hide"]();
|
|
||||||
if (countryMap[city]) {
|
|
||||||
$("office-country-select").value = countryMap[city];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var remover = function(e) {
|
|
||||||
e.element().up().remove();
|
|
||||||
e.stop();
|
|
||||||
};
|
|
||||||
var adder = function(name, title) {
|
|
||||||
title = "Remove " + title;
|
|
||||||
return function(e) {
|
|
||||||
var div = new Element("div");
|
|
||||||
var input = new Element("input", {type: "text", name: name});
|
|
||||||
var a = new Element("a", {href: '#', title: title});
|
|
||||||
div.insert(input).insert(a);
|
|
||||||
a.observe("click", remover).addClassName("remove-link");
|
|
||||||
e.element().insert({before: div}); e.stop();
|
|
||||||
input.focus();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
$("email-alias-add").observe("click", adder("emailAlias[]", "e-mail"));
|
|
||||||
$("phone-number-add").observe("click", adder("mobile[]", "number"));
|
|
||||||
$("im-add").observe("click", adder("im[]", "account"));
|
|
||||||
|
|
||||||
$w("email-aliases phone-numbers im-accounts").map(function(x) {
|
|
||||||
return $(x).descendants().find("input + a");
|
|
||||||
}).flatten().compact().invoke("observe", "click", remover).each(function(x) {
|
|
||||||
x.writeAttribute("title", x.innerHTML).update('');
|
|
||||||
});
|
|
||||||
|
|
||||||
var manager = new Element("input", {type: "text", id: "manager-text"});
|
|
||||||
$("select-manager").hide().insert({before: manager});
|
|
||||||
manager.value = $$("option[value='#{dn}']".interpolate({
|
|
||||||
dn: $F("select-manager")
|
|
||||||
}))[0].innerHTML;
|
|
||||||
new Autocomplete(manager, {
|
|
||||||
serviceUrl: "./search.php?format=autocomplete",
|
|
||||||
minChars: 2,
|
|
||||||
onSelect: function(value, data) {
|
|
||||||
$("select-manager").value = data;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<?php require_once('templates/footer.php'); ?>
|
<?php require_once('templates/footer.php'); ?>
|
||||||
|
|
|
@ -5,85 +5,8 @@
|
||||||
<title>Mozilla Phonebook</title>
|
<title>Mozilla Phonebook</title>
|
||||||
<link href="css/style.css" rel="stylesheet" type="text/css" />
|
<link href="css/style.css" rel="stylesheet" type="text/css" />
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="./favicon.ico" />
|
<link rel="shortcut icon" type="image/x-icon" href="./favicon.ico" />
|
||||||
<script src="js/prototype.js" type="text/javascript"></script>
|
<script type="text/javascript" src="js/prototype.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript" src="js/common.js"></script>
|
||||||
if (!window.console) {
|
|
||||||
window.console = {};
|
|
||||||
window.console.log = Prototype.emptyFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement onhashchange support
|
|
||||||
(function() {
|
|
||||||
var hash = window.location.hash;
|
|
||||||
var fire = function(str) {
|
|
||||||
$(document).fire("hash:changed", { hash: str.substring(1) });
|
|
||||||
};
|
|
||||||
var pe = new PeriodicalExecuter(function() {
|
|
||||||
var newHash = window.location.hash;
|
|
||||||
if (newHash != hash) {
|
|
||||||
fire(newHash);
|
|
||||||
hash = newHash;
|
|
||||||
}
|
|
||||||
}, 1);
|
|
||||||
})();
|
|
||||||
|
|
||||||
Element.addMethods({
|
|
||||||
verticallyCenter: function(element, percentage) {
|
|
||||||
element = $(element);
|
|
||||||
if (!element.retrieve("originalMarginTop")) {
|
|
||||||
element.store("originalMarginTop", element.getStyle("marginTop"));
|
|
||||||
}
|
|
||||||
var offset = $(document).viewport.getHeight() - element.getHeight();
|
|
||||||
return element.setStyle({marginTop: (offset * (percentage || 0.4)) + "px"});
|
|
||||||
},
|
|
||||||
|
|
||||||
stopVerticallyCentering: function(element) {
|
|
||||||
element = $(element);
|
|
||||||
var original = element.getStorage().unset("originalMarginTop");
|
|
||||||
return element.setStyle({marginTop: original});
|
|
||||||
},
|
|
||||||
|
|
||||||
searchify: function(element, results) {
|
|
||||||
return $(element).writeAttribute({type: "search", results: results || 5});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Element.addMethods("input", {
|
|
||||||
releaseFocus: function(element) {
|
|
||||||
$w("blur focus blur").each(function(method) { $(element)[method](); });
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Prototype.resizeTarget = document.onresize ? document : window;
|
|
||||||
|
|
||||||
Array.prototype.find = function find(selector) {
|
|
||||||
return this.filter(function(x) {
|
|
||||||
return x.match ? x.match(selector) : false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
String.prototype.dnToEmail = function() {
|
|
||||||
var m = this.match(/mail=(\w+@mozilla.*),o=/);
|
|
||||||
return (m ? m[1] : null);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ajax.Responders.register({
|
|
||||||
onCreate: function() { $("throbber").addClassName("loading"); },
|
|
||||||
onComplete: function() { $("throbber").removeClassName("loading"); }
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).observe("dom:loaded", function() {
|
|
||||||
$$("#menu a.persist").each(function(link) {
|
|
||||||
link.store("originalLink", link.readAttribute("href"));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$(document).observe("hash:changed", function(e) {
|
|
||||||
$$("#menu a.persist").each(function(link) {
|
|
||||||
link.writeAttribute("href", link.retrieve("originalLink") + "#" + e.memo.hash);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
@ -98,7 +21,7 @@
|
||||||
<div id="throbber"></div>
|
<div id="throbber"></div>
|
||||||
<ul id="menu">
|
<ul id="menu">
|
||||||
<li><a class="card persist" href="./">Cards</a></li>
|
<li><a class="card persist" href="./">Cards</a></li>
|
||||||
<li><a class="wall persist" href="./face.php">Faces</a></li>
|
<li><a class="wall persist" href="./faces.php">Faces</a></li>
|
||||||
<li><a class="tree" href="./tree.php">Org Chart</a></li>
|
<li><a class="tree" href="./tree.php">Org Chart</a></li>
|
||||||
<li class="edit"><a class="edit" href="./edit.php" id="edit-entry">Edit My Entry</a></li>
|
<li class="edit"><a class="edit" href="./edit.php" id="edit-entry">Edit My Entry</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
213
tree.php
213
tree.php
|
@ -1,11 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
require_once "init.php";
|
require_once "init.php";
|
||||||
|
require_once "config.php";
|
||||||
|
|
||||||
$search = ldap_search(
|
$search = ldap_search(
|
||||||
$ldapconn,
|
$ldapconn,
|
||||||
"o=com, dc=mozilla",
|
$tree_config["ldap"]["search_base"],
|
||||||
"mail=*",
|
$tree_config["ldap"]["search_filter"],
|
||||||
array("cn", "manager", "title", "mail", "employeeType")
|
$tree_config["ldap"]["search_attributes"]
|
||||||
);
|
);
|
||||||
$data = ldap_get_entries($ldapconn, $search);
|
$data = ldap_get_entries($ldapconn, $search);
|
||||||
|
|
||||||
|
@ -13,15 +14,11 @@ $people = array();
|
||||||
$orphans = array();
|
$orphans = array();
|
||||||
$everyone = array();
|
$everyone = array();
|
||||||
|
|
||||||
|
$tree_view_roots = tree_view_roots();
|
||||||
|
|
||||||
foreach ($data as $person) {
|
foreach ($data as $person) {
|
||||||
$mail = $person['mail'][0];
|
$mail = $person['mail'][0];
|
||||||
$everyone[$mail] = array(
|
$everyone[$mail] = tree_view_process_entry($person);
|
||||||
"title" => !empty($person["title"][0]) ? $person["title"][0] : null,
|
|
||||||
"name" => !empty($person["cn"][0]) ? $person["cn"][0] : null,
|
|
||||||
"disabled" => isset($person["employeetype"]) ?
|
|
||||||
strpos($person["employeetype"][0], 'D') !== FALSE:
|
|
||||||
FALSE
|
|
||||||
);
|
|
||||||
|
|
||||||
// If a user has a manager, try to find their place in the tree.
|
// If a user has a manager, try to find their place in the tree.
|
||||||
if (!empty($person["manager"][0])) {
|
if (!empty($person["manager"][0])) {
|
||||||
|
@ -34,34 +31,17 @@ foreach ($data as $person) {
|
||||||
} else {
|
} else {
|
||||||
$people[$manager][] = $mail;
|
$people[$manager][] = $mail;
|
||||||
}
|
}
|
||||||
} elseif (!empty($mail) &&
|
} elseif (!empty($mail) && !in_array($mail, $tree_view_roots)) {
|
||||||
strpos("lilly@mozilla.com", $mail) === FALSE &&
|
|
||||||
strpos("mitchell@mozilla.com", $mail) === FALSE) {
|
|
||||||
// Person is an orphan.
|
// Person is an orphan.
|
||||||
$orphans[] = $mail;
|
$orphans[] = $mail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function item($email, $leaf=FALSE) {
|
|
||||||
global $everyone;
|
|
||||||
$email = htmlspecialchars($email);
|
|
||||||
$id = str_replace('@', "-at-", $email);
|
|
||||||
$name = htmlspecialchars($everyone[$email]["name"]);
|
|
||||||
$title = htmlspecialchars($everyone[$email]["title"]);
|
|
||||||
$leaf = $leaf ? " leaf" : '';
|
|
||||||
$disabled = $everyone[$email]["disabled"] ? " disabled" : '';
|
|
||||||
return "<li id=\"$id\" class=\"hr-node expanded$leaf$disabled\">".
|
|
||||||
"<a href=\"#search/$email\" class=\"hr-link\">$name</a> ".
|
|
||||||
"<span class=\"title\">$title</span>".
|
|
||||||
"</li>";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function make_tree($level, $root, $nodes=null) {
|
function make_tree($level, $root, $nodes=null) {
|
||||||
global $people;
|
global $people;
|
||||||
global $everyone;
|
global $everyone;
|
||||||
|
|
||||||
print "\n". item($root, ($nodes == null));
|
print "\n". tree_view_item($root, ($nodes == null));
|
||||||
|
|
||||||
if (is_array($nodes)) {
|
if (is_array($nodes)) {
|
||||||
print "\n<ul>";
|
print "\n<ul>";
|
||||||
|
@ -85,8 +65,15 @@ require_once "templates/header.php";
|
||||||
|
|
||||||
<div id="orgchart" class="tree">
|
<div id="orgchart" class="tree">
|
||||||
<ul>
|
<ul>
|
||||||
<?= make_tree(0, 'mitchell@mozilla.com'); ?>
|
<?php
|
||||||
<?= make_tree(0, 'lilly@mozilla.com', $people['lilly@mozilla.com']); ?>
|
foreach ($tree_view_roots as $root) {
|
||||||
|
if (!isset($people[$root])) {
|
||||||
|
make_tree(0, $root);
|
||||||
|
} else {
|
||||||
|
make_tree(0, $root, $people[$root]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
@ -96,7 +83,7 @@ require_once "templates/header.php";
|
||||||
<ul>
|
<ul>
|
||||||
<?php
|
<?php
|
||||||
foreach ($orphans as $orphan) {
|
foreach ($orphans as $orphan) {
|
||||||
print "\n". item($orphan, TRUE);
|
print "\n". tree_view_item($orphan, TRUE);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -108,166 +95,6 @@ print "\n". item($orphan, TRUE);
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript" src="js/view-tree.js"></script>
|
||||||
Element.addMethods("li", {
|
|
||||||
childTree: function(element) {
|
|
||||||
var next = $(element).next();
|
|
||||||
return (next && next.match("ul")) ? next : undefined;
|
|
||||||
},
|
|
||||||
|
|
||||||
collapse: function(element) {
|
|
||||||
var child = $(element).childTree();
|
|
||||||
child && child.hide();
|
|
||||||
return $(element).addClassName("collapsed").removeClassName("expanded");
|
|
||||||
},
|
|
||||||
|
|
||||||
expand: function(element) {
|
|
||||||
var child = $(element).childTree();
|
|
||||||
child && child.show();
|
|
||||||
return $(element).addClassName("expanded").removeClassName("collapsed");
|
|
||||||
},
|
|
||||||
|
|
||||||
collapsed: function(element) {
|
|
||||||
return $(element).hasClassName("collapsed");
|
|
||||||
},
|
|
||||||
|
|
||||||
expanded: function(element) {
|
|
||||||
return !$(element).collapsed();
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleTree: function(element) {
|
|
||||||
element = $(element);
|
|
||||||
return element[element.collapsed() ? "expand" : "collapse"]();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).observe("dom:loaded", function() {
|
|
||||||
$("search").update("Filter");
|
|
||||||
$("menu").down("a.tree").addClassName("selected");
|
|
||||||
var region = $("person");
|
|
||||||
|
|
||||||
$(document).observe("scroll", scrollSnap);
|
|
||||||
|
|
||||||
$$("div li.hr-node").invoke("observe", "click", function(e) {
|
|
||||||
!e.element().match("a") && $(this).toggleTree();
|
|
||||||
select(this);
|
|
||||||
e.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
$$("div li.hr-node span.title").invoke("observe", "click", function(e) {
|
|
||||||
select($(this).up().addClassName("selected"));
|
|
||||||
e.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).observe("keypress", function(e) {
|
|
||||||
if ((e.which || e.keyCode) == 47) { // KEY_SLASH
|
|
||||||
$("text").focus(); e.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("text").observe("keypress", function(e) {
|
|
||||||
if ((e.which || e.keyCode) == Event.KEY_ESC) {
|
|
||||||
(function() { $(this).clear(); }).bind(this).defer();
|
|
||||||
stopFiltering();
|
|
||||||
}
|
|
||||||
if ((e.which || e.keyCode) == 47) {
|
|
||||||
e.stop();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("phonebook-search").observe("submit", function(e) {
|
|
||||||
e.stop();
|
|
||||||
stopFiltering();
|
|
||||||
$("text").blur();
|
|
||||||
if (!$F("text").strip()) {
|
|
||||||
$$("#orgchart li:not(.leaf)").invoke("expand");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// window.location.hash = "#search/" + $F("text");
|
|
||||||
filter();
|
|
||||||
});
|
|
||||||
|
|
||||||
function scrollSnap() {
|
|
||||||
var card = region.down("div.vcard");
|
|
||||||
var tree = $("orgchart");
|
|
||||||
if (!card || !tree) { return; }
|
|
||||||
if (!card.retrieve("originalTop")) {
|
|
||||||
card.store("originalTop", card.getStyle("marginTop"));
|
|
||||||
}
|
|
||||||
var refTop = tree.viewportOffset().top;
|
|
||||||
card[refTop >= 5 ? "removeClassName" : "addClassName"]("snap-to-top");
|
|
||||||
}
|
|
||||||
|
|
||||||
function filter() {
|
|
||||||
$("phonebook-search").request({
|
|
||||||
parameters: {format: "json"},
|
|
||||||
onSuccess: function onSuccess(r) {
|
|
||||||
var people = r.responseText.evalJSON().pluck("dn").map(function(x) {
|
|
||||||
var m = x.match(/mail=(\w+@mozilla.*),o=/);
|
|
||||||
return m ? $(m[1].replace('@', "-at-")) : null;
|
|
||||||
}).compact();
|
|
||||||
people.sort(function(a, b) {
|
|
||||||
return a.cumulativeOffset().top - b.cumulativeOffset().top;
|
|
||||||
});
|
|
||||||
console.log("Post-eval");
|
|
||||||
|
|
||||||
var allowedToShow = people.map(function(x) {
|
|
||||||
console.log(" " + x.id);
|
|
||||||
var rootwards = x.ancestors().find("ul").compact().invoke("previous", "li");
|
|
||||||
console.log(" Post rootwards");
|
|
||||||
var leafwards = [];
|
|
||||||
console.log(" Post leafwards");
|
|
||||||
// leafwards = leafwards && leafwards.match("ul") ? leafwards.select("li") : [];
|
|
||||||
console.log(" Post leafing");
|
|
||||||
return [x].concat(rootwards).concat(leafwards).compact();
|
|
||||||
});
|
|
||||||
|
|
||||||
$$("#orgchart li:not(.leaf)").invoke("collapse");
|
|
||||||
console.log("Post-collapsing");
|
|
||||||
allowedToShow.flatten().uniq().find(":not(.leaf)").invoke("expand");
|
|
||||||
console.log("Post-expansion");
|
|
||||||
people.invoke("addClassName", "highlighted").first().scrollTo();
|
|
||||||
$("orgchart").addClassName("filter-view");
|
|
||||||
// allowedToShow.each(function(x) console.log(x));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopFiltering() {
|
|
||||||
$("orgchart").removeClassName("filter-view");
|
|
||||||
$$("#orgchart li.highlighted").invoke("removeClassName", "highlighted");
|
|
||||||
$$("#orgchart li:not(.leaf)").invoke("expand");
|
|
||||||
}
|
|
||||||
|
|
||||||
var selected = null;
|
|
||||||
function select(node) {
|
|
||||||
selected && selected.removeClassName("selected");
|
|
||||||
selected = $(node).addClassName("selected");
|
|
||||||
window.location.hash = "#search/" + selected.id.replace("-at-", '@');
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).observe("hash:changed", function(e) {
|
|
||||||
showPerson(e.memo.hash.replace("search/", ''));
|
|
||||||
});
|
|
||||||
var hash = window.location.hash;
|
|
||||||
if (hash.startsWith("#search/")) {
|
|
||||||
$(document).fire("hash:changed", {hash: hash.substring(1)});
|
|
||||||
var search = $("text").value = hash.replace(/^#search\//, '');
|
|
||||||
if (!search.strip()) { return; }
|
|
||||||
filter();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPerson(email) {
|
|
||||||
new Ajax.Request("search.php", {
|
|
||||||
method: "get",
|
|
||||||
parameters: {query: email, format: "html"},
|
|
||||||
onSuccess: function(r) {
|
|
||||||
$("person").update(r.responseText).down(".vcard");
|
|
||||||
scrollSnap();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<?php require_once "templates/footer.php"; ?>
|
<?php require_once "templates/footer.php"; ?>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче