1// 2// showdown-gui.js 3// 4// A sample application for Showdown, a javascript port 5// of --Markdown-- txt2tags. 6// 7// Copyright (c) 2007 John Fraser. 8// 9// Redistributable under a BSD-style open source license. 10// See license.txt for more information. 11// 12// The full source distribution was at: 13// 14// A A L 15// T C A 16// T K B 17// 18// <http://www.attacklab.net/> 19// 20 21// 22// The Showdown converter itself is in showdown.js, which must be 23// included by the HTML before this file is. 24// 25// showdown-gui.js assumes the id and class definitions in 26// showdown.html. It isn't dependent on the CSS, but it does 27// manually hide, display, and resize the individual panes -- 28// overriding the stylesheets. 29// 30// This sample application only interacts with showdown.js in 31// two places: 32// 33// In startGui(): 34// 35// converter = new Showdown.converter(); 36// 37// In convertText(): 38// 39// text = converter.makeHtml(text); 40// 41// The rest of this file is user interface stuff. 42// 43 44 45// 46// Register for onload 47// 48 49 50if(typeof wons == "undefined") 51 wons = new Array(); 52 53wons.push(startGui); 54 55window.onload = function() { 56 for(var i = 0; i < wons.length; i++) 57 wons[i](); 58} 59 60 61// 62// Globals 63// 64 65var converter; 66var convertTextTimer,processingTime; 67var lastText,lastOutput,lastRoomLeft,lastHeight; 68var inputPane,previewPane; 69var maxDelay = 3000; // Longest update pause (in ms) 70var scrollSynchro = true; // Synchronized scrolling 71var typeDisplay = "inline-block"; // "inline" or "block" 72var displayPreview = false; // Show previewPane 73var initSizePane = 400; // First size of inputPane 74var tabMarkItUp = {"line": 10, "col": 10}; // Size of MarkItUp automatic table 75 76// 77// Initialization 78// 79 80function startGui() { 81 82 // find elements 83 if(!(inputPane = document.getElementById('inputPane'))) { 84 window.onresize = setPaneHeights; 85 window.setInterval(setPaneHeights,30); 86 return; 87 } 88 previewPane = document.getElementById("previewPane"); 89 90 if(initSizePane > 0) { 91 inputPane.style.height = initSizePane + "px"; 92 initSizePane = 0; 93 } 94 95 // set event handlers 96 window.onresize = setPaneHeights; 97 98 // First, try registering for keyup events 99 // (There's no harm in calling onInput() repeatedly) 100 101 window.onkeyup = inputPane.onkeyup = onInput; 102 103 // In case we can't capture paste events, poll for them 104 var pollingFallback = window.setInterval(function(){ 105 if(inputPane.value != lastText) 106 onInput(); 107 },1000); 108 109 // Try registering for paste events 110 inputPane.onpaste = function() { 111 // It worked! Cancel paste polling. 112 if (pollingFallback != undefined) { 113 window.clearInterval(pollingFallback); 114 pollingFallback = undefined; 115 } 116 onInput(); 117 } 118 119 // Try registering for input events (the best solution) 120 if (inputPane.addEventListener) { 121 // Let's assume input also fires on paste. 122 // No need to cancel our keyup handlers; 123 // they're basically free. 124 inputPane.addEventListener("input",inputPane.onpaste,false); 125 } 126 127 // poll for changes in font size 128 // this is cheap; do it often 129 window.setInterval(setPaneHeights,30); 130 131 // start with blank page? 132 if (top.document.location.href.match(/\?blank=1$/)) 133 inputPane.value = ""; 134 135 // build the converter 136 converter = new Txt2tags.converter(); 137 138 // do an initial conversion to avoid a hiccup 139 convertText(); 140 141 // give the input pane focus 142 inputPane.focus(); 143 144 //createPreTable(tab["line"],tab["col"]); 145 inputPane.addEventListener('DOMMouseScroll', wheel, false); 146 previewPane.addEventListener('DOMMouseScroll', wheel, false); 147 switchSync(); 148 switchDisplay(typeDisplay); 149 previewCache(displayPreview); 150 151 // start the other panes at the top 152 // (our smart scrolling moved them to the bottom) 153 inputPane.scrollTop = 0; 154 previewPane.scrollTop = 0; 155} 156 157 158// 159// Conversion 160// 161 162function convertText() { 163 // get input text 164 var text = inputPane.value; 165 166 // if there's no change to input, cancel conversion 167 if (text && text == lastText) { 168 return; 169 } else { 170 lastText = text; 171 } 172 173 var startTime = new Date().getTime(); 174 175 // Do the conversion 176 text = converter.makeHtml(text); 177 178 // display processing time 179 var endTime = new Date().getTime(); 180 processingTime = endTime - startTime; 181 182 // save proportional scroll positions 183 saveScrollPositions(); 184 185 // update right pane 186 // the preview pane is selected 187 previewPane.innerHTML = text; 188 189 lastOutput = text; 190 191 // restore proportional scroll positions 192 restoreScrollPositions(); 193}; 194 195 196// 197// Event handlers 198// 199 200function onConvertTextSettingChanged() { 201 // If the user just enabled automatic 202 // updates, we'll do one now. 203 onInput(); 204} 205 206function onConvertTextButtonClicked() { 207 // hack: force the converter to run 208 lastText = ""; 209 210 convertText(); 211 inputPane.focus(); 212} 213 214function onInput() { 215// In "delayed" mode, we do the conversion at pauses in input. 216// The pause is equal to the last runtime, so that slow 217// updates happen less frequently. 218// 219// Use a timer to schedule updates. Each keystroke 220// resets the timer. 221 222 // if we already have convertText scheduled, cancel it 223 if (convertTextTimer) { 224 window.clearTimeout(convertTextTimer); 225 convertTextTimer = undefined; 226 } 227 228 var timeUntilConvertText = 0; 229 // make timer adaptive 230 timeUntilConvertText = processingTime; 231 232 if (timeUntilConvertText > maxDelay) 233 timeUntilConvertText = maxDelay; 234 235 // Schedule convertText(). 236 // Even if we're updating every keystroke, use a timer at 0. 237 // This gives the browser time to handle other events. 238 convertTextTimer = window.setTimeout(convertText,timeUntilConvertText); 239} 240 241 242//
243// Smart scrollbar adjustment 244// 245// We need to make sure the user can't type off the bottom 246// of the preview and output pages. We'll do this by saving 247// the proportional scroll positions before the update, and 248// restoring them afterwards. 249// 250 251var previewScrollPos; 252 253function getScrollPos(element) { 254 // favor the bottom when the text first overflows the window 255 if (element.scrollHeight <= element.clientHeight) 256 return 0; 257 return element.scrollTop/(element.scrollHeight-element.clientHeight); 258} 259 260function setScrollPos(element,pos) { 261 element.scrollTop = (element.scrollHeight - element.clientHeight) * pos; 262} 263 264function saveScrollPositions() { 265 previewScrollPos = getScrollPos(previewPane); 266} 267 268function restoreScrollPositions() { 269 // hack for IE: setting scrollTop ensures scrollHeight 270 // has been updated after a change in contents 271 previewPane.scrollTop = previewPane.scrollTop; 272 273 setScrollPos(previewPane,previewScrollPos); 274} 275 276// 277// Textarea resizing 278// 279// Some browsers (i.e. IE) refuse to set textarea 280// percentage heights in standards mode. (But other units? 281// No problem. Percentage widths? No problem.) 282// 283// So we'll do it in javascript. If IE's behavior ever 284// changes, we should remove this crap and do 100% textarea 285// heights in CSS, because it makes resizing much smoother 286// on other browsers. 287// 288 289function getTop(element) { 290 var sum = element.offsetTop; 291 while(element = element.offsetParent) 292 sum += element.offsetTop; 293 return sum; 294} 295 296function getElementHeight(element) { 297 var height = element.clientHeight; 298 if (!height) height = element.scrollHeight; 299 return height; 300} 301 302function getWindowHeight(element) { 303 if (window.innerHeight) 304 return window.innerHeight; 305 else if (document.documentElement && document.documentElement.clientHeight) 306 return document.documentElement.clientHeight; 307 else if (document.body) 308 return document.body.clientHeight; 309} 310 311function setPaneHeights() { 312 var height = 0; 313 var fix; 314 315 if(document.getElementById('inputPane')) { 316 var markItUp = document.getElementById('markItUpInputPane') ? getElementHeight(document.getElementById('markItUpInputPane')) - getElementHeight(inputPane) : 0; 317 var panesContainer = document.getElementById('panesContainer'); 318 fix = getElementHeight(inputPane) - (inputPane.style.height ? parseInt(inputPane.style.height) : getElementHeight(inputPane)); 319 height = Math.max(200,getElementHeight(inputPane) + markItUp); 320 321 if(typeDisplay == "inline-block") { 322 previewPane.style.height = height - fix + "px"; 323 inputPane.style.height = height - markItUp - fix + "px"; 324 panesContainer.parentNode.style.height = (height + 30) + "px"; 325 document.getElementById('rightContainer').style.top = 0; 326 document.getElementById('rightContainer').style.left = "51%"; 327 } else { 328 previewPane.style.height = height + "px"; 329 inputPane.style.height = height - markItUp - fix + "px"; 330 panesContainer.parentNode.style.height = (height*(displayPreview ? 1 : 2) + 30) + "px"; 331 document.getElementById('rightContainer').style.top = (height + 15) + "px"; 332 document.getElementById('rightContainer').style.left = "0%"; 333 } 334 document.getElementById('leftContainer').style.top = 0; 335 document.getElementById('leftContainer').style.left = "0%"; 336 } else if(document.getElementsByClassName('ajaxContentTextarea').length > 0) { 337 for(var i = 0; i < document.getElementsByClassName('ajaxContentTextarea').length; i++) { 338 fix = getElementHeight(document.getElementsByClassName('ajaxContentTextarea')[i]) 339 - (document.getElementsByClassName('ajaxContentTextarea')[i].style.height 340 ? parseInt(document.getElementsByClassName('ajaxContentTextarea')[i].style.height) 341 : getElementHeight(document.getElementsByClassName('ajaxContentTextarea')[i])); 342 height = Math.max(200,getElementHeight(document.getElementsByClassName('ajaxContentTextarea')[i])); 343 344 document.getElementsByClassName('ajaxContentTextarea')[i].style.height = height - fix + "px"; 345 } 346 } 347} 348 349function switchPlace() { 350 var scrollPos = document.body.scrollTop; 351 var left = document.getElementById('leftContainer'); 352 var right = document.getElementById('rightContainer'); 353 left.setAttribute("class", "switch"); 354 right.setAttribute("class", "switch"); 355 left.setAttribute("id", "rightContainer"); 356 right.setAttribute("id", "leftContainer"); 357 setPaneHeights(); 358 359 setTimeout(function() { 360 left.setAttribute("class",""); 361 right.setAttribute("class",""); 362 document.body.scrollTop = scrollPos; 363 }, 500); 364} 365 366function change() { 367 temp = valueOfPlace[0]; 368 valueOfPlace[0] = valueOfPlace[1]; 369 valueOfPlace[1] = temp; 370} 371 372function sync(idScroll) { 373 if(idScroll) { 374 previewPane.scrollTop = Math.round(inputPane.scrollTop / (inputPane.scrollHeight - inputPane.offsetHeight) 375 * (previewPane.scrollHeight - previewPane.offsetHeight)); 376 } else { 377 inputPane.scrollTop = Math.round(previewPane.scrollTop / (previewPane.scrollHeight - previewPane.offsetHeight) 378 * (inputPane.scrollHeight - inputPane.offsetHeight)); 379 } 380} 381 382function switchSync() { 383 scrollSynchro = !scrollSynchro; 384 if(scrollSynchro) { 385 inputPane.setAttribute("onscroll",""); 386 previewPane.setAttribute("onscroll",""); 387 document.getElementById('synchronizeButton').setAttribute("class", "txt2tagsMenu button_txt2tags_false"); 388 } else { 389 inputPane.setAttribute("onscroll","sync(true)"); 390 previewPane.setAttribute("onscroll","sync(false)"); 391 document.getElementById('synchronizeButton').setAttribute("class", "txt2tagsMenu button_txt2tags_true"); 392 } 393} 394 395function wheel(event) { 396 if (event.detail) { 397 this.scrollTop += (event.detail/3)*100; 398 event.preventDefault; 399 } 400 event.returnValue = false;
401} 402 403function switchDisplay(display) { 404 if(!display) { 405 typeDisplay == "inline-block" ? display = "block" : display = "inline-block"; 406 } 407 var left = document.getElementById("leftContainer"); 408 var right = document.getElementById("rightContainer"); 409 if(display == "inline-block") { 410 left.style.display = "inline-block"; 411 right.style.display = "inline-block"; 412 left.style.width = displayPreview ? "100%" : "49%"; 413 right.style.width = displayPreview ? "100%" : "49%"; 414 typeDisplay = "inline-block"; 415 } else { 416 left.style.display = "block"; 417 right.style.display = "block"; 418 left.style.width = "100%"; 419 right.style.width = "100%"; 420 typeDisplay = "block"; 421 } 422} 423 424function previewCache() { 425 panesContainer = document.getElementById('panesContainer'); 426 if(previewPane.parentNode.id == "leftContainer") switchPlace(); 427 if(displayPreview) { 428 previewPane.style.display = typeDisplay; 429 if(typeDisplay == "inline-block") { 430 document.getElementById("leftContainer").style.width = "49%"; 431 document.getElementById("rightContainer").style.width = "49%"; 432 } else inputPane.style.height = parseInt(inputPane.style.height)/2 + "px"; 433 document.getElementById('displayPreview').setAttribute("class", "txt2tagsMenu button_txt2tags_true"); 434 document.getElementById('changeButton').style.display = "inline-block"; 435 document.getElementById('displayPane').style.display = "inline-block"; 436 document.getElementById('synchronizeButton').style.display = "inline-block"; 437 } else { 438 previewPane.style.display = "none"; 439 if(typeDisplay == "inline-block") { 440 document.getElementById("leftContainer").style.width = "100%"; 441 document.getElementById("rightContainer").style.width = "100%"; 442 } else inputPane.style.height = parseInt(inputPane.style.height)*2 + "px"; 443 document.getElementById('displayPreview').setAttribute("class", "txt2tagsMenu button_txt2tags_false"); 444 document.getElementById('changeButton').style.display = "none"; 445 document.getElementById('displayPane').style.display = "none"; 446 document.getElementById('synchronizeButton').style.display = "none"; 447 } 448 displayPreview = !displayPreview; 449}
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.