Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
CKEDITOR_BASEPATH = 'ckeditor/';
window.less = {async: true, fileSync: true};
</script>

<script src="node_modules/steal/steal.js" main="a2jauthor/app"></script>
</body>
</html>
3 changes: 2 additions & 1 deletion src/variables/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import DefineMap from 'can-define/map/map'
import Component from 'can-component'
import template from './editor.stache'
import constants from '~/src/models/constants'
import { vcGatherUsage } from './vcGatherUsage'

export const VariableEditorVM = DefineMap.extend('VariableEditorVM', {
/*
Expand Down Expand Up @@ -150,7 +151,7 @@ export const VariableEditorVM = DefineMap.extend('VariableEditorVM', {
onFindUsage () {
// use the initially loaded name in case they've edited it in the form before checking usage
const variableName = this.initialVarName
const html = window.vcGatherUsage(variableName)
const html = vcGatherUsage(variableName)
this.variableUsageHtml = html
}
})
Expand Down
15 changes: 15 additions & 0 deletions src/variables/editor/vcGatherUsage-test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html>

<title>vcGatherUsage Tests</title>

<div id="mocha"></div>
<div id="test-area"></div>

<script type="text/javascript">
window.less = {async: true, fileSync: true};
</script>

<script src="../../../node_modules/steal/steal.js"
mocha="bdd"
main="a2jauthor/src/variables/editor/vcGatherUsage-test"></script>
166 changes: 166 additions & 0 deletions src/variables/editor/vcGatherUsage-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import 'jquery'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see if jquery is required, if not, remove import

import { assert } from 'chai'
import 'steal-mocha'
import { vcGatherUsage, findMacroMatches, findLogicMatches, findLiteralMatches, findMatches} from './vcGatherUsage'

// Tests for these functions reflect that varname and testValue will be lowercase by the point they reach these functions

describe('findMacroMatches', function () {
it.only('returns matches based on A2J Macro Syntax', function () {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove .only so other tests can run

const matches = findMacroMatches('Enter your mailing address, %%[Client First Name TE ]%%', 'Client First Name TE')
const matches2 = findMacroMatches('Enter your mailing address, %%[Client First Name TE D]%%', 'Client First Name TE')
const matches3 = findMacroMatches('Enter your mailing address, %%[ Client First Name TE ]%%', 'Client First Name TE')

//explicit = true should pass, fail, pass
//explicit = false should pass all

assert.deepEqual(matches, ['[Client First Name TE ]'], 'Should find one match')
assert.deepEqual(matches2, ['[Client First Name TE D]'], 'Should find one match')
assert.deepEqual(matches3, [ '[ Client First Name TE ]' ], 'Should find one match')
})
})

describe('findLogicMatches', function () {
it.only('Returns true search target is matched', function () {
const matches = findLogicMatches('set client first name te to "matt"','client first name te')
const matches2 = findLogicMatches("set [client last name te] to 'matt'",'client first name te')

assert.deepEqual(matches, true, "should return true if match is found")
assert.deepEqual(matches2, null, "should return null if no match is found")
})
})

describe('findLiteralMatches', function () {
it.only('Returns true if target matches exactly', function () {
const matches = findLiteralMatches('client age', 'clientage')
const matches2 = findLiteralMatches('client age', 'CLIENT AGE')

assert.deepEqual(matches, [], "should return null if no match found")
assert.deepEqual(matches2, [ 'client age'], "Returns true if exact match")
})
})

//Find Matches currently needs regex type things to have bracket, paren, percent, logic and literal
describe('findMatches', function () {
it.only('Returns found if it finds a match', function() {
const testButton = {name:'', label:'', value:'', repeatVar:' [CLIENT FIRST NAME TE] ', url:''}
const testEntry = {key: 'repeatVar', type: 'regex', display: 'Button Counting Variable' }
const testVarName = 'Client First Name TE'

const found = findMatches(testButton, testEntry, testVarName)

assert.deepEqual(found, [ '[client first name te]' ], "testing")
})
})

describe('vcGatherUsage', function () {
let usageTestPage
const testProps = {
page: [
{ key: 'name', type: 'regex', display: 'Page Name' },
{ key: 'text', type: 'regex', display: 'Question Text' },
{ key: 'repeatVar', type: 'string', display: 'Counting Variable' },
{ key: 'outerLoopVar', type: 'string', display: 'Outer Loop Variable' },
{ key: 'learn', type: 'regex', display: 'LearnMore Prompt' },
{ key: 'help', type: 'regex', display: 'LearnMore Response' },
{ key: 'helpReader', type: 'regex', display: 'Video Transcript' },
{ key: 'codeBefore', type: 'logic', display: 'Before Logic' },
{ key: 'codeAfter', type: 'logic', display: 'After Logic' }
],
fields: [
{ key: 'label', type: 'regex', display: 'Field Label' },
{ key: 'name', type: 'string', display: 'Field Variable' },
{ key: 'value', type: 'regex', display: 'Field Default Value' },
{ key: 'invalidPrompt', type: 'regex', display: 'Field Custom Invalid Prompt' },
{ key: 'sample', type: 'regex', display: 'Field Sample Value' }
],
buttons: [
{ key: 'label', type: 'regex', display: 'Button Label' },
{ key: 'name', type: 'string', display: 'Button Variable Name' },
{ key: 'value', type: 'regex', display: 'Button Default Value' },
{ key: 'repeatVar', type: 'string', display: 'Button Counting Variable' },
{ key: 'url', type: 'regex', display: 'Button URL' }
]
}

beforeEach(() => {
usageTestPage = new window.TPage()
usageTestPage.fields = [new window.TField()]
usageTestPage.buttons = [new window.TButton()]

const gGuide = new window.TGuide()
window.gGuide = gGuide
window.gGuide.pages = { usageTestPage }
})

afterEach(() => {
window.gGuide = null
})

it('gathers usage on Page, Field, and Button level property values using variables', function () {
const setTestProps = (targetMap, propsToSet) => {
for (const entry of propsToSet) {
const prop = entry.key
if (entry.type === 'regex') {
targetMap[prop] = 'macro style %%[Number NU]%%'
} else if (entry.type === 'logic') {
targetMap[prop] = 'SET [Number NU] TO 1'
} else { // direct var set
targetMap[prop] = 'Number NU'
}
}
}
setTestProps(usageTestPage, testProps.page)
setTestProps(usageTestPage.fields[0], testProps.fields)
setTestProps(usageTestPage.buttons[0], testProps.buttons)

const foundMessage = vcGatherUsage('Number NU')
// if found, `display value` will be in foundMessage for each entry
for (const entry of testProps.page) {
const usedInPage = foundMessage.indexOf(entry.display) !== -1
assert.isTrue(usedInPage, `should find Number NU usage in page.${entry.key} by displaying ${entry.display} in returned foundMessage html`)
}
for (const entry of testProps.fields) {
const usedInField = foundMessage.indexOf(entry.display) !== -1
assert.isTrue(usedInField, `should find Number NU usage in field.${entry.key} by displaying ${entry.display} in returned foundMessage html`)
}
for (const entry of testProps.buttons) {
const usedInButton = foundMessage.indexOf(entry.display) !== -1
assert.isTrue(usedInButton, `should find Number NU usage in button.${entry.key} by displaying ${entry.display} in returned foundMessage html`)
}
})

it('gathers explicit usage on Page, Field, and Button level property values using variables', function () {
const setTestProps = (targetMap, propsToSet) => {
for (const entry of propsToSet) {
const prop = entry.key
if (entry.type === 'regex') {
targetMap[prop] = 'macro style %%[Number NU]%%'
} else if (entry.type === 'logic') {
targetMap[prop] = 'SET [Number123 NU] TO 1'
} else { // direct var set
targetMap[prop] = 'Number foo NU'
}
}
}

setTestProps(usageTestPage, testProps.page)
setTestProps(usageTestPage.fields[0], testProps.fields)
setTestProps(usageTestPage.buttons[0], testProps.buttons)

const foundMessage = vcGatherUsage('Number NU')
// if found, `display value` will be in foundMessage for each entry
for (const entry of testProps.page) {
const usedInPage = foundMessage.indexOf(entry.display) !== -1
assert.isTrue(usedInPage, `should find Number NU usage in page.${entry.key} by displaying ${entry.display} in returned foundMessage html`)
}
for (const entry of testProps.fields) {
const usedInField = foundMessage.indexOf(entry.display) !== -1
assert.isTrue(usedInField, `should find Number NU usage in field.${entry.key} by displaying ${entry.display} in returned foundMessage html`)
}
for (const entry of testProps.buttons) {
const usedInButton = foundMessage.indexOf(entry.display) !== -1
assert.isTrue(usedInButton, `should find Number NU usage in button.${entry.key} by displaying ${entry.display} in returned foundMessage html`)
}
})
})
152 changes: 152 additions & 0 deletions src/variables/editor/vcGatherUsage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { lowerCase } from "lodash"

const pageProps = [
{ key: 'name', type: 'regex', display: 'Page Name' },
{ key: 'text', type: 'regex', display: 'Question Text' },
{ key: 'repeatVar', type: 'string', display: 'Counting Variable' },
{ key: 'outerLoopVar', type: 'string', display: 'Outer Loop Variable' },
{ key: 'learn', type: 'regex', display: 'LearnMore Prompt' },
{ key: 'help', type: 'regex', display: 'LearnMore Response' },
{ key: 'helpReader', type: 'regex', display: 'Video Transcript' },
{ key: 'codeBefore', type: 'logic', display: 'Before Logic' },
{ key: 'codeAfter', type: 'logic', display: 'After Logic' }
]
const fieldProps = [
{ key: 'label', type: 'regex', display: 'Field Label' },
{ key: 'name', type: 'string', display: 'Field Variable' },
{ key: 'value', type: 'regex', display: 'Field Default Value' },
{ key: 'invalidPrompt', type: 'regex', display: 'Field Custom Invalid Prompt' },
{ key: 'sample', type: 'regex', display: 'Field Sample Value' }
]
const buttonProps = [
{ key: 'label', type: 'regex', display: 'Button Label' },
{ key: 'name', type: 'string', display: 'Button Variable Name' },
{ key: 'value', type: 'regex', display: 'Button Default Value' },
{ key: 'repeatVar', type: 'string', display: 'Button Counting Variable' },
{ key: 'url', type: 'regex', display: 'Button URL' }
]

/*

Type Match = {
pageName:
location:
foundCount:
}

*/

export const findMacroMatches = (testValue, lowerCaseVarName, explicit) => {
explicit = true;

//For greedy search, Regex looks for lowerCaseVarName followed by any character 0+ times, then white space 0+ times, then the closing half of bracket, paren, percent
const parenRegexString = `\\(\\s*${lowerCaseVarName}.*\\s*\\)`
const percentRegexString = `\\%\\s*${lowerCaseVarName}.*\\s*\\%`
const bracketRegexString = `\\[\\s*${lowerCaseVarName}.*\\s*\\]`

//For explicit search, Regex ends with '$', meaning nothing can follow
const parenRegexStringX = `\\(\\s*${lowerCaseVarName}\\s*\\)`
const percentRegexStringX = `\\%\\s*${lowerCaseVarName}\\s*\\%`
const bracketRegexStringX = `\\[\\s*${lowerCaseVarName}\\s*\\]`

const regexString = `${parenRegexString}|${percentRegexString}|${bracketRegexString}`
const regexStringX = `${parenRegexStringX}|${percentRegexStringX}|${bracketRegexStringX}`

//Checks explicit and uses the appropriate regexString to make macroRegex
const macroRegex = (explicit === false) ? new RegExp(regexString, 'ig'): new RegExp(regexStringX, 'ig')

const matches = testValue.match(macroRegex)

return matches ? matches :[]
}

export const findLogicMatches = (testValue, lowerCaseVarName) => {
const logicRegexString = `${lowerCaseVarName}`
const logicRegex = new RegExp(logicRegexString, 'ig')

const matches = testValue.match(logicRegex)

return matches ? matches :[]
}

export const findLiteralMatches =(testValue, lowerCaseVarName) => {
// finds variables assigned explicitly to buttons, fields, and counting variables
const literalRegexString = `${lowerCaseVarName}`
const literalRegex = new RegExp(literalRegexString, 'ig')

const matches = testValue.match(literalRegex)

return matches ? matches :[]
}

export const findMatches = (searchTarget, usageItem, varName) => {
// skip check if not string value to check
const prop = usageItem.key
if (!searchTarget[prop]) { return }

let found = []
let explicit

const testValue = searchTarget[prop].toLowerCase()
const lowerCaseVarName = varName.toLowerCase()

if (usageItem.type === 'regex') { // check for macro matches, `%%someVar%%`
found = findMacroMatches(testValue, lowerCaseVarName, explicit)
} else if (usageItem.type === 'logic') {
found = findLogicMatches(testValue, lowerCaseVarName)
} else {
found = findLiteralMatches(testValue, lowerCaseVarName)
}

return (found.length !== 0) ? usageItem.display : []
}

export function vcGatherUsage (varName, explicitSearch) { // 2015-03-27 Search for variable or constant
// alter below line to test two search methods
explicitSearch = true
let html = ''
let count = 0
let pageName

for (pageName in window.gGuide.pages) { // Search text, buttons, help, fields and logic for variable name.
/** @type TPage */
let where = [] // list where it's on this page
let pageMatches, fieldMatches, buttonMatches

const page = window.gGuide.pages[pageName]

// check top level page properties
for (const entry of pageProps) {
pageMatches = findMatches(page, entry, varName)
if(pageMatches && pageMatches.length > 1) {
where = [...where, pageMatches]
}
}

// check all page fields
for (const field of page.fields) {
for (const entry of fieldProps) {
fieldMatches = findMatches(field, entry, varName)
if(fieldMatches && fieldMatches.length > 1) {
where = [...where, fieldMatches]
}
}
}

// check all buttons
for (const button of page.buttons) {
for (const entry of buttonProps) {
buttonMatches = findMatches(button, entry, varName)
if(buttonMatches && buttonMatches.length > 1) {
where = [...where, buttonMatches]
}
}
}

if (where.length) { // If we found anything, we'll list the page and its location.
count++
html += ('<li>' + page.name + '</li><ul>' + '<li>' + where.join('<li>') + '</ul>')
}
}
return 'Used in ' + count + ' pages' + '<ul>' + html + '</ul>'
}
1 change: 1 addition & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ import 'a2jauthor/src/pages-tab/components/var-picker/field/var-picker-field-tes
// import 'a2jauthor/src/templates/edit/toolbar/toolbar-test'
// import 'a2jauthor/src/templates/list/item/item-test'
// import 'a2jauthor/src/templates/list/sortbar/sortbar-test'
import 'a2jauthor/src/variables/editor/vcGatherUsage-test.js'
Loading