Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
03/20/13 16:56:28 (12 years ago)
Author:
fschoepp
Message:

#1888:

  • DAL: Added a Delete method which deletes by experiment id.
  • HL DataTables will now be transposed and mapped as double[ROWS][COLUMNS] (transposed)
  • JS: Moved all classes into "modules" to prevent namespace pollution (using OAAS_MODEL for model classes, OAAS_VIEW for views and OAAS_CONTROLLER for controllers)
  • JS: Moved DatatypeMapper classes into Backbone views
  • JS: Models now correctly send DELETE requests
  • Added a new job overview page (which also renders run details) using AJAX
  • Using moment.min.js to format DateTime as string
  • Controllers now inherit from BaseController which provides a RedirectToLoginIfNecessary-method
  • Added loading animations to several AJAX bound places (loading experiments / scenarios)
  • Added a section to _Layout.cshtml which allows page-specific JavaScript includes (<script> only for a certain page)
  • Fixed Build/Edit of experiment menu redirecting to the wrong page
  • The Experiment Variation Dialog disables input fields, if the property has not been activated before
Location:
branches/OaaS/HeuristicLab.Services.Optimization.Web/Content
Files:
7 added
5 edited

Legend:

Unmodified
Added
Removed
  • branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/Datatypemapping.js

    r9227 r9324  
    1 function DatatypeMapper() {
    2 }
     1var OAAS_VIEW = (function (my, _, $, Backbone) {
     2    my.DatatypeMapper = function () {
     3        this.cb = {};
     4        _.extend(this.cb, Backbone.Events);
    35
    4 DatatypeMapper.prototype.mapHtml = function (property) {
    5     var parameter = property.Value;
    6     var key = property.Name;
    7     if (property.Options) {
    8         return DatatypeMapper_mapStrings(property.Name, property.Options, property.Value);
    9     }
    10     else if (parameter instanceof Array) {
    11         // parameter is a vector of strings
    12         if (parameter[0] instanceof String || typeof (parameter[0]) == 'string') {
    13             return DatatypeMapper_mapStrings(key, parameter);
     6        this.mapHtml = function (property, el) {
     7            var parameter = property.Value;
     8            var key = property.Name;
     9            if (property.Options) {
     10                var osv = new OAAS_VIEW.SelectionView({ model: property, el: el });
     11                this.cb.listenTo(osv, 'selected', function (model) {
     12                    property.Value = model.value;
     13                });
     14                osv.render();
     15                return osv;
     16            }
     17            else if (parameter instanceof Array) {
     18                // parameter is a matrix or vector of numbers
     19                var tev = new OAAS_VIEW.TableEditView({ model: parameter, el: el, editable: true });
     20                tev.render();
     21                return tev;
     22            }
     23            else if (typeof (parameter) == 'boolean') {
     24                var osv = new OAAS_VIEW.OptionSelectionView({ model: parameter, el: el, hideText: true });
     25                this.cb.listenTo(osv, 'changed', function (model) {
     26                    property.Value = model.checked;
     27                });
     28                osv.render();
     29                return osv;
     30            }
     31            // parameter is a number
     32            else if (!isNaN(parameter)) {
     33                var nev = new OAAS_VIEW.NumberEditableView({ model: property, el: el });
     34                nev.render();
     35                return nev;
     36            }
     37            return 'No mapping for ' + typeof (parameter) + ' (Key: ' + key + ')';
     38        };
    1439
    15         }
    16         // parameter is a vector of numbers
    17         else if (!isNaN(parameter[0])) {
    18             return DatatypeMapper_mapNumbers(key, parameter);
    19         }
    20         // parameter is a matrix of numbers
    21         else {
    22             return DatatypeMapper_mapMatrix(key, parameter);
    23         }
    2440
    2541    }
    26     else if (typeof (parameter) == 'boolean') {
    27         return DatatypeMapper_mapBoolean(key, parameter);
    28     }
    29     // parameter is a number
    30     else if (!isNaN(parameter)) {
    31         return DatatypeMapper_mapNumber(key, parameter);
    32     }
    33     return 'No mapping for ' + typeof (parameter) + ' (Key: ' + key + ')';
    34 }
    3542
    3643
    37 function DatatypeMapper_mapStrings(key, param, selected) {
    38   // http://stackoverflow.com/questions/4814512/how-to-create-dropdown-list-dynamically-using-jquery
    39   var s = $('<select name="' + key + '"/>');
    40   for (var i = 0; i < param.length; i++) {
    41     $('<option />', { value: param[i], text: param[i] }).appendTo(s);
    42   }
    43   s.val(selected);
    44   return s;
    45 }
     44    function DatatypeMapper_mapStrings(key, param, selected) {
     45        // http://stackoverflow.com/questions/4814512/how-to-create-dropdown-list-dynamically-using-jquery
     46        var s = $('<select name="' + key + '"/>');
     47        for (var i = 0; i < param.length; i++) {
     48            $('<option />', { value: param[i], text: param[i] }).appendTo(s);
     49        }
     50        s.val(selected);
     51        return s;
     52    }
    4653
    47 function DatatypeMapper_mapNumber(key, param) {
    48   return $('<input type="text" name="' + key + '" />').val(param);
    49 }
     54    function DatatypeMapper_mapNumber(key, param) {
     55        return $('<input type="text" name="' + key + '" />').val(param);
     56    }
    5057
    51 function DatatypeMapper_mapBoolean(key, param) {
    52   var s = $('<select name="' + key + '"/>');
    53   $('<option />', { value: 'true', text: 'true' }).appendTo(s);
    54   $('<option />', { value: 'false', text: 'false' }).appendTo(s);
    55   return s;
    56 }
     58    function DatatypeMapper_mapBoolean(key, param) {
     59        var s = $('<select name="' + key + '"/>');
     60        $('<option />', { value: 'true', text: 'true' }).appendTo(s);
     61        $('<option />', { value: 'false', text: 'false' }).appendTo(s);
     62        return s;
     63    }
    5764
    58 function DatatypeMapper_mapNumbers(key, param) {
    59   // http: //stackoverflow.com/questions/8749236/create-table-with-jquery-append
    60   var table = $('<table></table>').addClass('editableTable');
    61   var head = $('<thead></thead>');
    62   // create head elements
    63   var headerRow = $('<tr></tr>');
    64   $('<td />').text(key + ' Column').appendTo(headerRow); 
    65   headerRow.appendTo(head);
    66   head.appendTo(table);
    67   var body = $('<tbody></tbody>');
    68   for (var i = 0; i < param.length; i++) {
    69     var row = $('<tr></tr>');
    70     var td = $('<td />').appendTo(row);
    71     $('<input type="text" name="' + key + '_' + i + '" />').val(param[i]).appendTo(td);   
    72     row.appendTo(body);
    73   }
    74   body.appendTo(table);
    75   return table;
    76 }
     65    function DatatypeMapper_mapNumbers(key, param) {
     66        // http: //stackoverflow.com/questions/8749236/create-table-with-jquery-append
     67        var table = $('<table></table>').addClass('editableTable');
     68        var head = $('<thead></thead>');
     69        // create head elements
     70        var headerRow = $('<tr></tr>');
     71        $('<td />').text(key + ' Column').appendTo(headerRow);
     72        headerRow.appendTo(head);
     73        head.appendTo(table);
     74        var body = $('<tbody></tbody>');
     75        for (var i = 0; i < param.length; i++) {
     76            var row = $('<tr></tr>');
     77            var td = $('<td />').appendTo(row);
     78            $('<input type="text" name="' + key + '_' + i + '" />').val(param[i]).appendTo(td);
     79            row.appendTo(body);
     80        }
     81        body.appendTo(table);
     82        return table;
     83    }
    7784
    78 function DatatypeMapper_mapMatrix(key, param) {
    79   // http: //stackoverflow.com/questions/8749236/create-table-with-jquery-append
    80   var table = $('<table></table>').addClass('editableTable');
    81   var head = $('<thead></thead>');
    82   // create head elements
    83   var headerRow = $('<tr></tr>');
    84   for (var i = 0; i < param[0].length; i++) {
    85     $('<td />').text(key + ' Column ' + i).appendTo(headerRow);
    86   }
    87   headerRow.appendTo(head);
    88   head.appendTo(table);
    89   var body = $('<tbody></tbody>');
    90   for (var i = 0; i < param.length; i++) {
    91     var row = $('<tr></tr>');
    92     for (var j = 0; j < param[i].length; j++) {
    93       var td = $('<td />').appendTo(row);     
    94       $('<input type="text" name="' + key + '_' + i + '_' + j + '" />').val(param[i][j]).appendTo(td);     
     85    function DatatypeMapper_mapMatrix(key, param) {
     86        // http: //stackoverflow.com/questions/8749236/create-table-with-jquery-append
     87        var table = $('<table></table>').addClass('editableTable');
     88        var head = $('<thead></thead>');
     89        // create head elements
     90        var headerRow = $('<tr></tr>');
     91        for (var i = 0; i < param[0].length; i++) {
     92            $('<td />').text(key + ' Column ' + i).appendTo(headerRow);
     93        }
     94        headerRow.appendTo(head);
     95        head.appendTo(table);
     96        var body = $('<tbody></tbody>');
     97        for (var i = 0; i < param.length; i++) {
     98            var row = $('<tr></tr>');
     99            for (var j = 0; j < param[i].length; j++) {
     100                var td = $('<td />').appendTo(row);
     101                $('<input type="text" name="' + key + '_' + i + '_' + j + '" />').val(param[i][j]).appendTo(td);
     102            }
     103            row.appendTo(body);
     104        }
     105        body.appendTo(table);
     106        return table;
     107
     108        /*var table = '<table class="editableTable"><thead><tr>';
     109        for (var i = 0; i < param[0].length; i++) {
     110        table += '<th>' + key + ' Column ' + (i + 1) + '</th>';
     111        }
     112        table += '</tr>';
     113        // foreach value entry (2d entry)
     114        for (var i = 0; i < param.length; i++) {
     115        table += '<tr>';
     116        for (var j = 0; j < param[i].length; j++) {
     117        table += '<td><input type="text" name="' + key + '_' + i + '_' + j + '" /></td>';
     118        }
     119        table += '</tr>';
     120        }
     121        return $*/
    95122    }
    96     row.appendTo(body);
    97   }
    98   body.appendTo(table);
    99   return table;
    100123
    101   /*var table = '<table class="editableTable"><thead><tr>';
    102   for (var i = 0; i < param[0].length; i++) {
    103     table += '<th>' + key + ' Column ' + (i + 1) + '</th>';
    104   }
    105   table += '</tr>';
    106   // foreach value entry (2d entry)
    107   for (var i = 0; i < param.length; i++) {
    108     table += '<tr>';
    109     for (var j = 0; j < param[i].length; j++) {
    110       table += '<td><input type="text" name="' + key + '_' + i + '_' + j + '" /></td>';
     124    /*
     125    DatatypeMapper.prototype.mapString = function (value) {
     126    if (value == "true") return true;
     127    else if (value == "false") return false;
     128    else if (!isNaN(value)) return parseFloat(value.replace(',', '.'));
     129    return value;
    111130    }
    112     table += '</tr>';
    113   }
    114   return $*/
    115 }
    116131
    117 DatatypeMapper.prototype.mapString = function (value) {
    118   if (value == "true") return true;
    119   else if (value == "false") return false;
    120   else if (!isNaN(value)) return parseFloat(value.replace(',', '.'));
    121   return value;
    122 }
    123 
    124 DatatypeMapper.prototype.aggregateTables = function (data) {
     132    DatatypeMapper.prototype.aggregateTables = function (data) {
    125133    // aggregate tables:
    126134    for (var dataKey in data) {
    127         var entry = data[dataKey];
    128         var tableEntries = {};
    129         var toRemove = [];
    130         for (var key in entry) {
    131             if (key.indexOf('_') != -1) {
    132                 var splitted = key.split('_');
    133                 var name = splitted[0];
    134                 var row = parseInt(splitted[1]);
    135                 if (!(name in tableEntries)) {
    136                     tableEntries[name] = []
    137                 }
     135    var entry = data[dataKey];
     136    var tableEntries = {};
     137    var toRemove = [];
     138    for (var key in entry) {
     139    if (key.indexOf('_') != -1) {
     140    var splitted = key.split('_');
     141    var name = splitted[0];
     142    var row = parseInt(splitted[1]);
     143    if (!(name in tableEntries)) {
     144    tableEntries[name] = []
     145    }
    138146
    139                 if (splitted.length == 2) { // its a vector of elements
    140                     tableEntries[name].push(entry[key])
    141                 } else if (splitted.length == 3) { // its a matrix of elements
    142                     column = parseInt(splitted[2]);
    143                     if (tableEntries[name].length < row + 1)
    144                         tableEntries[name].push([]);
    145                     tableEntries[name][row][column] = entry[key];
    146                 }
    147                 toRemove.push(key);
    148             }
    149         }
     147    if (splitted.length == 2) { // its a vector of elements
     148    tableEntries[name].push(entry[key])
     149    } else if (splitted.length == 3) { // its a matrix of elements
     150    column = parseInt(splitted[2]);
     151    if (tableEntries[name].length < row + 1)
     152    tableEntries[name].push([]);
     153    tableEntries[name][row][column] = entry[key];
     154    }
     155    toRemove.push(key);
     156    }
     157    }
    150158
    151         for (var i = 0; i < toRemove.length; i++) {
    152             delete entry[toRemove[i]];
    153         }
     159    for (var i = 0; i < toRemove.length; i++) {
     160    delete entry[toRemove[i]];
     161    }
    154162
    155         for (var key in tableEntries) {
    156             entry[key] = tableEntries[key];
    157         }
     163    for (var key in tableEntries) {
     164    entry[key] = tableEntries[key];
    158165    }
    159 }
     166    }
     167    }*/
     168    return my;
     169} (OAAS_VIEW || {}, _, $, Backbone));
  • branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/experiment.controller.js

    r9305 r9324  
    1 function GeneralController() {
    2     this.variationRequestHandler = function (evt) {
    3         var self = this;
    4         var dialog = new VariationDialog({ model: evt.model });
    5         var dialogController = {};
    6         _.extend(dialogController, Backbone.Events);
    7         dialogController.listenTo(dialog, 'variations-generated', function (variations) {
    8             var parent = evt.model.get('parent');
    9             for (var i = 0; i < variations.length; i++) {
    10                 var title = evt.model.get('title');
    11                 var offset = title.indexOf('(')
    12                 if (offset != -1) {
    13                     title = title.substring(0, offset);
    14                 }
    15                 title += '(';
    16                 for (var j = 0; j < variations[i].length; j++) {
    17                     title += variations[i][j].Name + " = " + variations[i][j].Value + "; ";
    18                 }
    19                 title += ')';
    20                 var data = { AlgorithmParameters: variations[i] };
    21                 if (evt.model.attributes.data.ProblemParameters) {
    22                     data.ProblemParameters = evt.model.attributes.data.ProblemParameters;
    23                 }
    24                 parent.addNode({ title: title, nodeId: evt.model.get('nodeId'), data: data });
    25             }
    26             self.model.trigger('change');
    27         });
    28         dialog.render();
    29     },
    30     this.experimentFinishedHandler = function (experimentModel, availableExperiments, selectableGroup) {
    31         var loadingDialog = new LoadingDialog({ el: $('#loadingDialog') });
    32         // start the loading dialog
    33         loadingDialog.setLoading(true);
    34         loadingDialog.text('Saving experiment ' + experimentModel.get('title') + '...');
    35         loadingDialog.render();
    36         // send experiment to server
    37         experimentModel.save({}, { success: function () {
    38             loadingDialog.setLoading(false);
    39             loadingDialog.text('Experiment successfully saved!');
    40             loadingDialog.render();
    41             if (availableExperiments)
    42                 availableExperiments.fetch({ cache: false, success: function (itm) {
    43                     selectableGroup.render();
    44                 }
    45                 });
    46         }
    47         });
    48         //loadingDialog.close();
    49     }
    50 }
    51 
    52 function ExperimentPageController() {
    53     this.refreshExperiments = function () {
    54         var availableExperiments = new ExperimentList();
    55         availableExperiments.fetch({ cache: false, success: function (itm) {
    56             $('#experiments').empty();
    57             for (var i = 0; i < availableExperiments.length; i++) {
    58                 new DraggableView({ model: availableExperiments.models[i], el: $('#experiments') }).render();
    59             }
    60         }
    61         });
    62     },
    63     this.refreshScenarios = function () {
    64         var availableScenarios = new ScenarioList();
    65         availableScenarios.fetch({ cache: false, success: function (itm) {
    66             var group = new DraggableGroup({ model: availableScenarios, el: $('#algorithms') });
    67             group.render();
    68         }
    69         });
    70     },
    71     this.create = function () {
    72         var self = this;
    73         var generalController = new GeneralController();
    74         // create all models + required view for the experiment page
    75         var model = new ExperimentNode({
    76             title: 'Experiment',
    77             key: 0,
    78             isExperiment: true
    79         }, { parse: true });
    80         generalController.model = model;
    81         var experimentModel = new Experiment({ experiment: model });
    82 
    83         var view = new ExperimentTreeView({ model: model, el: $('#container') });
    84         view.render();
    85 
    86         this.refreshScenarios();
    87 
    88         this.refreshExperiments();
    89 
    90         var wizard = new StepWizardView({ el: $('#stepWizard') });
    91         wizard.render();
    92 
    93         var detailsView = new ExperimentDetailsTreeView({ model: model, el: $('#container2') });
    94         var validationView = new ValidationHintsView({ model: { header: "Validation failed!", text: ""} });
    95         var parameterDialog = new ParameterDialog({ model: model, el: $('#parameterDialog') });
    96 
    97         var wizardController = {};
    98         _.extend(wizardController, Backbone.Events);
    99 
    100         wizardController.listenTo(model, 'change', function () {
    101             // update the details view, when the model changes
    102             view.render();
    103             detailsView.render();
    104         });
    105 
    106 
    107         wizardController.listenTo(wizard, 'experiment-finished', function () {
    108             generalController.experimentFinishedHandler(experimentModel, null, null);
    109             self.refreshExperiments();
    110             /*// start the loading dialog
     1var OAAS_CONTROLLER = (function (my, Backbone, OAAS_VIEW, OAAS_MODEL, _, $) {
     2    my.GeneralController = function () {
     3        this.variationRequestHandler = function (evt) {
     4            var self = this;
     5            var dialog = new OAAS_VIEW.VariationDialog({ model: evt.model });
     6            var dialogController = {};
     7            _.extend(dialogController, Backbone.Events);
     8            dialogController.listenTo(dialog, 'variations-generated', function (variations) {
     9                var parent = evt.model.get('parent');
     10                for (var i = 0; i < variations.length; i++) {
     11                    var title = evt.model.get('title');
     12                    var offset = title.indexOf('(')
     13                    if (offset != -1) {
     14                        title = title.substring(0, offset);
     15                    }
     16                    title += '(';
     17                    for (var j = 0; j < variations[i].length; j++) {
     18                        title += variations[i][j].Name + " = " + variations[i][j].Value + "; ";
     19                    }
     20                    title += ')';
     21                    var data = { AlgorithmParameters: variations[i] };
     22                    if (evt.model.attributes.data.ProblemParameters) {
     23                        data.ProblemParameters = evt.model.attributes.data.ProblemParameters;
     24                    }
     25                    parent.addNode({ title: title, nodeId: evt.model.get('nodeId'), data: data });
     26                }
     27                self.model.trigger('change');
     28            });
     29            dialog.render();
     30        },
     31        this.experimentFinishedHandler = function (experimentModel, availableExperiments, selectableGroup) {
     32            var loadingDialog = new OAAS_VIEW.LoadingDialog({ el: $('#loadingDialog') });
     33            // start the loading dialog
    11134            loadingDialog.setLoading(true);
    11235            loadingDialog.text('Saving experiment ' + experimentModel.get('title') + '...');
     
    11437            // send experiment to server
    11538            experimentModel.save({}, { success: function () {
    116             loadingDialog.setLoading(false);
    117             loadingDialog.text('Experiment successfully saved!');
    118             loadingDialog.render();
    119             self.refreshExperiments();
    120             }
    121             });*/
     39                loadingDialog.setLoading(false);
     40                loadingDialog.text('Experiment successfully saved!');
     41                loadingDialog.render();
     42                if (availableExperiments)
     43                    availableExperiments.fetch({ cache: false, success: function (itm) {
     44                        selectableGroup.render();
     45                    }
     46                    });
     47            }
     48            });
    12249            //loadingDialog.close();
    123         });
    124 
    125         wizardController.listenTo(view, 'structure-changed', function (node) {
     50        }
     51    }
     52
     53    my.ExperimentPageController = function () {
     54        this.refreshExperiments = function () {
     55            var availableExperiments = new OAAS_MODEL.ExperimentList();
     56            availableExperiments.fetch({ cache: false, success: function (itm) {
     57                var group = new OAAS_VIEW.DraggableGroup({ collection: availableExperiments, el: $('#experiments') });
     58                group.render();
     59            }
     60            });
     61        },
     62        this.refreshScenarios = function () {
     63            var availableScenarios = new OAAS_MODEL.ScenarioList();
     64            availableScenarios.fetch({ cache: false, success: function (itm) {
     65                var group = new OAAS_VIEW.DraggableGroup({ collection: availableScenarios, el: $('#algorithms') });
     66                group.render();
     67            }
     68            });
     69        },
     70        this.create = function () {
     71            var self = this;
     72            var generalController = new my.GeneralController();
     73            // create all models + required view for the experiment page
     74            var model = new OAAS_MODEL.ExperimentNode({
     75                title: 'Experiment',
     76                key: 0,
     77                isExperiment: true
     78            }, { parse: true });
     79            generalController.model = model;
     80            var experimentModel = new OAAS_MODEL.Experiment({ experiment: model });
     81
     82            var view = new OAAS_VIEW.ExperimentTreeView({ model: model, el: $('#container') });
    12683            view.render();
    127             detailsView.render();
    128         });
    129 
    130         wizardController.listenTo(view, 'node-added', function (node) {
    131             // get details about the node
    132             node.fetch({ success: function (itm) {
    133                 model.trigger('change', {});
    134             }
    135             });
    136         });
    137 
    138         wizardController.listenTo(detailsView, 'node-clicked', function (node) {
    139             // get details about the node
    140             var modelNode = ExperimentNode.lookup(node.data.key);
    141             if (!modelNode.get('isExperiment')) {
    142                 parameterDialog.model = modelNode;
    143                 parameterDialog.render();
    144             }
    145         });
    146 
    147         wizardController.listenTo(parameterDialog, 'parameters-finished', function (node) {
    148             parameterDialog.close();
    149         });
    150 
    151         wizardController.listenTo(view, 'variation-request', function (evt) {
    152             generalController.variationRequestHandler(evt);
    153         });
    154 
    155         var experimentDetailsView = new ExperimentDetailsView({ el: $('#step3'), model: experimentModel });
     84
     85            this.refreshScenarios();
     86
     87            this.refreshExperiments();
     88
     89            var wizard = new OAAS_VIEW.StepWizardView({ el: $('#stepWizard') });
     90            wizard.render();
     91
     92            var detailsView = new OAAS_VIEW.ExperimentDetailsTreeView({ model: model, el: $('#container2') });
     93            var validationView = new OAAS_VIEW.ValidationHintsView({ model: { header: "Validation failed!", text: ""} });
     94            var parameterDialog = new OAAS_VIEW.ParameterDialog({ model: model, el: $('#parameterDialog') });
     95
     96            var wizardController = {};
     97            _.extend(wizardController, Backbone.Events);
     98
     99            wizardController.listenTo(model, 'change', function () {
     100                // update the details view, when the model changes
     101                view.render();
     102                detailsView.render();
     103            });
     104
     105
     106            wizardController.listenTo(wizard, 'experiment-finished', function () {
     107                generalController.experimentFinishedHandler(experimentModel, null, null);
     108                self.refreshExperiments();
     109            });
     110
     111            wizardController.listenTo(view, 'structure-changed', function (node) {
     112                view.render();
     113                detailsView.render();
     114            });
     115
     116            wizardController.listenTo(view, 'node-added', function (node) {
     117                // get details about the node
     118                node.fetch({ success: function (itm) {
     119                    model.trigger('change', {});
     120                }
     121                });
     122            });
     123
     124            wizardController.listenTo(detailsView, 'node-clicked', function (node) {
     125                // get details about the node
     126                var modelNode = OAAS_MODEL.ExperimentNode.lookup(node.data.key);
     127                if (!modelNode.get('isExperiment')) {
     128                    parameterDialog.model = modelNode;
     129                    parameterDialog.render();
     130                }
     131            });
     132
     133            wizardController.listenTo(parameterDialog, 'parameters-finished', function (node) {
     134                parameterDialog.close();
     135            });
     136
     137            wizardController.listenTo(view, 'variation-request', function (evt) {
     138                generalController.variationRequestHandler(evt);
     139            });
     140
     141            var experimentDetailsView = new OAAS_VIEW.ExperimentDetailsView({ el: $('#step3'), model: experimentModel });
     142
     143
     144        }
    156145    }
    157 }
    158 
    159 
    160 
    161 /// ==================== EDIT PAGE =========================
    162 /// ==================== EDIT PAGE =========================
    163 /// ==================== EDIT PAGE =========================
    164 
    165 function ExperimentEditPageController() {
    166     this.refreshScenarios = function () {
    167         var availableScenarios = new ScenarioList();
    168         availableScenarios.fetch({ cache: false, success: function (itm) {
    169             var group = new DraggableGroup({ model: availableScenarios, el: $('#draggableAlgorithms') });
    170             group.render();
    171             /*$('#algorithms').empty();
    172             for (var i = 0; i < availableScenarios.length; i++) {
    173             new DraggableView({ model: availableScenarios.models[i], el: $('#algorithms') }).render();
    174             }*/
     146
     147
     148
     149    /// ==================== EDIT PAGE =========================
     150    /// ==================== EDIT PAGE =========================
     151    /// ==================== EDIT PAGE =========================
     152
     153    my.ExperimentEditPageController = function () {
     154        this.refreshScenarios = function () {
     155            var availableScenarios = new OAAS_MODEL.ScenarioList();
     156            availableScenarios.fetch({ cache: false, success: function (itm) {
     157                var group = new OAAS_VIEW.DraggableGroup({ collection: availableScenarios, el: $('#draggableAlgorithms') });
     158                group.render();
     159            }
     160            });
     161        },
     162        this.create = function () {
     163            var generalController = new my.GeneralController();
     164
     165            var self = this;
     166            // create all models + required view for the experiment page
     167            var controllerModel = new OAAS_MODEL.ControllerModel();
     168            var model = new OAAS_MODEL.ExperimentNode({
     169                title: 'Experiment',
     170                key: 0,
     171                isExperiment: true
     172            }, { parse: true });
     173
     174            generalController.model = model;
     175            var experimentModel = new OAAS_MODEL.Experiment({ experiment: model });
     176            var experimentDetailsView = new OAAS_VIEW.ExperimentDetailsView({ el: $('#step4'), model: experimentModel });
     177            experimentDetailsView.render();
     178
     179            var availableExperiments = new OAAS_MODEL.ExperimentList();
     180
     181            var wizardController = {};
     182            _.extend(wizardController, Backbone.Events);
     183
     184            this.refreshScenarios();
     185
     186            var selectableGroup = new OAAS_VIEW.SelectableGroup({ collection: availableExperiments, el: $('#experiments') });
     187            //selectableGroup.render();
     188            var draggableExperiments = new OAAS_VIEW.DraggableGroup({ collection: availableExperiments, el: $('#draggableExperiments') });
     189            availableExperiments.fetch({ cache: false, success: function (itm) {
     190                // selectableGroup = new OAAS_VIEW.SelectableGroup({ collection: availableExperiments, el: $('#experiments') });
     191                selectableGroup.render();
     192
     193                wizardController.listenTo(selectableGroup, 'node-selected', function (nodeId) {
     194                    var node = availableExperiments.find(function (itm) { return itm.get('nodeId') == nodeId; });
     195
     196                    var newNode = new OAAS_MODEL.ExperimentNode(node.attributes);
     197                    newNode.fetch({ success: function () {
     198                        experimentModel.set({
     199                            experiment: newNode,
     200                            title: node.get('title'),
     201                            nodeId: node.get('nodeId'),
     202                            run: node.get('run'),
     203                            repititions: node.get('repititions'),
     204                            group: node.get('group')
     205                        });
     206                        controllerModel.set({ selectedNode: newNode });
     207                        $('#deleteExperimentButton').removeAttr('disabled');
     208                        detailsView.model = newNode;
     209                        detailsView.render();
     210                        view.model = newNode;
     211                        view.render();
     212                        experimentDetailsView.render();
     213                    }
     214                    });
     215                }
     216                );
     217            }
     218            });
     219
     220            // create wizard with 4 steps
     221            var wizard = new OAAS_VIEW.StepWizardView({ el: $('#stepWizard') });
     222            wizard.render();
     223
     224            var view = new OAAS_VIEW.ExperimentTreeView({ model: model, el: $('#container') });
     225            view.render();
     226            var validationView = new OAAS_VIEW.ValidationHintsView({ model: { header: "Validation failed!", text: ""} });
     227
     228            var detailsView = new OAAS_VIEW.ExperimentDetailsTreeView({ model: model, el: $('#container2') });
     229
     230            var parameterDialog = new OAAS_VIEW.ParameterDialog({ model: model, el: $('#parameterDialog') });
     231            var loadingDialog = new OAAS_VIEW.LoadingDialog({ el: $('#loadingDialog') });
     232
     233            wizardController.listenTo(wizard, 'step-validated', function (validationModel) {
     234                // update the details view
     235                if (validationModel.stepNumber == 1) {
     236                    if (controllerModel.get('selectedNode') == null) {
     237                        validationView.model["text"] = 'Please select an experiment to continue!';
     238                        validationView.render();
     239                        validationModel.succeeded = false;
     240                    }
     241                }
     242                detailsView.render();
     243            });
     244
     245            wizardController.listenTo(model, 'change', function () {
     246                // update the details view, when the model changes
     247                view.render();
     248                detailsView.render();
     249            });
     250
     251            wizardController.listenTo(view, 'structure-changed', function (node) {
     252                view.render();
     253            });
     254
     255            wizardController.listenTo(view, 'node-added', function (node) {
     256                // get details about the node
     257                //if (!node.get('isExperiment'))
     258                node.fetch({ success: function (itm) {
     259                    model.trigger('change', {});
     260                }
     261                });
     262            });
     263
     264            wizardController.listenTo(wizard, 'experiment-finished', function () {
     265                generalController.experimentFinishedHandler(experimentModel, availableExperiments, selectableGroup);
     266            });
     267
     268            wizardController.listenTo(detailsView, 'node-clicked', function (node) {
     269                // get details about the node
     270                var modelNode = OAAS_MODEL.ExperimentNode.lookup(node.data.key);
     271                if (!modelNode.get('isExperiment')) {
     272                    parameterDialog.model = modelNode;
     273                    parameterDialog.render();
     274                }
     275            });
     276
     277            wizardController.listenTo(view, 'variation-request', function (evt) {
     278                generalController.variationRequestHandler(evt);
     279            });
     280
     281            wizardController.listenTo(parameterDialog, 'parameters-finished', function (node) {
     282                parameterDialog.close();
     283            });
     284
     285            $('#deleteExperimentButton').click(function (evt) {
     286                var node = controllerModel.get('selectedNode');
     287                var nodes = availableExperiments.where({ nodeId: node.get('nodeId') });
     288                if (nodes.length == 1) {
     289                    nodes[0].destroy();
     290                    $('#deleteExperimentButton').attr('disabled', 'disabled');
     291                    controllerModel.set('selectedNode', null);
     292                }
     293            });
    175294        }
    176         });
    177     },
    178     this.create = function () {
    179         var generalController = new GeneralController();
    180 
    181         var self = this;
    182         // create all models + required view for the experiment page
    183         var controllerModel = new ControllerModel();
    184         var model = new ExperimentNode({
    185             title: 'Experiment',
    186             key: 0,
    187             isExperiment: true
    188         }, { parse: true });
    189 
    190         generalController.model = model;
    191         var experimentModel = new Experiment({ experiment: model });
    192         var experimentDetailsView = new ExperimentDetailsView({ el: $('#step4'), model: experimentModel });
    193         experimentDetailsView.render();
    194 
    195         var availableExperiments = new ExperimentList();
    196         var selectableGroup = null;
    197         var wizardController = {};
    198         _.extend(wizardController, Backbone.Events);
    199 
    200         this.refreshScenarios();
    201 
    202         availableExperiments.fetch({ cache: false, success: function (itm) {
    203             selectableGroup = new SelectableGroup({ model: availableExperiments, el: $('#experiments') });
    204             selectableGroup.render();
    205             var draggableExperiments = new DraggableGroup({ model: availableExperiments, el: $('#draggableExperiments') });
    206             draggableExperiments.render();
    207 
    208             wizardController.listenTo(selectableGroup, 'node-selected', function (nodeId) {
    209                 var node = availableExperiments.find(function (itm) { return itm.get('nodeId') == nodeId; });
    210                 var newNode = new ExperimentNode(node.attributes);
    211                 experimentModel.set({
    212                     experiment: newNode,
    213                     title: node.get('title'),
    214                     nodeId: node.get('nodeId'),
    215                     run: node.get('run'),
    216                     repititions: node.get('repititions'),
    217                     group: node.get('group')
    218                 });
    219                 controllerModel.set({ selectedNode: newNode });
    220                 detailsView.model = newNode;
    221                 detailsView.render();
    222                 view.model = newNode;
    223                 view.render();
    224                 experimentDetailsView.render();
    225             }
    226             );
    227         }
    228         });
    229 
    230         // create wizard with 4 steps
    231         var wizard = new StepWizardView({ el: $('#stepWizard') });
    232         wizard.render();
    233 
    234         var view = new ExperimentTreeView({ model: model, el: $('#container') });
    235         view.render();
    236         var validationView = new ValidationHintsView({ model: { header: "Validation failed!", text: ""} });
    237 
    238         var detailsView = new ExperimentDetailsTreeView({ model: model, el: $('#container2') });
    239 
    240         var parameterDialog = new ParameterDialog({ model: model, el: $('#parameterDialog') });
    241         var loadingDialog = new LoadingDialog({ el: $('#loadingDialog') });
    242 
    243         wizardController.listenTo(wizard, 'step-validated', function (validationModel) {
    244             // update the details view
    245             if (validationModel.stepNumber == 1) {
    246                 if (controllerModel.get('selectedNode') == null) {
    247                     validationView.model["text"] = 'Please select an experiment to continue!';
    248                     validationView.render();
    249                     validationModel.succeeded = false;
    250                 }
    251             }
    252             detailsView.render();
    253         });
    254 
    255         wizardController.listenTo(model, 'change', function () {
    256             // update the details view, when the model changes
    257             view.render();
    258             detailsView.render();
    259         });
    260 
    261         wizardController.listenTo(view, 'structure-changed', function (node) {
    262             view.render();
    263         });
    264 
    265         wizardController.listenTo(view, 'node-added', function (node) {
    266             // get details about the node
    267             //if (!node.get('isExperiment'))
    268             node.fetch({ success: function (itm) {
    269                 model.trigger('change', {});
    270             }
    271             });
    272         });
    273 
    274         wizardController.listenTo(wizard, 'experiment-finished', function () {
    275             generalController.experimentFinishedHandler(experimentModel, availableExperiments, selectableGroup);         
    276         });
    277 
    278         wizardController.listenTo(detailsView, 'node-clicked', function (node) {
    279             // get details about the node
    280             var modelNode = ExperimentNode.lookup(node.data.key);
    281             if (!modelNode.get('isExperiment')) {
    282                 parameterDialog.model = modelNode;
    283                 parameterDialog.render();
    284             }
    285         });
    286 
    287         wizardController.listenTo(view, 'variation-request', function (evt) {
    288             generalController.variationRequestHandler(evt);
    289         });
    290 
    291         wizardController.listenTo(parameterDialog, 'parameters-finished', function (node) {
    292             parameterDialog.close();
    293         });
    294295    }
    295 }
    296 
     296    return my;
     297} (OAAS_CONTROLLER || {}, Backbone, OAAS_VIEW, OAAS_MODEL, _, $));
    297298
    298299 
  • branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/experiment.model.js

    r9305 r9324  
    11//================== MODELS =====================
    2 var ControllerModel = Backbone.Model.extend({
    3   defaults: {
    4     selectedNode: null 
     2var OAAS_MODEL = (function (my, Backbone) {
     3    Backbone.Relational.store.addModelScope(my);
     4
     5    my.ControllerModel = Backbone.Model.extend({
     6        defaults: {
     7            selectedNode: null
     8        }
     9    });
     10
     11    my.Experiment = Backbone.RelationalModel.extend({
     12        url: function () {
     13            return '/Experiment/Experiment?nodeId=' + this.get('nodeId');
     14        },
     15        isNew: function () { return false; },
     16        defaults: {
     17            title: 'My Experiment',
     18            isExperiment: true,
     19            run: false,
     20            nodeId: null,
     21            repititions: 1,
     22            group: 'TESTAZURE'
     23        },
     24        relations: [{
     25            key: 'experiment',
     26            relatedModel: 'ExperimentNode'
     27        }]
     28    });
     29
     30    my.ExperimentNode = Backbone.RelationalModel.extend({
     31        defaults: {
     32            title: 'Experiment',
     33            key: -1,
     34            data: {},
     35            parent: null,
     36            isExperiment: false,
     37            nodeId: null
     38        },       
     39        relations: [{
     40            type: Backbone.HasMany,
     41            key: 'children',
     42            relatedModel: 'ExperimentNode',
     43            collectionType: 'AlgorithmList',
     44            reverseRelation: {
     45                key: 'parent'
     46            }
     47        }],
     48        url: function () {
     49            return this.get('isExperiment') ? '/Experiment/Experiment?nodeId=' + this.get('nodeId') : '/Experiment/Scenario?nodeId=' + this.get('nodeId');
     50        },
     51        initialize: function (spec) {
     52            if (typeof spec.key === 'undefined' || spec.key == -1) {
     53                spec.key = my.ExperimentNode.globalKeyCount;
     54                this.set({ key: spec.key });
     55                my.ExperimentNode.globalKeyCount++;
     56            }
     57            else if (spec.key >= my.ExperimentNode.globalKeyCount)
     58                my.ExperimentNode.globalKeyCount = spec.key + 1;
     59
     60            my.ExperimentNode.globalNodeMap[spec.key] = this;
     61        },
     62        // adds a new experimentNode to this node
     63        addNode: function (experimentNode) {
     64            if (!(experimentNode instanceof my.ExperimentNode)) {
     65                experimentNode = new my.ExperimentNode(experimentNode);
     66            }
     67            this.get('children').add(experimentNode);
     68            experimentNode.set({ parent: this });
     69            this.trigger('node-added', experimentNode);
     70            return experimentNode;
     71        },
     72        // moves an experimentNode into this node
     73        moveNode: function (experimentNode) {
     74            var parent = experimentNode.get('parent');
     75            if (parent != null) {
     76                // remove from parent
     77                parent.get('children').remove(experimentNode);
     78            }
     79            this.addNode(experimentNode);
     80        },
     81        // delete this node
     82        remove: function () {
     83            var parent = this.get('parent');
     84            if (parent != null) {
     85                parent.get('children').remove(this);
     86                this.set({ parent: null });
     87                // simply replace it with 'undefined'
     88                delete my.ExperimentNode.globalNodeMap[this.get('key')];
     89            }
     90        },
     91        lookup: function (key) {
     92            return my.ExperimentNode.globalNodeMap[key];
     93        }
     94    },
     95  {
     96      globalKeyCount: 0,
     97      globalNodeMap: {},
     98      lookup: function (key) {
     99          return my.ExperimentNode.globalNodeMap[key];
     100      },
     101      nextGlobalKey: function () {
     102          var key = my.ExperimentNode.globalKeyCount;
     103          my.ExperimentNode.globalKeyCount++;
     104          return key;
     105      }
    5106  }
    6 });
     107  );
    7108
    8 var Experiment = Backbone.RelationalModel.extend({   
    9   url: function () {
    10     return '/Experiment/Experiment?nodeId=' + this.get('nodeId');
    11   },
    12   defaults: {
    13     title: 'My Experiment',
    14     isExperiment: true,
    15     run: false,
    16     nodeId: null,
    17     repititions: 1,
    18     group: 'TESTAZURE'
    19   },
    20   isNew: function() { return this.get('nodeId') == null; },
    21   relations: [{
    22     key: 'experiment',
    23     relatedModel: 'ExperimentNode'
    24   }]
    25 });
     109    my.ExperimentList = Backbone.Collection.extend({
     110        url: function () {
     111            return "/Experiment/ExperimentList";
     112        },
     113        model: my.Experiment
     114    });
    26115
    27 var ExperimentNode = Backbone.RelationalModel.extend({
    28     defaults: {
    29         title: 'Experiment',
    30         key: -1,
    31         data: {},
    32         parent: null,
    33         isExperiment: false,
    34         nodeId: null
    35     },
    36     relations: [{
    37         type: Backbone.HasMany,
    38         key: 'children',
    39         relatedModel: 'ExperimentNode',
    40         collectionType: 'ScenarioList',
    41         reverseRelation: {
    42             key: 'parent'
    43         }
    44     }],
    45     url: function () {
    46         return this.get('isExperiment') ? '/Experiment/Experiment?nodeId=' + this.get('nodeId') : '/Experiment/Scenario?nodeId=' + this.get('nodeId');
    47     },
    48     initialize: function (spec) {
    49         if (typeof spec.key === 'undefined' || spec.key == -1) {
    50             spec.key = ExperimentNode.globalKeyCount;
    51             this.set({ key: spec.key });
    52             ExperimentNode.globalKeyCount++;
    53         }
    54         else if (spec.key >= ExperimentNode.globalKeyCount)
    55             ExperimentNode.globalKeyCount = spec.key + 1;
     116    my.AlgorithmList = Backbone.Collection.extend({
     117        url: function () {
     118            return "/Experiment/AlgorithmList";
     119        },
     120        model: my.ExperimentNode
     121    });
    56122
    57         ExperimentNode.globalNodeMap[spec.key] = this;
    58     },
    59     // adds a new experimentNode to this node
    60     addNode: function (experimentNode) {
    61         if (!(experimentNode instanceof ExperimentNode)) {
    62             experimentNode = new ExperimentNode(experimentNode);
    63         }
    64         this.get('children').add(experimentNode);
    65         experimentNode.set({ parent: this });
    66         this.trigger('node-added', experimentNode);
    67         return experimentNode;
    68     },
    69     // moves an experimentNode into this node
    70     moveNode: function (experimentNode) {
    71         var parent = experimentNode.get('parent');
    72         if (parent != null) {
    73             // remove from parent
    74             parent.get('children').remove(experimentNode);
    75         }
    76         this.addNode(experimentNode);
    77     },
    78     // delete this node
    79     remove: function () {
    80         var parent = this.get('parent');
    81         if (parent != null) {
    82             parent.get('children').remove(this);
    83             this.set({ parent: null });
    84             // simply replace it with 'undefined'
    85             delete ExperimentNode.globalNodeMap[this.get('key')];
    86         }
    87         this.trigger('node-removed', this);
    88     },
    89     lookup: function (key) {
    90         return ExperimentNode.globalNodeMap[key];
    91     }
    92 },
    93 {
    94     globalKeyCount: 0,
    95     globalNodeMap: {},
    96     lookup: function (key) {
    97         return ExperimentNode.globalNodeMap[key];
    98     },
    99     nextGlobalKey: function () {
    100         var key = ExperimentNode.globalKeyCount;
    101         ExperimentNode.globalKeyCount++;
    102         return key;
    103     }
    104 }
    105 );
    106 
    107 var ExperimentList = Backbone.Collection.extend({
    108   url: function () {
    109     return "/Experiment/ExperimentList";
    110   },
    111   model: Experiment
    112 });
    113 
    114 var ScenarioList = Backbone.Collection.extend({
    115   url: function () {
    116     return "/Experiment/ScenarioList";
    117   },
    118   model: ExperimentNode
    119 });
     123    my.ScenarioList = Backbone.Collection.extend({
     124        url: function () {
     125            return "/Experiment/ScenarioList";
     126        },
     127        model: my.ExperimentNode
     128    });
     129    return my;
     130} (OAAS_MODEL || {}, Backbone));
  • branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/experiment.view.js

    r9305 r9324  
    1 // ================ VIEWS =======================
    2 var ExperimentTreeView = Backbone.View.extend({
    3     renderTree: function (model) {
    4         var jsonModel = model.toJSON();
    5         var self = this;
    6         this.tree = $('<div />').dynatree({
    7             children: [jsonModel],
    8             autoExpandMS: 750,
    9             onActivate: function (node) {
    10                 // if we are able to remove this node from the tree, enable the remove button.
    11                 if (node && node.parent.parent != null) {
    12                     $('.remove-button', this.$el).removeAttr("disabled");
    13                 } else if (node) {
    14                     $('.remove-button', this.$el).attr("disabled", "disabled");
    15                 }
    16 
    17                 var modelNode = ExperimentNode.lookup(node.data.key);
    18                 if (modelNode && !modelNode.get('isExperiment')) {
    19                     $('.variate-button', this.$el).removeAttr("disabled");
    20                 } else {
    21                     $('.variate-button', this.$el).attr("disabled", "disabled");
    22                 }
    23             },
    24             dnd: {
    25                 onDragStart: function (node) {
    26                     return node.parent.parent != null;
     1var OAAS_VIEW = (function (my, Backbone, _, $, OAAS_MODEL) {
     2    // ================ VIEWS =======================
     3    my.ExperimentTreeView = Backbone.View.extend({
     4        renderTree: function (model) {
     5            var jsonModel = model.toJSON();
     6            var self = this;
     7            this.tree = $('<div />').dynatree({
     8                children: [jsonModel],
     9                autoExpandMS: 750,
     10                onActivate: function (node) {
     11                    // if we are able to remove this node from the tree, enable the remove button.
     12                    if (node && node.parent.parent != null) {
     13                        $('.remove-button', this.$el).removeAttr("disabled");
     14                    } else if (node) {
     15                        $('.remove-button', this.$el).attr("disabled", "disabled");
     16                    }
     17
     18                    var modelNode = OAAS_MODEL.ExperimentNode.lookup(node.data.key);
     19                    if (modelNode && !modelNode.get('isExperiment')) {
     20                        $('.variate-button', this.$el).removeAttr("disabled");
     21                    } else {
     22                        $('.variate-button', this.$el).attr("disabled", "disabled");
     23                    }
    2724                },
    28                 onDragEnter: function (node, sourceNode) {
    29                     return true;
     25                dnd: {
     26                    onDragStart: function (node) {
     27                        return node.parent.parent != null;
     28                    },
     29                    onDragEnter: function (node, sourceNode) {
     30                        return true;
     31                    },
     32                    onDragOver: function (node, sourceNode, hitMode) {
     33                        return node.data.title !== "Experiment" || hitMode === "over";
     34                    },
     35                    onDrop: function (node, sourceNode, hitMode, ui, draggable) {
     36                        if (hitMode !== 'over')
     37                            return;
     38                        var modelNode = OAAS_MODEL.ExperimentNode.lookup(node.data.key);
     39                        if (sourceNode) {
     40                            var sourceModelNode = OAAS_MODEL.ExperimentNode.lookup(sourceNode.data.key);
     41                            sourceNode.move(node, hitMode);
     42                            // move node into the modelNode
     43                            sourceModelNode.moveNode(modelNode);
     44                        }
     45                        else {
     46                            var elem = $(draggable.element[0]);
     47                            var newNode = { nodeId: elem.attr('id'), isExperiment: elem.attr('data-isExperiment') === 'true', title: elem.attr('data-name'), key: OAAS_MODEL.ExperimentNode.nextGlobalKey() };
     48                            if (hitMode == "over") {
     49                                node.addChild(newNode);
     50                                node.expand(true);
     51                                // update the data model
     52                                newNode = modelNode.addNode(newNode);
     53                                self.trigger('node-added', newNode);
     54                            }
     55                        }
     56                        self.trigger('structure-changed', modelNode);
     57                    }
     58                }
     59            });
     60            this.tree.dynatree("getRoot").visit(function (node) {
     61                node.expand(true);
     62            });
     63        },
     64        initialize: function (spec) {
     65            this.renderTree(spec.model);
     66        },
     67        events: {
     68            'click .remove-button': 'doRemove',
     69            'click .variate-button': 'doVariate'
     70        },
     71        render: function () {
     72            this.$el.empty();
     73            this.renderTree(this.model);
     74            var content = $(_.template($('#stepwizard_template').html(), {}));
     75            this.tree.appendTo(this.$el);
     76            content.appendTo(this.$el);
     77        },
     78        doRemove: function () {
     79            var node = this.tree.dynatree('getActiveNode');
     80            if (node && node.parent.parent != null) {
     81                var nxt = node.getNextSibling();
     82                if (nxt == null)
     83                    nxt = node.getPrevSibling();
     84                if (nxt == null)
     85                    nxt = node.getParent();
     86                node.remove();
     87                OAAS_MODEL.ExperimentNode.lookup(node.data.key).remove();
     88                if (nxt) {
     89                    this.tree.dynatree("getTree").activateKey(nxt.data.key);
     90                }
     91            }
     92            this.trigger('structure-changed', node);
     93        },
     94        doVariate: function () {
     95            var node = this.tree.dynatree('getActiveNode');
     96            var modelNode = OAAS_MODEL.ExperimentNode.lookup(node.data.key);
     97            this.trigger('variation-request', {
     98                parentNode: node.parent,
     99                model: modelNode
     100            });
     101        }
     102    });
     103
     104    my.ExperimentDetailsTreeView = Backbone.View.extend({
     105        render: function () {
     106            var jsonModel = this.model.toJSON();
     107            var self = this;
     108            var tree = $('<div />').dynatree({
     109                children: [jsonModel],
     110                autoExpandMS: 750,
     111                onActivate: function (node) {
     112                    // if we click a node, simply open a dialog to enter it's parameters
     113                    self.trigger('node-clicked', node);
     114                }
     115            });
     116
     117            this.$el.empty();
     118            tree.appendTo(this.$el);
     119            tree.dynatree("getRoot").visit(function (node) {
     120                node.expand(true);
     121            });
     122        }
     123    });
     124
     125    my.DraggableGroup = Backbone.View.extend({
     126        initialize: function () {
     127            this.collection.bind('remove', this.render, this);
     128            this.collection.bind('add', this.render, this);
     129        },
     130        render: function () {
     131            var self = this;
     132            var div = $('<div />');
     133            if (this.collection.length == 0) {
     134                $('<p></p>').text("No items found!").appendTo(div);
     135            }
     136            for (var i = 0; i < this.collection.length; i++) {
     137                new my.DraggableView({ model: this.collection.models[i], el: div }).render();
     138            }
     139
     140            this.$el.empty();
     141            div.appendTo(this.$el);
     142        }
     143    });
     144
     145
     146    my.DraggableView = Backbone.View.extend({
     147        render: function () {
     148            var late = _.template($("#draggable_template").html(), this.model.attributes);
     149            $(late).draggable({
     150                revert: true,
     151                connectToDynatree: true,
     152                cursorAt: { top: -5, left: -5 },
     153                helper: "clone"
     154            }).appendTo(this.$el);
     155        }
     156    });
     157
     158    my.SelectableGroup = Backbone.View.extend({
     159        initialize: function () {
     160            this.collection.bind('remove', this.render, this);
     161            this.collection.bind('add', this.render, this);
     162            this.collection.bind('change', this.render, this);
     163        },
     164        render: function () {
     165            var self = this;
     166            var div = $('<div />');
     167            if (this.collection.length == 0) {
     168                $('<p></p>').text("No experiments found!").appendTo(div);
     169            }
     170
     171            for (var i = 0; i < this.collection.length; i++) {
     172                new my.SelectableView({ model: this.collection.models[i], el: div }).render();
     173            }
     174            this.$el.empty();
     175            div.selectable({
     176                filter: 'div',
     177                selected: function (event, ui) {
     178                    self.selected(event, ui);
     179                }
     180            }).appendTo(this.$el);
     181        },
     182        selected: function (event, ui) {
     183            var nodeId = $(ui.selected).attr('id');
     184            this.trigger('node-selected', nodeId);
     185        }
     186    });
     187
     188    my.SelectableView = Backbone.View.extend({
     189        render: function () {
     190            var late = _.template($("#draggable_template").html(), this.model.attributes);
     191            $(late).appendTo(this.$el);
     192        }
     193    });
     194
     195    my.StepWizardView = Backbone.View.extend({
     196        render: function () {
     197            var self = this;
     198            this.$el.smartWizard({
     199                onLeaveStep: function (step) {
     200                    var stepNum = parseInt(step.attr("rel"));
     201                    return self.validateStep(stepNum);
    30202                },
    31                 onDragOver: function (node, sourceNode, hitMode) {
    32                     return node.data.title !== "Experiment" || hitMode === "over";
     203                onShowStep: function (step) {
     204                    var stepNum = parseInt(step.attr("rel"));
     205                    return self.showStep(stepNum);
    33206                },
    34                 onDrop: function (node, sourceNode, hitMode, ui, draggable) {
    35                     if (hitMode !== 'over')
    36                         return;
    37                     var modelNode = ExperimentNode.lookup(node.data.key);
    38                     if (sourceNode) {
    39                         var sourceModelNode = ExperimentNode.lookup(sourceNode.data.key);
    40                         sourceNode.move(node, hitMode);
    41                         // move node into the modelNode
    42                         sourceModelNode.moveNode(modelNode);
    43                     }
    44                     else {
    45                         var elem = $(draggable.element[0]);
    46                         var newNode = { nodeId: elem.attr('id'), isExperiment: elem.attr('data-isExperiment') === 'true', title: elem.attr('data-name'), key: ExperimentNode.nextGlobalKey() };
    47                         if (hitMode == "over") {
    48                             node.addChild(newNode);
    49                             node.expand(true);
    50                             // update the data model
    51                             newNode = modelNode.addNode(newNode);
    52                             self.trigger('node-added', newNode);
    53                         }
    54                     }
    55                     self.trigger('structure-changed', modelNode);
    56                 }
    57             }
    58         });
    59         this.tree.dynatree("getRoot").visit(function (node) {
    60             node.expand(true);
    61         });
    62     },
    63     initialize: function (spec) {
    64         this.renderTree(spec.model);
    65     },
    66     events: {
    67         'click .remove-button': 'doRemove',
    68         'click .variate-button': 'doVariate'
    69     },
    70     render: function () {
    71         this.$el.empty();
    72         this.renderTree(this.model);
    73         var content = $(_.template($('#stepwizard_template').html(), {}));
    74         this.tree.appendTo(this.$el);
    75         content.appendTo(this.$el);
    76     },
    77     doRemove: function () {
    78         var node = this.tree.dynatree('getActiveNode');
    79         if (node && node.parent.parent != null) {
    80             var nxt = node.getNextSibling();
    81             if (nxt == null)
    82                 nxt = node.getPrevSibling();
    83             if (nxt == null)
    84                 nxt = node.getParent();
    85             node.remove();
    86             ExperimentNode.lookup(node.data.key).remove();
    87             if (nxt) {
    88                 this.tree.dynatree("getTree").activateKey(nxt.data.key);
    89             }
    90         }
    91         this.trigger('structure-changed', node);
    92     },
    93     doVariate: function () {
    94         var node = this.tree.dynatree('getActiveNode');
    95         var modelNode = ExperimentNode.lookup(node.data.key);
    96         this.trigger('variation-request', {
    97             parentNode: node.parent,
    98             model: modelNode
    99         });
    100     }
    101 });
    102 
    103 var ExperimentDetailsTreeView = Backbone.View.extend({
    104   render: function () {
    105     var jsonModel = this.model.toJSON();
    106     var self = this;
    107     var tree = $('<div />').dynatree({
    108       children: [jsonModel],
    109       autoExpandMS: 750,
    110       onActivate: function (node) {
    111         // if we click a node, simply open a dialog to enter it's parameters
    112         self.trigger('node-clicked', node);
    113       }
    114     });
    115 
    116     this.$el.empty();
    117     tree.appendTo(this.$el);
    118     tree.dynatree("getRoot").visit(function (node) {
    119         node.expand(true);
    120     });
    121   }
    122 });
    123 
    124 var DraggableGroup = Backbone.View.extend({
    125     render: function () {
    126         var self = this;
    127         var div = $('<div />');
    128 
    129         for (var i = 0; i < this.model.length; i++) {
    130             new DraggableView({ model: this.model.models[i], el: div }).render();
    131         }
    132 
    133         this.$el.empty();
    134         div.appendTo(this.$el);
    135     }
    136 });
    137 
    138 
    139 var DraggableView = Backbone.View.extend({
    140   render: function () {
    141     var late = _.template($("#draggable_template").html(), this.model.attributes);   
    142     $(late).draggable({
    143       revert: true,
    144       connectToDynatree: true,
    145       cursorAt: { top: -5, left: -5 },
    146       helper: "clone"
    147     }).appendTo(this.$el);
    148   }
    149 });
    150 
    151 var SelectableGroup = Backbone.View.extend({
    152     render: function () {
    153         var self = this;
    154         var div = $('<div />');
    155         for (var i = 0; i < this.model.length; i++) {
    156             new SelectableView({ model: this.model.models[i], el: div }).render();
    157         }
    158         this.$el.empty();
    159         div.selectable({
    160             filter: 'div',
    161             selected: function (event, ui) {
    162                 self.selected(event, ui);
    163             }
    164         }).appendTo(this.$el);
    165     },
    166     selected: function (event, ui) {
    167         var nodeId = $(ui.selected).attr('id');
    168         this.trigger('node-selected', nodeId);
    169     }
    170 });
    171 
    172 var SelectableView = Backbone.View.extend({
    173     render: function () {
    174         var late = _.template($("#draggable_template").html(), this.model.attributes);
    175         $(late).appendTo(this.$el);
    176     }
    177 });
    178 
    179 var StepWizardView = Backbone.View.extend({
    180     render: function () {
    181         var self = this;
    182         this.$el.smartWizard({
    183             onLeaveStep: function (step) {
    184                 var stepNum = parseInt(step.attr("rel"));
    185                 return self.validateStep(stepNum);
    186             },
    187             onShowStep: function (step) {
    188                 var stepNum = parseInt(step.attr("rel"));
    189                 return self.showStep(stepNum);
    190             },
    191             onFinish: function () {
    192                 self.trigger('experiment-finished');
    193             }
    194         });
    195     },
    196     validateStep: function (stepNumber) {
    197         var validationModel = {
    198             stepNumber: stepNumber,
    199             succeeded: true
    200         };
    201         this.trigger('step-validated', validationModel);
    202         return validationModel.succeeded;
    203     },
    204     showStep: function (stepNumber) {
    205         this.trigger('step-shown', stepNumber);
    206         return true;
    207     }
    208 });
    209 
    210 var ParameterWizard = Backbone.View.extend({
    211   createWizard: function (steps) {
    212     // use template instead of jquery?!
    213     var newWizard = $('<div />').addClass('wizard swMain');
    214     var stepMenu = $('<ul />');
    215     var prefix = name + '_';
    216     for (var i = 0; i < steps.length; i++) {
    217       var step = steps[i];
    218       var a = $('<a></a>', { href: '#' + prefix + (i + 1) });
    219       $('<label />').addClass("stepNumber").text((i + 1)).appendTo(a);
    220       $('<span />').addClass("stepDesc").html(step.heading + '<br /><small>' + step.description + '</small>').appendTo(a);
    221       var li = $('<li />').append(a);
    222       li.appendTo(stepMenu);
    223     }
    224     stepMenu.appendTo(newWizard);
    225     for (var i = 0; i < steps.length; i++) {
    226       var div = $('<div />', { id: prefix + (i + 1) });
    227       if (steps[i].content && steps[i].content != null)
    228         div.append(steps[i].content);
    229       div.appendTo(newWizard);
    230     }
    231     return newWizard;
    232   },
    233   render: function () {
    234     var self = this;
    235     this.$el.empty();
    236     var data = this.model.get('data');
    237 
    238     var hasProblemParameters = typeof data.ProblemParameters !== 'undefined';
    239     var dialog = $('<div />');
    240     var algoDiv = $('<div />');
    241     var problemDiv = $('<div />');
    242 
    243     for (var i = 0; i < data.AlgorithmParameters.length; i++) {
    244       var parameterView = new ParameterEditableView({ model: data.AlgorithmParameters[i] });
    245       // render to dialog
    246       parameterView.render();
    247       parameterView.$el.appendTo(algoDiv);
    248     }
    249 
    250     if (hasProblemParameters) {
    251       var problemParameters = data.ProblemParameters;
    252       for (var i = 0; i < problemParameters.length; i++) {
    253         var parameterView = new ParameterEditableView({ model: problemParameters[i] });
    254         // render to dialog
    255         parameterView.render();
    256         parameterView.$el.appendTo(problemDiv);
    257       }
    258     }
    259 
    260     var newWizard =
    261         hasProblemParameters ?
    262           this.createWizard([
    263             { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoDiv },
    264             { heading: "Problem Parameters", description: "Adjust problem parameters", content: problemDiv }
    265           ]) :
    266           this.createWizard([
    267             { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoDiv }
    268           ]);
    269 
    270     newWizard.appendTo(this.$el);
    271     newWizard.smartWizard({
    272       onFinish: function () {
    273         self.trigger('parameters-finished');
    274       }
    275     });
    276   }
    277 });
    278 
    279 var ParameterEditableView = Backbone.View.extend({
    280     events: {
     207                onFinish: function () {
     208                    self.trigger('experiment-finished');
     209                }
     210            });
     211        },
     212        validateStep: function (stepNumber) {
     213            var validationModel = {
     214                stepNumber: stepNumber,
     215                succeeded: true
     216            };
     217            this.trigger('step-validated', validationModel);
     218            return validationModel.succeeded;
     219        },
     220        showStep: function (stepNumber) {
     221            this.trigger('step-shown', stepNumber);
     222            return true;
     223        }
     224    });
     225
     226    my.ParameterWizard = Backbone.View.extend({
     227        createWizard: function (steps) {
     228            // use template instead of jquery?!
     229            var newWizard = $('<div />').addClass('wizard swMain');
     230            var stepMenu = $('<ul />');
     231            var prefix = name + '_';
     232            for (var i = 0; i < steps.length; i++) {
     233                var step = steps[i];
     234                var a = $('<a></a>', { href: '#' + prefix + (i + 1) });
     235                $('<label />').addClass("stepNumber").text((i + 1)).appendTo(a);
     236                $('<span />').addClass("stepDesc").html(step.heading + '<br /><small>' + step.description + '</small>').appendTo(a);
     237                var li = $('<li />').append(a);
     238                li.appendTo(stepMenu);
     239            }
     240            stepMenu.appendTo(newWizard);
     241            for (var i = 0; i < steps.length; i++) {
     242                var div = $('<div />', { id: prefix + (i + 1) });
     243                if (steps[i].content && steps[i].content != null)
     244                    div.append(steps[i].content);
     245                div.appendTo(newWizard);
     246            }
     247            return newWizard;
     248        },
     249        render: function () {
     250            var self = this;
     251            this.$el.empty();
     252            var data = this.model.get('data');
     253
     254            var hasProblemParameters = typeof data.ProblemParameters !== 'undefined';
     255            var dialog = $('<div />');
     256            var algoDiv = $('<div />');
     257            var problemDiv = $('<div />');
     258
     259            for (var i = 0; i < data.AlgorithmParameters.length; i++) {
     260                var parameterView = new my.ParameterEditableView({ model: data.AlgorithmParameters[i] });
     261                // render to dialog
     262                parameterView.render();
     263                parameterView.$el.appendTo(algoDiv);
     264            }
     265
     266            if (hasProblemParameters) {
     267                var problemParameters = data.ProblemParameters;
     268                for (var i = 0; i < problemParameters.length; i++) {
     269                    var parameterView = new my.ParameterEditableView({ model: problemParameters[i] });
     270                    // render to dialog
     271                    parameterView.render();
     272                    parameterView.$el.appendTo(problemDiv);
     273                }
     274            }
     275
     276            var newWizard =
     277          hasProblemParameters ?
     278            this.createWizard([
     279              { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoDiv },
     280              { heading: "Problem Parameters", description: "Adjust problem parameters", content: problemDiv }
     281            ]) :
     282            this.createWizard([
     283              { heading: "Algorithm Parameters", description: "Adjust algorithm parameters", content: algoDiv }
     284            ]);
     285
     286            newWizard.appendTo(this.$el);
     287            newWizard.smartWizard({
     288                onFinish: function () {
     289                    self.trigger('parameters-finished');
     290                }
     291            });
     292        }
     293    });
     294
     295    my.ParameterEditableView = Backbone.View.extend({
     296        /*events: {
    281297        'change': 'valueChanged'
    282     },
    283     render: function () {
    284         var mapper = new DatatypeMapper();
    285         var content = $(_.template($('#parameter_template').html(), this.model));
    286         mapper.mapHtml(this.model).appendTo($('.rightEntry', content));
    287         content.appendTo(this.$el);
    288     },
    289     valueChanged: function (param) {
    290         var value = $(param.target).val();
    291         if (!isNaN(value))
    292             value = parseFloat(value);
    293         var name = $(param.target).attr("name");
    294         // normally a controller would do this, just for once, let the view update the model
    295         var splitted = name.split("_");
    296         if (splitted.length == 1) {
    297             this.model.Value = value;
    298         } else if (splitted.length == 2) {
    299             this.model.Value[parseInt(splitted[1])] = value;
    300         } else if (splitted.length == 3) {
    301             this.model.Value[parseInt(splitted[1])][parseInt(splitted[2])] = value;
    302         }
    303     }
    304 });
    305 
    306 
    307 var LoadingDialog = Backbone.View.extend({
    308     initialize: function () {
    309         this.reset();
    310     },
    311     render: function () {
    312         var self = this;
    313         this.$el.empty();
    314         var dialog = $('<div />');
    315         this.content.appendTo(dialog);
    316         dialog.appendTo(this.$el);
    317         this.$el.dialog({
    318             autoOpen: true
    319         });
    320     },
    321     text: function (txt) {
    322         $('p', this.$el).text(txt);
    323     },
    324     setLoading: function(isLoading) {
    325       if (isLoading)
    326         $('img', this.$el).show();
    327       else
    328         $('img', this.$el).hide();
    329     },
    330     reset: function () {
    331         this.content = $(_.template($('#loading_template').html(), {}));
    332     },
    333     setContent: function (el) {
    334         this.content = el;
    335     },
    336     close: function () {
    337         this.$el.dialog("close");
    338     }
    339 });
    340 
    341 
    342 var ParameterDialog = Backbone.View.extend({
    343   render: function () {
    344     var self = this;
    345 
    346     this.$el.empty();
    347     var data = this.model.get('data');
    348 
    349     var hasProblemParameters = typeof data.ProblemParameters !== 'undefined';
    350     var dialog = $('<div />');
    351 
    352     var parameterWizard = new ParameterWizard({ model: this.model, el: dialog });
    353     parameterWizard.render();
    354     this.listenTo(parameterWizard, 'parameters-finished', function () {
    355       self.trigger('parameters-finished');
    356     });
    357     dialog.appendTo(this.$el);
    358     this.$el.dialog({
    359       autoOpen: true,
    360       width: 1024,
    361       height: 768
    362     });
    363   },
    364   close: function () {
    365     this.$el.dialog("close");
    366   }
    367 });
    368 
    369 var ExperimentDetailsView = Backbone.View.extend({
    370     events: {
    371         'change': 'valueChanged'
    372     },
    373     valueChanged: function (param) {
    374         var value = $(param.target).val();
    375         if (!isNaN(value))
    376             value = parseFloat(value);
    377         var name = $(param.target).attr("name");
    378         if (name == 'Name')
    379             this.model.set({ title: value });
    380         else if (name == 'RunImmediately')
    381             this.model.set({ run: $(param.target).is(':checked') });
    382         else if (name == 'Repititions')
    383             this.model.set({ repititions: value });
    384         else if (name == 'Group')
    385             this.model.set({ group: value });
    386 
    387         if (this.model.get('run')) {
    388             $('input[name="Repititions"]', this.$el).removeAttr('disabled');
    389             $('input[name="Group"]', this.$el).removeAttr('disabled');
    390         } else {
    391             $('input[name="Repititions"]', this.$el).attr('disabled', 'disabled');
    392             $('input[name="Group"]', this.$el).attr('disabled', 'disabled');
    393         }
    394     },
    395     render: function () {
    396         $('input[name="Name"]', this.$el).val(this.model.get('title'));
    397         $('input[name="RunImmediately"]', this.$el).attr('checked', this.model.get('run'));
    398         $('input[name="Repititions"]', this.$el).val(this.model.get('repititions'));
    399         $('input[name="Group"]', this.$el).val(this.model.get('group'));
    400     }
    401 });
    402 
    403 var ValidationHintsView = Backbone.View.extend({
    404     render: function () {
    405         var template = _.template($('#validationhints_template').html(), this.model);
    406         $(template).dialog({
    407             resizable: false,
    408             modal: true,
    409             buttons: {
    410                 "OK": function () {
    411                     $(this).dialog("close");
    412                 }
    413             }
    414         });
    415     }
    416 });
    417 
    418 // ========== Variation Dialog Views ============
    419 
    420 var VariationDialog = Backbone.View.extend({
    421     initialize: function (spec) {
    422 
    423     },
    424     events: {
    425         'change': 'entrySelected'
    426     },
    427     render: function () {
    428         var self = this;
    429         var dialog = $(_.template($('#variationdialog_template').html(), {}));
    430 
    431         var content = $('select[class="variationDialogContent"]', dialog);
    432         var data = this.model.get('data');
    433         for (var i = 0; i < data.AlgorithmParameters.length; i++) {
    434             data.AlgorithmParameters[i].Index = i;
    435             var entry = new VariationEntryView({ model: data.AlgorithmParameters[i], el: content });
    436             entry.render();
    437         }
    438 
    439         this.details = $('div[class="variationDetails"]', dialog);
    440         this.activateButton = $('input[name="active"]', dialog);
    441         this.activateButton.change(function (evt) {
    442             var checked = $(evt.target).is(':checked');
    443             if (self.selectedModel && self.selectedModel != null) {
    444                 self.selectedModel.Active = checked;
    445             }
    446         });
    447         dialog.dialog({
    448             height: 300,
    449             buttons: {
    450                 "Abort": function () {
    451                     $(this).dialog("close");
    452                 },
    453                 "OK": function () {
    454                     self.generateVariations();
    455                     $(this).dialog("close");
    456                 }
    457             }
    458         });
    459 
    460         content.change(function (evt) {
    461             var optionSelected = $("option:selected", this);
    462             var model = self.model.get('data').AlgorithmParameters[parseInt($(optionSelected).attr('data-index'))]
    463             self.entrySelected(model);
    464         });
    465 
    466         this.variationDetails = new VariationContentView({ el: this.details });
    467         var model = this.model.get('data').AlgorithmParameters[0];
    468         this.entrySelected(model);
    469     },
    470     entrySelected: function (model) {
    471         this.selectedModel = model;
    472         if (model.Active)
    473             this.activateButton.attr('checked', 'checked');
    474         else
    475             this.activateButton.removeAttr('checked');
    476         this.variationDetails.model = model;
    477         this.details.empty();
    478         this.variationDetails.render();
    479     },
    480     generateVariations: function () {
    481         this.solutions = [];
    482         this.exhaust(0, []);
    483         this.trigger('variations-generated', this.solutions);
    484     },
    485     exhaust: function (index, element) {
    486         if (index == this.model.get('data').AlgorithmParameters.length) {
    487             // we found a solution! store it by creating a deep copy
    488             this.solutions.push($.extend(true, [], element));
    489             return;
    490         }
    491 
    492         var currentParameter = this.model.get('data').AlgorithmParameters[index];
    493         if (currentParameter.Active && currentParameter.Generated) {
    494             for (var i = 0; i < currentParameter.Generated.length; i++) {
     298        },*/
     299        render: function () {
     300            var mapper = new my.DatatypeMapper();
     301            var content = $(_.template($('#parameter_template').html(), this.model));
     302            mapper.mapHtml(this.model, $('.rightEntry', content));
     303            content.appendTo(this.$el);
     304        } /*,
     305        valueChanged: function (param) {
     306            var value = $(param.target).val();
     307            if (!isNaN(value))
     308                value = parseFloat(value);
     309            var name = $(param.target).attr("name");
     310            // normally a controller would do this, just for once, let the view update the model
     311            var splitted = name.split("_");
     312            if (splitted.length == 1) {
     313                this.model.Value = value;
     314            } else if (splitted.length == 2) {
     315                this.model.Value[parseInt(splitted[1])] = value;
     316            } else if (splitted.length == 3) {
     317                this.model.Value[parseInt(splitted[1])][parseInt(splitted[2])] = value;
     318            }
     319        }*/
     320    });
     321
     322
     323    my.LoadingDialog = Backbone.View.extend({
     324        initialize: function () {
     325            this.reset();
     326        },
     327        render: function () {
     328            var self = this;
     329            this.$el.empty();
     330            var dialog = $('<div />');
     331            this.content.appendTo(dialog);
     332            dialog.appendTo(this.$el);
     333            this.$el.dialog({
     334                autoOpen: true
     335            });
     336        },
     337        text: function (txt) {
     338            $('p', this.$el).text(txt);
     339        },
     340        setLoading: function (isLoading) {
     341            if (isLoading)
     342                $('img', this.$el).show();
     343            else
     344                $('img', this.$el).hide();
     345        },
     346        reset: function () {
     347            this.content = $(_.template($('#loading_template').html(), {}));
     348        },
     349        setContent: function (el) {
     350            this.content = el;
     351        },
     352        close: function () {
     353            this.$el.dialog("close");
     354        }
     355    });
     356
     357
     358    my.ParameterDialog = Backbone.View.extend({
     359        render: function () {
     360            var self = this;
     361
     362            this.$el.empty();
     363            var data = this.model.get('data');
     364
     365            var hasProblemParameters = typeof data.ProblemParameters !== 'undefined';
     366            var dialog = $('<div />');
     367
     368            var parameterWizard = new my.ParameterWizard({ model: this.model, el: dialog });
     369            parameterWizard.render();
     370            this.listenTo(parameterWizard, 'parameters-finished', function () {
     371                self.trigger('parameters-finished');
     372            });
     373            dialog.appendTo(this.$el);
     374            this.$el.dialog({
     375                autoOpen: true,
     376                width: 1024,
     377                height: 768
     378            });
     379        },
     380        close: function () {
     381            this.$el.dialog("close");
     382        }
     383    });
     384
     385    my.ExperimentDetailsView = Backbone.View.extend({
     386        events: {
     387            'change': 'valueChanged'
     388        },
     389        valueChanged: function (param) {
     390            var value = $(param.target).val();
     391            if (!isNaN(value))
     392                value = parseFloat(value);
     393            var name = $(param.target).attr("name");
     394            if (name == 'Name')
     395                this.model.set({ title: value });
     396            else if (name == 'RunImmediately')
     397                this.model.set({ run: $(param.target).is(':checked') });
     398            else if (name == 'Repititions')
     399                this.model.set({ repititions: value });
     400            else if (name == 'Group')
     401                this.model.set({ group: value });
     402
     403            if (this.model.get('run')) {
     404                $('input[name="Repititions"]', this.$el).removeAttr('disabled');
     405                $('input[name="Group"]', this.$el).removeAttr('disabled');
     406            } else {
     407                $('input[name="Repititions"]', this.$el).attr('disabled', 'disabled');
     408                $('input[name="Group"]', this.$el).attr('disabled', 'disabled');
     409            }
     410        },
     411        render: function () {
     412            $('input[name="Name"]', this.$el).val(this.model.get('title'));
     413            $('input[name="RunImmediately"]', this.$el).attr('checked', this.model.get('run'));
     414            $('input[name="Repititions"]', this.$el).val(this.model.get('repititions'));
     415            $('input[name="Group"]', this.$el).val(this.model.get('group'));
     416        }
     417    });
     418
     419    my.ValidationHintsView = Backbone.View.extend({
     420        render: function () {
     421            var template = _.template($('#validationhints_template').html(), this.model);
     422            $(template).dialog({
     423                resizable: false,
     424                modal: true,
     425                buttons: {
     426                    "OK": function () {
     427                        $(this).dialog("close");
     428                    }
     429                }
     430            });
     431        }
     432    });
     433
     434    // ========== Variation Dialog Views ============
     435
     436    my.VariationDialog = Backbone.View.extend({
     437        initialize: function (spec) {
     438
     439        },
     440        events: {
     441            'change': 'entrySelected'
     442        },
     443        render: function () {
     444            var self = this;
     445            var dialog = $(_.template($('#variationdialog_template').html(), {}));
     446
     447            var content = $('select[class="variationDialogContent"]', dialog);
     448            var data = this.model.get('data');
     449            for (var i = 0; i < data.AlgorithmParameters.length; i++) {
     450                data.AlgorithmParameters[i].Index = i;
     451                var entry = new my.VariationEntryView({ model: data.AlgorithmParameters[i], el: content });
     452                entry.render();
     453            }
     454
     455            this.details = $('div[class="variationDetails"]', dialog);
     456            this.activateButton = $('input[name="active"]', dialog);
     457            this.activateButton.change(function (evt) {
     458                var checked = $(evt.target).is(':checked');
     459                if (self.selectedModel && self.selectedModel != null) {
     460                    self.selectedModel.Active = checked;
     461                }
     462
     463                if (self.selectedModel.Active) {
     464                    $('*', self.details).removeAttr('disabled');
     465                }
     466                else {
     467                    //$('input,button,select', self.details).attr('disabled', 'disabled');
     468                    $('*', self.details).attr('disabled', 'disabled');
     469                }
     470            });
     471            dialog.dialog({
     472                height: 300,
     473                buttons: {
     474                    "Abort": function () {
     475                        $(this).dialog("close");
     476                    },
     477                    "OK": function () {
     478                        self.generateVariations();
     479                        $(this).dialog("close");
     480                    }
     481                }
     482            });
     483
     484            content.change(function (evt) {
     485                var optionSelected = $("option:selected", this);
     486                var model = self.model.get('data').AlgorithmParameters[parseInt($(optionSelected).attr('data-index'))]
     487                self.entrySelected(model);
     488            });
     489
     490            this.variationDetails = new my.VariationContentView({ el: this.details });
     491            var model = this.model.get('data').AlgorithmParameters[0];
     492            this.entrySelected(model);
     493        },
     494        entrySelected: function (model) {
     495            this.selectedModel = model;
     496            this.variationDetails.model = model;
     497            this.details.empty();
     498            this.variationDetails.render();
     499            if (model.Active) {
     500                this.activateButton.attr('checked', 'checked');
     501                $('*', this.details).removeAttr('disabled');
     502            }
     503            else {
     504                this.activateButton.removeAttr('checked');
     505                $('*', this.details).attr('disabled', 'disabled');
     506            }
     507        },
     508        generateVariations: function () {
     509            this.solutions = [];
     510            this.exhaust(0, []);
     511            this.trigger('variations-generated', this.solutions);
     512        },
     513        exhaust: function (index, element) {
     514            if (index == this.model.get('data').AlgorithmParameters.length) {
     515                // we found a solution! store it by creating a deep copy
     516                this.solutions.push($.extend(true, [], element));
     517                return;
     518            }
     519
     520            var currentParameter = this.model.get('data').AlgorithmParameters[index];
     521            if (currentParameter.Active && currentParameter.Generated) {
     522                for (var i = 0; i < currentParameter.Generated.length; i++) {
     523                    element[index] = {
     524                        Name: currentParameter.Name,
     525                        Value: currentParameter.Generated[i]
     526                    };
     527                    if (currentParameter.Options) {
     528                        element[index].Options = currentParameter.Options;
     529                    }
     530                    this.exhaust(index + 1, element);
     531                }
     532            } else {
    495533                element[index] = {
    496534                    Name: currentParameter.Name,
    497                     Value: currentParameter.Generated[i]
     535                    Value: currentParameter.Value
    498536                };
    499537                if (currentParameter.Options) {
     
    502540                this.exhaust(index + 1, element);
    503541            }
    504         } else {
    505             element[index] = {
    506                 Name: currentParameter.Name,
    507                 Value: currentParameter.Value
    508             };
    509             if (currentParameter.Options) {
    510                 element[index].Options = currentParameter.Options;
    511             }
    512             this.exhaust(index + 1, element);
    513         }
    514     }
    515 });
    516 
    517 var TableEditView = Backbone.View.extend({
    518     events: {
    519         'change': 'valueChanged',
    520         'click button[data-operation="Add"]': 'addClicked',
    521         'click button[data-operation="Remove"]': 'removeClicked'
     542        }
     543    });
     544
     545    my.TableEditView = Backbone.View.extend({
     546        events: {
     547            'change': 'valueChanged',
     548            'click button[data-operation="Add"]': 'addClicked',
     549            'click button[data-operation="Remove"]': 'removeClicked'
     550        },
     551        render: function () {
     552            this.$el.empty();
     553            // http: //stackoverflow.com/questions/8749236/create-table-with-jquery-append
     554            var table = $('<table></table>').addClass('editableTable');
     555
     556            // determine dimensions
     557            var rows = this.model.length;
     558            var columns = 1;
     559            if ($.isArray(this.model[0])) {
     560                columns = this.model[0].length;
     561            }
     562
     563            // create head elements
     564            var head = $('<thead></thead>');
     565            var headerRow = $('<tr></tr>');
     566            headerRow.appendTo(head);
     567            if (this.options.rowNames) {
     568                var rowNames = this.options.rowNames;
     569                for (var i = 0; i < rowNames.length; i++) {
     570                    $('<td />').text(rowNames[i]).appendTo(headerRow);
     571                }
     572            } else {
     573                for (var i = 0; i < columns; i++) {
     574                    $('<td />').text((i + 1) + '. Column').appendTo(headerRow);
     575                }
     576            }
     577            head.appendTo(table);
     578
     579            // create body
     580            var body = $('<tbody></tbody>');
     581
     582            for (var i = 0; i < rows; i++) {
     583                var row = $('<tr></tr>');
     584                for (var j = 0; j < columns; j++) {
     585                    var rowContent = this.model[i];
     586                    var columnEntry = $.isArray(rowContent) ? rowContent[j] : rowContent;
     587                    var col = $('<td></td>');
     588                    if (this.options.editable) {
     589                        $('<input type="text" name="' + i + '_' + j + '" />').val(columnEntry).appendTo(col);
     590                    } else {
     591                        col.text(columnEntry);
     592                    }
     593                    col.appendTo(row);
     594                }
     595                if (this.options.editable) {
     596                    $('<button data-operation="Add" name="' + i + '" />').val(columnEntry).text('+').appendTo(col);
     597                    $('<button data-operation="Remove" name="' + i + '" />').val(columnEntry).text('-').appendTo(col);
     598                }
     599                row.appendTo(body);
     600            }
     601            body.appendTo(table);
     602
     603            table.appendTo(this.$el);
     604            if (this.options.useDatatable)
     605                table.dataTable();
     606        },
     607        valueChanged: function (evt) {
     608            var target = $(evt.target);
     609            var value = target.val();
     610            var index = target.attr('name');
     611            var splittedName = index.split('_');
     612            var i = parseInt(splittedName[0]);
     613            var j = parseInt(splittedName[1]);
     614            if ($.isArray(this.model[i])) {
     615                this.model[i][j] = parseFloat(value);
     616            } else {
     617                this.model[i] = parseFloat(value);
     618            }
     619        },
     620        addClicked: function (evt) {
     621            var target = $(evt.target);
     622            var index = target.attr('name');
     623            var i = parseInt(index);
     624            if ($.isArray(this.model[i])) {
     625                var cpy = [];
     626                for (var j = 0; j < this.model[i].length; j++) {
     627                    cpy.push(this.model[i][j]);
     628                }
     629                this.model.splice(i, 0, cpy);
     630            } else {
     631                this.model.splice(i, 0, this.model[i]);
     632            }
     633            // render after model changes
     634            this.render();
     635        },
     636        removeClicked: function (evt) {
     637            var target = $(evt.target);
     638            var index = target.attr('name');
     639            var i = parseInt(index);
     640            this.model.splice(i, 1);
     641            // render after model changes
     642            this.render();
     643        }
     644    });
     645
     646    my.NumberEditableView = Backbone.View.extend({
     647        events: {
     648            'change': 'valueChanged'
     649        },
     650        render: function () {
     651            $('<input type="text" />').val(this.model.Value).appendTo(this.$el);
     652
     653        },
     654        valueChanged: function (evt) {
     655            var value = $(evt.target).val();
     656            if (!isNaN(value)) {
     657                value = parseFloat(value);
     658                this.model.Value = value;
     659            } else {
     660                $('input', this.$el).val(this.model.Value);
     661            }
     662        }
     663    });
     664
     665    my.SelectionView = Backbone.View.extend({
     666        events: {
     667            'change': 'checked'
     668        },
     669        render: function () {
     670            this.$el.empty();
     671            var s = $('<select />').attr('data-name', this.model.Name).appendTo(this.$el);
     672            for (var i = 0; i < this.model.Options.length; i++) {
     673                $('<option />', { value: this.model.Options[i], text: this.model.Options[i] }).appendTo(s);
     674            }
     675            s.val(this.model.Value);
     676        },
     677        checked: function (evt) {
     678            var value = $(evt.target).val();
     679            var name = $(evt.target).attr('data-name')
     680            this.trigger('selected', { name: name, value: value });
     681        }
     682    });
     683
     684    my.OptionSelectionView = Backbone.View.extend({
     685        events: {
     686            'change': 'checked'
     687        },
     688        render: function () {
     689            this.$el.empty();
     690            if ($.isArray(this.model)) {
     691                for (var i = 0; i < this.model.length; i++) {
     692                    $(_.template($('#checkbox_template').html(), { checked: false, name: this.model[i], text: this.model[i], hideText: this.options.hideText })).appendTo(this.$el);
     693                }
     694            }
     695            else {
     696                $(_.template($('#checkbox_template').html(), { checked: this.model, name: this.model, text: this.model, hideText: this.options.hideText })).appendTo(this.$el);
     697            }
     698        },
     699        checked: function (evt) {
     700            var checked = $(evt.target).is(':checked');
     701            var name = $(evt.target).attr('name')
     702            this.trigger('changed', { name: name, checked: checked });
     703        }
     704    });
     705
     706
     707    my.PlotView = Backbone.View.extend({
     708        render: function () {
     709            this.$el.empty();
     710            var plotLabels = undefined;
     711            if (this.model.RowNames) {
     712                plotLabels = [];
     713                for (var i = 0; i < this.model.RowNames.length; i++) {
     714                    plotLabels.push({ label: this.model.RowNames[i] });
     715                }
     716            }
     717
     718            var values = this.model.Value ? this.model.Value : this.model;
     719
     720            var plotValues = [];
     721            if ($.isArray(values[0])) {
     722                var columnCount = values[0].length;
     723                var colVals = {};
     724                for (var i = 0; i < columnCount; i++)
     725                    colVals[i] = [];
     726
     727                for (var i = 0; i < values.length; i++) {
     728                    for (var j = 0; j < columnCount; j++) {
     729                        colVals[j].push(values[i][j]);
     730                    }
     731                }
     732
     733                for (var i = 0; i < columnCount; i++) {
     734                    plotValues.push(colVals[i]);
     735                }
     736            } else {
     737                plotValues.push(values);
     738            }
     739
     740            if (!this.$el.attr('id')) {
     741                this.$el.attr('id', my.PlotView.nextId());
     742            }
     743
     744            this.$el.css('width', '500px');
     745
     746            this.plot = $.jqplot(this.$el.attr('id'), plotValues, {
     747                cursor: {
     748                    show: true,
     749                    zoom: true,
     750                    showTooltip: false
     751                },
     752                series: plotLabels,
     753                seriesDefaults: {
     754                    lineWidth: 1.5,
     755                    markerOptions: {
     756                        size: 2,
     757                        lineWidth: 2
     758                    }
     759                },
     760                legend: {
     761                    show: true,
     762                    placement: 'outsideGrid'
     763                },
     764                highlighter: {
     765                    show: true,
     766                    sizeAdjust: 7.5
     767                }
     768            });
     769        },
     770        refresh: function () {
     771            if (this.plot)
     772                this.plot.replot({ resetAxes: true });
     773        }
    522774    },
    523     render: function () {
    524         this.$el.empty();
    525         // http: //stackoverflow.com/questions/8749236/create-table-with-jquery-append
    526         var table = $('<table></table>').addClass('editableTable');
    527 
    528         // determine dimensions
    529         var rows = this.model.length;
    530         var columns = 1;
    531         if ($.isArray(this.model[0])) {
    532             columns = this.model[0].length;
    533         }
    534 
    535         // create head elements
    536         var head = $('<thead></thead>');
    537         var headerRow = $('<tr></tr>');
    538         headerRow.appendTo(head);
    539         for (var i = 0; i < columns; i++) {
    540             $('<td />').text((i + 1) + '. Column').appendTo(headerRow);
    541         }
    542         head.appendTo(table);
    543 
    544         // create body
    545         var body = $('<tbody></tbody>');
    546 
    547         for (var i = 0; i < rows; i++) {
    548             var row = $('<tr></tr>');
    549             for (var j = 0; j < columns; j++) {
    550                 var rowContent = this.model[i];
    551                 var columnEntry = $.isArray(rowContent) ? rowContent[j] : rowContent;
    552                 var col = $('<td></td>');
    553                 $('<input type="text" name="' + i + '_' + j + '" />').val(columnEntry).appendTo(col);
    554                 col.appendTo(row);
    555             }
    556             if (this.options.editable) {
    557                 $('<button data-operation="Add" name="' + i + '" />').val(columnEntry).text('+').appendTo(col);
    558                 $('<button data-operation="Remove" name="' + i + '" />').val(columnEntry).text('-').appendTo(col);
    559             }
    560             row.appendTo(body);
    561         }
    562         body.appendTo(table);
    563         table.appendTo(this.$el);
    564     },
    565     valueChanged: function (evt) {
    566         var target = $(evt.target);
    567         var value = target.val();
    568         var index = target.getattr('name');
    569         var splittedName = index.split('_');
    570         var i = parseInt(splittedName[0]);
    571         var j = parseInt(splittedName[1]);
    572         if ($.isArray(this.model[i])) {
    573             this.model[i][j] = parseFloat(value);
    574         } else {
    575             this.model[i] = parseFloat(value);
    576         }
    577     },
    578     addClicked: function (evt) {
    579         var target = $(evt.target);
    580         var index = target.attr('name');
    581         var i = parseInt(index);
    582         if ($.isArray(this.model[i])) {
    583             var cpy = [];
    584             for (var j = 0; j < this.model[i].length; j++) {
    585                 cpy.push(this.model[i][j]);
    586             }
    587             this.model.splice(i, 0, cpy);
    588         } else {
    589             this.model.splice(i, 0, this.model[i]);
    590         }
    591         // render after model changes
    592         this.render();
    593     },
    594     removeClicked: function (evt) {
    595         var target = $(evt.target);
    596         var index = target.attr('name');
    597         var i = parseInt(index);
    598         this.model.splice(i, 1);
    599         // render after model changes
    600         this.render();
    601     }
    602 });
    603 
    604 var OptionSelectionView = Backbone.View.extend({
    605     events: {
    606         'change': 'checked'
    607     },
    608     render: function () {
    609         this.$el.empty();
    610 
    611         for (var i = 0; i < this.model.length; i++) {
    612             $(_.template($('#checkbox_template').html(), { name: this.model[i], text: this.model[i] })).appendTo(this.$el);
    613         }
    614     },
    615     checked: function (evt) {
    616         var checked = $(evt.target).is(':checked');
    617         var name = $(evt.target).attr('name')
    618         this.trigger('changed', { name: name, checked: checked });
    619     }
    620 });
    621 
    622 var VariationContentView = Backbone.View.extend({
    623     render: function () {
    624         var self = this;
    625         if (this.model.Value === 'false' || this.model.Value === 'true' ||
    626             this.model.Value === true || this.model.Value === false) {
    627             $(_.template($('#variation_boolean_template').html(), {})).appendTo(this.$el);
    628             this.model.Generated = [false, true];
    629         }
    630         else if (!isNaN(this.model.Value)) {
    631             var elem = $(_.template($('#variation_number_template').html(), {}));
    632             elem.appendTo(this.$el)
    633             $('input[name="generate"]', elem).click(function (evt) { self.openGenerator(evt); });
    634             if (!this.model.Generated) {
    635                 this.model.Generated = [0, 1, 2];
    636             }
    637             var tev = new TableEditView({ model: this.model.Generated, el: $('div div', this.$el), editable: true });
     775  {
     776      plotId: 1,
     777      nextId: function () {
     778          return my.PlotView.plotId++;
     779      }
     780  });
     781
     782    my.VariationContentView = Backbone.View.extend({
     783        render: function () {
     784            var self = this;
     785            if (this.model.Value === 'false' || this.model.Value === 'true' ||
     786              this.model.Value === true || this.model.Value === false) {
     787                $(_.template($('#variation_boolean_template').html(), {})).appendTo(this.$el);
     788                this.model.Generated = [false, true];
     789            }
     790            else if (!isNaN(this.model.Value)) {
     791                var elem = $(_.template($('#variation_number_template').html(), {}));
     792                elem.appendTo(this.$el)
     793                $('input[name="generate"]', elem).click(function (evt) { self.openGenerator(evt); });
     794                if (!this.model.Generated) {
     795                    this.model.Generated = [0, 1, 2];
     796                }
     797                var tev = new my.TableEditView({ model: this.model.Generated, el: $('div div', this.$el), editable: true });
     798                tev.render();
     799            }
     800            else if (this.model.Options) {
     801                var osv = new my.OptionSelectionView({ model: this.model.Options, el: this.$el });
     802                this.listenTo(osv, 'changed', function (evt) {
     803                    self.selectionChanged(evt);
     804                });
     805                if (!this.model.Generated)
     806                    this.model.Generated = [];
     807                osv.render();
     808                for (var i = 0; i < this.model.Generated.length; i++) {
     809                    $('input[name="' + this.model.Generated[i] + '"]', this.$el).attr('checked', 'checked');
     810                }
     811            }
     812        },
     813        openGenerator: function (evt) {
     814            var self = this;
     815            var generator = new my.GeneratorDialog();
     816            this.listenTo(generator, 'success', function (data) {
     817                self.doGenerate(data);
     818            });
     819            generator.render();
     820        },
     821        doGenerate: function (data) {
     822            if (data.minimum > data.maximum) {
     823                var tmp = data.minimum;
     824                data.minimum = data.maximum;
     825                data.maximum = tmp;
     826            }
     827            if (data.step < 0)
     828                data.step *= -1;
     829            if (data.step == 0)
     830                data.step = 1;
     831            this.model.Generated = _.range(data.minimum, data.maximum + 1, data.step);
     832            var tev = new my.TableEditView({ model: this.model.Generated, el: $('div div', this.$el), editable: true });
    638833            tev.render();
    639         }
    640         else if (this.model.Options) {
    641             var osv = new OptionSelectionView({ model: this.model.Options, el: this.$el });
    642             this.listenTo(osv, 'changed', function (evt) {
    643                 self.selectionChanged(evt);
    644             });
    645             if (!this.model.Generated)
    646                 this.model.Generated = [];
    647             osv.render();
    648             for (var i = 0; i < this.model.Generated.length; i++) {
    649                 $('input[name="' + this.model.Generated[i] + '"]', this.$el).attr('checked', 'checked');
    650             }
    651         }
    652     },
    653     openGenerator: function (evt) {
    654         var self = this;
    655         var generator = new GeneratorDialog();
    656         this.listenTo(generator, 'success', function (data) {
    657             self.doGenerate(data);
    658         });
    659         generator.render();
    660     },
    661     doGenerate: function (data) {
    662         if (data.minimum > data.maximum) {
    663             var tmp = data.minimum;
    664             data.minimum = data.maximum;
    665             data.maximum = tmp;
    666         }
    667         if (data.step < 0)
    668             data.step *= -1;
    669         if (data.step == 0)
    670             data.step = 1;
    671         this.model.Generated = _.range(data.minimum, data.maximum + 1, data.step);
    672         var tev = new TableEditView({ model: this.model.Generated, el: $('div div', this.$el), editable: true });
    673         tev.render();
    674     },
    675     selectionChanged: function (evt) {
    676         if (!evt.checked) {
    677             this.model.Generated = _.without(this.model.Generated, evt.name);
    678         } else if (_.indexOf(this.model.Generated, evt.name) == -1) {
    679             this.model.Generated.push(evt.name);
    680         }
    681     }
    682 });
    683 
    684 var GeneratorDialog = Backbone.View.extend({
    685     render: function() {
    686         var self = this;
    687         var generator = $(_.template($('#variation_generator_template').html(),{}));
    688         generator.dialog({
    689             buttons: {
    690                 "Abort": function () {
    691                     $(this).dialog("close");
    692                 },
    693                 "OK": function () {
    694                     $(this).dialog("close");
    695                     self.trigger("success", {
    696                         minimum: parseInt($('input[name="minimum"]', generator).val()),
    697                         maximum: parseInt($('input[name="maximum"]', generator).val()),
    698                         step: parseFloat($('input[name="step"]', generator).val())
    699                     });
    700                 }
    701             }
    702         });
    703     }
    704 });
    705 
    706 var VariationEntryView = Backbone.View.extend({
    707     render: function () {
    708         var entryTemplate = _.template($('#variationentry_template').html(), this.model);
    709         $(entryTemplate).appendTo(this.$el);       
    710     }
    711 });
     834        },
     835        selectionChanged: function (evt) {
     836            if (!evt.checked) {
     837                this.model.Generated = _.without(this.model.Generated, evt.name);
     838            } else if (_.indexOf(this.model.Generated, evt.name) == -1) {
     839                this.model.Generated.push(evt.name);
     840            }
     841        }
     842    });
     843
     844    my.GeneratorDialog = Backbone.View.extend({
     845        render: function () {
     846            var self = this;
     847            var generator = $(_.template($('#variation_generator_template').html(), {}));
     848            generator.dialog({
     849                buttons: {
     850                    "Abort": function () {
     851                        $(this).dialog("close");
     852                    },
     853                    "OK": function () {
     854                        $(this).dialog("close");
     855                        self.trigger("success", {
     856                            minimum: parseInt($('input[name="minimum"]', generator).val()),
     857                            maximum: parseInt($('input[name="maximum"]', generator).val()),
     858                            step: parseFloat($('input[name="step"]', generator).val())
     859                        });
     860                    }
     861                }
     862            });
     863        }
     864    });
     865
     866    my.VariationEntryView = Backbone.View.extend({
     867        render: function () {
     868            var entryTemplate = _.template($('#variationentry_template').html(), this.model);
     869            $(entryTemplate).appendTo(this.$el);
     870        }
     871    });
     872    return my;
     873} (OAAS_VIEW || {}, Backbone, _, $, OAAS_MODEL));
  • branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/hl/Site.css

    r9305 r9324  
    447447    background: #EA8511; 
    448448}
     449
     450.loader
     451{
     452  width: 24px;
     453  height: 24px;
     454}
     455
     456.bigImage
     457{
     458  text-align: center;
     459  display: block;
     460  margin-left: auto;
     461  margin-right: auto; 
     462}
     463
     464.selectedRow
     465{
     466  font-weight: bolder;
     467}
     468
     469.experimentMenu
     470{
     471    clear: left;
     472    float: left;
     473    display: inline;
     474}
Note: See TracChangeset for help on using the changeset viewer.