diff options
Diffstat (limited to 'javascripts')
-rw-r--r-- | javascripts/Nfa.js | 3 | ||||
-rw-r--r-- | javascripts/Nfa2Dfa.js | 4 | ||||
-rw-r--r-- | javascripts/NfaSimulator.js | 3 | ||||
-rw-r--r-- | javascripts/NfaState.js | 3 | ||||
-rw-r--r-- | javascripts/RegexParser.js | 5 | ||||
-rw-r--r-- | javascripts/Stack.js | 3 | ||||
-rw-r--r-- | javascripts/globals.js | 23 | ||||
-rw-r--r-- | javascripts/graph.js | 21 | ||||
-rw-r--r-- | javascripts/lib/jquery.bgiframe.js | 104 | ||||
-rw-r--r-- | javascripts/lib/jquery.dimensions.js | 504 | ||||
-rw-r--r-- | javascripts/lib/jquery.tooltip.js | 294 | ||||
-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); |