<commit_before>/*** @used { core.RAIIEventEmitter } **/
/*** @used { core.Text } **/
/*** @used { core.Image } **/

exports.capabilities = {}
var runtime = _globals.pure.runtime
var renderer = null
var rootItem = null
var updatedItems = new Set()
var updateTimer

var rgba_re = /rgba\((\d+),(\d+),(\d+),(.*)\)/

var Rect = runtime.Rect

var registerGenericListener = function(target) {
	var prefix = '__nativeEventHandler_'
	target.onListener('',
		function(name) {
			log('registering generic event', name)
			var pname = prefix + name
			var callback = target[pname] = function() {
				COPY_ARGS(args, 0)
				target.emitWithArgs(name, args)
			}
			//target.dom.addEventListener(name, callback)
		},
		function(name) {
			log('removing generic event', name)
			var pname = prefix + name
			//target.dom.removeEventListener(name, target[pname])
		}
	)
}

var _paintRect = function(renderer) {
	var color = this._styles['background-color']
	if (color === undefined)
		return

	var m = rgba_re.exec(color)
	if (m === null) {
		log('invalid color specification: ' + color)
		return
	}
	renderer.paintRectangle(renderer.rect, parseInt(m[1]), parseInt(m[2]), parseInt(m[3]), Math.floor(parseFloat(m[4]) * 255))
}

var _paintImage = function(renderer) {
	renderer.paintImage(renderer.rect, this._image)
}

var _paintText = function(renderer) {
	renderer.paintText(renderer.rect)
}

var Element = function(context, tag) {
	_globals.core.RAIIEventEmitter.apply(this)
	this._context = context
	this._styles = {}
	this._paint = _paintRect
	this.children = []
	registerGenericListener(this)
}

Element.prototype = Object.create(_globals.core.RAIIEventEmitter.prototype)
Element.prototype.constructor = Element

Element.prototype.addClass = function(cls) { }
Element.prototype.setHtml = function(cls) { }

var importantStyles = new Set([
	'left', 'top', 'width', 'height', 'visibility',
	'background-color', 'border-radius',
	'color', 'font-size', 'text-align'
])

Element.prototype._onUpdate = function(name) {
	if (importantStyles.has(name))
		this.update()
//	else
//		log('unhandled style ' + name)
}

Element.prototype.style = function(name, style) {
	if (style !== undefined) {
		this._onUpdate(name)
		if (style !== '') //fixme: replace it with explicit 'undefined' syntax
			this._styles[name] = style
		else
			delete this._styles[name]
	} else if (name instanceof Object) { //style({ }) assignment
		for(var k in name) {
			this._onUpdate(k)
			var value = name[k]
			if (value !== '') //fixme: replace it with explicit 'undefined' syntax
				this._styles[k] = value
			else
				delete this._styles[k]
		}
	}
	else
		return this._styles[name]
}
Element.prototype.updateStyle = function() { }

Element.prototype.update = function() {
	updatedItems.add(this)
	if (updateTimer === undefined) {
		updateTimer = setTimeout(function() {
			log('frame paint')
			updateTimer = undefined
			updatedItems = new Set()
			rootItem.paint(renderer)
		}, 0)
	}
}

Element.prototype.append = function(child) {
	if (child._parent !== undefined)
		throw new Error('double append on element')
	child._parent = this
	this.children.push(child)
	child.update()
}

Element.prototype.remove = function() {
	var parent = this._parent
	if (parent !== undefined) {
		var idx = parent.children.indexOf(this)
		if (idx < 0)
			throw new Error('remove(): no child in parent children array')
		parent.children.splice(idx, 1)
		parent.update()
		this._parent = undefined
	} else
		throw new Error('remove() called without adding to parent')
}

Element.prototype.getRect = function() {
	var style = this._styles
	var l = style['left'] || 0, t = style['top'] || 0
	var w = style['width'] || 0, h = style['height'] || 0
	return new Rect(l, t, w + l, h + t)
}

Element.prototype.paint = function(renderer) {
	var visibility = this._styles['visibility']
	if (visibility === 'hidden')
		return
	var old = renderer.rect
	renderer.rect = this.getRect()
	renderer.rect.l += old.l
	renderer.rect.t += old.t
	this._paint(renderer)
	this.children.forEach(function(child) {
		child.paint(renderer)
	})
	renderer.rect = old
}

exports.init = function(ctx) {
	renderer = new runtime.Renderer(480, 640) //fixme: pass in options?
	rootItem = ctx.element = new Element(ctx, ctx.getTag())
	ctx.width = renderer.width
	ctx.height = renderer.height
}

exports.run = function(ctx) {
	ctx._run()
}

exports.createElement = function(ctx, tag) {
	return new Element(ctx, tag)
}

exports.initImage = function(image) {
	var element = image.element
	element._image = new Image()
	element._paint = _paintImage
}

var ImageStatusNull			= 0
var ImageStatusLoaded		= 1
var ImageStatusUnloaded		= 2
var ImageStatusError		= 3

exports.loadImage = function(image) {
	log('loading image ' + image.source)
	var Image = _globals.core.Image
	var element = image.element
	image.status = Image.Loading
	element._image.load(image.source, function(status) {
		log('image ' + image.source + ' status: ' + status + ' ' + element._image.width + ' ' + element._image.height)
		image.paintedWidth = element._image.width
		image.paintedHeight = element._image.height
		if (!image.width)
			image.width = image.paintedWidth
		if (!image.height)
			image.height = image.paintedHeight
		switch(status) {
			case ImageStatusNull:	image.status = Image.Null; break
			case ImageStatusLoaded:	image.status = Image.Ready; break
			case ImageStatusError:	image.status = Image.Error; break
		}
		element.update()
	})
}

exports.initText = function(text) {
	text.element._paint = _paintText
}

exports.layoutText = function(text) {
	text.element.update()
}

exports.requestAnimationFrame = function(callback) {
	return setTimeout(callback, 0)
}

exports.cancelAnimationFrame = function (timer) {
	clearTimeout(timer)
}
<commit_msg>do not store anything in renderer, pass rect explicitly<commit_after>/*** @used { core.RAIIEventEmitter } **/
/*** @used { core.Text } **/
/*** @used { core.Image } **/

exports.capabilities = {}
var runtime = _globals.pure.runtime
var renderer = null
var rootItem = null
var updatedItems = new Set()
var updateTimer

var rgba_re = /rgba\((\d+),(\d+),(\d+),(.*)\)/

var Rect = runtime.Rect

var registerGenericListener = function(target) {
	var prefix = '__nativeEventHandler_'
	target.onListener('',
		function(name) {
			log('registering generic event', name)
			var pname = prefix + name
			var callback = target[pname] = function() {
				COPY_ARGS(args, 0)
				target.emitWithArgs(name, args)
			}
			//target.dom.addEventListener(name, callback)
		},
		function(name) {
			log('removing generic event', name)
			var pname = prefix + name
			//target.dom.removeEventListener(name, target[pname])
		}
	)
}

var _paintRect = function(renderer, rect) {
	var color = this._styles['background-color']
	if (color === undefined)
		return

	var m = rgba_re.exec(color)
	if (m === null) {
		log('invalid color specification: ' + color)
		return
	}
	renderer.paintRectangle(rect, parseInt(m[1]), parseInt(m[2]), parseInt(m[3]), Math.floor(parseFloat(m[4]) * 255))
}

var _paintImage = function(renderer, rect) {
	renderer.paintImage(rect, this._image)
}

var _paintText = function(renderer, rect) {
	renderer.paintText(rect)
}

var Element = function(context, tag) {
	_globals.core.RAIIEventEmitter.apply(this)
	this._context = context
	this._styles = {}
	this._paint = _paintRect
	this.children = []
	registerGenericListener(this)
}

Element.prototype = Object.create(_globals.core.RAIIEventEmitter.prototype)
Element.prototype.constructor = Element

Element.prototype.addClass = function(cls) { }
Element.prototype.setHtml = function(cls) { }

var importantStyles = new Set([
	'left', 'top', 'width', 'height', 'visibility',
	'background-color', 'border-radius',
	'color', 'font-size', 'text-align'
])

Element.prototype._onUpdate = function(name) {
	if (importantStyles.has(name))
		this.update()
//	else
//		log('unhandled style ' + name)
}

Element.prototype.style = function(name, style) {
	if (style !== undefined) {
		this._onUpdate(name)
		if (style !== '') //fixme: replace it with explicit 'undefined' syntax
			this._styles[name] = style
		else
			delete this._styles[name]
	} else if (name instanceof Object) { //style({ }) assignment
		for(var k in name) {
			this._onUpdate(k)
			var value = name[k]
			if (value !== '') //fixme: replace it with explicit 'undefined' syntax
				this._styles[k] = value
			else
				delete this._styles[k]
		}
	}
	else
		return this._styles[name]
}
Element.prototype.updateStyle = function() { }

Element.prototype.update = function() {
	updatedItems.add(this)
	if (updateTimer === undefined) {
		updateTimer = setTimeout(function() {
			log('frame paint')
			updateTimer = undefined
			updatedItems = new Set()
			rootItem.paint(renderer, 0, 0)
		}, 0)
	}
}

Element.prototype.append = function(child) {
	if (child._parent !== undefined)
		throw new Error('double append on element')
	child._parent = this
	this.children.push(child)
	child.update()
}

Element.prototype.remove = function() {
	var parent = this._parent
	if (parent !== undefined) {
		var idx = parent.children.indexOf(this)
		if (idx < 0)
			throw new Error('remove(): no child in parent children array')
		parent.children.splice(idx, 1)
		parent.update()
		this._parent = undefined
	} else
		throw new Error('remove() called without adding to parent')
}

Element.prototype.getRect = function() {
	var style = this._styles
	var l = style['left'] || 0, t = style['top'] || 0
	var w = style['width'] || 0, h = style['height'] || 0
	return new Rect(l, t, w + l, h + t)
}

Element.prototype.paint = function(renderer, x, y) {
	var visibility = this._styles['visibility']
	if (visibility === 'hidden')
		return

	var rect = this.getRect()
	rect.l += x
	rect.t += y
	this._paint(renderer, rect)
	this.children.forEach(function(child) {
		child.paint(renderer, rect.l, rect.t)
	})
}

exports.init = function(ctx) {
	renderer = new runtime.Renderer(480, 640) //fixme: pass in options?
	rootItem = ctx.element = new Element(ctx, ctx.getTag())
	ctx.width = renderer.width
	ctx.height = renderer.height
}

exports.run = function(ctx) {
	ctx._run()
}

exports.createElement = function(ctx, tag) {
	return new Element(ctx, tag)
}

exports.initImage = function(image) {
	var element = image.element
	element._image = new Image()
	element._paint = _paintImage
}

var ImageStatusNull			= 0
var ImageStatusLoaded		= 1
var ImageStatusUnloaded		= 2
var ImageStatusError		= 3

exports.loadImage = function(image) {
	log('loading image ' + image.source)
	var Image = _globals.core.Image
	var element = image.element
	image.status = Image.Loading
	element._image.load(image.source, function(status) {
		log('image ' + image.source + ' status: ' + status + ' ' + element._image.width + ' ' + element._image.height)
		image.paintedWidth = element._image.width
		image.paintedHeight = element._image.height
		if (!image.width)
			image.width = image.paintedWidth
		if (!image.height)
			image.height = image.paintedHeight
		switch(status) {
			case ImageStatusNull:	image.status = Image.Null; break
			case ImageStatusLoaded:	image.status = Image.Ready; break
			case ImageStatusError:	image.status = Image.Error; break
		}
		element.update()
	})
}

exports.initText = function(text) {
	text.element._paint = _paintText
}

exports.layoutText = function(text) {
	text.element.update()
}

exports.requestAnimationFrame = function(callback) {
	return setTimeout(callback, 0)
}

exports.cancelAnimationFrame = function (timer) {
	clearTimeout(timer)
}
<|endoftext|>


<commit_before>// @flow

import React from 'react'
import type {Props} from './index.render'
import {Confirm, Box, Text, Icon} from '../../common-adapters'
import {globalStyles, globalColors} from '../../styles/style-guide'
import type {Props as IconProps} from '../../common-adapters/icon'

const Render = ({name, type, deviceID, currentDevice, onSubmit, onCancel}: Props) => {
  const icon: IconProps.type = {
    'mobile': 'phone-color-revoke-m',
    'desktop': 'computer-bw-revoke-m',
    'backup': 'paper-key-remove-m'
  }[type]

  return (
    <Confirm theme='public' danger submitLabel='Yes, delete it' onSubmit={() => onSubmit({deviceID, name, currentDevice})} onCancel={onCancel}>
      <Box style={{...globalStyles.flexBoxColumn, minHeight: 80, marginBottom: 16, alignItems: 'center'}}>
        <Icon type={icon} />
        <Text type='Body' style={stylesName}>{name}</Text>
      </Box>
      <Text type='Header'>Are you sure you want to revoke {currentDevice ? 'your current device' : name}?</Text>
    </Confirm>
  )
}

const stylesName = {
  textDecoration: 'line-through',
  color: globalColors.red,
  fontStyle: 'italic',
  marginTop: 4,
  flow: 1
}

export default Render
<commit_msg>Remove invalid CSS rule<commit_after>// @flow

import React from 'react'
import type {Props} from './index.render'
import {Confirm, Box, Text, Icon} from '../../common-adapters'
import {globalStyles, globalColors} from '../../styles/style-guide'
import type {Props as IconProps} from '../../common-adapters/icon'

const Render = ({name, type, deviceID, currentDevice, onSubmit, onCancel}: Props) => {
  const icon: IconProps.type = {
    'mobile': 'phone-color-revoke-m',
    'desktop': 'computer-bw-revoke-m',
    'backup': 'paper-key-remove-m'
  }[type]

  return (
    <Confirm theme='public' danger submitLabel='Yes, delete it' onSubmit={() => onSubmit({deviceID, name, currentDevice})} onCancel={onCancel}>
      <Box style={{...globalStyles.flexBoxColumn, minHeight: 80, marginBottom: 16, alignItems: 'center'}}>
        <Icon type={icon} />
        <Text type='Body' style={stylesName}>{name}</Text>
      </Box>
      <Text type='Header'>Are you sure you want to revoke {currentDevice ? 'your current device' : name}?</Text>
    </Confirm>
  )
}

const stylesName = {
  textDecoration: 'line-through',
  color: globalColors.red,
  fontStyle: 'italic',
  marginTop: 4
}

export default Render
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 Autodesk, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// http://opensource.org/licenses/MIT

var logBuffer = [];
var answer_inputCount = 0;
var tabindex = 1;

if (!window.console) { var console = {}; }
if (!console.log) { console.log = function () { }; }
if (!console.log) { console.log = function () { }; }
if (!console.error) { console.error = function () { }; }
if (!console.warn) { console.warn = function () { }; }

var nsURL = "/survey/not_supported/";
var debug = (window.location.href.indexOf("debug_question") > -1);

if ((!Modernizr.canvas || !Modernizr.inlinesvg) && window.location.href.indexOf(nsURL) == -1) {
    window.location.href = nsURL;
}
//(bowser.safari && bowser.version >= 5) ||
//(bowser.opera && bowser.version >= 11.0) ||

if ((bowser.msie && bowser.version >= 9) ||
    (bowser.chrome && bowser.version >= 14) ||
    (bowser.firefox && bowser.version >= 4.0) ||
    window.location.href.indexOf(nsURL) != -1) {
    // We are good
} else {
    window.location.href = nsURL;
}

$('#mainForm').find(':input').each(function () {
    if (this.type != "hidden") {
        var $input = $(this);
        $input.attr("tabindex", tabindex);
        tabindex++;
    }
});

function getSelectionText() {

    var startNode, startOffset, endNode, endOffset;
    var text = "";
    var sel = rangy.getSelection();
    text = sel.toString();
    if (text.length > 0) {
        var selectionData = rangy.serializeSelection(sel, true, $("body")[0]);
        return [text, selectionData];
    } else {
        return ["", ""];
    }
}
function getScrollXY() {
    var scrOfX = 0, scrOfY = 0;
    if (typeof (window.pageYOffset) == 'number') {
        //Netscape compliant
        scrOfY = window.pageYOffset;
        scrOfX = window.pageXOffset;
    } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
        //DOM compliant
        scrOfY = document.body.scrollTop;
        scrOfX = document.body.scrollLeft;
    } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
        //IE6 standards compliant mode
        scrOfY = document.documentElement.scrollTop;
        scrOfX = document.documentElement.scrollLeft;
    }
    //var scrOfX = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
    //var scrOfY = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
    return [scrOfX, scrOfY];
}

function isDefined(e, prop) {
    return (prop in e) && typeof e[prop] !== 'undefined' && e[prop] != undefined && e[prop] != 'undefined';
}

function captureElementData2(id) {
    var elementData = {};
    var element = $("#" + id);
    elementData['id'] = id;
    elementData['width'] = element.width();
    elementData['height'] = element.height();
    elementData['innerWidth'] = element.innerWidth();
    elementData['innerHeight'] = element.innerHeight();
    elementData['outerWidth'] = element.outerWidth();
    elementData['outerHeight'] = element.outerHeight();
    elementData['outerWidthWithMargin'] = element.outerWidth(true);
    elementData['outerHeightWithMargin'] = element.outerHeight(true);
    elementData['offset'] = element.offset();
    elementData['position'] = element.position();
    elementData['class'] = element.attr('class');
    elementData['tabindex'] = element.attr('tabindex');
    elementData['nodeName'] = element[0].nodeName;

    return elementData;
}
function captureElementData(e, eventRaw, idName) {
    eventRaw[idName] = {};
    var identifier = "";
    if (isDefined(e[idName], 'id') && e[idName].id != "") {
        //console.log("captureElementData: has id", e[idName].id, e, eventRaw, idName);
        eventRaw[idName]['id'] = e[idName].id;
        identifier = "#" + e[idName].id;
        eventRaw[idName]['width'] = $(identifier).width();
        eventRaw[idName]['height'] = $(identifier).height();
        eventRaw[idName]['innerWidth'] = $(identifier).innerWidth();
        eventRaw[idName]['innerHeight'] = $(identifier).innerHeight();
        eventRaw[idName]['outerWidth'] = $(identifier).outerWidth();
        eventRaw[idName]['outerHeight'] = $(identifier).outerHeight();
        eventRaw[idName]['outerWidthWithMargin'] = $(identifier).outerWidth(true);
        eventRaw[idName]['outerHeightWithMargin'] = $(identifier).outerHeight(true);
        eventRaw[idName]['offset'] = $(identifier).offset();
        eventRaw[idName]['position'] = $(identifier).position();
        eventRaw[idName]['class'] = $(identifier).attr('class');
        eventRaw[idName]['nodeName'] = $(identifier)[0].nodeName;
        eventRaw[idName]['tabindex'] = $(identifier).attr('tabindex');

        //if ($(identifier)[0].nodeName == "OPTION" || $(identifier)[0].nodeName == "SELECT") {
        //    eventRaw[idName]['parent'] = captureElementData2($(identifier)[0].parentNode.id);
            //console.log(e, eventRaw, idName);
        //}
    } else if (isDefined(e[idName], 'documentElement')) {
        eventRaw[idName]['id'] = "document";
        identifier = "document";
        eventRaw[idName]['width'] = $(document).width();
        eventRaw[idName]['height'] = $(document).height();
        eventRaw[idName]['clientWidth'] = document.documentElement.clientWidth;
        eventRaw[idName]['clientHeight'] = document.documentElement.clientHeight;
        eventRaw[idName]['offsetWidth'] = document.documentElement.offsetWidth;
        eventRaw[idName]['offsetHeight'] = document.documentElement.offsetHeight;
        eventRaw[idName]['nodeName'] = document.nodeName;
        eventRaw[idName]['offset'] = { 'left': 0, 'top': 0 };;

    } else if (isDefined(e[idName], 'document')) {
        eventRaw[idName]['id'] = "window";
        identifier = "window";
        eventRaw[idName]['width'] = $(window).width();
        eventRaw[idName]['height'] = $(window).height();
        eventRaw[idName]['screenX'] = (window.screenX !== undefined) ? window.screenX : window.screenLeft;
        eventRaw[idName]['screenY'] = (window.screenY !== undefined) ? window.screenY : window.screenTop;
        eventRaw[idName]['innerWidth'] = window.innerWidth;
        eventRaw[idName]['innerHeight'] = window.innerHeight;
        eventRaw[idName]['outerWidth'] = window.outerWidth;
        eventRaw[idName]['outerHeight'] = window.outerHeight;
        eventRaw[idName]['nodeName'] = window.nodeName;
        eventRaw[idName]['offset'] = { 'left': 0, 'top': 0 };;
        if (isDefined(window, 'mozInnerScreenX')) {
            eventRaw[idName]['offset'] = { 'left': window.mozInnerScreenX, 'top': window.mozInnerScreenY };
        }
        if (isDefined(window, 'innerScreenX')) {
            eventRaw[idName]['offset'] = { 'left': window.innerScreenX, 'top': window.innerScreenY };
        }

    } else {
        //console.warn("didn't find the element", e, eventRaw, idName);
    }
}
function logFormatted(e, typeOverwrite) {
    var eventName = typeOverwrite || e.type;
    var extraData = {};
    if (eventName == "init") {
        extraData['version'] = 2.0;
        extraData['navigator'] = {};
        extraData['navigator']['appCodeName'] = navigator.appCodeName;
        extraData['navigator']['appName'] = navigator.appName;
        extraData['navigator']['appVersion'] = navigator.appVersion;
        extraData['navigator']['cookieEnabled'] = navigator.cookieEnabled;
        extraData['navigator']['language'] = navigator.language;
        extraData['navigator']['platform'] = navigator.platform;
        extraData['navigator']['product'] = navigator.product;
        extraData['navigator']['userAgent'] = navigator.userAgent;

        extraData['screen'] = {};
        extraData['screen']['width'] = screen.width;
        extraData['screen']['height'] = screen.height;
        extraData['screen']['availWidth'] = screen.availWidth;
        extraData['screen']['availHeight'] = screen.availHeight;
        extraData['screen']['colorDepth'] = screen.colorDepth;
        extraData['screen']['pixelDepth'] = screen.pixelDepth;
    }
    // Add Window and Document Dimentionss
    if (eventName == "init" || eventName == "resize" || eventName == "focusin" || eventName == "focus") {
        extraData['window'] = {};
        extraData['window']['width'] = $(window).width();
        extraData['window']['height'] = $(window).height();
        extraData['window']['screenX'] = window.screenX;
        extraData['window']['screenY'] = window.screenY;
        extraData['window']['innerWidth'] = window.innerWidth;
        extraData['window']['innerHeight'] = window.innerHeight;
        extraData['window']['outerWidth'] = window.outerWidth;
        extraData['window']['outerHeight'] = window.outerHeight;
        extraData['window']['offset'] = { 'left': 0, 'top': 0 };
        if (isDefined(window, 'mozInnerScreenX')) {
            extraData['window']['offset'] = { 'left': window.mozInnerScreenX, 'top': window.mozInnerScreenY };
        }

        extraData['document'] = {};
        extraData['document']['width'] = $(document).width();
        extraData['document']['height'] = $(document).height();
        extraData['document']['clientWidth'] = document.documentElement.clientWidth;
        extraData['document']['clientHeight'] = document.documentElement.clientHeight;
        extraData['document']['offsetWidth'] = document.documentElement.offsetWidth;
        extraData['document']['offsetHeight'] = document.documentElement.offsetHeight;
        extraData['document']['offset'] = { 'left': 0, 'top': 0 };

        extraData['body'] = {};
        extraData['body']['width'] = $("body").width();
        extraData['body']['height'] = $("body").height();
        extraData['body']['innerWidth'] = $("body").innerWidth();
        extraData['body']['innerHeight'] = $("body").innerHeight();
        extraData['body']['outerWidth'] = $("body").outerWidth();
        extraData['body']['outerHeight'] = $("body").outerHeight();
        extraData['body']['outerWidthWithMargin'] = $("body").outerWidth(true);
        extraData['body']['outerHeightWithMargin'] = $("body").outerHeight(true);
        extraData['body']['offset'] = $("body").offset();
    }

    // Add scroll Data
    if (eventName == "init" || eventName == "scroll" || eventName == "resize" || eventName == "mousewheel") {
        var offs = getScrollXY();
        extraData['scrollOffset'] = {};
        extraData['scrollOffset']['pageXOffset'] = offs[0];
        extraData['scrollOffset']['pageYOffset'] = offs[1];

    }

    // Add text selections
    if (eventName == "mouseup" || eventName == "mousemove" || eventName == "click" || eventName == "dblclick" || eventName == "scroll" || eventName == "keyup") {
        selectionData = getSelectionText();
        extraData['selectedText'] = selectionData[1];
    }
    var eventRaw = {};

    if (isDefined(e, 'deltaX')) {
        eventRaw['deltaX'] = e.deltaX;
    }
    if (isDefined(e, 'deltaY')) {
        eventRaw['deltaY'] = e.deltaY;
    }
    if (isDefined(e, 'deltaFactor')) {
        eventRaw['deltaFactor'] = e.deltaFactor;
    }

    // Add dimentions of the target
    if (isDefined(e, 'target')) {
        captureElementData(e, eventRaw, "target");
    }

    if (eventName == "init" || eventName == "scroll" || eventName == "resize" || eventName == "keyup") {
        extraData['zoom'] = {}
        var zoom = detectZoom.zoom();
        var device = detectZoom.device();
        extraData['zoom']['zoomLevel'] = zoom;
        extraData['zoom']['devicePixelRatio'] = device;
        //console.log(zoom, device);
    }
    if (isDefined(e, 'altKey')) {
        eventRaw['altKey'] = e.altKey;
    }
    if (isDefined(e, 'button')) {
        eventRaw['button'] = e.button;
    }
    if (isDefined(e, 'buttons')) {
        eventRaw['buttons'] = e.buttons;
    }
    if (isDefined(e, 'clientX')) {
        eventRaw['clientX'] = e.clientX;
    }
    if (isDefined(e, 'clientY')) {
        eventRaw['clientY'] = e.clientY;
    }
    if (isDefined(e, 'ctrlKey')) {
        eventRaw['ctrlKey'] = e.ctrlKey;
    }
    //if (isDefined(e, 'currentTarget')) {
    //    captureElementData(e, eventRaw, "currentTarget");
   // }
    //if (isDefined(e, 'delegateTarget')) {
    //    captureElementData(e, eventRaw, "delegateTarget");
    //}

    if (isDefined(e, 'eventPhase')) {
        eventRaw['eventPhase'] = e.eventPhase;
    }
    if (isDefined(e, 'metaKey')) {
        eventRaw['metaKey'] = e.metaKey;
    }
    if (isDefined(e, 'offsetX')) {
        eventRaw['offsetX'] = e.offsetX;
    }
    if (isDefined(e, 'offsetY')) {
        eventRaw['offsetY'] = e.offsetY;
    }
    if (isDefined(e, 'pageX')) {
        eventRaw['pageX'] = e.pageX;
    }
    if (isDefined(e, 'pageY')) {
        eventRaw['pageY'] = e.pageY;
    }
    //if (isDefined(e, 'relatedTarget')) {
    //    captureElementData(e, eventRaw, "relatedTarget");
    //}
    if (isDefined(e, 'screenX')) {
        eventRaw['screenX'] = e.screenX;
    }
    if (isDefined(e, 'screenY')) {
        eventRaw['screenY'] = e.screenY;
    }
    if (isDefined(e, 'shiftKey')) {
        eventRaw['shiftKey'] = e.shiftKey;
    }
    if (isDefined(e, 'timeStamp')) {
        eventRaw['timeStamp'] = (new Date).getTime(); //e.timeStamp;
    }
    if (isDefined(e, 'which')) {
        eventRaw['which'] = e.which;
    }
    var eventObject = [eventName, eventRaw, extraData];
    logBuffer.push(eventObject);
}

$(document).ready(function () {
    // Document Mouse Events
    if (!debug) {
        $(document).mousemove(function (e) {
            // First mouse move lets add a ready event
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });

        $(document).click(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });

        $(document).dblclick(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });

        $(document).mouseenter(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });

        $(document).mouseleave(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });

        $(document).mousedown(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(document).mouseup(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });

        // Keyboard Events
        $(document).keydown(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(document).keyup(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(document).keypress(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(document).focusin(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(document).focusout(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(document).mousewheel(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });

        // Window Events
        $(window).resize(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(window).scroll(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(window).focus(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        $(window).blur(function (e) {
            if (logBuffer.length == 0) {
                logFormatted(e, "init");
            }
            logFormatted(e);
        });
        //$(document).on(screenfull.raw.fullscreenchange, function () {
            //console.log('Fullscreen change');
            //alert('Fullscreen change');
        //});

    }
}); //$(document).ready(function() {

<commit_msg>removed old mimic file<commit_after><|endoftext|>


<commit_before>(function() {
'use strict';
angular.module('wfm.culturalDatepicker', ['currentUserInfoService'])
.controller('CulturalDatepickerCtrl', ['$scope', 'CurrentUserInfo', function($scope, CurrentUserInfo) {
    var dateFormat = CurrentUserInfo.CurrentUserInfo().DateFormatLocale;
    $scope.isJalaali = dateFormat === 'fa-IR' ? true : false;
    $scope.isGregorian = !$scope.isJalaali;
}])
.directive('wfmCulturalDatepicker', function() {
    return {
        controller: 'CulturalDatepickerCtrl',
        restrict: 'E',
        scope: {
            date: '=ngModel'
        },
        template: '
<persian-datepicker ng-if="isJalaali" ng-model="date" class="wfm-datepicker"></persian-datepicker>

'
    };
});
})();
<commit_msg>refactored a little<commit_after>(function() {
    'use strict';
    angular.module('wfm.culturalDatepicker', ['currentUserInfoService'])
        .controller('CulturalDatepickerCtrl', ['$scope', 'CurrentUserInfo', function($scope, CurrentUserInfo) {
            var dateFormat = CurrentUserInfo.CurrentUserInfo().DateFormatLocale;
            $scope.isJalaali = dateFormat === 'fa-IR' ? true : false;
            $scope.isGregorian = !$scope.isJalaali;
        }])
        .directive('wfmCulturalDatepicker', function() {
            var jalaaliTemplate = '<persian-datepicker ng-if="isJalaali" ng-model="date" class="wfm-datepicker"></persian-datepicker>';
            var gregorianTemplate = '

';
            return {
                controller: 'CulturalDatepickerCtrl',
                restrict: 'E',
                scope: {
                    date: '=ngModel'
                },
                template: '
' + jalaaliTemplate + gregorianTemplate + '
'
            };
        });
})();
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { parse as parseQueryString } from 'query-string';

import urlQueryDecoder from '../urlQueryDecoder';
import urlQueryConfig from '../urlQueryConfig';
import { updateUrlQuerySingle } from '../updateUrlQuery';
import { encode } from '../serialize';

/**
 * Higher order component (HOC) that injects URL query parameters as props.
 *
 * @param {Function} mapUrlToProps `function(url, props) -> {Object}` returns props to inject
 * @return {React.Component}
 */
export default function addUrlProps(options) {
  const {
    mapUrlToProps = d => d,
    mapUrlChangeHandlersToProps,
    urlPropsQueryConfig,
    addRouterParams,
    addUrlChangeHandlers,
  } = options;

  return function addPropsWrapper(WrappedComponent) {
    // caching to prevent unnecessary generation of new onChange functions
    let cachedHandlers;

    let decodeQuery;

    // initialize decode query (with cache) if a config is provided
    if (urlPropsQueryConfig) {
      decodeQuery = urlQueryDecoder(urlPropsQueryConfig);
    }

    /**
     * Parse the URL query into an object. If a urlPropsQueryConfig is provided
     * the values are decoded based on type.
     */
    function getUrlObject(props) {
      let location;

      // react-router provides it as a prop
      if (props.location && props.location.query) {
        location = props.location;

      // check in history
      } else if (urlQueryConfig.history.location) {
        location = urlQueryConfig.history.location;

      // not found. just use location from window
      } else {
        location = window.location;
      }

      const currentQuery = location.query || parseQueryString(location.search) || {};

      let result;
      // if a url query decoder is provided, decode the query then return that.
      if (decodeQuery) {
        result = decodeQuery(currentQuery);
      } else {
        result = currentQuery;
      }

      // add in react-router params if requested
      if (addRouterParams || (addRouterParams !== false && urlQueryConfig.addRouterParams)) {
        Object.assign(result, props.params);
      }

      return result;
    }

    const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
    class AddUrlProps extends Component {
      static displayName = `AddUrlProps(${displayName})`
      static WrappedComponent = WrappedComponent
      static propTypes = {
        location: PropTypes.object, // eslint-disable-line react/forbid-prop-types
      }

      /**
       * Create URL change handlers based on props, the urlPropsQueryConfig (if provided),
       * and mapUrlChangeHandlersToProps (if provided).
       * As a member function so we can read `this.props` in generated handlers dynamically.
       */
      getUrlChangeHandlerProps(propsWithUrl) {
        let handlers;

        if (urlPropsQueryConfig) {
          // if we have a props->query config, generate the change handler props unless
          // addUrlChangeHandlers is false
          if (addUrlChangeHandlers || (addUrlChangeHandlers == null && urlQueryConfig.addUrlChangeHandlers)) {
            // use cache if available. Have to do this since urlQueryConfig can change between
            // renders (although that is unusual).
            if (cachedHandlers) {
              handlers = cachedHandlers;
            } else {
              // for each URL config prop, create a handler
              handlers = Object.keys(urlPropsQueryConfig).reduce((handlersAccum, propName) => {
                const { updateType, queryParam = propName, type } = urlPropsQueryConfig[propName];

                // name handler for `foo` => `onChangeFoo`
                const handlerName = `onChange${propName[0].toUpperCase()}${propName.substring(1)}`;

                // handler encodes the value and updates the URL with the encoded value
                // based on the `updateType` in the config. Default is `replaceIn`
                handlersAccum[handlerName] = function generatedUrlChangeHandler(value) {
                  const encodedValue = encode(type, value);
                  updateUrlQuerySingle(updateType, queryParam, encodedValue, this.props.location);
                }.bind(this); // bind this so we can access props dynamically

                return handlersAccum;
              }, {});

              // cache these so we don't regenerate new functions every render
              cachedHandlers = handlers;
            }
          }
        }

        // if a manual mapping function is provided, use it, passing in the auto-generated
        // handlers as an optional secondary argument.
        if (mapUrlChangeHandlersToProps) {
          handlers = mapUrlChangeHandlersToProps(propsWithUrl, handlers);
        }

        return handlers;
      }

      render() {
        // get the url query parameters as an object mapping name to value.
        // if a config is provided, these are decoded based on their `type` and their
        // name will match the prop name.
        // if no config is provided, they are not decoded and their names are whatever
        // they were in the URL.
        const url = getUrlObject(this.props);

        // pass to mapUrlToProps for further decoding if provided
        const propsWithUrl = Object.assign({}, this.props, mapUrlToProps(url, this.props));

        // add in the URL change handlers - either auto-generated based on config
        // or from mapUrlChangeHandlersToProps.
        Object.assign(propsWithUrl, this.getUrlChangeHandlerProps(propsWithUrl));

        // render the wrapped component with the URL props added in.
        return <WrappedComponent {...propsWithUrl} />;
      }
    }

    return AddUrlProps;
  };
}
<commit_msg>Make change handler generated name configurable<commit_after>import React, { Component, PropTypes } from 'react';
import { parse as parseQueryString } from 'query-string';

import urlQueryDecoder from '../urlQueryDecoder';
import urlQueryConfig from '../urlQueryConfig';
import { updateUrlQuerySingle } from '../updateUrlQuery';
import { encode } from '../serialize';

/**
 * Creates a change handler name for a given prop name.
 * foo => onChangeFoo
 */
function defaultChangeHandlerName(propName) {
  return `onChange${propName[0].toUpperCase()}${propName.substring(1)}`;
}

/**
 * Higher order component (HOC) that injects URL query parameters as props.
 *
 * @param {Function} mapUrlToProps `function(url, props) -> {Object}` returns props to inject
 * @return {React.Component}
 */
export default function addUrlProps(options) {
  const {
    mapUrlToProps = d => d,
    mapUrlChangeHandlersToProps,
    urlPropsQueryConfig,
    addRouterParams,
    addUrlChangeHandlers,
  } = options;

  let {
    changeHandlerName,
  } = options;

  return function addPropsWrapper(WrappedComponent) {
    // caching to prevent unnecessary generation of new onChange functions
    let cachedHandlers;

    let decodeQuery;

    // initialize decode query (with cache) if a config is provided
    if (urlPropsQueryConfig) {
      decodeQuery = urlQueryDecoder(urlPropsQueryConfig);
    }

    /**
     * Parse the URL query into an object. If a urlPropsQueryConfig is provided
     * the values are decoded based on type.
     */
    function getUrlObject(props) {
      let location;

      // react-router provides it as a prop
      if (props.location && props.location.query) {
        location = props.location;

      // check in history
      } else if (urlQueryConfig.history.location) {
        location = urlQueryConfig.history.location;

      // not found. just use location from window
      } else {
        location = window.location;
      }

      const currentQuery = location.query || parseQueryString(location.search) || {};

      let result;
      // if a url query decoder is provided, decode the query then return that.
      if (decodeQuery) {
        result = decodeQuery(currentQuery);
      } else {
        result = currentQuery;
      }

      // add in react-router params if requested
      if (addRouterParams || (addRouterParams !== false && urlQueryConfig.addRouterParams)) {
        Object.assign(result, props.params);
      }

      return result;
    }

    const displayName = WrappedComponent.displayName || WrappedComponent.name || 'Component';
    class AddUrlProps extends Component {
      static displayName = `AddUrlProps(${displayName})`
      static WrappedComponent = WrappedComponent
      static propTypes = {
        location: PropTypes.object, // eslint-disable-line react/forbid-prop-types
      }

      /**
       * Create URL change handlers based on props, the urlPropsQueryConfig (if provided),
       * and mapUrlChangeHandlersToProps (if provided).
       * As a member function so we can read `this.props` in generated handlers dynamically.
       */
      getUrlChangeHandlerProps(propsWithUrl) {
        let handlers;

        if (urlPropsQueryConfig) {
          // if we have a props->query config, generate the change handler props unless
          // addUrlChangeHandlers is false
          if (addUrlChangeHandlers || (addUrlChangeHandlers == null && urlQueryConfig.addUrlChangeHandlers)) {
            // use cache if available. Have to do this since urlQueryConfig can change between
            // renders (although that is unusual).
            if (cachedHandlers) {
              handlers = cachedHandlers;
            } else {
              // read in function from options for how to generate a name from a prop
              if (!changeHandlerName) {
                changeHandlerName = urlQueryConfig.changeHandlerName || defaultChangeHandlerName;
              }

              // for each URL config prop, create a handler
              handlers = Object.keys(urlPropsQueryConfig).reduce((handlersAccum, propName) => {
                const { updateType, queryParam = propName, type } = urlPropsQueryConfig[propName];

                // name handler for `foo` => `onChangeFoo`
                const handlerName = changeHandlerName(propName);

                // handler encodes the value and updates the URL with the encoded value
                // based on the `updateType` in the config. Default is `replaceIn`
                handlersAccum[handlerName] = function generatedUrlChangeHandler(value) {
                  const encodedValue = encode(type, value);
                  updateUrlQuerySingle(updateType, queryParam, encodedValue, this.props.location);
                }.bind(this); // bind this so we can access props dynamically

                return handlersAccum;
              }, {});

              // cache these so we don't regenerate new functions every render
              cachedHandlers = handlers;
            }
          }
        }

        // if a manual mapping function is provided, use it, passing in the auto-generated
        // handlers as an optional secondary argument.
        if (mapUrlChangeHandlersToProps) {
          handlers = mapUrlChangeHandlersToProps(propsWithUrl, handlers);
        }

        return handlers;
      }

      render() {
        // get the url query parameters as an object mapping name to value.
        // if a config is provided, these are decoded based on their `type` and their
        // name will match the prop name.
        // if no config is provided, they are not decoded and their names are whatever
        // they were in the URL.
        const url = getUrlObject(this.props);

        // pass to mapUrlToProps for further decoding if provided
        const propsWithUrl = Object.assign({}, this.props, mapUrlToProps(url, this.props));

        // add in the URL change handlers - either auto-generated based on config
        // or from mapUrlChangeHandlersToProps.
        Object.assign(propsWithUrl, this.getUrlChangeHandlerProps(propsWithUrl));

        // render the wrapped component with the URL props added in.
        return <WrappedComponent {...propsWithUrl} />;
      }
    }

    return AddUrlProps;
  };
}
<|endoftext|>


<commit_before>import React from 'react';
import { SprkCard } from '@sparkdesignsystem/spark-react';
import { Link } from 'react-router-dom';
import CentralColumnLayout from '../../containers/CentralColumnLayout/CentralColumnLayout';
import ExampleContainer from '../../containers/ExampleContainer/ExampleContainer';

const SprkCardDocs = () => {
  const testHighlightedHeaderConfig = {
    bodyText: `Highlight header card body text.
        Lorem ipsum dolor sit amet, doctus invenire vix te.
        Facilisi perpetua an pri, errem commune mea at,
        mei prima tantas signiferumque at.
        Numquam.`,
    title: 'Highlight Header Card Title',
    description: 'Highlight Header Description',
  };

  const stackedTeaserImage = {
    bodyText: 'Body text of a teaser card.',
    cta: {
      ctaAnalytics: 'test',
      text: 'Learn More',
      ctaVariant: 'link',
      href: 'https://sparkdesignsystem.com/',
    },
    media: {
      href: 'https://sparkdesignsystem.com/',
      mediaLinkElement: 'a',
      imgAlt: 'placeholder image',
      imgSrc: 'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
      mediaAnalyticsString: 'Card:teaser-link',
      mediaVariant: 'img',
    },
    title: 'Teaser Card Title',
    titleFirst: false,
  };

  const stackedTeaserIcon = {
    bodyText: 'Body text of a teaser card.',
    cta: {
      ctaAnalytics: 'test',
      text: 'Learn More',
      ctaVariant: 'link',
      href: 'https://sparkdesignsystem.com/',
    },
    media: {
      additionalMediaIconClasses: 'sprk-c-Icon--xxl',
      href: 'https://sparkdesignsystem.com/',
      mediaLinkElement: 'a',
      iconName: 'call-team-member',
      mediaVariant: 'icon',
    },
    title: 'Teaser Card Title',
    titleFirst: false,
  };

  return (
    <CentralColumnLayout>
      <ExampleContainer>

Base Card

        <SprkCard
          additionalContentClasses="
            sprk-o-Stack
            sprk-o-Stack--large"
        >
          Base Card Content
        </SprkCard>
      </ExampleContainer>

      <ExampleContainer>

Standout Card

        <SprkCard
          isStandout
          additionalContentClasses="
            sprk-o-Stack
            sprk-o-Stack--medium"
        >
          Standout Card Content
        </SprkCard>
      </ExampleContainer>

      <ExampleContainer>

          Card with Highlighted Header

        <SprkCard
          highlightedHeaderConfig={testHighlightedHeaderConfig}
          idString="card-with-highlighted-header"
          isStandout
          variant="highlightedHeader"
        />
      </ExampleContainer>

      <ExampleContainer>

          Image / Anchor / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Image / Anchor / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Image / Router / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              ctaLinkElement: Link,
              to: '/cards',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Router link / Link

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              ctaLinkElement: Link,
              to: '/cards',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              to: 'https://sparkdesignsystem.com/',
              mediaLinkElement: Link,
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Router link / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              ctaLinkElement: Link,
              to: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              to: 'https://sparkdesignsystem.com/',
              mediaLinkElement: Link,
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Anchor / Link

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              ctaLinkElement: 'a',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Router Link / Link with Icon

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              ctaIcon: 'chevron-right',
              ctaLinkElement: Link,
              to: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              to: 'https://sparkdesignsystem.com/',
              mediaLinkElement: Link,
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Title First / Image / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: true,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Title First / Icon / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              iconName: 'call-team-member',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: true,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Card Layout - Two Up

          <SprkCard
            idString="1"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="2"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserImage}
          />

      </ExampleContainer>

      <ExampleContainer>

          Card Layout - Three Up

          <SprkCard
            idString="card-1"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserIcon}
          />
          <SprkCard
            idString="card-2"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserIcon}
          />
          <SprkCard
            idString="card-3"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserIcon}
          />

      </ExampleContainer>
      <ExampleContainer>

          Card Layout - Four Up

          <SprkCard
            idString="1"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="2"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="3"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="4"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />

      </ExampleContainer>
    </CentralColumnLayout>
  );
};

export default SprkCardDocs;
<commit_msg>correct first teaser  spark card docs<commit_after>import React from 'react';
import { SprkCard } from '@sparkdesignsystem/spark-react';
import { Link } from 'react-router-dom';
import CentralColumnLayout from '../../containers/CentralColumnLayout/CentralColumnLayout';
import ExampleContainer from '../../containers/ExampleContainer/ExampleContainer';

const SprkCardDocs = () => {
  const testHighlightedHeaderConfig = {
    bodyText: `Highlight header card body text.
        Lorem ipsum dolor sit amet, doctus invenire vix te.
        Facilisi perpetua an pri, errem commune mea at,
        mei prima tantas signiferumque at.
        Numquam.`,
    title: 'Highlight Header Card Title',
    description: 'Highlight Header Description',
  };

  const stackedTeaserImage = {
    bodyText: 'Body text of a teaser card.',
    cta: {
      ctaAnalytics: 'test',
      text: 'Learn More',
      ctaVariant: 'link',
      href: 'https://sparkdesignsystem.com/',
    },
    media: {
      href: 'https://sparkdesignsystem.com/',
      mediaLinkElement: 'a',
      imgAlt: 'placeholder image',
      imgSrc: 'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
      mediaAnalyticsString: 'Card:teaser-link',
      mediaVariant: 'img',
    },
    title: 'Teaser Card Title',
    titleFirst: false,
  };

  const stackedTeaserIcon = {
    bodyText: 'Body text of a teaser card.',
    cta: {
      ctaAnalytics: 'test',
      text: 'Learn More',
      ctaVariant: 'link',
      href: 'https://sparkdesignsystem.com/',
    },
    media: {
      additionalMediaIconClasses: 'sprk-c-Icon--xxl',
      href: 'https://sparkdesignsystem.com/',
      mediaLinkElement: 'a',
      iconName: 'call-team-member',
      mediaVariant: 'icon',
    },
    title: 'Teaser Card Title',
    titleFirst: false,
  };

  return (
    <CentralColumnLayout>
      <ExampleContainer>

Base Card

        <SprkCard
          additionalContentClasses="
            sprk-o-Stack
            sprk-o-Stack--large"
        >
          Base Card Content
        </SprkCard>
      </ExampleContainer>

      <ExampleContainer>

Standout Card

        <SprkCard
          isStandout
          additionalContentClasses="
            sprk-o-Stack
            sprk-o-Stack--medium"
        >
          Standout Card Content
        </SprkCard>
      </ExampleContainer>

      <ExampleContainer>

          Card with Highlighted Header

        <SprkCard
          highlightedHeaderConfig={testHighlightedHeaderConfig}
          idString="card-with-highlighted-header"
          isStandout
          variant="highlightedHeader"
        />
      </ExampleContainer>

      <ExampleContainer>

          Image / Anchor / Link

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Image / Anchor / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Image / Router / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              ctaLinkElement: Link,
              to: '/cards',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Router link / Link

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              ctaLinkElement: Link,
              to: '/cards',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              to: 'https://sparkdesignsystem.com/',
              mediaLinkElement: Link,
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Router link / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              ctaLinkElement: Link,
              to: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              to: 'https://sparkdesignsystem.com/',
              mediaLinkElement: Link,
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Anchor / Link

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              ctaLinkElement: 'a',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Icon / Router Link / Link with Icon

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'link',
              ctaIcon: 'chevron-right',
              ctaLinkElement: Link,
              to: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              to: 'https://sparkdesignsystem.com/',
              mediaLinkElement: Link,
              iconName: 'call-team-member',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: false,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Title First / Image / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'img',
            },
            title: 'Teaser Card Title',
            titleFirst: true,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Title First / Icon / Button

        <SprkCard
          idString="test"
          variant="teaser"
          teaserConfig={{
            bodyText: 'Body text of a teaser card.',
            cta: {
              ctaAnalytics: 'test',
              text: 'Learn More',
              ctaVariant: 'button',
              href: 'https://sparkdesignsystem.com/',
            },
            media: {
              additionalMediaIconClasses: 'sprk-c-Icon--xxl',
              href: 'https://sparkdesignsystem.com/',
              mediaLinkElement: 'a',
              iconName: 'call-team-member',
              imgAlt: 'placeholder image',
              imgSrc:
                'https://sparkdesignsystem.com/assets/toolkit/images/desktop.jpg',
              mediaAnalyticsString: 'Card:teaser-link',
              mediaVariant: 'icon',
            },
            title: 'Teaser Card Title',
            titleFirst: true,
          }}
        />
      </ExampleContainer>

      <ExampleContainer>

          Card Layout - Two Up

          <SprkCard
            idString="1"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="2"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserImage}
          />

      </ExampleContainer>

      <ExampleContainer>

          Card Layout - Three Up

          <SprkCard
            idString="card-1"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserIcon}
          />
          <SprkCard
            idString="card-2"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserIcon}
          />
          <SprkCard
            idString="card-3"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@l"
            teaserConfig={stackedTeaserIcon}
          />

      </ExampleContainer>
      <ExampleContainer>

          Card Layout - Four Up

          <SprkCard
            idString="1"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="2"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="3"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />
          <SprkCard
            idString="4"
            variant="teaser"
            additionalClasses="sprk-o-Stack__item sprk-o-Stack__item--flex@xl"
            teaserConfig={stackedTeaserImage}
          />

      </ExampleContainer>
    </CentralColumnLayout>
  );
};

export default SprkCardDocs;
<|endoftext|>


<commit_before>import { createElement } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import GeFormRenderer from 'c/geFormRenderer';
import GeLabelService from 'c/geLabelService';

import upsertDataImport from '@salesforce/apex/GE_GiftEntryController.upsertDataImport';
import retrieveDefaultSGERenderWrapper from '@salesforce/apex/GE_GiftEntryController.retrieveDefaultSGERenderWrapper';
import sendPurchaseRequest from '@salesforce/apex/GE_GiftEntryController.sendPurchaseRequest';
import getAllocationsSettings from '@salesforce/apex/GE_GiftEntryController.getAllocationsSettings';

import { mockCheckInputValidity } from 'lightning/input';
import { mockCheckComboboxValidity } from 'lightning/combobox';
import { mockGetIframeReply } from 'c/psElevateTokenHandler';

const mockWrapperWithNoNames = require('./data/retrieveDefaultSGERenderWrapper.json');
const getRecordContact1Imported = require('./data/getRecordContact1Imported.json');
const dataImportObjectInfo = require('./data/dataImportObjectInfo.json');
const allocationsSettingsNoDefaultGAU = require('./data/allocationsSettingsNoDefaultGAU.json');

describe('c-ge-form-renderer', () => {

    afterEach(() => {
        clearDOM();
        jest.clearAllMocks();
    });

    it('loads a template with four sections', async () => {

        retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
        getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);
        const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });

        document.body.appendChild(element);
        await flushPromises();

        expect(retrieveDefaultSGERenderWrapper).toHaveBeenCalledTimes(1);
        const sections = element.shadowRoot.querySelectorAll('c-ge-form-section');
        expect(sections).toHaveLength(4);
    });

    it('form when saving without filling anything in should result in a page level error for missing fields', async () => {
        retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
        // This error is specific to this mockRenderWrapperWithNoNames
        // Donor Type, Donation Date, Donation Amount, Payment Method should appear as required
        getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

        mockCheckInputValidity.mockReturnValue(true); // lightning-input is always valid
        mockCheckComboboxValidity.mockReturnValue(true); // lightning-combobox is always valid

        const element = createElement('c-ge-form-renderer', {is: GeFormRenderer});
        document.body.appendChild(element);

        await flushPromises();
        const saveButton = element.shadowRoot.querySelectorAll('lightning-button')[1];
        saveButton.click();

        await flushPromises();

        const pageLevelMessage = element.shadowRoot.querySelector('c-util-page-level-message');
        const pElement = pageLevelMessage.querySelector('p');

        expect(pElement.innerHTML).toBe('The following fields are required: Donor Type, Donation Date, Donation Amount');
    });

    it('form with payment widget, when payment method changed to credit card then payment iframe loads', async () => {
        retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);

        mockCheckInputValidity.mockReturnValue(true); // lightning-input will always report it is valid
        mockCheckComboboxValidity.mockReturnValue(true); // lightning-combobox will always report it is valid
        getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

        const element = createElement('c-ge-form-renderer', {is: GeFormRenderer});
        document.body.appendChild(element);
        await flushPromises();

        const sectionWithWidget = element.shadowRoot.querySelectorAll('c-ge-form-section')[0];
        expect(sectionWithWidget.isPaymentWidgetAvailable).toBeTruthy();

        dispatchFormFieldChange(sectionWithWidget, 'Credit Card', 'Payment_Method_87c012365');
        await flushPromises();

        const {commonPaymentServices} = GeLabelService.CUSTOM_LABELS;
        const iframeSelector = `iframe[data-id='${commonPaymentServices}']`;
        const selectors = ['c-ge-form-widget', 'c-ge-form-widget-tokenize-card', iframeSelector];
        const iframeElement = traverse(sectionWithWidget, ...selectors);

        expect(iframeElement).toMatchSnapshot();
    });

    it('form without contact firstname when lookup populated and widget in chargeable state then sendPurchaseRequest is called with first name',
        async () => {
            const EXPECTED_PURCHASE_BODY_PARAMS = JSON.stringify({
                "firstName": "DummyFirstName",
                "lastName": "DummyLastName",
                "metadata": {},
                "amount": 1,
                "paymentMethodToken": "a_dummy_token",
                "paymentMethodType": "CARD"
            });
            const EXPECTED_UPSERT_DATAIMPORT_FIELDS = {
                Donation_Donor__c: 'Contact',
                Contact1Imported__c: '003J000001zoYLGIA2',
                Donation_Date__c: '2021-02-23',
                Donation_Amount__c: '0.01',
                Payment_Authorization_Token__c: "a_dummy_token",
                Payment_Method__c: "Credit Card",
                Payment_Status__c: "PENDING"
            };
            const DUMMY_CONTACT_ID = '003J000001zoYLGIA2';

            retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
            mockCheckInputValidity.mockReturnValue(true); // lightning-inputs always report they are valid
            mockCheckComboboxValidity.mockReturnValue(true); // lightning-comboboxes always report they are valid
            getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

            mockGetIframeReply.mockImplementation((iframe, message, targetOrigin) => {
                // if message action is "createToken", reply with dummy token immediately
                // instead of trying to hook into postMessage
                // see sendIframeMessage in mocked psElevateTokenHandler
                if (message.action === 'createToken') {
                    return {"type": "post__npsp", "token": "a_dummy_token"};
                }
            });

            upsertDataImport.mockImplementation((dataImport) => {
                return { Id: 'fakeDataImportId', ...dataImport };
            });

            const element = createElement('c-ge-form-renderer', {is: GeFormRenderer});
            document.body.appendChild(element);

            getObjectInfo.emit(dataImportObjectInfo, config => {
                return config.objectApiName.objectApiName === 'DataImport__c';
            });

            await flushPromises();

            const sectionWithWidget = element.shadowRoot.querySelectorAll('c-ge-form-section')[0];

            expect(sectionWithWidget.isPaymentWidgetAvailable).toBeTruthy();

            dispatchFormFieldChange(sectionWithWidget, 'Credit Card', 'Payment_Method_87c012365');
            dispatchFormFieldChange(sectionWithWidget, 'Contact', 'Donation_Donor__c');
            dispatchFormFieldChange(sectionWithWidget, '0.01', 'Donation_Amount_9e48e0798');
            dispatchFormFieldChange(sectionWithWidget, '2021-02-23', 'Donation_Date_de92fcb14');
            dispatchFormFieldChange(sectionWithWidget, DUMMY_CONTACT_ID, 'Contact1Imported__c');
            await flushPromises();

            // simulate getting back data for DUMMY_CONTACT_ID
            getRecord.emit(getRecordContact1Imported, config => {
                return config.recordId === DUMMY_CONTACT_ID;
            });
            await flushPromises();
            // resolve form updates before clicking save button

            const saveButton = element.shadowRoot.querySelectorAll('lightning-button')[1];
            saveButton.click();
            await flushPromises();

            expect(sendPurchaseRequest).toHaveBeenCalledTimes(1);
            expect(upsertDataImport).toHaveBeenCalledTimes(1);
            expect(sendPurchaseRequest).toHaveBeenLastCalledWith({
                dataImportRecordId: undefined,
                requestBodyParameters: EXPECTED_PURCHASE_BODY_PARAMS
            });
            expect(upsertDataImport).toHaveBeenLastCalledWith({
                dataImport: expect.objectContaining(EXPECTED_UPSERT_DATAIMPORT_FIELDS)
            });
            // first name should not be present in upsert request if not on template
            expect(upsertDataImport).toHaveBeenLastCalledWith({
                dataImport: expect.not.objectContaining({
                    Contact1_Firstname__c: expect.anything(),
                    Contact1_LastName__c: expect.anything()
                })
            });
        });
});

const traverse = (element, ...selectors) => {
    if(selectors.length === 1) {
        return element.shadowRoot.querySelector(selectors[0]);
    }
    const [firstSelector, ...rest] = selectors;
    const nextElement = element.shadowRoot.querySelector(firstSelector);
    return traverse(nextElement, ...rest);
}

const dispatchFormFieldChange = (element, value, fieldMappingDevName) => {
    const changeEvent = new CustomEvent('formfieldchange', {
        detail: {
            value,
            "label": value,
            fieldMappingDevName
        }
    });
    element.dispatchEvent(changeEvent);
};

<commit_msg>update jest test<commit_after>import { createElement } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import GeFormRenderer from 'c/geFormRenderer';
import GeLabelService from 'c/geLabelService';

import upsertDataImport from '@salesforce/apex/GE_GiftEntryController.upsertDataImport';
import retrieveDefaultSGERenderWrapper from '@salesforce/apex/GE_GiftEntryController.retrieveDefaultSGERenderWrapper';
import sendPurchaseRequest from '@salesforce/apex/GE_GiftEntryController.sendPurchaseRequest';
import getAllocationsSettings from '@salesforce/apex/GE_GiftEntryController.getAllocationsSettings';

import { mockCheckInputValidity } from 'lightning/input';
import { mockCheckComboboxValidity } from 'lightning/combobox';
import { mockGetIframeReply } from 'c/psElevateTokenHandler';

const mockWrapperWithNoNames = require('./data/retrieveDefaultSGERenderWrapper.json');
const getRecordContact1Imported = require('./data/getRecordContact1Imported.json');
const dataImportObjectInfo = require('./data/dataImportObjectInfo.json');
const allocationsSettingsNoDefaultGAU = require('./data/allocationsSettingsNoDefaultGAU.json');

describe('c-ge-form-renderer', () => {

    afterEach(() => {
        clearDOM();
        jest.clearAllMocks();
    });

    it('loads a template with four sections', async () => {

        retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
        getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);
        const element = createElement('c-ge-form-renderer', {is: GeFormRenderer });

        document.body.appendChild(element);
        await flushPromises();

        expect(retrieveDefaultSGERenderWrapper).toHaveBeenCalledTimes(1);
        const sections = element.shadowRoot.querySelectorAll('c-ge-form-section');
        expect(sections).toHaveLength(4);
    });

    it('form when saving without filling anything in should result in a page level error for missing fields', async () => {
        retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
        // This error is specific to this mockRenderWrapperWithNoNames
        // Donor Type, Donation Date, Donation Amount, Payment Method should appear as required
        getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

        mockCheckInputValidity.mockReturnValue(true); // lightning-input is always valid
        mockCheckComboboxValidity.mockReturnValue(true); // lightning-combobox is always valid

        const element = createElement('c-ge-form-renderer', {is: GeFormRenderer});
        document.body.appendChild(element);

        await flushPromises();
        const saveButton = element.shadowRoot.querySelectorAll('lightning-button')[1];
        saveButton.click();

        await flushPromises();

        const pageLevelMessage = element.shadowRoot.querySelector('c-util-page-level-message');
        const pElement = pageLevelMessage.querySelector('p');

        expect(pElement.innerHTML).toBe('The following fields are required: Donor Type, Donation Date, Donation Amount');
    });

    it('form with payment widget, when payment method changed to credit card then payment iframe loads', async () => {
        retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);

        mockCheckInputValidity.mockReturnValue(true); // lightning-input will always report it is valid
        mockCheckComboboxValidity.mockReturnValue(true); // lightning-combobox will always report it is valid
        getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

        const element = createElement('c-ge-form-renderer', {is: GeFormRenderer});
        document.body.appendChild(element);
        await flushPromises();

        const sectionWithWidget = element.shadowRoot.querySelectorAll('c-ge-form-section')[0];
        expect(sectionWithWidget.isPaymentWidgetAvailable).toBeTruthy();

        dispatchFormFieldChange(sectionWithWidget, 'Credit Card', 'Payment_Method_87c012365');
        await flushPromises();

        const {commonPaymentServices} = GeLabelService.CUSTOM_LABELS;
        const iframeSelector = `iframe[data-id='${commonPaymentServices}']`;
        const selectors = ['c-ge-form-widget', 'c-ge-form-widget-tokenize-card', iframeSelector];
        const iframeElement = traverse(sectionWithWidget, ...selectors);

        expect(iframeElement).toMatchSnapshot();
    });

    it('form without contact firstname when lookup populated and widget in chargeable state then sendPurchaseRequest is called with first name',
        async () => {
            const EXPECTED_PURCHASE_BODY_PARAMS = JSON.stringify({
                "firstName": "DummyFirstName",
                "lastName": "DummyLastName",
                "metadata": {},
                "amount": 1,
                "paymentMethodToken": "a_dummy_token",
                "paymentMethodType": "CARD"
            });
            const EXPECTED_UPSERT_DATAIMPORT_FIELDS = {
                Donation_Donor__c: 'Contact',
                Contact1Imported__c: '003J000001zoYLGIA2',
                Donation_Date__c: '2021-02-23',
                Donation_Amount__c: '0.01',
                Payment_Method__c: "Credit Card",
                Payment_Status__c: "PENDING"
            };
            const DUMMY_CONTACT_ID = '003J000001zoYLGIA2';

            retrieveDefaultSGERenderWrapper.mockResolvedValue(mockWrapperWithNoNames);
            mockCheckInputValidity.mockReturnValue(true); // lightning-inputs always report they are valid
            mockCheckComboboxValidity.mockReturnValue(true); // lightning-comboboxes always report they are valid
            getAllocationsSettings.mockResolvedValue(allocationsSettingsNoDefaultGAU);

            mockGetIframeReply.mockImplementation((iframe, message, targetOrigin) => {
                // if message action is "createToken", reply with dummy token immediately
                // instead of trying to hook into postMessage
                // see sendIframeMessage in mocked psElevateTokenHandler
                if (message.action === 'createToken') {
                    return {"type": "post__npsp", "token": "a_dummy_token"};
                }
            });

            upsertDataImport.mockImplementation((dataImport) => {
                return { Id: 'fakeDataImportId', ...dataImport };
            });

            const element = createElement('c-ge-form-renderer', {is: GeFormRenderer});
            document.body.appendChild(element);

            getObjectInfo.emit(dataImportObjectInfo, config => {
                return config.objectApiName.objectApiName === 'DataImport__c';
            });

            await flushPromises();

            const sectionWithWidget = element.shadowRoot.querySelectorAll('c-ge-form-section')[0];

            expect(sectionWithWidget.isPaymentWidgetAvailable).toBeTruthy();

            dispatchFormFieldChange(sectionWithWidget, 'Credit Card', 'Payment_Method_87c012365');
            dispatchFormFieldChange(sectionWithWidget, 'Contact', 'Donation_Donor__c');
            dispatchFormFieldChange(sectionWithWidget, '0.01', 'Donation_Amount_9e48e0798');
            dispatchFormFieldChange(sectionWithWidget, '2021-02-23', 'Donation_Date_de92fcb14');
            dispatchFormFieldChange(sectionWithWidget, DUMMY_CONTACT_ID, 'Contact1Imported__c');
            await flushPromises();

            // simulate getting back data for DUMMY_CONTACT_ID
            getRecord.emit(getRecordContact1Imported, config => {
                return config.recordId === DUMMY_CONTACT_ID;
            });
            await flushPromises();
            // resolve form updates before clicking save button

            const saveButton = element.shadowRoot.querySelectorAll('lightning-button')[1];
            saveButton.click();
            await flushPromises();

            expect(sendPurchaseRequest).toHaveBeenCalledTimes(1);
            expect(upsertDataImport).toHaveBeenCalledTimes(1);
            expect(sendPurchaseRequest).toHaveBeenLastCalledWith({
                dataImportRecordId: undefined,
                requestBodyParameters: EXPECTED_PURCHASE_BODY_PARAMS
            });
            expect(upsertDataImport).toHaveBeenLastCalledWith({
                dataImport: expect.objectContaining(EXPECTED_UPSERT_DATAIMPORT_FIELDS)
            });
            // first name should not be present in upsert request if not on template
            expect(upsertDataImport).toHaveBeenLastCalledWith({
                dataImport: expect.not.objectContaining({
                    Contact1_Firstname__c: expect.anything(),
                    Contact1_LastName__c: expect.anything()
                })
            });
        });
});

const traverse = (element, ...selectors) => {
    if(selectors.length === 1) {
        return element.shadowRoot.querySelector(selectors[0]);
    }
    const [firstSelector, ...rest] = selectors;
    const nextElement = element.shadowRoot.querySelector(firstSelector);
    return traverse(nextElement, ...rest);
}

const dispatchFormFieldChange = (element, value, fieldMappingDevName) => {
    const changeEvent = new CustomEvent('formfieldchange', {
        detail: {
            value,
            "label": value,
            fieldMappingDevName
        }
    });
    element.dispatchEvent(changeEvent);
};

<|endoftext|>