1*2ebb07b4SGreg Roach/** 2*2ebb07b4SGreg Roach * webtrees: online genealogy 3*2ebb07b4SGreg Roach * Copyright (C) 2019 webtrees development team 4*2ebb07b4SGreg Roach * This program is free software: you can redistribute it and/or modify 5*2ebb07b4SGreg Roach * it under the terms of the GNU General Public License as published by 6*2ebb07b4SGreg Roach * the Free Software Foundation, either version 3 of the License, or 7*2ebb07b4SGreg Roach * (at your option) any later version. 8*2ebb07b4SGreg Roach * This program is distributed in the hope that it will be useful, 9*2ebb07b4SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 10*2ebb07b4SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11*2ebb07b4SGreg Roach * GNU General Public License for more details. 12*2ebb07b4SGreg Roach * You should have received a copy of the GNU General Public License 13*2ebb07b4SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 14*2ebb07b4SGreg Roach */ 15*2ebb07b4SGreg Roach 16*2ebb07b4SGreg Roachfunction TreeViewHandler(treeview_instance, ged) { 17*2ebb07b4SGreg Roach var tv = this; // Store "this" for usage within jQuery functions where "this" is not this ;-) 18*2ebb07b4SGreg Roach 19*2ebb07b4SGreg Roach this.treeview = $("#" + treeview_instance + "_in"); 20*2ebb07b4SGreg Roach this.loadingImage = $("#" + treeview_instance + "_loading"); 21*2ebb07b4SGreg Roach this.toolbox = $("#tv_tools"); 22*2ebb07b4SGreg Roach this.buttons = $(".tv_button:first", this.toolbox); 23*2ebb07b4SGreg Roach this.zoom = 100; // in percent 24*2ebb07b4SGreg Roach this.boxWidth = 180; // default family box width 25*2ebb07b4SGreg Roach this.boxExpandedWidth = 250; // default expanded family box width 26*2ebb07b4SGreg Roach this.cookieDays = 3; // lifetime of preferences memory, in days 27*2ebb07b4SGreg Roach this.ajaxUrl = "index.php?route=module&module=tree&ged=" + encodeURIComponent(ged) + "&instance=" + treeview_instance + "&action="; 28*2ebb07b4SGreg Roach 29*2ebb07b4SGreg Roach this.container = this.treeview.parent(); // Store the container element ("#" + treeview_instance + "_out") 30*2ebb07b4SGreg Roach this.auto_box_width = false; 31*2ebb07b4SGreg Roach this.updating = false; 32*2ebb07b4SGreg Roach 33*2ebb07b4SGreg Roach // Restore user preferences 34*2ebb07b4SGreg Roach if (readCookie("compact") === "true") { 35*2ebb07b4SGreg Roach tv.compact(); 36*2ebb07b4SGreg Roach } 37*2ebb07b4SGreg Roach 38*2ebb07b4SGreg Roach /////////////////////////////////////////////// 39*2ebb07b4SGreg Roach // Based on https://codepen.io/chriscoyier/pen/zdsty 40*2ebb07b4SGreg Roach (function($) { 41*2ebb07b4SGreg Roach $.fn.drags = function(opt) { 42*2ebb07b4SGreg Roach var $el = this; 43*2ebb07b4SGreg Roach 44*2ebb07b4SGreg Roach return $el.css('cursor', 'move').on("mousedown", function(e) { 45*2ebb07b4SGreg Roach var $drag = $(this); 46*2ebb07b4SGreg Roach var drg_h = $drag.outerHeight(); 47*2ebb07b4SGreg Roach var drg_w = $drag.outerWidth(); 48*2ebb07b4SGreg Roach var pos_y = $drag.offset().top + drg_h - e.pageY; 49*2ebb07b4SGreg Roach var pos_x = $drag.offset().left + drg_w - e.pageX; 50*2ebb07b4SGreg Roach 51*2ebb07b4SGreg Roach $drag.addClass('draggable'); 52*2ebb07b4SGreg Roach 53*2ebb07b4SGreg Roach $(document) 54*2ebb07b4SGreg Roach .on("mousemove", function(e) { 55*2ebb07b4SGreg Roach $('.draggable').offset({ 56*2ebb07b4SGreg Roach top:e.pageY + pos_y - drg_h, 57*2ebb07b4SGreg Roach left:e.pageX + pos_x - drg_w 58*2ebb07b4SGreg Roach }).on("mouseup", function() { 59*2ebb07b4SGreg Roach $drag.removeClass('draggable'); 60*2ebb07b4SGreg Roach }); 61*2ebb07b4SGreg Roach }).on("mouseup", function() { 62*2ebb07b4SGreg Roach $drag.removeClass('draggable'); 63*2ebb07b4SGreg Roach tv.updateTree(); 64*2ebb07b4SGreg Roach }); 65*2ebb07b4SGreg Roach e.preventDefault(); 66*2ebb07b4SGreg Roach }); 67*2ebb07b4SGreg Roach 68*2ebb07b4SGreg Roach } 69*2ebb07b4SGreg Roach })(jQuery); 70*2ebb07b4SGreg Roach 71*2ebb07b4SGreg Roach tv.treeview.drags(); 72*2ebb07b4SGreg Roach /////////////////////////////////////////////// 73*2ebb07b4SGreg Roach 74*2ebb07b4SGreg Roach // Add click handlers to buttons 75*2ebb07b4SGreg Roach tv.toolbox.find("#tvbCompact").each(function (index, tvCompact) { 76*2ebb07b4SGreg Roach tvCompact.onclick = function () { 77*2ebb07b4SGreg Roach tv.compact(); 78*2ebb07b4SGreg Roach }; 79*2ebb07b4SGreg Roach }); 80*2ebb07b4SGreg Roach // If we click the "hide/show all partners" button, toggle the setting before reloading the page 81*2ebb07b4SGreg Roach tv.toolbox.find("#tvbAllPartners").each(function (index, tvAllPartners) { 82*2ebb07b4SGreg Roach tvAllPartners.onclick = function () { 83*2ebb07b4SGreg Roach createCookie("allPartners", readCookie("allPartners") === "true" ? "false" : "true", tv.cookieDays); 84*2ebb07b4SGreg Roach document.location = document.location; 85*2ebb07b4SGreg Roach }; 86*2ebb07b4SGreg Roach }); 87*2ebb07b4SGreg Roach tv.toolbox.find("#tvbOpen").each(function (index, tvbOpen) { 88*2ebb07b4SGreg Roach var b = $(tvbOpen, tv.toolbox); 89*2ebb07b4SGreg Roach tvbOpen.onclick = function () { 90*2ebb07b4SGreg Roach b.addClass("tvPressed"); 91*2ebb07b4SGreg Roach tv.setLoading(); 92*2ebb07b4SGreg Roach var e = jQuery.Event("click"); 93*2ebb07b4SGreg Roach tv.treeview.find(".tv_box:not(.boxExpanded)").each(function (index, box) { 94*2ebb07b4SGreg Roach var pos = $(box, tv.treeview).offset(); 95*2ebb07b4SGreg Roach if (pos.left >= tv.leftMin && pos.left <= tv.leftMax && pos.top >= tv.topMin && pos.top <= tv.topMax) { 96*2ebb07b4SGreg Roach tv.expandBox(box, e); 97*2ebb07b4SGreg Roach } 98*2ebb07b4SGreg Roach }); 99*2ebb07b4SGreg Roach b.removeClass("tvPressed"); 100*2ebb07b4SGreg Roach tv.setComplete(); 101*2ebb07b4SGreg Roach }; 102*2ebb07b4SGreg Roach }); 103*2ebb07b4SGreg Roach tv.toolbox.find("#tvbClose").each(function (index, tvbClose) { 104*2ebb07b4SGreg Roach var b = $(tvbClose, tv.toolbox); 105*2ebb07b4SGreg Roach tvbClose.onclick = function () { 106*2ebb07b4SGreg Roach b.addClass("tvPressed"); 107*2ebb07b4SGreg Roach tv.setLoading(); 108*2ebb07b4SGreg Roach tv.treeview.find(".tv_box.boxExpanded").each(function (index, box) { 109*2ebb07b4SGreg Roach $(box).css("display", "none").removeClass("boxExpanded").parent().find(".tv_box.collapsedContent").css("display", "block"); 110*2ebb07b4SGreg Roach }); 111*2ebb07b4SGreg Roach b.removeClass("tvPressed"); 112*2ebb07b4SGreg Roach tv.setComplete(); 113*2ebb07b4SGreg Roach }; 114*2ebb07b4SGreg Roach }); 115*2ebb07b4SGreg Roach 116*2ebb07b4SGreg Roach tv.centerOnRoot(); // fire ajax update if needed, which call setComplete() when all is loaded 117*2ebb07b4SGreg Roach} 118*2ebb07b4SGreg Roach/** 119*2ebb07b4SGreg Roach * Class TreeView setLoading method 120*2ebb07b4SGreg Roach */ 121*2ebb07b4SGreg RoachTreeViewHandler.prototype.setLoading = function () { 122*2ebb07b4SGreg Roach this.treeview.css("cursor", "wait"); 123*2ebb07b4SGreg Roach this.loadingImage.css("display", "block"); 124*2ebb07b4SGreg Roach}; 125*2ebb07b4SGreg Roach/** 126*2ebb07b4SGreg Roach * Class TreeView setComplete method 127*2ebb07b4SGreg Roach */ 128*2ebb07b4SGreg RoachTreeViewHandler.prototype.setComplete = function () { 129*2ebb07b4SGreg Roach this.treeview.css("cursor", "move"); 130*2ebb07b4SGreg Roach this.loadingImage.css("display", "none"); 131*2ebb07b4SGreg Roach}; 132*2ebb07b4SGreg Roach 133*2ebb07b4SGreg Roach/** 134*2ebb07b4SGreg Roach * Class TreeView getSize method 135*2ebb07b4SGreg Roach * Store the viewport current size 136*2ebb07b4SGreg Roach */ 137*2ebb07b4SGreg RoachTreeViewHandler.prototype.getSize = function () { 138*2ebb07b4SGreg Roach var tv = this; 139*2ebb07b4SGreg Roach // retrieve the current container bounding box 140*2ebb07b4SGreg Roach var container = tv.container.parent(); 141*2ebb07b4SGreg Roach var offset = container.offset(); 142*2ebb07b4SGreg Roach tv.leftMin = offset.left; 143*2ebb07b4SGreg Roach tv.leftMax = tv.leftMin + container.innerWidth(); 144*2ebb07b4SGreg Roach tv.topMin = offset.top; 145*2ebb07b4SGreg Roach tv.topMax = tv.topMin + container.innerHeight(); 146*2ebb07b4SGreg Roach /* 147*2ebb07b4SGreg Roach var frm = $("#tvTreeBorder"); 148*2ebb07b4SGreg Roach tv.treeview.css("width", frm.width()); 149*2ebb07b4SGreg Roach tv.treeview.css("height", frm.height());*/ 150*2ebb07b4SGreg Roach}; 151*2ebb07b4SGreg Roach 152*2ebb07b4SGreg Roach/** 153*2ebb07b4SGreg Roach * Class TreeView updateTree method 154*2ebb07b4SGreg Roach * Perform ajax requests to complete the tree after drag 155*2ebb07b4SGreg Roach * param boolean @center center on root person when done 156*2ebb07b4SGreg Roach */ 157*2ebb07b4SGreg RoachTreeViewHandler.prototype.updateTree = function (center, button) { 158*2ebb07b4SGreg Roach var tv = this; // Store "this" for usage within jQuery functions where "this" is not this ;-) 159*2ebb07b4SGreg Roach var to_load = []; 160*2ebb07b4SGreg Roach var elts = []; 161*2ebb07b4SGreg Roach this.getSize(); 162*2ebb07b4SGreg Roach 163*2ebb07b4SGreg Roach // check which td with datafld attribute are within the container bounding box 164*2ebb07b4SGreg Roach // and therefore need to be dynamically loaded 165*2ebb07b4SGreg Roach tv.treeview.find("td[abbr]").each(function (index, el) { 166*2ebb07b4SGreg Roach el = $(el, tv.treeview); 167*2ebb07b4SGreg Roach var pos = el.offset(); 168*2ebb07b4SGreg Roach if (pos.left >= tv.leftMin && pos.left <= tv.leftMax && pos.top >= tv.topMin && pos.top <= tv.topMax) { 169*2ebb07b4SGreg Roach to_load.push(el.attr("abbr")); 170*2ebb07b4SGreg Roach elts.push(el); 171*2ebb07b4SGreg Roach } 172*2ebb07b4SGreg Roach }); 173*2ebb07b4SGreg Roach // if some boxes need update, we perform an ajax request 174*2ebb07b4SGreg Roach if (to_load.length > 0) { 175*2ebb07b4SGreg Roach tv.updating = true; 176*2ebb07b4SGreg Roach tv.setLoading(); 177*2ebb07b4SGreg Roach jQuery.ajax({ 178*2ebb07b4SGreg Roach url: tv.ajaxUrl + "Persons", 179*2ebb07b4SGreg Roach dataType: "json", 180*2ebb07b4SGreg Roach data: "q=" + to_load.join(";"), 181*2ebb07b4SGreg Roach success: function (ret) { 182*2ebb07b4SGreg Roach var nb = elts.length; 183*2ebb07b4SGreg Roach var root_element = $(".rootPerson", this.treeview); 184*2ebb07b4SGreg Roach var l = root_element.offset().left; 185*2ebb07b4SGreg Roach for (var i = 0; i < nb; i++) { 186*2ebb07b4SGreg Roach elts[i].removeAttr("abbr").html(ret[i]); 187*2ebb07b4SGreg Roach } 188*2ebb07b4SGreg Roach // we now ajust the draggable treeview size to its content size 189*2ebb07b4SGreg Roach tv.getSize(); 190*2ebb07b4SGreg Roach }, 191*2ebb07b4SGreg Roach complete: function () { 192*2ebb07b4SGreg Roach if (tv.treeview.find("td[abbr]").length) { 193*2ebb07b4SGreg Roach tv.updateTree(center, button); // recursive call 194*2ebb07b4SGreg Roach } 195*2ebb07b4SGreg Roach // the added boxes need that in mode compact boxes 196*2ebb07b4SGreg Roach if (tv.auto_box_width) { 197*2ebb07b4SGreg Roach tv.treeview.find(".tv_box").css("width", "auto"); 198*2ebb07b4SGreg Roach } 199*2ebb07b4SGreg Roach tv.updating = true; // avoid an unuseful recursive call when all requested persons are loaded 200*2ebb07b4SGreg Roach if (center) { 201*2ebb07b4SGreg Roach tv.centerOnRoot(); 202*2ebb07b4SGreg Roach } 203*2ebb07b4SGreg Roach if (button) { 204*2ebb07b4SGreg Roach button.removeClass("tvPressed"); 205*2ebb07b4SGreg Roach } 206*2ebb07b4SGreg Roach tv.setComplete(); 207*2ebb07b4SGreg Roach tv.updating = false; 208*2ebb07b4SGreg Roach }, 209*2ebb07b4SGreg Roach timeout: function () { 210*2ebb07b4SGreg Roach if (button) { 211*2ebb07b4SGreg Roach button.removeClass("tvPressed"); 212*2ebb07b4SGreg Roach } 213*2ebb07b4SGreg Roach tv.updating = false; 214*2ebb07b4SGreg Roach tv.setComplete(); 215*2ebb07b4SGreg Roach } 216*2ebb07b4SGreg Roach }); 217*2ebb07b4SGreg Roach } else { 218*2ebb07b4SGreg Roach if (button) { 219*2ebb07b4SGreg Roach button.removeClass("tvPressed"); 220*2ebb07b4SGreg Roach } 221*2ebb07b4SGreg Roach tv.setComplete(); 222*2ebb07b4SGreg Roach } 223*2ebb07b4SGreg Roach return false; 224*2ebb07b4SGreg Roach}; 225*2ebb07b4SGreg Roach 226*2ebb07b4SGreg Roach/** 227*2ebb07b4SGreg Roach * Class TreeView compact method 228*2ebb07b4SGreg Roach */ 229*2ebb07b4SGreg RoachTreeViewHandler.prototype.compact = function () { 230*2ebb07b4SGreg Roach var tv = this; 231*2ebb07b4SGreg Roach var b = $("#tvbCompact", tv.toolbox); 232*2ebb07b4SGreg Roach tv.setLoading(); 233*2ebb07b4SGreg Roach if (tv.auto_box_width) { 234*2ebb07b4SGreg Roach var w = tv.boxWidth * (tv.zoom / 100) + "px"; 235*2ebb07b4SGreg Roach var ew = tv.boxExpandedWidth * (tv.zoom / 100) + "px"; 236*2ebb07b4SGreg Roach tv.treeview.find(".tv_box:not(boxExpanded)", tv.treeview).css("width", w); 237*2ebb07b4SGreg Roach tv.treeview.find(".boxExpanded", tv.treeview).css("width", ew); 238*2ebb07b4SGreg Roach tv.auto_box_width = false; 239*2ebb07b4SGreg Roach if (readCookie("compact")) { 240*2ebb07b4SGreg Roach createCookie("compact", false, tv.cookieDays); 241*2ebb07b4SGreg Roach } 242*2ebb07b4SGreg Roach b.removeClass("tvPressed"); 243*2ebb07b4SGreg Roach } else { 244*2ebb07b4SGreg Roach tv.treeview.find(".tv_box").css("width", "auto"); 245*2ebb07b4SGreg Roach tv.auto_box_width = true; 246*2ebb07b4SGreg Roach if (!readCookie("compact")) { 247*2ebb07b4SGreg Roach createCookie("compact", true, tv.cookieDays); 248*2ebb07b4SGreg Roach } 249*2ebb07b4SGreg Roach if (!tv.updating) { 250*2ebb07b4SGreg Roach tv.updateTree(); 251*2ebb07b4SGreg Roach } 252*2ebb07b4SGreg Roach b.addClass("tvPressed"); 253*2ebb07b4SGreg Roach } 254*2ebb07b4SGreg Roach tv.setComplete(); 255*2ebb07b4SGreg Roach return false; 256*2ebb07b4SGreg Roach}; 257*2ebb07b4SGreg Roach 258*2ebb07b4SGreg Roach/** 259*2ebb07b4SGreg Roach * Class TreeView centerOnRoot method 260*2ebb07b4SGreg Roach */ 261*2ebb07b4SGreg RoachTreeViewHandler.prototype.centerOnRoot = function () { 262*2ebb07b4SGreg Roach this.loadingImage.css("display", "block"); 263*2ebb07b4SGreg Roach var tv = this; 264*2ebb07b4SGreg Roach var tvc = this.container; 265*2ebb07b4SGreg Roach var tvc_width = tvc.innerWidth() / 2; 266*2ebb07b4SGreg Roach if (isNaN(tvc_width)) { 267*2ebb07b4SGreg Roach return false; 268*2ebb07b4SGreg Roach } 269*2ebb07b4SGreg Roach var tvc_height = tvc.innerHeight() / 2; 270*2ebb07b4SGreg Roach var root_person = $(".rootPerson", this.treeview); 271*2ebb07b4SGreg Roach 272*2ebb07b4SGreg Roach if (!this.updating) { 273*2ebb07b4SGreg Roach tv.setComplete(); 274*2ebb07b4SGreg Roach } 275*2ebb07b4SGreg Roach return false; 276*2ebb07b4SGreg Roach}; 277*2ebb07b4SGreg Roach 278*2ebb07b4SGreg Roach/** 279*2ebb07b4SGreg Roach * Class TreeView expandBox method 280*2ebb07b4SGreg Roach * param string @box the person box element 281*2ebb07b4SGreg Roach * param string @event the call event 282*2ebb07b4SGreg Roach * param string @pid the person id 283*2ebb07b4SGreg Roach * 284*2ebb07b4SGreg Roach * called ONLY for elements which have NOT the class tv_link to avoid unuseful requests to the server 285*2ebb07b4SGreg Roach */ 286*2ebb07b4SGreg RoachTreeViewHandler.prototype.expandBox = function (box, event) { 287*2ebb07b4SGreg Roach var t = $(event.target); 288*2ebb07b4SGreg Roach if (t.hasClass("tv_link")) { 289*2ebb07b4SGreg Roach return false; 290*2ebb07b4SGreg Roach } 291*2ebb07b4SGreg Roach 292*2ebb07b4SGreg Roach var box = $(box, this.treeview); 293*2ebb07b4SGreg Roach var bc = box.parent(); // bc is Box Container 294*2ebb07b4SGreg Roach var pid = box.attr("abbr"); 295*2ebb07b4SGreg Roach var tv = this; // Store "this" for usage within jQuery functions where "this" is not this ;-) 296*2ebb07b4SGreg Roach var expanded; 297*2ebb07b4SGreg Roach var collapsed; 298*2ebb07b4SGreg Roach 299*2ebb07b4SGreg Roach if (bc.hasClass("detailsLoaded")) { 300*2ebb07b4SGreg Roach collapsed = bc.find(".collapsedContent"); 301*2ebb07b4SGreg Roach expanded = bc.find(".tv_box:not(.collapsedContent)"); 302*2ebb07b4SGreg Roach } else { 303*2ebb07b4SGreg Roach // Cache the box content as an hidden person's box in the box's parent element 304*2ebb07b4SGreg Roach expanded = box; 305*2ebb07b4SGreg Roach collapsed = box.clone(); 306*2ebb07b4SGreg Roach bc.append(collapsed.addClass("collapsedContent").css("display", "none")); 307*2ebb07b4SGreg Roach // we add a waiting image at the right side of the box 308*2ebb07b4SGreg Roach var loading_image = this.loadingImage.find("img").clone().addClass("tv_box_loading").css("display", "block"); 309*2ebb07b4SGreg Roach box.prepend(loading_image); 310*2ebb07b4SGreg Roach tv.updating = true; 311*2ebb07b4SGreg Roach tv.setLoading(); 312*2ebb07b4SGreg Roach // perform the Ajax request and load the result in the box 313*2ebb07b4SGreg Roach box.load(tv.ajaxUrl + "Details&pid=" + pid, function () { 314*2ebb07b4SGreg Roach // If Lightbox module is active, we reinitialize it for the new links 315*2ebb07b4SGreg Roach if (typeof CB_Init === "function") { 316*2ebb07b4SGreg Roach CB_Init(); 317*2ebb07b4SGreg Roach } 318*2ebb07b4SGreg Roach box.css("width", tv.boxExpandedWidth * (tv.zoom / 100) + "px"); 319*2ebb07b4SGreg Roach loading_image.remove(); 320*2ebb07b4SGreg Roach bc.addClass("detailsLoaded"); 321*2ebb07b4SGreg Roach tv.setComplete(); 322*2ebb07b4SGreg Roach tv.updating = false; 323*2ebb07b4SGreg Roach }); 324*2ebb07b4SGreg Roach } 325*2ebb07b4SGreg Roach if (box.hasClass("boxExpanded")) { 326*2ebb07b4SGreg Roach expanded.css("display", "none"); 327*2ebb07b4SGreg Roach collapsed.css("display", "block"); 328*2ebb07b4SGreg Roach box.removeClass("boxExpanded"); 329*2ebb07b4SGreg Roach } else { 330*2ebb07b4SGreg Roach expanded.css("display", "block"); 331*2ebb07b4SGreg Roach collapsed.css("display", "none"); 332*2ebb07b4SGreg Roach expanded.addClass("boxExpanded"); 333*2ebb07b4SGreg Roach } 334*2ebb07b4SGreg Roach // we must ajust the draggable treeview size to its content size 335*2ebb07b4SGreg Roach this.getSize(); 336*2ebb07b4SGreg Roach return false; 337*2ebb07b4SGreg Roach}; 338*2ebb07b4SGreg Roach 339*2ebb07b4SGreg Roachfunction createCookie(name, value, days) { 340*2ebb07b4SGreg Roach if (days) { 341*2ebb07b4SGreg Roach var date = new Date(); 342*2ebb07b4SGreg Roach date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 343*2ebb07b4SGreg Roach document.cookie = name + "=" + value + "; expires=" + date.toGMTString() + "; path=/"; 344*2ebb07b4SGreg Roach } else { 345*2ebb07b4SGreg Roach document.cookie = name + "=" + value + "; path=/"; 346*2ebb07b4SGreg Roach } 347*2ebb07b4SGreg Roach} 348*2ebb07b4SGreg Roach 349*2ebb07b4SGreg Roachfunction readCookie(name) { 350*2ebb07b4SGreg Roach var name_equals = name + "="; 351*2ebb07b4SGreg Roach var ca = document.cookie.split(';'); 352*2ebb07b4SGreg Roach for (var i = 0; i < ca.length; i++) { 353*2ebb07b4SGreg Roach var c = ca[i]; 354*2ebb07b4SGreg Roach while (c.charAt(0) === ' ') { 355*2ebb07b4SGreg Roach c = c.substring(1, c.length); 356*2ebb07b4SGreg Roach } 357*2ebb07b4SGreg Roach if (c.indexOf(name_equals) === 0) { 358*2ebb07b4SGreg Roach return c.substring(name_equals.length, c.length); 359*2ebb07b4SGreg Roach } 360*2ebb07b4SGreg Roach } 361*2ebb07b4SGreg Roach return null; 362*2ebb07b4SGreg Roach} 363