extensions/net.sf.basedb.reggie/trunk/resources/admin/install.js

Code
Comments
Other
Rev Date Author Line
2327 08 Apr 14 nicklas 1 var Install = function()
2327 08 Apr 14 nicklas 2 {
2327 08 Apr 14 nicklas 3   var install = {};
2593 19 Aug 14 nicklas 4   var debug = 0;
4361 16 Feb 17 nicklas 5   var checks;
2327 08 Apr 14 nicklas 6   
2327 08 Apr 14 nicklas 7   install.initPage = function()
2327 08 Apr 14 nicklas 8   {
2618 01 Sep 14 nicklas 9     if (!App.getActiveProjectId()) return;
4361 16 Feb 17 nicklas 10     Events.addEventHandler('typeFilter', 'change', install.filterOnChange);
4361 16 Feb 17 nicklas 11     Events.addEventHandler('nameFilter', 'change', install.filterOnChange);
4361 16 Feb 17 nicklas 12     Events.addEventHandler('messageFilter', 'change', install.filterOnChange);
4361 16 Feb 17 nicklas 13
2327 08 Apr 14 nicklas 14     Buttons.addClickHandler('btnFixItems', install.fixInstallation);
2327 08 Apr 14 nicklas 15     Buttons.addClickHandler('btnCreateMissingItems', install.fixInstallation);
6713 28 Apr 22 nicklas 16     Buttons.addClickHandler('btnReggieUpdated', install.fixInstallation);
2327 08 Apr 14 nicklas 17     
2618 01 Sep 14 nicklas 18     install.checkInstallation('Validate', 'Checking installation...');
2327 08 Apr 14 nicklas 19   }
2327 08 Apr 14 nicklas 20   
2327 08 Apr 14 nicklas 21   install.fixInstallation = function()
2327 08 Apr 14 nicklas 22   {
2618 01 Sep 14 nicklas 23     install.checkInstallation('Install', 'Fixing installation...');
2327 08 Apr 14 nicklas 24   }
2327 08 Apr 14 nicklas 25
2327 08 Apr 14 nicklas 26   
2618 01 Sep 14 nicklas 27   install.checkInstallation = function(cmd, workText)
2327 08 Apr 14 nicklas 28   {
4361 16 Feb 17 nicklas 29     Doc.hide('item-list');
4361 16 Feb 17 nicklas 30     Doc.hide('itemTable');
2618 01 Sep 14 nicklas 31     Doc.hide('createMissingItems');
2618 01 Sep 14 nicklas 32     Doc.hide('fixIncompleteItems');
6713 28 Apr 22 nicklas 33     Doc.hide('registerUpdated');
2618 01 Sep 14 nicklas 34     
2327 08 Apr 14 nicklas 35     var url = '../Install.servlet?ID=' + App.getSessionId();
2327 08 Apr 14 nicklas 36     url += '&cmd='+cmd;
2618 01 Sep 14 nicklas 37     Doc.addClass('workInProgress', 'working');
2618 01 Sep 14 nicklas 38     Wizard.showLoadingAnimation(workText);
2618 01 Sep 14 nicklas 39     Wizard.asyncJsonRequest(url, install.onChecked);
2327 08 Apr 14 nicklas 40   }
2327 08 Apr 14 nicklas 41   
2618 01 Sep 14 nicklas 42   install.onChecked = function(response)
2327 08 Apr 14 nicklas 43   {
2618 01 Sep 14 nicklas 44     Doc.removeClass('workInProgress', 'working');
2327 08 Apr 14 nicklas 45     
4361 16 Feb 17 nicklas 46     checks = response.checks;
2327 08 Apr 14 nicklas 47     
2327 08 Apr 14 nicklas 48     var numMissing = 0;
2327 08 Apr 14 nicklas 49     var numWarnings = 0;
2327 08 Apr 14 nicklas 50     var numErrors = 0;
2327 08 Apr 14 nicklas 51     var numIncomplete = 0;
4361 16 Feb 17 nicklas 52     
2327 08 Apr 14 nicklas 53     var index = 0;
2327 08 Apr 14 nicklas 54     var topLines = []; // Top lines are for items with error/warning/special message
2327 08 Apr 14 nicklas 55     var bottomLines = []; // Bottom lines are for all 'OK' items
2327 08 Apr 14 nicklas 56     var allOk = true;
2327 08 Apr 14 nicklas 57     var clickableItems = [];
4361 16 Feb 17 nicklas 58     var typeFilter = Doc.element('typeFilter');
4361 16 Feb 17 nicklas 59     typeFilter.length = 0;
4361 16 Feb 17 nicklas 60     typeFilter[0] = new Option();
4361 16 Feb 17 nicklas 61     var types = [];
2327 08 Apr 14 nicklas 62     
4361 16 Feb 17 nicklas 63     for (var checkNo = 0; checkNo < checks.length; checkNo++)
2327 08 Apr 14 nicklas 64     {
4361 16 Feb 17 nicklas 65       var check = checks[checkNo];
4361 16 Feb 17 nicklas 66       
2327 08 Apr 14 nicklas 67       var icon = 'ok.png';
2327 08 Apr 14 nicklas 68       check.ok = true;
6864 04 Nov 22 nicklas 69       check.fixable = false;
2327 08 Apr 14 nicklas 70       if (check.status == 'missing') 
2327 08 Apr 14 nicklas 71       {
2327 08 Apr 14 nicklas 72         numMissing++;
2327 08 Apr 14 nicklas 73         icon = 'error.png';
2327 08 Apr 14 nicklas 74         check.ok = false;
6864 04 Nov 22 nicklas 75         check.fixable = true;
2327 08 Apr 14 nicklas 76       }
2327 08 Apr 14 nicklas 77       if (check.status == 'incomplete')
2327 08 Apr 14 nicklas 78       {
2327 08 Apr 14 nicklas 79         numIncomplete++;
2327 08 Apr 14 nicklas 80         icon = 'warning.png';
2327 08 Apr 14 nicklas 81         check.ok = false;
6864 04 Nov 22 nicklas 82         check.fixable = true;
2327 08 Apr 14 nicklas 83       }
2327 08 Apr 14 nicklas 84       if (check.status == 'error') 
2327 08 Apr 14 nicklas 85       {
2327 08 Apr 14 nicklas 86         numErrors++;
2327 08 Apr 14 nicklas 87         icon = 'error.png';
2327 08 Apr 14 nicklas 88         check.ok = false;
2327 08 Apr 14 nicklas 89       }
2327 08 Apr 14 nicklas 90       if (check.status == 'warning') 
2327 08 Apr 14 nicklas 91       {
2327 08 Apr 14 nicklas 92         numWarnings++;
2327 08 Apr 14 nicklas 93         icon = 'warning.png';
2327 08 Apr 14 nicklas 94         check.ok = false;
2327 08 Apr 14 nicklas 95       }
2327 08 Apr 14 nicklas 96       allOk &= check.ok;
2327 08 Apr 14 nicklas 97       
4361 16 Feb 17 nicklas 98       if (!types[check.itemType])
2327 08 Apr 14 nicklas 99       {
4361 16 Feb 17 nicklas 100         typeFilter[typeFilter.length] = new Option(check.itemType);
4361 16 Feb 17 nicklas 101         types[check.itemType] = 1;
2327 08 Apr 14 nicklas 102       }
2327 08 Apr 14 nicklas 103       
4361 16 Feb 17 nicklas 104       var line = '<tr id="check'+checkNo+'"class="highlight '+check.itemType+' ' + (check.ok ? 'check-ok' : 'check-not-ok') + '">';
4361 16 Feb 17 nicklas 105       line += '<td class="indexCol"><span id="index.'+checkNo+'">'+(checkNo+1)+'</span></td>';
4361 16 Feb 17 nicklas 106
4361 16 Feb 17 nicklas 107       line += '<td class="dottedleft">'+Strings.encodeTags(check.itemType)+'</td>';
4361 16 Feb 17 nicklas 108       var name = Strings.encodeTags(check.name);
2327 08 Apr 14 nicklas 109       if (check.mainType) name += ' <span class="itemsubtype">[' + check.mainType + ']</span>'; 
2327 08 Apr 14 nicklas 110       if (check.id)
2327 08 Apr 14 nicklas 111       {
2327 08 Apr 14 nicklas 112         clickableItems[clickableItems.length] = check.itemType+check.id;
4361 16 Feb 17 nicklas 113         line += '<td><div class="link" id="'+check.itemType+check.id+'" data-item-type="'+check.itemType+'" data-item-id="'+check.id+'"';
2327 08 Apr 14 nicklas 114         line += ' title="View this item (use CTRL, ALT or SHIFT to edit)">'+name+'</div></td>';
2327 08 Apr 14 nicklas 115       }
2327 08 Apr 14 nicklas 116       else
2327 08 Apr 14 nicklas 117       {
2327 08 Apr 14 nicklas 118         line += '<td class="itemTypeCol"><i>' + name + '</i></td>';
2327 08 Apr 14 nicklas 119       }
6864 04 Nov 22 nicklas 120       line += '<td class="iconCol">';
6864 04 Nov 22 nicklas 121       if (check.fixable) line += '<img src="../../../images/fixit.png">';
6864 04 Nov 22 nicklas 122       line += '<img src="../images/'+icon+'">';
6864 04 Nov 22 nicklas 123       line += '</td>';
4361 16 Feb 17 nicklas 124       line += '<td>';
2327 08 Apr 14 nicklas 125       if (check.messages.length > 1)
2327 08 Apr 14 nicklas 126       {
2327 08 Apr 14 nicklas 127         for (var m = 0; m < check.messages.length; m++)
2327 08 Apr 14 nicklas 128         {
2327 08 Apr 14 nicklas 129           line += '• '+check.messages[m] + '<br>';
2327 08 Apr 14 nicklas 130         }
2327 08 Apr 14 nicklas 131       }
2327 08 Apr 14 nicklas 132       else
2327 08 Apr 14 nicklas 133       {
2327 08 Apr 14 nicklas 134         line += check.messages;
2327 08 Apr 14 nicklas 135       }
5962 03 Jun 20 nicklas 136       if (check.stderr)
5962 03 Jun 20 nicklas 137       {
5962 03 Jun 20 nicklas 138         line += '<div class="stacktrace">'+Strings.encodeTags(check.stderr)+'</div>';
5962 03 Jun 20 nicklas 139       }
2327 08 Apr 14 nicklas 140       line += '</td></tr>';
2327 08 Apr 14 nicklas 141       
2327 08 Apr 14 nicklas 142       if (!check.ok || check.messages != 'Ok')
2327 08 Apr 14 nicklas 143       {
2327 08 Apr 14 nicklas 144         topLines[topLines.length] = line;
2327 08 Apr 14 nicklas 145       }
2327 08 Apr 14 nicklas 146       else
2327 08 Apr 14 nicklas 147       {
2327 08 Apr 14 nicklas 148         bottomLines[bottomLines.length] = line;
2327 08 Apr 14 nicklas 149       }
2327 08 Apr 14 nicklas 150       index++;
2327 08 Apr 14 nicklas 151     }
2327 08 Apr 14 nicklas 152     
4361 16 Feb 17 nicklas 153     if (topLines.length + bottomLines.length > 0)
2327 08 Apr 14 nicklas 154     {
4361 16 Feb 17 nicklas 155       Doc.element('item-list').innerHTML = topLines.join('') + bottomLines.join('');
4361 16 Feb 17 nicklas 156       Doc.show('item-list');
2327 08 Apr 14 nicklas 157     }
4361 16 Feb 17 nicklas 158     Doc.show('itemTable', 'table');
2618 01 Sep 14 nicklas 159
2327 08 Apr 14 nicklas 160     // Add click handler to items
2327 08 Apr 14 nicklas 161     for (var i = 0; i < clickableItems.length; i++)
2327 08 Apr 14 nicklas 162     {
2327 08 Apr 14 nicklas 163       Events.addEventHandler(clickableItems[i], 'click', Items.itemOnClick);
2327 08 Apr 14 nicklas 164     }
2327 08 Apr 14 nicklas 165     
2327 08 Apr 14 nicklas 166     if (numErrors > 0)
2327 08 Apr 14 nicklas 167     {
4361 16 Feb 17 nicklas 168       Wizard.setWizardStatus('messagecontainer error', numErrors+' errors was detected. You need to fix those manually.');  
2327 08 Apr 14 nicklas 169     }
2618 01 Sep 14 nicklas 170     else if (numMissing > 0)
2618 01 Sep 14 nicklas 171     {
2618 01 Sep 14 nicklas 172       Doc.show('createMissingItems');
2618 01 Sep 14 nicklas 173     }
2618 01 Sep 14 nicklas 174     else if (numIncomplete > 0)
2618 01 Sep 14 nicklas 175     {
2618 01 Sep 14 nicklas 176       Doc.show('fixIncompleteItems');
2618 01 Sep 14 nicklas 177     }
6713 28 Apr 22 nicklas 178     else 
2327 08 Apr 14 nicklas 179     {
6713 28 Apr 22 nicklas 180       if (numWarnings > 0)
6713 28 Apr 22 nicklas 181       {
6713 28 Apr 22 nicklas 182         Wizard.setWizardStatus('all-checks-passed with-warnings', numWarnings+' warnings was detected. Reggie may still work. If not, you need to fix it manually.');
6713 28 Apr 22 nicklas 183       }
6713 28 Apr 22 nicklas 184       else
6713 28 Apr 22 nicklas 185       {
6713 28 Apr 22 nicklas 186         Wizard.setWizardStatus('all-checks-passed', 'All checks passed');
6713 28 Apr 22 nicklas 187       }
6713 28 Apr 22 nicklas 188       if (response.installedVersion != Reggie.VERSION)
6713 28 Apr 22 nicklas 189       {
6713 28 Apr 22 nicklas 190         Doc.show('registerUpdated');
6713 28 Apr 22 nicklas 191       }
2327 08 Apr 14 nicklas 192     }
2327 08 Apr 14 nicklas 193   }
2327 08 Apr 14 nicklas 194   
4361 16 Feb 17 nicklas 195   install.filterOnChange = function()
2327 08 Apr 14 nicklas 196   {
4361 16 Feb 17 nicklas 197     
4361 16 Feb 17 nicklas 198     var filter = new Filter();
4361 16 Feb 17 nicklas 199     filter.addTextCriteria(ItemProperty.ItemType, Doc.element('typeFilter').value);
4361 16 Feb 17 nicklas 200     filter.addContainsCriteria(ItemProperty.Name, Doc.element('nameFilter').value);
4361 16 Feb 17 nicklas 201     filter.addContainsCriteria(ItemProperty.Messages, Doc.element('messageFilter').value);
4361 16 Feb 17 nicklas 202
4361 16 Feb 17 nicklas 203     var numMatch = 0;
4361 16 Feb 17 nicklas 204     for (var checkNo = 0; checkNo < checks.length; checkNo++)
4361 16 Feb 17 nicklas 205     {
4361 16 Feb 17 nicklas 206       var check = checks[checkNo];
4361 16 Feb 17 nicklas 207       
4361 16 Feb 17 nicklas 208       check.include = filter.check(check);
4361 16 Feb 17 nicklas 209       if (check.include)
4361 16 Feb 17 nicklas 210       {
4361 16 Feb 17 nicklas 211         numMatch++;
4361 16 Feb 17 nicklas 212         Doc.show('check'+checkNo);
4361 16 Feb 17 nicklas 213       }
4361 16 Feb 17 nicklas 214       else
4361 16 Feb 17 nicklas 215       {
4361 16 Feb 17 nicklas 216         Doc.hide('check'+checkNo);
4361 16 Feb 17 nicklas 217       }
4361 16 Feb 17 nicklas 218     }
4361 16 Feb 17 nicklas 219     
4361 16 Feb 17 nicklas 220     Doc.showHide('item-list', numMatch > 0);
4361 16 Feb 17 nicklas 221     Doc.showHide('no-matching-items', numMatch==0);
2327 08 Apr 14 nicklas 222   }
2327 08 Apr 14 nicklas 223
2327 08 Apr 14 nicklas 224   
2327 08 Apr 14 nicklas 225   return install;
2327 08 Apr 14 nicklas 226 }();
2327 08 Apr 14 nicklas 227
2327 08 Apr 14 nicklas 228 Doc.onLoad(Install.initPage);
4361 16 Feb 17 nicklas 229
4361 16 Feb 17 nicklas 230 var ItemProperty = function()
4361 16 Feb 17 nicklas 231 {
4361 16 Feb 17 nicklas 232   var p = {};
4361 16 Feb 17 nicklas 233   
4361 16 Feb 17 nicklas 234   p.Name = function(item)
4361 16 Feb 17 nicklas 235   {
4361 16 Feb 17 nicklas 236     return item.name;
4361 16 Feb 17 nicklas 237   }
4361 16 Feb 17 nicklas 238   
4361 16 Feb 17 nicklas 239   p.ItemType = function(item)
4361 16 Feb 17 nicklas 240   {
4361 16 Feb 17 nicklas 241     return item.itemType;
4361 16 Feb 17 nicklas 242   }
4361 16 Feb 17 nicklas 243
4361 16 Feb 17 nicklas 244   p.Messages = function(item)
4361 16 Feb 17 nicklas 245   {
4361 16 Feb 17 nicklas 246     return item.messages.join('');
4361 16 Feb 17 nicklas 247   }
4361 16 Feb 17 nicklas 248   
4361 16 Feb 17 nicklas 249   return p;
4361 16 Feb 17 nicklas 250 }();
4361 16 Feb 17 nicklas 251
4361 16 Feb 17 nicklas 252 /**
4361 16 Feb 17 nicklas 253   Holds one or more filter criterias. Use the 'add*' methods
4361 16 Feb 17 nicklas 254   to add criterias to the filter, and the 'check(item)' method
4361 16 Feb 17 nicklas 255   to evaluate all criterias against a single item.
4361 16 Feb 17 nicklas 256 */
4361 16 Feb 17 nicklas 257 var Filter = function()
4361 16 Feb 17 nicklas 258 {
4361 16 Feb 17 nicklas 259   this.criterias = [];
4361 16 Feb 17 nicklas 260 }
4361 16 Feb 17 nicklas 261
4361 16 Feb 17 nicklas 262 /**
4361 16 Feb 17 nicklas 263   Adds a text criteria comparing the given item property to
4361 16 Feb 17 nicklas 264   a static value (f2).
4361 16 Feb 17 nicklas 265 */
4361 16 Feb 17 nicklas 266 Filter.prototype.addTextCriteria = function(itemProp, f2)
4361 16 Feb 17 nicklas 267 {
4361 16 Feb 17 nicklas 268   if (f2 != '') 
4361 16 Feb 17 nicklas 269   {
4361 16 Feb 17 nicklas 270     var cmp;
4361 16 Feb 17 nicklas 271     if (f2 == '=')
4361 16 Feb 17 nicklas 272     {
4361 16 Feb 17 nicklas 273       cmp = Comparator.eq;
4361 16 Feb 17 nicklas 274       f2 = null;
4361 16 Feb 17 nicklas 275     }
4361 16 Feb 17 nicklas 276     else if (f2 == '<>')
4361 16 Feb 17 nicklas 277     {
4361 16 Feb 17 nicklas 278       cmp = Comparator.neq;
4361 16 Feb 17 nicklas 279       f2 = null;
4361 16 Feb 17 nicklas 280     }
4361 16 Feb 17 nicklas 281     else
4361 16 Feb 17 nicklas 282     {
4361 16 Feb 17 nicklas 283       cmp = Comparator.eq;
4361 16 Feb 17 nicklas 284     }
4361 16 Feb 17 nicklas 285     this.criterias[this.criterias.length] = function(item) { return cmp(itemProp(item), f2) };
4361 16 Feb 17 nicklas 286   }
4361 16 Feb 17 nicklas 287 }
4361 16 Feb 17 nicklas 288
4361 16 Feb 17 nicklas 289 /**
4361 16 Feb 17 nicklas 290   Adds a text criteria checking if the given item property to
4361 16 Feb 17 nicklas 291   contains a static value (f2).
4361 16 Feb 17 nicklas 292 */
4361 16 Feb 17 nicklas 293 Filter.prototype.addContainsCriteria = function(itemProp, f2)
4361 16 Feb 17 nicklas 294 {
4361 16 Feb 17 nicklas 295   if (f2 != '') 
4361 16 Feb 17 nicklas 296   {
4361 16 Feb 17 nicklas 297     var cmp;
4361 16 Feb 17 nicklas 298     if (f2 == '=')
4361 16 Feb 17 nicklas 299     {
4361 16 Feb 17 nicklas 300       cmp = Comparator.eq;
4361 16 Feb 17 nicklas 301       f2 = null;
4361 16 Feb 17 nicklas 302     }
4361 16 Feb 17 nicklas 303     else if (f2 == '<>')
4361 16 Feb 17 nicklas 304     {
4361 16 Feb 17 nicklas 305       cmp = Comparator.neq;
4361 16 Feb 17 nicklas 306       f2 = null;
4361 16 Feb 17 nicklas 307     }
4361 16 Feb 17 nicklas 308     else
4361 16 Feb 17 nicklas 309     {
4361 16 Feb 17 nicklas 310       cmp = Comparator.contains;
4361 16 Feb 17 nicklas 311     }
4361 16 Feb 17 nicklas 312     this.criterias[this.criterias.length] = function(item) { return cmp(itemProp(item), f2) };
4361 16 Feb 17 nicklas 313   }
4361 16 Feb 17 nicklas 314 }
4361 16 Feb 17 nicklas 315
4361 16 Feb 17 nicklas 316 /**
4361 16 Feb 17 nicklas 317   Evaluate all criterias. Return true if all pass, false otherwise.
4361 16 Feb 17 nicklas 318 */
4361 16 Feb 17 nicklas 319 Filter.prototype.check = function(item)
4361 16 Feb 17 nicklas 320 {
4361 16 Feb 17 nicklas 321   for (var i = 0; i < this.criterias.length; i++)
4361 16 Feb 17 nicklas 322   {
4361 16 Feb 17 nicklas 323     if (!this.criterias[i](item)) return false;
4361 16 Feb 17 nicklas 324   }
4361 16 Feb 17 nicklas 325   return true;
4361 16 Feb 17 nicklas 326 }
4361 16 Feb 17 nicklas 327
4361 16 Feb 17 nicklas 328
4361 16 Feb 17 nicklas 329 var Comparator = function()
4361 16 Feb 17 nicklas 330 {
4361 16 Feb 17 nicklas 331   var cmp = {};
4361 16 Feb 17 nicklas 332   
4361 16 Feb 17 nicklas 333   /**
4361 16 Feb 17 nicklas 334     Return a comparator based on the symbol
4361 16 Feb 17 nicklas 335     which can be either '>' or '<' to return
4361 16 Feb 17 nicklas 336     Comparator.gt or Comparator.lt. Otherwise
4361 16 Feb 17 nicklas 337     the given default or Comparator.eq is returned.
4361 16 Feb 17 nicklas 338   */
4361 16 Feb 17 nicklas 339   cmp.get = function(symbol, defaultCmp)
4361 16 Feb 17 nicklas 340   {
4361 16 Feb 17 nicklas 341     var c;
4361 16 Feb 17 nicklas 342     if (symbol == '<')
4361 16 Feb 17 nicklas 343     {
4361 16 Feb 17 nicklas 344       c = cmp.lt;
4361 16 Feb 17 nicklas 345     }
4361 16 Feb 17 nicklas 346     else if (symbol == '>')
4361 16 Feb 17 nicklas 347     {
4361 16 Feb 17 nicklas 348       c = cmp.gt;
4361 16 Feb 17 nicklas 349     }
4361 16 Feb 17 nicklas 350     else
4361 16 Feb 17 nicklas 351     {
4361 16 Feb 17 nicklas 352       c = defaultCmp || cmp.eq;
4361 16 Feb 17 nicklas 353     }
4361 16 Feb 17 nicklas 354     return c;
4361 16 Feb 17 nicklas 355   }
4361 16 Feb 17 nicklas 356   
4361 16 Feb 17 nicklas 357   // Compare if two values are equal
4361 16 Feb 17 nicklas 358   cmp.eq = function(v1, v2)
4361 16 Feb 17 nicklas 359   {
4361 16 Feb 17 nicklas 360     return v1 == v2;
4361 16 Feb 17 nicklas 361   }
4361 16 Feb 17 nicklas 362   
4361 16 Feb 17 nicklas 363   // Compare if two values are different
4361 16 Feb 17 nicklas 364   cmp.neq = function(v1, v2)
4361 16 Feb 17 nicklas 365   {
4361 16 Feb 17 nicklas 366     return v1 != v2;
4361 16 Feb 17 nicklas 367   }
4361 16 Feb 17 nicklas 368   
4361 16 Feb 17 nicklas 369   // Check if v2 is contained in v1
4361 16 Feb 17 nicklas 370   cmp.contains = function(v1, v2)
4361 16 Feb 17 nicklas 371   {
4361 16 Feb 17 nicklas 372     return v1 != null && v2 != null && v1.indexOf(v2) >= 0;
4361 16 Feb 17 nicklas 373   }
4361 16 Feb 17 nicklas 374   
4361 16 Feb 17 nicklas 375   // Compare if two values are appoximately equals (difference is not more than 0.05)
4361 16 Feb 17 nicklas 376   cmp.approx = function(v1, v2)
4361 16 Feb 17 nicklas 377   {
4361 16 Feb 17 nicklas 378     return Math.abs(v2 - v1) < 0.05;
4361 16 Feb 17 nicklas 379   }
4361 16 Feb 17 nicklas 380   
4361 16 Feb 17 nicklas 381   // Compare if v1 starts with the same string as v2
4361 16 Feb 17 nicklas 382   cmp.startsWith = function(v1, v2)
4361 16 Feb 17 nicklas 383   {
4361 16 Feb 17 nicklas 384     return v1 != null && v1.indexOf(v2) == 0;
4361 16 Feb 17 nicklas 385   }
4361 16 Feb 17 nicklas 386   
4361 16 Feb 17 nicklas 387   // Compare if v1 is greater than or equal to v2
4361 16 Feb 17 nicklas 388   cmp.gt = function(v1, v2)
4361 16 Feb 17 nicklas 389   {
4361 16 Feb 17 nicklas 390     return v1 != null && v2 != null && v1 >= v2;
4361 16 Feb 17 nicklas 391   }
4361 16 Feb 17 nicklas 392   
4361 16 Feb 17 nicklas 393   // Compare if v1 is less than or equal to v2
4361 16 Feb 17 nicklas 394   cmp.lt = function(v1, v2)
4361 16 Feb 17 nicklas 395   {
4361 16 Feb 17 nicklas 396     return v1 != null && v2 != null && v1 <= v2;
4361 16 Feb 17 nicklas 397   }
4361 16 Feb 17 nicklas 398   
4361 16 Feb 17 nicklas 399   return cmp;
4361 16 Feb 17 nicklas 400 }();
4361 16 Feb 17 nicklas 401
4361 16 Feb 17 nicklas 402
4361 16 Feb 17 nicklas 403