Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@htmlguyllc/jpack

Package Overview
Dependencies
Maintainers
1
Versions
191
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@htmlguyllc/jpack - npm Package Compare versions

Comparing version 1.0.12 to 1.0.13

examples/FormModalFromURL/app.js

938

es/components/form/index.js

@@ -8,7 +8,4 @@ import axios from 'axios';

//default options for form.fromURL()
let from_url_defaults = {
incomingElementSelector: null, //the form element or wrapper that you want to retrieve from the URL
insertIntoElement: null, //what element to put the form into
onload: function(form){ return this; }, //once the form is loaded onto the page
//defaults for the XHRForm class
const XHRFormDefaults = {
xhrSubmit: true, //submit the form using XHR instead of the default action

@@ -19,23 +16,36 @@ submitURL:null, //will be grabbed from the form's action attribute, or fallback to the URL the form was retrieved from

onSuccess: function(response, form){ }, //called when the form is submitted successfully
//validate the form, display any errors and return false to block submission
validateForm: function(form){
//add .was-validated for bootstrap to show errors
form.classList.add('was-validated');
//if there are any :invalid elements, the form is not valid
const is_valid = !form.querySelector(':invalid');
//if it's valid, clear the validation indicators
if( is_valid ) form.classList.remove('was-validated');
return is_valid;
}
};
//defaults for the FormFromURL class
const FormFromURLDefaults = {
incomingElementSelector: null, //the form element or wrapper that you want to retrieve from the URL
insertIntoElement: null, //what element to put the form into
onload: function(form){ return this; }, //once the form is loaded onto the page
};
/**
* Form based helpers
*
* @type {{fromURL: form.fromURL}}
* This class allows you to submit a form via XHR and easily handle the results
*/
export const form = {
export class XHRForm {
/**
* Grabs a form from a URL and returns it to the current page
* Form can be just about any datatype - uses dom.getElement()
*
* Also handles form submission using XHR and can open a modal to display the form
*
* Only methods that require notes or are commonly used externally are commented below
*
* @param url - string
* @param options - object{incomingElementSelector,insertIntoElement, onload}
* @param form
* @param options
*/
fromURL: function(url, options){
if( typeof url !== "string" ) throw `${url} is not a string`;
constructor(form, options){

@@ -45,419 +55,513 @@ //if options are undefined, set them

//make sure options is an object (empty or not) with only the keys set in the defaults
type_checks.isDataObject(options, Object.keys(from_url_defaults), false, true, true);
//make sure options is an object (empty or not)
type_checks.isDataObject(options, Object.keys(XHRFormDefaults), false, false, true);
//extend defaults with provided options
options = {...from_url_defaults, ...options};
options = {...XHRFormDefaults, ...options};
/**
* Set the URL from which the form will be retrieved
*
* @param url
* @returns {form}
*/
this.setURL = function(url){
if( typeof url !== 'string' ) throw `${url} is not a string`;
this._url = url;
return this;
};
this.getURL = function(){
return this._url;
};
//set it immediately from the provided string
this.setURL(url);
this.setForm(form);
this.setValidateCallback(options.validateForm);
this.setXHRSubmit(options.xhrSubmit);
this.setSubmitMethod(options.submitMethod);
this.setSubmitURL(options.submitURL);
this.onSuccess(options.onSuccess);
this.onError(options.onError);
}
/**
* If the URL provided returns HTML, this selector will be used to pull the form out
*
* If left null, it will assume the entire response is the form's HTML
*
* @param selector: string|null
* @returns {form}
*/
this.setIncomingElementSelector = function(selector){
if( selector !== null && typeof selector !== 'string' ) throw `${selector} is not a string or null value`;
this._incomingElementSelector = selector;
return this;
};
this.getIncomingElementSelector = function(){
return this._incomingElementSelector;
};
//set it immediately from options
this.setIncomingElementSelector(options.incomingElementSelector);
//validation callback
_validateCallback = null;
/**
* Allows you to set a parent element that the form will be inserted into using the default insertForm method
* Alternatively, you can leave this and override insertForm() and have more control over where it should go
*
* Uses dom.getElement() so you can pass a string, jQuery object, object, etc
* However if more than 1 element is detected, an error will be thrown
*
* @param element
*/
this.setInsertIntoElement = function(element){
this._insertIntoElement = element;
};
this.getInsertIntoElement = function(){
return this._insertIntoElement;
};
//set it immediately from the options
this.setInsertIntoElement(options.insertIntoElement);
/**
*
* @param callback
* @returns {XHRForm}
*/
setValidateCallback(callback){
if( typeof callback !== "function" ) throw `${callback} is not a function`;
this._validateCallback = callback;
return this;
}
/**
* Get the form from the URL and pass to insertForm
*
* There are three main ways to provide the form from your server:
* 1) Straight HTML. The entire response is the form and that's it.
* 2) Straight HTML, but the form is only a part of the response so it needs to be parsed out based on a selector.
* 3) A JSON object containing the key "html" like this: {"html":"<form>your form here</form>"}
*
*/
this.getForm = function(){
var self = this;
/**
* Runs the validate callback and passes the form
*
* @returns {null}
*/
validate(form){
if( typeof form === "undefined" ) form = this.getForm();
return this._validateCallback(form);
}
navigation.showLoader();
axios.get(this.getURL()).then(function (response) {
navigation.hideLoader();
/**
* Set the form element
*
* @param form
* @returns {XHRForm}
*/
setForm(form){
if( !form || typeof form === 'undefined' ) throw `Form element is required`;
let data = response.data;
form = dom.getElement(form, true, true);
if( !form ) throw `Invalid form element received`;
//just in case the server returned the wrong response type and it's actually JSON - ignore errors
try{ data = typeof data === 'string' ? JSON.parse(data) : data; } catch(e){ }
this._form = form;
//if the response is a string (probably HTML)
if( typeof data === 'string' ){
if( typeof self.getIncomingElementSelector() === 'string' ){
//parse the incoming HTML
const parsed = navigation.parseHTML(data, self.getIncomingElementSelector());
//provide the form's HTML in an object containing other details like the route and the full response to insertForm
return self.insertForm(parsed, data);
}
//otherwise the entire response is assumed to be the form
return self.insertForm({html:data});
}
//if the response is an object (probably JSON)
else if( typeof data === 'object' ){
//if HTML was provided in the object
if( typeof data.html !== "undefined" ){
return self.insertForm({html:data.html}, data);
}
}
return this;
}
throw `Unexpected server response ${data}`;
})
.catch(function (error) {
navigation.hideLoader();
throw error;
});
};
/**
* Get the form element
*
* @returns {*|Element|HTMLDocument}
*/
getForm(){
return this._form;
}
/**
* Use this method to modify the form immediately after it's displayed
*
* You'll likely want to attach plugins for datepickers/dropdowns, or maybe hide a field based on the value of another
*
* @param onload
* @returns {form}
*/
this.setOnload = function(onload){
if( typeof onload !== 'function' ) throw `${onload} is not a function`;
this._onload = onload;
return this;
};
this.triggerOnload = function(form){
return this._onload(form);
};
//set it immediately from the options
this.setOnload(options.onload);
/**
* Whether or not you want the form to be submitted using an XHR request
*
* @param enabled - bool
*/
setXHRSubmit(enabled){
this._xhrSubmit = !!enabled;
return this;
}
/**
* Attaches the on submit handler (only if xhrSubmit is true)
*
* Pass the form or form selector
*/
this.attachSubmitHandler = function(form){
if( !this._xhrSubmit ) return;
/**
* How to submit the form - if set to null, the method will be pulled from the form's
* method attribute or fallback to "POST"
*
* @param method
* @returns {form}
*/
setSubmitMethod(method){
if( typeof method !== "string" && method !== null ) throw `${method} is not a string or null`;
this._submitMethod = method;
return this;
}
//just incase you didn't provide the actual Element
/**
* Gets the form submission method (POST, GET, etc)
*
* @returns {*|string}
*/
getSubmitMethod(){
return this._submitMethod;
}
/**
* The URL to submit the form to
*
* If null, the form's action attribute will be used.
* Use a function if you want to dynamically generate the URL just prior to the request
* - the function will receive the form as a param
* Generally speaking a string is sufficient
*
* @param url
* @returns {form}
*/
setSubmitURL(url){
if( typeof url !== "string"
&& typeof url !== "function"
&& url !== null ) throw `${url} is not a string, function, or null`;
this._submitURL = url;
return this;
}
/**
* Gets the URL the form will be submitted to
*
* @param form
* @returns {*|string|*}
*/
getSubmitURL(form){
//if a function, run it
if( typeof this._submitURL === "function" ) return this._submitURL(form);
return this._submitURL;
}
/**
* Attaches the on submit handler (only if xhrSubmit is true)
*
* Pass the form or form selector
*/
attachSubmitHandler(form){
if( !this._xhrSubmit ) return;
//if not passed, get it from this object
if( typeof form === "undefined" ) {
form = this.getForm();
}else {
form = dom.getElement(form);
}
var self = this;
if( !form ) throw `Form element not received, cannot attach submit handler`;
form.addEventListener('submit', function(e){
e.preventDefault();
self.submitForm(form);
return false;
});
};
var self = this;
/**
* Whether or not you want the form to be submitted using an XHR request
*
* @param enabled - bool
*/
this.setXHRSubmit = function(enabled){
this._xhrSubmit = !!enabled;
return this;
};
//set it immediately from the options
this.setXHRSubmit(options.xhrSubmit);
form.addEventListener('submit', function(e){
//if xhr submit is disabled, don't block the default action
if( !self._xhrSubmit ) return true;
e.preventDefault();
self.submitForm(form);
return false;
});
/**
* How to submit the form - if set to null, the method will be pulled from the form's
* method attribute or fallback to "POST"
*
* @param method
* @returns {form}
*/
this.setSubmitMethod = function(method){
if( typeof method !== "string" && method !== null ) throw `${method} is not a string or null`;
this._submitMethod = method;
return this;
};
this.getSubmitMethod = function(){
return this._submitMethod;
};
//set it immediately from the options
this.setSubmitMethod(options.submitMethod);
return this;
}
/**
* The URL to submit the form to
*
* If null, the form's action attribute will be used.
* Use a function if you want to dynamically generate the URL just prior to the request
* - the function will receive the form as a param
* Generally speaking a string is sufficient
*
* @param url
* @returns {form}
*/
this.setSubmitURL = function(url){
if( typeof url !== "string"
&& typeof url !== "function"
&& url !== null ) throw `${url} is not a string, function, or null`;
/**
* Set a callback function to run when the form is submitted successfully
*
* Your function will receive 2 params, the first is the response from the server and the second is the form on the page
*
* @param callback
* @returns {form}
*/
onSuccess(callback){
if( typeof callback !== "function" ) throw `${callback} is not a function`;
this._onSuccess.push(callback);
return this;
}
this._submitURL = url;
return this;
};
this.getSubmitURL = function(form){
//if a function, run it
if( typeof this._submitURL === "function" ) return this._submitURL(form);
/**
* Removes all onSuccess callbacks you've set
*/
clearOnSuccessCallbacks(){
this._onSuccess = [];
return this;
}
return this._submitURL;
};
//set it immediately from the options
this.setSubmitURL(options.submitURL);
//stores all onSuccess callbacks
_onSuccess = [];
/**
* Returns an object containing all form values to be submitted
*
* Override/extend this if you want to manipulate the data prior to submission
*
* @returns FormData
*/
this.getFormValues = function(form){
return new FormData(form);
};
/**
* Triggers all onSuccess callbacks
*
* @param response
* @param form
*/
triggerOnSuccess(response, form){
this._onSuccess.forEach(function(onSuccess){
onSuccess(response, form);
});
return this;
}
/**
* Set a callback function to run when the form is submitted successfully
*
* Your function will receive 2 params, the first is the response from the server and the second is the form on the page
*
* @param onSuccess
* @returns {form}
*/
this.setOnSuccess = function(onSuccess){
if( typeof onSuccess !== "function" ) throw `${onSuccess} is not a function`;
this._onSuccess = onSuccess;
return this;
};
this.triggerOnSuccess = function(response, form){
return this._onSuccess(response, form);
};
//set immediately from options
this.setOnSuccess(options.onSuccess);
/**
* Add a callback function to run when the form is submitted successfully
*
* @param callback
* @returns {FormFromURL}
*/
onError(callback){
if( typeof callback !== "function" ) throw `${callback} is not a function`;
this._onError.push(callback);
return this;
}
this.setOnError = function(onError){
if( typeof onError !== "function" ) throw `${onError} is not a function`;
this._onError = onError;
return this;
};
this.triggerOnError = function(error, response, form){
this._onError(error, response, form);
return this;
};
//set immediately from options
this.setOnError(options.onError);
/**
* Clears all onError callbacks you've set
* @returns {XHRForm}
*/
clearOnErrorCallbacks(){
this._onError = [];
return this;
}
//stores all onError callbacks
_onError = [];
/**
* Triggers the onError callbacks
*
* @param error
* @param response
* @param form
* @returns {XHRForm}
*/
triggerOnError(error, response, form){
this._onError.forEach(function(onError){
onError(error, response, form);
});
return this;
}
};
/**
* Allows you to insert the form wherever you want on the page
* Override this method to customize where the form is inserted
* (maybe you want to open a modal first and place it there?)
*
* parsed_content.html will always be the HTML
*
* parsed_content may contain other data like route and title if the form was pulled out of
* a full HTML page which contains those items
*
* response is the full server response (html string or object from JSON - not provided if the response is only the form's HTML)
*
* form is provided if this is after the form was submitted and HTML was returned form the server
*
* @param parsed_content
* @param response
* @param form
* @returns {*|Element|HTMLDocument}
*/
form.fromURL.prototype.insertForm = function(parsed_content, response, form) {
//selector for where the form will go
let el = this.getInsertIntoElement();
/**
* Submits the form using XHR
*
* 1) Determines the URL
* 2) Determines the method (GET, POST, PATCH, etc)
* 3) Determines if the form is valid
* 4) Gets the form's values
* 5) Submits the form
* 6) Replaces the form, runs onError, or runs onSuccess based on the response (see next line)
* Response Type = Action Taken
* string html with form inside = replace form
* string html with incomingElementSelector set, but not found = kickoff onError
* string - replace form on page with entire response
* object.html = replace form
* object.error = kickoff onError
* object in general = kickoff onSuccess
*
* @param form
* @returns {form|boolean}
*/
submitForm(form) {
//cache for use inside other scopes
var self = this;
//if not provided
if( el === null ) throw 'Cannot determine where to insert form. Overwrite insertForm() or provide insertIntoElement';
//get the provided submit URL
let url = this.getSubmitURL(form);
//if the URL is null, grab from the form
if( url === null ){
if( form.attributes.action ){ //check that it was set explicitly
url = form.action; //grab JUST the value
}
}
//default to the URL used to grab the form if it's not provided
url = !url ? this.getURL() : url;
//get the container element - error if not found
el = dom.getElement(el, true);
//get the provided submit method
let method = this.getSubmitMethod();
//if it's null, grab it from the form
if( method === null ){
if( typeof form.attributes.method !== 'undefined' ){ //check that it was set explicitly
method = form.method; //grab JUST the value
}
}
//default to post if we still don't have a method and lowercase anything that was provided
method = !method ? 'post' : method.toLowerCase();
//put the form in the container element
el.innerHTML = parsed_content.html;
//if not valid, stop here until they resubmit
if (!this.validate(form)) return false;
//find the newly added form
form = el.querySelector('form');
navigation.showLoader();
//attach an on-submit listener to send the form's values via XHR
this.attachSubmitHandler(form);
//get form values
const form_values = Array.from(
this.getFormValues(form),
e => e.map(encodeURIComponent).join('=')
).join('&');
//run the onload callback now that the form is there
this.triggerOnload(form);
axios({
url: url,
method: method,
data: form_values,
}).then(function (response) {
navigation.hideLoader();
return el;
};
let data = response.data;
/**
* Uses Bootstrap 4's 'was-validated' class and :invalid attributes to determine validity and display errors
*
* If you need more custom front-end validation, you should extend this object and overwrite this method
*
* Nothing is kicked off if this returns false. It just prevents form submission, so make sure you display errors
*
* @returns {boolean}
*/
form.fromURL.prototype.isValid = function(form){
//add .was-validated for bootstrap to show errors
form.classList.add('was-validated');
//just in case the server returned the wrong response type and it's actually JSON - ignore errors
try{ data = typeof data === 'string' ? JSON.parse(data) : data; } catch(e){ }
//if there are any :invalid elements, the form is not valid
const is_valid = !form.querySelector(':invalid');
//if the response is a string, it's probably/hopefully the form with inline errors
if( typeof data === 'string' ){
//if we are looking for an element within the response
if( typeof self.getIncomingElementSelector() === 'string' ){
//parse the incoming HTML
const parsed = navigation.parseHTML(data, self.getIncomingElementSelector());
//if the form was not found in it, let's assume it doesn't contain the form. If not, then maybe
if( !parsed.html.length ){
return self.triggerOnError(`${self.getIncomingElementSelector()} could not be found in response from the server`, data, form);
}
//provide the form's HTML in an object containing other details like the route and the full response to insertForm
return self.insertForm(parsed, data, form);
}
return self.insertForm({html:data}, data, form);
}
//if the response is an object, it's probably JSON
else if( typeof data === 'object' ){
//if it contains the HTML, just pop it back on the page
if( data.html ){
return self.insertForm({html:data.html}, data, form);
}
//if it's valid, clear the validation indicators
if( is_valid ) form.classList.remove('was-validated');
//if it contains an error message, trigger the callback
if( data.error ){
return self.triggerOnError(data.error, data, form);
}
return is_valid;
};
//if it doesn't APPEAR to be the form again, or an error, let's call it a success
return self.triggerOnSuccess(data, form)
}
})
.catch(function (error) {
navigation.hideLoader();
throw error;
});
return this;
}
/**
* Returns an object containing all form values to be submitted
*
* Override/extend this if you want to manipulate the data prior to submission
*
* @returns FormData
*/
getFormValues(form){
return new FormData(form);
}
}
/**
* Submits the form using XHR
* Grabs a form from a URL and returns it to the current page
*
* 1) Determines the URL
* 2) Determines the method (GET, POST, PATCH, etc)
* 3) Determines if the form is valid
* 4) Gets the form's values
* 5) Submits the form
* 6) Replaces the form, runs onError, or runs onSuccess based on the response (see next line)
* Response Type = Action Taken
* string html with form inside = replace form
* string html with incomingElementSelector set, but not found = kickoff onError
* string - replace form on page with entire response
* object.html = replace form
* object.error = kickoff onError
* object in general = kickoff onSuccess
* Also handles form submission using XHR and can open a modal to display the form
*
* @param form
* @returns {form|boolean}
*/
form.fromURL.prototype.submitForm = function(form) {
//cache for use inside other scopes
var self = this;
export class FormFromURL extends XHRForm {
//get the provided submit URL
let url = this.getSubmitURL(form);
//if the URL is null, grab from the form
if( url === null ){
if( form.attributes.action ){ //check that it was set explicitly
url = form.action; //grab JUST the value
}
/**
* @param url - string
* @param options - object{incomingElementSelector,insertIntoElement, onload}
*/
constructor(url, options){
super(null, options);
if( typeof url !== "string" ) throw `${url} is not a string`;
//if options are undefined, set them
options = typeof options === "undefined" ? {} : options;
//make sure options is an object (empty or not)
type_checks.isDataObject(options, Object.keys(FormFromURLDefaults), false, false, true);
//extend defaults with provided options
options = {...FormFromURLDefaults, ...options};
this.setURL(url);
this.setIncomingElementSelector(options.incomingElementSelector);
this.setInsertIntoElement(options.insertIntoElement);
this.onload(options.onload);
}
//default to the URL used to grab the form if it's not provided
url = !url ? this.getURL() : url;
//get the provided submit method
let method = this.getSubmitMethod();
//if it's null, grab it from the form
if( method === null ){
if( typeof form.attributes.method !== 'undefined' ){ //check that it was set explicitly
method = form.method; //grab JUST the value
}
/**
* Override the parent because it's not required for this class
*
* Still keeping it functional but removing all validation
*
* @param form
* @returns {XHRForm}
*/
setForm(form){
this._form = form;
return this;
}
//default to post if we still don't have a method and lowercase anything that was provided
method = !method ? 'post' : method.toLowerCase();
//if not valid, stop here until they resubmit
if (!this.isValid(form)) return false;
/**
* Set the URL from which the form will be retrieved
*
* @param url
* @returns {form}
*/
setURL(url){
if( typeof url !== 'string' ) throw `${url} is not a string`;
this._url = url;
return this;
}
navigation.showLoader();
/**
* Get the form's URL
*
* @returns {*|string}
*/
getURL(){
return this._url;
}
//get form values
const form_values = Array.from(
this.getFormValues(form),
e => e.map(encodeURIComponent).join('=')
).join('&');
/**
* If the URL provided returns HTML, this selector will be used to pull the form out
*
* If left null, it will assume the entire response is the form's HTML
*
* @param selector: string|null
* @returns {form}
*/
setIncomingElementSelector(selector){
if( selector !== null && typeof selector !== 'string' ) throw `${selector} is not a string or null value`;
this._incomingElementSelector = selector;
return this;
}
axios({
url: url,
method: method,
data: form_values,
}).then(function (response) {
navigation.hideLoader();
/**
* Returns a selector for the form or a parent of it that will be returned from the URL
*
* @returns {*|string}
*/
getIncomingElementSelector(){
return this._incomingElementSelector;
}
let data = response.data;
/**
* Allows you to set a parent element that the form will be inserted into using the default insertForm method
* Alternatively, you can leave this and override insertForm() and have more control over where it should go
*
* Uses dom.getElement() so you can pass a string, jQuery object, object, etc
* However if more than 1 element is detected, an error will be thrown
*
* @param element
*/
setInsertIntoElement(element){
this._insertIntoElement = element;
}
//just in case the server returned the wrong response type and it's actually JSON - ignore errors
try{ data = typeof data === 'string' ? JSON.parse(data) : data; } catch(e){ }
/**
* Returns the element the form will be inserted into
*
* @returns {*}
*/
getInsertIntoElement(){
return this._insertIntoElement;
}
//if the response is a string, it's probably/hopefully the form with inline errors
if( typeof data === 'string' ){
//if we are looking for an element within the response
if( typeof self.getIncomingElementSelector() === 'string' ){
//parse the incoming HTML
const parsed = navigation.parseHTML(data, self.getIncomingElementSelector());
//if the form was not found in it, let's assume it doesn't contain the form. If not, then maybe
if( !parsed.html.length ){
return self.triggerOnError(`${self.getIncomingElementSelector()} could not be found in response from the server`, data, form);
/**
* Get the form from the URL and pass to insertForm
*
* There are three main ways to provide the form from your server:
* 1) Straight HTML. The entire response is the form and that's it.
* 2) Straight HTML, but the form is only a part of the response so it needs to be parsed out based on a selector.
* 3) A JSON object containing the key "html" like this: {"html":"<form>your form here</form>"}
*
*/
getForm(){
var self = this;
navigation.showLoader();
axios.get(this.getURL()).then(function (response) {
navigation.hideLoader();
let data = response.data;
//just in case the server returned the wrong response type and it's actually JSON - ignore errors
try{ data = typeof data === 'string' ? JSON.parse(data) : data; } catch(e){ }
//if the response is a string (probably HTML)
if( typeof data === 'string' ){
if( typeof self.getIncomingElementSelector() === 'string' ){
//parse the incoming HTML
const parsed = navigation.parseHTML(data, self.getIncomingElementSelector());
//provide the form's HTML in an object containing other details like the route and the full response to insertForm
return self.insertForm(parsed, data);
}
//provide the form's HTML in an object containing other details like the route and the full response to insertForm
return self.insertForm(parsed, data, form);
//otherwise the entire response is assumed to be the form
return self.insertForm({html:data});
}
return self.insertForm({html:data}, data, form);
}
//if the response is an object, it's probably JSON
else if( typeof data === 'object' ){
//if it contains the HTML, just pop it back on the page
if( data.html ){
return self.insertForm({html:data.html}, data, form);
//if the response is an object (probably JSON)
else if( typeof data === 'object' ){
//if HTML was provided in the object
if( typeof data.html !== "undefined" ){
return self.insertForm({html:data.html}, data);
}
}
//if it contains an error message, trigger the callback
if( data.error ){
return self.triggerOnError(data.error, data, form);
}
//if it doesn't APPEAR to be the form again, or an error, let's call it a success
return self.triggerOnSuccess(data, form)
}
})
throw `Unexpected server response ${data}`;
})
.catch(function (error) {

@@ -467,4 +571,84 @@ navigation.hideLoader();

});
}
return this;
};
/**
* Allows you to insert the form wherever you want on the page
* Override this method to customize where the form is inserted
* (maybe you want to open a modal first and place it there?)
*
* parsed_content.html will always be the HTML
*
* parsed_content may contain other data like route and title if the form was pulled out of
* a full HTML page which contains those items
*
* response is the full server response (html string or object from JSON - not provided if the response is only the form's HTML)
*
* form is provided if this is after the form was submitted and HTML was returned form the server
*
* @param parsed_content
* @param response
* @param form
* @returns {*|Element|HTMLDocument}
*/
insertForm(parsed_content, response, form){
//selector for where the form will go
let el = this.getInsertIntoElement();
//if not provided
if( el === null ) throw 'Cannot determine where to insert form. Overwrite insertForm() or provide insertIntoElement';
//get the container element - error if not found
el = dom.getElement(el, true);
//put the form in the container element
el.innerHTML = parsed_content.html;
//find the newly added form
form = el.querySelector('form');
//attach an on-submit listener to send the form's values via XHR
this.attachSubmitHandler(form);
//run the onload callback now that the form is there
this.triggerOnload(form);
return el;
}
/**
* Use this method to modify the form immediately after it's displayed
*
* You'll likely want to attach plugins for datepickers/dropdowns, or maybe hide a field based on the value of another
*
* @param callback
* @returns {form}
*/
onload(callback){
if( typeof callback !== 'function' ) throw `${callback} is not a function`;
this._onload.push(callback);
return this;
}
/**
* Clears all onload callbacks you've set
*
* @returns {FormFromURL}
*/
clearOnloadCallbacks(){
this._onload = [];
return this;
}
//all onload callbacks
_onload = [];
/**
* @param form
*/
triggerOnload(form){
this._onload.forEach(function(onload){
onload(form);
});
return this;
}
}
{
"name": "@htmlguyllc/jpack",
"version": "1.0.12",
"version": "1.0.13",
"description": "Core Javascript Library of Everyday Objects, Events, and Utilities",

@@ -5,0 +5,0 @@ "keywords": [

@@ -232,113 +232,114 @@ # jPack

### -Form
_Makes dynamic form interactions simpler - currently only supports pulling a form from another page and submitting it using an XHR request_
### -XHRForm
_Submits a form using XHR_
Method/Property | Params (name:type) | Return | Notes
--- | --- | --- | ---
fromURL|url:string, options:object|self|instantiate a new form.fromURL('/my-form-url', options); to grab a form from another page and insert it into the current
constructor|form:Element,options:object |self|
setXHRSubmit|enabled:bool|self|enable/disable the XHR submission of the form
setSubmitMethod|method:string|self|override the form and provide a method (GET, POST, PATCH)
getSubmitMethod| |method:string|
setSubmitURL|url:mixed|self|pass null to use the form's action, function to dynamically generate the URL (receives the form as a param), or string
getSubmitURL| |url:string|returns whatever was set in the constructor or using setSubmitURL, not the final URL
attachSubmitHandler|form:mixed|self|attaches the event listener to on submit of the passed form
onSuccess|callback:function|self|adds an onSuccess callback (you can add as many as you'd like)
clearOnSuccessCallbacks| |self|
triggerOnSuccess|response:mixed, form:Element|self|runs all onSuccess callbacks and passes the server's response and the form element
onError|callback:function|self|adds an onError callback (you can add as many as you'd like)
clearOnErrorCallbacks| |self|
triggerOnError|error:string, response:mixed, form:Element|self|triggers all onError callbacks and passes the error string, server response, and form Element
submitForm|form:Element|self|gets URL and method, checks form validity using .validate(), gets values, submits, and kicks off callbacks
getFormValues|form:Element|self|returns data from the form to be submitted - override this if you want to manipulate it first
setValidateCallback|callback:function|is_valid:bool|pass a function to validate the form and return true if it's valid, false if it's not. False prevents form submission so you must display errors for the user within here. The default callback uses Bootstrap 4's "was-validated" class to show errors and HTML5's :invalid attribute to validate
validate|form:Element|bool|passes the form to the validate callback and returns the response
##### To use:
```javascript
import {form} from '@htmlguyllc/jpack/es/components';
import {XHRForm} from '@htmlguyllc/jpack/es/components';
var remote_form = new form.fromURL('/my-form', {
incomingElementSelector: null, //the form element or wrapper that you want to retrieve from the URL
insertIntoElement: null, //what element to put the form into
onload: function(form){ return this; }, //once the form is loaded onto the page
xhrSubmit: true, //submit the form using XHR instead of the default action
submitURL:null, //will be grabbed from the form's action attribute, or fallback to the URL the form was retrieved from
submitMethod:null, //will be grabbed from the form's method attribute, or fallback to "POST"
onError: function(error, response, form){ }, //called when the form is submitted and fails
onSuccess: function(response, form){ }, //called when the form is submitted successfully
//shown with defaults
var remote_form = new XHRForm(document.getElementById('my-form'), {
xhrSubmit: true, //wouldn't make a whole lotta sent to use this if this were false lol, but it's here for extending classes and incase you want to toggle it for whatever reason
submitURL:null, //when null, the form's action will be used (if explicitly defined), otherwise it falls back to the URL the form was retrieved from
submitMethod:null, //when null, the form's method will be used (if explicitly defined), otherwise it falls back to POST
onError: function(error, response, form){ }, //although you can add more, you can only pass 1 to start with in the constructor
onSuccess: function(response, form){ }, //although you can add more, you can only pass 1 to start with in the constructor
//validate the form, display any errors and return false to block submission
validateForm: function(form){
//add .was-validated for bootstrap to show errors
form.classList.add('was-validated');
//if there are any :invalid elements, the form is not valid
const is_valid = !form.querySelector(':invalid');
//if it's valid, clear the validation indicators
if( is_valid ) form.classList.remove('was-validated');
return is_valid;
}
});
//grab the form and insert in into the "insertIntoElement"
remote_form.getForm();
//attach the submission handler
remote_form.attachSubmitHandler();
```
//let's say you want to show it in a modal, here's what you would need to do:
### -FormFromURL
_Allows you to pull a form from a URL and insert it into the current page very easily including optional XHR form submission!_
var modal_form = new form.fromURL('/my-form-popup', {
incomingElementSelector: 'form',
onload: function(form){
//attach plugins or do something with the form now that it's showing in the modal
return this;
},
onError: function(error, response, form){
$.jAlert({
title:'Error',
theme:'red',
content:error
});
},
onSuccess: function(response, form){
form.parents('.jAlert').closeAlert();
//do something else
},
});
Method/Property | Params (name:type) | Return | Notes
--- | --- | --- | ---
constructor | url:string, options:object |self|
setURL|url:string|self|set the URL to pull the form from
getURL| |url:string|
setIncomingElementSelector|selector:string|self|set a selector for the form element or it's parent that is returned by the URL
getIncomingElementSelector| |selector:string|
setInsertIntoElement|element:mixed|self|set the element that the form should be inserted into
getInsertIntoElement| |element:mixed|
getForm| |void|pulls the form from the URL and runs the insertForm method
insertForm|parsed_content:object, response:mixed, form:Element/null|el:Element|inserts the form into the parent element, attaches the submit handler, triggers onload, and returns the parent element
onload|callback:function|self|adds a callback function to be run when the form is loaded on the page
clearOnloadCallbacks| |self|removes all onload callbacks
triggerOnload|form:Element|self|runs all onload callbacks and passes the form to them
//override the insertForm method to use a modal
modal_form.insertForm = function(parsed_content, response, form){
var self = this;
__There are several methods and properties inherited from XHRForm that are not listed here. Please see XHRForm above for those details__
##### To use:
```javascript
import {FormFromURL} from '@htmlguyllc/jpack/es/components';
//shown with defaults
var remote_form = new FormFromURL('/my-form', {
incomingElementSelector: null, //when null, it assumes the entire response is the form's HTML
insertIntoElement: null, //error on null, must provide this
onload: function(form){ return this; }, //although you can add more, you can only pass 1 to start with in the constructor
xhrSubmit: true,
submitURL:null, //when null, the form's action will be used (if explicitly defined), otherwise it falls back to the URL the form was retrieved from
submitMethod:null, //when null, the form's method will be used (if explicitly defined), otherwise it falls back to POST
onError: function(error, response, form){ }, //although you can add more, you can only pass 1 to start with in the constructor
onSuccess: function(response, form){ }, //although you can add more, you can only pass 1 to start with in the constructor
//validate the form, display any errors and return false to block submission
validateForm: function(form){
//add .was-validated for bootstrap to show errors
form.classList.add('was-validated');
//if form is already defined, it was submitted and the response contained HTML, so we need to just replace it ourselves
if( form ){
//replace and reassign
form = dom.replaceElWithHTML(form, parsed_content.html);
//attach submit handler
self.attachSubmitHandler(form);
//trigger onload again (you can pas a param to say it's the second time if you want
self.triggerOnload(form);
return;
}
//if there are any :invalid elements, the form is not valid
const is_valid = !form.querySelector(':invalid');
//using jAlert as an example (https://htmlguyllc.github.io/jAlert/)
$.jAlert({
title:'My Form',
theme:'blue',
size: '1000px',
content: parsed_content.html,
onOpen: function(alert){
//find my form in there
form = alert[0].querySelector(self.getIncomingElementSelector());
//attach an on-submit listener to send the form's values via XHR
self.attachSubmitHandler(form);
//if it's valid, clear the validation indicators
if( is_valid ) form.classList.remove('was-validated');
//run the onload callback now that the form is there
self.triggerOnload(form);
return is_valid;
}
});
};
});
//show the form in a modal
modal_form.getForm();
//grab the form and insert in into the "insertIntoElement"
remote_form.getForm();
```
#### Prototyping:
#### Extending:
You can use prototypes to globally overwrite 3 methods in form.fromURL (isValid, insertForm, and submitForm).
FormFromURL extends XHRForm and either can be extended as you need.
```javascript
import {form} from '@htmlguyllc/jpack/es/components';
See examples/FormModalFromURL for an example
form.fromURL.prototype.insertForm = function(parsed_content, response, form) {
//this is useful if you always want to show your form in a modal like shown in the example above
};
form.fromURL.prototype.isValid = function(form){
//perform validation on the form and return a bool
//false prevents form submission so make sure you display any errors for the user
};
//now create a new form and both methods above will be used
var my_form = new form.fromURL('/my-form');
//no matter how many you create, they all share the same logic now
var my_form2 = new form.fromURL('/my-form2');
```
## - Objects -

@@ -345,0 +346,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc