Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ |
michael@0 | 3 | /* Copyright 2012 Mozilla Foundation |
michael@0 | 4 | * |
michael@0 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
michael@0 | 6 | * you may not use this file except in compliance with the License. |
michael@0 | 7 | * You may obtain a copy of the License at |
michael@0 | 8 | * |
michael@0 | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
michael@0 | 10 | * |
michael@0 | 11 | * Unless required by applicable law or agreed to in writing, software |
michael@0 | 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
michael@0 | 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
michael@0 | 14 | * See the License for the specific language governing permissions and |
michael@0 | 15 | * limitations under the License. |
michael@0 | 16 | */ |
michael@0 | 17 | /* globals PDFJS */ |
michael@0 | 18 | |
michael@0 | 19 | 'use strict'; |
michael@0 | 20 | |
michael@0 | 21 | var FontInspector = (function FontInspectorClosure() { |
michael@0 | 22 | var fonts; |
michael@0 | 23 | var active = false; |
michael@0 | 24 | var fontAttribute = 'data-font-name'; |
michael@0 | 25 | function removeSelection() { |
michael@0 | 26 | var divs = document.querySelectorAll('div[' + fontAttribute + ']'); |
michael@0 | 27 | for (var i = 0, ii = divs.length; i < ii; ++i) { |
michael@0 | 28 | var div = divs[i]; |
michael@0 | 29 | div.className = ''; |
michael@0 | 30 | } |
michael@0 | 31 | } |
michael@0 | 32 | function resetSelection() { |
michael@0 | 33 | var divs = document.querySelectorAll('div[' + fontAttribute + ']'); |
michael@0 | 34 | for (var i = 0, ii = divs.length; i < ii; ++i) { |
michael@0 | 35 | var div = divs[i]; |
michael@0 | 36 | div.className = 'debuggerHideText'; |
michael@0 | 37 | } |
michael@0 | 38 | } |
michael@0 | 39 | function selectFont(fontName, show) { |
michael@0 | 40 | var divs = document.querySelectorAll('div[' + fontAttribute + '=' + |
michael@0 | 41 | fontName + ']'); |
michael@0 | 42 | for (var i = 0, ii = divs.length; i < ii; ++i) { |
michael@0 | 43 | var div = divs[i]; |
michael@0 | 44 | div.className = show ? 'debuggerShowText' : 'debuggerHideText'; |
michael@0 | 45 | } |
michael@0 | 46 | } |
michael@0 | 47 | function textLayerClick(e) { |
michael@0 | 48 | if (!e.target.dataset.fontName || |
michael@0 | 49 | e.target.tagName.toUpperCase() !== 'DIV') { |
michael@0 | 50 | return; |
michael@0 | 51 | } |
michael@0 | 52 | var fontName = e.target.dataset.fontName; |
michael@0 | 53 | var selects = document.getElementsByTagName('input'); |
michael@0 | 54 | for (var i = 0; i < selects.length; ++i) { |
michael@0 | 55 | var select = selects[i]; |
michael@0 | 56 | if (select.dataset.fontName != fontName) { |
michael@0 | 57 | continue; |
michael@0 | 58 | } |
michael@0 | 59 | select.checked = !select.checked; |
michael@0 | 60 | selectFont(fontName, select.checked); |
michael@0 | 61 | select.scrollIntoView(); |
michael@0 | 62 | } |
michael@0 | 63 | } |
michael@0 | 64 | return { |
michael@0 | 65 | // Properties/functions needed by PDFBug. |
michael@0 | 66 | id: 'FontInspector', |
michael@0 | 67 | name: 'Font Inspector', |
michael@0 | 68 | panel: null, |
michael@0 | 69 | manager: null, |
michael@0 | 70 | init: function init() { |
michael@0 | 71 | var panel = this.panel; |
michael@0 | 72 | panel.setAttribute('style', 'padding: 5px;'); |
michael@0 | 73 | var tmp = document.createElement('button'); |
michael@0 | 74 | tmp.addEventListener('click', resetSelection); |
michael@0 | 75 | tmp.textContent = 'Refresh'; |
michael@0 | 76 | panel.appendChild(tmp); |
michael@0 | 77 | |
michael@0 | 78 | fonts = document.createElement('div'); |
michael@0 | 79 | panel.appendChild(fonts); |
michael@0 | 80 | }, |
michael@0 | 81 | cleanup: function cleanup() { |
michael@0 | 82 | fonts.textContent = ''; |
michael@0 | 83 | }, |
michael@0 | 84 | enabled: false, |
michael@0 | 85 | get active() { |
michael@0 | 86 | return active; |
michael@0 | 87 | }, |
michael@0 | 88 | set active(value) { |
michael@0 | 89 | active = value; |
michael@0 | 90 | if (active) { |
michael@0 | 91 | document.body.addEventListener('click', textLayerClick, true); |
michael@0 | 92 | resetSelection(); |
michael@0 | 93 | } else { |
michael@0 | 94 | document.body.removeEventListener('click', textLayerClick, true); |
michael@0 | 95 | removeSelection(); |
michael@0 | 96 | } |
michael@0 | 97 | }, |
michael@0 | 98 | // FontInspector specific functions. |
michael@0 | 99 | fontAdded: function fontAdded(fontObj, url) { |
michael@0 | 100 | function properties(obj, list) { |
michael@0 | 101 | var moreInfo = document.createElement('table'); |
michael@0 | 102 | for (var i = 0; i < list.length; i++) { |
michael@0 | 103 | var tr = document.createElement('tr'); |
michael@0 | 104 | var td1 = document.createElement('td'); |
michael@0 | 105 | td1.textContent = list[i]; |
michael@0 | 106 | tr.appendChild(td1); |
michael@0 | 107 | var td2 = document.createElement('td'); |
michael@0 | 108 | td2.textContent = obj[list[i]].toString(); |
michael@0 | 109 | tr.appendChild(td2); |
michael@0 | 110 | moreInfo.appendChild(tr); |
michael@0 | 111 | } |
michael@0 | 112 | return moreInfo; |
michael@0 | 113 | } |
michael@0 | 114 | var moreInfo = properties(fontObj, ['name', 'type']); |
michael@0 | 115 | var m = /url\(['"]?([^\)"']+)/.exec(url); |
michael@0 | 116 | var fontName = fontObj.loadedName; |
michael@0 | 117 | var font = document.createElement('div'); |
michael@0 | 118 | var name = document.createElement('span'); |
michael@0 | 119 | name.textContent = fontName; |
michael@0 | 120 | var download = document.createElement('a'); |
michael@0 | 121 | download.href = m[1]; |
michael@0 | 122 | download.textContent = 'Download'; |
michael@0 | 123 | var logIt = document.createElement('a'); |
michael@0 | 124 | logIt.href = ''; |
michael@0 | 125 | logIt.textContent = 'Log'; |
michael@0 | 126 | logIt.addEventListener('click', function(event) { |
michael@0 | 127 | event.preventDefault(); |
michael@0 | 128 | console.log(fontObj); |
michael@0 | 129 | }); |
michael@0 | 130 | var select = document.createElement('input'); |
michael@0 | 131 | select.setAttribute('type', 'checkbox'); |
michael@0 | 132 | select.dataset.fontName = fontName; |
michael@0 | 133 | select.addEventListener('click', (function(select, fontName) { |
michael@0 | 134 | return (function() { |
michael@0 | 135 | selectFont(fontName, select.checked); |
michael@0 | 136 | }); |
michael@0 | 137 | })(select, fontName)); |
michael@0 | 138 | font.appendChild(select); |
michael@0 | 139 | font.appendChild(name); |
michael@0 | 140 | font.appendChild(document.createTextNode(' ')); |
michael@0 | 141 | font.appendChild(download); |
michael@0 | 142 | font.appendChild(document.createTextNode(' ')); |
michael@0 | 143 | font.appendChild(logIt); |
michael@0 | 144 | font.appendChild(moreInfo); |
michael@0 | 145 | fonts.appendChild(font); |
michael@0 | 146 | // Somewhat of a hack, should probably add a hook for when the text layer |
michael@0 | 147 | // is done rendering. |
michael@0 | 148 | setTimeout(function() { |
michael@0 | 149 | if (this.active) { |
michael@0 | 150 | resetSelection(); |
michael@0 | 151 | } |
michael@0 | 152 | }.bind(this), 2000); |
michael@0 | 153 | } |
michael@0 | 154 | }; |
michael@0 | 155 | })(); |
michael@0 | 156 | |
michael@0 | 157 | // Manages all the page steppers. |
michael@0 | 158 | var StepperManager = (function StepperManagerClosure() { |
michael@0 | 159 | var steppers = []; |
michael@0 | 160 | var stepperDiv = null; |
michael@0 | 161 | var stepperControls = null; |
michael@0 | 162 | var stepperChooser = null; |
michael@0 | 163 | var breakPoints = {}; |
michael@0 | 164 | return { |
michael@0 | 165 | // Properties/functions needed by PDFBug. |
michael@0 | 166 | id: 'Stepper', |
michael@0 | 167 | name: 'Stepper', |
michael@0 | 168 | panel: null, |
michael@0 | 169 | manager: null, |
michael@0 | 170 | init: function init() { |
michael@0 | 171 | var self = this; |
michael@0 | 172 | this.panel.setAttribute('style', 'padding: 5px;'); |
michael@0 | 173 | stepperControls = document.createElement('div'); |
michael@0 | 174 | stepperChooser = document.createElement('select'); |
michael@0 | 175 | stepperChooser.addEventListener('change', function(event) { |
michael@0 | 176 | self.selectStepper(this.value); |
michael@0 | 177 | }); |
michael@0 | 178 | stepperControls.appendChild(stepperChooser); |
michael@0 | 179 | stepperDiv = document.createElement('div'); |
michael@0 | 180 | this.panel.appendChild(stepperControls); |
michael@0 | 181 | this.panel.appendChild(stepperDiv); |
michael@0 | 182 | if (sessionStorage.getItem('pdfjsBreakPoints')) { |
michael@0 | 183 | breakPoints = JSON.parse(sessionStorage.getItem('pdfjsBreakPoints')); |
michael@0 | 184 | } |
michael@0 | 185 | }, |
michael@0 | 186 | cleanup: function cleanup() { |
michael@0 | 187 | stepperChooser.textContent = ''; |
michael@0 | 188 | stepperDiv.textContent = ''; |
michael@0 | 189 | steppers = []; |
michael@0 | 190 | }, |
michael@0 | 191 | enabled: false, |
michael@0 | 192 | active: false, |
michael@0 | 193 | // Stepper specific functions. |
michael@0 | 194 | create: function create(pageIndex) { |
michael@0 | 195 | var debug = document.createElement('div'); |
michael@0 | 196 | debug.id = 'stepper' + pageIndex; |
michael@0 | 197 | debug.setAttribute('hidden', true); |
michael@0 | 198 | debug.className = 'stepper'; |
michael@0 | 199 | stepperDiv.appendChild(debug); |
michael@0 | 200 | var b = document.createElement('option'); |
michael@0 | 201 | b.textContent = 'Page ' + (pageIndex + 1); |
michael@0 | 202 | b.value = pageIndex; |
michael@0 | 203 | stepperChooser.appendChild(b); |
michael@0 | 204 | var initBreakPoints = breakPoints[pageIndex] || []; |
michael@0 | 205 | var stepper = new Stepper(debug, pageIndex, initBreakPoints); |
michael@0 | 206 | steppers.push(stepper); |
michael@0 | 207 | if (steppers.length === 1) { |
michael@0 | 208 | this.selectStepper(pageIndex, false); |
michael@0 | 209 | } |
michael@0 | 210 | return stepper; |
michael@0 | 211 | }, |
michael@0 | 212 | selectStepper: function selectStepper(pageIndex, selectPanel) { |
michael@0 | 213 | var i; |
michael@0 | 214 | if (selectPanel) { |
michael@0 | 215 | this.manager.selectPanel(this); |
michael@0 | 216 | } |
michael@0 | 217 | for (i = 0; i < steppers.length; ++i) { |
michael@0 | 218 | var stepper = steppers[i]; |
michael@0 | 219 | if (stepper.pageIndex == pageIndex) { |
michael@0 | 220 | stepper.panel.removeAttribute('hidden'); |
michael@0 | 221 | } else { |
michael@0 | 222 | stepper.panel.setAttribute('hidden', true); |
michael@0 | 223 | } |
michael@0 | 224 | } |
michael@0 | 225 | var options = stepperChooser.options; |
michael@0 | 226 | for (i = 0; i < options.length; ++i) { |
michael@0 | 227 | var option = options[i]; |
michael@0 | 228 | option.selected = option.value == pageIndex; |
michael@0 | 229 | } |
michael@0 | 230 | }, |
michael@0 | 231 | saveBreakPoints: function saveBreakPoints(pageIndex, bps) { |
michael@0 | 232 | breakPoints[pageIndex] = bps; |
michael@0 | 233 | sessionStorage.setItem('pdfjsBreakPoints', JSON.stringify(breakPoints)); |
michael@0 | 234 | } |
michael@0 | 235 | }; |
michael@0 | 236 | })(); |
michael@0 | 237 | |
michael@0 | 238 | // The stepper for each page's IRQueue. |
michael@0 | 239 | var Stepper = (function StepperClosure() { |
michael@0 | 240 | // Shorter way to create element and optionally set textContent. |
michael@0 | 241 | function c(tag, textContent) { |
michael@0 | 242 | var d = document.createElement(tag); |
michael@0 | 243 | if (textContent) { |
michael@0 | 244 | d.textContent = textContent; |
michael@0 | 245 | } |
michael@0 | 246 | return d; |
michael@0 | 247 | } |
michael@0 | 248 | |
michael@0 | 249 | function glyphsToString(glyphs) { |
michael@0 | 250 | var out = ''; |
michael@0 | 251 | for (var i = 0; i < glyphs.length; i++) { |
michael@0 | 252 | if (glyphs[i] === null) { |
michael@0 | 253 | out += ' '; |
michael@0 | 254 | } else { |
michael@0 | 255 | out += glyphs[i].fontChar; |
michael@0 | 256 | } |
michael@0 | 257 | } |
michael@0 | 258 | return out; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | var opMap = null; |
michael@0 | 262 | |
michael@0 | 263 | var glyphCommands = { |
michael@0 | 264 | 'showText': 0, |
michael@0 | 265 | 'showSpacedText': 0, |
michael@0 | 266 | 'nextLineShowText': 0, |
michael@0 | 267 | 'nextLineSetSpacingShowText': 2 |
michael@0 | 268 | }; |
michael@0 | 269 | |
michael@0 | 270 | function simplifyArgs(args) { |
michael@0 | 271 | if (typeof args === 'string') { |
michael@0 | 272 | var MAX_STRING_LENGTH = 75; |
michael@0 | 273 | return args.length <= MAX_STRING_LENGTH ? args : |
michael@0 | 274 | args.substr(0, MAX_STRING_LENGTH) + '...'; |
michael@0 | 275 | } |
michael@0 | 276 | if (typeof args !== 'object' || args === null) { |
michael@0 | 277 | return args; |
michael@0 | 278 | } |
michael@0 | 279 | if ('length' in args) { // array |
michael@0 | 280 | var simpleArgs = [], i, ii; |
michael@0 | 281 | var MAX_ITEMS = 10; |
michael@0 | 282 | for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) { |
michael@0 | 283 | simpleArgs.push(simplifyArgs(args[i])); |
michael@0 | 284 | } |
michael@0 | 285 | if (i < args.length) { |
michael@0 | 286 | simpleArgs.push('...'); |
michael@0 | 287 | } |
michael@0 | 288 | return simpleArgs; |
michael@0 | 289 | } |
michael@0 | 290 | var simpleObj = {}; |
michael@0 | 291 | for (var key in args) { |
michael@0 | 292 | simpleObj[key] = simplifyArgs(args[key]); |
michael@0 | 293 | } |
michael@0 | 294 | return simpleObj; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | function Stepper(panel, pageIndex, initialBreakPoints) { |
michael@0 | 298 | this.panel = panel; |
michael@0 | 299 | this.breakPoint = 0; |
michael@0 | 300 | this.nextBreakPoint = null; |
michael@0 | 301 | this.pageIndex = pageIndex; |
michael@0 | 302 | this.breakPoints = initialBreakPoints; |
michael@0 | 303 | this.currentIdx = -1; |
michael@0 | 304 | this.operatorListIdx = 0; |
michael@0 | 305 | } |
michael@0 | 306 | Stepper.prototype = { |
michael@0 | 307 | init: function init() { |
michael@0 | 308 | var panel = this.panel; |
michael@0 | 309 | var content = c('div', 'c=continue, s=step'); |
michael@0 | 310 | var table = c('table'); |
michael@0 | 311 | content.appendChild(table); |
michael@0 | 312 | table.cellSpacing = 0; |
michael@0 | 313 | var headerRow = c('tr'); |
michael@0 | 314 | table.appendChild(headerRow); |
michael@0 | 315 | headerRow.appendChild(c('th', 'Break')); |
michael@0 | 316 | headerRow.appendChild(c('th', 'Idx')); |
michael@0 | 317 | headerRow.appendChild(c('th', 'fn')); |
michael@0 | 318 | headerRow.appendChild(c('th', 'args')); |
michael@0 | 319 | panel.appendChild(content); |
michael@0 | 320 | this.table = table; |
michael@0 | 321 | if (!opMap) { |
michael@0 | 322 | opMap = Object.create(null); |
michael@0 | 323 | for (var key in PDFJS.OPS) { |
michael@0 | 324 | opMap[PDFJS.OPS[key]] = key; |
michael@0 | 325 | } |
michael@0 | 326 | } |
michael@0 | 327 | }, |
michael@0 | 328 | updateOperatorList: function updateOperatorList(operatorList) { |
michael@0 | 329 | var self = this; |
michael@0 | 330 | |
michael@0 | 331 | function cboxOnClick() { |
michael@0 | 332 | var x = +this.dataset.idx; |
michael@0 | 333 | if (this.checked) { |
michael@0 | 334 | self.breakPoints.push(x); |
michael@0 | 335 | } else { |
michael@0 | 336 | self.breakPoints.splice(self.breakPoints.indexOf(x), 1); |
michael@0 | 337 | } |
michael@0 | 338 | StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints); |
michael@0 | 339 | } |
michael@0 | 340 | |
michael@0 | 341 | var MAX_OPERATORS_COUNT = 15000; |
michael@0 | 342 | if (this.operatorListIdx > MAX_OPERATORS_COUNT) { |
michael@0 | 343 | return; |
michael@0 | 344 | } |
michael@0 | 345 | |
michael@0 | 346 | var chunk = document.createDocumentFragment(); |
michael@0 | 347 | var operatorsToDisplay = Math.min(MAX_OPERATORS_COUNT, |
michael@0 | 348 | operatorList.fnArray.length); |
michael@0 | 349 | for (var i = this.operatorListIdx; i < operatorsToDisplay; i++) { |
michael@0 | 350 | var line = c('tr'); |
michael@0 | 351 | line.className = 'line'; |
michael@0 | 352 | line.dataset.idx = i; |
michael@0 | 353 | chunk.appendChild(line); |
michael@0 | 354 | var checked = this.breakPoints.indexOf(i) != -1; |
michael@0 | 355 | var args = operatorList.argsArray[i] || []; |
michael@0 | 356 | |
michael@0 | 357 | var breakCell = c('td'); |
michael@0 | 358 | var cbox = c('input'); |
michael@0 | 359 | cbox.type = 'checkbox'; |
michael@0 | 360 | cbox.className = 'points'; |
michael@0 | 361 | cbox.checked = checked; |
michael@0 | 362 | cbox.dataset.idx = i; |
michael@0 | 363 | cbox.onclick = cboxOnClick; |
michael@0 | 364 | |
michael@0 | 365 | breakCell.appendChild(cbox); |
michael@0 | 366 | line.appendChild(breakCell); |
michael@0 | 367 | line.appendChild(c('td', i.toString())); |
michael@0 | 368 | var fn = opMap[operatorList.fnArray[i]]; |
michael@0 | 369 | var decArgs = args; |
michael@0 | 370 | if (fn in glyphCommands) { |
michael@0 | 371 | var glyphIndex = glyphCommands[fn]; |
michael@0 | 372 | var glyphs = args[glyphIndex]; |
michael@0 | 373 | decArgs = args.slice(); |
michael@0 | 374 | var newArg; |
michael@0 | 375 | if (fn === 'showSpacedText') { |
michael@0 | 376 | newArg = []; |
michael@0 | 377 | for (var j = 0; j < glyphs.length; j++) { |
michael@0 | 378 | if (typeof glyphs[j] === 'number') { |
michael@0 | 379 | newArg.push(glyphs[j]); |
michael@0 | 380 | } else { |
michael@0 | 381 | newArg.push(glyphsToString(glyphs[j])); |
michael@0 | 382 | } |
michael@0 | 383 | } |
michael@0 | 384 | } else { |
michael@0 | 385 | newArg = glyphsToString(glyphs); |
michael@0 | 386 | } |
michael@0 | 387 | decArgs[glyphIndex] = newArg; |
michael@0 | 388 | } |
michael@0 | 389 | line.appendChild(c('td', fn)); |
michael@0 | 390 | line.appendChild(c('td', JSON.stringify(simplifyArgs(decArgs)))); |
michael@0 | 391 | } |
michael@0 | 392 | if (operatorsToDisplay < operatorList.fnArray.length) { |
michael@0 | 393 | line = c('tr'); |
michael@0 | 394 | var lastCell = c('td', '...'); |
michael@0 | 395 | lastCell.colspan = 4; |
michael@0 | 396 | chunk.appendChild(lastCell); |
michael@0 | 397 | } |
michael@0 | 398 | this.operatorListIdx = operatorList.fnArray.length; |
michael@0 | 399 | this.table.appendChild(chunk); |
michael@0 | 400 | }, |
michael@0 | 401 | getNextBreakPoint: function getNextBreakPoint() { |
michael@0 | 402 | this.breakPoints.sort(function(a, b) { return a - b; }); |
michael@0 | 403 | for (var i = 0; i < this.breakPoints.length; i++) { |
michael@0 | 404 | if (this.breakPoints[i] > this.currentIdx) { |
michael@0 | 405 | return this.breakPoints[i]; |
michael@0 | 406 | } |
michael@0 | 407 | } |
michael@0 | 408 | return null; |
michael@0 | 409 | }, |
michael@0 | 410 | breakIt: function breakIt(idx, callback) { |
michael@0 | 411 | StepperManager.selectStepper(this.pageIndex, true); |
michael@0 | 412 | var self = this; |
michael@0 | 413 | var dom = document; |
michael@0 | 414 | self.currentIdx = idx; |
michael@0 | 415 | var listener = function(e) { |
michael@0 | 416 | switch (e.keyCode) { |
michael@0 | 417 | case 83: // step |
michael@0 | 418 | dom.removeEventListener('keydown', listener, false); |
michael@0 | 419 | self.nextBreakPoint = self.currentIdx + 1; |
michael@0 | 420 | self.goTo(-1); |
michael@0 | 421 | callback(); |
michael@0 | 422 | break; |
michael@0 | 423 | case 67: // continue |
michael@0 | 424 | dom.removeEventListener('keydown', listener, false); |
michael@0 | 425 | var breakPoint = self.getNextBreakPoint(); |
michael@0 | 426 | self.nextBreakPoint = breakPoint; |
michael@0 | 427 | self.goTo(-1); |
michael@0 | 428 | callback(); |
michael@0 | 429 | break; |
michael@0 | 430 | } |
michael@0 | 431 | }; |
michael@0 | 432 | dom.addEventListener('keydown', listener, false); |
michael@0 | 433 | self.goTo(idx); |
michael@0 | 434 | }, |
michael@0 | 435 | goTo: function goTo(idx) { |
michael@0 | 436 | var allRows = this.panel.getElementsByClassName('line'); |
michael@0 | 437 | for (var x = 0, xx = allRows.length; x < xx; ++x) { |
michael@0 | 438 | var row = allRows[x]; |
michael@0 | 439 | if (row.dataset.idx == idx) { |
michael@0 | 440 | row.style.backgroundColor = 'rgb(251,250,207)'; |
michael@0 | 441 | row.scrollIntoView(); |
michael@0 | 442 | } else { |
michael@0 | 443 | row.style.backgroundColor = null; |
michael@0 | 444 | } |
michael@0 | 445 | } |
michael@0 | 446 | } |
michael@0 | 447 | }; |
michael@0 | 448 | return Stepper; |
michael@0 | 449 | })(); |
michael@0 | 450 | |
michael@0 | 451 | var Stats = (function Stats() { |
michael@0 | 452 | var stats = []; |
michael@0 | 453 | function clear(node) { |
michael@0 | 454 | while (node.hasChildNodes()) { |
michael@0 | 455 | node.removeChild(node.lastChild); |
michael@0 | 456 | } |
michael@0 | 457 | } |
michael@0 | 458 | function getStatIndex(pageNumber) { |
michael@0 | 459 | for (var i = 0, ii = stats.length; i < ii; ++i) { |
michael@0 | 460 | if (stats[i].pageNumber === pageNumber) { |
michael@0 | 461 | return i; |
michael@0 | 462 | } |
michael@0 | 463 | } |
michael@0 | 464 | return false; |
michael@0 | 465 | } |
michael@0 | 466 | return { |
michael@0 | 467 | // Properties/functions needed by PDFBug. |
michael@0 | 468 | id: 'Stats', |
michael@0 | 469 | name: 'Stats', |
michael@0 | 470 | panel: null, |
michael@0 | 471 | manager: null, |
michael@0 | 472 | init: function init() { |
michael@0 | 473 | this.panel.setAttribute('style', 'padding: 5px;'); |
michael@0 | 474 | PDFJS.enableStats = true; |
michael@0 | 475 | }, |
michael@0 | 476 | enabled: false, |
michael@0 | 477 | active: false, |
michael@0 | 478 | // Stats specific functions. |
michael@0 | 479 | add: function(pageNumber, stat) { |
michael@0 | 480 | if (!stat) { |
michael@0 | 481 | return; |
michael@0 | 482 | } |
michael@0 | 483 | var statsIndex = getStatIndex(pageNumber); |
michael@0 | 484 | if (statsIndex !== false) { |
michael@0 | 485 | var b = stats[statsIndex]; |
michael@0 | 486 | this.panel.removeChild(b.div); |
michael@0 | 487 | stats.splice(statsIndex, 1); |
michael@0 | 488 | } |
michael@0 | 489 | var wrapper = document.createElement('div'); |
michael@0 | 490 | wrapper.className = 'stats'; |
michael@0 | 491 | var title = document.createElement('div'); |
michael@0 | 492 | title.className = 'title'; |
michael@0 | 493 | title.textContent = 'Page: ' + pageNumber; |
michael@0 | 494 | var statsDiv = document.createElement('div'); |
michael@0 | 495 | statsDiv.textContent = stat.toString(); |
michael@0 | 496 | wrapper.appendChild(title); |
michael@0 | 497 | wrapper.appendChild(statsDiv); |
michael@0 | 498 | stats.push({ pageNumber: pageNumber, div: wrapper }); |
michael@0 | 499 | stats.sort(function(a, b) { return a.pageNumber - b.pageNumber; }); |
michael@0 | 500 | clear(this.panel); |
michael@0 | 501 | for (var i = 0, ii = stats.length; i < ii; ++i) { |
michael@0 | 502 | this.panel.appendChild(stats[i].div); |
michael@0 | 503 | } |
michael@0 | 504 | }, |
michael@0 | 505 | cleanup: function () { |
michael@0 | 506 | stats = []; |
michael@0 | 507 | clear(this.panel); |
michael@0 | 508 | } |
michael@0 | 509 | }; |
michael@0 | 510 | })(); |
michael@0 | 511 | |
michael@0 | 512 | // Manages all the debugging tools. |
michael@0 | 513 | var PDFBug = (function PDFBugClosure() { |
michael@0 | 514 | var panelWidth = 300; |
michael@0 | 515 | var buttons = []; |
michael@0 | 516 | var activePanel = null; |
michael@0 | 517 | |
michael@0 | 518 | return { |
michael@0 | 519 | tools: [ |
michael@0 | 520 | FontInspector, |
michael@0 | 521 | StepperManager, |
michael@0 | 522 | Stats |
michael@0 | 523 | ], |
michael@0 | 524 | enable: function(ids) { |
michael@0 | 525 | var all = false, tools = this.tools; |
michael@0 | 526 | if (ids.length === 1 && ids[0] === 'all') { |
michael@0 | 527 | all = true; |
michael@0 | 528 | } |
michael@0 | 529 | for (var i = 0; i < tools.length; ++i) { |
michael@0 | 530 | var tool = tools[i]; |
michael@0 | 531 | if (all || ids.indexOf(tool.id) !== -1) { |
michael@0 | 532 | tool.enabled = true; |
michael@0 | 533 | } |
michael@0 | 534 | } |
michael@0 | 535 | if (!all) { |
michael@0 | 536 | // Sort the tools by the order they are enabled. |
michael@0 | 537 | tools.sort(function(a, b) { |
michael@0 | 538 | var indexA = ids.indexOf(a.id); |
michael@0 | 539 | indexA = indexA < 0 ? tools.length : indexA; |
michael@0 | 540 | var indexB = ids.indexOf(b.id); |
michael@0 | 541 | indexB = indexB < 0 ? tools.length : indexB; |
michael@0 | 542 | return indexA - indexB; |
michael@0 | 543 | }); |
michael@0 | 544 | } |
michael@0 | 545 | }, |
michael@0 | 546 | init: function init() { |
michael@0 | 547 | /* |
michael@0 | 548 | * Basic Layout: |
michael@0 | 549 | * PDFBug |
michael@0 | 550 | * Controls |
michael@0 | 551 | * Panels |
michael@0 | 552 | * Panel |
michael@0 | 553 | * Panel |
michael@0 | 554 | * ... |
michael@0 | 555 | */ |
michael@0 | 556 | var ui = document.createElement('div'); |
michael@0 | 557 | ui.id = 'PDFBug'; |
michael@0 | 558 | |
michael@0 | 559 | var controls = document.createElement('div'); |
michael@0 | 560 | controls.setAttribute('class', 'controls'); |
michael@0 | 561 | ui.appendChild(controls); |
michael@0 | 562 | |
michael@0 | 563 | var panels = document.createElement('div'); |
michael@0 | 564 | panels.setAttribute('class', 'panels'); |
michael@0 | 565 | ui.appendChild(panels); |
michael@0 | 566 | |
michael@0 | 567 | var container = document.getElementById('viewerContainer'); |
michael@0 | 568 | container.appendChild(ui); |
michael@0 | 569 | container.style.right = panelWidth + 'px'; |
michael@0 | 570 | |
michael@0 | 571 | // Initialize all the debugging tools. |
michael@0 | 572 | var tools = this.tools; |
michael@0 | 573 | var self = this; |
michael@0 | 574 | for (var i = 0; i < tools.length; ++i) { |
michael@0 | 575 | var tool = tools[i]; |
michael@0 | 576 | var panel = document.createElement('div'); |
michael@0 | 577 | var panelButton = document.createElement('button'); |
michael@0 | 578 | panelButton.textContent = tool.name; |
michael@0 | 579 | panelButton.addEventListener('click', (function(selected) { |
michael@0 | 580 | return function(event) { |
michael@0 | 581 | event.preventDefault(); |
michael@0 | 582 | self.selectPanel(selected); |
michael@0 | 583 | }; |
michael@0 | 584 | })(i)); |
michael@0 | 585 | controls.appendChild(panelButton); |
michael@0 | 586 | panels.appendChild(panel); |
michael@0 | 587 | tool.panel = panel; |
michael@0 | 588 | tool.manager = this; |
michael@0 | 589 | if (tool.enabled) { |
michael@0 | 590 | tool.init(); |
michael@0 | 591 | } else { |
michael@0 | 592 | panel.textContent = tool.name + ' is disabled. To enable add ' + |
michael@0 | 593 | ' "' + tool.id + '" to the pdfBug parameter ' + |
michael@0 | 594 | 'and refresh (seperate multiple by commas).'; |
michael@0 | 595 | } |
michael@0 | 596 | buttons.push(panelButton); |
michael@0 | 597 | } |
michael@0 | 598 | this.selectPanel(0); |
michael@0 | 599 | }, |
michael@0 | 600 | cleanup: function cleanup() { |
michael@0 | 601 | for (var i = 0, ii = this.tools.length; i < ii; i++) { |
michael@0 | 602 | if (this.tools[i].enabled) { |
michael@0 | 603 | this.tools[i].cleanup(); |
michael@0 | 604 | } |
michael@0 | 605 | } |
michael@0 | 606 | }, |
michael@0 | 607 | selectPanel: function selectPanel(index) { |
michael@0 | 608 | if (typeof index !== 'number') { |
michael@0 | 609 | index = this.tools.indexOf(index); |
michael@0 | 610 | } |
michael@0 | 611 | if (index === activePanel) { |
michael@0 | 612 | return; |
michael@0 | 613 | } |
michael@0 | 614 | activePanel = index; |
michael@0 | 615 | var tools = this.tools; |
michael@0 | 616 | for (var j = 0; j < tools.length; ++j) { |
michael@0 | 617 | if (j == index) { |
michael@0 | 618 | buttons[j].setAttribute('class', 'active'); |
michael@0 | 619 | tools[j].active = true; |
michael@0 | 620 | tools[j].panel.removeAttribute('hidden'); |
michael@0 | 621 | } else { |
michael@0 | 622 | buttons[j].setAttribute('class', ''); |
michael@0 | 623 | tools[j].active = false; |
michael@0 | 624 | tools[j].panel.setAttribute('hidden', 'true'); |
michael@0 | 625 | } |
michael@0 | 626 | } |
michael@0 | 627 | } |
michael@0 | 628 | }; |
michael@0 | 629 | })(); |