Răsfoiți Sursa

Merge branch 'feature/bootstrap' into develop

Taddeus Kroes 13 ani în urmă
părinte
comite
995dc123f2

+ 2 - 0
TODO

@@ -48,3 +48,5 @@
 - frontend: replace 'dx' with '(dx)' with regex before sending to parser
 
 - "sin^2 x" is supported by parser, but not yet by line printer.
+
+- Multiple integrals -> use different constant names (e.g. C and D instead of 2C)

+ 59 - 114
src/frontend/css/editor.css

@@ -1,147 +1,92 @@
-html {
-    background-color: #ccddef;
-    margin: 0;
-    padding: 0;
-}
-
 body {
-    margin: 0;
-    padding: 20px;
-    font: 16px/24px Verdana, Arial, sans;
+    padding-top: 40px;
+    background-color: #f9f9f9;
 }
 
-#loader {
-    background: url(/static/img/load.gif) no-repeat scroll 0 0 transparent;
-    height: 31px;
-    width: 31px;
+.alert {
     display: none;
-    position: absolute;
-    margin-top: -5px;
-    margin-left: 16px;
-}
-
-.panel {
-    background-color: #fff;
-    border: 3px solid #bbb;
-    cursor: text;
-    min-height: 400px;
-    padding-bottom: 10px;
-    position: absolute;
-    top: 58px;
-    width: 47%;
+    margin: 10px 0 0;
 }
-
-#error {
-    /*display: none;*/
-    font-size: 12px;
-    clear: both;
-    margin-top: 20px;
-    position: absolute;
+.alert strong {
+    margin-right: 8px;
 }
 
-#input {
-    float: left;
-    left: 2%;
+.math-input {
+    width: 436px !important;
+    min-height: 314px;
+    padding: 7px 11px;
+    line-height: 26px;
+    overflow: hidden;
+    resize: none;
 }
 
-#input textarea {
-    width: 100%;
-    border: 0;
-    margin: 0;
-    padding: 0;
-    height: 388px;
-    overflow-y: visible;
-    font: 16px/24px Verdana, Arial, sans;
-    outline: 0;
+.pretty-print {
+    background-color: #fff;
+    border-color: #ccc;
+    min-height: 300px;
+    padding: 14px 19px;
 }
 
-.box {
-    padding: 10px 15px 0 15px;
+.box, .hint {
+    position: relative;
+    margin: 5px 0;
+    padding-left: 20px;
 }
 
-#math {
-    float:right;
-    right: 2%;
+.label, .icon {
+    position: absolute;
+    top: 50%;
 }
-
-#math .box {
-    padding: 10px 15px 0 40px;
-    background: no-repeat scroll 15px 13px transparent;
+.label {
+    margin-top: -9px;
+    left: -8px;
 }
-
-#math .box.correct {
-    background-image: url(/static/img/tick.png);
+.icon {
+    margin-top: -8px;
+    left: 0;
 }
 
-#math .box.wrong {
-    background-image: url(/static/img/cross.png);
+.current-line {
+    border-right: 3px solid #ddd;
 }
 
-#math .box.no-progress {
-    background-image: url(/static/img/error.png);
+.credits {
+    text-align: center;
+    font-size: 13px;
 }
 
-#math .hint {
-    padding: 10px 15px 0 40px;
-    background: url(/static/img/info.png) no-repeat scroll 15px 13px transparent;
-    color: #666;
-    font-size: 14px;
-    line-height: 20px;
+#loader {
+    display: inline-block;
+    visibility: hidden;
+    position: relative;
+    background: url(/static/img/load.gif) no-repeat;
+    height: 16px;
+    width: 16px;
+    top: 8px;
+    margin-left: 10px;
 }
 
-#math .hint .MathJax {
-    color: #000;
+.popover {
+    z-index: 1500;
+    white-space: normal;
+    color: #333;
 }
 
-#control-buttons {
-    height: 21px;
-    left: 2%;
-    line-height: 0;
-    margin-bottom: 16px;
-    position: absolute;
-    vertical-align: top;
+.popover-content {
+    font-size: 14px;
 }
 
-.separator {
-    border-right: 1px solid #999;
+.popover-title span {
+    font-size: 18px;
+    margin-top: 6px;
     display: inline-block;
-    width: 0;
-    height: 21px;
-    margin: 1px 5px;
-    vertical-align: top;
 }
 
-.panel .label {
-    background-color: #fff;
-    border: 1px solid #ccc;
-    clear: both;
-    float: left;
-    font-size: 10px;
-    line-height: 14px;
-    margin-left: 4px;
-    margin-top: -12px;
-    padding: 2px;
+.popover-title .btn-group {
+    float: right;
+    margin-right: -6px;
 }
 
-/* Codemirror should not resize the input area. */
-/*
-.CodeMirror-scroll {
-    height: auto;
-    overflow: visible;
-}
-
-.CodeMirror-lines {
-    padding: 0 !important;
-}
-*/
-
-#credits {
-    clear both;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    position: fixed;
-    font-size: 10px;
-    color: #666;
-    text-align: center;
+.clear {
+    clear: both;
 }

+ 3 - 0
src/frontend/js/docs.js

@@ -0,0 +1,3 @@
+(function($, undefined) {
+})(jQuery);
+

+ 214 - 158
src/frontend/js/editor.js

@@ -1,21 +1,94 @@
-(function ($) {
+(function($, undefined) {
+    // http://stackoverflow.com/questions/1891444/how-can-i-get-cursor-position-in-a-textarea
+    $.fn.getCursorPosition = function() {
+        var el = $(this).get(0);
+        var pos = 0;
+
+        if ('selectionStart' in el) {
+            pos = el.selectionStart;
+        } else if ('selection' in document) {
+            el.focus();
+            var Sel = document.selection.createRange();
+            var SelLength = document.selection.createRange().text.length;
+            Sel.moveStart('character', -el.value.length);
+            pos = Sel.text.length - SelLength;
+        }
+
+        return pos;
+    };
+
     var QUEUE = MathJax.Hub.queue;  // shorthand for the queue
     var math = null; // the element jax for the math output
 
     var trigger_update = true;
-    var input_textarea = $('#MathInput');
+    var input_textarea = $('#math-input');
+    var pretty_print = $('#pretty-print');
 
     // Set the requested query as input value if a query string is given.
     if (location.search.substr(0, 3) == '?q=')
         input_textarea.val(decodeURIComponent(location.search.substr(3)));
 
-    input_textarea.change(function(){ trigger_update = true; })
-        .keyup(function(){ trigger_update = true; });
+    input_textarea.bind('change keyup click', function() {
+        trigger_update = true;
+    });
 
-    $('#input').click(function(){
+    input_textarea.closest('div').click(function() {
         input_textarea.focus();
     });
 
+    // Put cursor at end of textarea
+    var old_val = input_textarea.val();
+    input_textarea.val('').focus().val(old_val);
+
+    var STATUS_FAILURE = 0,
+        STATUS_NOPROGRESS = 1,
+        STATUS_SUCCESS = 2,
+        STATUS_ERROR = 3;
+
+    var status_icons = ['thumbs-down', 'thumbs-up', 'thumbs-up', 'remove'];
+    var status_labels = ['important', 'warning', 'success', 'important'];
+    var status_titles = ['Incorrect', 'No progress', 'Correct', 'Error'];
+    var status_messages = [
+        'This step is incorrect.',
+        'This step leads to the correct answer, but not in a lower number of '
+        + 'steps than the previous step.',
+        'This step is correct.',
+        'An error occurred while validating this step.'
+    ];
+
+    function set_status(elem, stat) {
+        elem = $(elem);
+        elem.find('.label').remove();
+
+        if (stat !== undefined) {
+            var label = $('<span class="label label-'
+                          + status_labels[stat] + '"/>');
+            label.append('<i class="icon-white icon-'
+                         + status_icons[stat] + '"/>');
+            //label.tooltip({placement: 'left', title: status_messages[stat]});
+            label.popover({
+                placement: 'left',
+                trigger: 'hover',
+                title: status_titles[stat],
+                content: status_messages[stat]
+            });
+            elem.append(label);
+        }
+    }
+
+    function get_current_line() {
+        var input = input_textarea.val(),
+            caret = input_textarea.getCursorPosition(),
+            lines = 0;
+
+        for (var i = 0; i < caret; i++) {
+            if (input.charAt(i) == '\n')
+                lines++;
+        }
+
+        return lines;
+    }
+
     // Get the element jax when MathJax has produced it.
     QUEUE.Push(function() {
         // The onchange event handler that typesets the math entered
@@ -23,13 +96,14 @@
         // so we don't see a flash as the math is cleared and replaced.
         var update_math = function(tex) {
             var parts = tex.split('\n');
+            var math_lines = pretty_print.find('div.box script');
 
-            var math_container = $('#math'),
-                math_lines = math_container.find('div.box script');
+            // Stretch textarea size with number of input lines
+            input_textarea.attr('rows', parts.length);
 
             // Select all mathjax instances which are inside a div.box element
             var mathjax_instances = [];
-            var all_instances = MathJax.Hub.getAllJax('math');
+            var all_instances = MathJax.Hub.getAllJax('pretty-print');
 
             for (var i = 0; i < all_instances.length; i++) {
                 var elem = all_instances[i];
@@ -39,7 +113,8 @@
             }
 
             var real_lines = 0,
-                updated_line = -1;
+                updated_line = -1,
+                current_line = get_current_line();
 
             for (var p = 0; p < parts.length; p++) {
                 if (!parts[p])
@@ -56,22 +131,26 @@
                         QUEUE.Push(['Text', elem, parts[p]]);
                     }
 
+                    elem = $(math_lines[real_lines]).parent();
+
                     if (updated_line > -1) {
                         // Remove the out-of-date status information. This will
                         // be done from now on for all remaining lines, whether
                         // they are up-to-date or not.
-                        $(math_lines[real_lines]).parent()
-                            .removeClass('wrong').removeClass('correct');
+                        set_status(elem);
                     }
                 } else {
                     var line = '`' + parts[p] + '`',
                         elem = $('<div class="box"/>').text(line);
 
-                    math_container.append(elem);
+                    pretty_print.append(elem);
 
                     QUEUE.Push(['Typeset', MathJax.Hub, elem[0]]);
                 }
 
+                // Highlight current line.
+                $(elem).toggleClass('current-line', p == current_line);
+
                 real_lines++;
             }
 
@@ -85,7 +164,7 @@
                 // and remove all following hint nodes.  Note that if there is
                 // no line updated, all hints not directly following the last
                 // line are removed.
-                var elems = $('#math div');
+                var elems = pretty_print.find('div');
 
                 if(updated_line == -1)
                     updated_line = real_lines;
@@ -112,193 +191,170 @@
                 var input = input_textarea.val();
 
                 // Make sure that xx is not displayed as a cross.
-                while(/xx/.test(input))
-                    input = input.replace(/xx/, 'x x');
+                input = input.replace(/xx/g, 'x x');
 
                 update_math(input);
             }
         };
 
+        window.update_math();
         setInterval(window.update_math, 100);
     });
 
-    var loader = $('#loader');
+    var error = $('#error'),
+        loader = $('#loader');
 
-    window.report_error = function(e) {
-        $('.panel').css({top: 74});
-        $('#error').text('error: ' + e.error).show();
+    function report_error(e) {
+        var msg = e.error;
+
+        if ('statusText' in e)
+            msg = e.status + ' ' + e.statusText;
+
+        error.show().find('.text').text(msg);
 
         if (console && console.log)
             console.log('error:', e);
 
-        loader.hide();
-    };
+        hide_loader();
+    }
 
-    window.clear_error = function() {
-        $('#error').hide();
-        $('.panel').css({top: 58});
-    };
+    function clear_error() {
+        error.hide();
+    }
 
-    window.show_loader = function() {
-        loader.show().css('display', 'inline-block');
-    };
+    error.find('.close').click(clear_error);
 
-    window.hide_loader = function() {
-        loader.hide();
-        clear_error();
-    };
+    var pending_request = false;
+
+    function show_loader() {
+        pending_request = true;
+        loader.css('visibility', 'visible');
+    }
 
-    window.append_hint = function(hint) {
-        $('#math div').last().filter('.hint').remove();
+    function hide_loader() {
+        pending_request = false;
+        loader.css('visibility', 'hidden');
+    }
 
-        var elem = $('<div class=hint/>');
+    function append_hint(hint) {
+        pretty_print.find('div').last().filter('.hint').remove();
+
+        var elem = $('<div class="hint"/>');
         elem.text(hint);
-        $('#math').append(elem);
+        elem.append('<div class="icon icon-info-sign"/>');
+        pretty_print.append(elem);
         QUEUE.Push(['Typeset', MathJax.Hub, elem[0]]);
-    };
+    }
 
-    window.append_input = function(input) {
+    function append_input(input) {
         input_textarea.val(input_textarea.val() + '\n' + input);
-    };
-
-    window.answer_input = function() {
-        show_loader();
-
-        // TODO: disable input box and enable it when this ajax request is done
-        // (on failure and success).
-        $.post('/answer', {data: input_textarea.val()}, function(response) {
-            if (!response)
-                return;
-
-            if ('error' in response)
-                return report_error(response);
-
-            if ('steps' in response) {
-                for(i = 0; i < response.steps.length; i++) {
-                    cur = response.steps[i];
-
-                    if ('step' in cur)
-                        window.append_input(cur.step);
-
-                    if('hint' in cur)
-                        window.append_hint(cur.hint);
-
-                    trigger_update = true;
-                    window.update_math();
-                }
-            }
-
-            if('hint' in response)
-                window.append_hint(response.hint);
+    }
 
-            input_textarea.focus();
-
-            hide_loader();
-        }, 'json').error(report_error);
-    };
-
-    window.hint_input = function() {
-        show_loader();
-
-        // TODO: disable input box and enable it when this ajax request is done
-        // (on failure and success).
-        $.post('/hint', {data: input_textarea.val()}, function(response) {
-            if (!response)
-                return;
-
-            if ('error' in response)
-                return report_error(response);
-
-            window.append_hint(response.hint);
-
-            input_textarea.focus();
-
-            hide_loader();
-        }, 'json').error(report_error);
-    };
+    $('#btn-clear').click(function() {
+        clear_error();
+        hide_loader();
+        input_textarea.val('').focus();
+        trigger_update = true;
+        window.update_math();
+    });
 
-    window.step_input = function() {
-        show_loader();
+    function bind_request(btn, url, handler, condition) {
+        $('#btn-' + btn).click(function() {
+            var input = input_textarea.val();
 
-        // TODO: disable input box and enable it when this ajax request is done
-        // (on failure and success).
-        $.post('/step', {data: input_textarea.val()}, function(response) {
-            if (!response)
+            if (pending_request || !$.trim(input).length
+                    || (condition && !condition())) {
                 return;
-
-            if ('error' in response)
-                return report_error(response);
-
-            if ('step' in response) {
-                window.append_input(response.step);
-                trigger_update = true;
             }
 
-            if('hint' in response)
-                window.append_hint(response.hint);
+            show_loader();
+            clear_error();
+
+            // TODO: disable input box and enable it when this ajax request is done
+            // (on failure and success).
+            $.post(url, {data: input}, function(response) {
+                if (!response)
+                    return;
+
+                if ('error' in response)
+                    return report_error(response);
+
+                handler(response);
+                hide_loader();
+                clear_error();
+            }, 'json').error(report_error);
+        });
+    }
+
+    // No need to show a hint if there is already one at the end of the
+    // calculation
+    function no_hint_displayed() {
+        return !pretty_print.children(':last').hasClass('hint');
+    }
+
+    bind_request('hint', '/hint', function(response) {
+        append_hint(response.hint);
+        input_textarea.focus();
+    }, no_hint_displayed);
 
-            input_textarea.focus();
+    bind_request('step', '/step', function(response) {
+        if ('step' in response) {
+            append_input(response.step);
+            trigger_update = true;
+        }
 
-            hide_loader();
-        }, 'json').error(report_error);
-    };
+        if('hint' in response && no_hint_displayed())
+            append_hint(response.hint);
 
-    window.validate_input = function() {
-        show_loader();
+        input_textarea.focus();
+    });
 
-        // TODO: disable input box and enable it when this ajax request is done
-        // (on failure and success).
-        $.post('/validate', {data: input_textarea.val()}, function(response) {
-            if (!response)
-                return;
+    bind_request('validate', '/validate', function(response) {
+        var math_lines = pretty_print.find('div.box');
+        var i = 0;
 
-            if ('error' in response)
-                return report_error(response);
+        // Remove the status indicator from all remaining lines.
+        for (; i < math_lines.length; i++)
+            set_status(math_lines[i]);
 
-            var math_container = $('#math'),
-                math_lines = math_container.find('div.box');
+        i = 0;
 
-            var i = 0;
+        // Check if the first line has a correct syntax, since there is
+        // nothing to validate here.
+        if (i < math_lines.length && i <= response.validated) {
+            set_status(math_lines[i], STATUS_SUCCESS);
+            i++;
+        }
 
-            // Remove the status indicator from all remaining lines.
-            for(; i < math_lines.length; i++) {
-                $(math_lines[i])
-                    .removeClass('correct')
-                    .removeClass('wrong')
-                    .removeClass('no-progress');
-            }
+        // Mark every line as {wrong,no-progress,correct,error}.
+        for (; i < math_lines.length && i <= response.validated; i++)
+            set_status(math_lines[i], response.status[i - 1]);
 
-            i = 0;
+        if (i < math_lines.length) {
+            // Mark the current line as wrong.
+            set_status(math_lines[i], STATUS_FAILURE);
+        }
+    });
 
-            // Check if the first line has a correct syntax, since there is
-            // nothing to validate here.
-            if (i < math_lines.length && i <= response.validated) {
-                $(math_lines[i]).addClass('correct');
-                i++;
-            }
+    bind_request('answer', '/answer', function(response) {
+        if ('steps' in response) {
+            for (i = 0; i < response.steps.length; i++) {
+                cur = response.steps[i];
 
-            var status_classes = ['wrong', 'no-progress', 'correct', 'error'];
+                if ('step' in cur)
+                    append_input(cur.step);
 
-            // Mark every line as {wrong,no-progress,correct,error}.
-            for (; i < math_lines.length && i <= response.validated; i++) {
-                var status_class = status_classes[response.status[i - 1]];
-                $(math_lines[i]).addClass(status_class);
-            }
+                if ('hint' in cur)
+                    append_hint(cur.hint);
 
-            if (i < math_lines.length) {
-                // Mark the current line as wrong.
-                $(math_lines[i]).addClass('wrong');
+                trigger_update = true;
+                window.update_math();
             }
+        }
 
-            hide_loader();
-        }, 'json').error(report_error);
-    };
+        if ('hint' in response)
+            append_hint(response.hint);
 
-    window.clear_input = function() {
-        input_textarea.val('');
-        $('#math .box,#math .hint').remove();
-        trigger_update = true;
-        clear_error();
-        hide_loader();
-    };
+        input_textarea.focus();
+    });
 })(jQuery);

+ 268 - 0
src/frontend/js/examples.js

@@ -0,0 +1,268 @@
+(function($) {
+    function Example(actions) {
+        this.actions = actions;
+        this.actions.push(this.destroy_popover);
+        this.current_elem = null;
+    }
+
+    var current_example = null;
+
+    $.extend(Example.prototype, {
+        destroy_popover: function() {
+            if (this.current_elem) {
+                this.current_elem.popover('destroy');
+                this.current_elem = null;
+            }
+        },
+        show_popover: function(selector, alignment, description) {
+            var buttons = $('<div class="btn-group"/>'),
+                dropdown_buttons = $('<ul class="dropdown-menu pull-right"/>'),
+                btn_container = $('<div><div class="clear"/></div>');
+
+            buttons.append(
+                '<button class="btn btn-primary next-example-step">' +
+                    'next' +
+                '</button>'
+            );
+            buttons.append(
+                '<button class="btn btn-primary dropdown-toggle" ' +
+                        'data-toggle="dropdown">' +
+                    '<span class="caret"></span>' +
+                '</button>'
+            );
+            dropdown_buttons.append(
+                '<li><a href="#" class="cancel-example">cancel</a></li>'
+            );
+            dropdown_buttons.append(
+                '<li><a href="#" class="restart-example">restart</a></li>'
+            );
+            buttons.append(dropdown_buttons);
+            btn_container.prepend(buttons);
+
+            this.destroy_popover();
+            this.current_elem = $(selector);
+            this.current_elem.popover({
+                trigger: 'manual',
+                placement: alignment,
+                html: true,
+                title: btn_container,
+                content: description,
+                animation: false
+            }).popover('show');
+        },
+        reset: function() {
+            this.destroy_popover();
+            this.current_action = 0;
+        },
+        cancel: function() {
+            this.reset();
+            current_example = null;
+        },
+        play: function() {
+            current_example && current_example.cancel();
+            current_example = this;
+            this.current_action = 0;
+            this.next();
+        },
+        next: function() {
+            if (this.current_action < this.actions.length)
+                $.proxy(this.actions[this.current_action++], this)();
+
+            if (this.current_action == this.actions.length)
+                current_example = null;
+        }
+    });
+
+    $('.next-example-step').live('click', function() {
+        current_example.next();
+    });
+
+    $('.cancel-example').live('click', function() {
+        current_example.cancel();
+    });
+
+    $('.restart-example').live('click', function() {
+        current_example.reset();
+        current_example.play();
+    });
+
+    function widescreen() {
+        return $('body').width() > 1400;
+    }
+
+    function clear_input() {
+        $('#math-input').val('').change();
+        window.update_math && window.update_math();
+        $('#math-input').focus();
+        this.next();
+    }
+
+    function append_line(line) {
+        return function() {
+            $('#math-input')
+                .val($.trim($('#math-input').val() + '\n' + line))
+                .change();
+            window.update_math();
+            this.next();
+        };
+    }
+
+    function erase_line() {
+        var value = $.trim($('#math-input').val());
+
+        for (var i = value.length - 1; i >= 0; i--) {
+            if (value.charAt(i) == '\n') {
+                value = value.substring(0, i);
+                break;
+            }
+        }
+
+        $('#math-input').val(value).change();
+        window.update_math();
+        this.next();
+    }
+
+    function label_elem(selector, alignment, description) {
+        return function() {
+            this.show_popover(selector, alignment, description);
+        };
+    }
+
+    function label_button(btn, description) {
+        return label_elem('#btn-' + btn, 'bottom', description);
+    }
+
+    function label_input(description) {
+        return label_elem('#math-input', widescreen() ? 'left' : 'bottom',
+                          description);
+    }
+
+    function label_pretty_print(description) {
+        return label_elem('#pretty-print', widescreen() ? 'right' : 'bottom',
+                          description);
+    }
+
+    function click_button(btn) {
+        return function() {
+            console.log($('#btn-' + btn));
+            this.destroy_popover();
+            $('#btn-' + btn).click();
+            this.next();
+        };
+    }
+
+    var tutorial = [
+        clear_input,
+        label_input('You type expressions in this area.'),
+        label_pretty_print('Expressions you type in the input area appear '
+                           + 'here in pretty-printed mathematical notation. '
+                           + 'Click &ldquo;next&rdquo; to try it out!'),
+        append_line('x^2 + 4x - 7'),
+        label_pretty_print('Neat huh...'),
+        label_elem('#btn-answer', 'right', 'These controls allow you to '
+                                           + 'communicate to the system.'),
+        label_button('validate', 'Validate that the steps you have done so far '
+                                 + 'are correct.'),
+        label_button('hint', 'Ask the system for a hint on how to continue when '
+                             + 'you are stuck.'),
+        label_button('step', 'Let the system sort out the next step in your '
+                             + 'calculation'),
+        label_button('answer', 'Let the system do your entire calculation.'),
+        label_elem('#examples', 'bottom', 'Here are some examples that show you '
+                                          + 'how to use the interface properly.'),
+    ];
+
+    $('#tutorial').click(function() {
+        new Example(tutorial).play();
+    });
+
+    var examples = [[
+        clear_input,
+        label_input('This example shows how you can interactively rewrite an '
+                    + 'expression with a little help by the system. Start '
+                    + 'by entering an expression.'),
+        append_line('[sin(x) + sin(x)]\''),
+        label_input('Rewrite the expression as far as you can.'),
+        append_line('[2sin(x)]\''),
+        label_button('validate', 'Validate that your calculation is correct.'),
+        click_button('validate'),
+        label_pretty_print('All icons should be green.'),
+        label_button('hint', 'When you\'re stuck, ask for a hint.'),
+        click_button('hint'),
+        label_pretty_print('The hint appears here, try to apply it.'),
+        //label_button('step', 'If you do not understand the hint, let the '
+        //                     + 'system apply it for you.'),
+        //click_button('step'),
+        //label_pretty_print('Understand it now? You may want to erase the last '
+        //                   + 'line and try for yourself!'),
+        //erase_line,
+        //label_input('Take a step back, try to apply the hint yourself.'),
+        append_line('3[sin(x)]\''),
+        label_button('validate', 'Again, validate that your calculation is '
+                                 + 'correct.'),
+        click_button('validate'),
+        label_pretty_print('Oops! You made an error, you should fix it before '
+                           + 'continuing.'),
+        erase_line,
+        append_line('2[sin(x)]\''),
+        click_button('validate'),
+        label_input('Continue rewriting the expression.'),
+        append_line('(1 + 1)[sin(x)]\''),
+        label_input('This step is correct, but makes no sense because it does '
+                    + 'not help you any further.'),
+        label_button('validate', 'The validator will detect this too.'),
+        click_button('validate'),
+        label_pretty_print('The orange icon indicates that you have not made '
+                           + 'any progress.'),
+        label_input('Go back and try something else.'),
+        erase_line,
+        append_line('2cos(x)'),
+        label_button('validate', 'Keep validating...'),
+        click_button('validate'),
+        label_pretty_print('Yay! This seems to be the answer you were looking '
+                           + 'for.'),
+        label_button('hint', 'Assert that you are done by checking if there '
+                     + 'are any hints left.'),
+        click_button('hint'),
+    ], [
+        clear_input,
+        label_input('This example shows how you can let the system rewrite an '
+                    + 'expression step-wise. Start with an expression.'),
+        append_line('[sin(x) + sin(x)]\''),
+        label_button('step', 'Ask the system to execute a step.'),
+        click_button('step'),
+        label_pretty_print('The step will be displayed with a preceding hint.'),
+        label_button('step', 'You can keep asking for steps until the '
+                             + 'calculation is done.'),
+        click_button('step'),
+        label_button('step', 'You can keep asking for steps until the '
+                             + 'calculation is done.'),
+        click_button('step'),
+        label_button('step', 'You can keep asking for steps until the '
+                             + 'calculation is done.'),
+        click_button('step'),
+    ], [
+        clear_input,
+        label_input('This example shows how you can let the system rewrite an '
+                    + 'expression fast. Start with an expression.'),
+        append_line('[sin(x) + sin(x)]\''),
+        label_button('answer', 'Ask the system for an answer.'),
+        click_button('answer'),
+        label_pretty_print('All steps will be displayed with preceding hints.'),
+    ]];
+
+    $('#examples .dropdown-menu a').each(function(i) {
+        $(this).click(function() {
+            new Example(examples[i]).play();
+        });
+    });
+
+    if (location.search.substr(0, 3) == '?t=') {
+        var t = parseInt(decodeURIComponent(location.search.substr(3)));
+
+        if (t == 0)
+            new Example(tutorial).play();
+        else if (t > 0 && t <= examples.length)
+            new Example(examples[t - 1]).play();
+    }
+})(jQuery);

+ 40 - 0
src/frontend/tpl/docs.html

@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <meta http-equiv="content-type" content="text/html; charset=utf-8">
+        <title>Mathematical term rewriting frontend</title>
+        <link rel="stylesheet" href="/static/frontend/css/editor.css">
+        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
+    </head>
+    <body>
+        <div class="navbar navbar-inverse navbar-fixed-top">
+            <div class="navbar-inner">
+                <div class="container">
+                    <a class="brand" href="">Mathematical Term Rewriting</a>
+                    <ul class="nav">
+                        <li><a href="index.html">Editor</a></li>
+                        <li><a href="index.html?t=0">Tutorial</a></li>
+                        <li class="dropdown">
+                            <a href="#" data-toggle="dropdown" class="dropdown-toggle">
+                                Examples <b class="caret"></b>
+                            </a>
+                            <ul class="dropdown-menu">
+                                <li><a href="index.html?t=1">Validation &amp; hints</a></li>
+                                <li><a href="index.html?t=2">Steps</a></li>
+                                <li><a href="index.html?t=3">Direct answer</a></li>
+                            </ul>
+                        </li>
+                        <li class="active"><a href="docs.html">Documentation</a></li>
+                    </ul>
+                </div>
+            </div>
+        </div>
+
+        <div class="container">
+        </div>
+
+        <script type="text/javascript" src="/static/js/jquery-1.8.2.min.js"></script>
+        <script type="text/javascript" src="/static/bootstrap/js/bootstrap.min.js"></script>
+        <script type="text/javascript" src="/static/frontend/js/docs.js"></script>
+    </body>
+</html>

+ 60 - 18
src/frontend/tpl/editor.html

@@ -3,33 +3,75 @@
     <head>
         <meta http-equiv="content-type" content="text/html; charset=utf-8">
         <title>Mathematical term rewriting frontend</title>
-        <script type="text/javascript" src="/static/js/jquery-1.8.2.min.js"></script>
-        <script type="text/javascript"
-            src="/static/external/mathjax/MathJax.js?config=AM_HTMLorMML-full"></script>
+        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
         <link rel="stylesheet" href="/static/frontend/css/editor.css">
     </head>
     <body>
-        <div id="control-buttons"><button onclick=window.clear_input()>clear</button><div class="separator"></div><button onclick=window.validate_input()>validate</button><button onclick=window.hint_input()>hint</button><button onclick=window.step_input()>step</button><button onclick=window.answer_input()>answer</button><div id="loader"></div></div>
+        <div class="navbar navbar-inverse navbar-fixed-top">
+            <div class="navbar-inner">
+                <div class="container">
+                    <a class="brand" href="">Mathematical Term Rewriting</a>
+                    <ul class="nav">
+                        <li class="active"><a href="index.html">Editor</a></li>
+                        <li><a id="tutorial" href="#">Tutorial</a></li>
+                        <li class="dropdown" id="examples">
+                            <a href="#" data-toggle="dropdown" class="dropdown-toggle">
+                                Examples <b class="caret"></b>
+                            </a>
+                            <ul class="dropdown-menu">
+                                <li><a href="#">Validation &amp; hints</a></li>
+                                <li><a href="#">Steps</a></li>
+                                <li><a href="#">Direct answer</a></li>
+                            </ul>
+                        </li>
+                        <li><a href="docs.html">Documentation</a></li>
+                    </ul>
+                </div>
+            </div>
+        </div>
 
-        <div id="error"></div>
+        <div class="container">
+            <div id="error" class="alert alert-error">
+                <button type="button" class="close">&times;</button>
+                <strong>Error</strong> <span class="text"></span>
+            </div>
 
-        <div id="input" class="panel">
-            <div class="label">Input view</div>
-            <div class="box">
-                <textarea id="MathInput"></textarea>
+            <div class="row">
+                <div class="span12">
+                    <div class="btn-toolbar">
+                        <button id="btn-clear" class="btn">clear</button>
+                        <div class="btn-group">
+                            <button id="btn-validate" class="btn btn-info">validate</button>
+                            <button id="btn-hint" class="btn btn-info">hint</button>
+                            <button id="btn-step" class="btn btn-info">step</button>
+                        </div>
+                        <button id="btn-answer" class="btn">answer</button>
+                        <div id="loader"></div>
+                    </div>
+                </div>
             </div>
-        </div>
 
-        <div id="math" class="panel">
-            <div class="label">Math view</div>
-        </div>
+            <div class="row">
+                <div class="span6">
+                    <textarea id="math-input" class="span6 math-input"></textarea>
+                </div>
+                <div class="span6">
+                    <div id="pretty-print" class="well pretty-print"></div>
+                </div>
+            </div>
 
-        <div id="credits">Idea and feedback by <a
-                href="http://homepages.cwi.nl/~apt/" target=_window>Prof.dr.
-                K.R. Apt</a>, implementation by Taddeüs Kroes and <a
-                href="http://smvv.kompiler.org" target=_window>Sander van
-                Veen</a>. </div>
+            <div class="row">
+                <div class="span12 credits">
+                    Idea and feedback by <a href="http://homepages.cwi.nl/~apt/" target="_blank">Prof.dr. Krzysztof R. Apt</a>,
+                    implementation by Tadde&uuml;s Kroes and <a href="http://smvv.kompiler.org" target="_blank">Sander van Veen</a>.
+                </div>
+            </div>
+        </div>
 
+        <script type="text/javascript" src="/static/js/jquery-1.8.2.min.js"></script>
+        <script type="text/javascript" src="/static/bootstrap/js/bootstrap.min.js"></script>
+        <script type="text/javascript" src="/static/external/mathjax/MathJax.js?config=AM_HTMLorMML-full"></script>
         <script type="text/javascript" src="/static/frontend/js/editor.js"></script>
+        <script type="text/javascript" src="/static/frontend/js/examples.js"></script>
     </body>
 </html>

Fișier diff suprimat deoarece este prea mare
+ 8 - 0
static/bootstrap/css/bootstrap.min.css


BIN
static/bootstrap/img/glyphicons-halflings-white.png


BIN
static/bootstrap/img/glyphicons-halflings.png


Fișier diff suprimat deoarece este prea mare
+ 5 - 0
static/bootstrap/js/bootstrap.min.js


BIN
static/img/cross.png


BIN
static/img/error.png


BIN
static/img/info.png


BIN
static/img/load.gif


BIN
static/img/tick.png


+ 3 - 2
tests/rules.mk

@@ -15,7 +15,7 @@ TGT_DIR := $(TGT_DIR) $(PROFILER_OUTPUT_DIR)
 
 .PHONY: test coverage $(TESTS)
 
-test: $(TESTS) build/external/pybison
+test: $(TESTS)
 
 ifeq ($(findstring python-coverage,$(wildcard /usr/bin/*)), python-coverage)
 coverage: ${COVERAGE} build
@@ -42,7 +42,8 @@ ${COVERAGE}:
 	@echo "Install package 'python-coverage' to generate a coverage report."
 	@echo "On Debian/Ubuntu use: sudo apt-get install python-coverage"; false
 
-$(TESTS): build/external/pybison; @python -m external.testrunner $@
+$(TESTS): build
+	@python -m external.testrunner $@
 
 profile-test-%: $(PROFILER_OUTPUT_DIR) build
 	 python -m cProfile -s cumulative \

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff