├── .gitignore ├── index.js ├── readme.md ├── src ├── Helpers.js ├── fields │ ├── Group.js │ ├── FieldTransformer.js │ ├── ModuleField.js │ └── Field.js └── plugins │ └── FieldsPlugin.js ├── LICENSE ├── __tests__ └── Field.js ├── package.json ├── CHANGELOG.md └── CONTRIBUTING.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Group = require('./src/fields/Group'); 2 | const Field = require('./src/fields/Field'); 3 | const FieldsPlugin = require('./src/plugins/FieldsPlugin'); 4 | const { randomId, parseArgs } = require('./src/Helpers'); 5 | 6 | module.exports = { 7 | // Field + Group helpers 8 | Group, 9 | Field, 10 | // Webpack plugin 11 | FieldsPlugin, 12 | // Helpers 13 | randomId, 14 | parseArgs 15 | }; -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # HubSpot Fields JS 2 | 3 | ## iGoMoon's HubSpot FieldsJS package has moved! 4 | 5 | It is now part of our HubSpot Tool repository on GitHub 6 | 7 | [HubSpot Tools - https://github.com/iGoMoon/hubspot-tools](https://github.com/iGoMoon/hubspot-tools) 8 | 9 | 10 | [HubSpot Fields JS - https://github.com/iGoMoon/hubspot-tools/tree/main/packages/hubspot-fields-js](https://github.com/iGoMoon/hubspot-tools/tree/main/packages/hubspot-fields-js) 11 | 12 | You'll find the current and future version there. 13 | 14 | Happy Coding! -------------------------------------------------------------------------------- /src/Helpers.js: -------------------------------------------------------------------------------- 1 | const crypto = require("crypto"); 2 | 3 | /** 4 | * Generate a random hex id 5 | * eg. df395847d1890bd33836227ab296a0bc11d58dfdc426d8d06c3d4e440bd951a3 6 | */ 7 | const randomId = () => { 8 | return crypto.randomBytes(32).toString("hex"); 9 | } 10 | 11 | /** 12 | * Merge arguments with default 13 | * 14 | * @param {object} defaults 15 | * @param {object} args to pass in 16 | */ 17 | const parseArgs = (defaults = {}, args = {}) => { 18 | return Object.assign(defaults, args) 19 | } 20 | 21 | module.exports = { 22 | randomId, 23 | parseArgs 24 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 iGoMoon AB 2 | Licensed under the Apache License, Version 2.0 (the "License"); 3 | you may not use this file except in compliance with the License. 4 | You may obtain a copy of the License at 5 | 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | Unless required by applicable law or agreed to in writing, software 9 | distributed under the License is distributed on an "AS IS" BASIS, 10 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | See the License for the specific language governing permissions and 12 | limitations under the License. -------------------------------------------------------------------------------- /__tests__/Field.js: -------------------------------------------------------------------------------- 1 | const { italic } = require('chalk'); 2 | const Field = require('../src/fields/Field'); 3 | 4 | describe('Field.js', () => { 5 | 6 | let field = Field.text({ name: 'name', label: 'label' }); 7 | 8 | it('has the correct name', () => { 9 | expect(field.data.name).toBe('name'); 10 | }); 11 | 12 | it('has the correct type', () => { 13 | expect(field.data.type).toBe('text'); 14 | }); 15 | 16 | it('can repeat', () => { 17 | let repeater = Field.text({}).repeat(); 18 | expect(typeof repeater.data.occurrence).toBe('object'); 19 | }); 20 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@igomoon/hubspot-fields-js", 3 | "label": "hubspot-fields-js", 4 | "description": "A webpack plugin to generate HubSpot module fields.json files with js", 5 | "author": "iGoMoon", 6 | "version": "1.2.0", 7 | "license": "Apache-2.0", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/iGoMoon/hubspot-fields-js" 11 | }, 12 | "publishConfig": { 13 | "access": "public" 14 | }, 15 | "homepage": "https://github.com/iGoMoon/hubspot-fields-js#readme", 16 | "scripts": { 17 | "test": "npx jest" 18 | }, 19 | "devDependencies": { 20 | "jest": "^26.6.3" 21 | } 22 | } -------------------------------------------------------------------------------- /src/fields/Group.js: -------------------------------------------------------------------------------- 1 | const ModuleField = require('./ModuleField'); 2 | 3 | class Group extends ModuleField { 4 | 5 | constructor(overrides = {}, children) { 6 | super(); 7 | this.data = Object.assign({ 8 | "name": "group", 9 | "label": "Group", 10 | "required": false, 11 | "locked": false, 12 | "children": children, 13 | "type": "group", 14 | "inline_help_text": "", 15 | "help_text": "", 16 | "default": {} 17 | }, overrides); 18 | } 19 | 20 | 21 | /** 22 | * Return field as JSON 23 | */ 24 | toJSON() { 25 | this.data.children = this.data.children.filter(c => !!c) 26 | this.data.children 27 | .map(child => { 28 | return child.toJSON(); 29 | }); 30 | 31 | return this.data 32 | } 33 | 34 | 35 | } 36 | 37 | module.exports = Group; -------------------------------------------------------------------------------- /src/fields/FieldTransformer.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | class FieldTransformer { 4 | 5 | /** 6 | * Check if is valid 7 | * @param {mixed} field 8 | */ 9 | static validateField(field) { 10 | return !!field && typeof field == 'object' 11 | } 12 | 13 | /** 14 | * Transform single field into JSON. 15 | * @param {object} field 16 | */ 17 | static fieldToJson(field) { 18 | if (typeof field['toJSON'] === "function") { 19 | return field.toJSON() 20 | } 21 | return field; 22 | } 23 | 24 | /** 25 | * Transform fields into JSON file. 26 | * @param {array} fields 27 | */ 28 | static transform(file, fields) { 29 | // Default to an empty array 30 | let fieldsJson = []; 31 | // Transform all fields in array toJSON() 32 | let transformed = fields 33 | .filter(c => this.validateField(c)) 34 | .map(field => this.fieldToJson(field)); 35 | 36 | try { 37 | // Try to load the fields.json file 38 | fieldsJson = JSON.parse(fs.readFileSync(file)); 39 | 40 | // Append the transformed fields to the end of the fields.json file 41 | fieldsJson = fieldsJson.concat(transformed); 42 | 43 | } catch(e) { 44 | // If it didn't exist, we'll just write it 45 | fieldsJson = transformed; 46 | } 47 | 48 | // Write the file with indention. 49 | fs.writeFileSync(file, JSON.stringify(fieldsJson, null , 4)); 50 | 51 | return true; 52 | } 53 | 54 | } 55 | 56 | module.exports = FieldTransformer; -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [1.2.0] - 2022-01-01 6 | - Js Partials are now imported relative to src file, NOT from final dist file. Field JS tranformation using the src file and then updates webpack's emission functionlity to properly handle the upload. 7 | - Plugin now accepts options 8 | - `src`: The starting directory to search for field.js files eg. "./src" 9 | - `extraDirsToWatch`: an array of relative paths to directories that will trigger a recompilation. Useful for FieldJS partials 10 | - `ignore`: An array of relative paths to ignore when searching for field.js files 11 | 12 | ```javascript 13 | new FieldsPlugin({ 14 | "src": "", 15 | "extraDirsToWatch" : ["./src/fields"], 16 | "ignore": [] 17 | }) 18 | ``` 19 | 20 | ## [1.1.6] - 2021-11-11 21 | - Allow null values in array and filter them out of the final JSON 22 | - `applyIf` helper method 23 | - `parseArgs` helper method 24 | 25 | ## [1.1.5] - 2021-05-11 26 | - Hot fixes 27 | 28 | ## [1.1.4] - 2021-05-10 29 | - Need some Defaults 30 | 31 | ## [1.1.3] - 2021-05-07 32 | - Choices and Children helpers 33 | 34 | ## [1.1.2] - 2021-05-07 35 | - Wrong version in ReadMe.md 36 | 37 | ## [1.1.1] - 2021-05-07 (Not published on NPM) 38 | - Upadate this changelog 39 | 40 | ## [1.1.0] - 2021-05-07 (Not published on NPM) 41 | - Update Readme and contributing file 42 | 43 | ## [1.0.4] - 2021-05-07 44 | - Update Field methods so we dont override hubspot defaults 45 | 46 | ## [1.0.3] - 2021-02-25 47 | - New Field Helper Functions: crmObject, hubdbRow, embed, video, sfCampaign 48 | 49 | ## [1.0.2] - 2021-02-16 50 | - Package.json updates 51 | 52 | ## [1.0.1] - 2021-02-16 53 | - Remove unnecessary dependencies 54 | 55 | ## [1.0.0] - 2021-02-16 56 | - Initial Publish 57 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue,email, or any other method with the owners of this repository before making a change. 4 | 5 | Please note we have a code of conduct, please follow it in all your interactions with the project. 6 | 7 | ## Pull Request Process 8 | 9 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. 10 | 1. Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters. 11 | 1. Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 12 | 1. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. 13 | 14 | ## Code of Conduct 15 | 16 | ### Our Pledge 17 | 18 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 19 | 20 | ### Our Standards 21 | 22 | Examples of behavior that contributes to creating a positive environment include: 23 | 24 | * Using welcoming and inclusive language 25 | * Being respectful of differing viewpoints and experiences 26 | * Gracefully accepting constructive criticism 27 | * Focusing on what is best for the community 28 | * Showing empathy towards other community members 29 | 30 | Examples of unacceptable behavior by participants include: 31 | 32 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 33 | * Trolling, insulting/derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a professional setting 37 | 38 | ### Our Responsibilities 39 | 40 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 41 | 42 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 43 | 44 | ### Scope 45 | 46 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 47 | 48 | ### Enforcement 49 | 50 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [INSERT EMAIL ADDRESS]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 51 | 52 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 53 | 54 | ### Attribution 55 | 56 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 57 | available at [http://contributor-covenant.org/][version] 58 | 59 | [homepage]: http://contributor-covenant.org 60 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /src/fields/ModuleField.js: -------------------------------------------------------------------------------- 1 | class ModuleField { 2 | 3 | /** 4 | * 5 | */ 6 | applyIf(show, callback) { 7 | if (!!show) { 8 | return callback(this) 9 | } 10 | return this; 11 | } 12 | 13 | 14 | /** 15 | * 16 | * @param {string} controllingField The controlling field name. Including nesting with group.name 17 | * @param string} regex The comparing value 18 | * @param {string} type Comparison type. Eg. 'EQUAL' etc. 19 | */ 20 | visibleIf(controllingField, regex, type = "EQUAL") { 21 | if (!this.data.visibility) { 22 | this.data.visibility = {}; 23 | } 24 | 25 | this.data.visibility = Object.assign(this.data.visibility, { 26 | "controlling_field": controllingField, 27 | "controlling_value_regex": regex, 28 | "operator": type, 29 | }); 30 | 31 | return this; 32 | } 33 | 34 | /** 35 | * Group should repeat 36 | * @param {Object} overrides 37 | */ 38 | repeat(overrides = {}) { 39 | this.data.occurrence = Object.assign({ 40 | "min": null, 41 | "max": null, 42 | "sorting_label_field": null, 43 | "default": null 44 | }, overrides); 45 | this.data.default = []; 46 | 47 | return this; 48 | } 49 | 50 | /** 51 | * 52 | * @param {object} subFields eg. {opacity: true} 53 | */ 54 | hiddenSubfields(subFields) { 55 | if (!this.data.visibility) { 56 | this.data.visibility = {}; 57 | } 58 | 59 | this.data.visibility.hidden_subfields = subFields; 60 | return this; 61 | } 62 | 63 | /** 64 | * Set name and label 65 | * @param {String} name 66 | * @param {String} label 67 | */ 68 | name(name, label) { 69 | this.data.name = name; 70 | this.data.label = label; 71 | return this; 72 | } 73 | 74 | /** 75 | * Set inline help text 76 | * @param {String} text 77 | */ 78 | inlineHelpText(text) { 79 | this.data.inline_help_text = text; 80 | return this; 81 | } 82 | 83 | /** 84 | * Set help text 85 | * @param {String} text 86 | */ 87 | helpText(text) { 88 | this.data.help_text = text; 89 | return this; 90 | } 91 | 92 | /** 93 | * Determines if the field can be left blank in the editor. If true, content will not be allowed to publish without filling out this field. 94 | * @param {boolean} 95 | */ 96 | required(required = true) { 97 | this.data.required = Boolean(required); 98 | return this; 99 | } 100 | 101 | /** 102 | * Determines if the field is editable in the content editor. If "true", the field will not appear in the content editor. 103 | * @param {boolean} 104 | */ 105 | locked(locked = true) { 106 | this.data.locked = Boolean(locked); 107 | return this; 108 | } 109 | 110 | /** 111 | * Set any key. 112 | * @param {string} key 113 | * @param {string} value 114 | */ 115 | set(key, value) { 116 | this.data[key] = value; 117 | return this; 118 | } 119 | 120 | /** 121 | * Set id 122 | * @param {String} id 123 | */ 124 | id(id) { 125 | this.data.id = id; 126 | return this; 127 | } 128 | 129 | /** 130 | * Set label 131 | * @param {String} label 132 | */ 133 | label(label) { 134 | this.data.label = label; 135 | return this; 136 | } 137 | 138 | /** 139 | * Set default value of field 140 | * @param {*} value 141 | */ 142 | default(value) { 143 | this.data.default = value; 144 | return this; 145 | } 146 | 147 | /** 148 | * Set chocies for choice 149 | * @param {Array} choices 150 | */ 151 | choices(choices = []) { 152 | if (this.data.type == 'choice') { 153 | this.data.choices = choices; 154 | } 155 | return this; 156 | } 157 | 158 | /** 159 | * Set children for choice 160 | * @param {Array} children 161 | */ 162 | children(children = []) { 163 | if (this.data.type == 'group') { 164 | this.data.children = children; 165 | } 166 | return this; 167 | } 168 | 169 | } 170 | 171 | module.exports = ModuleField; -------------------------------------------------------------------------------- /src/plugins/FieldsPlugin.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const glob = require('glob'); 3 | const path = require('path'); // Use path to ensure files are resolved correctly across all OS 4 | 5 | const FieldTransformer = require('../fields/FieldTransformer'); 6 | 7 | class FieldsPlugin { 8 | 9 | constructor(options = {}) { 10 | this.options = Object.assign({ 11 | src: "", 12 | extraDirsToWatch: [], 13 | ignore: [] 14 | }, options); 15 | } 16 | 17 | addAdditionalDirectoriesToWatch(compilation) { 18 | let watchDirs = this.options.extraDirsToWatch 19 | watchDirs = Array.isArray(watchDirs) ? watchDirs : watchDirs.split(',') 20 | 21 | watchDirs.forEach(dir => { 22 | let context = path.resolve(compilation.options.context, dir) 23 | compilation.contextDependencies.add(context) 24 | }) 25 | } 26 | 27 | defineFoldersToIgnore(compilation) { 28 | let ignore = [] 29 | // Get from options 30 | let ignoreDirs = this.options.ignore 31 | ignoreDirs = Array.isArray(ignoreDirs) ? ignoreDirs : ignoreDirs.split(',') 32 | // Add Defaults 33 | ignoreDirs = ignoreDirs.concat(['./dist/**', './node_modules/**']) 34 | // Reolve 35 | ignoreDirs.forEach(i => { 36 | ignore.push(path.resolve(compilation.options.context, i)) 37 | }) 38 | // Return 39 | return [... new Set(ignore)] 40 | } 41 | 42 | async clearFieldsJson(compilation) { 43 | return new Promise(async (resolve, reject) => { 44 | let distFolder = compilation.options.output.path; 45 | glob(distFolder + '/**/fields.json', {}, (err, files) => { 46 | files.forEach(file => { 47 | fs.unlinkSync(file); 48 | }); 49 | resolve(); 50 | }); 51 | }); 52 | } 53 | 54 | async apply(compiler) { 55 | 56 | // Clear out any old fields.json files before compiler runs. 57 | // This is to ensure that we dont end up with duplicate fields. 58 | compiler.hooks.run.tapPromise('FieldsPlugin', this.clearFieldsJson); 59 | compiler.hooks.watchRun.tapPromise('FieldsPlugin', this.clearFieldsJson); 60 | compiler.hooks.emit.tapPromise('FieldsPlugin', this.clearFieldsJson); 61 | 62 | // Transform the fields.json 63 | compiler.hooks.afterEmit.tapPromise('FieldsPlugin', async compilation => { 64 | 65 | let webpackRoot = compilation.options.context 66 | let srcFolder = path.resolve(webpackRoot, this.options.src); 67 | let distFolder = compilation.options.output.path; 68 | 69 | // Setup 70 | this.addAdditionalDirectoriesToWatch(compilation) 71 | let ignore = this.defineFoldersToIgnore(compilation) 72 | 73 | // Handle fields.js file 74 | return await new Promise((resolve, reject) => { 75 | let files = glob.sync(`${srcFolder}/**/fields.js`, { ignore }) 76 | 77 | // Find every modules fields.js file. 78 | files.forEach((JsSrcFullPath) => { 79 | try { 80 | 81 | // Get the module path for matching 82 | let fileUniqueKey = JsSrcFullPath.split("/").slice(-2).join('/'); 83 | // Get the path from the DIST folder for the asset 84 | let JsDistRelativePath = Object.keys(compilation.assets).find(a => a.endsWith(fileUniqueKey)) 85 | let JsonDistRelativePath = JsDistRelativePath.replace('fields.js', 'fields.json'); 86 | // Get Final Paths 87 | let JsonDistFullPath = path.resolve(distFolder, './' + JsonDistRelativePath); 88 | 89 | let fields = require(JsSrcFullPath); 90 | // Transform to Json and append to fields.json file 91 | FieldTransformer.transform(JsonDistFullPath, fields); 92 | 93 | // If the file is not yet added to emittedAssets then handle it now so fields.js is not uploaded to HubSpot 94 | 95 | if (!compilation.emittedAssets[JsDistRelativePath]) { 96 | // remove fields.js from assets because hsAutouploadPlugin looks for this to be emitted: true in order to upload 97 | delete compilation.assets[JsDistRelativePath]; 98 | // remove fields.js from emittedAssets Set 99 | compilation.emittedAssets.delete(JsDistRelativePath) 100 | // add json version to emittedAssets set. Functionally tricks AutoUplaoder into thinking that this file was updated as part of the actual webpack process 101 | compilation.emittedAssets.add(JsonDistRelativePath) 102 | } 103 | 104 | // Remove field.js file from dist directory. 105 | let JsDistFullPath = path.resolve(distFolder, './' + JsDistRelativePath); 106 | fs.existsSync(JsDistFullPath) ? fs.unlinkSync(JsDistFullPath) : null; 107 | // remove fields.js from cache so it will reupload on future watch saves 108 | delete require.cache[require.resolve(JsSrcFullPath)] 109 | 110 | } catch (e) { 111 | delete require.cache[require.resolve(JsSrcFullPath)]; 112 | console.log("Could not transform: " + JsSrcFullPath + "\nError: " + e.message); 113 | } 114 | 115 | }); 116 | 117 | resolve(); 118 | }); 119 | 120 | }); 121 | } 122 | } 123 | 124 | module.exports = FieldsPlugin; -------------------------------------------------------------------------------- /src/fields/Field.js: -------------------------------------------------------------------------------- 1 | const ModuleField = require('./ModuleField'); 2 | 3 | class Field extends ModuleField { 4 | 5 | constructor(data) { 6 | super(); 7 | this.data = Object.assign({ 8 | "required": false, 9 | "locked": false, 10 | "help_text": "", 11 | "inline_help_text": "", 12 | //"default": null (HS handles this for us) 13 | }, data); 14 | } 15 | 16 | /** 17 | * Blog field 18 | * @param {Object} overrides 19 | */ 20 | static blog(overrides) { 21 | return new Field(Object.assign({ 22 | "name": "blog_field", 23 | "label": "Blog field", 24 | "type": "blog" 25 | }, overrides)); 26 | } 27 | 28 | /** 29 | * Boolean field 30 | * @param {Object} overrides 31 | */ 32 | static boolean(overrides) { 33 | return new Field(Object.assign({ 34 | "name": "boolean_field", 35 | "label": "Boolean field", 36 | "type": "boolean", 37 | //"default": false 38 | }, overrides)); 39 | } 40 | 41 | /** 42 | * Choice field 43 | * @param {Object} overrides 44 | * @param {Array} choices 45 | */ 46 | static choice(overrides, choices = []) { 47 | return new Field(Object.assign({ 48 | "name": "choice_field", 49 | "label": "Choice field", 50 | //"display": "select", 51 | "choices": choices, 52 | "type": "choice" 53 | }, overrides)); 54 | } 55 | 56 | /** 57 | * Color field 58 | * @param {Object} overrides 59 | */ 60 | static color(overrides) { 61 | return new Field(Object.assign({ 62 | "name": "color_field", 63 | "label": "Color field", 64 | "type": "color" 65 | }, overrides)); 66 | } 67 | 68 | /** 69 | * Cta field 70 | * @param {Object} overrides 71 | */ 72 | static cta(overrides) { 73 | return new Field(Object.assign({ 74 | "name": "cta_field", 75 | "label": "CTA field", 76 | "type": "cta" 77 | }, overrides)); 78 | } 79 | 80 | /** 81 | * CRM Object field 82 | * @param {Object} overrides 83 | * @param {String} overrides.object_type - Type of CRM Object the user can pick from. 84 | * @param {Array} overrides.properties_to_fetch - Array of property names associated with the object type in string form. {@link https://developers.hubspot.com/docs/cms/features/custom-objects#supported-crm-object-types} 85 | * @param {Object} overrides.default - Object with id of default selected object instance. Contact ID, Company ID etc 86 | * 87 | * @see {@link https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields#crm-object} 88 | */ 89 | static crmObject(overrides) { 90 | return new Field(Object.assign({ 91 | "name" : "crmobject_field", 92 | "label" : "CRM object", 93 | "object_type" : "CONTACT", 94 | //"properties_to_fetch" : [ ], 95 | "type" : "crmobject" 96 | }, overrides)); 97 | } 98 | 99 | /** 100 | * Date field 101 | * @param {Object} overrides 102 | */ 103 | static date(overrides) { 104 | return new Field(Object.assign({ 105 | "name": "date_field", 106 | "label": "Date field", 107 | "type": "date" 108 | }, overrides)); 109 | } 110 | 111 | /** 112 | * DateTime field 113 | * @param {Object} overrides 114 | */ 115 | static dateTime(overrides) { 116 | return new Field(Object.assign({ 117 | "name": "datetime_field", 118 | "label": "Date and time field", 119 | //"step" : 30, 120 | "type": "datetime" 121 | }, overrides)); 122 | } 123 | 124 | /** 125 | * Email field 126 | * @param {Object} overrides 127 | */ 128 | static email(overrides) { 129 | return new Field(Object.assign({ 130 | "name": "email_field", 131 | "label": "Email Address Field", 132 | "type": "email" 133 | }, overrides)); 134 | } 135 | 136 | /** 137 | * Embed field 138 | * @param {Object} overrides 139 | * @param {Array} overrides.supported_source_types - Supported source types for either oEmbed URLs or HTML embed code 140 | * @param {Array} overrides.supported_oembed_types - Supported oEmbed type including "photo", "video", "link", and "rich". 141 | * @param {Object} overrides.default - An array containing the "source_type" parameter. This parameter has one string based value from the options provided in the "supported_source_types" parameter. 142 | * 143 | * @see {@link https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields#embed} 144 | */ 145 | static embed(overrides) { 146 | return new Field(Object.assign({ 147 | "name" : "embed_field", 148 | "label" : "Embed", 149 | //"supported_source_types" : [ "oembed", "html" ], 150 | //"supported_oembed_types" : [ "photo", "video", "link", "rich" ], 151 | "type" : "embed", 152 | }, overrides)); 153 | } 154 | 155 | /** 156 | * File field 157 | * @param {Object} overrides 158 | */ 159 | static file(overrides) { 160 | return new Field(Object.assign({ 161 | "name": "file_field", 162 | "label": "File field", 163 | //"picker" : "file", 164 | "type": "file" 165 | }, overrides)); 166 | } 167 | 168 | /** 169 | * Follow up email field 170 | * @param {Object} overrides 171 | */ 172 | static followUpEmail(overrides) { 173 | return new Field(Object.assign({ 174 | "name": "followupemail_field", 175 | "label": "Followup email field", 176 | "type": "followupemail" 177 | }, overrides)); 178 | } 179 | 180 | /** 181 | * Font field 182 | * @param {Object} overrides 183 | */ 184 | static font(overrides) { 185 | return new Field(Object.assign({ 186 | "name": "font_field", 187 | "label": "font_field", 188 | "type": "font", 189 | //"load_external_fonts" : true, 190 | //"default" : { 191 | // "size": 12, 192 | // "size_unit": "px", 193 | // "color": "#000", 194 | // "styles": {} 195 | // } 196 | }, overrides)); 197 | } 198 | 199 | /** 200 | * Form field 201 | * @param {Object} overrides 202 | */ 203 | static form(overrides) { 204 | return new Field(Object.assign({ 205 | "name": "form_field", 206 | "label": "Form field", 207 | "type": "form", 208 | // "default": { 209 | // "response_type": "inline", 210 | // "message": "Thanks for submitting the form." 211 | // } 212 | }, overrides)); 213 | } 214 | 215 | /** 216 | * HubDB Row field 217 | * @param {Object} overrides 218 | * @param {string} overrides.table_name_or_id - The name or ID of the HubDB table. This field is required. 219 | * @param {Array} overrides.columns_to_fetch - An array of column names to fetch from the table. If left blank, will return all columns in the table. 220 | * @param {Array} overrides.display_columns - An array of column names to use in choice label. If left blank, will return only the first column in the table. 221 | * @param {String} overrides.display_format - The format you would like the column data to display in the HubDB row selector using the percent symbol and number to designate a column. 222 | * @param {Object} overrides.default - Object containing “id” for setting the default hubdb row. 223 | * 224 | * @see {@link https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields#hubdb-row} 225 | */ 226 | static hubdbRow(overrides) { 227 | return new Field(Object.assign({ 228 | "name" : "hubdbrow_field", 229 | "label" : "HubDB row", 230 | "table_name_or_id" : "", 231 | // "columns_to_fetch" : [], 232 | // "display_columns" : [], 233 | // "display_format" : "%0 - %1", 234 | "type" : "hubdbrow", 235 | }, overrides)); 236 | } 237 | 238 | /** 239 | * HubDB Table field 240 | * @param {Object} overrides 241 | */ 242 | static hubdbTable(overrides) { 243 | return new Field(Object.assign({ 244 | "name": "hubdbtable_field", 245 | "label": "HubDB table field", 246 | "type": "hubdbtable" 247 | }, overrides)); 248 | } 249 | 250 | /** 251 | * Icon field 252 | * @param {Object} overrides 253 | */ 254 | static icon(overrides) { 255 | return new Field(Object.assign({ 256 | "name": "icon_field", 257 | "label": "Icon field", 258 | "type": "icon", 259 | "default": {} 260 | }, overrides)); 261 | } 262 | 263 | /** 264 | * Image field 265 | * @param {Object} overrides 266 | */ 267 | static image(overrides) { 268 | return new Field(Object.assign({ 269 | "name": "image_field", 270 | "label": "Image field", 271 | //"responsive": true, 272 | //"show_loading": false, 273 | //"resizable": true, 274 | "type": "image", 275 | "default" : { 276 | "size_type" : "auto", 277 | "src" : "", 278 | "alt" : null, 279 | "loading": "disabled" 280 | } 281 | }, overrides)); 282 | } 283 | 284 | /** 285 | * Link field 286 | * @param {Object} overrides 287 | */ 288 | static link(overrides) { 289 | return new Field(Object.assign({ 290 | "name": "link_field", 291 | "label": "Link field", 292 | "type": "link", 293 | //"supported_types": ["EXTERNAL", "CONTENT", "FILE", "EMAIL_ADDRESS", "BLOG"], 294 | "default": { 295 | "url" : { 296 | "content_id" : null, 297 | "type" : "EXTERNAL", 298 | "href" : "" 299 | }, 300 | "open_in_new_tab" : false, 301 | "no_follow" : false 302 | } 303 | }, overrides)); 304 | } 305 | 306 | /** 307 | * Logo field 308 | * @param {Object} overrides 309 | */ 310 | static logo(overrides) { 311 | return new Field(Object.assign({ 312 | "name": "logo_field", 313 | "label": "Logo field", 314 | "type": "logo", 315 | "default": { 316 | "override_inherited_src" : false, 317 | "src" : null, 318 | "alt" : null 319 | } 320 | }, overrides)); 321 | } 322 | 323 | /** 324 | * Menu field 325 | * @param {Object} overrides 326 | */ 327 | static menu(overrides) { 328 | return new Field(Object.assign({ 329 | "name": "menu_field", 330 | "label": "Menu field", 331 | "type": "menu", 332 | "default": "default" 333 | }, overrides)); 334 | } 335 | 336 | /** 337 | * Text field 338 | * @param {Object} overrides 339 | */ 340 | static number(overrides) { 341 | return new Field(Object.assign({ 342 | "name": "number_field", 343 | "label": "Number field", 344 | "type": "number", 345 | // "display": "text", 346 | // "step": 1, 347 | // "min": null, 348 | // "max": null 349 | }, overrides)); 350 | } 351 | 352 | /** 353 | * Page field 354 | * @param {Object} overrides 355 | */ 356 | static page(overrides) { 357 | return new Field(Object.assign({ 358 | "name": "page_field", 359 | "label": "Page field", 360 | "type": "page" 361 | }, overrides)); 362 | } 363 | 364 | /** 365 | * Rich text field 366 | * @param {Object} overrides 367 | */ 368 | static richText(overrides) { 369 | return new Field(Object.assign({ 370 | "name": "richtext_field", 371 | "label": "Rich text field", 372 | "type": "richtext" 373 | }, overrides)); 374 | } 375 | 376 | /** 377 | * Simple field 378 | * @param {Object} overrides 379 | */ 380 | static simpleMenu(overrides) { 381 | return new Field(Object.assign({ 382 | "name": "simplemenu_field", 383 | "label": "Simple menu field", 384 | "type": "simplemenu" 385 | }, overrides)); 386 | } 387 | 388 | /** 389 | * Tag field 390 | * @param {Object} overrides 391 | */ 392 | static tag(overrides) { 393 | return new Field(Object.assign({ 394 | "name": "tag_field", 395 | "label": "Tag field", 396 | //"tag_value": "SLUG", 397 | "type": "tag" 398 | }, overrides)); 399 | } 400 | 401 | /** 402 | * Text field 403 | * @param {Object} overrides 404 | */ 405 | static text(overrides) { 406 | return new Field(Object.assign({ 407 | "name": "text", 408 | "label": "Text", 409 | // "validation_regex": "", 410 | // "allow_new_line": false, 411 | // "show_emoji_picker": false, 412 | "type": "text" 413 | }, overrides)); 414 | } 415 | 416 | /** 417 | * URL field 418 | * @param {Object} overrides 419 | */ 420 | static url(overrides) { 421 | return new Field(Object.assign({ 422 | "name": "url_field", 423 | "label": "URL field", 424 | "type": "url", 425 | //"supported_types": ["EXTERNAL", "CONTENT", "FILE", "EMAIL_ADDRESS", "BLOG"], 426 | "default": { 427 | "content_id" : null, 428 | "href" : "", 429 | "type" : "EXTERNAL" 430 | } 431 | }, overrides)); 432 | } 433 | 434 | /** 435 | * Video field 436 | * @param {Object} overrides 437 | * @param {Object} overrides.default - Video object with settings for player_id, height, width, size_type, and conversion_asset object. 438 | * 439 | * @see {@link https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields#video} 440 | */ 441 | static video(overrides) { 442 | return new Field(Object.assign({ 443 | "name" : "videoplayer_field", 444 | "label" : "Video", 445 | "type" : "videoplayer" 446 | }, overrides)); 447 | } 448 | 449 | /** 450 | * Salesforce Campaign field 451 | * @param {Object} overrides 452 | */ 453 | static sfCampaign(overrides) { 454 | return new Field(Object.assign({ 455 | "name" : "sfdc_campaign", 456 | "label" : "Salesforce Campaign Field", 457 | "type" : "salesforcecampaign", 458 | }, overrides)); 459 | } 460 | 461 | /** 462 | * Return the fields Json representation. 463 | */ 464 | toJSON() { 465 | return this.data; 466 | } 467 | 468 | /** 469 | * Set default value of field 470 | * @param {*} value 471 | */ 472 | default(value) { 473 | switch (this.data.type) { 474 | case "link": 475 | case "url": 476 | this.data.default.url.href = value; 477 | break; 478 | case "color": 479 | this.data.default.color = value; 480 | break; 481 | case "image": 482 | this.data.default.src = value; 483 | break; 484 | case "form": 485 | this.data.default.form_id = value; 486 | break; 487 | case "crmobject": 488 | case "hubdbrow": 489 | this.data.default.id = value; 490 | break; 491 | case "embed": 492 | this.data.default.source_type = value; 493 | break; 494 | default: 495 | this.data.default = value; 496 | break; 497 | } 498 | 499 | return this; 500 | } 501 | 502 | } 503 | 504 | module.exports = Field; --------------------------------------------------------------------------------