| 1 | #include <string>
 | 
| 2 | 
 | 
| 3 | namespace souffle {
 | 
| 4 | namespace profile {
 | 
| 5 | namespace html {
 | 
| 6 | std::string jsTableSort = R"___(
 | 
| 7 | /*!
 | 
| 8 |  * tablesort v4.1.0 (2016-12-29)
 | 
| 9 |  * http://tristen.ca/tablesort/demo/
 | 
| 10 |  * Copyright (c) 2016 ; Licensed MIT
 | 
| 11 |  */
 | 
| 12 | (function() {
 | 
| 13 |     function Tablesort(el, options) {
 | 
| 14 |         if (!(this instanceof Tablesort)) return new Tablesort(el, options);
 | 
| 15 | 
 | 
| 16 |         if (!el || el.tagName !== 'TABLE') {
 | 
| 17 |             throw new Error('Element must be a table');
 | 
| 18 |         }
 | 
| 19 |         this.init(el, options || {});
 | 
| 20 |     }
 | 
| 21 | 
 | 
| 22 |     var sortOptions = [];
 | 
| 23 | 
 | 
| 24 |     var createEvent = function(name) {
 | 
| 25 |         var evt;
 | 
| 26 | 
 | 
| 27 |         if (!window.CustomEvent || typeof window.CustomEvent !== 'function') {
 | 
| 28 |             evt = document.createEvent('CustomEvent');
 | 
| 29 |             evt.initCustomEvent(name, false, false, undefined);
 | 
| 30 |         } else {
 | 
| 31 |             evt = new CustomEvent(name);
 | 
| 32 |         }
 | 
| 33 | 
 | 
| 34 |         return evt;
 | 
| 35 |     };
 | 
| 36 | 
 | 
| 37 |     var getInnerText = function(el) {
 | 
| 38 |         return el.getAttribute('data-sort') || el.textContent || el.innerText || '';
 | 
| 39 |     };
 | 
| 40 | 
 | 
| 41 |     // Default sort method if no better sort method is found
 | 
| 42 |     var caseInsensitiveSort = function(a, b) {
 | 
| 43 |         a = a.toLowerCase();
 | 
| 44 |         b = b.toLowerCase();
 | 
| 45 | 
 | 
| 46 |         if (a === b) return 0;
 | 
| 47 |         if (a < b) return 1;
 | 
| 48 | 
 | 
| 49 |         return -1;
 | 
| 50 |     };
 | 
| 51 | 
 | 
| 52 |     // Stable sort function
 | 
| 53 |     // If two elements are equal under the original sort function,
 | 
| 54 |     // then there relative order is reversed
 | 
| 55 |     var stabilize = function(sort, antiStabilize) {
 | 
| 56 |         return function(a, b) {
 | 
| 57 |             var unstableResult = sort(a.td, b.td);
 | 
| 58 | 
 | 
| 59 |             if (unstableResult === 0) {
 | 
| 60 |                 if (antiStabilize) return b.index - a.index;
 | 
| 61 |                 return a.index - b.index;
 | 
| 62 |             }
 | 
| 63 | 
 | 
| 64 |             return unstableResult;
 | 
| 65 |         };
 | 
| 66 |     };
 | 
| 67 | 
 | 
| 68 |     Tablesort.extend = function(name, pattern, sort) {
 | 
| 69 |         if (typeof pattern !== 'function' || typeof sort !== 'function') {
 | 
| 70 |             throw new Error('Pattern and sort must be a function');
 | 
| 71 |         }
 | 
| 72 | 
 | 
| 73 |         sortOptions.push({
 | 
| 74 |             name: name,
 | 
| 75 |             pattern: pattern,
 | 
| 76 |             sort: sort
 | 
| 77 |         });
 | 
| 78 |     };
 | 
| 79 | 
 | 
| 80 |     Tablesort.prototype = {
 | 
| 81 | 
 | 
| 82 |         init: function(el, options) {
 | 
| 83 |             var that = this,
 | 
| 84 |                 firstRow,
 | 
| 85 |                 defaultSort,
 | 
| 86 |                 i,
 | 
| 87 |                 cell;
 | 
| 88 | 
 | 
| 89 |             that.table = el;
 | 
| 90 |             that.thead = false;
 | 
| 91 |             that.options = options;
 | 
| 92 | 
 | 
| 93 |             if (el.rows && el.rows.length > 0) {
 | 
| 94 |                 if (el.tHead && el.tHead.rows.length > 0) {
 | 
| 95 |                     for (i = 0; i < el.tHead.rows.length; i++) {
 | 
| 96 |                         if (el.tHead.rows[i].getAttribute('data-sort-method') === 'thead') {
 | 
| 97 |                             firstRow = el.tHead.rows[i];
 | 
| 98 |                             break;
 | 
| 99 |                         }
 | 
| 100 |                     }
 | 
| 101 |                     if (!firstRow) {
 | 
| 102 |                         firstRow = el.tHead.rows[el.tHead.rows.length - 1];
 | 
| 103 |                     }
 | 
| 104 |                     that.thead = true;
 | 
| 105 |                 } else {
 | 
| 106 |                     firstRow = el.rows[0];
 | 
| 107 |                 }
 | 
| 108 |             }
 | 
| 109 | 
 | 
| 110 |             if (!firstRow) return;
 | 
| 111 | 
 | 
| 112 |             var onClick = function() {
 | 
| 113 |                 if (that.current && that.current !== this) {
 | 
| 114 |                     that.current.removeAttribute('aria-sort');
 | 
| 115 |                 }
 | 
| 116 | 
 | 
| 117 |                 that.current = this;
 | 
| 118 |                 that.sortTable(this);
 | 
| 119 |             };
 | 
| 120 | 
 | 
| 121 |             // Assume first row is the header and attach a click handler to each.
 | 
| 122 |             for (i = 0; i < firstRow.cells.length; i++) {
 | 
| 123 |                 cell = firstRow.cells[i];
 | 
| 124 |                 cell.setAttribute('role','columnheader');
 | 
| 125 |                 if (cell.getAttribute('data-sort-method') !== 'none') {
 | 
| 126 |                     cell.tabindex = 0;
 | 
| 127 |                     cell.addEventListener('click', onClick, false);
 | 
| 128 | 
 | 
| 129 |                     if (cell.getAttribute('data-sort-default') !== null) {
 | 
| 130 |                         defaultSort = cell;
 | 
| 131 |                     }
 | 
| 132 |                 }
 | 
| 133 |             }
 | 
| 134 | 
 | 
| 135 |             if (defaultSort) {
 | 
| 136 |                 that.current = defaultSort;
 | 
| 137 |                 that.sortTable(defaultSort);
 | 
| 138 |             }
 | 
| 139 |         },
 | 
| 140 | 
 | 
| 141 |         sortTable: function(header, update) {
 | 
| 142 |             var that = this,
 | 
| 143 |                 column = header.cellIndex,
 | 
| 144 |                 sortFunction = caseInsensitiveSort,
 | 
| 145 |                 item = '',
 | 
| 146 |                 items = [],
 | 
| 147 |                 i = that.thead ? 0 : 1,
 | 
| 148 |                 sortMethod = header.getAttribute('data-sort-method'),
 | 
| 149 |                 sortOrder = header.getAttribute('aria-sort');
 | 
| 150 | 
 | 
| 151 |             that.table.dispatchEvent(createEvent('beforeSort'));
 | 
| 152 | 
 | 
| 153 |             // If updating an existing sort, direction should remain unchanged.
 | 
| 154 |             if (!update) {
 | 
| 155 |                 if (sortOrder === 'ascending') {
 | 
| 156 |                     sortOrder = 'descending';
 | 
| 157 |                 } else if (sortOrder === 'descending') {
 | 
| 158 |                     sortOrder = 'ascending';
 | 
| 159 |                 } else {
 | 
| 160 |                     sortOrder = that.options.descending ? 'ascending' : 'descending';
 | 
| 161 |                 }
 | 
| 162 | 
 | 
| 163 |                 header.setAttribute('aria-sort', sortOrder);
 | 
| 164 |             }
 | 
| 165 | 
 | 
| 166 |             if (that.table.rows.length < 2) return;
 | 
| 167 | 
 | 
| 168 |             // If we force a sort method, it is not necessary to check rows
 | 
| 169 |             if (!sortMethod) {
 | 
| 170 |                 while (items.length < 3 && i < that.table.tBodies[0].rows.length) {
 | 
| 171 |                     item = getInnerText(that.table.tBodies[0].rows[i].cells[column]);
 | 
| 172 |                     item = item.trim();
 | 
| 173 | 
 | 
| 174 |                     if (item.length > 0) {
 | 
| 175 |                         items.push(item);
 | 
| 176 |                     }
 | 
| 177 | 
 | 
| 178 |                     i++;
 | 
| 179 |                 }
 | 
| 180 | 
 | 
| 181 |                 if (!items) return;
 | 
| 182 |             }
 | 
| 183 | 
 | 
| 184 |             for (i = 0; i < sortOptions.length; i++) {
 | 
| 185 |                 item = sortOptions[i];
 | 
| 186 | 
 | 
| 187 |                 if (sortMethod) {
 | 
| 188 |                     if (item.name === sortMethod) {
 | 
| 189 |                         sortFunction = item.sort;
 | 
| 190 |                         break;
 | 
| 191 |                     }
 | 
| 192 |                 } else if (items.every(item.pattern)) {
 | 
| 193 |                     sortFunction = item.sort;
 | 
| 194 |                     break;
 | 
| 195 |                 }
 | 
| 196 |             }
 | 
| 197 | 
 | 
| 198 |             that.col = column;
 | 
| 199 | 
 | 
| 200 |             for (i = 0; i < that.table.tBodies.length; i++) {
 | 
| 201 |                 var newRows = [],
 | 
| 202 |                     noSorts = {},
 | 
| 203 |                     j,
 | 
| 204 |                     totalRows = 0,
 | 
| 205 |                     noSortsSoFar = 0;
 | 
| 206 | 
 | 
| 207 |                 if (that.table.tBodies[i].rows.length < 2) continue;
 | 
| 208 | 
 | 
| 209 |                 for (j = 0; j < that.table.tBodies[i].rows.length; j++) {
 | 
| 210 |                     item = that.table.tBodies[i].rows[j];
 | 
| 211 |                     if (item.getAttribute('data-sort-method') === 'none') {
 | 
| 212 |                         // keep no-sorts in separate list to be able to insert
 | 
| 213 |                         // them back at their original position later
 | 
| 214 |                         noSorts[totalRows] = item;
 | 
| 215 |                     } else {
 | 
| 216 |                         // Save the index for stable sorting
 | 
| 217 |                         newRows.push({
 | 
| 218 |                             tr: item,
 | 
| 219 |                             td: getInnerText(item.cells[that.col]),
 | 
| 220 |                             index: totalRows
 | 
| 221 |                         });
 | 
| 222 |                     }
 | 
| 223 |                     totalRows++;
 | 
| 224 |                 }
 | 
| 225 |                 // Before we append should we reverse the new array or not?
 | 
| 226 |                 // If we reverse, the sort needs to be `anti-stable` so that
 | 
| 227 |                 // the double negatives cancel out
 | 
| 228 |                 if (sortOrder === 'descending') {
 | 
| 229 |                     newRows.sort(stabilize(sortFunction, true));
 | 
| 230 |                     newRows.reverse();
 | 
| 231 |                 } else {
 | 
| 232 |                     newRows.sort(stabilize(sortFunction, false));
 | 
| 233 |                 }
 | 
| 234 | 
 | 
| 235 |                 // append rows that already exist rather than creating new ones
 | 
| 236 |                 for (j = 0; j < totalRows; j++) {
 | 
| 237 |                     if (noSorts[j]) {
 | 
| 238 |                         // We have a no-sort row for this position, insert it here.
 | 
| 239 |                         item = noSorts[j];
 | 
| 240 |                         noSortsSoFar++;
 | 
| 241 |                     } else {
 | 
| 242 |                         item = newRows[j - noSortsSoFar].tr;
 | 
| 243 |                     }
 | 
| 244 | 
 | 
| 245 |                     // appendChild(x) moves x if already present somewhere else in the DOM
 | 
| 246 |                     that.table.tBodies[i].appendChild(item);
 | 
| 247 |                 }
 | 
| 248 |             }
 | 
| 249 | 
 | 
| 250 |             that.table.dispatchEvent(createEvent('afterSort'));
 | 
| 251 |         },
 | 
| 252 | 
 | 
| 253 |         refresh: function() {
 | 
| 254 |             if (this.current !== undefined) {
 | 
| 255 |                 this.sortTable(this.current, true);
 | 
| 256 |             }
 | 
| 257 |         }
 | 
| 258 |     };
 | 
| 259 | 
 | 
| 260 |     if (typeof module !== 'undefined' && module.exports) {
 | 
| 261 |         module.exports = Tablesort;
 | 
| 262 |     } else {
 | 
| 263 |         window.Tablesort = Tablesort;
 | 
| 264 |     }
 | 
| 265 | })();
 | 
| 266 | 
 | 
| 267 | )___";
 | 
| 268 | }
 | 
| 269 | }  // namespace profile
 | 
| 270 | }  // namespace souffle
 |