Skip to content

Commit

Permalink
Merge branch 'master' into plugin-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rachelnicole committed Jun 16, 2016
2 parents 8f7606f + 6e306fc commit fda6196
Show file tree
Hide file tree
Showing 12 changed files with 393 additions and 16 deletions.
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{long description}}

```gherkin
Feature: {{feature}}
As a {{persona}}
I want {{need}}
So that {{rationale}}
Scenario: {{scenario}}
Given {{thing}}
When {{action}}
Then {{result}}
```

---

- [ ] {{feature}}/{{scenario}}
25 changes: 25 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{{short description}}

**Changelog**

```markdown
**New**

* {{new thing}}
* {{other new thing}}

**Changed**

* {{change thing}}
* {{other change thing}}

**Removed**

* {{removed thing}}
* {{other removed thing}}
```

---
Resolves: #

`DCO 1.1 Signed-off-by: {{full name}} <{{email address}}>`
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Contributing to Punchcard Content Types

Please follow the [Punchcard Contributing Guidelines](https://github.com/punchcard-cms/punchcard/blob/master/CONTRIBUTING.md)
37 changes: 37 additions & 0 deletions lib/content-types/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,31 @@ const _ = require('lodash');
*/
const plugins = plugabilly().name().containsSync('input-plugin-');

/*
* Determine required level
*
* @param {string} level - `required` level written in config
*
* @returns {string} system-compliant level string
*/
const requiredLevel = (level) => {
if ((level === true) || (level === 'save') || (level === 2)) {
return 'save';
}
if ((level === 'publish') || (level === 1)) {
return 'publish';
}

return false;
};

/*
* Combine content types configurations with input plugins
*
* @param {array} types - content types configurations
*
* @returns {promise} - combined content type with input plugin configs
*/
const squish = (types) => {
return new Promise((resolve, reject) => {
if (!Array.isArray(types)) {
Expand Down Expand Up @@ -64,6 +89,10 @@ const squish = (types) => {
if (attribute.description) {
plugin.description = attribute.description;
}
if (attribute.required) {
plugin.required = requiredLevel(attribute.required);
}

plugin.id = attribute.id;
plugin.type = attribute.type;

Expand All @@ -85,6 +114,14 @@ const squish = (types) => {
merged.validation = plugin.inputs[attr].validation;
merged.type = plugin.inputs[attr].type;

// add required if it doesn't exist
if (!merged.hasOwnProperty('required')) {
merged.required = plugin.required;
}
else {
merged.required = requiredLevel(merged.required);
}

plugin.inputs[attr] = merged;
}
});
Expand Down
87 changes: 79 additions & 8 deletions lib/form/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const addError = (html, input, errors) => {
if (errors) {
Object.keys(input.inputs).map(inp => {
const name = `${input.id}--${inp}`;
const find = new RegExp(`/name=['"]\\s*${name}\\s*['"]/`);
const find = new RegExp(`name=['"]\\s*${name}\\s*['"]`);
const errored = render.replace(find, `name="${name}" aria-invalid="true"`);

if (errors.hasOwnProperty(name)) {
Expand All @@ -29,7 +29,75 @@ const addError = (html, input, errors) => {
});
}

result += html;
result += render;

return result;
};

/*
* Add Required Rendered Inputs
*
* @param {string} html - Rendered HTML
* @param {InputType} type - Input type being rendered
*
* @returns {string} - Rendered HTML, with required indicators
*/
const addRequired = (html, input) => {
let render = html;
let result = '';

Object.keys(input.inputs).map(inp => {
if (input.required === 'save' || input.inputs[inp].required === 'save' || input.required === 'publish' || input.inputs[inp].required === 'publish') {
const id = input.inputs[inp].id;
let level = '';

if (input.inputs[inp].hasOwnProperty('required')) {
level += `required--${input.inputs[inp].required}`;
}
else {
level += `required--${input.required}`;
}

// pre-regex strings
const stringClass = 'class=["\'][\\w\\W\\s]+?["\']';
const stringFor = `for=["']\\s*${input.inputs[inp].id}\\s*["']`;

// regex to get the label for THIS input
const regexLabel = new RegExp(`.*(<label[\\w\\W\\s]*${stringFor}[\\w\\W\\s]*?>)`);

// THIS input's label
const label = render.match(regexLabel);

// regex to get first class attributes from the captured label
const regexClass = new RegExp(`.*(${stringClass})`);

// regex to get classes out of `class`
const regexClasses = new RegExp('class=["\']([\\w\\s\\W]+?)["\']');

// regex to search for `for`
const reFor = new RegExp(`(${stringFor})`);

// first, check if `class` exists in label
if (Array.isArray(label[1].match(regexClass))) {
const cls = label[1].match(regexClass);
const classAttr = cls[1].match(regexClasses);
const classes = classAttr[1].split(/\s+/).concat([level]);
const newClass = `class="${classes.join(' ')}"`;
render = render.replace(label[0], label[0].replace(classAttr[0], newClass));
}
else {
// else, we add class after the `for` attribute
render = render.replace(reFor, `for="${id}" class="${level}"`);
}

// add required to input
const name = `${input.id}--${inp}`;
const reName = new RegExp(`name=['"]\\s*${name}\\s*['"]`);
render = render.replace(reName, `name="${name}" aria-required="true" required`);
}
});

result += render;

return result;
};
Expand All @@ -50,23 +118,27 @@ const renderer = (type, errors) => {
const context = input.inputs;
const html = nunjucks.renderString(input.html, context);
let render = '';
let required = '';
if (input.hasOwnProperty('required')) {
required = `required--${input.required}`;
}

// Set opening tags based on number of inputs
if (inputs > 1) {
render += `<fieldset id="${input.id}" class="form--fieldset">`;
render += `<lengend class="form--lengend">${input.name}</lengend>`;
render += `<fieldset id="${input.id}" class="form--fieldset ${required}">`;
render += `<legend class="form--legend">${input.name}</legend>`;

// Add Description
if (description) {
render += `<p class="form--description">${input.description}</p>`;
}
}
else {
render += `<div id="${input.id}" class="form--field">`;
render += `<div id="${input.id}" class="form--field ${required}">`;
}

// Render the form element
render += addError(html, input, errors);
// Add error messaging and required
render += addRequired(addError(html, input, errors), input);

// Set closing tags based on number of inputs
if (inputs > 1) {
Expand All @@ -84,7 +156,6 @@ const renderer = (type, errors) => {
});

rendered = rendered.join('\n\n');

res(rendered);
});
};
Expand Down
30 changes: 28 additions & 2 deletions lib/form/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,29 @@ const buildValues = working => {
return values;
};

/*
* Checks for required fields before running validation
*
* @param {object} input - Input Type being tested
* @param {ValidationSettings} settings - All validation settings
*
* @returns {true|FormInputValues} - Returns `true` if there are no validation or required issues, {FormInputValues} with error messages as values if there are
*/
const valueCheck = (input, settings, validation) => {
if (input.target.hasOwnProperty('required') && (input.target.required === 'save' || input.target.required === 'publish') && input.target.value === '') {
return 'Field cannot be left blank!';
}

return validation(input, settings);
};

/*
* Validates the Raw Input
*
* @param {FormInputValues} raw - Raw form input
* @param {InputType} type - Individual input type
*
@returns {true|FormInputValues} - Returns `true` if there are no validation issues, {FormInputValues} with error messages as values if there are
* @returns {true|FormInputValues} - Returns `true` if there are no validation issues, {FormInputValues} with error messages as values if there are
*/
const validate = (raw, type) => {
let working = split(raw);
Expand All @@ -197,6 +213,16 @@ const validate = (raw, type) => {
input.target.value = result.value;
input.all = values[result.plugin];

// check if parent plugin is required
if (plugin.hasOwnProperty('required')) {
input.target.required = plugin.required;
}

// check if input is required, supersede main plugin
if (plugin.inputs[result.input].hasOwnProperty('required')) {
input.target.required = plugin.inputs[result.input].required;
}

if (typeof value.index !== 'undefined') {
input.all = input.all[result.index];
}
Expand All @@ -206,7 +232,7 @@ const validate = (raw, type) => {
settings.all = allSettings[value.plugin];

// Run the validation function
result.validation = plugin.validation[plugin.inputs[result.input].validation.function](input, settings);
result.validation = valueCheck(input, settings, plugin.validation[plugin.inputs[result.input].validation.function]);

return result;
});
Expand Down
12 changes: 11 additions & 1 deletion lib/form/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const rendered = (type) => {
inputs[inp.id] = {};
inputs[inp.id].name = input;
inputs[inp.id].validation = inp.validation;
inputs[inp.id].required = inp.required;
inputs[inp.id].settings = {};
inputs[inp.id].parent = {
id: plugin.id,
Expand Down Expand Up @@ -89,6 +90,14 @@ var allInputs = ${JSON.stringify(inputs)};
var allSettings = ${JSON.stringify(allSettings)};
var allIDs = ${JSON.stringify(ids)};
var valueCheck = function (input, settings, validation) {
if (input.target.required && (input.target.required === 'save' || input.target.required === 'publish') && input.target.value === '') {
return 'Field cannot be left blank!';
}
return validation(input, settings);
};
// Work those requires
Object.keys(allValidation).forEach(function(plugin) {
var plug = require(allValidation[plugin]);
Expand All @@ -114,6 +123,7 @@ var validate = function (e) {
input.target = {
value: value,
name: inp.name,
required: inp.required,
};
input.all = {};
input.all[inp.name] = value;
Expand All @@ -130,7 +140,7 @@ var validate = function (e) {
});
// Run the validation
validation = allValidation[inp.parent.type][inp.validation.function](input, settings);
validation = valueCheck(input, settings, allValidation[inp.parent.type][inp.validation.function]);
// Add/Remove validation
if (validation === true) {
Expand Down
12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "punchcard-content-types",
"version": "0.5.2",
"version": "0.6.0",
"description": "",
"main": "index.js",
"keywords": [
Expand Down Expand Up @@ -36,20 +36,23 @@
"node-dir": "^0.1.11",
"node-sass": "^3.4.2",
"nunjucks": "^2.4.0",
"plugabilly": "0.0.0",
"plugabilly": "^0.0.1",
"uuid": "^2.0.2"
},
"devDependencies": {
"ava": "^0.15.1",
"coveralls": "^2.11.9",
"eslint": "^2",
"eslint-config-punchcard": "^1.0.0",
"ghooks": "^1.2.4",
"input-plugin-datetime": "^0.0.1",
"input-plugin-email": "^0.1.0",
"input-plugin-quote": "0.0.1",
"input-plugin-text": "^0.0.5",
"input-plugin-textarea": "^0.0.1",
"nyc": "^6.0.0",
"open-exchange-rates": "^0.3.0",
"punchcard-commit-msg": "^1.0.0",
"raw-loader": "^0.5.1",
"tap-diff": "^0.1.1"
},
Expand All @@ -69,5 +72,10 @@
],
"failFast": true,
"tap": true
},
"config": {
"ghooks": {
"commit-msg": "punchcard-commit-msg"
}
}
}
9 changes: 6 additions & 3 deletions tests/content-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ test('merged', t => {
t.is(result[0].name, 'Content Type BAR', 'Get first content type name');
t.is(result[0].description, 'Bar Baz Foo', 'Get first content type desc');
t.is(result[0].id, 'bar', 'Get first content type id');
t.is(result[1].name, 'Content Type FOO', 'Get second content type name');
t.is(result[1].description, 'Foo Bar Baz', 'Get second content type desc');
t.is(result[1].id, 'foo', 'Get second content type id');
t.is(result[1].name, 'Content Type Baz', 'Get second content type name');
t.is(result[1].description, 'Bar Baz Foo', 'Get second content type desc');
t.is(result[1].id, 'baz', 'Get second content type id');
t.is(result[2].name, 'Content Type FOO', 'Get third content type name');
t.is(result[2].description, 'Foo Bar Baz', 'Get third content type desc');
t.is(result[2].id, 'foo', 'Get third content type id');
});
});

Expand Down
Loading

0 comments on commit fda6196

Please sign in to comment.