31 August 2013
Live
button at the bottom of this page.18 March 2012
17 March 2012
Sometimes, I've been asked to fix some code that was not working properly or explain why it is not working properly. We ended up pasting stuff through the clunky interface which trimmed the script due to limitations. The other variant was to just exchange scripts but that lead to appending numbers to the script name in order to keep track of the changes.
Since that proved itself to be majorly inconvenient, the following system was created using PHP, JS/JSON, SQLite, GeSHi and plain HTML. I've also paid attention that the result can be projected onto a primitive using prim media so that it may be used in teaching classes. It is also one of the reasons we needed to create Homebrew on iOS so that we can run this on a low-end server.
The system has four components:
* a save.php
script used to commit the changes to the database.
* a load.php
script used to load the changes once they have been committed to the database.
* a live.php
script which offers a simple text-only editor.
* a class.php
script which can be projected onto a primitive so that all the changes appear automatically without needed to reload the page.
… and a bunch of Javascript files (read on).
First, create an sqlite
database called live.sqlite
with the following structure:
CREATE TABLE "data" ( "txt" BLOB, "idx" INTEGER NOT NULL, PRIMARY KEY("idx") );
Then, dump the save.php
, load.php
, live.php
and class.php
in the same directory as the sqlite database you created. You need to place all the files in the same directory and the javascript files in a top-level directory under /js/libs/
. You can find the tree-structure of the filesystem in the next section.
In order to project the script in-world, create a primitive and set the media url to:
http://webserver.com/cc/live.php
assuming that your webserver is pointed at by webserver.com
.
Here is an overview of the filesystem assuming 'root
' stands for the top-level directory:
root | <--- webroot | | +-js/ | | | +-libs/ | | | | | +-jquery-1.6.2.min.js | -+ | +-jquery.autogrow.js | | | +-jquery.jeditable.autogrow.js | |=- Javascript | +-jquery.jeditable.js | | components | +-jquery.textarea.js | -+ | +-jquery.snippet.js | <--- syntax highlighting | +-sh_c.js | <--- c-style highlighting | | +-css/ | | | +-jquery.snippet.css | <--- idk wtf this does | | but it certainly +cc/ | does it =)) | | +-live.sqlite | <--- sqlite database +-live.php | -+ +-save.php | |=- PHP pages +-load.php | -+
You may alter the paths but that would require changing the PHP files.
<html> <head> <title>Colaborative Coding</title> <link rel=stylesheet href='/css/jquery.snippet.css'> <style> * { margin:0; padding:0; } a { outline:none; } .fade { width:300px; margin:20px auto; background:#EEE; padding:12px; overflow:hidden; } .fade .tabs { float:left; overflow:auto; } .fade .tabs li { float:left; list-style:none; border:1px solid #444; margin:1px; -moz-border-radius:2px; } .fade .tabs li a { display:block; float:left; width:16px; height:16px; text-align:center; color:#000; text-decoration:none; font:bold 10pt Verdana; background:#CCC; border:1px solid #FFF; } .fade .tabs li:hover { margin:0; border-width:2px; } .fade .tabs li a.selected { border-color:#444; } .fade .items { clear:both; padding:6px 0; position:relative; top:0; left:0; height:1em; } .fade .items div { display:none; position:absolute; top:0; left:0; padding-top:6px; } </style> <script src="/js/libs/jquery-1.6.2.min.js"></script> <script src="/js/libs/jquery.jeditable.js"></script> <script src="/js/libs/jquery.jeditable.autogrow.js"></script> <script src="/js/libs/jquery.autogrow.js"></script> <script src="/js/libs/jquery.textarea.js"></script> <script src="/js/libs/jquery.snippet.js"></script> <script src="/js/libs/sh_c.js"></script> <script src="/js/libs/jquery.idTabs.js"></script> <script type="text/javascript"> var fade = function(id,s){ s.tabs.removeClass(s.selected); s.tab(id).addClass(s.selected); s.items.fadeOut(); s.item(id).fadeIn(); return false; }; </script> <script> $(document).ready(function() { $('.autogrow').editable('save.php', { loadurl : 'load.php?r=' + Math.random(), type : 'autogrow', submit : 'OK', cancel : 'cancel', onblur : 'submit', autogrow : { lineHeight : 16, minHeight : 32 }, callback : function(value, settings) { location.reload(); } }); $('.autogrow').tabby(); $('.autogrow').snippet("c",{style:"vim",transparent:true,showNum:true}); $.fn.fadeTabs = $.idTabs.extend(fade); $(".fade").fadeTabs(); }); </script> </head> <body> <div class="fade"> <ul class="tabs"> <li><a href="#item1">1</a></li> <li><a href="#item2">2</a></li> <li><a href="#item3">3</a></li> </ul> </div> <div class="items"> <?php $db = new PDO('sqlite:live.sqlite'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $q = $db->prepare('SELECT txt FROM data'); $q->execute(); echo <<< EOH <div id="item1"><pre class="autogrow"> EOH; print stripslashes($q->fetchObject()->txt); echo <<< EOH </pre></div><div id="item2"><pre class="autogrow"> EOH; print stripslashes($q->fetchObject()->txt); echo <<< EOH </pre></div><div id="item3"><pre class="autogrow"> EOH; print stripslashes($q->fetchObject()->txt); echo <<< EOH </pre></div> EOH; ?> </div> </body> </html>
<?php try { $db = new PDO('sqlite:live.sqlite'); $q = $db->prepare('SELECT txt FROM data WHERE idx=1'); $q->execute(); print stripslashes($q->fetchObject()->txt); } catch(PDOException $e) { print $e->getMessage(); return; } ?>
<?php if(!isset($_POST['value'])) { print 'ERROR: No POST data.'; return; } $data = $_POST['value']; try { $db = new PDO('sqlite:live.sqlite'); $db->beginTransaction(); $q = $db->prepare('UPDATE data SET txt=(SELECT txt FROM data WHERE idx=2) where idx=3'); $q->execute(); $q = $db->prepare('UPDATE data SET txt=(SELECT txt FROM data WHERE idx=1) where idx=2'); $q->execute(); $q = $db->prepare('UPDATE data SET txt=:txt WHERE idx=1'); $q->execute(array(':txt' => addslashes($data))); $db->commit(); } catch(PDOException $e) { die; } ?>
This is a mirror, the project seems to be down. You can use this one till [http://www.chrysbader.com Chrys] updates his script.
* * Auto Expanding Text Area (1.2.2) * by Chrys Bader (www.chrysbader.com) * chrysb@gmail.com * * Special thanks to: * Jake Chapa - jake@hybridstudio.com * John Resig - jeresig@gmail.com * * Copyright (c) 2008 Chrys Bader (www.chrysbader.com) * Licensed under the GPL (GPL-LICENSE.txt) license. * * * NOTE: This script requires jQuery to work. Download jQuery at www.jquery.com * */ (function(jQuery) { var self = null; jQuery.fn.autogrow = function(o) { return this.each(function() { new jQuery.autogrow(this, o); }); }; /** * The autogrow object. * * @constructor * @name jQuery.autogrow * @param Object e The textarea to create the autogrow for. * @param Hash o A set of key/value pairs to set as configuration properties. * @cat Plugins/autogrow */ jQuery.autogrow = function (e, o) { this.options = o || {}; this.dummy = null; this.interval = null; this.line_height = this.options.lineHeight || parseInt(jQuery(e).css('line-height')); this.min_height = this.options.minHeight || parseInt(jQuery(e).css('min-height')); this.max_height = this.options.maxHeight || parseInt(jQuery(e).css('max-height'));; this.textarea = jQuery(e); if(this.line_height == NaN) this.line_height = 0; // Only one textarea activated at a time, the one being used this.init(); }; jQuery.autogrow.fn = jQuery.autogrow.prototype = { autogrow: '1.2.2' }; jQuery.autogrow.fn.extend = jQuery.autogrow.extend = jQuery.extend; jQuery.autogrow.fn.extend({ init: function() { var self = this; this.textarea.css({overflow: 'hidden', display: 'block'}); this.textarea.bind('focus', function() { self.startExpand() } ).bind('blur', function() { self.stopExpand() }); this.checkExpand(); }, startExpand: function() { var self = this; this.interval = window.setInterval(function() {self.checkExpand()}, 400); }, stopExpand: function() { clearInterval(this.interval); }, checkExpand: function() { if (this.dummy == null) { this.dummy = jQuery('<div></div>'); this.dummy.css({ 'font-size' : this.textarea.css('font-size'), 'font-family': this.textarea.css('font-family'), 'width' : this.textarea.css('width'), 'padding' : this.textarea.css('padding'), 'line-height': this.line_height + 'px', 'overflow-x' : 'hidden', 'position' : 'absolute', 'top' : 0, 'left' : -9999 }).appendTo('body'); } // Strip HTML tags var html = this.textarea.val().replace(/(<|>)/g, ''); // IE is different, as per usual if ($.browser.msie) { html = html.replace(/\n/g, '<BR>new'); } else { html = html.replace(/\n/g, '<br>new'); } if (this.dummy.html() != html) { this.dummy.html(html); if (this.max_height > 0 && (this.dummy.height() + this.line_height > this.max_height)) { this.textarea.css('overflow-y', 'auto'); } else { this.textarea.css('overflow-y', 'hidden'); if (this.textarea.height() < this.dummy.height() + this.line_height || (this.dummy.height() < this.textarea.height())) { this.textarea.animate({height: (this.dummy.height() + this.line_height) + 'px'}, 100); } } } } }); })(jQuery);
Also as a mirror from the jeditable project:
/* * Autogrow textarea for Jeditable * * Copyright (c) 2008 Mika Tuupola * * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * * Depends on Autogrow jQuery plugin by Chrys Bader: * http://www.aclevercookie.com/facebook-like-auto-growing-textarea/ * * Project home: * http://www.appelsiini.net/projects/jeditable * * Revision: $Id$ * */ $.editable.addInputType('autogrow', { element : function(settings, original) { var textarea = $('<textarea />'); if (settings.rows) { textarea.attr('rows', settings.rows); } else { textarea.height(settings.height); } if (settings.cols) { textarea.attr('cols', settings.cols); } else { textarea.width(settings.width); } $(this).append(textarea); return(textarea); }, plugin : function(settings, original) { $('textarea', this).autogrow(settings.autogrow); } });