Roundup Tracker

Attachment 'breadcrumb.js'

Download

   1 // This is the javascript code for the Roundup breadcrumb feature.
   2 //
   3 // The localStorage object is used to store breadcrumb data. There are
   4 // 3 objects stored there:
   5 //   max_breadcrumbs - a number which is the upper bound on the number
   6 //   of visible breadcrumbs.
   7 //
   8 //   multi_tracker - 'on' or 'off'. Indicates whether the breadcrumbs
   9 //   are for one tracker or are for multiple trackers.
  10 //
  11 //   breadcrumb - holds the breadcrumb detail.
  12 
  13 // The breadcrumb localStorage object is a dict (a.k.a. hash table,
  14 // a.k.a. associative array). The key is the tracker name and the
  15 // value is an array of [issue, title, location_data] triples.  The
  16 // issue is used to formulate a link, the title is the hover text, and
  17 // the location is used to make breadcrumbs work on more than one
  18 // tracker. The hover text can be changed to another issue field. If
  19 // the key to breadcrumb is 'multi' then the same triple is used but
  20 // the value can be for more than one tracker. When a tracker's
  21 // breadcrumb is modified, the breadcrumb for 'multi' is also
  22 // modified. This way if one switches from multi-tracker to not or
  23 // vice versa, the breadcrumb data is consistent.
  24 
  25 // Name of field whose value is displayed as a tooltip.
  26 var  hover_text_field_name = 'title';
  27 // To specify another field, put something like the following in
  28 // html/page.html after the 'import' of this file:
  29 //   <script type="text/javascript">
  30 //   var hover_text_field_name = 'some other field';
  31 //   </script>
  32 // To determine fields, view the page source while looking at an issue
  33 // and do a backwards page search for 'name=' (without the quotes).
  34 // Ignore the hidden entries and names that start with an @ sign.
  35 
  36 // The previous version had an array of issue #s. Another earlier
  37 // version was an array of (issue, title, location_data) triples.
  38 // This version has a has a hash table where keys are tracker names,
  39 // or 'multi', and the values are arrays of (issue, title,
  40 // location_data) triples. The following code will convert the old
  41 // ways of recording issues to the new way. A title of '' causes
  42 // nothing to be displayed in the 'hover' text.
  43 if (localStorage.breadcrumb) {
  44     var bc = JSON.parse(localStorage.breadcrumb);
  45     var all_bcs, ele0, issue;
  46     var tracker = location.pathname.split('/')[1];
  47     var loc = {protocol: location.protocol, host: location.host, pathname: location.pathname};
  48     if (Array.isArray(bc)) {
  49 	ele0 = bc[0];
  50 	if (typeof ele0 == 'string' || ele0 instanceof String) {
  51 	    // this is an issue number, expressed as a string.
  52 	    for (var i in bc) {
  53 		issue = bc[i];
  54 		bc[i] = [issue, '', loc];
  55 	    }
  56 	    // Can not use assoc array literal because it treats tracker as 'tracker'.
  57 	    all_bcs = {'multi': bc};
  58 	    all_bcs[tracker] = bc;
  59 	    localStorage.breadcrumb = JSON.stringify(all_bcs);
  60 	} else if (Array.isArray(ele0)) {
  61 	    var j = 0;
  62 	    for (var i in bc) {
  63 		issue = bc[i][0];
  64 		title = bc[i][1];
  65 		loc   = bc[i][2];
  66 		if (issue != null && issue.search(/^\d+$/) != -1) {
  67 		    // Some breadcrumb entries have trash: missing or null issue #.
  68 		    bc[j++] = [issue, title, loc];
  69 		}
  70 	    }
  71 	    all_bcs = {'multi': bc};
  72 	    all_bcs[tracker] = bc;
  73 	    localStorage.breadcrumb = JSON.stringify(all_bcs);
  74         }
  75     }
  76 }
  77 
  78 
  79 function initialize_localStorage() {
  80     var max = localStorage.max_breadcrumbs;
  81     if (max == null) {
  82         max = '8';
  83         localStorage.max_breadcrumbs = max;
  84     }
  85 
  86     var mt = localStorage.multi_tracker;
  87     if (mt == null) {
  88         mt = 'off';
  89         localStorage.multi_tracker = mt;
  90     }
  91 }
  92 
  93 function bindEventToNavigation(){
  94     var paths = location.pathname.split('/');
  95     var title = '';
  96     var tracker = location.pathname.split('/')[1];
  97     initialize_localStorage();
  98     if (paths.length >= 3) {
  99         // Looking for issue12345.
 100         var klassitem = paths[2];
 101         var titles = document.getElementsByName(hover_text_field_name);
 102         if (titles.length > 0) {
 103             title = titles[0].value;
 104         }
 105         if (klassitem.startsWith('issue')) {
 106             issue = klassitem.slice(5);
 107             if (issue.search(/^\d+$/) != -1) {
 108                 // Issue must contain only digits.
 109                 addBreadCrumb(tracker, issue, title);
 110                 addBreadCrumb('multi', issue, title);
 111             }
 112         }
 113     }
 114     showBreadCrumb();
 115 }
 116 
 117 window.onload = bindEventToNavigation;
 118 
 119 // Add issue to the front of the breadcrumbs.
 120 function addBreadCrumb(tracker, issue, title) {
 121     var all_bcs = {};
 122     var raw_bc = localStorage.breadcrumb;
 123     var bc = []
 124     var loc = {protocol: location.protocol, host: location.host, pathname: location.pathname};
 125     if (raw_bc) {
 126         all_bcs = JSON.parse(raw_bc);
 127 	bc = all_bcs[tracker];
 128 	if (bc) {
 129 	    if (bc.find((val) => val[0] == issue)) {
 130 		// Remove issue and put at the front.
 131 		bc = [[issue, title, loc]].concat(bc.filter((val) => issue != val[0]));
 132 	    } else if (bc.length >= localStorage.max_breadcrumbs) {
 133 		// Lop off the last element and put issue at the front.
 134 		bc = [[issue, title, loc]].concat(bc.slice(0, localStorage.max_breadcrumbs - 1));
 135 	    } else {
 136 		// Plenty of room for the new issue.
 137 		bc = [[issue, title, loc]].concat(bc);
 138 	    }
 139 	} else {
 140             // First issue
 141             bc = [[issue, title, loc]];
 142 	}
 143     } else {
 144         // First issue
 145         bc = [[issue, title, loc]];
 146     }
 147     all_bcs[tracker] = bc;
 148     
 149     localStorage.breadcrumb = JSON.stringify(all_bcs);
 150 }
 151 
 152 function showBreadCrumb(){
 153     var tracker, bc, all_bcs;
 154     var raw_bc = localStorage.breadcrumb;
 155     var html = "";
 156     if (localStorage.multi_tracker == 'on') {
 157 	tracker = 'multi';
 158     } else {
 159 	tracker = location.pathname.split('/')[1];
 160     }
 161 
 162     if (raw_bc) {
 163         var all_bcs = JSON.parse(raw_bc);
 164 	if (tracker in all_bcs) {
 165 	    bc = all_bcs[tracker];
 166 	} else {
 167 	    bc = {};
 168 	}
 169         // alert('showBreadCrumb: bc=' + bc + ', bc.length=' + bc.length);
 170         var front, tracker, issue, title, loc;
 171         for (var i in bc) {
 172             issue = bc[i][0];
 173             title = bc[i][1];
 174             if (bc[i].length > 2) {
 175                 // Have location detail here.
 176                 loc = bc[i][2];
 177             } else {
 178                 loc = location;
 179             }
 180             tracker = loc.pathname.split('/')[1];
 181             if (tracker != location.pathname.split('/')[1]) {
 182                 // If jumping to another tracker, indicate that.
 183                 // Scoot it to the right so the mouse doesn't cover it up.
 184                 title = '  ' + tracker + ': ' + title;
 185             }
 186             front = loc.protocol + "//" + loc.host + "/" + tracker;
 187             html = html + ("<a href='" + front + "/issue" + issue
 188                            + "' title='" + title.replace("'", "`")
 189                            + "'>" + issue + "</a>&nbsp;&nbsp;");
 190         }
 191     }
 192     // alert('showBreadCrumb: html=' + html);
 193     document.getElementById('breadcrumb').innerHTML = html;
 194 }
 195 
 196 // Code to display the list of fields in item.issue.html.
 197 // It may be useful when deciding what to put in hover_text_field_name.
 198 // Return array of INPUT element names.
 199 function get_issue_field_names() {
 200     var inputs = document.getElementsByTagName('INPUT');
 201     var names = [];
 202     var name;
 203     for (var i in inputs) {
 204         if (i.search(/^\d+$/) != -1) {
 205 	    name = inputs[i].name;
 206 	    if (name == null || name.length <= 0 || name[0] == '@') {
 207 		continue;
 208 	    }
 209 	    if (name.search(/^submit/) == -1) {
 210 		names.push(name);
 211 	    }
 212 	}
 213     }
 214     var selects = document.getElementsByTagName('SELECT');
 215     var sel;
 216     for (var i in selects) {
 217         if (i.search(/^\d+$/) != -1) {
 218 	    sel = selects[i];
 219 	    names.push(sel.name);
 220 	}
 221     }
 222 
 223     return [...new Set(names)].sort();
 224 }
 225 
 226 // localStorage.removeItem('breadcrumb')
 227 

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2022-05-17 15:18:25, 7.8 KB) [[attachment:breadcrumb.js]]
  • [get | view] (2022-03-10 17:05:28, 13.1 KB) [[attachment:breadcrumbs-407x125.jpg]]
  • [get | view] (2022-05-17 15:18:56, 2.8 KB) [[attachment:issue.breadcrumb.html]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.