<commit_before>var app = require('app');  // Module to control application life.
var request = require('request');
var BrowserWindow = require('browser-window');  // Module to create native browser window.
var Menu = require('menu');
var Dialog = require('dialog');
var Fs = require('fs');
var XLSX = require('xlsx');
var ipc = require('ipc');

var datapackage = require('./browser/datapackage')

// Report crashes to our server.
require('crash-reporter').start();

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is GCed.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', function() {
  var template = [
    {
      label: 'Electron',
      submenu: [
        {
          label: 'About Electron',
          selector: 'orderFrontStandardAboutPanel:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Services',
          submenu: []
        },
        {
          type: 'separator'
        },
        {
          label: 'Hide Electron',
          accelerator: 'CmdOrCtrl+H',
          selector: 'hide:'
        },
        {
          label: 'Hide Others',
          accelerator: 'CmdOrCtrl+Shift+H',
          selector: 'hideOtherApplications:'
        },
        {
          label: 'Show All',
          selector: 'unhideAllApplications:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Quit',
          accelerator: 'CmdOrCtrl+Q',
          selector: 'terminate:'
        },
      ]
    },
    {
      label: 'File',
      submenu: [
        {
          label: 'New',
          accelerator: 'CmdOrCtrl+N',
          click: function() { createWindow(); }
        },
        {
          type: 'separator'
        },
        {
          label: 'Open..',
          accelerator: 'CmdOrCtrl+O',
          click: function() { openFile(); }
        },
        {
          label: 'Import Excel file',
          accelerator: 'CmdOrCtrl+I',
          click: function() { importExcel(); }
        },
        {
          type: 'separator'
        },
        {
          label: 'Save',
          accelerator: 'CmdOrCtrl+S',
          click: function() { saveFile(); },
          enabled: false,
          id: 'save'
        },
        {
          label: 'Save As..',
          accelerator: 'Shift+CmdOrCtrl+S',
          click: function() { saveFileAs(); }
        },
        {
          label: 'Export as Datapackage',
          accelerator: 'CmdOrCtrl+D',
          click: function() { datapackage.exportDatapackage(); }
        }
      ]
    },
    {
      label: 'Edit',
      submenu: [
        {
          label: 'Undo',
          accelerator: 'CmdOrCtrl+Z',
          selector: 'undo:'
        },
        {
          label: 'Redo',
          accelerator: 'Shift+CmdOrCtrl+Z',
          selector: 'redo:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Cut',
          accelerator: 'CmdOrCtrl+X',
          selector: 'cut:'
        },
        {
          label: 'Copy',
          accelerator: 'CmdOrCtrl+C',
          selector: 'copy:'
        },
        {
          label: 'Paste',
          accelerator: 'CmdOrCtrl+V',
          selector: 'paste:'
        },
        {
          label: 'Select All',
          accelerator: 'CmdOrCtrl+A',
          selector: 'selectAll:'
        }
      ]
    },
    {

      label: 'Tools',
      submenu: [
        {
          label: 'Validate',
          accelerator: 'Shift+CmdOrCtrl+V',
          click: function() { validateFile(); }
        },
        {
          label: 'Fix Ragged Rows',
          click: function() { fixRaggedRowsFile(); }

        },
        {
          label: 'Generate Header',
          click: function(){ generateSchemaFromHeader(); }
        }
      ]
    },
    {
      label: 'View',
      submenu: [
        {
          label: 'Reload',
          accelerator: 'CmdOrCtrl+R',
          click: function() { BrowserWindow.getFocusedWindow().reload(); }
        },
        {
          label: 'Toggle DevTools',
          accelerator: 'Alt+CmdOrCtrl+I',
          click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
        },
      ]
    },
    {
      label: 'Window',
      submenu: [
        {
          label: 'Minimize',
          accelerator: 'CmdOrCtrl+M',
          selector: 'performMiniaturize:'
        },
        {
          label: 'Close',
          accelerator: 'CmdOrCtrl+W',
          selector: 'performClose:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Bring All to Front',
          selector: 'arrangeInFront:'
        }
      ]
    },
    {
      label: 'Help',
      submenu: []
    }
  ];

  menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);

  // Create the browser window.
  createWindow();
});

function createWindow(data, title) {
  data = typeof data !== 'undefined' ? data : '"","",""';
  title = typeof title !== 'undefined' ? title : "Untitled.csv";

  mainWindow = new BrowserWindow({width: 800, height: 600});

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/comma-chameleon/views/index.html');

  mainWindow.webContents.on('did-finish-load', function() {
    mainWindow.setTitle(title);
    mainWindow.webContents.send('loadData', data);
  });

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
}

function ipcTest(){
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('ipcTest');
}

function openFile() {
    Dialog.showOpenDialog(
        { filters: [
            { name: 'csv files', extensions: ['csv'] },
            { name: 'json schemas', extensions: ['json'] }
        ]}, function (fileNames) {
            if (fileNames === undefined) {
                return;
            } else {
                console.log("the file processed = "+JSON.stringify(fileNames));
                var fileName = fileNames[0];
                Fs.readFile(fileName, 'utf-8', function (err, data) {
                    createWindow(data, fileName);
                    enableSave();
                });
            }
        });
}

function saveFileAs() {
  window = BrowserWindow.getFocusedWindow();
  Dialog.showSaveDialog({ filters: [
    { name: 'text', extensions: ['csv'] }
  ]}, function (fileName) {
    if (fileName === undefined) return;
    window.webContents.send('saveData', fileName);
    enableSave();
  });
}

function saveFile() {
  window = BrowserWindow.getFocusedWindow();
  fileName = window.getTitle();
  window.webContents.send('saveData', fileName);
}

function enableSave() {
  item = Menu.getApplicationMenu().items[1].submenu.items[5]
  item.enabled = true
}

function importExcel() {
  Dialog.showOpenDialog({ filters: [
    { name: 'text', extensions: ['xlsx', 'xls'] }
  ]}, function (fileNames) {
    if (fileNames === undefined) return;
    var fileName = fileNames[0];
    var workbook = XLSX.readFile(fileName);
    var first_sheet_name = workbook.SheetNames[0];
    var worksheet = workbook.Sheets[first_sheet_name];

    popup = new BrowserWindow({width: 300, height: 150, 'always-on-top': true});
    popup.loadUrl('file://' + __dirname + '/comma-chameleon/views/select_worksheet.html');

    popup.webContents.on('did-finish-load', function() {
      popup.webContents.send('loadSheets', workbook.SheetNames);

      ipc.once('worksheetSelected', function(e, sheet_name) {
        data = XLSX.utils.sheet_to_csv(workbook.Sheets[sheet_name]);
        popup.close();
        createWindow(data);
      });

      ipc.once('worksheetCanceled', function() {
        popup.close();
      });
    });

    popup.on('closed', function() {
      popup = null;
    });
  });
}

// tools

function validateFile() {
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('validate');
}

function generateSchemaFromHeader() {
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('schemaFromHeaders');
}

function fixRaggedRowsFile() {
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('ragged_rows');
}
<commit_msg>Remove dev options<commit_after>var app = require('app');  // Module to control application life.
var request = require('request');
var BrowserWindow = require('browser-window');  // Module to create native browser window.
var Menu = require('menu');
var Dialog = require('dialog');
var Fs = require('fs');
var XLSX = require('xlsx');
var ipc = require('ipc');

var datapackage = require('./browser/datapackage')

// Report crashes to our server.
require('crash-reporter').start();

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is GCed.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', function() {
  var template = [
    {
      label: 'Electron',
      submenu: [
        {
          label: 'About Electron',
          selector: 'orderFrontStandardAboutPanel:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Services',
          submenu: []
        },
        {
          type: 'separator'
        },
        {
          label: 'Hide Electron',
          accelerator: 'CmdOrCtrl+H',
          selector: 'hide:'
        },
        {
          label: 'Hide Others',
          accelerator: 'CmdOrCtrl+Shift+H',
          selector: 'hideOtherApplications:'
        },
        {
          label: 'Show All',
          selector: 'unhideAllApplications:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Quit',
          accelerator: 'CmdOrCtrl+Q',
          selector: 'terminate:'
        },
      ]
    },
    {
      label: 'File',
      submenu: [
        {
          label: 'New',
          accelerator: 'CmdOrCtrl+N',
          click: function() { createWindow(); }
        },
        {
          type: 'separator'
        },
        {
          label: 'Open..',
          accelerator: 'CmdOrCtrl+O',
          click: function() { openFile(); }
        },
        {
          label: 'Import Excel file',
          accelerator: 'CmdOrCtrl+I',
          click: function() { importExcel(); }
        },
        {
          type: 'separator'
        },
        {
          label: 'Save',
          accelerator: 'CmdOrCtrl+S',
          click: function() { saveFile(); },
          enabled: false,
          id: 'save'
        },
        {
          label: 'Save As..',
          accelerator: 'Shift+CmdOrCtrl+S',
          click: function() { saveFileAs(); }
        },
        {
          label: 'Export as Datapackage',
          accelerator: 'CmdOrCtrl+D',
          click: function() { datapackage.exportDatapackage(); }
        }
      ]
    },
    {
      label: 'Edit',
      submenu: [
        {
          label: 'Undo',
          accelerator: 'CmdOrCtrl+Z',
          selector: 'undo:'
        },
        {
          label: 'Redo',
          accelerator: 'Shift+CmdOrCtrl+Z',
          selector: 'redo:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Cut',
          accelerator: 'CmdOrCtrl+X',
          selector: 'cut:'
        },
        {
          label: 'Copy',
          accelerator: 'CmdOrCtrl+C',
          selector: 'copy:'
        },
        {
          label: 'Paste',
          accelerator: 'CmdOrCtrl+V',
          selector: 'paste:'
        },
        {
          label: 'Select All',
          accelerator: 'CmdOrCtrl+A',
          selector: 'selectAll:'
        }
      ]
    },
    {

      label: 'Tools',
      submenu: [
        {
          label: 'Validate',
          accelerator: 'Shift+CmdOrCtrl+V',
          click: function() { validateFile(); }
        },
        {
          label: 'Fix Ragged Rows',
          click: function() { fixRaggedRowsFile(); }

        },
        {
          label: 'Generate Header',
          click: function(){ generateSchemaFromHeader(); }
        }
      ]
    },
    // {
    //   label: 'View',
    //   submenu: [
    //     {
    //       label: 'Reload',
    //       accelerator: 'CmdOrCtrl+R',
    //       click: function() { BrowserWindow.getFocusedWindow().reload(); }
    //     },
    //     {
    //       label: 'Toggle DevTools',
    //       accelerator: 'Alt+CmdOrCtrl+I',
    //       click: function() { BrowserWindow.getFocusedWindow().toggleDevTools(); }
    //     },
    //   ]
    // },
    {
      label: 'Window',
      submenu: [
        {
          label: 'Minimize',
          accelerator: 'CmdOrCtrl+M',
          selector: 'performMiniaturize:'
        },
        {
          label: 'Close',
          accelerator: 'CmdOrCtrl+W',
          selector: 'performClose:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Bring All to Front',
          selector: 'arrangeInFront:'
        }
      ]
    },
    {
      label: 'Help',
      submenu: []
    }
  ];

  menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);

  // Create the browser window.
  createWindow();
});

function createWindow(data, title) {
  data = typeof data !== 'undefined' ? data : '"","",""';
  title = typeof title !== 'undefined' ? title : "Untitled.csv";

  mainWindow = new BrowserWindow({width: 800, height: 600});

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/comma-chameleon/views/index.html');

  mainWindow.webContents.on('did-finish-load', function() {
    mainWindow.setTitle(title);
    mainWindow.webContents.send('loadData', data);
  });

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
}

function ipcTest(){
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('ipcTest');
}

function openFile() {
    Dialog.showOpenDialog(
        { filters: [
            { name: 'csv files', extensions: ['csv'] },
            { name: 'json schemas', extensions: ['json'] }
        ]}, function (fileNames) {
            if (fileNames === undefined) {
                return;
            } else {
                console.log("the file processed = "+JSON.stringify(fileNames));
                var fileName = fileNames[0];
                Fs.readFile(fileName, 'utf-8', function (err, data) {
                    createWindow(data, fileName);
                    enableSave();
                });
            }
        });
}

function saveFileAs() {
  window = BrowserWindow.getFocusedWindow();
  Dialog.showSaveDialog({ filters: [
    { name: 'text', extensions: ['csv'] }
  ]}, function (fileName) {
    if (fileName === undefined) return;
    window.webContents.send('saveData', fileName);
    enableSave();
  });
}

function saveFile() {
  window = BrowserWindow.getFocusedWindow();
  fileName = window.getTitle();
  window.webContents.send('saveData', fileName);
}

function enableSave() {
  item = Menu.getApplicationMenu().items[1].submenu.items[5]
  item.enabled = true
}

function importExcel() {
  Dialog.showOpenDialog({ filters: [
    { name: 'text', extensions: ['xlsx', 'xls'] }
  ]}, function (fileNames) {
    if (fileNames === undefined) return;
    var fileName = fileNames[0];
    var workbook = XLSX.readFile(fileName);
    var first_sheet_name = workbook.SheetNames[0];
    var worksheet = workbook.Sheets[first_sheet_name];

    popup = new BrowserWindow({width: 300, height: 150, 'always-on-top': true});
    popup.loadUrl('file://' + __dirname + '/comma-chameleon/views/select_worksheet.html');

    popup.webContents.on('did-finish-load', function() {
      popup.webContents.send('loadSheets', workbook.SheetNames);

      ipc.once('worksheetSelected', function(e, sheet_name) {
        data = XLSX.utils.sheet_to_csv(workbook.Sheets[sheet_name]);
        popup.close();
        createWindow(data);
      });

      ipc.once('worksheetCanceled', function() {
        popup.close();
      });
    });

    popup.on('closed', function() {
      popup = null;
    });
  });
}

// tools

function validateFile() {
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('validate');
}

function generateSchemaFromHeader() {
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('schemaFromHeaders');
}

function fixRaggedRowsFile() {
  window = BrowserWindow.getFocusedWindow();
  window.webContents.send('ragged_rows');
}
<|endoftext|>


<commit_before>var app = require('app');
var path = require('path');
var BrowserWindow = require('browser-window');
var Shell = require('shell');
var ConfigStore = require('configstore');
var Menu = require('./menu');
var SquirrelWindows = require('./squirrel_windows');

if (SquirrelWindows.handleStartupEvent()) {
  return;
}

var mainWindow = null;
var menu = null;
const host = 'https://www.irccloud.com';
const config = new ConfigStore(app.getName(), {
  'width': 1024,
  'height': 768
});

var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
  // Someone tried to run a second instance, we should focus our window
  if (mainWindow) {
    if (mainWindow.isMinimized()) {
        mainWindow.restore();
    }
    mainWindow.focus();
  }
  return true;
});

if (shouldQuit) {
  app.quit();
  return;
}

function openMainWindow() {
  mainWindow = new BrowserWindow({
    'icon': __dirname + '/icon.png',
    'width': config.get('width'),
    'height': config.get('height'),
    'webPreferences': {
      'allowDisplayingInsecureContent': true,
      'preload': path.join(__dirname, 'preload.js'),
      'nodeIntegration': false
    },
    'title': app.getName()
  });
  mainWindow.loadURL(host);

  mainWindow.on('closed', function() {
    mainWindow = null;
  });

  mainWindow.on('swipe-right', function (e) {
    if (mainWindow.webContents.canGoForward()) {
      mainWindow.webContents.goForward();
    }
  });

  mainWindow.on('swipe-left', function (e) {
    if (mainWindow.webContents.canGoBack()) {
      mainWindow.webContents.goBack();
    }
  });

  mainWindow.on('resize', function() {
    size = mainWindow.getSize();
    config.set({
      'width': size[0],
      'height': size[1]
    });
  });

  mainWindow.on('page-title-updated', function(event) {
      var title = mainWindow.getTitle();
      if (title && process.platform == 'darwin') {
          var unread = "";
          var matches = title.match(/^\((\d+)\)/);
          if (matches) {
            unread = matches[1];
          }
          app.dock.setBadge(unread);
      }
  });

  mainWindow.on('app-command', function (e, cmd) {
    switch (cmd) {
    case 'browser-backward':
      if (mainWindow.webContents.canGoBack()) {
        mainWindow.webContents.goBack();
      }
      break;
    case 'browser-forward':
      if (mainWindow.webContents.canGoForward()) {
        mainWindow.webContents.goForward();
      }
      break;
    case 'browser-refresh':
      mainWindow.webContents.reloadIgnoringCache();
      break;
    default:
      break;
    }
  });

  mainWindow.webContents.on('did-navigate-in-page', function (e, url) {
    var historyMenu = menu.items.find(function (item) {
      return item.id == 'history';
    });
    historyMenu.submenu.items.forEach(function (historyItem) {
      switch (historyItem.id) {
      case 'backMenu':
        historyItem.enabled = mainWindow.webContents.canGoBack();
        break;
      case 'fwdMenu':
        historyItem.enabled = mainWindow.webContents.canGoForward();
        break;
      default:
        break;
      }
    });
  });

  mainWindow.webContents.on('new-window', function(event, url, frameName, disposition) {
      event.preventDefault();
      Shell.openExternal(url);
  });
}

app.on('activate-with-no-open-windows', openMainWindow);
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  menu = Menu.setup(app, host);
  openMainWindow();
});
<commit_msg>use path.join for icon<commit_after>var app = require('app');
var path = require('path');
var BrowserWindow = require('browser-window');
var Shell = require('shell');
var ConfigStore = require('configstore');
var Menu = require('./menu');
var SquirrelWindows = require('./squirrel_windows');

if (SquirrelWindows.handleStartupEvent()) {
  return;
}

var mainWindow = null;
var menu = null;
const host = 'https://www.irccloud.com';
const config = new ConfigStore(app.getName(), {
  'width': 1024,
  'height': 768
});

var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
  // Someone tried to run a second instance, we should focus our window
  if (mainWindow) {
    if (mainWindow.isMinimized()) {
        mainWindow.restore();
    }
    mainWindow.focus();
  }
  return true;
});

if (shouldQuit) {
  app.quit();
  return;
}

function openMainWindow() {
  mainWindow = new BrowserWindow({
    'icon': path.join(__dirname, 'icon.png'),
    'width': config.get('width'),
    'height': config.get('height'),
    'webPreferences': {
      'allowDisplayingInsecureContent': true,
      'preload': path.join(__dirname, 'preload.js'),
      'nodeIntegration': false
    },
    'title': app.getName()
  });
  mainWindow.loadURL(host);

  mainWindow.on('closed', function() {
    mainWindow = null;
  });

  mainWindow.on('swipe-right', function (e) {
    if (mainWindow.webContents.canGoForward()) {
      mainWindow.webContents.goForward();
    }
  });

  mainWindow.on('swipe-left', function (e) {
    if (mainWindow.webContents.canGoBack()) {
      mainWindow.webContents.goBack();
    }
  });

  mainWindow.on('resize', function() {
    size = mainWindow.getSize();
    config.set({
      'width': size[0],
      'height': size[1]
    });
  });

  mainWindow.on('page-title-updated', function(event) {
      var title = mainWindow.getTitle();
      if (title && process.platform == 'darwin') {
          var unread = "";
          var matches = title.match(/^\((\d+)\)/);
          if (matches) {
            unread = matches[1];
          }
          app.dock.setBadge(unread);
      }
  });

  mainWindow.on('app-command', function (e, cmd) {
    switch (cmd) {
    case 'browser-backward':
      if (mainWindow.webContents.canGoBack()) {
        mainWindow.webContents.goBack();
      }
      break;
    case 'browser-forward':
      if (mainWindow.webContents.canGoForward()) {
        mainWindow.webContents.goForward();
      }
      break;
    case 'browser-refresh':
      mainWindow.webContents.reloadIgnoringCache();
      break;
    default:
      break;
    }
  });

  mainWindow.webContents.on('did-navigate-in-page', function (e, url) {
    var historyMenu = menu.items.find(function (item) {
      return item.id == 'history';
    });
    historyMenu.submenu.items.forEach(function (historyItem) {
      switch (historyItem.id) {
      case 'backMenu':
        historyItem.enabled = mainWindow.webContents.canGoBack();
        break;
      case 'fwdMenu':
        historyItem.enabled = mainWindow.webContents.canGoForward();
        break;
      default:
        break;
      }
    });
  });

  mainWindow.webContents.on('new-window', function(event, url, frameName, disposition) {
      event.preventDefault();
      Shell.openExternal(url);
  });
}

app.on('activate-with-no-open-windows', openMainWindow);
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  menu = Menu.setup(app, host);
  openMainWindow();
});
<|endoftext|>


<commit_before>'use strict';

var electron = require('electron');
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;

// not gc window instance
let mainWindow;

// window all closed
app.on('window-all-closed', function() {
    app.quit();
});

// initial
app.on('ready', function() {
    mainWindow = new BrowserWindow({
        width: 1280,
        height: 720,
        icon: __dirname + '/icons/icon_win_256x256.ico'
    });
    mainWindow.setMenu(null);
    mainWindow.loadURL('file://' + __dirname + '/index.html');

    // if not darwin then close window
    mainWindow.on('closed', function() {
        if(process.platform !== 'darwin'){
            mainWindow = null;
        }
    });

    // darwin only
    if(process.platform === 'darwin'){
        var name = app.getName()
        var template = [{
            label: 'editron',
            submenu: [{
                role: 'undo'
            }, {
                role: 'redo'
            }, {
                type: 'separator'
            }, {
                role: 'cut'
            }, {
                role: 'copy'
            }, {
                role: 'paste'
            }, {
                role: 'pasteandmatchstyle'
            }, {
                role: 'selectall'
            }]
        }, {
            label: 'developer',
            submenu: [{
                label: 'developer tools',
                accelerator: 'Alt+Command+I',
                click (item, focusedWindow){
                    if(focusedWindow){
                        focusedWindow.webContents.toggleDevTools();
                    }
                }
            }]
        }];
        var menu = electron.Menu.buildFromTemplate(template)
        electron.Menu.setApplicationMenu(menu)
    }
});
<commit_msg>Responded to the change that the default value of "nodeIntegration" parameter in electron 5.x.<commit_after>'use strict';

var electron = require('electron');
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;

// not gc window instance
let mainWindow;

// window all closed
app.on('window-all-closed', function() {
    app.quit();
});

// initial
app.on('ready', function() {
    mainWindow = new BrowserWindow({
        width: 1280,
        height: 720,
        icon: __dirname + '/icons/icon_win_256x256.ico',
        webPreferences: {
            nodeIntegration: true
        }
    });
    mainWindow.setMenu(null);
    mainWindow.loadURL('file://' + __dirname + '/index.html');

    // if not darwin then close window
    mainWindow.on('closed', function() {
        if(process.platform !== 'darwin'){
            mainWindow = null;
        }
    });

    // darwin only
    if(process.platform === 'darwin'){
        var name = app.getName()
        var template = [{
            label: 'editron',
            submenu: [{
                role: 'undo'
            }, {
                role: 'redo'
            }, {
                type: 'separator'
            }, {
                role: 'cut'
            }, {
                role: 'copy'
            }, {
                role: 'paste'
            }, {
                role: 'pasteandmatchstyle'
            }, {
                role: 'selectall'
            }]
        }, {
            label: 'developer',
            submenu: [{
                label: 'developer tools',
                accelerator: 'Alt+Command+I',
                click (item, focusedWindow){
                    if(focusedWindow){
                        focusedWindow.webContents.toggleDevTools();
                    }
                }
            }]
        }];
        var menu = electron.Menu.buildFromTemplate(template)
        electron.Menu.setApplicationMenu(menu)
    }
});
<|endoftext|>


<commit_before>const {app, BrowserWindow, ipcMain, dialog} = require('electron')
const log = require('electron-log');
const {autoUpdater} = require("electron-updater");

const path = require('path')
const url = require('url')

autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
log.info('App starting...');

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function sendStatusToWindow(text) {
  log.info(text);
  mainWindow.webContents.send('message', text);
}

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 450,
    height: 350,
    minWidth: 450,
    minHeight: 350,
    icon: path.join(__dirname, 'assets/icons/png/64x64.png')
  })

  // and load the index.html of the app.
  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  // Open the DevTools.
  // if (NODE_ENV && NODE_ENV == 'development') {
  //   mainWindow.webContents.openDevTools()
  // }
  mainWindow.setMenu(null);

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
    app.quit();
  })

  return mainWindow;
}

autoUpdater.on('checking-for-update', () => {
  sendStatusToWindow('Checking for update...');
})
autoUpdater.on('update-available', (ev, info) => {
  sendStatusToWindow('Update available.', info);
  mainWindow.webContents.send('updateReady');
})
autoUpdater.on('update-not-available', (ev, info) => {
  sendStatusToWindow('Update not available.');
})
autoUpdater.on('error', (ev, err) => {
  sendStatusToWindow('Error in auto-updater.');
})
autoUpdater.on('download-progress', (ev, progressObj) => {
  sendStatusToWindow('Download progress...');
})
autoUpdater.on('update-downloaded', (ev, info) => {
  sendStatusToWindow('Update downloaded');
});

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
  createWindow();
})

// when the update has been downloaded and is ready to be installed, notify the BrowserWindow
/*
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {
    mainWindow.webContents.send('updateReady')
    const dialogOpts = {
        type: 'info',
        buttons: ['Restart', 'Later'],
        title: 'Application Update',
        message: process.platform === 'win32' ? releaseNotes : releaseName,
        detail: 'A new version has been downloaded. Restart the application to apply the updates.'
      }

      dialog.showMessageBox(dialogOpts, (response) => {
        if (response === 0) autoUpdater.quitAndInstall()
      })
});

// when receiving a quitAndInstall signal, quit and install the new version ;)
ipcMain.on("quitAndInstall", (event, arg) => {
    autoUpdater.quitAndInstall();
})
*/

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})

app.on('ready', function()  {
  setInterval(() => {
    autoUpdater.checkForUpdates()
  }, 60000)
  autoUpdater.checkForUpdates()
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<commit_msg><commit_after>const {app, BrowserWindow, ipcMain, dialog} = require('electron');
const log = require('electron-log');
const {autoUpdater} = require("electron-updater");

const path = require('path');
const url = require('url');

console.log(app.getName());

autoUpdater.logger = log;
autoUpdater.logger.transports.file.level = 'info';
log.info('App starting...');

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function sendStatusToWindow(text) {
  log.info(text);
  mainWindow.webContents.send('message', text);
}

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 450,
    height: 350,
    minWidth: 450,
    minHeight: 350,
    icon: path.join(__dirname, 'assets/icons/png/64x64.png')
  });

  // and load the index.html of the app.
  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }));

  // Open the DevTools.
  // if (NODE_ENV && NODE_ENV == 'development') {
  //   mainWindow.webContents.openDevTools()
  // }
  mainWindow.setMenu(null);

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
    app.quit();
  });

  return mainWindow;
}

autoUpdater.on('checking-for-update', () => {
  sendStatusToWindow('Checking for update...');
});
autoUpdater.on('update-available', (ev, info) => {
  sendStatusToWindow('Update available.', info);
  mainWindow.webContents.send('updateReady');
});
autoUpdater.on('update-not-available', (ev, info) => {
  sendStatusToWindow('Update not available.');
});
autoUpdater.on('error', (ev, err) => {
  sendStatusToWindow('Error in auto-updater.');
});
autoUpdater.on('download-progress', (ev, progressObj) => {
  sendStatusToWindow('Download progress...');
});
autoUpdater.on('update-downloaded', (ev, info) => {
  sendStatusToWindow('Update downloaded');
});

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
  createWindow();
});

// when the update has been downloaded and is ready to be installed, notify the BrowserWindow
/*
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName) => {
    mainWindow.webContents.send('updateReady')
    const dialogOpts = {
        type: 'info',
        buttons: ['Restart', 'Later'],
        title: 'Application Update',
        message: process.platform === 'win32' ? releaseNotes : releaseName,
        detail: 'A new version has been downloaded. Restart the application to apply the updates.'
      }

      dialog.showMessageBox(dialogOpts, (response) => {
        if (response === 0) autoUpdater.quitAndInstall()
      })
});

// when receiving a quitAndInstall signal, quit and install the new version ;)
ipcMain.on("quitAndInstall", (event, arg) => {
    autoUpdater.quitAndInstall();
})
*/

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  }
});

app.on('ready', function()  {
  setInterval(() => {
    autoUpdater.checkForUpdates();
  }, 60000);
  autoUpdater.checkForUpdates();
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<|endoftext|>


<commit_before>'use strict';
const os = require('os');
const path = require('path');
const {app, BrowserWindow, dialog, shell, Menu} = require('electron');
const isDev = require('electron-is-dev');

const {sendToBrowser} = require('./utils');

const appName = app.getName();
const appVersion = app.getVersion();

/*
 *   Mac (macOS only)
 */
const macTemplate = {
    label: `${app.getName()}`,
    submenu: [
        {
            role: 'about'
        }, {
            type: 'separator'
        }, {
            label: 'Preferences...',
            accelerator: 'Cmd+,',
            click() {
                sendToBrowser('show-preferences');
            }
        }, {
            label: 'Accounts...',
            click() {
                sendToBrowser('show-accounts');
            }
        }, {
            type: 'separator'
        }, {
            label: 'Logout',
            click() {
                sendToBrowser('logout');
            }
        }, {
            type: 'separator'
        }, {
            role: 'services',
            submenu: []
        }, {
            type: 'separator'
        }, {
            role: 'hide'
        }, {
            role: 'hideothers'
        }, {
            role: 'unhide'
        }, {
            type: 'separator'
        }, {
            role: 'quit'
        }
    ]
};

/*
 *   File (Windows / Linux only)
 */
const fileTemplate = {
    label: 'File',
    submenu: [
        {
            label: 'Preferences...',
            accelerator: 'Ctrl+,',
            click() {
                sendToBrowser('show-preferences');
            }
        }, {
            label: 'Accounts...',
            click() {
                sendToBrowser('show-accounts');
            }
        }, {
            type: 'separator'
        }, {
            label: 'Logout',
            click() {
                sendToBrowser('logout');
            }
        }, {
            type: 'separator'
        }, {
            role: 'quit'
        }
    ]
};

/*
 *   View
 */
const viewTemplate = [{
    label: 'By Week',
    accelerator: 'CmdOrCtrl+1',
    click() {
        sendToBrowser('toggle-view', 'week');
    }
}, {
    label: 'By Month',
    accelerator: 'CmdOrCtrl+2',
    click() {
        sendToBrowser('toggle-view', 'month');
    }
}, {
    type: 'separator'
}, {
    label: 'Next',
    accelerator: 'CmdOrCtrl+Right',
    click() {
        sendToBrowser('move-right');
    }
}, {
    label: 'Previous',
    accelerator: 'CmdOrCtrl+Left',
    click() {
        sendToBrowser('move-left');
    }
}, {
    type: 'separator'
}, {
    label: 'Go to Today',
    accelerator: 'CmdOrCtrl+T',
    click() {
        sendToBrowser('move-today');
    }
}, {
    type: 'separator'
}, {
    label: 'Make Text Bigger',
    accelerator: 'CmdOrCtrl+Plus',
    click() {
        sendToBrowser('make-text-bigger');
    }
}, {
    label: 'Make Text Smaller',
    accelerator: 'CmdOrCtrl+-',
    click() {
        sendToBrowser('make-text-smaller');
    }
}, {
    label: 'Reset Text Size',
    accelerator: 'CmdOrCtrl+0',
    click() {
        sendToBrowser('reset-text-size');
    }
}, {
    type: 'separator'
}, {
    type: 'checkbox',
    label: 'Show Calendars',
    checked: true,
    accelerator: 'CmdOrCtrl+Shift+S',
    click() {
        sendToBrowser('toggle-calendars');
    }
}, {
    type: 'checkbox',
    label: 'Show Notifications',
    checked: false,
    click() {
        sendToBrowser('toggle-notifications');
    }
}, {
    type: 'separator'
}, {
    label: 'Sync Calendars',
    accelerator: 'CmdOrCtrl+R',
    click() {
        sendToBrowser('sync-calendars');
    }
}, {
    label: 'Reload Kin',
    accelerator: 'CmdOrCtrl+Shift+R',
    click() {
        const [win] = BrowserWindow.getAllWindows();
        win.reload();
    }
}, {
    type: 'separator'
}, {
    role: 'togglefullscreen'
}];

if (isDev) {
    viewTemplate.push({
        type: 'separator'
    }, {
        role: 'toggledevtools'
    });
}

/*
 *   Window
 */
const windowTemplate = [{
    role: 'close'
}, {
    role: 'minimize'
}, {
    type: 'separator'
}, {
    label: 'Open in Browser',
    accelerator: 'CmdOrCtrl+o',
    click() {
        shell.openExternal('https://calendar.kin.today/');
    }
}, {
    type: 'separator'
}, {
    role: 'front'
}];

/*
 *   Help
 */
const helpTemplate = [{
    label: `${appName} Website`,
    click() {
        shell.openExternal('https://kin.today/');
    }
}, {
    label: 'Report an Issue…',
    click() {
        const body = `
<!-- Please succinctly describe your issue and steps to reproduce it. -->

-

${appName} ${appVersion}
Electron ${process.versions.electron}
${process.platform} ${process.arch} ${os.release()}`;

        shell.openExternal(`https://github.com/arbourd/kin-desktop/issues/new?body=${encodeURIComponent(body)}`);
    }
}];

if (process.platform !== 'darwin') {
    helpTemplate.push({
        type: 'separator'
    }, {
        role: 'about',
        click() {
            dialog.showMessageBox({
                title: `About ${appName}`,
                message: `${appName} ${appVersion}`,
                detail: 'Created by Dylan Arbour',
                icon: path.join(__dirname, 'assets/icon.png')
            });
        }
    });
}

/*
 *   Main
 */
const template = [{
    role: 'editMenu'
}, {
    label: 'View',
    submenu: viewTemplate
}, {
    label: 'Window',
    submenu: windowTemplate
}, {
    role: 'help',
    submenu: helpTemplate
}];

if (process.platform === 'darwin') {
    template.unshift(macTemplate);
} else {
    template.unshift(fileTemplate);
}

module.exports = Menu.buildFromTemplate(template);
<commit_msg>Use built-in over custom role<commit_after>'use strict';
const os = require('os');
const path = require('path');
const {app, dialog, shell, Menu} = require('electron');
const isDev = require('electron-is-dev');

const {sendToBrowser} = require('./utils');

const appName = app.getName();
const appVersion = app.getVersion();

/*
 *   Mac (macOS only)
 */
const macTemplate = {
    label: `${app.getName()}`,
    submenu: [
        {
            role: 'about'
        }, {
            type: 'separator'
        }, {
            label: 'Preferences...',
            accelerator: 'Cmd+,',
            click() {
                sendToBrowser('show-preferences');
            }
        }, {
            label: 'Accounts...',
            click() {
                sendToBrowser('show-accounts');
            }
        }, {
            type: 'separator'
        }, {
            label: 'Logout',
            click() {
                sendToBrowser('logout');
            }
        }, {
            type: 'separator'
        }, {
            role: 'services',
            submenu: []
        }, {
            type: 'separator'
        }, {
            role: 'hide'
        }, {
            role: 'hideothers'
        }, {
            role: 'unhide'
        }, {
            type: 'separator'
        }, {
            role: 'quit'
        }
    ]
};

/*
 *   File (Windows / Linux only)
 */
const fileTemplate = {
    label: 'File',
    submenu: [
        {
            label: 'Preferences...',
            accelerator: 'Ctrl+,',
            click() {
                sendToBrowser('show-preferences');
            }
        }, {
            label: 'Accounts...',
            click() {
                sendToBrowser('show-accounts');
            }
        }, {
            type: 'separator'
        }, {
            label: 'Logout',
            click() {
                sendToBrowser('logout');
            }
        }, {
            type: 'separator'
        }, {
            role: 'quit'
        }
    ]
};

/*
 *   View
 */
const viewTemplate = [{
    label: 'By Week',
    accelerator: 'CmdOrCtrl+1',
    click() {
        sendToBrowser('toggle-view', 'week');
    }
}, {
    label: 'By Month',
    accelerator: 'CmdOrCtrl+2',
    click() {
        sendToBrowser('toggle-view', 'month');
    }
}, {
    type: 'separator'
}, {
    label: 'Next',
    accelerator: 'CmdOrCtrl+Right',
    click() {
        sendToBrowser('move-right');
    }
}, {
    label: 'Previous',
    accelerator: 'CmdOrCtrl+Left',
    click() {
        sendToBrowser('move-left');
    }
}, {
    type: 'separator'
}, {
    label: 'Go to Today',
    accelerator: 'CmdOrCtrl+T',
    click() {
        sendToBrowser('move-today');
    }
}, {
    type: 'separator'
}, {
    label: 'Make Text Bigger',
    accelerator: 'CmdOrCtrl+Plus',
    click() {
        sendToBrowser('make-text-bigger');
    }
}, {
    label: 'Make Text Smaller',
    accelerator: 'CmdOrCtrl+-',
    click() {
        sendToBrowser('make-text-smaller');
    }
}, {
    label: 'Reset Text Size',
    accelerator: 'CmdOrCtrl+0',
    click() {
        sendToBrowser('reset-text-size');
    }
}, {
    type: 'separator'
}, {
    type: 'checkbox',
    label: 'Show Calendars',
    checked: true,
    accelerator: 'CmdOrCtrl+Shift+S',
    click() {
        sendToBrowser('toggle-calendars');
    }
}, {
    type: 'checkbox',
    label: 'Show Notifications',
    checked: false,
    click() {
        sendToBrowser('toggle-notifications');
    }
}, {
    type: 'separator'
}, {
    label: 'Sync Calendars',
    accelerator: 'CmdOrCtrl+R',
    click() {
        sendToBrowser('sync-calendars');
    }
}, {
    role: 'reload',
    label: 'Reload Kin',
    accelerator: 'CmdOrCtrl+Shift+R'
}, {
    type: 'separator'
}, {
    role: 'togglefullscreen'
}];

if (isDev) {
    viewTemplate.push({
        type: 'separator'
    }, {
        role: 'toggledevtools'
    });
}

/*
 *   Window
 */
const windowTemplate = [{
    role: 'close'
}, {
    role: 'minimize'
}, {
    type: 'separator'
}, {
    label: 'Open in Browser',
    accelerator: 'CmdOrCtrl+o',
    click() {
        shell.openExternal('https://calendar.kin.today/');
    }
}, {
    type: 'separator'
}, {
    role: 'front'
}];

/*
 *   Help
 */
const helpTemplate = [{
    label: `${appName} Website`,
    click() {
        shell.openExternal('https://kin.today/');
    }
}, {
    label: 'Report an Issue…',
    click() {
        const body = `
<!-- Please succinctly describe your issue and steps to reproduce it. -->

-

${appName} ${appVersion}
Electron ${process.versions.electron}
${process.platform} ${process.arch} ${os.release()}`;

        shell.openExternal(`https://github.com/arbourd/kin-desktop/issues/new?body=${encodeURIComponent(body)}`);
    }
}];

if (process.platform !== 'darwin') {
    helpTemplate.push({
        type: 'separator'
    }, {
        role: 'about',
        click() {
            dialog.showMessageBox({
                title: `About ${appName}`,
                message: `${appName} ${appVersion}`,
                detail: 'Created by Dylan Arbour',
                icon: path.join(__dirname, 'assets/icon.png')
            });
        }
    });
}

/*
 *   Main
 */
const template = [{
    role: 'editMenu'
}, {
    label: 'View',
    submenu: viewTemplate
}, {
    label: 'Window',
    submenu: windowTemplate
}, {
    role: 'help',
    submenu: helpTemplate
}];

if (process.platform === 'darwin') {
    template.unshift(macTemplate);
} else {
    template.unshift(fileTemplate);
}

module.exports = Menu.buildFromTemplate(template);
<|endoftext|>


<commit_before>update
update
<commit_msg>update<commit_after><|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.notification.email',
  name: 'EmailTemplate',

  documentation: 'Represents an email template',

  javaImports: [
    'java.nio.charset.StandardCharsets'
  ],

  ids: [ 'name' ],

  tableColumns: [ 'name' ],

  properties: [
    {
      class: 'String',
      name: 'name',
      documentation: 'Template name'
    },
    {
      class: 'String',
      name: 'body',
      documentation: 'Template body',
      view: { class: 'foam.u2.tag.TextArea', rows: 40, cols: 150 },
      javaSetter:
`body_ = val;
bodyIsSet_ = true;
bodyAsByteArray_ = null;
bodyAsByteArrayIsSet_ = false;`
    },
    {
      class: 'Array',
      name: 'bodyAsByteArray',
      hidden: true,
      transient: true,
      javaType: 'byte[]',
      javaFactory: 'return getBody() != null ? getBody().getBytes(StandardCharsets.UTF_8) : null;'
    }
  ]
});<commit_msg>Add group property to EmailTemplate.<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.nanos.notification.email',
  name: 'EmailTemplate',

  documentation: 'Represents an email template',

  javaImports: [
    'java.nio.charset.StandardCharsets'
  ],

  tableColumns: [ 'name', 'group' ],

  properties: [
    {
      class: 'Long',
      name: 'id'
    },
    {
      class: 'String',
      name: 'name',
      documentation: 'Template name'
    },
    {
      class: 'String',
      name: 'group',
      value: '*'
    },
    {
      class: 'String',
      name: 'body',
      documentation: 'Template body',
      view: { class: 'foam.u2.tag.TextArea', rows: 40, cols: 150 },
      javaSetter:
`body_ = val;
bodyIsSet_ = true;
bodyAsByteArray_ = null;
bodyAsByteArrayIsSet_ = false;`
    },
    {
      class: 'Array',
      name: 'bodyAsByteArray',
      hidden: true,
      transient: true,
      javaType: 'byte[]',
      javaFactory: 'return getBody() != null ? getBody().getBytes(StandardCharsets.UTF_8) : null;'
    }
  ]
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { storiesOf } from '@storybook/react';

import { Grommet, Box, RangeSelector, Stack, Text } from 'grommet';
import { grommet } from 'grommet/themes';
import { deepMerge } from 'grommet/utils';

const customThemeRangeSelector = deepMerge(grommet, {
  global: {
    borderSize: {
      small: '6px',
    },
    edgeSize: {
      small: '13px',
    },
    spacing: '10px',
    colors: {
      control: 'accent-2',
      border: 'brand',
    },
  },
  rangeSelector: {
    background: {
      invert: {
        color: 'brand',
      },
    },
    edge: {
      type: 'bar',
    },
  },
});
class CustomRangeSelector extends Component {
  static defaultProps = {
    direction: 'horizontal',
  };

  state = { values: [12, 16] };

  onChange = values => this.setState({ values });

  render() {
    const { direction, ...rest } = this.props;
    const { values } = this.state;
    return (
      <Grommet theme={customThemeRangeSelector}>
        <Box align="center" pad="large">
          <Stack>
            <Box
              direction={direction === 'vertical' ? 'column' : 'row'}
              justify="between"
            >
              {[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map(value => (
                <Box
                  key={value}
                  width="xxsmall"
                  height="xxsmall"
                  align="center"
                  pad="small"
                  border={false}
                >
                  <Text style={{ fontFamily: 'monospace' }}>{value}</Text>
                </Box>
              ))}
            </Box>
            <RangeSelector
              invert
              direction={direction}
              min={10}
              max={20}
              size="full"
              values={values}
              onChange={this.onChange}
              {...rest}
            />
          </Stack>
        </Box>
      </Grommet>
    );
  }
}

storiesOf('RangeSelector', module).add('Custom', () => <CustomRangeSelector />);
<commit_msg>Refactor RangeSelector Custom Story to use Hooks (#3421)<commit_after>import React, { useState } from 'react';
import { storiesOf } from '@storybook/react';

import { Grommet, Box, RangeSelector, Stack, Text } from 'grommet';
import { grommet } from 'grommet/themes';
import { deepMerge } from 'grommet/utils';

const customThemeRangeSelector = deepMerge(grommet, {
  global: {
    borderSize: {
      small: '6px',
    },
    edgeSize: {
      small: '13px',
    },
    spacing: '10px',
    colors: {
      control: 'accent-2',
      border: 'brand',
    },
  },
  rangeSelector: {
    background: {
      invert: {
        color: 'brand',
      },
    },
    edge: {
      type: 'bar',
    },
  },
});

const CustomRangeSelector = ({ direction = 'horizontal', ...rest }) => {
  const [range, setRange] = useState([12, 16]);
  const onChange = values => {
    setRange(values);
  };

  return (
    <Grommet theme={customThemeRangeSelector}>
      <Box align="center" pad="large">
        <Stack>
          <Box
            direction={direction === 'vertical' ? 'column' : 'row'}
            justify="between"
          >
            {[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].map(value => (
              <Box
                key={value}
                width="xxsmall"
                height="xxsmall"
                align="center"
                pad="small"
                border={false}
              >
                <Text style={{ fontFamily: 'monospace' }}>{value}</Text>
              </Box>
            ))}
          </Box>
          <RangeSelector
            invert
            direction={direction}
            min={10}
            max={20}
            size="full"
            values={range}
            onChange={onChange}
            {...rest}
          />
        </Stack>
      </Box>
    </Grommet>
  );
};

storiesOf('RangeSelector', module).add('Custom', () => <CustomRangeSelector />);
<|endoftext|>


<commit_before>import React from "react";
import Template from "../../core/Template";
import Wizard from "../base/Wizard";
import DataError from "../base/DataError";

function encodeTextCollection(text, separator) {
    let items = text.split(separator);

    // Remove whitespace and empty elements
    items = items.map((item) => item.trim()).filter((item) => item !== "");

    if (items.length === 0) {
        // Special value to signal no elements, because proto can't differentiate
        // between default value and empty collection…
        return [
            {
                name: ""
            }
        ];
    }

    return items.map((item) => {
        return {
            name: item
        };
    });
}

/**
 * @author Niklas Keller
 */
class ExperimentWizard extends Wizard {
    constructor() {
        super();

        this.state = Object.assign(this.state || {}, {
            algorithms: {
                taskChooserAlgorithms: [],
                ratingQualityAlgorithms: [],
                answerQualityAlgorithms: []
            }
        });
    }

    componentDidMount() {
        super.componentDidMount();
        this.fetchAlgorithms();

        if (this.props.location.state && "experiment" in this.props.location.state) {
            let form = Wizard.decodeForm(this.props.location.state.experiment, this.getForm(), this.getDefaultForm());
            delete form.id;

            this.setState({
                form: form,
                data: form,
                loaded: true,
                failed: false
            });
        } else if (this.props.location.state && "template" in this.props.location.state) {
            let template = this.props.location.state.template;
            let form = this.getDefaultForm();

            Object.assign(form, {
                constraints: template.constraints.map(i => i.name).join("\n"),
                tags: template.tags.map(i => i.name).join(", ")
            });

            this.setState({
                form: form
            });
        }
    }

    componentWillReceiveProps(next) {
        super.componentWillReceiveProps(next);

        if (this.props.location.state && "experiment" in this.props.location.state) {
            let form = Wizard.decodeForm(this.props.location.state.experiment, this.getForm(), this.getDefaultForm());
            delete form.id;

            this.setState({
                form: form,
                data: form,
                loaded: true,
                failed: false
            });
        } else if (this.props.location.state && "template" in this.props.location.state) {
            let template = this.props.location.state.template;
            let form = this.getDefaultForm();

            Object.assign(form, {
                constraints: template.constraints.map(i => i.name).join("\n"),
                tags: template.tags.map(i => i.name).join(", ")
            });

            this.setState({
                form: form
            });
        }
    }

    getForm() {
        if (!this.state) {
            return {};
        }

        let base = {
            title: {
                type: "text",
                label: "Title",
                help: "Task name will be published on crowdworking platforms."
            }
        };

        let nonTemplate = {
            description: {
                type: "longtext",
                label: "Description",
                help: "Description of the creative task."
            },
            answerType: {
                type: "enum",
                label: "Answer Type",
                help: "Collect text or images from workers?",
                default: "TEXT",
                values: [
                    {
                        value: "TEXT",
                        text: "Text"
                    },
                    {
                        value: "IMAGE",
                        text: "Images"
                    }
                ]
            },
            placeholders: {
                type: "hidden",
                value: "",
                encoder: () => {
                    return {};
                }
            }
        };

        if (this.state.loaded && !this.state.failed) {
            let isTemplate = this.state.new && this.props.location.state && "template" in this.props.location.state || this.state.data && "templateId" in this.state.data;

            if (isTemplate) {
                let text;

                if (this.state.new && this.props.location.state) {
                    let template;

                    if ("template" in this.props.location.state) {
                        template = this.props.location.state.template;
                    } else if ("experiment" in this.props.location.state) {
                        template = {
                            content: this.props.location.state.experiment.description,
                            answerType: this.props.location.state.experiment.answerType,
                            id: this.props.location.state.experiment.templateId
                        }
                    } else {
                        throw "Invalid state!";
                    }

                    text = template.content;

                    Object.assign(base, {
                        description: {
                            type: "hidden",
                            value: text
                        },
                        answerType: {
                            type: "hidden",
                            value: template.answerType
                        },
                        templateId: {
                            type: "hidden",
                            value: template.id,
                            decoder: (i) => i.value,
                            encoder: (i) => {
                                return {value: parseInt(i)};
                            }
                        }
                    });
                } else {
                    text = this.state.data.description;
                }

                let placeholders = Template.parse(text);

                Object.keys(placeholders).forEach((name) => {
                    base["placeholders[" + name + "]"] = {
                        type: placeholders[name].type,
                        label: name,
                        help: placeholders[name].description
                    };
                });
            } else {
                Object.assign(base, nonTemplate);
            }
        } else {
            Object.assign(base, nonTemplate);
        }

        let algorithmMapper = (chooser) => {
            return {
                value: chooser.name,
                text: chooser.description
            };
        };

        let algorithmOptions = (formName, specName) => {
            let current = this.state.form[formName] ? this.state.form[formName].name : null;
            let availableAlgorithms = this.state.algorithms[specName];

            for (let key in availableAlgorithms) {
                if (availableAlgorithms[key].name !== current) {
                    continue;
                }

                let parameters = availableAlgorithms[key].parameters || [];

                parameters.map((item, i) => {
                    base[formName + "[parameters][" + i + "][id]"] = {
                        type: "hidden",
                        value: item.id,
                        encoder: parseInt
                    };

                    base[formName + "[parameters][" + i + "][value]"] = {
                        type: "text",
                        label: "Parameter", // TODO Add name…
                        help: item.description,
                        validation: {
                            validator: () => {
                                let key = formName + "[parameters][" + i + "][value]";
                                let value = key in this.refs ? this.refs[key].value : "";
                                let regex = new RegExp(item.regex);

                                let state = {};
                                state["validation." + formName + "[parameters][" + i + "][value]"] = value === "" || regex.exec(value) !== null;

                                this.setState(state);
                            },
                            renderer: () => {
                                let valid = this.state["validation." + formName + "[parameters][" + i + "][value]"];

                                if (valid === false) {
                                    return (

                                            Parameter does not match required format: {item.regex}

                                    );
                                }
                            }
                        }
                    };
                });
            }
        };

        base["algorithmTaskChooser[name]"] = {
            type: "enum",
            label: "Task Chooser Algorithm",
            help: "How should tasks be chosen?",
            values: this.state.algorithms.taskChooserAlgorithms.map(algorithmMapper),
        };

        Object.assign(base, algorithmOptions("algorithmTaskChooser", "taskChooserAlgorithms"));

        base["algorithmQualityAnswer[name]"] = {
            type: "enum",
            label: "Answer Quality Algorithm",
            help: "How should the quality of an answer be determined?",
            values: this.state.algorithms.answerQualityAlgorithms.map(algorithmMapper)
        };

        Object.assign(base, algorithmOptions("algorithmQualityAnswer", "answerQualityAlgorithms"));

        base["algorithmQualityRating[name]"] = {
            type: "enum",
            label: "Rating Quality Algorithm",
            help: "How should the quality of a rating be determined?",
            values: this.state.algorithms.ratingQualityAlgorithms.map(algorithmMapper)
        };

        Object.assign(base, algorithmOptions("algorithmQualityRating", "ratingQualityAlgorithms"));

        Object.assign(base, {
            state: {
                type: "hidden",
                value: "DRAFT"
            },
            neededAnswers: {
                type: "number",
                label: "Needed Answers",
                help: "How many creative answers should be collected?",
                default: 10,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            answersPerWorker: {
                type: "number",
                label: "Answers / Worker",
                help: "How many answers should each worker be able to give?",
                default: 3,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            ratingsPerWorker: {
                type: "number",
                label: "Ratings / Worker",
                help: "How many ratings should each worker be able to give?",
                default: 3,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            ratingsPerAnswer: {
                type: "number",
                label: "Ratings / Answer",
                help: "How many ratings should each answer receive?",
                default: 3,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentBase: {
                type: "number",
                label: "Base Payment",
                help: "Basic payment a worker gets for completing a task.",
                unit: "¢ (USD)",
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentAnswer: {
                type: "number",
                label: "Answer Payment",
                help: "Payment for each creative answer.",
                unit: "¢ (USD)",
                default: 10,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentRating: {
                type: "number",
                label: "Rating Payment",
                help: "Payment for each rating.",
                unit: "¢ (USD)",
                default: 10,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentQualityThreshold: {
                type: "number",
                label: "Minimum Quality",
                help: "How good must a task answer be to pay for it?",
                default: 0,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                },
                validation: {
                    validator: () => {
                        let value = parseInt(this.refs.paymentQualityThreshold.value);
                        this.setState({
                            "validation.paymentQualityThreshold": value >= 0 && value <= 9
                        });
                    },
                    renderer: () => {
                        if (!this.state["validation.paymentQualityThreshold"]) {
                            return (

                                    Value must be between 0 and 9.

                            );
                        }
                    }
                }
            },
            ratingOptions: { // TODO: Add editor for rating options, just preserve them for now…
                type: "hidden",
                value: "",
                encoder: (json) => {
                    console.log(json);
                    try {
                        return JSON.parse(json);
                    } catch (e) {
                        console.error(e);
                    }
                },
                decoder: (items) => {
                    if (items.length) {
                        return JSON.stringify(items);
                    } else {
                        return JSON.stringify([
                            {name: "good", value: 10},
                            {name: "bad", value: 0}
                        ]);
                    }
                }
            },
            constraints: {
                type: "longtext",
                label: "Constraints",
                help: "Constraints that should be matched by all creative answers. List one per line.",
                encoder: (text) => encodeTextCollection(text, "\n"),
                decoder: (items) => items.map((item) => item.name).join("\n")
            },
            tags: {
                type: "text",
                label: "Tags",
                help: "Tags helps workers to find this experiment. Separate multiple values with commas.", // TODO
                encoder: (text) => encodeTextCollection(text, ","),
                decoder: (items) => items.map((item) => item.name).join(", ")
            },
            workerQualityThreshold: {
                type: "number",
                label: "Worker Quality Threshold",
                help: "Minimum worker quality to participate in this experiment.",
                default: 0,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: i};
                },
                validation: {
                    validator: () => {
                        let value = parseInt(this.refs.workerQualityThreshold.value);
                        this.setState({
                            "validation.workerQualityThreshold": value >= 0 && value <= 9
                        });
                    },
                    renderer: () => {
                        if (!this.state["validation.workerQualityThreshold"]) {
                            return (

                                    Value must be between 0 and 9.

                            );
                        }
                    }
                }
            }
        });

        return base;
    }

    render() {
        if (this.state.algorithmsFailed) {
            return (
                <DataError />
            );
        }

        return super.render();
    }

    getCollectionUri(query) {
        if (typeof query !== "undefined") {
            return "experiments?" + query;
        }

        return "experiments";
    }

    fetchAlgorithms() {
        this.props.backend.request("GET", "algorithms").then((response) => {
            let form = this.state.form;

            let taskChooser = response.data.taskChooserAlgorithms;
            let ratingQuality = response.data.ratingQualityAlgorithms;
            let answerQuality = response.data.answerQualityAlgorithms;

            delete form["algorithmTaskChooser[name]"];
            delete form["algorithmQualityRating[name]"];
            delete form["algorithmQualityAnswer[name]"];

            Object.assign(form, {
                "algorithmTaskChooser": {
                    name: taskChooser.length ? taskChooser[0].name : ""
                },
                "algorithmQualityRating": {
                    name: ratingQuality.length ? ratingQuality[0].name : ""
                },
                "algorithmQualityAnswer": {
                    name: answerQuality.length ? answerQuality[0].name : ""
                }
            });

            this.setState({
                algorithms: {
                    taskChooserAlgorithms: taskChooser,
                    ratingQualityAlgorithms: ratingQuality,
                    answerQualityAlgorithms: answerQuality
                },
                form: form
            }, () => console.log(this.state));
        }).catch(() => {
            this.setState({
                algorithmsFailed: true
            });
        });
    }
}

export default ExperimentWizard;<commit_msg>Correctly send rating options and template id in experiments<commit_after>import React from "react";
import Template from "../../core/Template";
import Wizard from "../base/Wizard";
import DataError from "../base/DataError";

function encodeTextCollection(text, separator) {
    let items = text.split(separator);

    // Remove whitespace and empty elements
    items = items.map((item) => item.trim()).filter((item) => item !== "");

    if (items.length === 0) {
        // Special value to signal no elements, because proto can't differentiate
        // between default value and empty collection…
        return [
            {
                name: ""
            }
        ];
    }

    return items.map((item) => {
        return {
            name: item
        };
    });
}

/**
 * @author Niklas Keller
 */
class ExperimentWizard extends Wizard {
    constructor() {
        super();

        this.state = Object.assign(this.state || {}, {
            algorithms: {
                taskChooserAlgorithms: [],
                ratingQualityAlgorithms: [],
                answerQualityAlgorithms: []
            }
        });
    }

    componentDidMount() {
        super.componentDidMount();
        this.fetchAlgorithms();

        if (this.props.location.state && "experiment" in this.props.location.state) {
            let form = Wizard.decodeForm(this.props.location.state.experiment, this.getForm(), this.getDefaultForm());
            delete form.id;

            this.setState({
                form: form,
                data: form,
                loaded: true,
                failed: false
            });
        } else if (this.props.location.state && "template" in this.props.location.state) {
            let template = this.props.location.state.template;
            let form = this.getDefaultForm();

            Object.assign(form, {
                constraints: template.constraints.map(i => i.name).join("\n"),
                tags: template.tags.map(i => i.name).join(", ")
            });

            this.setState({
                form: form
            });
        }
    }

    componentWillReceiveProps(next) {
        super.componentWillReceiveProps(next);

        if (this.props.location.state && "experiment" in this.props.location.state) {
            let form = Wizard.decodeForm(this.props.location.state.experiment, this.getForm(), this.getDefaultForm());
            delete form.id;

            this.setState({
                form: form,
                data: form,
                loaded: true,
                failed: false
            });
        } else if (this.props.location.state && "template" in this.props.location.state) {
            let template = this.props.location.state.template;
            let form = this.getDefaultForm();

            Object.assign(form, {
                constraints: template.constraints.map(i => i.name).join("\n"),
                tags: template.tags.map(i => i.name).join(", ")
            });

            this.setState({
                form: form
            });
        }
    }

    getForm() {
        if (!this.state) {
            return {};
        }

        let base = {
            title: {
                type: "text",
                label: "Title",
                help: "Task name will be published on crowdworking platforms."
            }
        };

        let nonTemplate = {
            description: {
                type: "longtext",
                label: "Description",
                help: "Description of the creative task."
            },
            answerType: {
                type: "enum",
                label: "Answer Type",
                help: "Collect text or images from workers?",
                default: "TEXT",
                values: [
                    {
                        value: "TEXT",
                        text: "Text"
                    },
                    {
                        value: "IMAGE",
                        text: "Images"
                    }
                ]
            },
            placeholders: {
                type: "hidden",
                value: "",
                encoder: () => {
                    return {};
                }
            }
        };

        if (this.state.loaded && !this.state.failed) {
            let isTemplate = this.state.new && this.props.location.state && "template" in this.props.location.state || this.state.data && "templateId" in this.state.data;

            if (isTemplate) {
                let text;

                if (this.state.new && this.props.location.state) {
                    let template;

                    if ("template" in this.props.location.state) {
                        template = this.props.location.state.template;
                    } else if ("experiment" in this.props.location.state) {
                        template = {
                            content: this.props.location.state.experiment.description,
                            answerType: this.props.location.state.experiment.answerType,
                            id: this.props.location.state.experiment.templateId
                        }
                    } else {
                        throw "Invalid state!";
                    }

                    text = template.content;

                    Object.assign(base, {
                        description: {
                            type: "hidden",
                            value: text
                        },
                        answerType: {
                            type: "hidden",
                            value: template.answerType
                        },
                        templateId: {
                            type: "hidden",
                            value: template.id,
                            decoder: (i) => i.value,
                            encoder: (i) => {
                                return {value: parseInt(i)};
                            }
                        }
                    });
                } else {
                    text = this.state.data.description;
                }

                let placeholders = Template.parse(text);

                Object.keys(placeholders).forEach((name) => {
                    base["placeholders[" + name + "]"] = {
                        type: placeholders[name].type,
                        label: name,
                        help: placeholders[name].description
                    };
                });
            } else {
                Object.assign(base, nonTemplate);
            }
        } else {
            Object.assign(base, nonTemplate);
        }

        let algorithmMapper = (chooser) => {
            return {
                value: chooser.name,
                text: chooser.description
            };
        };

        let algorithmOptions = (formName, specName) => {
            let current = this.state.form[formName] ? this.state.form[formName].name : null;
            let availableAlgorithms = this.state.algorithms[specName];

            for (let key in availableAlgorithms) {
                if (availableAlgorithms[key].name !== current) {
                    continue;
                }

                let parameters = availableAlgorithms[key].parameters || [];

                parameters.map((item, i) => {
                    base[formName + "[parameters][" + i + "][id]"] = {
                        type: "hidden",
                        value: item.id,
                        encoder: parseInt
                    };

                    base[formName + "[parameters][" + i + "][value]"] = {
                        type: "text",
                        label: "Parameter", // TODO Add name…
                        help: item.description,
                        validation: {
                            validator: () => {
                                let key = formName + "[parameters][" + i + "][value]";
                                let value = key in this.refs ? this.refs[key].value : "";
                                let regex = new RegExp(item.regex);

                                let state = {};
                                state["validation." + formName + "[parameters][" + i + "][value]"] = value === "" || regex.exec(value) !== null;

                                this.setState(state);
                            },
                            renderer: () => {
                                let valid = this.state["validation." + formName + "[parameters][" + i + "][value]"];

                                if (valid === false) {
                                    return (

                                            Parameter does not match required format: {item.regex}

                                    );
                                }
                            }
                        }
                    };
                });
            }
        };

        base["algorithmTaskChooser[name]"] = {
            type: "enum",
            label: "Task Chooser Algorithm",
            help: "How should tasks be chosen?",
            values: this.state.algorithms.taskChooserAlgorithms.map(algorithmMapper),
        };

        Object.assign(base, algorithmOptions("algorithmTaskChooser", "taskChooserAlgorithms"));

        base["algorithmQualityAnswer[name]"] = {
            type: "enum",
            label: "Answer Quality Algorithm",
            help: "How should the quality of an answer be determined?",
            values: this.state.algorithms.answerQualityAlgorithms.map(algorithmMapper)
        };

        Object.assign(base, algorithmOptions("algorithmQualityAnswer", "answerQualityAlgorithms"));

        base["algorithmQualityRating[name]"] = {
            type: "enum",
            label: "Rating Quality Algorithm",
            help: "How should the quality of a rating be determined?",
            values: this.state.algorithms.ratingQualityAlgorithms.map(algorithmMapper)
        };

        Object.assign(base, algorithmOptions("algorithmQualityRating", "ratingQualityAlgorithms"));

        Object.assign(base, {
            state: {
                type: "hidden",
                value: "DRAFT"
            },
            neededAnswers: {
                type: "number",
                label: "Needed Answers",
                help: "How many creative answers should be collected?",
                default: 10,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            answersPerWorker: {
                type: "number",
                label: "Answers / Worker",
                help: "How many answers should each worker be able to give?",
                default: 3,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            ratingsPerWorker: {
                type: "number",
                label: "Ratings / Worker",
                help: "How many ratings should each worker be able to give?",
                default: 3,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            ratingsPerAnswer: {
                type: "number",
                label: "Ratings / Answer",
                help: "How many ratings should each answer receive?",
                default: 3,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentBase: {
                type: "number",
                label: "Base Payment",
                help: "Basic payment a worker gets for completing a task.",
                unit: "¢ (USD)",
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentAnswer: {
                type: "number",
                label: "Answer Payment",
                help: "Payment for each creative answer.",
                unit: "¢ (USD)",
                default: 10,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentRating: {
                type: "number",
                label: "Rating Payment",
                help: "Payment for each rating.",
                unit: "¢ (USD)",
                default: 10,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                }
            },
            paymentQualityThreshold: {
                type: "number",
                label: "Minimum Quality",
                help: "How good must a task answer be to pay for it?",
                default: 0,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: parseInt(i)};
                },
                validation: {
                    validator: () => {
                        let value = parseInt(this.refs.paymentQualityThreshold.value);
                        this.setState({
                            "validation.paymentQualityThreshold": value >= 0 && value <= 9
                        });
                    },
                    renderer: () => {
                        if (!this.state["validation.paymentQualityThreshold"]) {
                            return (

                                    Value must be between 0 and 9.

                            );
                        }
                    }
                }
            },
            ratingOptions: { // TODO: Add editor for rating options, just preserve them for now…
                type: "hidden",
                value: "",
                encoder: (json) => {
                    try {
                        return JSON.parse(json);
                    } catch (e) {
                        return [
                            {
                                name: "good",
                                value: 10
                            },
                            {
                                name: "bad",
                                value: 0
                            }
                        ];
                    }
                },
                decoder: (items) => {
                    if (items && items.length) {
                        return JSON.stringify(items);
                    } else {
                        return JSON.stringify([
                            {
                                name: "good",
                                value: 10
                            },
                            {
                                name: "bad",
                                value: 0
                            }
                        ]);
                    }
                }
            },
            constraints: {
                type: "longtext",
                label: "Constraints",
                help: "Constraints that should be matched by all creative answers. List one per line.",
                encoder: (text) => encodeTextCollection(text, "\n"),
                decoder: (items) => items.map((item) => item.name).join("\n")
            },
            tags: {
                type: "text",
                label: "Tags",
                help: "Tags helps workers to find this experiment. Separate multiple values with commas.", // TODO
                encoder: (text) => encodeTextCollection(text, ","),
                decoder: (items) => items.map((item) => item.name).join(", ")
            },
            templateId: {
                type: "hidden",
                value: "",
                encoder: (i) => {
                    return i ? {value: i} : null;
                },
                decoder: (i) => {
                    return i ? i.value : null;
                }
            },
            workerQualityThreshold: {
                type: "number",
                label: "Worker Quality Threshold",
                help: "Minimum worker quality to participate in this experiment.",
                default: 0,
                decoder: (i) => i.value,
                encoder: (i) => {
                    return {value: i};
                },
                validation: {
                    validator: () => {
                        let value = parseInt(this.refs.workerQualityThreshold.value);
                        this.setState({
                            "validation.workerQualityThreshold": value >= 0 && value <= 9
                        });
                    },
                    renderer: () => {
                        if (!this.state["validation.workerQualityThreshold"]) {
                            return (

                                    Value must be between 0 and 9.

                            );
                        }
                    }
                }
            }
        });

        return base;
    }

    render() {
        if (this.state.algorithmsFailed) {
            return (
                <DataError />
            );
        }

        return super.render();
    }

    getCollectionUri(query) {
        if (typeof query !== "undefined") {
            return "experiments?" + query;
        }

        return "experiments";
    }

    fetchAlgorithms() {
        this.props.backend.request("GET", "algorithms").then((response) => {
            let form = this.state.form;

            let taskChooser = response.data.taskChooserAlgorithms;
            let ratingQuality = response.data.ratingQualityAlgorithms;
            let answerQuality = response.data.answerQualityAlgorithms;

            delete form["algorithmTaskChooser[name]"];
            delete form["algorithmQualityRating[name]"];
            delete form["algorithmQualityAnswer[name]"];

            Object.assign(form, {
                "algorithmTaskChooser": {
                    name: taskChooser.length ? taskChooser[0].name : ""
                },
                "algorithmQualityRating": {
                    name: ratingQuality.length ? ratingQuality[0].name : ""
                },
                "algorithmQualityAnswer": {
                    name: answerQuality.length ? answerQuality[0].name : ""
                }
            });

            this.setState({
                algorithms: {
                    taskChooserAlgorithms: taskChooser,
                    ratingQualityAlgorithms: ratingQuality,
                    answerQualityAlgorithms: answerQuality
                },
                form: form
            }, () => console.log(this.state));
        }).catch(() => {
            this.setState({
                algorithmsFailed: true
            });
        });
    }
}

export default ExperimentWizard;<|endoftext|>


<commit_before>/**
 * @fileOverview Error class.
 * @author Paul Cuthbertson
 * @copyright Gamesys Limited 2013
 */

var luajs = luajs || {};

/**
 * An error that occurs in the Lua code.
 * @constructor
 * @param {string} message Error message.
 */
luajs.Error = function (message) {
	//Error.call (this, message); //AS3 no likey
	this.message = message;
};

luajs.Error.prototype = new Error ();

luajs.Error.catchExecutionError = function (e) {
	//if ((e || {}) instanceof luajs.Error && console) throw new Error ('[luajs] ' + e.message + '\n    ' + (e.luaStack || []).join ('\n    '));
	if (e instanceof luajs.Error) e.message = e.message + '\n    ' + (e.luaStack || []).join('\n    ');

	throw e;
};

/**
 * Coerces the error to a string for logging.
 * @return {string} message Error message.
 */
luajs.Error.prototype.toString = function () {
	return 'Luajs Error: ' + this.message;
};

<commit_msg>Frigg added to overcome the Chromium issue whereby it fails to log errors correctly.<commit_after>/**
 * @fileOverview Error class.
 * @author Paul Cuthbertson
 * @copyright Gamesys Limited 2013
 */

var luajs = luajs || {};

/**
 * An error that occurs in the Lua code.
 * @constructor
 * @param {string} message Error message.
 */
luajs.Error = function (message) {
	//Error.call (this, message); //AS3 no likey
	//this.message = message;

	// The following is an ugly frigg to overcome Chromium bug: https://code.google.com/p/chromium/issues/detail?id=228909
	var err = new Error(message);

	err.constructor = this.constructor;
	err.__proto__ = this;
	err.name = 'luajs.Error';

	return err;
};

luajs.Error.prototype = new Error ();
luajs.Error.prototype.constructor = luajs.Error;

/**
 * Handles error reporting in a consistent manner.
 * @static
 * @param {Error|luajs.Error} e Error that was thown.
 */
luajs.Error.catchExecutionError = function (e) {
	if (!e) return;
	//if ((e || {}) instanceof luajs.Error && console) throw new Error ('[luajs] ' + e.message + '\n    ' + (e.luaStack || []).join ('\n    '));
	if (e instanceof luajs.Error) e.message = e.message + '\n    ' + (e.luaStack || []).join('\n    ');

	throw e;
};

/**
 * Coerces the error to a string for logging.
 * @return {string} String representation of error.
 */
luajs.Error.prototype.toString = function () {
	return 'Luajs Error: ' + this.message;
};<|endoftext|>