diff --git a/static/application.css b/static/application.css index c2155b1..f17facb 100644 --- a/static/application.css +++ b/static/application.css @@ -36,14 +36,6 @@ textarea { user-select: none; } -.line { - /* display: block;*/ -} - -/*.line:hover { - background-color: #cbd387; -}*/ - .lineHighlight { background-color: yellow; } diff --git a/static/application.js b/static/application.js index 78d5e73..1bd825d 100644 --- a/static/application.js +++ b/static/application.js @@ -3,428 +3,443 @@ ///// represents a single document var haste_document = function(app) { - this.locked = false; - this.app = app; -}; - -// Escapes HTML tag characters -haste_document.prototype.htmlEscape = function(s) { - return s - .replace(/&/g, '&') - .replace(/>/g, '>') - .replace(/= selectedLines.startLine && - currentLine <= selectedLines.endLine - ) { - spanClass = "lineHighlight"; - } - highlighted = "" + highlighted + ""; - high.value += highlighted + "\n"; - } - //// scroll to position in document after ensuring components h"ve had time to render - setTimeout(function() { - // show current line and the one before it - if (selectedLines.startLine >= 3) { - document.body.scrollTo(0, $("#line-" + (selectedLines.startLine - 2)).offset().top) - } else { - // if lines 1-2, go to top of file - document.body.scrollTo(0, 0); - } - }, 0); - } catch (err) { - // failed highlight, fall back on auto - high = hljs.highlightAuto(res.data); - } - callback({ - value: high.value, - key: key, - language: high.language || lang, - lineCount: res.data.split('\n').length - }); - }, - error: function() { - callback(false); - } - }); -}; - -// Save this document to the server and lock it here -haste_document.prototype.save = function(data, callback) { - if (this.locked) { - return false; - } - this.data = data; - var _this = this; - $.ajax(_this.app.baseUrl + 'documents', { - type: 'post', - data: data, - dataType: 'json', - contentType: 'text/plain; charset=utf-8', - success: function(res) { - _this.locked = true; - _this.key = res.key; - var high = hljs.highlightAuto(data); - callback(null, { - value: high.value, - key: res.key, - language: high.language, - lineCount: data.split('\n').length - }); - }, - error: function(res) { - try { - callback($.parseJSON(res.responseText)); - } - catch (e) { - callback({message: 'Something went wrong!'}); - } - } - }); -}; - -///// represents the paste application - -var haste = function(appName, options) { - this.appName = appName; - this.$textarea = $('textarea'); - this.$box = $('#box'); - this.$code = $('#box code'); - this.$linenos = $('#linenos'); - this.options = options; - this.configureShortcuts(); - this.configureButtons(); - // If twitter is disabled, hide the button - if (!options.twitter) { - $('#box2 .twitter').hide(); + this.locked = false; + this.app = app; }; - this.baseUrl = options.baseUrl || '/'; - this.selectedLines = options.selectedLines; -}; - -// Set the page title - include the appName -haste.prototype.setTitle = function(ext) { - var title = ext ? this.appName + ' - ' + ext : this.appName; - document.title = title; -}; - -// Show a message box -haste.prototype.showMessage = function(msg, cls) { - var msgBox = $('
  • '+msg+'
  • '); - $('#messages').prepend(msgBox); - setTimeout(function() { - msgBox.slideUp('fast', function() { $(this).remove(); }); - }, 3000); -}; - -// Show the light key -haste.prototype.lightKey = function() { - this.configureKey(['new', 'save']); -}; - -// Show the full key -haste.prototype.fullKey = function() { - this.configureKey(['new', 'duplicate', 'twitter', 'raw']); -}; - -// Set the key up for certain things to be enabled -haste.prototype.configureKey = function(enable) { - var $this, i = 0; - $('#box2 .function').each(function() { - $this = $(this); - for (i = 0; i < enable.length; i++) { - if ($this.hasClass(enable[i])) { - $this.addClass('enabled'); - return true; - } - } - $this.removeClass('enabled'); - }); -}; - -// Remove the current document (if there is one) -// and set up for a new one -haste.prototype.newDocument = function(hideHistory) { - this.$box.hide(); - this.doc = new haste_document(this); - if (!hideHistory) { - window.history.pushState(null, this.appName, this.baseUrl); - } - this.setTitle(); - this.lightKey(); - this.$textarea.val('').show('fast', function() { - this.focus(); - }); - this.selectedLines = { startLine: null, endLine: null }; - this.removeLineNumbers(); -}; - -// Map of common extensions -// Note: this list does not need to include anything that IS its extension, -// due to the behavior of lookupTypeByExtension and lookupExtensionByType -// Note: optimized for lookupTypeByExtension -haste.extensionMap = { - rb: 'ruby', py: 'python', pl: 'perl', php: 'php', scala: 'scala', go: 'go', - xml: 'xml', html: 'xml', htm: 'xml', css: 'css', js: 'javascript', vbs: 'vbscript', - lua: 'lua', pas: 'delphi', java: 'java', cpp: 'cpp', cc: 'cpp', m: 'objectivec', - vala: 'vala', sql: 'sql', sm: 'smalltalk', lisp: 'lisp', ini: 'ini', - diff: 'diff', bash: 'bash', sh: 'bash', tex: 'tex', erl: 'erlang', hs: 'haskell', - md: 'markdown', txt: '', coffee: 'coffee', swift: 'swift' -}; - -// Look up the extension preferred for a type -// If not found, return the type itself - which we'll place as the extension -haste.prototype.lookupExtensionByType = function(type) { - for (var key in haste.extensionMap) { - if (haste.extensionMap[key] === type) return key; - } - return type; -}; - -// Look up the type for a given extension -// If not found, return the extension - which we'll attempt to use as the type -haste.prototype.lookupTypeByExtension = function(ext) { - return haste.extensionMap[ext] || ext; -}; - -// Add line numbers to the document -// For the specified number of lines, each with a class and id -haste.prototype.addLineNumbers = function(lineCount) { - var h = ''; - for (var i = 0; i < lineCount; i++) { - h += '' + (i + 1) + '
    '; - } - $('#linenos').html(h); -}; - -// Remove the line numbers -haste.prototype.removeLineNumbers = function() { - $('#linenos').html('>'); -}; - -// Load a document and show it -haste.prototype.loadDocument = function(key) { - // Split the key up - var parts = key.split('.', 2); - // Ask for what we want - var _this = this; - _this.doc = new haste_document(this); - _this.doc.load(parts[0], function(ret) { - if (ret) { - _this.$code.html(ret.value); - _this.setTitle(ret.key); - _this.fullKey(); - _this.$textarea.val('').hide(); - _this.$box.show().focus(); - _this.addLineNumbers(ret.lineCount); - } - else { - _this.newDocument(); - } - }, this.lookupTypeByExtension(parts[1])); -}; - -// Duplicate the current document - only if locked -haste.prototype.duplicateDocument = function() { - if (this.doc.locked) { - var currentData = this.doc.data; - this.newDocument(); - this.$textarea.val(currentData); - } -}; - -// Lock the current document -haste.prototype.lockDocument = function() { - var _this = this; - this.doc.save(this.$textarea.val(), function(err, ret) { - if (err) { - _this.showMessage(err.message, 'error'); - } - else if (ret) { - _this.$code.html(ret.value); - _this.setTitle(ret.key); - var file = _this.baseUrl + ret.key; - if (ret.language) { - file += '.' + _this.lookupExtensionByType(ret.language); - } - window.history.pushState(null, _this.appName + '-' + ret.key, file); - _this.fullKey(); - _this.$textarea.val('').hide(); - _this.$box.show().focus(); - _this.addLineNumbers(ret.lineCount); - // Load Document Again - var path = window.location.href; - console.log(path); - _this.loadDocument(path.split('#')[0].split('/').slice(-1)[0]); - } - }); -}; - -haste.prototype.configureButtons = function() { - var _this = this; - this.buttons = [ - { - $where: $('#box2 .save'), - label: 'Save', - shortcutDescription: 'control + s', - shortcut: function(evt) { - return evt.ctrlKey && (evt.keyCode === 83); + + // Escapes HTML tag characters + haste_document.prototype.htmlEscape = function(s) { + return s + .replace(/&/g, '&') + .replace(/>/g, '>') + .replace(/= selectedLines.startLine && + currentLine <= selectedLines.endLine + ) { + spanClass = "lineHighlight"; + } + highlighted = "" + highlighted + ""; + high.value += highlighted + "\n"; + } + //// scroll to position in document after ensuring components h"ve had time to render + setTimeout(function() { + // show current line and the one before it + if (selectedLines.startLine >= 3) { + document.body.scrollTo(0, $("#line-" + (selectedLines.startLine - 2)).offset().top); + } else { + // if lines 1-2, go to top of file + document.body.scrollTo(0, 0); + } + }, 0); + } catch(err) { + // failed highlight, fall back on auto + high = hljs.highlightAuto(res.data); + } + callback({ + value: high.value, + key: key, + language: high.language || lang, + lineCount: res.data.split('\n').length + }); }, - action: function() { - if (_this.$textarea.val().replace(/^\s+|\s+$/g, '') !== '') { - _this.lockDocument(); + error: function() { + callback(false); + } + }); + }; + + // Save this document to the server and lock it here + haste_document.prototype.save = function(data, callback) { + if (this.locked) { + return false; + } + this.data = data; + var _this = this; + $.ajax(_this.app.baseUrl + 'documents', { + type: 'post', + data: data, + dataType: 'json', + contentType: 'text/plain; charset=utf-8', + success: function(res) { + _this.locked = true; + _this.key = res.key; + var high = hljs.highlightAuto(data); + callback(null, { + value: high.value, + key: res.key, + language: high.language, + lineCount: data.split('\n').length + }); + }, + error: function(res) { + try { + callback($.parseJSON(res.responseText)); + } + catch (e) { + callback({message: 'Something went wrong!'}); } } - }, - { - $where: $('#box2 .new'), - label: 'New', - shortcut: function(evt) { - return evt.ctrlKey && evt.keyCode === 78; - }, - shortcutDescription: 'control + n', - action: function() { - _this.newDocument(!_this.doc.key); - } - }, - { - $where: $('#box2 .duplicate'), - label: 'Duplicate & Edit', - shortcut: function(evt) { - return _this.doc.locked && evt.ctrlKey && evt.keyCode === 68; - }, - shortcutDescription: 'control + d', - action: function() { - _this.duplicateDocument(); - } - }, - { - $where: $('#box2 .raw'), - label: 'Just Text', - shortcut: function(evt) { - return evt.ctrlKey && evt.shiftKey && evt.keyCode === 82; - }, - shortcutDescription: 'control + shift + r', - action: function() { - window.location.href = _this.baseUrl + 'raw/' + _this.doc.key; - } - }, - { - $where: $('#box2 .twitter'), - label: 'Twitter', - shortcut: function(evt) { - return _this.options.twitter && _this.doc.locked && evt.shiftKey && evt.ctrlKey && evt.keyCode == 84; - }, - shortcutDescription: 'control + shift + t', - action: function() { - window.open('https://twitter.com/share?url=' + encodeURI(window.location.href)); + }); + }; + + ///// represents the paste application + + var haste = function(appName, options) { + this.appName = appName; + this.$textarea = $('textarea'); + this.$box = $('#box'); + this.$code = $('#box code'); + this.$linenos = $('#linenos'); + this.options = options; + this.configureShortcuts(); + this.configureButtons(); + // If twitter is disabled, hide the button + if (!options.twitter) { + $('#box2 .twitter').hide(); + }; + this.baseUrl = options.baseUrl || '/'; + this.selectedLines = options.selectedLines; + }; + + // Set the page title - include the appName + haste.prototype.setTitle = function(ext) { + var title = ext ? this.appName + ' - ' + ext : this.appName; + document.title = title; + }; + + // Show a message box + haste.prototype.showMessage = function(msg, cls) { + var msgBox = $('
  • '+msg+'
  • '); + $('#messages').prepend(msgBox); + setTimeout(function() { + msgBox.slideUp('fast', function() { $(this).remove(); }); + }, 3000); + }; + + // Show the light key + haste.prototype.lightKey = function() { + this.configureKey(['new', 'save']); + }; + + // Show the full key + haste.prototype.fullKey = function() { + this.configureKey(['new', 'duplicate', 'twitter', 'raw']); + }; + + // Set the key up for certain things to be enabled + haste.prototype.configureKey = function(enable) { + var $this, i = 0; + $('#box2 .function').each(function() { + $this = $(this); + for (i = 0; i < enable.length; i++) { + if ($this.hasClass(enable[i])) { + $this.addClass('enabled'); + return true; + } } + $this.removeClass('enabled'); + }); + }; + + // Remove the current document (if there is one) + // and set up for a new one + haste.prototype.newDocument = function(hideHistory) { + this.$box.hide(); + this.doc = new haste_document(this); + if (!hideHistory) { + window.history.pushState(null, this.appName, this.baseUrl); } - ]; - for (var i = 0; i < this.buttons.length; i++) { - this.configureButton(this.buttons[i]); - } -}; - -haste.prototype.configureButton = function(options) { - // Handle the click action - options.$where.click(function(evt) { - evt.preventDefault(); - if (!options.clickDisabled && $(this).hasClass('enabled')) { - options.action(); + this.setTitle(); + this.lightKey(); + this.$textarea.val('').show('fast', function() { + this.focus(); + }); + this.selectedLines = { startLine: null, endLine: null }; + this.removeLineNumbers(); + }; + + // Map of common extensions + // Note: this list does not need to include anything that IS its extension, + // due to the behavior of lookupTypeByExtension and lookupExtensionByType + // Note: optimized for lookupTypeByExtension + haste.extensionMap = { + rb: 'ruby', py: 'python', pl: 'perl', php: 'php', scala: 'scala', go: 'go', + xml: 'xml', html: 'xml', htm: 'xml', css: 'css', js: 'javascript', vbs: 'vbscript', + lua: 'lua', pas: 'delphi', java: 'java', cpp: 'cpp', cc: 'cpp', m: 'objectivec', + vala: 'vala', sql: 'sql', sm: 'smalltalk', lisp: 'lisp', ini: 'ini', + diff: 'diff', bash: 'bash', sh: 'bash', tex: 'tex', erl: 'erlang', hs: 'haskell', + md: 'markdown', txt: '', coffee: 'coffee', swift: 'swift' + }; + + // Look up the extension preferred for a type + // If not found, return the type itself - which we'll place as the extension + haste.prototype.lookupExtensionByType = function(type) { + for (var key in haste.extensionMap) { + if (haste.extensionMap[key] === type) return key; } - }); - // Show the label - options.$where.mouseenter(function() { - $('#box3 .label').text(options.label); - $('#box3 .shortcut').text(options.shortcutDescription || ''); - $('#box3').show(); - $(this).append($('#pointer').remove().show()); - }); - // Hide the label - options.$where.mouseleave(function() { - $('#box3').hide(); - $('#pointer').hide(); - }); -}; - -// Configure keyboard shortcuts for the textarea -haste.prototype.configureShortcuts = function() { - var _this = this; - $(document.body).keydown(function(evt) { - var button; - for (var i = 0 ; i < _this.buttons.length; i++) { - button = _this.buttons[i]; - if (button.shortcut && button.shortcut(evt)) { - evt.preventDefault(); - button.action(); - return; - } + return type; + }; + + // Look up the type for a given extension + // If not found, return the extension - which we'll attempt to use as the type + haste.prototype.lookupTypeByExtension = function(ext) { + return haste.extensionMap[ext] || ext; + }; + + // Add line numbers to the document + // For the specified number of lines + haste.prototype.addLineNumbers = function(lineCount) { + var h = ''; + for (var i = 0; i < lineCount; i++) { + h += + '' + + (i + 1) + + "
    "; } - }); -}; - -///// Tab behavior in the textarea - 2 spaces per tab -$(function() { - - $('textarea').keydown(function(evt) { - if (evt.keyCode === 9) { - evt.preventDefault(); - var myValue = ' '; - // http://stackoverflow.com/questions/946534/insert-text-into-textarea-with-jquery - // For browsers like Internet Explorer - if (document.selection) { - this.focus(); - var sel = document.selection.createRange(); - sel.text = myValue; - this.focus(); - } - // Mozilla and Webkit - else if (this.selectionStart || this.selectionStart == '0') { - var startPos = this.selectionStart; - var endPos = this.selectionEnd; - var scrollTop = this.scrollTop; - this.value = this.value.substring(0, startPos) + myValue + - this.value.substring(endPos,this.value.length); - this.focus(); - this.selectionStart = startPos + myValue.length; - this.selectionEnd = startPos + myValue.length; - this.scrollTop = scrollTop; + $('#linenos').html(h); + }; + + // Remove the line numbers + haste.prototype.removeLineNumbers = function() { + $('#linenos').html('>'); + }; + + // Load a document and show it + haste.prototype.loadDocument = function(key) { + // Split the key up + var parts = key.split('.', 2); + // Ask for what we want + var _this = this; + _this.doc = new haste_document(this); + _this.doc.load(parts[0], function(ret) { + if (ret) { + _this.$code.html(ret.value); + _this.setTitle(ret.key); + _this.fullKey(); + _this.$textarea.val('').hide(); + _this.$box.show().focus(); + _this.addLineNumbers(ret.lineCount); } else { - this.value += myValue; - this.focus(); + _this.newDocument(); } + }, this.lookupTypeByExtension(parts[1])); + }; + + // Duplicate the current document - only if locked + haste.prototype.duplicateDocument = function() { + if (this.doc.locked) { + var currentData = this.doc.data; + this.newDocument(); + this.$textarea.val(currentData); } - }); -}); \ No newline at end of file + }; + + // Lock the current document + haste.prototype.lockDocument = function() { + var _this = this; + this.doc.save(this.$textarea.val(), function(err, ret) { + if (err) { + _this.showMessage(err.message, 'error'); + } + else if (ret) { + _this.$code.html(ret.value); + _this.setTitle(ret.key); + var file = _this.baseUrl + ret.key; + if (ret.language) { + file += '.' + _this.lookupExtensionByType(ret.language); + } + window.history.pushState(null, _this.appName + '-' + ret.key, file); + _this.fullKey(); + _this.$textarea.val('').hide(); + _this.$box.show().focus(); + _this.addLineNumbers(ret.lineCount); + // Load Document Again + var path = window.location.href; + _this.loadDocument(path.split('#')[0].split('/').slice(-1)[0]); + } + }); + }; + + haste.prototype.configureButtons = function() { + var _this = this; + this.buttons = [ + { + $where: $('#box2 .save'), + label: 'Save', + shortcutDescription: 'control + s', + shortcut: function(evt) { + return evt.ctrlKey && (evt.keyCode === 83); + }, + action: function() { + if (_this.$textarea.val().replace(/^\s+|\s+$/g, '') !== '') { + _this.lockDocument(); + } + } + }, + { + $where: $('#box2 .new'), + label: 'New', + shortcut: function(evt) { + return evt.ctrlKey && evt.keyCode === 78; + }, + shortcutDescription: 'control + n', + action: function() { + _this.newDocument(!_this.doc.key); + } + }, + { + $where: $('#box2 .duplicate'), + label: 'Duplicate & Edit', + shortcut: function(evt) { + return _this.doc.locked && evt.ctrlKey && evt.keyCode === 68; + }, + shortcutDescription: 'control + d', + action: function() { + _this.duplicateDocument(); + } + }, + { + $where: $('#box2 .raw'), + label: 'Just Text', + shortcut: function(evt) { + return evt.ctrlKey && evt.shiftKey && evt.keyCode === 82; + }, + shortcutDescription: 'control + shift + r', + action: function() { + window.location.href = _this.baseUrl + 'raw/' + _this.doc.key; + } + }, + { + $where: $('#box2 .twitter'), + label: 'Twitter', + shortcut: function(evt) { + return _this.options.twitter && _this.doc.locked && evt.shiftKey && evt.ctrlKey && evt.keyCode == 84; + }, + shortcutDescription: 'control + shift + t', + action: function() { + window.open('https://twitter.com/share?url=' + encodeURI(window.location.href)); + } + } + ]; + for (var i = 0; i < this.buttons.length; i++) { + this.configureButton(this.buttons[i]); + } + }; + + haste.prototype.configureButton = function(options) { + // Handle the click action + options.$where.click(function(evt) { + evt.preventDefault(); + if (!options.clickDisabled && $(this).hasClass('enabled')) { + options.action(); + } + }); + // Show the label + options.$where.mouseenter(function() { + $('#box3 .label').text(options.label); + $('#box3 .shortcut').text(options.shortcutDescription || ''); + $('#box3').show(); + $(this).append($('#pointer').remove().show()); + }); + // Hide the label + options.$where.mouseleave(function() { + $('#box3').hide(); + $('#pointer').hide(); + }); + }; + + // Configure keyboard shortcuts for the textarea + haste.prototype.configureShortcuts = function() { + var _this = this; + $(document.body).keydown(function(evt) { + var button; + for (var i = 0 ; i < _this.buttons.length; i++) { + button = _this.buttons[i]; + if (button.shortcut && button.shortcut(evt)) { + evt.preventDefault(); + button.action(); + return; + } + } + }); + }; + + ///// Tab behavior in the textarea - 2 spaces per tab + $(function() { + + $('textarea').keydown(function(evt) { + if (evt.keyCode === 9) { + evt.preventDefault(); + var myValue = ' '; + // http://stackoverflow.com/questions/946534/insert-text-into-textarea-with-jquery + // For browsers like Internet Explorer + if (document.selection) { + this.focus(); + var sel = document.selection.createRange(); + sel.text = myValue; + this.focus(); + } + // Mozilla and Webkit + else if (this.selectionStart || this.selectionStart == '0') { + var startPos = this.selectionStart; + var endPos = this.selectionEnd; + var scrollTop = this.scrollTop; + this.value = this.value.substring(0, startPos) + myValue + + this.value.substring(endPos,this.value.length); + this.focus(); + this.selectionStart = startPos + myValue.length; + this.selectionEnd = startPos + myValue.length; + this.scrollTop = scrollTop; + } + else { + this.value += myValue; + this.focus(); + } + } + }); + + }); \ No newline at end of file diff --git a/static/index.html b/static/index.html index ae13a01..d33d94f 100644 --- a/static/index.html +++ b/static/index.html @@ -1,166 +1,162 @@ - + - hastebin - - - + hastebin + + + - - - + + + - + - - function handleMouseUp(lineId) { - if(!isDragging){ - return; - } - if(isNaN(lineId)){ - lineId = app.selectedLines.endLine; - }else { - lineId = lineId + 1; - } - updateWindowLineHash(lineId); - isDragging = false; - } - + - + + - - - -
    - -
    - +
    + +
    + +
    +
    + + + + + +
    +
    -
    - - - - - -
    - -
    -
    - - +
    + + - + \ No newline at end of file