1/* 2 The SerGIS Project - sergis-author 3 4 Copyright (c) 2015, SerGIS Project Contributors. All rights reserved. 5 Use of this source code is governed by the MIT License, which can be found 6 in the LICENSE.txt file. 7*/ 8 9// This file handles the drawing of the main table. 10 11AUTHOR.TABLE = { 12 /* generateTable */ 13 /* setCurrentPrompt */ 14 /* setExpandAllPrompts */ 15}; 16 17(function () { 18 /** 19 * The current promptIndex that we have "open" (if expandAllPrompts==false). 20 */ 21 var currentPromptIndex = null; 22 23 /** 24 * Whether all prompts should be expanded. 25 */ 26 var expandAllPrompts = false; 27 28 /** 29 * Whether it's our first time auto-scrolling to the prompt we're at (in 30 * which case, we don't want to scroll, because the user just opened the 31 * Author). 32 */ 33 var firstTimeScrolling = true; 34 35 /** 36 * The columns of the table. 37 * Each column has a title string and a generator function. 38 * The generator function is passed 2 arguments: 39 * (1) the prompt index, and (2) `game.jsondata.promptList[promptIndex]`. 40 * The generator function should return either one td element or an array 41 * of td elements. 42 */ 43 var TABLE_COLUMNS = [ 44 { 45 title: "", 46 generator: AUTHOR.TABLE_COLUMNS.generateTitleColumn 47 }, 48 { 49 title: _("Map"), 50 generator: AUTHOR.TABLE_COLUMNS.generateMapColumn 51 }, 52 { 53 title: _("Content"), 54 generator: AUTHOR.TABLE_COLUMNS.generateContentColumn 55 }, 56 { 57 title: _("Choices"), 58 generator: AUTHOR.TABLE_COLUMNS.generateChoicesColumn 59 }, 60 { 61 title: _("Actions"), 62 generator: AUTHOR.TABLE_COLUMNS.generateActionsColumn 63 } 64 ]; 65 66 /** 67 * Set whether all prompts should be expanded. 68 */ 69 AUTHOR.TABLE.setExpandAllPrompts = function (yesorno) { 70 expandAllPrompts = yesorno; 71 currentPromptIndex = null; 72 checkCurrentPrompt(); 73 }; 74 75 /** 76 * Set the current prompt. 77 */ 78 AUTHOR.TABLE.setCurrentPrompt = function (promptIndex) { 79 currentPromptIndex = promptIndex; 80 // Re-draw the table 81 AUTHOR.TABLE.generateTable(); 82 }; 83 84 /** 85 * Update the table based on currentPrompt and/or expandAllRows, then make 86 * sure scrolling is all set up well. 87 */ 88 function checkCurrentPrompt() { 89 var expandAllPromptsHere = game.jsondata.promptList.length <= 1 ? true : expandAllPrompts; 90 forClass("prompt-row-minimal", function (elem) { 91 var isCurrentPromptIndex = currentPromptIndex !== null && elem.getAttribute("data-promptIndex") == currentPromptIndex.toString(); 92 if (expandAllPromptsHere || isCurrentPromptIndex) { 93 // The prompt is expanded, so hide the minimal row 94 elem.className += " prompt-row-hidden"; 95 } else { 96 // The prompt is minimized, so show the minimal row 97 elem.className = removeFromString(elem.className, "prompt-row-hidden"); 98 } 99 }); 100 var finalElem; 101 forClass("prompt-row-full", function (elem) { 102 var isCurrentPromptIndex = currentPromptIndex !== null && elem.getAttribute("data-promptIndex") == currentPromptIndex.toString(); 103 if (expandAllPromptsHere || isCurrentPromptIndex) { 104 // The prompt is expanded, so show the full row 105 elem.className = removeFromString(elem.className, "prompt-row-hidden"); 106 // Is it the current prompt index? 107 if (elem.className.indexOf("toprow") != -1 && isCurrentPromptIndex) { 108 finalElem = elem; 109 } 110 } else { 111 // The prompt is minimized, so hide the full row 112 elem.className += " prompt-row-hidden"; 113 } 114 }); 115 116 // Check scrolling 117 checkScroll(); 118 119 // Scroll the current prompt into view, if applicable 120 if (finalElem) { 121 if (firstTimeScrolling) { 122 firstTimeScrolling = false;
123 } else { 124 setTimeout(function () { 125 var bodyRect = document.body.getBoundingClientRect(), 126 elemRect = finalElem.getBoundingClientRect(), 127 offset = elemRect.top - bodyRect.top; 128 window.scrollTo(0, offset - 60); 129 }, 2); 130 } 131 } 132 } 133 134 135 /** 136 * Make the prompt table. 137 * 138 * @param {number} [newCurrentPromptIndex] - A new current prompt index. 139 * @param {number} [scrollToPromptIndex] - A prompt index to scroll to. 140 */ 141 AUTHOR.TABLE.generateTable = function (newCurrentPromptIndex) { 142 // Get rid of the old table 143 byId("promptContainer").innerHTML = ""; 144 145 // Create the new table and the table header with all the column titles 146 var table = create("table").create("thead").create("tr", /*Children:*/ TABLE_COLUMNS.map(function (column) { 147 return create("th", { 148 text: column.title 149 }); 150 })); 151 152 // Make the table body 153 var tbody = create("tbody"); 154 155 // Generate table row(s) for each prompt 156 game.jsondata.promptList.forEach(function (promptItem, promptIndex) { 157 // First, make the minimal row 158 tbody.appendChild(AUTHOR.TABLE_COLUMNS.generateMinimalRow(promptIndex, promptItem)); 159 160 // 2D array: first dimension is rows, second dimension is columns (td elements) 161 // This allows for some columns that require multple rows for a prompt 162 // (that are still part of this one "row", i.e. prompt) 163 var rows = [[]]; 164 // Generate each table column for this row 165 TABLE_COLUMNS.forEach(function (column, column_index) { 166 var tds = column.generator(promptIndex, promptItem); 167 if (!Array.isArray(tds)) { 168 // It's just one column, so put it in the first row 169 rows[0].push(tds); 170 } else { 171 // This column spans multiple rows 172 tds.forEach(function (td, row_index) { 173 // Make the new row if it doesn't exist 174 if (!rows[row_index]) { 175 rows[row_index] = []; 176 // Fill in empty space in the row up to this column 177 // (Fill it in with `null`s so we can recognize it later) 178 for (var i = 0; i < column_index; i++) { 179 rows[row_index].push(null); 180 } 181 } 182 // Add our column to the row 183 rows[row_index].push(td); 184 }); 185 } 186 }); 187 188 // Add the row(s) to the table 189 rows.forEach(function (row, row_index) { 190 var tds = []; 191 row.forEach(function (td, column_index) { 192 if (td) { 193 // See how many rows after this one in this column are null 194 // For any of those, we must "rowspan" over them 195 var rowspan = 1, rowi = row_index; 196 while (++rowi < rows.length && rows[rowi][column_index] === null) { 197 rowspan++; 198 } 199 // Set the rowspan on our td and add it to the list 200 td.setAttribute("rowspan", "" + rowspan); 201 tds.push(td); 202 } 203 }); 204 // Add this row to the table 205 tbody.appendChild(create("tr", { 206 className: "prompt-row-full " + (row_index === 0 ? "toprow" : "prompt-row-hidden"), 207 "data-promptIndex": promptIndex 208 }, tds)); 209 }); 210 }); 211 212 // Make spacer row (based on # of columns, i.e. # of titles) 213 tbody.appendChild(create("tr", /*Children:*/ TABLE_COLUMNS.map(function (column) { 214 // Make a spacer column for this column 215 return create("td", { 216 text: " ", 217 className: "prompt-container-header-cell-spacer" 218 }); 219 }))); 220 221 // Stick it all in there 222 table.appendChild(tbody); 223 byId("promptContainer").appendChild(table); 224 225 if (typeof newCurrentPromptIndex == "number") { 226 // Select a new current prompt 227 currentPromptIndex = newCurrentPromptIndex; 228 } 229 // Make sure current prompt is selected and scrolling is good 230 checkCurrentPrompt(); 231 }; 232 233 234 235 /** Whether the browser supports "window.pageXOffset" (for checkScroll). */ 236 var supportPageOffset = window.pageXOffset !== undefined; 237 /** Whether the browser's in "Standards Mode" (opposed to "Quirks Mode"). */ 238 var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat"); 239 240 /** Helper function to set the proper width on the table columns. */ 241 function setHeaderWidths(tbl, thead, auto) { 242 // Make sure the header cells stay the same width 243 thead.style.width = auto ? "auto" : thead.offsetWidth + "px"; 244 var kids = tbl.getElementsByTagName("th");
245 var kidSpacers = tbl.getElementsByClassName("prompt-container-header-cell-spacer"); 246 for (var j = 0; j < kids.length; j++) { 247 kidSpacers[j].style.minWidth = kids[j].style.width = auto ? "auto" : kids[j].offsetWidth + "px"; 248 } 249 } 250 251 /** 252 * Check the scrolling and set up the table header accordingly. 253 */ 254 function checkScroll() { 255 var tbl = byId("promptContainer").childNodes[0]; 256 if (tbl) { 257 // Find the <thead> 258 var thead; 259 for (var i = 0; i < tbl.childNodes.length; i++) { 260 if (tbl.childNodes[i].nodeName.toLowerCase() == "thead") { 261 thead = tbl.childNodes[i]; 262 break; 263 } 264 } 265 266 // Find the amount that the window is scrolled 267 var scrollY = supportPageOffset ? window.pageYOffset : 268 isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop; 269 270 // Find out how far the table is from the top of the page 271 var elem = tbl; 272 var offsetY = elem.offsetTop; 273 while ((elem = elem.offsetParent)) { 274 offsetY += elem.offsetTop || 0; 275 } 276 277 // Reset any and all spacing 278 tbl.className = removeFromString(tbl.className, "scrollFixed"); 279 setHeaderWidths(tbl, thead, true); 280 281 // Check if we should be .scrollFixed 282 if (scrollY >= offsetY) { 283 setHeaderWidths(tbl, thead); 284 // And, we should be .scrollFixed; let's add the class 285 tbl.className += " scrollFixed"; 286 } 287 } 288 } 289 290 // Set up the scrolling 291 window.addEventListener("load", function (event) { 292 window.addEventListener("scroll", function (event) { 293 checkScroll(); 294 }, false); 295 checkScroll(); 296 }, false); 297})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.