summaryrefslogtreecommitdiff
path: root/javascripts
diff options
context:
space:
mode:
Diffstat (limited to 'javascripts')
-rw-r--r--javascripts/Nfa.js3
-rw-r--r--javascripts/Nfa2Dfa.js4
-rw-r--r--javascripts/NfaSimulator.js3
-rw-r--r--javascripts/NfaState.js3
-rw-r--r--javascripts/RegexParser.js5
-rw-r--r--javascripts/Stack.js3
-rw-r--r--javascripts/globals.js23
-rw-r--r--javascripts/graph.js21
-rw-r--r--javascripts/lib/jquery.bgiframe.js104
-rw-r--r--javascripts/lib/jquery.dimensions.js504
-rw-r--r--javascripts/lib/jquery.tooltip.js294
-rw-r--r--javascripts/ui.js (renamed from javascripts/uifunc.js)67
12 files changed, 1010 insertions, 24 deletions
diff --git a/javascripts/Nfa.js b/javascripts/Nfa.js
index a214700..eab1d6c 100644
--- a/javascripts/Nfa.js
+++ b/javascripts/Nfa.js
@@ -2,6 +2,8 @@
* Nfa
* NFA consisting of several NfaStates, following Thompson's algorithm.
*/
+
+
function Nfa(symbol) {
this.startState = null;
this.finalState = null;
@@ -60,3 +62,4 @@ Nfa.prototype.kleene = function() {
return this;
};
+
diff --git a/javascripts/Nfa2Dfa.js b/javascripts/Nfa2Dfa.js
index f38b2cf..a29683e 100644
--- a/javascripts/Nfa2Dfa.js
+++ b/javascripts/Nfa2Dfa.js
@@ -3,6 +3,7 @@
* Convert a NFA to a DFA utilizing epsilon closure.
*/
+
// Compare two NfaStates for equality.
function StateCmp(a, b) {
if (a.id == b.id) {
@@ -11,7 +12,7 @@ function StateCmp(a, b) {
return false
};
-// Compare two stacks filled with NfaStates for euqality.
+// Compare two stacks filled with NfaStates for equality.
function NfaStackCmp(x, y) {
var b = true;
if (x.length != y.length) { return false }
@@ -114,3 +115,4 @@ Nfa2Dfa.prototype.move = function(str, p) {
};
return q;
};
+
diff --git a/javascripts/NfaSimulator.js b/javascripts/NfaSimulator.js
index c5a035f..d8ad9a2 100644
--- a/javascripts/NfaSimulator.js
+++ b/javascripts/NfaSimulator.js
@@ -2,6 +2,8 @@
* NfaSimulator
* Simulate a NFA with a word. Check if regular expression produces word.
*/
+
+
function NfaSimulator(nfa) {
this.startState = nfa.getStartState();
this.finalState = nfa.getFinalState();
@@ -64,3 +66,4 @@ NfaSimulator.prototype.move = function(symbol) {
};
};
};
+
diff --git a/javascripts/NfaState.js b/javascripts/NfaState.js
index 4291295..3453466 100644
--- a/javascripts/NfaState.js
+++ b/javascripts/NfaState.js
@@ -2,6 +2,8 @@
* NfaState
* Represents a state of a NFA (following Thompson's algorithm).
*/
+
+
function NfaState(symbol) {
if(!symbol) {
this.symbol = EPSILON;
@@ -20,3 +22,4 @@ NfaState.prototype.setFollowUp = function(index, state) {
if (! ((index == 0) || (index==1)) ) return;
this.followUps[index] = state;
};
+
diff --git a/javascripts/RegexParser.js b/javascripts/RegexParser.js
index 42251af..63b8558 100644
--- a/javascripts/RegexParser.js
+++ b/javascripts/RegexParser.js
@@ -3,6 +3,8 @@
* Parsing a regular expression using recursive descent method.
* parse() returns a NFA (constructed following Thompson's algrotihm).
*/
+
+
function RegexParser() {};
// Accessor functions
@@ -123,4 +125,5 @@ RegexParser.prototype.parse = function(regex) {
nfa = null;
};
return nfa;
-}
+};
+
diff --git a/javascripts/Stack.js b/javascripts/Stack.js
index 4ccd74e..3349ffb 100644
--- a/javascripts/Stack.js
+++ b/javascripts/Stack.js
@@ -2,6 +2,8 @@
* Stack
* Simple implementation of a stack using Array().
*/
+
+
function Stack() {
this.a = new Array();
this.length = 0;
@@ -53,3 +55,4 @@ Stack.prototype.str = function(separator) {
};
return a.join(separator);
};
+
diff --git a/javascripts/globals.js b/javascripts/globals.js
index e48018d..3a5a495 100644
--- a/javascripts/globals.js
+++ b/javascripts/globals.js
@@ -1,13 +1,16 @@
// globals
-var EPSILON = '~';
-var NEXTSTATE = 0;
-var EMPTYSYMBOL = '%';
-var ALPHABET = 'abcd'+EMPTYSYMBOL;
-var ALPHABETS = ALPHABET+'()|*';
-var REDELIMITER = '$';
+var EPSILON = '~'; // internal use, symbol for 'non-symbol'
+var NEXTSTATE = 0; // internal use, state indices, begin at 0
+var STOPSYMBOL = '%'; // internal use, stop symbol
+var ALPHABET = 'abcd'+STOPSYMBOL; // used alphabet, need to include stop symbol
+var SPECIALS = '()|*'; // symbol with special meaning in a regex
+var ALPHABETS = ALPHABET+SPECIALS; // include special symbols
+var REDELIMITER = '$'; // internal use, delimiter for regex
-var ttable = new Object();
-var g;
-var graphit = true;
-var lock = false;
+var ttable = new Object(); // transition table, internal use
+var g; // graph object (used by Raphael)
+var graphit = true; // draw a graph? value set by checkbox
+var lock = false; // lock for graph animation
+var alphabetEdit = false; // are we currently editing the alphabet?
+var alphabetEditable = true; // is the alphabet still editable?
diff --git a/javascripts/graph.js b/javascripts/graph.js
index 70b67d8..17dcaaf 100644
--- a/javascripts/graph.js
+++ b/javascripts/graph.js
@@ -1,4 +1,4 @@
-// Source: http://raphaeljs.com/graffle.html (extended with labels and arrow heads)
+// source: http://raphaeljs.com/graffle.html (extended with labels and arrow heads)
Raphael.fn.connection = function (obj1, obj2, line, bg, strokeColor, symbol, labelFontSize, name1, name2) {
if (obj1.line && obj1.from && obj1.to) {
line = obj1;
@@ -79,11 +79,15 @@ Raphael.fn.connection = function (obj1, obj2, line, bg, strokeColor, symbol, lab
return ret;
};
};
-// Source: http://stackoverflow.com/questions/2627436/svg-animation-along-path-with-raphael
+
+
+// source: http://stackoverflow.com/questions/2627436/svg-animation-along-path-with-raphael
Raphael.fn.circlePath = function(x , y, r) {
return "M"+x+","+(y-r)+"A"+r+","+r+",0,1,1,"+(x-0.1)+","+(y-r)+" z";
};
-// The nodes
+
+
+// nodes
Raphael.fn.aNode = function(x, y, r, isFinal, hasSelfConn,
strokeWidth, strokeColor,labelText, labelFontSize, name) {
var res = this.set();
@@ -143,15 +147,9 @@ Raphael.fn.aNode = function(x, y, r, isFinal, hasSelfConn,
name: name
};
};
-// Source: http://www.davidcramer.net/code/63/dir-in-javascript.html
-function dir(object) {
- methods = [];
- for (z in object) if (typeof(z) != 'number') methods.push(z);
- return methods.join(', ');
-};
-// Drawing the graph.
+// drawing a graph
function graph() {
var nodeRadius = 30;
var nodeRadiusHi = nodeRadius + 10;
@@ -180,6 +178,7 @@ function graph() {
up = function () {
this.animate({r:nodeRadius, opacity:nodeOpacity}, 500, ">");
};
+
// nodes
var nodes = [];
var nodeById = [];
@@ -221,6 +220,7 @@ function graph() {
nx = nx + nxOffset;
i++;
};
+
// connections
var connections = [];
var k = l = 0;
@@ -252,3 +252,4 @@ function graph() {
graphNodeByName: graphNodeByName
};
};
+
diff --git a/javascripts/lib/jquery.bgiframe.js b/javascripts/lib/jquery.bgiframe.js
new file mode 100644
index 0000000..5d270f3
--- /dev/null
+++ b/javascripts/lib/jquery.bgiframe.js
@@ -0,0 +1,104 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-06-20 03:23:36 +0200 (Mi, 20 Jun 2007) $
+ * $Rev: 2110 $
+ *
+ * Version 2.1
+ */
+
+(function($){
+
+/**
+ * The bgiframe is chainable and applies the iframe hack to get
+ * around zIndex issues in IE6. It will only apply itself in IE
+ * and adds a class to the iframe called 'bgiframe'. The iframe
+ * is appeneded as the first child of the matched element(s)
+ * with a tabIndex and zIndex of -1.
+ *
+ * By default the plugin will take borders, sized with pixel units,
+ * into account. If a different unit is used for the border's width,
+ * then you will need to use the top and left settings as explained below.
+ *
+ * NOTICE: This plugin has been reported to cause perfromance problems
+ * when used on elements that change properties (like width, height and
+ * opacity) a lot in IE6. Most of these problems have been caused by
+ * the expressions used to calculate the elements width, height and
+ * borders. Some have reported it is due to the opacity filter. All
+ * these settings can be changed if needed as explained below.
+ *
+ * @example $('div').bgiframe();
+ * @before <div><p>Paragraph</p></div>
+ * @result <div><iframe class="bgiframe".../><p>Paragraph</p></div>
+ *
+ * @param Map settings Optional settings to configure the iframe.
+ * @option String|Number top The iframe must be offset to the top
+ * by the width of the top border. This should be a negative
+ * number representing the border-top-width. If a number is
+ * is used here, pixels will be assumed. Otherwise, be sure
+ * to specify a unit. An expression could also be used.
+ * By default the value is "auto" which will use an expression
+ * to get the border-top-width if it is in pixels.
+ * @option String|Number left The iframe must be offset to the left
+ * by the width of the left border. This should be a negative
+ * number representing the border-left-width. If a number is
+ * is used here, pixels will be assumed. Otherwise, be sure
+ * to specify a unit. An expression could also be used.
+ * By default the value is "auto" which will use an expression
+ * to get the border-left-width if it is in pixels.
+ * @option String|Number width This is the width of the iframe. If
+ * a number is used here, pixels will be assume. Otherwise, be sure
+ * to specify a unit. An experssion could also be used.
+ * By default the value is "auto" which will use an experssion
+ * to get the offsetWidth.
+ * @option String|Number height This is the height of the iframe. If
+ * a number is used here, pixels will be assume. Otherwise, be sure
+ * to specify a unit. An experssion could also be used.
+ * By default the value is "auto" which will use an experssion
+ * to get the offsetHeight.
+ * @option Boolean opacity This is a boolean representing whether or not
+ * to use opacity. If set to true, the opacity of 0 is applied. If
+ * set to false, the opacity filter is not applied. Default: true.
+ * @option String src This setting is provided so that one could change
+ * the src of the iframe to whatever they need.
+ * Default: "javascript:false;"
+ *
+ * @name bgiframe
+ * @type jQuery
+ * @cat Plugins/bgiframe
+ * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ */
+$.fn.bgIframe = $.fn.bgiframe = function(s) {
+ // This is only for IE6
+ if ( $.browser.msie && parseInt($.browser.version) <= 6 ) {
+ s = $.extend({
+ top : 'auto', // auto == .currentStyle.borderTopWidth
+ left : 'auto', // auto == .currentStyle.borderLeftWidth
+ width : 'auto', // auto == offsetWidth
+ height : 'auto', // auto == offsetHeight
+ opacity : true,
+ src : 'javascript:false;'
+ }, s || {});
+ var prop = function(n){return n&&n.constructor==Number?n+'px':n;},
+ html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
+ 'style="display:block;position:absolute;z-index:-1;'+
+ (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
+ 'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
+ 'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
+ 'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
+ 'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
+ '"/>';
+ return this.each(function() {
+ if ( $('> iframe.bgiframe', this).length == 0 )
+ this.insertBefore( document.createElement(html), this.firstChild );
+ });
+ }
+ return this;
+};
+
+// Add browser.version if it doesn't exist
+if (!$.browser.version)
+ $.browser.version = navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1];
+
+})(jQuery); \ No newline at end of file
diff --git a/javascripts/lib/jquery.dimensions.js b/javascripts/lib/jquery.dimensions.js
new file mode 100644
index 0000000..2934714
--- /dev/null
+++ b/javascripts/lib/jquery.dimensions.js
@@ -0,0 +1,504 @@
+/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-06-22 04:38:37 +0200 (Fr, 22 Jun 2007) $
+ * $Rev: 2141 $
+ *
+ * Version: 1.0b2
+ */
+
+(function($){
+
+// store a copy of the core height and width methods
+var height = $.fn.height,
+ width = $.fn.width;
+
+$.fn.extend({
+ /**
+ * If used on document, returns the document's height (innerHeight)
+ * If used on window, returns the viewport's (window) height
+ * See core docs on height() to see what happens when used on an element.
+ *
+ * @example $("#testdiv").height()
+ * @result 200
+ *
+ * @example $(document).height()
+ * @result 800
+ *
+ * @example $(window).height()
+ * @result 400
+ *
+ * @name height
+ * @type Object
+ * @cat Plugins/Dimensions
+ */
+ height: function() {
+ if ( this[0] == window )
+ return self.innerHeight ||
+ $.boxModel && document.documentElement.clientHeight ||
+ document.body.clientHeight;
+
+ if ( this[0] == document )
+ return Math.max( document.body.scrollHeight, document.body.offsetHeight );
+
+ return height.apply(this, arguments);
+ },
+
+ /**
+ * If used on document, returns the document's width (innerWidth)
+ * If used on window, returns the viewport's (window) width
+ * See core docs on height() to see what happens when used on an element.
+ *
+ * @example $("#testdiv").width()
+ * @result 200
+ *
+ * @example $(document).width()
+ * @result 800
+ *
+ * @example $(window).width()
+ * @result 400
+ *
+ * @name width
+ * @type Object
+ * @cat Plugins/Dimensions
+ */
+ width: function() {
+ if ( this[0] == window )
+ return self.innerWidth ||
+ $.boxModel && document.documentElement.clientWidth ||
+ document.body.clientWidth;
+
+ if ( this[0] == document )
+ return Math.max( document.body.scrollWidth, document.body.offsetWidth );
+
+ return width.apply(this, arguments);
+ },
+
+ /**
+ * Returns the inner height value (without border) for the first matched element.
+ * If used on document, returns the document's height (innerHeight)
+ * If used on window, returns the viewport's (window) height
+ *
+ * @example $("#testdiv").innerHeight()
+ * @result 800
+ *
+ * @name innerHeight
+ * @type Number
+ * @cat Plugins/Dimensions
+ */
+ innerHeight: function() {
+ return this[0] == window || this[0] == document ?
+ this.height() :
+ this.is(':visible') ?
+ this[0].offsetHeight - num(this, 'borderTopWidth') - num(this, 'borderBottomWidth') :
+ this.height() + num(this, 'paddingTop') + num(this, 'paddingBottom');
+ },
+
+ /**
+ * Returns the inner width value (without border) for the first matched element.
+ * If used on document, returns the document's Width (innerWidth)
+ * If used on window, returns the viewport's (window) width
+ *
+ * @example $("#testdiv").innerWidth()
+ * @result 1000
+ *
+ * @name innerWidth
+ * @type Number
+ * @cat Plugins/Dimensions
+ */
+ innerWidth: function() {
+ return this[0] == window || this[0] == document ?
+ this.width() :
+ this.is(':visible') ?
+ this[0].offsetWidth - num(this, 'borderLeftWidth') - num(this, 'borderRightWidth') :
+ this.width() + num(this, 'paddingLeft') + num(this, 'paddingRight');
+ },
+
+ /**
+ * Returns the outer height value (including border) for the first matched element.
+ * Cannot be used on document or window.
+ *
+ * @example $("#testdiv").outerHeight()
+ * @result 1000
+ *
+ * @name outerHeight
+ * @type Number
+ * @cat Plugins/Dimensions
+ */
+ outerHeight: function() {
+ return this[0] == window || this[0] == document ?
+ this.height() :
+ this.is(':visible') ?
+ this[0].offsetHeight :
+ this.height() + num(this,'borderTopWidth') + num(this, 'borderBottomWidth') + num(this, 'paddingTop') + num(this, 'paddingBottom');
+ },
+
+ /**
+ * Returns the outer width value (including border) for the first matched element.
+ * Cannot be used on document or window.
+ *
+ * @example $("#testdiv").outerHeight()
+ * @result 1000
+ *
+ * @name outerHeight
+ * @type Number
+ * @cat Plugins/Dimensions
+ */
+ outerWidth: function() {
+ return this[0] == window || this[0] == document ?
+ this.width() :
+ this.is(':visible') ?
+ this[0].offsetWidth :
+ this.width() + num(this, 'borderLeftWidth') + num(this, 'borderRightWidth') + num(this, 'paddingLeft') + num(this, 'paddingRight');
+ },
+
+ /**
+ * Returns how many pixels the user has scrolled to the right (scrollLeft).
+ * Works on containers with overflow: auto and window/document.
+ *
+ * @example $("#testdiv").scrollLeft()
+ * @result 100
+ *
+ * @name scrollLeft
+ * @type Number
+ * @cat Plugins/Dimensions
+ */
+ /**
+ * Sets the scrollLeft property and continues the chain.
+ * Works on containers with overflow: auto and window/document.
+ *
+ * @example $("#testdiv").scrollLeft(10).scrollLeft()
+ * @result 10
+ *
+ * @name scrollLeft
+ * @param Number value A positive number representing the desired scrollLeft.
+ * @type jQuery
+ * @cat Plugins/Dimensions
+ */
+ scrollLeft: function(val) {
+ if ( val != undefined )
+ // set the scroll left
+ return this.each(function() {
+ if (this == window || this == document)
+ window.scrollTo( val, $(window).scrollTop() );
+ else
+ this.scrollLeft = val;
+ });
+
+ // return the scroll left offest in pixels
+ if ( this[0] == window || this[0] == document )
+ return self.pageXOffset ||
+ $.boxModel && document.documentElement.scrollLeft ||
+ document.body.scrollLeft;
+
+ return this[0].scrollLeft;
+ },
+
+ /**
+ * Returns how many pixels the user has scrolled to the bottom (scrollTop).
+ * Works on containers with overflow: auto and window/document.
+ *
+ * @example $("#testdiv").scrollTop()
+ * @result 100
+ *
+ * @name scrollTop
+ * @type Number
+ * @cat Plugins/Dimensions
+ */
+ /**
+ * Sets the scrollTop property and continues the chain.
+ * Works on containers with overflow: auto and window/document.
+ *
+ * @example $("#testdiv").scrollTop(10).scrollTop()
+ * @result 10
+ *
+ * @name scrollTop
+ * @param Number value A positive number representing the desired scrollTop.
+ * @type jQuery
+ * @cat Plugins/Dimensions
+ */
+ scrollTop: function(val) {
+ if ( val != undefined )
+ // set the scroll top
+ return this.each(function() {
+ if (this == window || this == document)
+ window.scrollTo( $(window).scrollLeft(), val );
+ else
+ this.scrollTop = val;
+ });
+
+ // return the scroll top offset in pixels
+ if ( this[0] == window || this[0] == document )
+ return self.pageYOffset ||
+ $.boxModel && document.documentElement.scrollTop ||
+ document.body.scrollTop;
+
+ return this[0].scrollTop;
+ },
+
+ /**
+ * Returns the top and left positioned offset in pixels.
+ * The positioned offset is the offset between a positioned
+ * parent and the element itself.
+ *
+ * @example $("#testdiv").position()
+ * @result { top: 100, left: 100 }
+ *
+ * @name position
+ * @param Map options Optional settings to configure the way the offset is calculated.
+ * @option Boolean margin Should the margin of the element be included in the calculations? False by default.
+ * @option Boolean border Should the border of the element be included in the calculations? False by default.
+ * @option Boolean padding Should the padding of the element be included in the calculations? False by default.
+ * @param Object returnObject An object to store the return value in, so as not to break the chain. If passed in the
+ * chain will not be broken and the result will be assigned to this object.
+ * @type Object
+ * @cat Plugins/Dimensions
+ */
+ position: function(options, returnObject) {
+ var elem = this[0], parent = elem.parentNode, op = elem.offsetParent,
+ options = $.extend({ margin: false, border: false, padding: false, scroll: false }, options || {}),
+ x = elem.offsetLeft,
+ y = elem.offsetTop,
+ sl = elem.scrollLeft,
+ st = elem.scrollTop;
+
+ // Mozilla and IE do not add the border
+ if ($.browser.mozilla || $.browser.msie) {
+ // add borders to offset
+ x += num(elem, 'borderLeftWidth');
+ y += num(elem, 'borderTopWidth');
+ }
+
+ if ($.browser.mozilla) {
+ do {
+ // Mozilla does not add the border for a parent that has overflow set to anything but visible
+ if ($.browser.mozilla && parent != elem && $.css(parent, 'overflow') != 'visible') {
+ x += num(parent, 'borderLeftWidth');
+ y += num(parent, 'borderTopWidth');
+ }
+
+ if (parent == op) break; // break if we are already at the offestParent
+ } while ((parent = parent.parentNode) && (parent.tagName.toLowerCase() != 'body' || parent.tagName.toLowerCase() != 'html'));
+ }
+
+ var returnValue = handleOffsetReturn(elem, options, x, y, sl, st);
+
+ if (returnObject) { $.extend(returnObject, returnValue); return this; }
+ else { return returnValue; }
+ },
+
+ /**
+ * Returns the location of the element in pixels from the top left corner of the viewport.
+ *
+ * For accurate readings make sure to use pixel values for margins, borders and padding.
+ *
+ * Known issues:
+ * - Issue: A div positioned relative or static without any content before it and its parent will report an offsetTop of 0 in Safari
+ * Workaround: Place content before the relative div ... and set height and width to 0 and overflow to hidden
+ *
+ * @example $("#testdiv").offset()
+ * @result { top: 100, left: 100, scrollTop: 10, scrollLeft: 10 }
+ *
+ * @example $("#testdiv").offset({ scroll: false })
+ * @result { top: 90, left: 90 }
+ *
+ * @example var offset = {}
+ * $("#testdiv").offset({ scroll: false }, offset)
+ * @result offset = { top: 90, left: 90 }
+ *
+ * @name offset
+ * @param Map options Optional settings to configure the way the offset is calculated.
+ * @option Boolean margin Should the margin of the element be included in the calculations? True by default.
+ * @option Boolean border Should the border of the element be included in the calculations? False by default.
+ * @option Boolean padding Should the padding of the element be included in the calculations? False by default.
+ * @option Boolean scroll Should the scroll offsets of the parent elements be included in the calculations? True by default.
+ * When true it adds the totla scroll offets of all parents to the total offset and also adds two properties
+ * to the returned object, scrollTop and scrollLeft.
+ * @options Boolean lite Will use offsetLite instead of offset when set to true. False by default.
+ * @param Object returnObject An object to store the return value in, so as not to break the chain. If passed in the
+ * chain will not be broken and the result will be assigned to this object.
+ * @type Object
+ * @cat Plugins/Dimensions
+ */
+ offset: function(options, returnObject) {
+ var x = 0, y = 0, sl = 0, st = 0,
+ elem = this[0], parent = this[0], op, parPos, elemPos = $.css(elem, 'position'),
+ mo = $.browser.mozilla, ie = $.browser.msie, sf = $.browser.safari, oa = $.browser.opera,
+ absparent = false, relparent = false,
+ options = $.extend({ margin: true, border: false, padding: false, scroll: true, lite: false }, options || {});
+
+ // Use offsetLite if lite option is true
+ if (options.lite) return this.offsetLite(options, returnObject);
+
+ if (elem.tagName.toLowerCase() == 'body') {
+ // Safari is the only one to get offsetLeft and offsetTop properties of the body "correct"
+ // Except they all mess up when the body is positioned absolute or relative
+ x = elem.offsetLeft;
+ y = elem.offsetTop;
+ // Mozilla ignores margin and subtracts border from body element
+ if (mo) {
+ x += num(elem, 'marginLeft') + (num(elem, 'borderLeftWidth')*2);
+ y += num(elem, 'marginTop') + (num(elem, 'borderTopWidth') *2);
+ } else
+ // Opera ignores margin
+ if (oa) {
+ x += num(elem, 'marginLeft');
+ y += num(elem, 'marginTop');
+ } else
+ // IE does not add the border in Standards Mode
+ if (ie && jQuery.boxModel) {
+ x += num(elem, 'borderLeftWidth');
+ y += num(elem, 'borderTopWidth');
+ }
+ } else {
+ do {
+ parPos = $.css(parent, 'position');
+
+ x += parent.offsetLeft;
+ y += parent.offsetTop;
+
+ // Mozilla and IE do not add the border
+ if (mo || ie) {
+ // add borders to offset
+ x += num(parent, 'borderLeftWidth');
+ y += num(parent, 'borderTopWidth');
+
+ // Mozilla does not include the border on body if an element isn't positioned absolute and is without an absolute parent
+ if (mo && parPos == 'absolute') absparent = true;
+ // IE does not include the border on the body if an element is position static and without an absolute or relative parent
+ if (ie && parPos == 'relative') relparent = true;
+ }
+
+ op = parent.offsetParent;
+ if (options.scroll || mo) {
+ do {
+ if (options.scroll) {
+ // get scroll offsets
+ sl += parent.scrollLeft;
+ st += parent.scrollTop;
+ }
+
+ // Mozilla does not add the border for a parent that has overflow set to anything but visible
+ if (mo && parent != elem && $.css(parent, 'overflow') != 'visible') {
+ x += num(parent, 'borderLeftWidth');
+ y += num(parent, 'borderTopWidth');
+ }
+
+ parent = parent.parentNode;
+ } while (parent != op);
+ }
+ parent = op;
+
+ if (parent.tagName.toLowerCase() == 'body' || parent.tagName.toLowerCase() == 'html') {
+ // Safari and IE Standards Mode doesn't add the body margin for elments positioned with static or relative
+ if ((sf || (ie && $.boxModel)) && elemPos != 'absolute' && elemPos != 'fixed') {
+ x += num(parent, 'marginLeft');
+ y += num(parent, 'marginTop');
+ }
+ // Mozilla does not include the border on body if an element isn't positioned absolute and is without an absolute parent
+ // IE does not include the border on the body if an element is positioned static and without an absolute or relative parent
+ if ( (mo && !absparent && elemPos != 'fixed') ||
+ (ie && elemPos == 'static' && !relparent) ) {
+ x += num(parent, 'borderLeftWidth');
+ y += num(parent, 'borderTopWidth');
+ }
+ break; // Exit the loop
+ }
+ } while (parent);
+ }
+
+ var returnValue = handleOffsetReturn(elem, options, x, y, sl, st);
+
+ if (returnObject) { $.extend(returnObject, returnValue); return this; }
+ else { return returnValue; }
+ },
+
+ /**
+ * Returns the location of the element in pixels from the top left corner of the viewport.
+ * This method is much faster than offset but not as accurate. This method can be invoked
+ * by setting the lite option to true in the offset method.
+ *
+ * @name offsetLite
+ * @param Map options Optional settings to configure the way the offset is calculated.
+ * @option Boolean margin Should the margin of the element be included in the calculations? True by default.
+ * @option Boolean border Should the border of the element be included in the calculations? False by default.
+ * @option Boolean padding Should the padding of the element be included in the calculations? False by default.
+ * @option Boolean scroll Should the scroll offsets of the parent elements be included in the calculations? True by default.
+ * When true it adds the totla scroll offets of all parents to the total offset and also adds two properties
+ * to the returned object, scrollTop and scrollLeft.
+ * @param Object returnObject An object to store the return value in, so as not to break the chain. If passed in the
+ * chain will not be broken and the result will be assigned to this object.
+ * @type Object
+ * @cat Plugins/Dimensions
+ */
+ offsetLite: function(options, returnObject) {
+ var x = 0, y = 0, sl = 0, st = 0, parent = this[0], op,
+ options = $.extend({ margin: true, border: false, padding: false, scroll: true }, options || {});
+
+ do {
+ x += parent.offsetLeft;
+ y += parent.offsetTop;
+
+ op = parent.offsetParent;
+ if (options.scroll) {
+ // get scroll offsets
+ do {
+ sl += parent.scrollLeft;
+ st += parent.scrollTop;
+ parent = parent.parentNode;
+ } while(parent != op);
+ }
+ parent = op;
+ } while (parent && parent.tagName.toLowerCase() != 'body' && parent.tagName.toLowerCase() != 'html');
+
+ var returnValue = handleOffsetReturn(this[0], options, x, y, sl, st);
+
+ if (returnObject) { $.extend(returnObject, returnValue); return this; }
+ else { return returnValue; }
+ }
+});
+
+/**
+ * Handles converting a CSS Style into an Integer.
+ * @private
+ */
+var num = function(el, prop) {
+ return parseInt($.css(el.jquery?el[0]:el,prop))||0;
+};
+
+/**
+ * Handles the return value of the offset and offsetLite methods.
+ * @private
+ */
+var handleOffsetReturn = function(elem, options, x, y, sl, st) {
+ if ( !options.margin ) {
+ x -= num(elem, 'marginLeft');
+ y -= num(elem, 'marginTop');
+ }
+
+ // Safari and Opera do not add the border for the element
+ if ( options.border && ($.browser.safari || $.browser.opera) ) {
+ x += num(elem, 'borderLeftWidth');
+ y += num(elem, 'borderTopWidth');
+ } else if ( !options.border && !($.browser.safari || $.browser.opera) ) {
+ x -= num(elem, 'borderLeftWidth');
+ y -= num(elem, 'borderTopWidth');
+ }
+
+ if ( options.padding ) {
+ x += num(elem, 'paddingLeft');
+ y += num(elem, 'paddingTop');
+ }
+
+ // do not include scroll offset on the element
+ if ( options.scroll ) {
+ sl -= elem.scrollLeft;
+ st -= elem.scrollTop;
+ }
+
+ return options.scroll ? { top: y - st, left: x - sl, scrollTop: st, scrollLeft: sl }
+ : { top: y, left: x };
+};
+
+})(jQuery); \ No newline at end of file
diff --git a/javascripts/lib/jquery.tooltip.js b/javascripts/lib/jquery.tooltip.js
new file mode 100644
index 0000000..63b715f
--- /dev/null
+++ b/javascripts/lib/jquery.tooltip.js
@@ -0,0 +1,294 @@
+/*
+ * jQuery Tooltip plugin 1.3
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/
+ * http://docs.jquery.com/Plugins/Tooltip
+ *
+ * Copyright (c) 2006 - 2008 Jörn Zaefferer
+ *
+ * $Id: jquery.tooltip.js 5741 2008-06-21 15:22:16Z joern.zaefferer $
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function($) {
+
+ // the tooltip element
+ var helper = {},
+ // the current tooltipped element
+ current,
+ // the title of the current element, used for restoring
+ title,
+ // timeout id for delayed tooltips
+ tID,
+ // IE 5.5 or 6
+ IE = $.browser.msie && /MSIE\s(5\.5|6\.)/.test(navigator.userAgent),
+ // flag for mouse tracking
+ track = false;
+
+ $.tooltip = {
+ blocked: false,
+ defaults: {
+ delay: 200,
+ fade: false,
+ showURL: true,
+ extraClass: "",
+ top: 15,
+ left: 15,
+ id: "tooltip"
+ },
+ block: function() {
+ $.tooltip.blocked = !$.tooltip.blocked;
+ }
+ };
+
+ $.fn.extend({
+ tooltip: function(settings) {
+ settings = $.extend({}, $.tooltip.defaults, settings);
+ createHelper(settings);
+ return this.each(function() {
+ $.data(this, "tooltip", settings);
+ this.tOpacity = helper.parent.css("opacity");
+ // copy tooltip into its own expando and remove the title
+ this.tooltipText = this.title;
+ $(this).removeAttr("title");
+ // also remove alt attribute to prevent default tooltip in IE
+ this.alt = "";
+ })
+ .mouseover(save)
+ .mouseout(hide)
+ .click(hide);
+ },
+ fixPNG: IE ? function() {
+ return this.each(function () {
+ var image = $(this).css('backgroundImage');
+ if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) {
+ image = RegExp.$1;
+ $(this).css({
+ 'backgroundImage': 'none',
+ 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
+ }).each(function () {
+ var position = $(this).css('position');
+ if (position != 'absolute' && position != 'relative')
+ $(this).css('position', 'relative');
+ });
+ }
+ });
+ } : function() { return this; },
+ unfixPNG: IE ? function() {
+ return this.each(function () {
+ $(this).css({'filter': '', backgroundImage: ''});
+ });
+ } : function() { return this; },
+ hideWhenEmpty: function() {
+ return this.each(function() {
+ $(this)[ $(this).html() ? "show" : "hide" ]();
+ });
+ },
+ url: function() {
+ return this.attr('href') || this.attr('src');
+ }
+ });
+
+ function createHelper(settings) {
+ // there can be only one tooltip helper
+ if( helper.parent )
+ return;
+ // create the helper, h3 for title, div for url
+ helper.parent = $('<div id="' + settings.id + '"><h3></h3><div class="body"></div><div class="url"></div></div>')
+ // add to document
+ .appendTo(document.body)
+ // hide it at first
+ .hide();
+
+ // apply bgiframe if available
+ if ( $.fn.bgiframe )
+ helper.parent.bgiframe();
+
+ // save references to title and url elements
+ helper.title = $('h3', helper.parent);
+ helper.body = $('div.body', helper.parent);
+ helper.url = $('div.url', helper.parent);
+ }
+
+ function settings(element) {
+ return $.data(element, "tooltip");
+ }
+
+ // main event handler to start showing tooltips
+ function handle(event) {
+ // show helper, either with timeout or on instant
+ if( settings(this).delay )
+ tID = setTimeout(show, settings(this).delay);
+ else
+ show();
+
+ // if selected, update the helper position when the mouse moves
+ track = !!settings(this).track;
+ $(document.body).bind('mousemove', update);
+
+ // update at least once
+ update(event);
+ }
+
+ // save elements title before the tooltip is displayed
+ function save() {
+ // if this is the current source, or it has no title (occurs with click event), stop
+ if ( $.tooltip.blocked || this == current || (!this.tooltipText && !settings(this).bodyHandler) )
+ return;
+
+ // save current
+ current = this;
+ title = this.tooltipText;
+
+ if ( settings(this).bodyHandler ) {
+ helper.title.hide();
+ var bodyContent = settings(this).bodyHandler.call(this);
+ if (bodyContent.nodeType || bodyContent.jquery) {
+ helper.body.empty().append(bodyContent)
+ } else {
+ helper.body.html( bodyContent );
+ }
+ helper.body.show();
+ } else if ( settings(this).showBody ) {
+ var parts = title.split(settings(this).showBody);
+ helper.title.html(parts.shift()).show();
+ helper.body.empty();
+ for(var i = 0, part; (part = parts[i]); i++) {
+ if(i > 0)
+ helper.body.append("<br/>");
+ helper.body.append(part);
+ }
+ helper.body.hideWhenEmpty();
+ } else {
+ helper.title.html(title).show();
+ helper.body.hide();
+ }
+
+ // if element has href or src, add and show it, otherwise hide it
+ if( settings(this).showURL && $(this).url() )
+ helper.url.html( $(this).url().replace('http://', '') ).show();
+ else
+ helper.url.hide();
+
+ // add an optional class for this tip
+ helper.parent.addClass(settings(this).extraClass);
+
+ // fix PNG background for IE
+ if (settings(this).fixPNG )
+ helper.parent.fixPNG();
+
+ handle.apply(this, arguments);
+ }
+
+ // delete timeout and show helper
+ function show() {
+ tID = null;
+ if ((!IE || !$.fn.bgiframe) && settings(current).fade) {
+ if (helper.parent.is(":animated"))
+ helper.parent.stop().show().fadeTo(settings(current).fade, current.tOpacity);
+ else
+ helper.parent.is(':visible') ? helper.parent.fadeTo(settings(current).fade, current.tOpacity) : helper.parent.fadeIn(settings(current).fade);
+ } else {
+ helper.parent.show();
+ }
+ update();
+ }
+
+ /**
+ * callback for mousemove
+ * updates the helper position
+ * removes itself when no current element
+ */
+ function update(event) {
+ if($.tooltip.blocked)
+ return;
+
+ if (event && event.target.tagName == "OPTION") {
+ return;
+ }
+
+ // stop updating when tracking is disabled and the tooltip is visible
+ if ( !track && helper.parent.is(":visible")) {
+ $(document.body).unbind('mousemove', update)
+ }
+
+ // if no current element is available, remove this listener
+ if( current == null ) {
+ $(document.body).unbind('mousemove', update);
+ return;
+ }
+
+ // remove position helper classes
+ helper.parent.removeClass("viewport-right").removeClass("viewport-bottom");
+
+ var left = helper.parent[0].offsetLeft;
+ var top = helper.parent[0].offsetTop;
+ if (event) {
+ // position the helper 15 pixel to bottom right, starting from mouse position
+ left = event.pageX + settings(current).left;
+ top = event.pageY + settings(current).top;
+ var right='auto';
+ if (settings(current).positionLeft) {
+ right = $(window).width() - left;
+ left = 'auto';
+ }
+ helper.parent.css({
+ left: left,
+ right: right,
+ top: top
+ });
+ }
+
+ var v = viewport(),
+ h = helper.parent[0];
+ // check horizontal position
+ if (v.x + v.cx < h.offsetLeft + h.offsetWidth) {
+ left -= h.offsetWidth + 20 + settings(current).left;
+ helper.parent.css({left: left + 'px'}).addClass("viewport-right");
+ }
+ // check vertical position
+ if (v.y + v.cy < h.offsetTop + h.offsetHeight) {
+ top -= h.offsetHeight + 20 + settings(current).top;
+ helper.parent.css({top: top + 'px'}).addClass("viewport-bottom");
+ }
+ }
+
+ function viewport() {
+ return {
+ x: $(window).scrollLeft(),
+ y: $(window).scrollTop(),
+ cx: $(window).width(),
+ cy: $(window).height()
+ };
+ }
+
+ // hide helper and restore added classes and the title
+ function hide(event) {
+ if($.tooltip.blocked)
+ return;
+ // clear timeout if possible
+ if(tID)
+ clearTimeout(tID);
+ // no more current element
+ current = null;
+
+ var tsettings = settings(this);
+ function complete() {
+ helper.parent.removeClass( tsettings.extraClass ).hide().css("opacity", "");
+ }
+ if ((!IE || !$.fn.bgiframe) && tsettings.fade) {
+ if (helper.parent.is(':animated'))
+ helper.parent.stop().fadeTo(tsettings.fade, 0, complete);
+ else
+ helper.parent.stop().fadeOut(tsettings.fade, complete);
+ } else
+ complete();
+
+ if( settings(this).fixPNG )
+ helper.parent.unfixPNG();
+ }
+
+})(jQuery);
diff --git a/javascripts/uifunc.js b/javascripts/ui.js
index f14b6b2..31a3cfa 100644
--- a/javascripts/uifunc.js
+++ b/javascripts/ui.js
@@ -1,3 +1,58 @@
+/*
+ * UI
+ * functions, intialization
+ */
+
+
+// initialization of ui
+$(function() {
+ // #alphabet
+ $('#alphabet').html(ALPHABET.substr(0,ALPHABET.length-1));
+ // #regex
+ $('#regex').change(function() { checkLength(this, "#parseButton"); });
+ $('#regex').keypress(function(event) { return getKey(event, ALPHABETS); });
+ $('#regex').mouseout(function() { checkLength(this, "#parseButton"); });
+ // #parseButton
+ $('#parseButton').click(function() {
+ uiParse();
+ alphabetEditable=false;
+ });
+ // #word
+ $('#word').change(function() { checkLength(this, "#checkButton"); });
+ $('#word').keypress(function(event) { return graphMoveByInput(event, ALPHABET); });
+ $('#word').mouseout(function() { checkLength(this, "#checkButton"); });
+ // #checkButton
+ $('#checkButton').click(function() { uiSimulate(); });
+ // #graphit
+ $('#graphit').change(function() { graphit = this.checked; });
+ // #reloadButton
+ $('#reloadButton').click(function() { window.location.reload(); });
+ // #descButton
+ $('#descButton').click(function() { $('#desc').toggle(); });
+ // in place edit of alphabet
+ $('body').click(function() {
+ if (alphabetEdit) {
+ ALPHABET = $('#alphabetInput').attr('value').replace(/\s/g,'').replace(/%/g, '').replace(/\*/g, '');
+ ALPHABET = ALPHABET.replace(/\(/g, '').replace(/\)/g, '').replace(/\|/g, '')+STOPSYMBOL;
+ ALPHABETS = ALPHABET+SPECIALS;
+ $('#alphabetInput').remove();
+ $('#alphabet').html('<strong class="grayc">'+ALPHABET.substr(0, ALPHABET.length-1)+'</strong>');
+ alphabetEdit = false;
+ }
+ });
+ $('#alphabet').dblclick(function() {
+ if (alphabetEditable) {
+ alphabetEdit = true;
+ $(this).html('<input id="alphabetInput" type="text" value="'+ALPHABET.substr(0,ALPHABET.length-1)+'" />');
+ $('#alphabetInput').click(function(event) {
+ event.stopPropagation();
+ });
+ }
+ });
+ // tooltips
+ $('*.help').tooltip({showBody: " - "});
+});
+
// Enable/disable if input length is > 0.
function checkLength(el, bId) {
if (graphit && (el.id == 'word')) return;
@@ -30,7 +85,9 @@ function graph_success() {
$('#word').removeClass('inprogress');
$('#word').addClass('success');
$('#checkMessage').effect("highlight", {}, 1000);
- window.g.mover.attr({fill: 'green'});//'#cdeb8b'});
+ if(graphit) {
+ window.g.mover.attr({fill: 'green'});//'#cdeb8b'});
+ }
};
function graph_failure() {
$('#checkMessage').html('Word not accepted');
@@ -45,6 +102,11 @@ function graph_failure() {
// Call of RegexParser.parse() from UI.
function uiParse() {
+ var regex = $('#regex').attr('value');
+ if (regex.match(/\*(\(|\))*\*/)) {
+ alert("Supernumerous * symbol(s), please correct regular expression.");
+ return;
+ }
disable('#graphit');
var parser = new RegexParser();
nfa = parser.parse($('#regex').attr('value'));
@@ -106,7 +168,6 @@ function getKey(e, set) {
};
// Moving inside the graph by input symbols.
-// setTimeout ?
function graphMoveByInput(e) {
if (lock) {
if (failedInputs) {
@@ -163,7 +224,9 @@ function graphMoveByInput(e) {
// go back one state
window.gPrevState = gPrevStates.pop();
+ if (!window.gPrevState) return; // none of word left
window.setTimeout(function() {
+ if (!window.gPrevState) return; // none of word left
g.mover.animate({cx:gPrevState.node[1][0].cx.baseVal.value, cy:gPrevState.node[1][0].cy.baseVal.value}, 250);
lock = false;
}, 250);