Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 33e6d6709683432c36b80c8e5b954b14355dc31e @coreyti coreyti committed Nov 13, 2008
Oops, something went wrong.
Oops, something went wrong.
@@ -0,0 +1,349 @@
+//
+// showdown-gui.js
+//
+// A sample application for Showdown, a javascript port
+// of Markdown.
+//
+// Copyright (c) 2007 John Fraser.
+//
+// Redistributable under a BSD-style open source license.
+// See license.txt for more information.
+//
+// The full source distribution is at:
+//
+// A A L
+// T C A
+// T K B
+//
+// <http://www.attacklab.net/>
+//
+
+//
+// The Showdown converter itself is in showdown.js, which must be
+// included by the HTML before this file is.
+//
+// showdown-gui.js assumes the id and class definitions in
+// showdown.html. It isn't dependent on the CSS, but it does
+// manually hide, display, and resize the individual panes --
+// overriding the stylesheets.
+//
+// This sample application only interacts with showdown.js in
+// two places:
+//
+// In startGui():
+//
+// converter = new Showdown.converter();
+//
+// In convertText():
+//
+// text = converter.makeHtml(text);
+//
+// The rest of this file is user interface stuff.
+//
+
+
+//
+// Register for onload
+//
+window.onload = startGui;
+
+
+//
+// Globals
+//
+
+var converter;
+var convertTextTimer,processingTime;
+var lastText,lastOutput,lastRoomLeft;
+var convertTextSetting, convertTextButton, paneSetting;
+var inputPane,previewPane,outputPane,syntaxPane;
+var maxDelay = 3000; // longest update pause (in ms)
+
+
+//
+// Initialization
+//
+
+function startGui() {
+ // find elements
+ convertTextSetting = document.getElementById("convertTextSetting");
+ convertTextButton = document.getElementById("convertTextButton");
+ paneSetting = document.getElementById("paneSetting");
+
+ inputPane = document.getElementById("inputPane");
+ previewPane = document.getElementById("previewPane");
+ outputPane = document.getElementById("outputPane");
+ syntaxPane = document.getElementById("syntaxPane");
+
+ // set event handlers
+ convertTextSetting.onchange = onConvertTextSettingChanged;
+ convertTextButton.onclick = onConvertTextButtonClicked;
+ paneSetting.onchange = onPaneSettingChanged;
+ window.onresize = setPaneHeights;
+
+ // First, try registering for keyup events
+ // (There's no harm in calling onInput() repeatedly)
+ window.onkeyup = inputPane.onkeyup = onInput;
+
+ // In case we can't capture paste events, poll for them
+ var pollingFallback = window.setInterval(function(){
+ if(inputPane.value != lastText)
+ onInput();
+ },1000);
+
+ // Try registering for paste events
+ inputPane.onpaste = function() {
+ // It worked! Cancel paste polling.
+ if (pollingFallback!=undefined) {
+ window.clearInterval(pollingFallback);
+ pollingFallback = undefined;
+ }
+ onInput();
+ }
+
+ // Try registering for input events (the best solution)
+ if (inputPane.addEventListener) {
+ // Let's assume input also fires on paste.
+ // No need to cancel our keyup handlers;
+ // they're basically free.
+ inputPane.addEventListener("input",inputPane.onpaste,false);
+ }
+
+ // poll for changes in font size
+ // this is cheap; do it often
+ window.setInterval(setPaneHeights,250);
+
+ // start with blank page?
+ if (top.document.location.href.match(/\?blank=1$/))
+ inputPane.value = "";
+
+ // refresh panes to avoid a hiccup
+ onPaneSettingChanged();
+
+ // build the converter
+ converter = new Showdown.converter();
+
+ // do an initial conversion to avoid a hiccup
+ convertText();
+
+ // give the input pane focus
+ inputPane.focus();
+
+ // start the other panes at the top
+ // (our smart scrolling moved them to the bottom)
+ previewPane.scrollTop = 0;
+ outputPane.scrollTop = 0;
+}
+
+
+//
+// Conversion
+//
+
+function convertText() {
+ // get input text
+ var text = inputPane.value;
+
+ // if there's no change to input, cancel conversion
+ if (text && text == lastText) {
+ return;
+ } else {
+ lastText = text;
+ }
+
+ var startTime = new Date().getTime();
+
+ // Do the conversion
+ text = converter.makeHtml(text);
+
+ // display processing time
+ var endTime = new Date().getTime();
+ processingTime = endTime - startTime;
+ document.getElementById("processingTime").innerHTML = processingTime+" ms";
+
+ // save proportional scroll positions
+ saveScrollPositions();
+
+ // update right pane
+ if (paneSetting.value == "outputPane") {
+ // the output pane is selected
+ outputPane.value = text;
+ } else if (paneSetting.value == "previewPane") {
+ // the preview pane is selected
+ previewPane.innerHTML = text;
+ }
+
+ lastOutput = text;
+
+ // restore proportional scroll positions
+ restoreScrollPositions();
+};
+
+
+//
+// Event handlers
+//
+
+function onConvertTextSettingChanged() {
+ // If the user just enabled automatic
+ // updates, we'll do one now.
+ onInput();
+}
+
+function onConvertTextButtonClicked() {
+ // hack: force the converter to run
+ lastText = "";
+
+ convertText();
+ inputPane.focus();
+}
+
+function onPaneSettingChanged() {
+ previewPane.style.display = "none";
+ outputPane.style.display = "none";
+ syntaxPane.style.display = "none";
+
+ // now make the selected one visible
+ top[paneSetting.value].style.display = "block";
+
+ lastRoomLeft = 0; // hack: force resize of new pane
+ setPaneHeights();
+
+ if (paneSetting.value == "outputPane") {
+ // Update output pane
+ outputPane.value = lastOutput;
+ } else if (paneSetting.value == "previewPane") {
+ // Update preview pane
+ previewPane.innerHTML = lastOutput;
+ }
+}
+
+function onInput() {
+// In "delayed" mode, we do the conversion at pauses in input.
+// The pause is equal to the last runtime, so that slow
+// updates happen less frequently.
+//
+// Use a timer to schedule updates. Each keystroke
+// resets the timer.
+
+ // if we already have convertText scheduled, cancel it
+ if (convertTextTimer) {
+ window.clearTimeout(convertTextTimer);
+ convertTextTimer = undefined;
+ }
+
+ if (convertTextSetting.value != "manual") {
+ var timeUntilConvertText = 0;
+ if (convertTextSetting.value == "delayed") {
+ // make timer adaptive
+ timeUntilConvertText = processingTime;
+ }
+
+ if (timeUntilConvertText > maxDelay)
+ timeUntilConvertText = maxDelay;
+
+ // Schedule convertText().
+ // Even if we're updating every keystroke, use a timer at 0.
+ // This gives the browser time to handle other events.
+ convertTextTimer = window.setTimeout(convertText,timeUntilConvertText);
+ }
+}
+
+
+//
+// Smart scrollbar adjustment
+//
+// We need to make sure the user can't type off the bottom
+// of the preview and output pages. We'll do this by saving
+// the proportional scroll positions before the update, and
+// restoring them afterwards.
+//
+
+var previewScrollPos;
+var outputScrollPos;
+
+function getScrollPos(element) {
+ // favor the bottom when the text first overflows the window
+ if (element.scrollHeight <= element.clientHeight)
+ return 1.0;
+ return element.scrollTop/(element.scrollHeight-element.clientHeight);
+}
+
+function setScrollPos(element,pos) {
+ element.scrollTop = (element.scrollHeight - element.clientHeight) * pos;
+}
+
+function saveScrollPositions() {
+ previewScrollPos = getScrollPos(previewPane);
+ outputScrollPos = getScrollPos(outputPane);
+}
+
+function restoreScrollPositions() {
+ // hack for IE: setting scrollTop ensures scrollHeight
+ // has been updated after a change in contents
+ previewPane.scrollTop = previewPane.scrollTop;
+
+ setScrollPos(previewPane,previewScrollPos);
+ setScrollPos(outputPane,outputScrollPos);
+}
+
+//
+// Textarea resizing
+//
+// Some browsers (i.e. IE) refuse to set textarea
+// percentage heights in standards mode. (But other units?
+// No problem. Percentage widths? No problem.)
+//
+// So we'll do it in javascript. If IE's behavior ever
+// changes, we should remove this crap and do 100% textarea
+// heights in CSS, because it makes resizing much smoother
+// on other browsers.
+//
+
+function getTop(element) {
+ var sum = element.offsetTop;
+ while(element = element.offsetParent)
+ sum += element.offsetTop;
+ return sum;
+}
+
+function getElementHeight(element) {
+ var height = element.clientHeight;
+ if (!height) height = element.scrollHeight;
+ return height;
+}
+
+function getWindowHeight(element) {
+ if (window.innerHeight)
+ return window.innerHeight;
+ else if (document.documentElement && document.documentElement.clientHeight)
+ return document.documentElement.clientHeight;
+ else if (document.body)
+ return document.body.clientHeight;
+}
+
+function setPaneHeights() {
+ var textarea = inputPane;
+ var footer = document.getElementById("footer");
+
+ var windowHeight = getWindowHeight();
+ var footerHeight = getElementHeight(footer);
+ var textareaTop = getTop(textarea);
+
+ // figure out how much room the panes should fill
+ var roomLeft = windowHeight - footerHeight - textareaTop;
+
+ if (roomLeft < 0) roomLeft = 0;
+
+ // if it hasn't changed, return
+ if (roomLeft == lastRoomLeft) {
+ return;
+ }
+ lastRoomLeft = roomLeft;
+
+ // resize all panes
+ inputPane.style.height = roomLeft + "px";
+ previewPane.style.height = roomLeft + "px";
+ outputPane.style.height = roomLeft + "px";
+ syntaxPane.style.height = roomLeft + "px";
+}
Oops, something went wrong.

0 comments on commit 33e6d67

Please sign in to comment.