<commit_before>//------------------------------------------------------
//-- Tab panel colors for the primary body color schemes
//------------------------------------------------------
// tab panels color together with the primary bg color.
tabPanelDomui = {
	sep: "#7c7c7c",
	inactive_col: '#ffffff',
	active_col: '#67267f',
	hover_inactive_col: '#ffffff',
	hover_active_col: '#4272C8',
	border: undefined,						// jal wtf is this? Without this the tabs render bad... Vladimir?
	border_active: 'transparent',
	img: 'tab-all-domui.png',
	topImg: 'tab-all-top-grey.png',
	arrows: 'tab-scrl-icon.png',
	btm_border: '0px'
};

//---------------------------------------------------------
//-- Data table's colors for the primary body color schemes
//---------------------------------------------------------
dataTableDomui = {
		even_row_bg: "#E5E5E5",
		header_bg: "#7c7c7c",
		header_bg_img: "",
		header_text_color: "#ffffff",
		header_btm_border: "undefined",
		cell_highlight_bg: "#67267f",
		cell_highlight_link_color_bg: "#ffffff",
		font_size: "11px",
		expanding_row_bg: "#efb87c"
};

//--------------------------------
//-- Data pager
//--------------------------------
dataPagerDomui = {
		icons: "data-pager-icons.png",
		icon_width: "32",
		icon_height: "19"
};

//--------------------------------
//-- Primary background selections
//--------------------------------
backgroundMap = new Object();		// REQUIRED NAME - used in VisualThemeEditPage
backgroundMap["domui"] = {
	name: 'Lichtgrijze achtergrond met verloop',
	image: 'bg-body-gray-dithered.png',
	bgcolor: '#ffffff',
	tabPanel: tabPanelDomui,
	dataTable: dataTableDomui,
	dataPager: dataPagerDomui
};

// "theme_body_set" is set in VpThemeFactory from VisualTheme.getBodyColor().
theme_body_set = 'domui';
currentBackground = backgroundMap[theme_body_set];
bg_image = currentBackground.image;
bg_body_color = currentBackground.bgcolor;

//------------------------
//-- Button set selections
//------------------------
buttonMap = new Object();			// REQUIRED NAME - used in VisualThemeEditPage
buttonMap["domui"] = {
	name: 'Blauwe knoppen',
	img: "btn-blue-all.png"
};

button_height=24;
highlight_bg= "#ffbb43";

//------------------------------------------------------------
//-- The tab panel's colors color with the selected background
//------------------------------------------------------------
currentTab = currentBackground.tabPanel;
tab_pnl_img = currentTab.img;
tab_pnl_top_img = currentTab.topImg;
tab_pnl_sep_bg = currentTab.sep;
tab_pnl_inactive_col = currentTab.inactive_col;
tab_pnl_active_col = currentTab.active_col;
tab_pnl_hover_inactive_col = currentTab.hover_inactive_col;
tab_pnl_hover_active_col = currentTab.hover_active_col;
tab_pnl_border_col = currentTab.border;
tab_pnl_active_border_col = currentTab.border_active;
tab_pnl_arrows = currentTab.arrows;
tab_pnl_btm_border = currentTab.btm_border;

//------------------------------------------------------------
//-- The data table's colors.
//------------------------------------------------------------
currentDataTable = currentBackground.dataTable;
data_tbl_even_row_bg = currentDataTable.even_row_bg;
data_tbl_header_bg = currentDataTable.header_bg;
data_tbl_header_bg_img = currentDataTable.header_bg_img;
data_tbl_header_text_color= currentDataTable.header_text_color;
data_tbl_header_btm_border = currentDataTable.header_btm_border;
data_tbl_cell_highlight_bg = currentDataTable.cell_highlight_bg;
data_tbl_cell_highlight_link_color_bg = currentDataTable.cell_highlight_link_color_bg;
data_tbl_font_size = currentDataTable.font_size;
data_tbl_expanding_row_bg = currentDataTable.expanding_row_bg;

//----------------------------
//-- The data pager icons.
//----------------------------
currentDataPager = currentBackground.dataPager;
data_pager_icons = currentDataPager.icons;
data_pager_icon_size_x = currentDataPager.icon_width;
data_pager_icon_size_y = currentDataPager.icon_height;

//-- Main page title gradient
bg_ttl_gradient = "bg-ttl-domui.png";
bg_ttl_end = '#7c7c7c';
bg_ttl_text = '#ffffff';

// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Fix below here and move up.

link_color = "#2200cc";
highlight_bg = "#ffbb43";
highlight2_bg = util.color(highlight_bg).lighter(0.5);

//-- Data table header: make it color "with" the button color set.
dataColorMap = new Object();
dataColorMap["blue"] = "#98bbf3";
dataColorMap["fg-blue"] = "#ffffff";

dataColorMap["fg-sec-ttl-blue"] = "#7FA6EB"; //used for titled section caption

dataColorMap["bg-hdr-ntbl-blue"] = "#6290E2"; //used for nested tables header and combo buttons menu
dataColorMap["fg-sec-ttl-grey"] = "#7FA6EB"; //used for titled section caption

dataColorMap["red"] = "#fba9a2";
dataColorMap["fg-red"] = "#000000";

dataColorMap["bluemetal"] = "#646c83";
dataColorMap["fg-bluemetal"] = "#ffffff";

dataColorMap["grey"] = "#8c8d8f";
dataColorMap["fg-grey"] = "#ffffff";

dataColorMap["mntbl-bgcol-blue"] = "#eeeeee";
dataColorMap["mntbl-bgcol-grey"] = "#dddddd";

bset = "domui";

resourceNameMap = new Object();
resourceNameMap["bg-body-blue"] = "bg-body.png";
resourceNameMap["bg-body-grey"] = "bg-body-grey.png";

resourceNameMap["button_img-blue"] = "btn-blue-all.png";
resourceNameMap["button_img-grey"] = "btn-blue-all.png";

resourceNameMap["sec-sep-img-blue"] = "hr-blue.png";
resourceNameMap["sec-sep-img-grey"] = "hr-blue.png";

resourceNameMap["bg-info-panel-blue"] = "bg-info-pnl.png";

//popup menu table
mntbl_bgcol = dataColorMap["mntbl-bgcol-" + bset];

bg_info_panel = resourceNameMap["bg-info-panel-" + bset];

fg_sec_ttl = dataColorMap["fg-sec-ttl-" + bset];
sec_sep_img = resourceNameMap["sec-sep-img-" + bset];

bg_hdr_ntbl = dataColorMap["bg-hdr-ntbl-" + bset];

//tree menu icons
icon_tree_folder = "btnTreeFold.png";
icon_tree_open_folder = "btnTreeOpen.png";
icon_tree_item = "btnTreeItem.gif";
icon_tree_line_branch = "btnTreeLinelastnode.gif";
icon_tree_line_vertical = "btnTreeLinevertical.gif";

//loading bar. You can use http://ajaxload.info/ for generating them in different colors
resourceNameMap["io-blk-wait-blue"] = "io-blk-wait-blue.gif";
resourceNameMap["io-blk-wait-grey"] = "io-blk-wait.gif";
io_blk_wait = resourceNameMap["io-blk-wait-" + bset];

//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Missing in icon.props.js file
body_image='bg-body-domui.png';
bg_color="#ffffff";
bg2_color="#ffffff";

//-- input bevel: darker grey / lighter grey
bevel_up="#ABADB3";
bevel_down="#BFCDD9";

//-- hovel input bevel for a component: dark blue/light blue
bevel_hover_up="#5794BF";
bevel_hover_down="#D7E8F8";

//-- selected items background
selected_bg="#ff9436";
caption_bg="#f0810a";
readonly_bg="transparent";

error_bg="#a9c5f1";	// red/pink light
error_border="#ff0000"; // red
error_fg="#ff0000"; // red
error_input_bg="#ffe5e5"; // error bg for input component

info_bg="#a9c5f1";		// blueish light
info_fg="blue";
info_border="blue";

header_bg="#7c7c7c";
link_color="#2200cc";	// dark blue

readonly_border="#EEEEEF"; // bit darker grey

warning_bg="#fffeee"; // light yellow
warning_border="yellow";
warning_fg="black";

//-- Bulk upload
upl_runing=highlight_bg;
upl_loading=data_tbl_cell_highlight_bg;
<commit_msg>Sets in orange.color.js are renamed form domui to orange<commit_after>//------------------------------------------------------
//-- Tab panel colors for the primary body color schemes
//------------------------------------------------------
// tab panels color together with the primary bg color.
tabPanelOrange = {
	sep: "#7c7c7c",
	inactive_col: '#ffffff',
	active_col: '#67267f',
	hover_inactive_col: '#ffffff',
	hover_active_col: '#4272C8',
	border: undefined,						// jal wtf is this? Without this the tabs render bad... Vladimir?
	border_active: 'transparent',
	img: 'tab-all-domui.png',
	topImg: 'tab-all-top-grey.png',
	arrows: 'tab-scrl-icon.png',
	btm_border: '0px'
};

//---------------------------------------------------------
//-- Data table's colors for the primary body color schemes
//---------------------------------------------------------
dataTableOrange = {
	even_row_bg : "#E5E5E5",
	header_bg : "#7c7c7c",
	header_bg_img : "",
	header_text_color : "#ffffff",
	header_btm_border : "undefined",
	cell_highlight_bg : "#67267f",
	cell_highlight_link_color_bg : "#ffffff",
	font_size : "11px",
	expanding_row_bg : "#efb87c"
};

//--------------------------------
//-- Data pager
//--------------------------------
dataPagerOrange = {
	icons: "data-pager-icons.png",
	icon_width: "32",
	icon_height: "19"
};

//--------------------------------
//-- Primary background selections
//--------------------------------
backgroundMap = new Object();		// REQUIRED NAME - used in VisualThemeEditPage
backgroundMap["Orange"] = {
	name: 'Lichtgrijze achtergrond met verloop',
	image: 'bg-body-gray-dithered.png',
	bgcolor: '#ffffff',
	tabPanel: tabPanelOrange,
	dataTable: dataTableOrange,
	dataPager: dataPagerOrange,
};

// "theme_body_set" is set in VpThemeFactory from VisualTheme.getBodyColor().
theme_body_set = 'Orange';
currentBackground = backgroundMap[theme_body_set];
bg_image = currentBackground.image;
bg_body_color = currentBackground.bgcolor;

//------------------------
//-- Button set selections
//------------------------
buttonMap = new Object();			// REQUIRED NAME - used in VisualThemeEditPage
buttonMap["Orange"] = {
	name: 'Blauwe knoppen',
	img: "btn-blue-all.png"
};

button_height=24;
highlight_bg= "#ffbb43";

//------------------------------------------------------------
//-- The tab panel's colors color with the selected background
//------------------------------------------------------------
currentTab = currentBackground.tabPanel;
tab_pnl_img = currentTab.img;
tab_pnl_top_img = currentTab.topImg;
tab_pnl_sep_bg = currentTab.sep;
tab_pnl_inactive_col = currentTab.inactive_col;
tab_pnl_active_col = currentTab.active_col;
tab_pnl_hover_inactive_col = currentTab.hover_inactive_col;
tab_pnl_hover_active_col = currentTab.hover_active_col;
tab_pnl_border_col = currentTab.border;
tab_pnl_active_border_col = currentTab.border_active;
tab_pnl_arrows = currentTab.arrows;
tab_pnl_btm_border = currentTab.btm_border;

//------------------------------------------------------------
//-- The data table's colors.
//------------------------------------------------------------
currentDataTable = currentBackground.dataTable;
data_tbl_even_row_bg = currentDataTable.even_row_bg;
data_tbl_header_bg = currentDataTable.header_bg;
data_tbl_header_bg_img = currentDataTable.header_bg_img;
data_tbl_header_text_color= currentDataTable.header_text_color;
data_tbl_header_btm_border = currentDataTable.header_btm_border;
data_tbl_cell_highlight_bg = currentDataTable.cell_highlight_bg;
data_tbl_cell_highlight_link_color_bg = currentDataTable.cell_highlight_link_color_bg;
data_tbl_font_size = currentDataTable.font_size;
data_tbl_expanding_row_bg = currentDataTable.expanding_row_bg;

//----------------------------
//-- The data pager icons.
//----------------------------
currentDataPager = currentBackground.dataPager;
data_pager_icons = currentDataPager.icons;
data_pager_icon_size_x = currentDataPager.icon_width;
data_pager_icon_size_y = currentDataPager.icon_height;

//-- Main page title gradient
bg_ttl_gradient = "bg-ttl-domui.png";
bg_ttl_end = '#7c7c7c';
bg_ttl_text = '#ffffff';

// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Fix below here and move up.

link_color = "#2200cc";
highlight_bg = "#ffbb43";
highlight2_bg = util.color(highlight_bg).lighter(0.5);

//-- Data table header: make it color "with" the button color set.
dataColorMap = new Object();
dataColorMap["blue"] = "#98bbf3";
dataColorMap["fg-blue"] = "#ffffff";

dataColorMap["fg-sec-ttl-blue"] = "#7FA6EB"; //used for titled section caption

dataColorMap["bg-hdr-ntbl-blue"] = "#6290E2"; //used for nested tables header and combo buttons menu
dataColorMap["fg-sec-ttl-grey"] = "#7FA6EB"; //used for titled section caption

dataColorMap["red"] = "#fba9a2";
dataColorMap["fg-red"] = "#000000";

dataColorMap["bluemetal"] = "#646c83";
dataColorMap["fg-bluemetal"] = "#ffffff";

dataColorMap["grey"] = "#8c8d8f";
dataColorMap["fg-grey"] = "#ffffff";

dataColorMap["mntbl-bgcol-blue"] = "#eeeeee";
dataColorMap["mntbl-bgcol-grey"] = "#dddddd";

bset = "Orange";

resourceNameMap = new Object();
resourceNameMap["bg-body-blue"] = "bg-body.png";
resourceNameMap["bg-body-grey"] = "bg-body-grey.png";

resourceNameMap["button_img-blue"] = "btn-blue-all.png";
resourceNameMap["button_img-grey"] = "btn-blue-all.png";

resourceNameMap["sec-sep-img-blue"] = "hr-blue.png";
resourceNameMap["sec-sep-img-grey"] = "hr-blue.png";

resourceNameMap["bg-info-panel-blue"] = "bg-info-pnl.png";

//popup menu table
mntbl_bgcol = dataColorMap["mntbl-bgcol-" + bset];

bg_info_panel = resourceNameMap["bg-info-panel-" + bset];

fg_sec_ttl = dataColorMap["fg-sec-ttl-" + bset];
sec_sep_img = resourceNameMap["sec-sep-img-" + bset];

bg_hdr_ntbl = dataColorMap["bg-hdr-ntbl-" + bset];

//tree menu icons
icon_tree_folder = "btnTreeFold.png";
icon_tree_open_folder = "btnTreeOpen.png";
icon_tree_item = "btnTreeItem.gif";
icon_tree_line_branch = "btnTreeLinelastnode.gif";
icon_tree_line_vertical = "btnTreeLinevertical.gif";

//loading bar. You can use http://ajaxload.info/ for generating them in different colors
resourceNameMap["io-blk-wait-blue"] = "io-blk-wait-blue.gif";
resourceNameMap["io-blk-wait-grey"] = "io-blk-wait.gif";
io_blk_wait = resourceNameMap["io-blk-wait-" + bset];

//vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Missing in icon.props.js file
body_image='bg-body-domui.png';
bg_color="#ffffff";
bg2_color="#ffffff";

//-- input bevel: darker grey / lighter grey
bevel_up="#ABADB3";
bevel_down="#BFCDD9";

//-- hovel input bevel for a component: dark blue/light blue
bevel_hover_up="#5794BF";
bevel_hover_down="#D7E8F8";

//-- selected items background
selected_bg="#ff9436";
caption_bg="#f0810a";
readonly_bg="transparent";

error_bg="#a9c5f1";	// red/pink light
error_border="#ff0000"; // red
error_fg="#ff0000"; // red
error_input_bg="#ffe5e5"; // error bg for input component

info_bg="#a9c5f1";		// blueish light
info_fg="blue";
info_border="blue";

header_bg="#7c7c7c";
link_color="#2200cc";	// dark blue

readonly_border="#EEEEEF"; // bit darker grey

warning_bg="#fffeee"; // light yellow
warning_border="yellow";
warning_fg="black";

//-- Bulk upload
upl_runing=highlight_bg;
upl_loading=data_tbl_cell_highlight_bg;
<|endoftext|>


<commit_before>import { getDocument, getWindow } from 'ssr-window';

function deleteProps(obj) {
  const object = obj;
  Object.keys(object).forEach((key) => {
    try {
      object[key] = null;
    } catch (e) {
      // no getter for object
    }
    try {
      delete object[key];
    } catch (e) {
      // something got wrong
    }
  });
}
function nextTick(callback, delay = 0) {
  return setTimeout(callback, delay);
}
function now() {
  return Date.now();
}
function getComputedStyle(el) {
  const window = getWindow();
  let style;
  if (window.getComputedStyle) {
    style = window.getComputedStyle(el, null);
  }
  if (!style && el.currentStyle) {
    style = el.currentStyle;
  }
  if (!style) {
    style = el.style;
  }

  return style;
}
function getTranslate(el, axis = 'x') {
  const window = getWindow();
  let matrix;
  let curTransform;
  let transformMatrix;

  const curStyle = getComputedStyle(el, null);

  if (window.WebKitCSSMatrix) {
    curTransform = curStyle.transform || curStyle.webkitTransform;
    if (curTransform.split(',').length > 6) {
      curTransform = curTransform
        .split(', ')
        .map((a) => a.replace(',', '.'))
        .join(', ');
    }
    // Some old versions of Webkit choke when 'none' is passed; pass
    // empty string instead in this case
    transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
  } else {
    transformMatrix =
      curStyle.MozTransform ||
      curStyle.OTransform ||
      curStyle.MsTransform ||
      curStyle.msTransform ||
      curStyle.transform ||
      curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
    matrix = transformMatrix.toString().split(',');
  }

  if (axis === 'x') {
    // Latest Chrome and webkits Fix
    if (window.WebKitCSSMatrix) curTransform = transformMatrix.m41;
    // Crazy IE10 Matrix
    else if (matrix.length === 16) curTransform = parseFloat(matrix[12]);
    // Normal Browsers
    else curTransform = parseFloat(matrix[4]);
  }
  if (axis === 'y') {
    // Latest Chrome and webkits Fix
    if (window.WebKitCSSMatrix) curTransform = transformMatrix.m42;
    // Crazy IE10 Matrix
    else if (matrix.length === 16) curTransform = parseFloat(matrix[13]);
    // Normal Browsers
    else curTransform = parseFloat(matrix[5]);
  }
  return curTransform || 0;
}
function isObject(o) {
  return (
    typeof o === 'object' &&
    o !== null &&
    o.constructor &&
    Object.prototype.toString.call(o).slice(8, -1) === 'Object'
  );
}
function isNode(node) {
  // eslint-disable-next-line
  if (typeof window !== 'undefined') {
    return node instanceof HTMLElement;
  }
  return node && (node.nodeType === 1 || node.nodeType === 11);
}
function extend(...args) {
  const to = Object(args[0]);
  const noExtend = ['__proto__', 'constructor', 'prototype'];
  for (let i = 1; i < args.length; i += 1) {
    const nextSource = args[i];
    if (nextSource !== undefined && nextSource !== null && !isNode(nextSource)) {
      const keysArray = Object.keys(Object(nextSource)).filter((key) => noExtend.indexOf(key) < 0);
      for (let nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex += 1) {
        const nextKey = keysArray[nextIndex];
        const desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
        if (desc !== undefined && desc.enumerable) {
          if (isObject(to[nextKey]) && isObject(nextSource[nextKey])) {
            if (nextSource[nextKey].__swiper__) {
              to[nextKey] = nextSource[nextKey];
            } else {
              extend(to[nextKey], nextSource[nextKey]);
            }
          } else if (!isObject(to[nextKey]) && isObject(nextSource[nextKey])) {
            to[nextKey] = {};
            if (nextSource[nextKey].__swiper__) {
              to[nextKey] = nextSource[nextKey];
            } else {
              extend(to[nextKey], nextSource[nextKey]);
            }
          } else {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
    }
  }
  return to;
}

function bindModuleMethods(instance, obj) {
  Object.keys(obj).forEach((key) => {
    if (isObject(obj[key])) {
      Object.keys(obj[key]).forEach((subKey) => {
        if (typeof obj[key][subKey] === 'function') {
          obj[key][subKey] = obj[key][subKey].bind(instance);
        }
      });
    }
    instance[key] = obj[key];
  });
}

function classesToSelector(classes = '') {
  return `.${classes
    .trim()
    .replace(/([\.:\/])/g, '\\$1') // eslint-disable-line
    .replace(/ /g, '.')}`;
}

function createElementIfNotDefined($container, params, createElements, checkProps) {
  const document = getDocument();
  if (createElements) {
    Object.keys(checkProps).forEach((key) => {
      if (!params[key] && params.auto === true) {
        const element = document.createElement('div');
        element.className = checkProps[key];
        $container.append(element);
        params[key] = element;
      }
    });
  }
  return params;
}

export {
  deleteProps,
  nextTick,
  now,
  getTranslate,
  isObject,
  extend,
  bindModuleMethods,
  getComputedStyle,
  classesToSelector,
  createElementIfNotDefined,
};
<commit_msg>fix: fix server side judge (close #4787) (#4788)<commit_after>import { getDocument, getWindow } from 'ssr-window';

function deleteProps(obj) {
  const object = obj;
  Object.keys(object).forEach((key) => {
    try {
      object[key] = null;
    } catch (e) {
      // no getter for object
    }
    try {
      delete object[key];
    } catch (e) {
      // something got wrong
    }
  });
}
function nextTick(callback, delay = 0) {
  return setTimeout(callback, delay);
}
function now() {
  return Date.now();
}
function getComputedStyle(el) {
  const window = getWindow();
  let style;
  if (window.getComputedStyle) {
    style = window.getComputedStyle(el, null);
  }
  if (!style && el.currentStyle) {
    style = el.currentStyle;
  }
  if (!style) {
    style = el.style;
  }

  return style;
}
function getTranslate(el, axis = 'x') {
  const window = getWindow();
  let matrix;
  let curTransform;
  let transformMatrix;

  const curStyle = getComputedStyle(el, null);

  if (window.WebKitCSSMatrix) {
    curTransform = curStyle.transform || curStyle.webkitTransform;
    if (curTransform.split(',').length > 6) {
      curTransform = curTransform
        .split(', ')
        .map((a) => a.replace(',', '.'))
        .join(', ');
    }
    // Some old versions of Webkit choke when 'none' is passed; pass
    // empty string instead in this case
    transformMatrix = new window.WebKitCSSMatrix(curTransform === 'none' ? '' : curTransform);
  } else {
    transformMatrix =
      curStyle.MozTransform ||
      curStyle.OTransform ||
      curStyle.MsTransform ||
      curStyle.msTransform ||
      curStyle.transform ||
      curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
    matrix = transformMatrix.toString().split(',');
  }

  if (axis === 'x') {
    // Latest Chrome and webkits Fix
    if (window.WebKitCSSMatrix) curTransform = transformMatrix.m41;
    // Crazy IE10 Matrix
    else if (matrix.length === 16) curTransform = parseFloat(matrix[12]);
    // Normal Browsers
    else curTransform = parseFloat(matrix[4]);
  }
  if (axis === 'y') {
    // Latest Chrome and webkits Fix
    if (window.WebKitCSSMatrix) curTransform = transformMatrix.m42;
    // Crazy IE10 Matrix
    else if (matrix.length === 16) curTransform = parseFloat(matrix[13]);
    // Normal Browsers
    else curTransform = parseFloat(matrix[5]);
  }
  return curTransform || 0;
}
function isObject(o) {
  return (
    typeof o === 'object' &&
    o !== null &&
    o.constructor &&
    Object.prototype.toString.call(o).slice(8, -1) === 'Object'
  );
}
function isNode(node) {
  // eslint-disable-next-line
  if (typeof window !== 'undefined' && typeof window.HTMLElement !== 'undefined') {
    return node instanceof HTMLElement;
  }
  return node && (node.nodeType === 1 || node.nodeType === 11);
}
function extend(...args) {
  const to = Object(args[0]);
  const noExtend = ['__proto__', 'constructor', 'prototype'];
  for (let i = 1; i < args.length; i += 1) {
    const nextSource = args[i];
    if (nextSource !== undefined && nextSource !== null && !isNode(nextSource)) {
      const keysArray = Object.keys(Object(nextSource)).filter((key) => noExtend.indexOf(key) < 0);
      for (let nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex += 1) {
        const nextKey = keysArray[nextIndex];
        const desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
        if (desc !== undefined && desc.enumerable) {
          if (isObject(to[nextKey]) && isObject(nextSource[nextKey])) {
            if (nextSource[nextKey].__swiper__) {
              to[nextKey] = nextSource[nextKey];
            } else {
              extend(to[nextKey], nextSource[nextKey]);
            }
          } else if (!isObject(to[nextKey]) && isObject(nextSource[nextKey])) {
            to[nextKey] = {};
            if (nextSource[nextKey].__swiper__) {
              to[nextKey] = nextSource[nextKey];
            } else {
              extend(to[nextKey], nextSource[nextKey]);
            }
          } else {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
    }
  }
  return to;
}

function bindModuleMethods(instance, obj) {
  Object.keys(obj).forEach((key) => {
    if (isObject(obj[key])) {
      Object.keys(obj[key]).forEach((subKey) => {
        if (typeof obj[key][subKey] === 'function') {
          obj[key][subKey] = obj[key][subKey].bind(instance);
        }
      });
    }
    instance[key] = obj[key];
  });
}

function classesToSelector(classes = '') {
  return `.${classes
    .trim()
    .replace(/([\.:\/])/g, '\\$1') // eslint-disable-line
    .replace(/ /g, '.')}`;
}

function createElementIfNotDefined($container, params, createElements, checkProps) {
  const document = getDocument();
  if (createElements) {
    Object.keys(checkProps).forEach((key) => {
      if (!params[key] && params.auto === true) {
        const element = document.createElement('div');
        element.className = checkProps[key];
        $container.append(element);
        params[key] = element;
      }
    });
  }
  return params;
}

export {
  deleteProps,
  nextTick,
  now,
  getTranslate,
  isObject,
  extend,
  bindModuleMethods,
  getComputedStyle,
  classesToSelector,
  createElementIfNotDefined,
};
<|endoftext|>


<commit_before>
import chokidar from 'chokidar';
import { debounce } from 'lodash';
import logger from './logger';
import { Defaults } from './resolveConfig';

export default function watch(options, handler) {
	const {
		enable = Defaults.WATCH,
		dirs = Defaults.WATCH_DIRS,
		ignoreDotFiles = Defaults.WATCH_IGNORE_DOT_FILES,
		...other,
	} = options;

	if (!enable) { return; }

	logger.trace('watch enabled');

	if (ignoreDotFiles) {
		logger.trace('watch ignoreDotFiles');
		other.ignored = /(^|[\/\\])\../;
	}

	chokidar.watch(dirs, {
		...other,
		usePolling: true,
		ignoreInitial: true,
	}).on('all', debounce(handler, 1000));
}
<commit_msg>fix watch option empty bug<commit_after>
import chokidar from 'chokidar';
import { debounce } from 'lodash';
import logger from './logger';
import { Defaults } from './resolveConfig';

export default function watch(options = {}, handler) {
	const {
		enable = Defaults.WATCH,
		dirs = Defaults.WATCH_DIRS,
		ignoreDotFiles = Defaults.WATCH_IGNORE_DOT_FILES,
		...other,
	} = options;

	if (!enable) { return; }

	logger.trace('watch enabled');

	if (ignoreDotFiles) {
		logger.trace('watch ignoreDotFiles');
		other.ignored = /(^|[/\\])\../;
	}

	chokidar.watch(dirs, {
		...other,
		usePolling: true,
		ignoreInitial: true,
	}).on('all', debounce(handler, 1000));
}
<|endoftext|>


<commit_before>define(function(require) {

  /**
   * Get the distance between from and to
   */
  function getDistance(from, to) {
    // is this an array?
    if (Object.prototype.toString.call(from) === "[object Array]") {
      from = from[0];
    }

    var dx = from.x - to.x,
        dy = from.y - to.y;

    return Math.sqrt(dx * dx + dy * dy);
  }

  return {

    /**
     * Is from far enough from to according to distance?
     */
    isFarEnough: function(from, to, distance) {
      if (!from || !to) {
        return false;
      }

      return getDistance(from, to) > distance;
    },

    getClosestPoint: function(from, to, distance) {
      if (distance <= 0) {
        return to;
      }

      var dX = to.x - from.x,
          dY = to.y - from.y,
          dH = Math.sqrt(dX * dX + dY * dY),
          expected = dH - distance,
          ratio = expected / dH;

      return {
        x: ratio * dX + from.x,
        y: ratio * dY + from.y
      };
    }

  };

});<commit_msg>if distance is less than and equal to 1, then just add the point<commit_after>// TODO review for performance
define(function(require) {

  /**
   * Get the distance between from and to
   */
  function getDistance(from, to) {
    // is this an array?
    if (Object.prototype.toString.call(from) === "[object Array]") {
      from = from[0];
    }

    var dx = from.x - to.x,
        dy = from.y - to.y;

    return Math.sqrt(dx * dx + dy * dy);
  }

  return {

    /**
     * Is from far enough from to according to distance?
     */
    isFarEnough: function(from, to, distance) {
      if (distance <= 1) {
        return true;
      }

      if (!from || !to) {
        return false;
      }

      return getDistance(from, to) > distance;
    },

    getClosestPoint: function(from, to, distance) {
      if (distance <= 1) {
        return to;
      }

      var dX = to.x - from.x,
          dY = to.y - from.y,
          dH = Math.sqrt(dX * dX + dY * dY),
          expected = dH - distance,
          ratio = expected / dH;

      return {
        x: ratio * dX + from.x,
        y: ratio * dY + from.y
      };
    }

  };

});<|endoftext|>


<commit_before>import path from 'path'
import express from 'express'
import webpack from 'webpack'
import helmet from 'helmet'
import morgan from 'morgan'
import cors from 'cors'
import compression from 'compression'
import bodyParser from 'body-parser'
import { env } from 'process'
import {
  accessSync,
  constants,
  createWriteStream,
  readFileSync
} from 'fs-extra'
import http from 'http'
import https from 'https'
import {
  defaultAppName,
  defaultTypeLog,
  defaultPort,
  defaultWebpackMode,
  defaultApps
} from './utils/constants/defaults'
import {
  validateServerIsSecure,
  getCert,
  getKey,
  genPathResources,
  genFireedgeKey
} from './utils/server'
import {
  entrypoint404,
  entrypointApi,
  entrypointApp
} from './routes/entrypoints'
import { websockets } from './routes/websockets'
import { vmrcUpgrade } from './routes/websockets/vmrc'
import { guacamole } from './routes/websockets/guacamole'
import { messageTerminal, getConfig } from './utils'

// set paths
genPathResources()

// set fireedge_key
genFireedgeKey()

// destructure imports
const unsecureServer = http.createServer
const secureServer = https.createServer

const app = express()
const basename = defaultAppName ? `/${defaultAppName}` : ''

let frontPath = 'client'

// settings
const appConfig = getConfig()
const port = appConfig.port || defaultPort
const userLog = appConfig.log || 'dev'

if (env && env.NODE_ENV && env.NODE_ENV === defaultWebpackMode) {
  // eslint-disable-next-line global-require
  const config = require('../../webpack.config.dev.client')
  const compiler = webpack(config)
  app.use(
    // eslint-disable-next-line global-require
    require('webpack-dev-middleware')(compiler, {
      noInfo: true,
      publicPath: config.output.publicPath,
      stats: {
        assets: false,
        colors: true,
        version: false,
        hash: false,
        timings: false,
        chunks: false,
        chunkModules: false
      }
    })
  )
  // eslint-disable-next-line import/no-extraneous-dependencies
  // eslint-disable-next-line global-require
  app.use(require('webpack-hot-middleware')(compiler))
  frontPath = '../client'
}
let log = morgan('dev')
if (userLog === defaultTypeLog && global && global.FIREEDGE_LOG) {
  try {
    accessSync(global.FIREEDGE_LOG, constants.W_OK)
    const logStream = createWriteStream(global.FIREEDGE_LOG, {
      flags: 'a'
    })
    log = morgan('combined', { stream: logStream })
  } catch (err) {
    const config = {
      color: 'red',
      message: 'Error: %s',
      type: err.message || ''
    }
    messageTerminal(config)
  }
}
app.use(helmet.hidePoweredBy())
app.use(compression())
app.use(`${basename}/client`, express.static(path.resolve(__dirname, frontPath)))

// log request
app.use(log)
// cors
if (appConfig.cors) {
  app.use(cors())
}
// post params parser body
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

app.use(`${basename}/api`, entrypointApi) // opennebula Api routes
const frontApps = Object.keys(defaultApps)
frontApps.map(frontApp => {
  app.get(`${basename}/${frontApp}`, entrypointApp)
  app.get(`${basename}/${frontApp}/*`, entrypointApp)
})
app.get('/*', (req, res) => res.send('index'))
// 404 - public
app.get('*', entrypoint404)

const appServer = validateServerIsSecure()
  ? secureServer(
    {
      key: readFileSync(getKey(), 'utf8'),
      cert: readFileSync(getCert(), 'utf8')
    },
    app
  )
  : unsecureServer(app)

websockets(appServer)

let config = {
  color: 'red',
  message: 'Server no start'
}

appServer.listen(port, '0.0.0.0', err => {
  if (!err) {
    config = {
      color: 'green',
      type: port,
      message: 'Server listen in port %s'
    }
  }
  messageTerminal(config)
})
vmrcUpgrade(appServer)
guacamole(appServer)
<commit_msg>F #3951: redirect to provision app<commit_after>import path from 'path'
import express from 'express'
import webpack from 'webpack'
import helmet from 'helmet'
import morgan from 'morgan'
import cors from 'cors'
import compression from 'compression'
import bodyParser from 'body-parser'
import { env } from 'process'
import {
  accessSync,
  constants,
  createWriteStream,
  readFileSync
} from 'fs-extra'
import http from 'http'
import https from 'https'
import {
  defaultAppName,
  defaultTypeLog,
  defaultPort,
  defaultWebpackMode,
  defaultApps
} from './utils/constants/defaults'
import {
  validateServerIsSecure,
  getCert,
  getKey,
  genPathResources,
  genFireedgeKey
} from './utils/server'
import {
  entrypoint404,
  entrypointApi,
  entrypointApp
} from './routes/entrypoints'
import { websockets } from './routes/websockets'
import { vmrcUpgrade } from './routes/websockets/vmrc'
import { guacamole } from './routes/websockets/guacamole'
import { messageTerminal, getConfig } from './utils'

// set paths
genPathResources()

// set fireedge_key
genFireedgeKey()

// destructure imports
const unsecureServer = http.createServer
const secureServer = https.createServer

const app = express()
const basename = defaultAppName ? `/${defaultAppName}` : ''

let frontPath = 'client'

// settings
const appConfig = getConfig()
const port = appConfig.port || defaultPort
const userLog = appConfig.log || 'dev'

if (env && env.NODE_ENV && env.NODE_ENV === defaultWebpackMode) {
  // eslint-disable-next-line global-require
  const config = require('../../webpack.config.dev.client')
  const compiler = webpack(config)
  app.use(
    // eslint-disable-next-line global-require
    require('webpack-dev-middleware')(compiler, {
      noInfo: true,
      publicPath: config.output.publicPath,
      stats: {
        assets: false,
        colors: true,
        version: false,
        hash: false,
        timings: false,
        chunks: false,
        chunkModules: false
      }
    })
  )
  // eslint-disable-next-line import/no-extraneous-dependencies
  // eslint-disable-next-line global-require
  app.use(require('webpack-hot-middleware')(compiler))
  frontPath = '../client'
}
let log = morgan('dev')
if (userLog === defaultTypeLog && global && global.FIREEDGE_LOG) {
  try {
    accessSync(global.FIREEDGE_LOG, constants.W_OK)
    const logStream = createWriteStream(global.FIREEDGE_LOG, {
      flags: 'a'
    })
    log = morgan('combined', { stream: logStream })
  } catch (err) {
    const config = {
      color: 'red',
      message: 'Error: %s',
      type: err.message || ''
    }
    messageTerminal(config)
  }
}
app.use(helmet.hidePoweredBy())
app.use(compression())
app.use(`${basename}/client`, express.static(path.resolve(__dirname, frontPath)))

// log request
app.use(log)
// cors
if (appConfig.cors) {
  app.use(cors())
}
// post params parser body
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

app.use(`${basename}/api`, entrypointApi) // opennebula Api routes
const frontApps = Object.keys(defaultApps)
frontApps.map(frontApp => {
  app.get(`${basename}/${frontApp}`, entrypointApp)
  app.get(`${basename}/${frontApp}/*`, entrypointApp)
})
app.get('/*', (req, res) => res.redirect(`/${defaultAppName}/provision`))
// 404 - public
app.get('*', entrypoint404)

const appServer = validateServerIsSecure()
  ? secureServer(
    {
      key: readFileSync(getKey(), 'utf8'),
      cert: readFileSync(getCert(), 'utf8')
    },
    app
  )
  : unsecureServer(app)

websockets(appServer)

let config = {
  color: 'red',
  message: 'Server no start'
}

appServer.listen(port, '0.0.0.0', err => {
  if (!err) {
    config = {
      color: 'green',
      type: port,
      message: 'Server listen in port %s'
    }
  }
  messageTerminal(config)
})
vmrcUpgrade(appServer)
guacamole(appServer)
<|endoftext|>


<commit_before>/*
WYSIWYG arguments

enableKeyboardExtras {boolean} enable creating new components on enter, and appending text to previous components on delete, etc
buttons {array} array of button names (strings) for tooltip
styled {boolean} apply input styles to contenteditable element
 */

var _ = require('lodash'),
  select = require('selection-range'),
  MediumEditor = require('medium-editor'),
  MediumButton = require('../services/medium-button'),
  dom = require('../services/dom'),
  db = require('../services/db'),
  render = require('../services/render'),
  focus = require('../decorators/focus'),
  references = require('../services/references'),
  edit = require('../services/edit'),
  model = require('../services/model-text'),
  getInput = require('../services/get-input'),
  site = require('../services/site'),
  refAttr = references.referenceAttribute;

/**
 * toggle the tiered toolbar
 * this is the action for the tieredToolbar extension
 * @param {Element} html
 * @returns {Element}
 */
function toggleTieredToolbar(html) {
  // note: this element doesn't exist before it's instantiated, so we need to grab it afterwards
  var toolbar = dom.find('.medium-editor-toolbar'),
    toolbarClasses = toolbar.classList;

  if (toolbarClasses.contains('show-none')) {
    toolbarClasses.remove('show-none');
  } else if (toolbarClasses.contains('show-all')) {
    toolbarClasses.add('show-none');
  } else {
    toolbarClasses.add('show-all');
  }
  return html;
}

/**
 * create new medium editor
 * @param {Element} field
 * @param {array} buttons
 * @returns {Element}
 */
function createEditor(field, buttons) {
  return new MediumEditor(field, {
    toolbar: {
      // buttons that go in the toolbar
      buttons: buttons,
      standardizeSelectionStart: true,
      allowMultiParagraphSelection: false
    },
    delay: 200, // wait a bit for the toolbar and link previews to display
    paste: {
      forcePlainText: false,
      cleanPastedHTML: true, // clean html from sources like google docs
      cleanTags: [ // remove these tags when pasting
        'meta',
        'script',
        'style',
        'img',
        'object',
        'iframe'
      ],
      cleanReplacements: [
        [/<h[1-9]>/ig, '
'],
        [/<\/h[1-9]>/ig, '
'], // force all headers to the same level
        [/
/ig, ''], // get rid of
 tags
        [/<\/p>/ig, '']
      ]
    },
    anchor: {
      linkValidation: true // check for common protocols on links
    },
    autoLink: false, // create links automatically when urls are entered
    imageDragging: false, // disallow dragging inline images
    targetBlank: true,
    disableReturn: true,
    placeholder: false, // the placeholder isn't native
    extensions: {
      tieredToolbar: new MediumButton({
        label: '…',
        action: toggleTieredToolbar
      })
    }
  });
}

/**
 * get elements and data for the current component
 * @param {Element} el
 * @returns {object}
 */
function getCurrent(el) {
  var currentComponent = dom.closest(el, '[' + refAttr + ']'),
    currentComponentRef = currentComponent.getAttribute(refAttr);

  return {
    field: el.getAttribute(references.fieldAttribute),
    component: currentComponent,
    ref: currentComponentRef,
    name: references.getComponentNameFromReference(currentComponentRef)
  };
}

/**
 * get elements and data for the parent component
 * @param {Element} el of the current component
 * @returns {object}
 */
function getParent(el) {
  var parentNode = el.parentNode,
    parentComponent = dom.closest(parentNode, '[' + refAttr + ']'),
    parentComponentRef = parentComponent.getAttribute(refAttr);

  return {
    field: dom.closest(parentNode, '[' + references.editableAttribute + ']').getAttribute(references.editableAttribute),
    component: parentComponent,
    ref: parentComponentRef,
    name: references.getComponentNameFromReference(parentComponentRef)
  };
}

/**
 * get previous component in list, if any
 * @param {object} current
 * @param {object} parent
 * @returns {Promise} with {_ref: previous ref} or undefined
 */
function getPrev(current, parent) {
  return db.get(parent.ref).then(function (parentData) {
    var index = _.findIndex(parentData[parent.field], { _ref: current.ref }),
      before = _.take(parentData[parent.field], index),
      prev = _.findLast(before, function (component) {
        return references.getComponentNameFromReference(component._ref) === current.name;
      });

    if (prev) {
      return {
        field: current.field,
        component: dom.find(parent.component, '[' + refAttr + '="' + prev._ref + '"]'),
        ref: prev._ref,
        name: current.name
      };
    }
  });
}

/**
 * get the contents of a wysiwyg field
 * note: if we want to remove / parse / sanitize contents when doing operations,
 * this is the place we should do it
 * @param {Element} el
 * @returns {string}
 */
function getFieldContents(el) {
  return el.innerHTML;
}

/**
 * append text/html to previous component's field
 * @param {string} html
 * @param {object} prev
 * @returns {Promise}
 */
function appendToPrev(html, prev) {
// note: get fresh data from the server
  return db.get(prev.ref).then(function (prevData) {
    var prevFieldData = _.get(prevData, prev.field),
      throwawayDiv = document.createElement('div'),
      textmodel, fragment, cleanedString;

    // add current field's html to the end of the previous field
    prevFieldData += html;

    // pass the full thing through text-model to clean it and merge tags
    textmodel = model.fromElement(dom.create(prevFieldData));
    fragment = model.toElement(textmodel);
    throwawayDiv.appendChild(fragment);
    cleanedString = throwawayDiv.innerHTML;

    // then put it back into the previous component's data
    _.set(prevData, prev.field, cleanedString);
    return edit.update(prev.ref, prevData);
  });
}

/**
 * remove current component from parent
 * @param {object} current
 * @param {object} parent
 * @returns {Function}
 */
function removeCurrentFromParent(current, parent) {
  return function () {
    return edit.removeFromParentList({el: current.component, ref: current.ref, parentField: parent.field, parentRef: parent.ref});
  };
}

/**
 * focus on the previous component's field
 * @param {object} parent
 * @param  {object} prev
 * @param {number} textLength
 * @returns {Function}
 */
function focusPreviousComponent(parent, prev, textLength) {
  return function () {
    var newEl = dom.find(parent.component, '[' + references.referenceAttribute + '="' + prev.ref + '"]');

    return focus.focus(newEl, { ref: prev.ref, path: prev.field }).then(function (prevField) {
      // set caret right before the new text we added
      select(prevField, { start: prevField.textContent.length - textLength });
    });
  };
}

/**
 * remove current component, append text to previous component (of the same name)
 * @param {Element} el
 * @returns {Promise|undefined}
 */
function removeComponent(el) {
  var current = getCurrent(el),
    parent = getParent(current.component),
    textLength = el.textContent.length;

  // find the previous component, if any
  return getPrev(current, parent).then(function (prev) {
    if (prev) {
      // there's a previous component with the same name!
      // get the contents of the current field, and append them to the previous component
      return appendToPrev(getFieldContents(el), prev)
        .then(removeCurrentFromParent(current, parent))
        .then(render.reloadComponent.bind(null, prev.ref))
        .then(focusPreviousComponent(parent, prev, textLength));
    }
  });
}

/**
 * add component after current component
 * @param {Element} el
 * @param {string} [text]
 * @returns {Promise}
 */
function addComponent(el, text) {
  var current = getCurrent(el),
    parent = getParent(current.component),
    newData = {};

  // if we're passing data in, set it into the object
  if (text) {
    newData[current.field] = text;
  }

  return edit.createComponent(current.name, newData)
    .then(function (res) {
      var newRef = res._ref;

      return edit.addToParentList({ref: newRef, prevRef: current.ref, parentField: parent.field, parentRef: parent.ref})
        .then(function (newEl) {
          dom.insertAfter(current.component, newEl);
          return render.addComponentsHandlers(newEl)
            .then(function () {
              // focus on the same field in the new component
              focus.focus(newEl, { ref: newRef, path: current.field }).then(function () {
                return newRef;
              });
            });
        });
    });
}

/**
 * split text in a component, creating a new component
 * @param {Element} el
 * @param {object} caret
 * @param {object} observer used to update the current component
 * @returns {Promise}
 */
function splitComponent(el, caret, observer) {
  var textmodel = model.fromElement(dom.create(el.innerHTML.replace(/ /g, ' '))),
    // note: we're removing any nonbreaking spaces BEFORE parsing the text
    splitText = model.split(textmodel, caret.start),
    oldText = splitText[0],
    newText = splitText[1],
    oldFragment = model.toElement(oldText),
    newFragment = model.toElement(newText),
    throwawayDiv = document.createElement('div');

  // to get the innerHTML of the document fragment,
  // we first need to append it to a throwaway div.
  // this is not awesome, but is the "best practice"
  throwawayDiv.appendChild(newFragment);

  // now that we have the split elements, put the old one back in and then create the new one
  dom.clearChildren(el); // clear the current children
  el.appendChild(oldFragment); // add the cleaned dom fragment
  observer.setValue(el.innerHTML); // update the current field
  // this is saved automatically when it's unfocused
  return addComponent(el, throwawayDiv.innerHTML);
}

/**
 * remove current component if we're at the beginning of the field
 * and there's a previous component to append it to
 * @param {Element} el
 * @param {KeyboardEvent} e
 * @returns {undefined|Promise}
 */
function handleComponentDeletion(el, e) {
  var caretPos = select(el);

  if (caretPos.start === 0 && caretPos.end === 0) {
    e.preventDefault(); // stop page reload
    return removeComponent(el);
  }
}

/**
 * create new component if we're at the end of the field
 * @param {Element} el
 * @param {object} observer
 * @returns {false|Promise}
 */
function handleComponentCreation(el, observer) {
  var caretPos = select(el); // get text after the cursor, if any

  // if there's stuff after the caret, get it
  if (caretPos.start < el.textContent.length - 1) {
    return splitComponent(el, caretPos, observer);
  } else {
    return addComponent(el);
  }
}

function isStyled(styled) {
  return styled ? ' styled' : ''; // note the preeeding space!
}

function addLineBreak() {
  var selection = window.getSelection(),
    range = selection.getRangeAt(0),
    br = document.createElement('br');

  // woah, crazy stuff!
  // this creates a range, inserts the
 tag, then sets the caret after it
  range.deleteContents();
  range.insertNode(br);
  range.setStartAfter(br);
  range.setEndAfter(br);
  range.collapse(false);
  selection.removeAllRanges();
  selection.addRange(range);
}

module.exports = function (result, args) {
  var rivets = result.rivets,
    buttons = args.buttons,
    styled = args.styled,
    enableKeyboardExtras = args.enableKeyboardExtras,
    textInput = getInput(result.el),
    field = dom.create(`<p class="wysiwyg-input${ isStyled(styled) }" data-field="${result.bindings.name}" rv-wysiwyg="data.value"></p>`);

  // if more than 5 buttons, put the rest on the second tier
  if (buttons.length > 5) {
    buttons.splice(5, 0, 'tieredToolbar'); // clicking this expands the toolbar with a second tier
  }

  // put the rich text field after the input
  dom.replaceElement(textInput, field);

  rivets.binders.wysiwyg = {
    publish: true,
    bind: function (el) {
      // this is called when the binder initializes
      var observer = this.observer,
        data = observer.value() || '', // don't print 'undefined' if there's no data
        editor = createEditor(field, buttons),
        italicBtn = dom.find('.medium-editor-action-italic'),
        strikeBtn = dom.find('.medium-editor-action-strikethrough'),
        linkBtn = dom.find('.medium-editor-action-anchor');

      // put the initial data into the editor
      el.innerHTML = data;

      // apply custom styling to buttons
      if (italicBtn) {
        italicBtn.innerHTML = 'I';
      }
      if (strikeBtn) {
        strikeBtn.innerHTML = '<s>M</s>';
      }
      if (linkBtn) {
        linkBtn.innerHTML = `<img src="${site.get('assetPath')}/media/components/clay-kiln/link-icon.svg" />`;
      }

      // hide the tier2 buttons when closing the toolbar
      editor.subscribe('hideToolbar', function () {
        dom.find('.medium-editor-toolbar').classList.remove('show-all');
        dom.find('.medium-editor-toolbar').classList.remove('show-none');
      });

      // persist editor data to data model on input
      editor.subscribe('editableInput', function (e, editable) {
        observer.setValue(editable.innerHTML);
      });

      // persist editor data to data model on paste
      editor.subscribe('editablePaste', function (e, editable) {
        var textmodel = model.fromElement(dom.create(editable.innerHTML)),
          fragment = model.toElement(textmodel);

        // note: we're using the model-text service to clean up and standardize html
        // this is in addition to the cleanup that medium-editor does by default,
        // as well as the options we specified in the cleanTags / cleanReplacements paste config

        dom.clearChildren(editable); // clear the current children
        editable.appendChild(fragment); // add the cleaned dom fragment
        observer.setValue(editable.innerHTML);
      });

      editor.subscribe('editableKeydownDelete', function (e, editable) {
        if (enableKeyboardExtras) {
          handleComponentDeletion(editable, e);
        }
      });

      editor.subscribe('editableKeydownEnter', function (e, editable) {
        if (enableKeyboardExtras && e.shiftKey) {
          // shift+enter was pressed. add a line break
          addLineBreak();
        } else if (enableKeyboardExtras) {
          // enter was pressed. create a new component if certain conditions are met
          handleComponentCreation(editable, observer);
        } else {
          // close the form?
          focus.unfocus();
        }
      });
    }
  };

  return result;
};
<commit_msg>wysiwyg toolbar button fix<commit_after>/*
WYSIWYG arguments

enableKeyboardExtras {boolean} enable creating new components on enter, and appending text to previous components on delete, etc
buttons {array} array of button names (strings) for tooltip
styled {boolean} apply input styles to contenteditable element
 */

var _ = require('lodash'),
  select = require('selection-range'),
  MediumEditor = require('medium-editor'),
  MediumButton = require('../services/medium-button'),
  dom = require('../services/dom'),
  db = require('../services/db'),
  render = require('../services/render'),
  focus = require('../decorators/focus'),
  references = require('../services/references'),
  edit = require('../services/edit'),
  model = require('../services/model-text'),
  getInput = require('../services/get-input'),
  site = require('../services/site'),
  refAttr = references.referenceAttribute;

/**
 * toggle the tiered toolbar
 * this is the action for the tieredToolbar extension
 * @param {Element} html
 * @returns {Element}
 */
function toggleTieredToolbar(html) {
  // note: this element doesn't exist before it's instantiated, so we need to grab it afterwards
  var toolbar = dom.find('.medium-editor-toolbar'),
    toolbarClasses = toolbar.classList;

  if (toolbarClasses.contains('show-none')) {
    toolbarClasses.remove('show-none');
  } else if (toolbarClasses.contains('show-all')) {
    toolbarClasses.add('show-none');
  } else {
    toolbarClasses.add('show-all');
  }
  return html;
}

/**
 * create new medium editor
 * @param {Element} field
 * @param {array} buttons
 * @returns {Element}
 */
function createEditor(field, buttons) {
  return new MediumEditor(field, {
    toolbar: {
      // buttons that go in the toolbar
      buttons: buttons,
      standardizeSelectionStart: true,
      allowMultiParagraphSelection: false
    },
    delay: 200, // wait a bit for the toolbar and link previews to display
    paste: {
      forcePlainText: false,
      cleanPastedHTML: true, // clean html from sources like google docs
      cleanTags: [ // remove these tags when pasting
        'meta',
        'script',
        'style',
        'img',
        'object',
        'iframe'
      ],
      cleanReplacements: [
        [/<h[1-9]>/ig, '
'],
        [/<\/h[1-9]>/ig, '
'], // force all headers to the same level
        [/
/ig, ''], // get rid of
 tags
        [/<\/p>/ig, '']
      ]
    },
    anchor: {
      linkValidation: true // check for common protocols on links
    },
    autoLink: false, // create links automatically when urls are entered
    imageDragging: false, // disallow dragging inline images
    targetBlank: true,
    disableReturn: true,
    placeholder: false, // the placeholder isn't native
    extensions: {
      tieredToolbar: new MediumButton({
        label: '…',
        action: toggleTieredToolbar
      })
    }
  });
}

/**
 * get elements and data for the current component
 * @param {Element} el
 * @returns {object}
 */
function getCurrent(el) {
  var currentComponent = dom.closest(el, '[' + refAttr + ']'),
    currentComponentRef = currentComponent.getAttribute(refAttr);

  return {
    field: el.getAttribute(references.fieldAttribute),
    component: currentComponent,
    ref: currentComponentRef,
    name: references.getComponentNameFromReference(currentComponentRef)
  };
}

/**
 * get elements and data for the parent component
 * @param {Element} el of the current component
 * @returns {object}
 */
function getParent(el) {
  var parentNode = el.parentNode,
    parentComponent = dom.closest(parentNode, '[' + refAttr + ']'),
    parentComponentRef = parentComponent.getAttribute(refAttr);

  return {
    field: dom.closest(parentNode, '[' + references.editableAttribute + ']').getAttribute(references.editableAttribute),
    component: parentComponent,
    ref: parentComponentRef,
    name: references.getComponentNameFromReference(parentComponentRef)
  };
}

/**
 * get previous component in list, if any
 * @param {object} current
 * @param {object} parent
 * @returns {Promise} with {_ref: previous ref} or undefined
 */
function getPrev(current, parent) {
  return db.get(parent.ref).then(function (parentData) {
    var index = _.findIndex(parentData[parent.field], { _ref: current.ref }),
      before = _.take(parentData[parent.field], index),
      prev = _.findLast(before, function (component) {
        return references.getComponentNameFromReference(component._ref) === current.name;
      });

    if (prev) {
      return {
        field: current.field,
        component: dom.find(parent.component, '[' + refAttr + '="' + prev._ref + '"]'),
        ref: prev._ref,
        name: current.name
      };
    }
  });
}

/**
 * get the contents of a wysiwyg field
 * note: if we want to remove / parse / sanitize contents when doing operations,
 * this is the place we should do it
 * @param {Element} el
 * @returns {string}
 */
function getFieldContents(el) {
  return el.innerHTML;
}

/**
 * append text/html to previous component's field
 * @param {string} html
 * @param {object} prev
 * @returns {Promise}
 */
function appendToPrev(html, prev) {
// note: get fresh data from the server
  return db.get(prev.ref).then(function (prevData) {
    var prevFieldData = _.get(prevData, prev.field),
      throwawayDiv = document.createElement('div'),
      textmodel, fragment, cleanedString;

    // add current field's html to the end of the previous field
    prevFieldData += html;

    // pass the full thing through text-model to clean it and merge tags
    textmodel = model.fromElement(dom.create(prevFieldData));
    fragment = model.toElement(textmodel);
    throwawayDiv.appendChild(fragment);
    cleanedString = throwawayDiv.innerHTML;

    // then put it back into the previous component's data
    _.set(prevData, prev.field, cleanedString);
    return edit.update(prev.ref, prevData);
  });
}

/**
 * remove current component from parent
 * @param {object} current
 * @param {object} parent
 * @returns {Function}
 */
function removeCurrentFromParent(current, parent) {
  return function () {
    return edit.removeFromParentList({el: current.component, ref: current.ref, parentField: parent.field, parentRef: parent.ref});
  };
}

/**
 * focus on the previous component's field
 * @param {object} parent
 * @param  {object} prev
 * @param {number} textLength
 * @returns {Function}
 */
function focusPreviousComponent(parent, prev, textLength) {
  return function () {
    var newEl = dom.find(parent.component, '[' + references.referenceAttribute + '="' + prev.ref + '"]');

    return focus.focus(newEl, { ref: prev.ref, path: prev.field }).then(function (prevField) {
      // set caret right before the new text we added
      select(prevField, { start: prevField.textContent.length - textLength });
    });
  };
}

/**
 * remove current component, append text to previous component (of the same name)
 * @param {Element} el
 * @returns {Promise|undefined}
 */
function removeComponent(el) {
  var current = getCurrent(el),
    parent = getParent(current.component),
    textLength = el.textContent.length;

  // find the previous component, if any
  return getPrev(current, parent).then(function (prev) {
    if (prev) {
      // there's a previous component with the same name!
      // get the contents of the current field, and append them to the previous component
      return appendToPrev(getFieldContents(el), prev)
        .then(removeCurrentFromParent(current, parent))
        .then(render.reloadComponent.bind(null, prev.ref))
        .then(focusPreviousComponent(parent, prev, textLength));
    }
  });
}

/**
 * add component after current component
 * @param {Element} el
 * @param {string} [text]
 * @returns {Promise}
 */
function addComponent(el, text) {
  var current = getCurrent(el),
    parent = getParent(current.component),
    newData = {};

  // if we're passing data in, set it into the object
  if (text) {
    newData[current.field] = text;
  }

  return edit.createComponent(current.name, newData)
    .then(function (res) {
      var newRef = res._ref;

      return edit.addToParentList({ref: newRef, prevRef: current.ref, parentField: parent.field, parentRef: parent.ref})
        .then(function (newEl) {
          dom.insertAfter(current.component, newEl);
          return render.addComponentsHandlers(newEl)
            .then(function () {
              // focus on the same field in the new component
              focus.focus(newEl, { ref: newRef, path: current.field }).then(function () {
                return newRef;
              });
            });
        });
    });
}

/**
 * split text in a component, creating a new component
 * @param {Element} el
 * @param {object} caret
 * @param {object} observer used to update the current component
 * @returns {Promise}
 */
function splitComponent(el, caret, observer) {
  var textmodel = model.fromElement(dom.create(el.innerHTML.replace(/ /g, ' '))),
    // note: we're removing any nonbreaking spaces BEFORE parsing the text
    splitText = model.split(textmodel, caret.start),
    oldText = splitText[0],
    newText = splitText[1],
    oldFragment = model.toElement(oldText),
    newFragment = model.toElement(newText),
    throwawayDiv = document.createElement('div');

  // to get the innerHTML of the document fragment,
  // we first need to append it to a throwaway div.
  // this is not awesome, but is the "best practice"
  throwawayDiv.appendChild(newFragment);

  // now that we have the split elements, put the old one back in and then create the new one
  dom.clearChildren(el); // clear the current children
  el.appendChild(oldFragment); // add the cleaned dom fragment
  observer.setValue(el.innerHTML); // update the current field
  // this is saved automatically when it's unfocused
  return addComponent(el, throwawayDiv.innerHTML);
}

/**
 * remove current component if we're at the beginning of the field
 * and there's a previous component to append it to
 * @param {Element} el
 * @param {KeyboardEvent} e
 * @returns {undefined|Promise}
 */
function handleComponentDeletion(el, e) {
  var caretPos = select(el);

  if (caretPos.start === 0 && caretPos.end === 0) {
    e.preventDefault(); // stop page reload
    return removeComponent(el);
  }
}

/**
 * create new component if we're at the end of the field
 * @param {Element} el
 * @param {object} observer
 * @returns {false|Promise}
 */
function handleComponentCreation(el, observer) {
  var caretPos = select(el); // get text after the cursor, if any

  // if there's stuff after the caret, get it
  if (caretPos.start < el.textContent.length - 1) {
    return splitComponent(el, caretPos, observer);
  } else {
    return addComponent(el);
  }
}

function isStyled(styled) {
  return styled ? ' styled' : ''; // note the preeeding space!
}

function addLineBreak() {
  var selection = window.getSelection(),
    range = selection.getRangeAt(0),
    br = document.createElement('br');

  // woah, crazy stuff!
  // this creates a range, inserts the
 tag, then sets the caret after it
  range.deleteContents();
  range.insertNode(br);
  range.setStartAfter(br);
  range.setEndAfter(br);
  range.collapse(false);
  selection.removeAllRanges();
  selection.addRange(range);
}

module.exports = function (result, args) {
  var rivets = result.rivets,
    buttons = args.buttons,
    styled = args.styled,
    enableKeyboardExtras = args.enableKeyboardExtras,
    textInput = getInput(result.el),
    field = dom.create(`<p class="wysiwyg-input${ isStyled(styled) }" data-field="${result.bindings.name}" rv-wysiwyg="data.value"></p>`);

  // if more than 5 buttons, put the rest on the second tier
  if (buttons.length > 5) {
    buttons.splice(5, 0, 'tieredToolbar'); // clicking this expands the toolbar with a second tier
  }

  // put the rich text field after the input
  dom.replaceElement(textInput, field);

  function findExtension(extname) {
    return function (ext) {
      return ext.name === extname;
    };
  }

  rivets.binders.wysiwyg = {
    publish: true,
    bind: function (el) {
      // this is called when the binder initializes
      var observer = this.observer,
        data = observer.value() || '', // don't print 'undefined' if there's no data
        editor = createEditor(field, buttons),
        italicExtension = _.find(editor.extensions, findExtension('italic')),
        strikethoughExtension = _.find(editor.extensions, findExtension('strikethrough')),
        linkExtension = _.find(editor.extensions, findExtension('anchor'));

      // apply custom styling to buttons
      if (italicExtension) {
        italicExtension.button.innerHTML = 'I';
      }
      if (strikethoughExtension) {
        strikethoughExtension.button.innerHTML = '<s>M</s>';
      }
      if (linkExtension) {
        linkExtension.button.innerHTML = `<img src="${site.get('assetPath')}/media/components/clay-kiln/link-icon.svg" />`;
      }

      // put the initial data into the editor
      el.innerHTML = data;

      // hide the tier2 buttons when closing the toolbar
      editor.subscribe('hideToolbar', function () {
        dom.find('.medium-editor-toolbar').classList.remove('show-all');
        dom.find('.medium-editor-toolbar').classList.remove('show-none');
      });

      // persist editor data to data model on input
      editor.subscribe('editableInput', function (e, editable) {
        observer.setValue(editable.innerHTML);
      });

      // persist editor data to data model on paste
      editor.subscribe('editablePaste', function (e, editable) {
        var textmodel = model.fromElement(dom.create(editable.innerHTML)),
          fragment = model.toElement(textmodel);

        // note: we're using the model-text service to clean up and standardize html
        // this is in addition to the cleanup that medium-editor does by default,
        // as well as the options we specified in the cleanTags / cleanReplacements paste config

        dom.clearChildren(editable); // clear the current children
        editable.appendChild(fragment); // add the cleaned dom fragment
        observer.setValue(editable.innerHTML);
      });

      editor.subscribe('editableKeydownDelete', function (e, editable) {
        if (enableKeyboardExtras) {
          handleComponentDeletion(editable, e);
        }
      });

      editor.subscribe('editableKeydownEnter', function (e, editable) {
        if (enableKeyboardExtras && e.shiftKey) {
          // shift+enter was pressed. add a line break
          addLineBreak();
        } else if (enableKeyboardExtras) {
          // enter was pressed. create a new component if certain conditions are met
          handleComponentCreation(editable, observer);
        } else {
          // close the form?
          focus.unfocus();
        }
      });
    }
  };

  return result;
};
<|endoftext|>


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

foam.CLASS({
  package: 'foam.lib.csv',
  name: 'CSVOutputter',

  javaImports: [
    'foam.core.*',
    'java.util.ArrayList',
    'java.util.List',
    'java.lang.String',
    'java.util.Date'
  ],

  properties: [
    {
      class: 'String',
      name: 'csv',
      view: 'foam.u2.tag.TextArea',
      documentation: 'Used for js version of this outputter.'
    },
    {
      class: 'Class',
      name: 'of',
      visibility: 'HIDDEN'
    },
    {
      class: 'StringArray',
      name: 'props',
      factory: function() {
        return this.of.getAxiomByName('tableColumns').columns;
      },
      javaFactory: `
        List<PropertyInfo> propInfoList = getOf().getAxioms();
        int listSize = propInfoList.size();
        List<String> propNameList = new ArrayList<String>();

        for( int i = 0; i < listSize; i++ ) {
          PropertyInfo propI = propInfoList.get(i);
          if ( ! propI.getNetworkTransient() ) propNameList.add(propI.getName());
        }
        return propNameList.toArray( new String[propNameList.size()] );
      `,
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isFirstRow',
      value: true,
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isFirstColumn',
      value: true,
      visibility: 'HIDDEN'
    },
    {
      class: 'Object',
      name: 'sb',
      flags: ['java'],
      javaType: 'java.lang.StringBuilder',
      javaFactory: 'return new StringBuilder();',
      documentation: 'Used for java version of this outputter.',
      visibility: 'HIDDEN'
    }
  ],

  methods: [
    {
      name: 'outputValue',
      args: [
        { name: 'value' }
      ],
      code: function(value) {
        if ( ! this.isFirstColumn ) this.csv += ',';
        this.isFirstColumn = false;
        this.outputValue_(value);
      },
      javaCode: `
        if ( ! getIsFirstColumn() ) getSb().append(",");
        setIsFirstColumn(false);
        outputValue_(value);
      `
    },
    {
      name: 'outputValue_',
      args: [
        { type: 'Any', name: 'value' }
      ],
      code:
        foam.mmethod(
          {
            String: function(value) {
              this.csv += `"${value.replace(/\"/g, '""')}"`;
            },
            Number: function(value) {
              this.csv += value.toString();
            },
            Boolean: function(value) {
              this.csv += value.toString();
            },
            Date: function(value) {
              this.outputValue_(value.toDateString());
            },
            FObject: function(value) {
              this.outputValue_(foam.json.Pretty.stringify(value));
            },
            Array: function(value) {
              this.outputValue_(foam.json.Pretty.stringify(value));
            },
            Undefined: function(value) {},
            Null: function(value) {}
          }, function(value) {
            this.outputValue_(value.toString());
        }),
      javaCode: `
        if ( value instanceof String ) {
          getSb().append("\\"");
          getSb().append(((String)value).replace("\\"", "\\"\\""));
          getSb().append("\\"");
        } else if ( value instanceof Number ) {
          getSb().append(value.toString());
        } else if ( value instanceof Boolean ) {
          getSb().append(value.toString());
        } else if ( value instanceof Date ) {
          getSb().append(value.toString());
        } else if ( value instanceof FObject ) {
          outputValue_(value.toString());
        } else if ( value instanceof List ) {
          outputValue_(value.toString());
        }  else if ( value == null ) {
          // Do nothing
        } else {
          outputValue_(value.toString());
        }
      `
    },
    {
      name: 'newLine_',
      code: function() {
        this.csv += '\n';
        this.isFirstColumn = true;
      },
      javaCode: `
        getSb().append("\\n");
        setIsFirstColumn(true);
      `
    },
    {
      name: 'toString',
      code: function() {
        return this.csv;
      },
      javaCode: 'return getSb().toString();'
    },
    {
      name: 'headerOutput',
      args: [
        { type: 'FObject', name: 'obj' }
      ],
      code: function() {
        var element;
        this.props.forEach((name) => {
          element = this.of.getAxiomByName(name);
          element.toCSVLabel(this, element);
        });
        this.newLine_();
        this.isFirstRow = false;
      },
      javaCode: `
        Object propObj;
        PropertyInfo columnProp;
        String[] tableColumnNames = getProps();

        for (String propName: tableColumnNames) {
          propObj = obj.getProperty(propName);
          columnProp = (PropertyInfo) getOf().getAxiomByName(propName);
          columnProp.toCSVLabel(this, propObj);
        }
        newLine_();
        setIsFirstRow(false);
      `
    },
    {
      name: 'outputFObject',
      args: [
        { type: 'FObject', name: 'obj' }
      ],
      code: function(obj) {
        var element;

        if ( ! this.of ) this.of = obj.cls_;

        if ( this.isFirstRow ) this.headerOutput();

        this.props.forEach((name) => {
          element = this.of.getAxiomByName(name);
          element.toCSV(x, obj, this, element);
        });

        this.newLine_();
      },
      javaCode: `
        if ( ! isPropertySet("of") || getOf() == null ) setOf(obj.getClassInfo());

        Object propObj;
        PropertyInfo columnProp;
        String[] tableColumnNames = getProps();

        if ( getIsFirstRow() ) headerOutput(obj);

        for (String propName : tableColumnNames) {
          propObj = obj.getProperty(propName);
          columnProp = (PropertyInfo) getOf().getAxiomByName(propName);
          columnProp.toCSV(getX(), obj, this, propObj);
        }

        newLine_();
      `
    },
    {
      name: 'flush',
      code: function() {
        ['csv', 'isFirstColumn', 'isFirstRow']
          .forEach( (s) => this.clearProperty(s) );
      },
      javaCode: `
        getSb().setLength(0);
        clearCsv();
        clearIsFirstRow();
        clearIsFirstColumn();
      `
    }
  ]
});
<commit_msg>style changes: var names, defauls, synax. on CSVOutputter<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.lib.csv',
  name: 'CSVOutputter',

  javaImports: [
    'foam.core.*',
    'foam.nanos.logger.Logger',
    'java.util.ArrayList',
    'java.util.List',
    'java.util.Date',
    'java.util.stream.Collectors'
  ],

  properties: [
    {
      class: 'String',
      name: 'csv',
      view: 'foam.u2.tag.TextArea',
      documentation: 'Used for js version of this outputter.'
    },
    {
      class: 'Class',
      name: 'of',
      visibility: 'HIDDEN'
    },
    {
      class: 'StringArray',
      name: 'props',
      factory: function(of) {
        if ( ! of ) console.error('csvOutputter does not know the \'of\' of an object');
        if ( of.getAxiomByName('tableColumns') ) return of.getAxiomByName('tableColumns').columns;
        return of.getAxiomsByClass().map((p) => p.name ).filter((p) => ! p.networkTransient).flat();
      },
      javaFactory: `
        if ( ! isPropertySet("of") ) {
          ((Logger)getX().get("logger"))
            .error("csvOutputter does not know the 'of' of an object");
        }

        ArrayList<String> propInfoArrayList =((List<PropertyInfo>)getOf().getAxioms()).stream()
          .filter((propI) -> ! propI.getNetworkTransient())
          .map((propI) -> propI.getName())
          .collect(Collectors.toCollection(ArrayList::new));
        return propInfoArrayList.toArray(new String[propInfoArrayList.size()]);
      `,
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isFirstRow',
      value: true,
      visibility: 'HIDDEN'
    },
    {
      class: 'Boolean',
      name: 'isFirstColumn',
      value: true,
      visibility: 'HIDDEN'
    },
    {
      class: 'Object',
      name: 'sb',
      flags: ['java'],
      javaType: 'java.lang.StringBuilder',
      javaFactory: 'return new StringBuilder();',
      documentation: 'Used for java version of this outputter.',
      visibility: 'HIDDEN'
    }
  ],

  methods: [
    {
      name: 'outputValue',
      args: [
        { name: 'value' }
      ],
      code: function(value) {
        if ( ! this.isFirstColumn ) this.csv += ',';
        this.isFirstColumn = false;
        this.outputValue_(value);
      },
      javaCode: `
        if ( ! getIsFirstColumn() ) getSb().append(",");
        setIsFirstColumn(false);
        outputValue_(value);
      `
    },
    {
      name: 'outputValue_',
      args: [
        { type: 'Any', name: 'value' }
      ],
      code:
        foam.mmethod(
          {
            String: function(value) {
              this.csv += `${value.replace(/\"/g, '""')}`;
            },
            Number: function(value) {
              this.csv += value.toString();
            },
            Boolean: function(value) {
              this.csv += value.toString();
            },
            Date: function(value) {
              this.outputValue_(value.toDateString());
            },
            FObject: function(value) {
              this.outputValue_(foam.json.Pretty.stringify(value));
            },
            Array: function(value) {
              this.outputValue_(foam.json.Pretty.stringify(value));
            },
            Undefined: function(value) {},
            Null: function(value) {}
          }, function(value) {
            this.outputValue_(value.toString());
        }),
      javaCode: `
        if ( value instanceof String ) {
          getSb().append(((String)value).replace("\\"", "\\"\\""));
        } else if ( value instanceof Number ) {
          getSb().append(value.toString());
        } else if ( value instanceof Boolean ) {
          getSb().append(value.toString());
        } else if ( value instanceof Date ) {
          getSb().append(value.toString());
        } else if ( value instanceof FObject ) {
          outputValue_(value.toString());
        } else if ( value instanceof List ) {
          outputValue_(value.toString());
        }  else if ( value == null ) {
          // Do nothing
        } else {
          outputValue_(value.toString());
        }
      `
    },
    {
      name: 'newLine_',
      code: function() {
        this.csv += '\n';
        this.isFirstColumn = true;
      },
      javaCode: `
        getSb().append("\\n");
        setIsFirstColumn(true);
      `
    },
    {
      name: 'toString',
      code: function() {
        return this.csv;
      },
      javaCode: 'return getSb().toString();'
    },
    {
      name: 'outputHeader',
      args: [
        { type: 'FObject', name: 'obj' }
      ],
      code: function() {
        this.props.forEach((name) => {
          let prop = this.of.getAxiomByName(name);
          prop.toCSVLabel(this, prop);
        });
        this.newLine_();
        this.isFirstRow = false;
      },
      javaCode: `
        Object propObj;
        PropertyInfo columnProp;
        String[] tableColumnNames = getProps();

        for (String propName: tableColumnNames) {
          propObj = obj.getProperty(propName);
          columnProp = (PropertyInfo) getOf().getAxiomByName(propName);
          columnProp.toCSVLabel(this, propObj);
        }
        newLine_();
        setIsFirstRow(false);
      `
    },
    {
      name: 'outputFObject',
      args: [
        { type: 'FObject', name: 'obj' }
      ],
      code: function(obj) {
        if ( ! this.of ) this.of = obj.cls_;

        if ( this.isFirstRow ) this.outputHeader();

        this.props.forEach((name) => {
          let prop = this.of.getAxiomByName(name);
          prop.toCSV(x, obj, this, prop);
        });

        this.newLine_();
      },
      javaCode: `
        if ( ! isPropertySet("of") || getOf() == null ) setOf(obj.getClassInfo());

        PropertyInfo prop;

        if ( getIsFirstRow() ) outputHeader(obj);

        for (String name : getProps()) {
          prop = (PropertyInfo) getOf().getAxiomByName(name);
          prop.toCSV(getX(), obj, this, null);
        }

        newLine_();
      `
    },
    {
      name: 'flush',
      code: function() {
        ['csv', 'isFirstColumn', 'isFirstRow']
          .forEach( (s) => this.clearProperty(s) );
      },
      javaCode: `
        getSb().setLength(0);
        clearCsv();
        clearIsFirstRow();
        clearIsFirstColumn();
      `
    }
  ]
});
<|endoftext|>