2021-05-25 22:27:23 -07:00
import { IgniteObject , IgniteProperty , IgniteRenderingContext } from './ignite-html.js' ;
2020-08-23 11:50:31 -07:00
import { IgniteElement } from './ignite-element.js' ;
2020-07-28 09:04:04 -07:00
2020-08-30 21:55:21 -07:00
/**
* The outline of a ignite template. Templates are a blueprint that specify's
* how to construct an element and then can be used to construct the element. Everything
* starts with a template.
*
* @example
* //You can easily create a template to construct any html element. See the following:
* class div extends IgniteTemplate {
* constructor(...items) {
* super("div", items);
* }
* }
2021-05-04 14:13:08 -07:00
*
* @example
* IgniteTemplate's construct method can be extended by adding a callback function to _constructors under a template:
* template._constructors.push(() => console.log('constructed'));
*
*
* @example
* IgniteTemplate's deconstruct method can be extended by adding a callback function to _destructors under a template:
* template._destructors.push(() => console.log('destructed'));
2020-08-30 21:55:21 -07:00
*/
2020-07-28 09:04:04 -07:00
class IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* Creates a new IgniteTemplate with the tag name of the element that will be constructed and an
* array of child elements.
* @param {String} tagName The tag name of the element this template will construct.
* @param {String|Number|IgniteProperty|IgniteTemplate} children An array of child elements to be added to this template.
*/
constructor ( tagName = null , children = null ) {
2020-07-28 09:04:04 -07:00
this . children = [];
2020-08-30 21:55:21 -07:00
this . tagName = tagName ;
2020-12-09 20:41:11 -08:00
this . tagNamespace = null ;
2020-07-28 09:04:04 -07:00
this . element = null ;
2020-10-26 15:30:11 -07:00
this . _attributes = {};
this . _classes = [];
this . _properties = {};
2021-03-28 23:23:58 -07:00
this . _variables = {};
2021-01-09 16:24:24 -08:00
this . _reflecting = {};
2020-10-26 15:30:11 -07:00
this . _refs = [];
this . _callbacks = [];
this . _events = {};
this . _styles = {};
2021-05-04 14:13:08 -07:00
this . _constructors = [];
this . _destructors = [];
2020-10-26 15:30:11 -07:00
this . _elementValue = null ;
this . _elementInnerHTML = null ;
2021-10-06 08:08:02 -07:00
this . _elementInnerText = null ;
2021-05-04 14:13:08 -07:00
this . _resizeObserverCallback = [];
2021-01-09 16:24:24 -08:00
this . _resizeObserver = null ;
2021-05-04 14:13:08 -07:00
this . _intersectObserverCallback = [];
this . _intersectObserver = null ;
2020-07-28 09:04:04 -07:00
2020-08-30 21:55:21 -07:00
if ( children ) {
for ( var i = 0 ; i < children . length ; i ++ ) {
2020-10-07 08:30:03 -07:00
if ( children [ i ] === undefined || children [ i ] === null ) {
continue ; //Skip undefined or null children.
} else if ( children [ i ] instanceof IgniteProperty ) {
2020-08-30 21:55:21 -07:00
this . children . push ( new html ( children [ i ]));
} else if ( children [ i ] instanceof String || typeof children [ i ] === 'string' ) {
this . children . push ( new html ( children [ i ]));
} else if ( children [ i ] instanceof Number || typeof children [ i ] === 'number' ) {
this . children . push ( new html ( children [ i ]));
} else if ( children [ i ] instanceof IgniteTemplate || children [ i ]. prototype instanceof IgniteTemplate ) {
this . children . push ( children [ i ]);
2020-07-29 14:01:41 -07:00
} else {
2020-08-30 21:55:21 -07:00
throw `Attempted to add a child for template: ${ this . tagName } which is not supported. Child: ${ children [ i ] } ` ;
2020-07-28 09:04:04 -07:00
}
}
}
}
2020-07-28 22:23:49 -07:00
/**
2020-08-31 22:11:19 -07:00
* Adds a CSS class to be added once this template is constructed.
* @param {String|IgniteProperty} name Name of the CSS class to add. Multiple CSS classes are supported if they are separated by a space.
2020-08-30 21:55:21 -07:00
* @param {Function} converter Optional function that can convert the class name into a different one.
2020-08-31 22:11:19 -07:00
* @example
* .class("row justify-content-center")
2020-08-30 21:55:21 -07:00
* @returns This ignite template so function calls can be chained.
2020-07-28 22:23:49 -07:00
*/
2020-08-23 22:27:12 -07:00
class ( name , converter = null ) {
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . push ();
2020-08-23 22:27:12 -07:00
if ( name instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( name . attachOnChange (( oldValue , newValue ) => this . onClassChanged (( converter != null ? converter ( oldValue ) : oldValue ), ( converter != null ? converter ( newValue ) : newValue ))));
2021-01-10 23:09:50 -08:00
this . _callbacks . push ( name . attachOnPush (( list , items ) => this . onClassChanged (( converter != null ? converter ( list ) : list ), ( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( name . attachOnUnshift (( list , items ) => this . onClassChanged (( converter != null ? converter ( list ) : list ), ( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( name . attachOnPop (( list ) => this . onClassChanged (( converter != null ? converter ( list ) : list ), ( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( name . attachOnShift (( list ) => this . onClassChanged (( converter != null ? converter ( list ) : list ), ( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( name . attachOnSplice (( list , start , deleteCount , items ) => this . onClassChanged (( converter != null ? converter ( list ) : list ), ( converter != null ? converter ( list ) : null ))));
2020-08-31 22:11:19 -07:00
var value = ( converter != null ? converter ( name . value ) : name . value );
2020-09-29 14:28:27 -07:00
( value != null ? value . toString (). split ( " " ) : []). forEach ( cl => {
if ( cl . length > 0 ) {
2020-10-26 15:30:11 -07:00
this . _classes . push ( cl );
2020-09-29 14:28:27 -07:00
}
});
} else if ( Array . isArray ( name ) && name . length > 0 && name [ 0 ] instanceof IgniteProperty ) {
//There must be a converter for this to work correctly
if ( ! converter ) {
throw "Cannot pass an array of properties without using a converter!" ;
}
//Attack a callback for all the properties
name . forEach ( prop => {
2020-10-20 13:18:26 -07:00
if ( prop instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( prop . attachOnChange (( oldValue , newValue ) => this . onClassChanged ( converter (... name . getOldPropertyValues ( prop , oldValue )), converter (... name . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPush (( list , items ) => this . onClassChanged ( converter (... name . getOldPropertyValues ( prop , list )), converter (... name . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnUnshift (( list , items ) => this . onClassChanged ( converter (... name . getOldPropertyValues ( prop , list )), converter (... name . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPop (( list ) => this . onClassChanged ( converter (... name . getOldPropertyValues ( prop , list )), converter (... name . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnShift (( list ) => this . onClassChanged ( converter (... name . getOldPropertyValues ( prop , list )), converter (... name . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnSplice (( list , start , deleteCount , items ) => this . onClassChanged ( converter (... name . getOldPropertyValues ( prop , list )), converter (... name . getPropertyValues ()))));
2020-10-20 13:18:26 -07:00
}
2020-09-29 14:28:27 -07:00
});
var value = converter (... name . getPropertyValues ());
( value != null ? value . toString (). split ( " " ) : []). forEach ( cl => {
2020-08-31 22:11:19 -07:00
if ( cl . length > 0 ) {
2020-10-26 15:30:11 -07:00
this . _classes . push ( cl );
2020-08-31 22:11:19 -07:00
}
});
2020-08-23 22:27:12 -07:00
} else {
2020-08-31 22:11:19 -07:00
var value = ( converter != null ? converter ( name ) : name );
2020-09-29 14:28:27 -07:00
( value != null ? value . toString (). split ( " " ) : []). forEach ( cl => {
2020-08-31 22:11:19 -07:00
if ( cl . length > 0 ) {
2020-10-26 15:30:11 -07:00
this . _classes . push ( cl );
2020-08-31 22:11:19 -07:00
}
});
2020-07-28 09:04:04 -07:00
}
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . pop ();
2020-07-28 09:04:04 -07:00
return this ;
}
2020-07-28 22:23:49 -07:00
/**
2020-08-30 21:55:21 -07:00
* Adds a html element attribute to this template to be added once this template is constructed.
* @param {String} name The name of the attribute to add
* @param {String|IgniteProperty} value The value of the attribute to set, can be anything. If Property is passed it will auto update.
* @param {Function} converter Optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
2020-07-28 22:23:49 -07:00
*/
2020-08-23 22:27:12 -07:00
attribute ( name , value , converter = null ) {
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . push ();
2020-07-28 09:04:04 -07:00
if ( value instanceof IgniteProperty ) {
2021-10-13 07:46:40 -07:00
this . _callbacks . push ( value . attachOnChange (( oldValue , newValue ) => this . onAttributeChanged ( name , ( converter ? converter ( newValue ) : newValue ))));
this . _callbacks . push ( value . attachOnPush (( list , items ) => this . onAttributeChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnUnshift (( list , items ) => this . onAttributeChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnPop (( list ) => this . onAttributeChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnShift (( list ) => this . onAttributeChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnSplice (( list , start , deleteCount , items ) => this . onAttributeChanged ( name , converter ? converter ( list ) : null )));
this . _attributes [ name ] = converter ? converter ( value . value ) : value . value ;
} else if ( Array . isArray ( value ) && value . length > 0 && value [ 0 ] instanceof IgniteProperty ) {
//There must be a converter for this to work correctly
if ( ! converter ) {
throw "Cannot pass an array of properties without using a converter!" ;
}
//Attack a callback for all the properties
value . forEach ( prop => {
if ( prop instanceof IgniteProperty ) {
this . _callbacks . push ( prop . attachOnChange (( oldValue , newValue ) => this . onAttributeChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPush (( list , items ) => this . onAttributeChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnUnshift (( list , items ) => this . onAttributeChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPop (( list ) => this . onAttributeChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnShift (( list ) => this . onAttributeChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnSplice (( list , start , deleteCount , items ) => this . onAttributeChanged ( name , converter (... value . getPropertyValues ()))));
}
});
this . _attributes [ name ] = converter (... value . getPropertyValues ());
2020-07-28 09:04:04 -07:00
} else {
2021-10-13 07:46:40 -07:00
this . _attributes [ name ] = converter ? converter ( value ) : value ;
2020-07-28 09:04:04 -07:00
}
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . pop ();
2020-07-28 09:04:04 -07:00
return this ;
}
2020-08-31 22:11:19 -07:00
/**
* Sets the value of the element this template is constructing with the option to reflect changes
* to the value.
* @param {String|IgniteProperty} value The value to set on the element.
2021-03-09 13:06:29 -08:00
* @param {Boolean|Function} reflect Whether or not to reflect changes to the value of the element back to the property if one was used.
2020-08-31 22:11:19 -07:00
* @param {Function} converter Optional function that can convert the value if needed.
2020-09-01 08:50:11 -07:00
* @returns This ignite template so function calls can be chained.
2020-08-31 22:11:19 -07:00
*/
value ( value , reflect = false , converter = null ) {
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . push ();
2020-08-31 22:11:19 -07:00
if ( value instanceof IgniteProperty ) {
2021-03-09 13:06:29 -08:00
this . _callbacks . push ( value . attachOnChange (( oldValue , newValue ) => this . onValueChanged (( converter != null ? converter ( newValue ) : newValue ))));
this . _callbacks . push ( value . attachOnPush (( list , items ) => this . onValueChanged (( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( value . attachOnUnshift (( list , items ) => this . onValueChanged (( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( value . attachOnPop (( list ) => this . onValueChanged (( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( value . attachOnShift (( list ) => this . onValueChanged (( converter != null ? converter ( list ) : null ))));
this . _callbacks . push ( value . attachOnSplice (( list , start , deleteCount , items ) => this . onValueChanged (( converter != null ? converter ( list ) : null ))));
if ( reflect != null && (( typeof ( reflect ) == "boolean" && reflect == true ) || reflect instanceof Function )) {
2021-05-04 14:13:08 -07:00
var valueChanged = () => {
2021-03-09 13:06:29 -08:00
var newValue = null ;
2021-04-18 12:49:17 -07:00
var type = this . element . hasAttribute ( "type" ) ? this . element . getAttribute ( "type" ). toLowerCase (). trim () : null ;
if ( type == "checkbox" ) {
2021-03-09 13:06:29 -08:00
newValue = this . element . checked ;
2021-04-18 12:49:17 -07:00
} else if ( type == "radio" ) {
2021-03-09 13:06:29 -08:00
newValue = this . element . checked ;
2021-04-18 12:49:17 -07:00
} else if ( type == "number" ) {
newValue = Number ( this . element . value );
2020-10-26 15:30:11 -07:00
} else if ( this . element . hasAttribute ( "contenteditable" ) && this . element . getAttribute ( "contenteditable" ). toLowerCase (). trim () == "true" ) {
2021-03-09 13:06:29 -08:00
newValue = this . element . textContent ;
2020-10-26 15:30:11 -07:00
} else {
2021-03-09 13:06:29 -08:00
newValue = this . element . value ;
}
if ( reflect instanceof Function ) {
reflect ( newValue );
} else {
value . setValue ( newValue , true );
2020-10-26 15:30:11 -07:00
}
2021-05-04 14:13:08 -07:00
this . _elementValue = newValue ;
2021-04-18 12:49:17 -07:00
};
2021-03-09 13:06:29 -08:00
2021-04-18 12:49:17 -07:00
this . on ( "change" , valueChanged );
2021-05-11 22:32:46 -07:00
this . on ( "keyup" , valueChanged );
2020-08-31 22:11:19 -07:00
}
2020-10-26 15:30:11 -07:00
this . _elementValue = ( converter != null ? converter ( value . value ) : value . value );
2020-08-31 22:11:19 -07:00
} else {
2020-10-26 15:30:11 -07:00
this . _elementValue = ( converter != null ? converter ( value ) : value );
2020-08-31 22:11:19 -07:00
}
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . pop ();
2020-08-31 22:11:19 -07:00
return this ;
}
2020-07-28 22:23:49 -07:00
/**
2021-03-28 23:23:58 -07:00
* Sets a property on the element this template will construct.
2020-08-30 21:55:21 -07:00
* @param {String} name Name of the property to set.
* @param {Any|IgniteProperty} value Value of the property to use. If a Property is passed the value will auto update.
* @param {Boolean} reflect If true whenever this property is changed it's value will be passed back to the Property that was passed as value if one was passed.
* @param {Function} converter Optional function that can be used to convert the value if needed.
* @returns This ignite template so function calls can be chained.
2020-07-28 22:23:49 -07:00
*/
2020-08-30 21:55:21 -07:00
property ( name , value , reflect = false , converter = null ) {
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . push ();
2020-10-26 15:30:11 -07:00
if ( this . _properties [ name ]) {
2020-08-23 11:50:31 -07:00
throw `Attempted to set a property twice on a IgniteTemplate: ${ this . tagName } . This is not allowed and should be avoided.` ;
}
2020-08-30 21:55:21 -07:00
if ( reflect && converter != null ) {
throw `Cannot add a property to an IgniteTemplate: ${ this . tagName } with reflect and a converter used at the same time.` ;
}
2020-07-28 09:04:04 -07:00
if ( value instanceof IgniteProperty ) {
2021-10-13 07:46:40 -07:00
this . _callbacks . push ( value . attachOnChange (( oldValue , newValue ) => this . onPropertyChanged ( name , converter ? converter ( newValue ) : newValue )));
this . _callbacks . push ( value . attachOnPush (( list , items ) => this . onPropertyChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnUnshift (( list , items ) => this . onPropertyChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnPop (( list ) => this . onPropertyChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnShift (( list ) => this . onPropertyChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnSplice (( list , start , deleteCount , items ) => this . onPropertyChanged ( name , converter ? converter ( list ) : list )));
2021-02-12 18:53:09 -08:00
2020-10-26 15:30:11 -07:00
this . _properties [ name ] = {
2020-08-30 21:55:21 -07:00
value : ( converter != null ? converter ( value . value ) : value . value ),
reflect : ( reflect == true ? value : null )
};
2020-07-28 09:04:04 -07:00
} else {
2020-10-26 15:30:11 -07:00
this . _properties [ name ] = {
2020-08-30 21:55:21 -07:00
value : ( converter != null ? converter ( value ) : value ),
reflect : null
};
2020-07-28 09:04:04 -07:00
}
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . pop ();
return this ;
}
2021-03-28 23:23:58 -07:00
/**
* Sets a variable on the element this template will construct.
* @param {String} name Name of the variable to set
* @param {Any|IgniteProperty} value Value of the variable to set
* @param {Function} converter Optional function that can be used to convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
variable ( name , value , converter = null ) {
IgniteRenderingContext . push ();
if ( this . _variables [ name ]) {
throw `Attempted to set a variable twice on a IgniteTemplate: ${ this . tagName } . This is not allowed and should be avoided.` ;
}
if ( value instanceof IgniteProperty ) {
2021-10-13 07:46:40 -07:00
this . _callbacks . push ( value . attachOnChange (( oldValue , newValue ) => this . onVariableChanged ( name , converter ? converter ( newValue ) : newValue )));
this . _callbacks . push ( value . attachOnPush (( list , items ) => this . onVariableChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnUnshift (( list , items ) => this . onVariableChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnPop (( list ) => this . onVariableChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnShift (( list ) => this . onVariableChanged ( name , converter ? converter ( list ) : list )));
this . _callbacks . push ( value . attachOnSplice (( list , start , deleteCount , items ) => this . onVariableChanged ( name , converter ? converter ( list ) : list )));
2021-03-28 23:23:58 -07:00
this . _variables [ name ] = {
value : ( converter != null ? converter ( value . value ) : value . value )
};
} else {
this . _variables [ name ] = {
value : ( converter != null ? converter ( value ) : value )
};
}
IgniteRenderingContext . pop ();
return this ;
}
2021-01-09 16:24:24 -08:00
/**
* Makes a property on this template reflect its value back to the given target.
* (You can reflect a property more than once if it's needed.)
* @param {String} name Name of the property to reflect.
* @param {IgniteProperty|Function} target The target for the value to be reflected to.
2021-03-16 22:26:33 -07:00
* @returns This ignite template so function calls can be chained.
2021-01-09 16:24:24 -08:00
*/
reflect ( name , target ) {
IgniteRenderingContext . push ();
if ( this . _reflecting [ name ] == undefined || this . _reflecting [ name ] == null ) {
this . _reflecting [ name ] = [];
}
if ( target instanceof IgniteProperty ) {
this . _reflecting [ name ]. push ( target );
} else if ( target instanceof Function ) {
this . _reflecting [ name ]. push ( target );
}
IgniteRenderingContext . pop ();
return this ;
}
2020-10-26 15:30:11 -07:00
/**
* Adds a set of properties from an object to be added to this template once it's constructed.
2021-05-25 22:27:23 -07:00
* @param {Object|IgniteObject} props The object value that property names/values will be pulled from.
2020-10-26 15:30:11 -07:00
* @returns This ignite template so function calls can be chained.
*/
properties ( props ) {
//Make sure we have a valid props.
if ( props == null || props == undefined ) {
return ;
}
2021-05-25 22:27:23 -07:00
else if ( ! ( typeof props === 'object' )) {
2020-10-26 15:30:11 -07:00
throw `Cannot set properties with a non object set of properties: ${ props } ` ;
}
2021-05-25 22:27:23 -07:00
if ( props instanceof IgniteObject ) {
props . update ();
2020-10-26 15:30:11 -07:00
2021-05-25 22:27:23 -07:00
Object . getOwnPropertyNames ( props ). forEach ( name => this . property ( name , props [ name ], true ));
}
else {
Object . keys ( props ). forEach ( name => this . property ( name , props [ name ], false , null ));
}
2020-10-26 15:30:11 -07:00
return this ;
}
2020-09-25 09:36:39 -07:00
/**
* Sets the inner html of the element to be constructed by this template.
* @param {String|IgniteProperty} value InnerHTML to set for element. If a property is passed the html will auto update.
* @param {Function} converter Optional function that can be used to convert the value if needed.
* @returns This ignite template so funciton calls can be chained.
*/
innerHTML ( value , converter = null ) {
IgniteRenderingContext . push ();
if ( value instanceof IgniteProperty ) {
2021-10-06 08:08:02 -07:00
this . _callbacks . push ( value . attachOnChange (( oldValue , newValue ) => this . onInnerHTMLChanged ( converter != null ? converter ( newValue ) : newValue )));
this . _callbacks . push ( value . attachOnPush (( list , items ) => this . onInnerHTMLChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnUnshift (( list , items ) => this . onInnerHTMLChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnPop (( list ) => this . onInnerHTMLChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnShift (( list ) => this . onInnerHTMLChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnSplice (( list , start , deleteCount , items ) => this . onInnerHTMLChanged ( converter != null ? converter ( list ) : null )));
2021-02-03 10:15:04 -08:00
2020-10-26 15:30:11 -07:00
this . _elementInnerHTML = ( converter != null ? converter ( value . value ) : value . value );
2021-06-30 08:48:24 -07:00
} else if ( Array . isArray ( value ) && value . length > 0 && value [ 0 ] instanceof IgniteProperty ) {
//There must be a converter for this to work correctly
if ( ! converter ) {
throw "Cannot pass an array of properties without using a converter!" ;
}
//Attack a callback for all the properties
value . forEach ( prop => {
if ( prop instanceof IgniteProperty ) {
2021-10-06 08:08:02 -07:00
this . _callbacks . push ( prop . attachOnChange (( oldValue , newValue ) => this . onInnerHTMLChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPush (( list , items ) => this . onInnerHTMLChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnUnshift (( list , items ) => this . onInnerHTMLChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPop (( list ) => this . onInnerHTMLChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnShift (( list ) => this . onInnerHTMLChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnSplice (( list , start , deleteCount , items ) => this . onInnerHTMLChanged ( converter (... value . getPropertyValues ()))));
2021-06-30 08:48:24 -07:00
}
});
this . _elementInnerHTML = converter (... value . getPropertyValues ());
2020-09-25 09:36:39 -07:00
} else {
2020-10-26 15:30:11 -07:00
this . _elementInnerHTML = ( converter != null ? converter ( value ) : value );
2020-09-25 09:36:39 -07:00
}
IgniteRenderingContext . pop ();
2020-07-28 09:04:04 -07:00
return this ;
}
2021-10-06 08:08:02 -07:00
/**
* Sets the inner text of the element to be constructed by this template.
* @param {String|IgniteProperty} value text to be set for this element. If a property is passed the text will auto update.
* @param {Function} converter Optional function that can be used to convert the value if needed.
* @returns This ignite template.
*/
innerText ( value , converter = null ) {
IgniteRenderingContext . push ();
if ( value instanceof IgniteProperty ) {
this . _callbacks . push ( value . attachOnChange (( oldValue , newValue ) => this . onInnerTextChanged ( converter != null ? converter ( newValue ) : newValue )));
this . _callbacks . push ( value . attachOnPush (( list , items ) => this . onInnerTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnUnshift (( list , items ) => this . onInnerTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnPop (( list ) => this . onInnerTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnShift (( list ) => this . onInnerTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnSplice (( list , start , deleteCount , items ) => this . onInnerTextChanged ( converter != null ? converter ( list ) : null )));
this . _elementInnerText = ( converter != null ? converter ( value . value ) : value . value );
} else if ( Array . isArray ( value ) && value . length > 0 && value [ 0 ] instanceof IgniteProperty ) {
//There must be a converter for this to work correctly
if ( ! converter ) {
throw "Cannot pass an array of properties without using a converter!" ;
}
//Attack a callback for all the properties
value . forEach ( prop => {
if ( prop instanceof IgniteProperty ) {
this . _callbacks . push ( prop . attachOnChange (( oldValue , newValue ) => this . onInnerTextChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPush (( list , items ) => this . onInnerTextChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnUnshift (( list , items ) => this . onInnerTextChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPop (( list ) => this . onInnerTextChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnShift (( list ) => this . onInnerTextChanged ( converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnSplice (( list , start , deleteCount , items ) => this . onInnerTextChanged ( converter (... value . getPropertyValues ()))));
}
});
this . _elementInnerText = converter (... value . getPropertyValues ());
} else {
this . _elementInnerText = ( converter != null ? converter ( value ) : value );
}
IgniteRenderingContext . pop ();
return this ;
}
2020-07-28 22:23:49 -07:00
/**
* Adds a single or series of children to be added once this template
2020-08-30 21:55:21 -07:00
* is constructed. Numbers, Strings, and Properties passed will be added as HTML child elements.
* @param {...Number|String|IgniteProperty|IgniteTemplate} items A series of children to be added to this template.
* @returns This ignite template so function calls can be chained.
2020-07-28 22:23:49 -07:00
*/
2020-07-28 09:04:04 -07:00
child (... items ) {
2020-08-30 21:55:21 -07:00
if ( items ) {
for ( var i = 0 ; i < items . length ; i ++ ) {
2020-10-07 08:30:03 -07:00
if ( items [ i ] === undefined || items [ i ] === null ) {
continue ; //Skip undefined or null items.
} else if ( items [ i ] instanceof IgniteProperty ) {
2020-08-30 21:55:21 -07:00
this . children . push ( new html ( items [ i ]));
} else if ( items [ i ] instanceof String || typeof items [ i ] === 'string' ) {
this . children . push ( new html ( items [ i ]));
} else if ( items [ i ] instanceof Number || typeof items [ i ] === 'number' ) {
this . children . push ( new html ( items [ i ]));
} else if ( items [ i ] instanceof IgniteTemplate || items [ i ]. prototype instanceof IgniteTemplate ) {
this . children . push ( items [ i ]);
} else {
throw `Attempted to add a child for template: ${ this . tagName } which is not supported. Child: ${ items [ i ] } ` ;
}
2020-07-28 22:23:49 -07:00
}
}
2020-07-28 09:04:04 -07:00
return this ;
}
2020-07-28 22:23:49 -07:00
/**
2020-08-30 21:55:21 -07:00
* Adds a reference callback function to be invoked once this template is constructed. The function will be invoked
* with the constructed HTMLElement. If an IgniteProperty is passed it's value will be set to the constructed HTMLElement once
* the template is constructed.
* @param {Function|IgniteProperty} refCallback The callback to be invoked with the HTMLElement of the element this template constructed.
* @returns This ignite template so function calls can be chained.
2020-07-28 22:23:49 -07:00
*/
2020-08-30 21:55:21 -07:00
ref ( refCallback ) {
if ( refCallback instanceof IgniteProperty ) {
2021-10-13 07:46:40 -07:00
this . _callbacks . push ( refCallback . attachOnChange (( oldValue , newValue ) => this . onRefChanged ( refCallback , newValue )));
2021-01-09 16:24:24 -08:00
this . _refs . push ( element => refCallback . value = element );
2020-07-28 09:50:26 -07:00
} else {
2020-10-26 15:30:11 -07:00
this . _refs . push ( refCallback );
2020-07-28 09:50:26 -07:00
}
return this ;
}
2020-07-30 08:32:44 -07:00
/**
2020-08-30 21:55:21 -07:00
* Adds an event by its name and the function to invoke once the event fires. Properties may be used
* for the function, but their value must be a valid function in order to get a proper event callback.
* @param {String} eventName The name of the event to add.
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
* @returns This ignite template so function calls can be chained.
2020-07-30 08:32:44 -07:00
*/
2020-08-30 21:55:21 -07:00
on ( eventName , eventCallback ) {
2021-01-09 16:24:24 -08:00
IgniteRenderingContext . push ();
2020-10-26 15:30:11 -07:00
if ( ! this . _events [ eventName ]) {
this . _events [ eventName ] = [];
2020-07-30 09:58:47 -07:00
}
2020-08-30 21:55:21 -07:00
if ( eventCallback instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( eventCallback . attachOnChange (( oldValue , newValue ) => this . onEventChanged ( oldValue , newValue , eventName )));
this . _events [ eventName ]. push ( eventCallback . value );
2020-07-30 08:32:44 -07:00
} else {
2020-10-26 15:30:11 -07:00
this . _events [ eventName ]. push ( eventCallback );
2020-07-30 08:32:44 -07:00
}
2021-01-09 16:24:24 -08:00
IgniteRenderingContext . pop ();
2020-07-30 08:32:44 -07:00
return this ;
}
2020-08-23 11:50:31 -07:00
/**
2021-01-09 16:24:24 -08:00
* Adds a click event handler to this template.
2020-08-30 21:55:21 -07:00
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
* @returns This ignite template so function calls can be chained.
2020-08-23 11:50:31 -07:00
*/
2020-08-30 21:55:21 -07:00
onClick ( eventCallback ) {
2020-09-25 09:36:39 -07:00
return this . on ( "click" , eventCallback );
}
2020-08-21 22:13:06 -07:00
2021-01-09 16:24:24 -08:00
/**
* Adds a touch event handler to this template.
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
* @returns This ignite template so function calls can be chained.
*/
onTouch ( eventCallback ) {
return this . on ( "touch" , eventCallback );
}
2020-09-25 09:36:39 -07:00
/**
* Adds a onblur event handler to this template.
2020-10-07 08:30:03 -07:00
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
2020-09-25 09:36:39 -07:00
* @returns This ignite template so function calls can be chained.
*/
onBlur ( eventCallback ) {
return this . on ( "blur" , eventCallback );
}
/**
* Adds a onfocus event handler to this template.
2020-10-07 08:30:03 -07:00
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
2020-09-25 09:36:39 -07:00
* @returns This ignite template so function calls can be chained.
*/
onFocus ( eventCallback ) {
return this . on ( "focus" , eventCallback );
2020-08-21 22:13:06 -07:00
}
2020-10-07 08:30:03 -07:00
/**
* Adds a onchange event handler to this template.
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
* @returns This ignite template so function calls can be chained.
*/
onChange ( eventCallback ) {
return this . on ( "change" , eventCallback );
}
2021-10-06 08:08:02 -07:00
/**
*
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked once the event fires.
* @returns This ignite template.
*/
onPaste ( eventCallback ) {
return this . on ( "paste" , eventCallback );
}
2020-08-23 11:50:31 -07:00
/**
* Adds a on enter key press event handler to this template.
2020-08-30 21:55:21 -07:00
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
* @returns This ignite template so function calls can be chained.
2020-08-23 11:50:31 -07:00
*/
2020-08-30 21:55:21 -07:00
onEnter ( eventCallback ) {
2020-08-21 22:13:06 -07:00
var eventName = "keydown" ;
2020-10-26 15:30:11 -07:00
if ( ! this . _events [ eventName ]) {
this . _events [ eventName ] = [];
2020-08-21 22:13:06 -07:00
}
2020-08-30 21:55:21 -07:00
if ( eventCallback instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( eventCallback . attachOnChange (( oldValue , newValue ) => {
2020-08-21 22:13:06 -07:00
//Create a new wrapped function to check for the enter key being pressed.
var wrapped = ( e ) => {
if ( e . key === 'Enter' ) {
newValue ( e );
}
};
2020-09-25 09:36:39 -07:00
eventCallback . _value = wrapped ; //Store the wrapped function into the property so we can remove it later
this . onEventChanged ( oldValue , wrapped , eventName ); //Invoke event changed with the old value and wrapped one.
2020-08-21 22:13:06 -07:00
}));
//Create the initial wrapper
2020-08-30 21:55:21 -07:00
var target = eventCallback . _value ;
2020-08-21 22:13:06 -07:00
var wrapped = ( e ) => {
if ( e . key === 'Enter' ) {
2020-08-21 22:14:57 -07:00
target ( e );
2020-08-21 22:13:06 -07:00
}
};
//Store the wrapped so that it's the old value next time around.
2020-08-30 21:55:21 -07:00
eventCallback . _value = wrapped ;
2020-08-21 22:13:06 -07:00
2020-10-26 15:30:11 -07:00
this . _events [ eventName ]. push ( wrapped );
2020-08-21 22:13:06 -07:00
} else {
this . on ( eventName , ( e ) => {
if ( e . key === 'Enter' ) {
2020-08-30 21:55:21 -07:00
eventCallback ( e );
2020-08-21 22:13:06 -07:00
}
});
}
return this ;
}
2020-09-25 09:36:39 -07:00
/**
* Adds a on backspace key press event handler to this template.
* @param {Function|IgniteProperty} eventCallback The callback function to be invoked by the event once it fires.
* @returns This ignite template so function calls can be chained.
*/
onBackspace ( eventCallback ) {
var eventName = "keydown" ;
2020-10-26 15:30:11 -07:00
if ( ! this . _events [ eventName ]) {
this . _events [ eventName ] = [];
2020-09-25 09:36:39 -07:00
}
if ( eventCallback instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( eventCallback . attachOnChange (( oldValue , newValue ) => {
2020-09-25 09:36:39 -07:00
//Create a new wrapped function to check for the enter key being pressed.
var wrapped = ( e ) => {
if ( e . key === 'Backspace' ) {
newValue ( e );
}
};
eventCallback . _value = wrapped ; //Store the wrapped function into the property so we can remove it later
this . onEventChanged ( oldValue , wrapped , eventName ); //Invoke event changed with the old value and wrapped one.
}));
//Create the initial wrapper
var target = eventCallback . _value ;
var wrapped = ( e ) => {
if ( e . key === 'Backspace' ) {
target ( e );
}
};
//Store the wrapped so that it's the old value next time around.
eventCallback . _value = wrapped ;
2020-10-26 15:30:11 -07:00
this . _events [ eventName ]. push ( wrapped );
2020-09-25 09:36:39 -07:00
} else {
this . on ( eventName , ( e ) => {
if ( e . key === 'Backspace' ) {
eventCallback ( e );
}
});
}
return this ;
}
2021-01-09 16:24:24 -08:00
/**
* Adds a special on resize event handler to this template that will
2021-05-04 14:13:08 -07:00
* fire anytime the element is resized by using a resize observer. You can call this more than once to attach more than one callback.
* @param {Function|IgniteProperty} callback The callback function to be invoked by the event once it fires.
2021-01-09 16:24:24 -08:00
* @returns This ignite template so function calls can be chained.
*/
2021-05-04 14:13:08 -07:00
onResize ( callback ) {
2021-01-09 16:24:24 -08:00
IgniteRenderingContext . push ();
2021-05-04 14:13:08 -07:00
if ( callback instanceof IgniteProperty ) {
this . _resizeObserverCallback . push ( callback . value );
} else if ( callback instanceof Function ) {
this . _resizeObserverCallback . push ( callback );
}
IgniteRenderingContext . pop ();
return this ;
}
/**
* Adds a special on intersect event handler to this template that will fire
* once the element is in view. You can call this more than once to attach more than one callback.
* @param {Function|IgniteProperty} callback The callback function to be invoked by the event once it fires.
* @returns This ignite template so function calls can be chained.
*/
onIntersect ( callback ) {
IgniteRenderingContext . push ();
if ( callback instanceof IgniteProperty ) {
this . _intersectObserverCallback . push ( callback . value );
} else if ( callback instanceof Function ) {
this . _intersectObserverCallback . push ( callback );
2021-01-09 16:24:24 -08:00
}
IgniteRenderingContext . pop ();
return this ;
}
2020-08-11 12:53:57 -07:00
/**
2020-08-30 21:55:21 -07:00
* Adds a CSS property to this template with a value and priority.
* @param {String} name The name of the CSS property to set.
* @param {String|IgniteProperty} value The value to set for the property. If an IgniteProperty is used it will auto update this style.
2020-09-25 09:36:39 -07:00
* @param {String} priority If set to "important" then the style will be marked with !important. Acceptable values: important, !important, true, false, null
2020-08-30 21:55:21 -07:00
* @param {Function} converter Optional function to convert the value if needed.
* @returns This ignite template so function calls can be chained.
2020-08-11 12:53:57 -07:00
*/
2020-08-23 22:27:12 -07:00
style ( name , value , priority = null , converter = null ) {
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . push ();
//If the name has a : remove it.
if ( name && typeof name === "string" && name . includes ( ":" )) {
name = name . replace ( ":" , "" );
}
//If the priority starts with a ! remove it.
if ( priority && typeof priority === "string" && priority . trim (). startsWith ( "!" )) {
priority = priority . split ( "!" )[ 1 ]. trim ();
} else if ( priority && typeof priority === "boolean" ) {
priority = "important" ; //If priority is true, set it to important
} else if ( ! priority && typeof priority === "boolean" ) {
priority = null ; //If priority is false, set it to null.
}
//If the value has a ; remove it.
if ( value && typeof value === "string" && value . includes ( ";" )) {
value = value . replace ( ";" , "" );
}
2020-08-11 12:53:57 -07:00
if ( value instanceof IgniteProperty ) {
2021-11-09 21:11:41 -08:00
this . _callbacks . push ( value . attachOnChange (( oldValue , newValue ) => this . onStyleChanged ( name , converter ? converter ( newValue ) : newValue )));
this . _callbacks . push ( value . attachOnPush (( list , items ) => this . onStyleChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnUnshift (( list , items ) => this . onStyleChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnPop (( list ) => this . onStyleChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnShift (( list ) => this . onStyleChanged ( name , converter ? converter ( list ) : null )));
this . _callbacks . push ( value . attachOnSplice (( list , start , deleteCount , items ) => this . onStyleChanged ( name , converter ? converter ( list ) : null )));
this . _styles [ name ] = { name : name , value : converter ? converter ( value . value ) : value . value , priority : priority };
2020-09-25 09:36:39 -07:00
} else if ( Array . isArray ( value ) && value . length > 0 && value [ 0 ] instanceof IgniteProperty ) {
//There must be a converter for this to work correctly
if ( ! converter ) {
2020-09-29 14:28:27 -07:00
throw "Cannot pass an array of properties without using a converter!" ;
2020-09-25 09:36:39 -07:00
}
//Attack a callback for all the properties
value . forEach ( prop => {
2020-10-20 13:18:26 -07:00
if ( prop instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( prop . attachOnChange (( oldValue , newValue ) => this . onStyleChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPush (( list , items ) => this . onStyleChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnUnshift (( list , items ) => this . onStyleChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPop (( list ) => this . onStyleChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnShift (( list ) => this . onStyleChanged ( name , converter (... value . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnSplice (( list , start , deleteCount , items ) => this . onStyleChanged ( name , converter (... value . getPropertyValues ()))));
2020-10-20 13:18:26 -07:00
}
2020-09-25 09:36:39 -07:00
});
2020-10-26 15:30:11 -07:00
this . _styles [ name ] = { name : name , value : converter (... value . getPropertyValues ()), priority : priority };
2020-08-11 12:53:57 -07:00
} else {
2020-10-26 15:30:11 -07:00
this . _styles [ name ] = { name : name , value : ( converter != null ? converter ( value ) : value ), priority : priority };
2020-08-11 12:53:57 -07:00
}
2020-09-25 09:36:39 -07:00
IgniteRenderingContext . pop ();
2020-08-11 12:53:57 -07:00
return this ;
}
2020-09-25 09:36:39 -07:00
/**
* Hides the element this template is constructing if the value is true.
2020-10-20 13:18:26 -07:00
* @param {Boolean|IgniteProperty} value If true hides the element this template is constructing. If an IgniteProperty is passed it's value will auto update this.
2020-09-25 09:36:39 -07:00
* @param {Function} converter An optional function to convert the value if needed.
2021-03-16 22:26:33 -07:00
* @returns This ignite template so function calls can be chained.
2020-09-25 09:36:39 -07:00
*/
hide ( value , converter = null ) {
return this . style ( "display" , value , true , (... params ) => {
return (( converter != null && converter (... params )) || ( converter == null && params [ 0 ])) ? "none" : null ;
});
}
2021-08-18 10:16:58 -07:00
/**
* Hides the element this template is constructing if the value is true.
* @param {Boolean|IgniteProperty} value If true hides the element this template is constructing. If an IgniteProperty is passed it's value will auto update this.
* @param {Function} converter An optional function to convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
invisible ( value , converter = null ) {
return this . style ( "visibility" , value , true , (... params ) => {
return (( converter != null && converter (... params )) || ( converter == null && params [ 0 ])) ? "hidden" : null ;
});
}
2020-10-20 13:18:26 -07:00
/**
* Shows the element this template is constructing if the value is true.
* @param {Boolean|IgniteProperty} value
* @param {Function} converter
2021-03-16 22:26:33 -07:00
* @returns This ignite template so function calls can be chained.
2020-10-20 13:18:26 -07:00
*/
show ( value , converter = null ) {
return this . style ( "display" , value , true , (... params ) => {
return (( converter != null && converter (... params )) || ( converter == null && params [ 0 ])) ? null : "none" ;
});
}
2021-08-18 10:16:58 -07:00
/**
* Shows the element this template is constructing if the value is true.
* @param {Boolean|IgniteProperty} value
* @param {Function} converter
* @returns This ignite template so function calls can be chained.
*/
visibile ( value , converter = null ) {
return this . style ( "visibility" , value , true , (... params ) => {
return (( converter != null && converter (... params )) || ( converter == null && params [ 0 ])) ? null : "visible" ;
});
}
2020-08-31 22:11:19 -07:00
/**
* Sets the id attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the id attribute of the element this template will construct.
* @param {Function} converter An optional function that can convert the value if needed.
2020-09-01 08:50:11 -07:00
* @returns This ignite template so function calls can be chained.
2020-08-31 22:11:19 -07:00
*/
id ( value , converter = null ) {
return this . attribute ( "id" , value , converter );
}
2021-03-16 22:26:33 -07:00
/**
* Sets the title attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the title attribute of the element this template will construct.
* @param {Function} converter An optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
title ( value , converter = null ) {
return this . attribute ( "title" , value , converter );
}
2021-01-05 10:29:14 -08:00
/**
* Sets the for attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the for attribute of the element this template will construct.
* @param {Function} converter An optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
for ( value , converter = null ) {
return this . attribute ( "for" , value , converter );
}
/**
* Adds a checked attribute to this template.
* @param {Boolean|IgniteProperty} value The value to set for the checked attribute.
* @param {*} converter Optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
checked ( value , converter = null ) {
return this . attribute ( "checked" , value , converter );
}
2021-02-03 10:00:26 -08:00
/**
* Adds a disabled attribute and class to this template.
* @param {Boolean|IgniteProperty} value A value to determine whether or not the element should be marked as disable dor not.
* @param {*} converter Optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
disabled ( value , converter = null ) {
if ( value instanceof IgniteProperty ) {
this . attribute ( "disabled" , value , convert => {
convert = ( converter != null ? converter ( convert ) : convert );
if ( convert ) {
return "disabled" ;
} else {
return null ;
}
});
this . class ( value , convert => {
convert = ( converter != null ? converter ( convert ) : convert );
if ( convert ) {
return "disabled" ;
} else {
return null ;
}
});
} else if ( value ) {
this . attribute ( "disabled" , "disabled" );
this . class ( "disabled" );
}
return this ;
}
2020-08-31 22:11:19 -07:00
/**
* Sets the type attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the type attribute of the element this template will construct.
* @param {Function} converter An optional function that can convert the value if needed.
2020-09-01 08:50:11 -07:00
* @returns This ignite template so function calls can be chained.
2020-08-31 22:11:19 -07:00
*/
type ( value , converter = null ) {
return this . attribute ( "type" , value , converter );
}
2020-09-25 09:36:39 -07:00
/**
* Sets a data attribute on the element to be constructed by this template.
* @param {String} name The name of the data attribute to set on the element this template will construct.
* @param {String|IgniteProperty} value The value to set for the data attribute of the element this template will construct.
* @param {*} converter An optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
data ( name , value , converter = null ) {
return this . attribute ( `data- ${ name } ` , value , converter );
}
2020-08-31 22:11:19 -07:00
/**
2021-09-22 09:43:18 -07:00
* Sets the src attribute of the element to be constructed by this template.
2020-08-31 22:11:19 -07:00
* @param {String|IgniteProperty} value The value to set for the src attribute of the element to be constructed by this template.
* @param {Function} converter An optional function that can convert the value if needed.
2020-09-01 08:50:11 -07:00
* @returns This ignite template so function calls can be chained.
2020-08-31 22:11:19 -07:00
*/
src ( value , converter = null ) {
return this . attribute ( "src" , value , converter );
}
2020-09-09 08:24:18 -07:00
/**
2021-09-22 09:43:18 -07:00
* Sets the href attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the href attribute of the element to be constructed by this template.
2020-09-09 08:24:18 -07:00
* @param {Function} converter An optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
href ( value , converter = null ) {
return this . attribute ( "href" , value , converter );
}
2021-09-22 09:43:18 -07:00
/**
* Sets the target attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the target attribute of the element to be constructed by this template.
* @param {Function} converter An optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
target ( value , converter = null ) {
return this . attribute ( "target" , value , converter );
}
2020-08-31 22:11:19 -07:00
/**
* Sets the name attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the name attribute of the element to be constructed by this template.
* @param {Function} converter An optional function that can convert the value if needed.
2020-09-01 08:50:11 -07:00
* @returns This ignite template so function calls can be chained.
2020-08-31 22:11:19 -07:00
*/
name ( value , converter = null ) {
return this . attribute ( "name" , value , converter );
}
2020-09-01 08:50:11 -07:00
/**
* Sets the placeholder attribute of the element to be constructed by this template.
* @param {String|IgniteProperty} value The value to set for the placeholder attribute of the element.
* @param {Function} converter An optional function that can convert the value if needed.
* @returns This ignite template so function calls can be chained.
*/
placeholder ( value , converter = null ) {
2021-10-26 00:14:30 -07:00
//If this is a input element, modify the attribute, otherwise add the placeholder class.
if ( this . tagName == "input" ) {
return this . attribute ( "placeholder" , value , converter );
} else {
if ( value instanceof IgniteProperty ) {
return this . class ( value , convert => {
convert = ( converter != null ? converter ( convert ) : convert );
if ( convert ) {
return "placeholder" ;
} else {
return null ;
}
});
} else {
return this . class ( "placeholder" );
}
}
2020-09-01 08:50:11 -07:00
}
2020-07-28 22:23:49 -07:00
/**
* Constructs this template and adds it to the DOM if this template
* has not already been constructed.
2020-08-30 21:55:21 -07:00
* @param {HTMLElement} parent Parent element that will contain the constructed element.
* @param {HTMLElement} sibling Optional sibling element that can be used to add the element adjacantly.
2020-07-28 22:23:49 -07:00
*/
construct ( parent , sibling ) {
2020-07-29 11:21:02 -07:00
//Don't construct if we have no parent, no sibling and no element.
if ( ! parent && ! sibling && ! this . element ) {
return ;
}
2020-07-28 09:04:04 -07:00
//Construct this element if we haven't already
if ( ! this . element ) {
2020-12-09 20:41:11 -08:00
//If we have a tag namespace use that to construct this element. This is mainly
//for svg elements since they have to be created this way.
if ( this . tagNamespace ) {
this . element = window . document . createElementNS ( this . tagNamespace , this . tagName );
} else {
this . element = window . document . createElement ( this . tagName );
}
2020-07-28 22:23:49 -07:00
2020-08-23 11:50:31 -07:00
//Pass back our template to the element we are creating if it's not a ignite element, since
//it will have it's own template automatically.
if ( ! ( this . element instanceof IgniteElement )) {
this . element . template = this ;
}
2020-07-28 22:23:49 -07:00
2020-08-23 11:50:31 -07:00
//Invoke any refs we have and pass back the element reference.
2020-10-26 15:30:11 -07:00
this . _refs . forEach (( ref ) => ref ( this . element ));
2020-07-28 09:04:04 -07:00
}
//Set the classes on this element
2020-10-26 15:30:11 -07:00
for ( var i = 0 ; i < this . _classes . length ; i ++ ) {
if ( this . _classes [ i ] !== null && this . _classes [ i ] !== undefined && this . _classes [ i ] !== "" ) {
this . element . classList . add ( this . _classes [ i ]);
2020-07-28 09:04:04 -07:00
}
}
//Set the attributes on this element
2020-10-26 15:30:11 -07:00
var keys = Object . keys ( this . _attributes );
2020-07-28 09:04:04 -07:00
for ( var i = 0 ; i < keys . length ; i ++ ) {
2020-10-26 15:30:11 -07:00
if ( this . _attributes [ keys [ i ]] !== null && this . _attributes [ keys [ i ]] !== undefined ) {
this . element . setAttribute ( keys [ i ], this . _attributes [ keys [ i ]]);
2020-07-28 09:04:04 -07:00
}
}
2020-07-30 08:32:44 -07:00
//Set the events on this element
2020-10-26 15:30:11 -07:00
var keys = Object . keys ( this . _events );
2020-07-30 08:32:44 -07:00
for ( var i = 0 ; i < keys . length ; i ++ ) {
2020-10-26 15:30:11 -07:00
this . _events [ keys [ i ]]. forEach (( event ) => {
2020-07-30 09:58:47 -07:00
if ( event !== null && event !== undefined ) {
this . element . addEventListener ( keys [ i ], event );
}
});
2020-07-30 08:32:44 -07:00
}
2020-08-11 12:53:57 -07:00
//Set the styles on this element.
2020-10-26 15:30:11 -07:00
var keys = Object . keys ( this . _styles );
2020-08-11 12:53:57 -07:00
for ( var i = 0 ; i < keys . length ; i ++ ) {
2020-10-26 15:30:11 -07:00
var style = this . _styles [ keys [ i ]];
2020-08-11 12:53:57 -07:00
this . element . style . setProperty ( style . name , style . value , style . priority );
}
2020-07-28 09:04:04 -07:00
//Set the properties on this element
2020-10-26 15:30:11 -07:00
var keys = Object . keys ( this . _properties );
2020-07-28 09:04:04 -07:00
for ( var i = 0 ; i < keys . length ; i ++ ) {
2020-10-26 15:30:11 -07:00
this . element [ keys [ i ]] = this . _properties [ keys [ i ]]. value ;
2020-08-23 11:50:31 -07:00
2021-05-25 22:27:23 -07:00
//Reflect the property if it can be on the element.
if ( this . _properties [ keys [ i ]]. reflect != null && this . element [ keys [ i ]] instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . element [ keys [ i ]]. reflected . push ( this . _properties [ keys [ i ]]. reflect );
2020-08-23 11:50:31 -07:00
}
2020-07-28 09:04:04 -07:00
}
2021-03-28 23:23:58 -07:00
//Set the variables on this element.
var keys = Object . keys ( this . _variables );
for ( var i = 0 ; i < keys . length ; i ++ ) {
this . element [ keys [ i ]] = this . _variables [ keys [ i ]]. value ;
}
2021-01-09 16:24:24 -08:00
//Setup any reflecting properties on this element
var keys = Object . keys ( this . _reflecting );
for ( var i = 0 ; i < keys . length ; i ++ ) {
this . _reflecting [ keys [ i ]]. forEach ( value => this . element [ keys [ i ]]. reflected . push ( value ));
}
2020-09-25 09:36:39 -07:00
//Set the elements inner html if it was set
2020-10-26 15:30:11 -07:00
if ( this . _elementInnerHTML != null ) {
this . element . innerHTML = this . _elementInnerHTML ;
2020-09-25 09:36:39 -07:00
}
2021-10-06 08:08:02 -07:00
//Set the elements inner text if it was set
if ( this . _elementInnerText != null ) {
this . element . innerText = this . _elementInnerText ;
}
2020-07-28 09:04:04 -07:00
//Construct the children under this element
for ( var i = 0 ; i < this . children . length ; i ++ ) {
2020-07-29 14:01:41 -07:00
this . children [ i ]. construct ( this . element );
2020-07-28 09:04:04 -07:00
}
2020-07-29 11:21:02 -07:00
2020-09-28 09:02:57 -07:00
//Set the elements value if there is one.
2020-10-26 15:30:11 -07:00
if ( this . _elementValue != null ) {
2021-03-09 13:06:29 -08:00
if ( this . element . hasAttribute ( "type" ) && ( this . element . getAttribute ( "type" ). toLowerCase (). trim () == "checkbox" || this . element . getAttribute ( "type" ). toLowerCase (). trim () == "radio" )) {
2020-10-26 15:30:11 -07:00
this . element . checked = this . _elementValue ;
} else if ( this . element . hasAttribute ( "contenteditable" ) && this . element . getAttribute ( "contenteditable" ). toLowerCase (). trim () == "true" ) {
this . element . textContent = this . _elementValue . toString ();
2020-09-28 09:02:57 -07:00
} else {
2020-10-26 15:30:11 -07:00
this . element . value = this . _elementValue ;
2020-09-28 09:02:57 -07:00
}
}
2021-01-09 16:24:24 -08:00
//Setup a resize observer if needed
2021-05-04 14:13:08 -07:00
if ( this . _resizeObserverCallback && this . _resizeObserverCallback . length > 0 ) {
this . _resizeObserver = new ResizeObserver ( e => {
this . _resizeObserverCallback . forEach ( callback => callback ( e ));
});
2021-01-09 16:24:24 -08:00
this . _resizeObserver . observe ( this . element );
}
2021-05-04 14:13:08 -07:00
//Setup a intersect observer if needed
if ( this . _intersectObserverCallback && this . _intersectObserverCallback . length > 0 ) {
this . _intersectObserver = new IntersectionObserver ( results => {
if ( results [ 0 ]. isIntersecting ) {
this . _intersectObserverCallback . forEach ( callback => callback ( results [ 0 ]));
}
2021-05-04 22:15:31 -07:00
}, { root : null , trackVisibility : true , delay : 1000 });
2021-05-04 14:13:08 -07:00
this . _intersectObserver . observe ( this . element );
}
//Invoke any custom constructors.
this . _constructors . forEach ( c => c ( parent , sibling ));
2020-07-29 11:21:02 -07:00
//If our element has not been added to the dom yet, then add it.
if ( this . element . isConnected == false && this . element . parentElement == null ) {
if ( sibling ) {
parent . insertBefore ( this . element , sibling );
} else {
parent . appendChild ( this . element );
}
}
2020-07-28 09:04:04 -07:00
}
2020-07-28 22:23:49 -07:00
/**
* Deconstructs this template and cleans up all resources to make sure
* there are no memory leaks.
*/
deconstruct () {
2020-07-30 08:32:44 -07:00
//Remove and disconnect all events
2020-10-26 15:30:11 -07:00
if ( this . element && this . _events ) {
var keys = Object . keys ( this . _events );
2020-07-30 08:32:44 -07:00
for ( var i = 0 ; i < keys . length ; i ++ ) {
2020-10-26 15:30:11 -07:00
this . element . removeEventListener ( keys [ i ], this . _events [ keys [ i ]]);
2020-07-30 08:32:44 -07:00
}
2020-10-26 15:30:11 -07:00
this . _events = null ;
2020-07-30 08:32:44 -07:00
}
2020-07-28 22:23:49 -07:00
//Remove our element if we have one.
if ( this . element ) {
this . element . remove ();
this . element = null ;
}
//Deconstruct all children elements.
if ( this . children ) {
for ( var i = 0 ; i < this . children . length ; i ++ ) {
if ( this . children [ i ] instanceof IgniteTemplate || this . children [ i ]. prototype instanceof IgniteTemplate ) {
this . children [ i ]. deconstruct ();
}
}
this . children = null ;
}
2020-07-29 12:24:36 -07:00
//Disconnect all callbacks
2020-10-26 15:30:11 -07:00
if ( this . _callbacks ) {
this . _callbacks . forEach (( item ) => item . disconnect ());
this . _callbacks = null ;
2020-07-28 22:23:49 -07:00
}
2021-01-09 16:24:24 -08:00
//Stop observing resize events if we need to.
2021-05-04 14:13:08 -07:00
if ( this . _resizeObserver ) {
2021-01-09 16:24:24 -08:00
this . _resizeObserver . disconnect ();
this . _resizeObserver = null ;
this . _resizeObserverCallback = null ;
}
2021-05-04 14:13:08 -07:00
//Stop observing intersects if we need to.
if ( this . _intersectObserver ) {
this . _intersectObserver . disconnect ();
this . _intersectObserver = null ;
this . _intersectObserverCallback = null ;
}
2020-07-29 12:24:36 -07:00
//Remove any refs
2020-10-26 15:30:11 -07:00
if ( this . _refs ) {
2020-09-25 09:36:39 -07:00
//Pass null to our refs so that the reference is updated.
2020-10-26 15:30:11 -07:00
this . _refs . forEach ( ref => ref ( null ));
this . _refs = null ;
2020-07-28 22:23:49 -07:00
}
2021-05-04 14:13:08 -07:00
//Invoke any custom destructors
if ( this . _destructors ) {
this . _destructors . forEach ( d => d ());
this . _destructors = null ;
}
2020-07-28 22:23:49 -07:00
}
/**
* Called when a class on this template was changed and needs to be updated
* on the template's element.
* @param {any} oldValue
* @param {any} newValue
2020-09-09 08:24:18 -07:00
* @param {Function} converter Optional converter for the value if needed.
2020-08-30 21:55:21 -07:00
* @ignore
2020-07-28 22:23:49 -07:00
*/
2020-09-29 14:28:27 -07:00
onClassChanged ( oldValue , newValue ) {
2020-09-09 08:24:18 -07:00
var oldClasses = ( oldValue != null && oldValue != "" ? oldValue . toString (). split ( " " ) : []);
var newClasses = ( newValue != null && newValue != "" ? newValue . toString (). split ( " " ) : []);
2020-08-31 22:11:19 -07:00
2020-07-29 11:21:02 -07:00
if ( this . element ) {
2020-09-09 08:24:18 -07:00
oldClasses . forEach (( cl ) => this . element . classList . remove ( cl ));
newClasses . forEach (( cl ) => this . element . classList . add ( cl ));
2020-07-28 09:04:04 -07:00
}
2020-07-29 11:21:02 -07:00
2020-08-31 22:11:19 -07:00
//Remove the old values from the template, but only remove one copy.
2020-10-26 15:30:11 -07:00
oldClasses . forEach (( cl ) => this . _classes . splice ( this . _classes . indexOf ( cl ), 1 ));
2020-07-30 10:11:09 -07:00
2020-08-31 22:11:19 -07:00
//Add the new classes to the template.
2020-10-26 15:30:11 -07:00
newClasses . forEach (( cl ) => this . _classes . push ( cl ));
2020-08-31 22:11:19 -07:00
//For any classes that are missing on the element, add them. If we have duplicates this
//can happen.
2020-10-26 15:30:11 -07:00
this . _classes . forEach (( cl ) => {
2020-08-31 22:11:19 -07:00
if ( ! this . element . classList . contains ( cl )) {
this . element . classList . add ( cl );
}
});
2020-07-28 09:04:04 -07:00
}
2020-07-28 22:23:49 -07:00
/**
* Called when a attribute on this template was changed and needs to be updated
* on the template's element.
2021-10-13 07:46:40 -07:00
* @param {string} name
2020-07-28 22:23:49 -07:00
* @param {any} newValue
2020-08-30 21:55:21 -07:00
* @ignore
2020-07-28 22:23:49 -07:00
*/
2021-10-13 07:46:40 -07:00
onAttributeChanged ( name , newValue ) {
2020-07-29 11:21:02 -07:00
if ( this . element ) {
if ( newValue == null || newValue == undefined ) {
2021-10-13 07:46:40 -07:00
this . element . removeAttribute ( name );
2020-07-29 11:21:02 -07:00
} else {
2021-10-13 07:46:40 -07:00
this . element . setAttribute ( name , newValue );
2020-07-29 11:21:02 -07:00
}
2020-07-28 09:04:04 -07:00
}
2020-07-29 11:21:02 -07:00
2021-10-13 07:46:40 -07:00
this . _attributes [ name ] = newValue ;
2020-07-28 09:04:04 -07:00
}
2020-08-31 22:11:19 -07:00
/**
* Called when a value for this template was changed and needs to be updated on the template's element.
* @param {any} newValue
* @ignore
*/
2021-03-09 13:06:29 -08:00
onValueChanged ( newValue ) {
2020-08-31 22:11:19 -07:00
//Only update the elements value if it actually changed.
//This is to prevent endless looping potentially.
if ( this . element ) {
2021-03-09 13:06:29 -08:00
if ( this . element . hasAttribute ( "type" ) && ( this . element . getAttribute ( "type" ). toLowerCase (). trim () == "checkbox" || this . element . getAttribute ( "type" ). toLowerCase (). trim () == "radio" )) {
2020-08-31 22:11:19 -07:00
if ( this . element . checked != newValue ) {
this . element . checked = newValue ;
}
2020-10-26 15:30:11 -07:00
} else if ( this . element . hasAttribute ( "contenteditable" ) && this . element . getAttribute ( "contenteditable" ). toLowerCase (). trim () == "true" ) {
if ( this . element . textContent != newValue . toString ()) {
this . element . textContent = newValue . toString ();
}
2020-08-31 22:11:19 -07:00
} else {
if ( this . element . value != newValue ) {
this . element . value = newValue ;
}
}
}
2020-10-26 15:30:11 -07:00
this . _elementValue = newValue ;
2020-08-31 22:11:19 -07:00
}
2020-07-28 22:23:49 -07:00
/**
* Called when a property on this template was changed and needs to be updated
* on the template's element.
* @param {string} propertyName
2021-02-12 18:53:09 -08:00
* @param {any} newValue
2020-08-30 21:55:21 -07:00
* @ignore
2020-07-28 22:23:49 -07:00
*/
2021-02-12 18:53:09 -08:00
onPropertyChanged ( propertyName , newValue ) {
2020-07-29 11:21:02 -07:00
if ( this . element ) {
2020-08-23 11:50:31 -07:00
//Use the set value function and don't reflect the change because it came from above which
//would be the reflected property, this reduces some functions being called twice that don't need to be.
2021-05-25 22:27:23 -07:00
IgniteRenderingContext . enter ();
if ( this . element [ propertyName ] instanceof IgniteProperty ) {
this . element [ propertyName ]. setValue ( newValue , false );
} else {
this . element [ propertyName ] = newValue ;
}
IgniteRenderingContext . leave ();
2020-07-29 11:21:02 -07:00
}
2020-10-26 15:30:11 -07:00
this . _properties [ propertyName ]. value = newValue ;
2020-07-28 09:04:04 -07:00
}
2020-07-29 12:24:36 -07:00
2021-03-28 23:23:58 -07:00
/**
* Called when a variable on this template was changed and needs to be updated.
* @param {string} variableName
* @param {any} newValue
* @ignore
*/
onVariableChanged ( variableName , newValue ) {
if ( this . element ) {
this . element [ variableName ] = newValue ;
}
this . _variables [ variableName ]. value = newValue ;
}
2020-09-25 09:36:39 -07:00
/**
* Called when the inner html for this template was changed and needs to be updated
* on the template's element.
* @param {any} newValue
* @ignore
*/
2021-10-06 08:08:02 -07:00
onInnerHTMLChanged ( newValue ) {
2020-09-25 09:36:39 -07:00
if ( this . element ) {
this . element . innerHTML = newValue ;
}
2020-10-26 15:30:11 -07:00
this . _elementInnerHTML = newValue ;
2020-09-25 09:36:39 -07:00
}
2021-10-06 08:08:02 -07:00
/**
* Called when the inner text for this template was changed and needs to be updated
* on the template's element.
* @param {any} newValue
* @ignore
*/
onInnerTextChanged ( newValue ) {
if ( this . element ) {
this . element . innerText = newValue ;
}
this . _elementInnerText = newValue ;
}
2020-07-29 12:24:36 -07:00
/**
* Called when a ref was changed and we need to update the refs
* value to match this elements reference.
* @param {any} ref
2021-10-13 07:46:40 -07:00
* @param {any} newValue
2020-08-30 21:55:21 -07:00
* @ignore
2020-07-29 12:24:36 -07:00
*/
2021-10-13 07:46:40 -07:00
onRefChanged ( ref , newValue ) {
2020-07-29 12:24:36 -07:00
//Only set the reference value to ourself if it's not our element.
//Otherwise we will get a never ending loop.
if ( this . element != newValue ) {
ref . value = this . element ;
}
}
2020-07-30 08:32:44 -07:00
/**
* Called when a event was changed and we need to update it.
* @param {any} oldValue
* @param {any} newValue
* @param {any} eventName
2020-08-30 21:55:21 -07:00
* @ignore
2020-07-30 08:32:44 -07:00
*/
onEventChanged ( oldValue , newValue , eventName ) {
if ( this . element ) {
if ( oldValue !== null && oldValue !== undefined ) {
this . element . removeEventListener ( eventName , oldValue );
}
if ( newValue !== null && newValue !== undefined ) {
this . element . addEventListener ( eventName , newValue );
}
2020-07-30 09:58:47 -07:00
//Remove the old value from the events
2020-10-26 15:30:11 -07:00
this . _events [ eventName ] = this . _events [ eventName ]. filter ( ev => ev != oldValue );
2020-07-30 10:11:09 -07:00
//Add the new value if it's needed
if ( newValue !== null && newValue !== undefined ) {
2020-10-26 15:30:11 -07:00
this . _events [ eventName ]. push ( newValue );
2020-07-30 10:11:09 -07:00
}
2020-07-30 08:32:44 -07:00
}
}
2020-08-11 12:53:57 -07:00
/**
* Called when a css value was changed and we need to update the styling.
2020-09-25 09:36:39 -07:00
* @param {String} name
2020-08-11 12:53:57 -07:00
* @param {any} newValue
2020-08-30 21:55:21 -07:00
* @ignore
2020-08-11 12:53:57 -07:00
*/
2020-09-25 09:36:39 -07:00
onStyleChanged ( name , newValue ) {
//Remove the ; from the value if there is one.
if ( newValue && typeof newValue === "string" && newValue . includes ( ";" )) {
newValue = newValue . replace ( ";" , "" );
2020-09-09 08:24:18 -07:00
}
2020-08-11 12:53:57 -07:00
if ( this . element ) {
2020-10-26 15:30:11 -07:00
this . element . style . setProperty ( name , newValue , this . _styles [ name ]. priority );
2020-08-11 12:53:57 -07:00
}
2020-08-23 22:27:12 -07:00
2020-10-26 15:30:11 -07:00
this . _styles [ name ]. value = newValue ;
2020-08-11 12:53:57 -07:00
}
2020-07-28 09:04:04 -07:00
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a div element.
*/
2020-07-28 09:04:04 -07:00
class div extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "div" , children );
2020-07-28 09:04:04 -07:00
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a hyperlink element.
*/
2020-07-28 09:04:04 -07:00
class a extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "a" , children );
2020-07-28 09:04:04 -07:00
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a input element.
*/
2020-08-21 22:13:06 -07:00
class input extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "input" , children );
}
}
2020-08-21 22:13:06 -07:00
2020-09-29 14:28:27 -07:00
/**
* An ignite template that can be used to construct a textarea element.
*/
class textarea extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "textarea" , children );
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a button element.
*/
class button extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "button" , children );
2020-09-25 09:36:39 -07:00
this . type ( "button" );
2020-08-21 22:13:06 -07:00
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a h1 element.
*/
2020-08-23 11:50:31 -07:00
class h1 extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "h1" , children );
2020-08-23 11:50:31 -07:00
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a h2 element.
*/
2020-08-23 11:50:31 -07:00
class h2 extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "h2" , children );
2020-08-23 11:50:31 -07:00
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a h3 element.
*/
2020-08-23 11:50:31 -07:00
class h3 extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "h3" , children );
2020-08-23 11:50:31 -07:00
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a h4 element.
*/
2020-08-23 11:50:31 -07:00
class h4 extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "h4" , children );
2020-08-23 11:50:31 -07:00
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a h5 element.
*/
2020-08-23 11:50:31 -07:00
class h5 extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "h5" , children );
2020-08-23 11:50:31 -07:00
}
}
2020-09-25 09:36:39 -07:00
/**
* An ignite template that can be used to construct a h6 element.
*/
class h6 extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "h6" , children );
}
}
2020-09-28 09:02:57 -07:00
/**
* An ignite template that can be used to construct a hr element.
*/
class hr extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "hr" , children );
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a p element.
*/
2020-08-23 11:50:31 -07:00
class p extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "p" , children );
2020-08-23 11:50:31 -07:00
}
}
2020-09-09 08:24:18 -07:00
/**
* An ignite template that can be used to construct a ul element.
*/
class ul extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "ul" , children );
}
}
/**
* An ignite template that can be used to construct a li element.
*/
class li extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "li" , children );
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a span element.
*/
2020-08-23 11:50:31 -07:00
class span extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "span" , children );
2020-08-23 11:50:31 -07:00
}
}
2021-07-28 08:38:33 -07:00
/**
* An ignite template that can be used to construct a small element.
*/
2021-08-04 10:03:20 -07:00
class small extends IgniteTemplate {
2021-07-28 08:38:33 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "small" , children );
}
}
2021-03-10 08:56:14 -08:00
/**
* An ignite template that can be used to construct a strong element.
*/
class strong extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "strong" , children );
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct an i element.
*/
2020-08-23 11:50:31 -07:00
class i extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "i" , children );
}
}
2020-12-09 20:41:11 -08:00
/**
* An ignite template that can be used to construct a table element.
*/
class table extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "table" , children );
}
}
/**
* An ignite template that can be used to construct a td element.
*/
class td extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "td" , children );
}
}
/**
* An ignite template that can be used to construct a th element.
*/
class th extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "th" , children );
}
}
/**
* An ignite template that can be used to construct a tr element.
*/
class tr extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "tr" , children );
}
}
/**
* An ignite template that can be used to construct a thead element.
*/
class thead extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "thead" , children );
}
}
/**
* An ignite template that can be used to construct a tbody element.
*/
class tbody extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "tbody" , children );
}
}
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a br element.
*/
class br extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "br" , children );
}
}
2020-08-23 11:50:31 -07:00
2020-08-30 21:55:21 -07:00
/**
* An ignite template that can be used to construct a img element.
*/
class img extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "img" , children );
2020-08-23 11:50:31 -07:00
}
}
2020-08-31 22:11:19 -07:00
/**
* An ignite template that can be used to construct a label element.
*/
class label extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "label" , children );
}
}
2020-09-28 09:02:57 -07:00
/**
* An ignite template that can be used to construct a select element.
*/
class select extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "select" , children );
}
}
/**
* An ignite template that can be used to construct a option element.
*/
class option extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "option" , children );
}
}
/**
* An ignite template that can be used to construct a script element.
*/
class script extends IgniteTemplate {
/**
2020-12-09 20:41:11 -08:00
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
2020-09-28 09:02:57 -07:00
constructor (... children ) {
super ( "script" , children );
}
}
2021-01-05 10:29:14 -08:00
/**
* An ignite template that can be used to construct a form element.
*/
class form extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "form" , children );
}
}
2021-08-04 10:03:20 -07:00
/**
* An ignite template that can be used to construct a header element.
*/
class header extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "header" , children );
}
}
/**
* An ignite template that can be used to construct a footer element.
*/
class footer extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "footer" , children );
}
}
2020-12-09 20:41:11 -08:00
/**
* An ignite template that can be used to construct a progress element.
*/
class progress extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "progress" , children );
}
}
/**
* An ignite template that can be used to construct a svg element.
*/
class svg extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "svg" , children );
this . tagNamespace = "http://www.w3.org/2000/svg" ;
}
}
2021-01-06 23:42:55 -08:00
/**
* An ignite template that can be used to construct a g element.
*/
class g extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "g" , children );
this . tagNamespace = "http://www.w3.org/2000/svg" ;
}
}
/**
* An ignite template that can be used to construct a path element.
*/
class path extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "path" , children );
this . tagNamespace = "http://www.w3.org/2000/svg" ;
}
}
2020-12-09 20:41:11 -08:00
/**
* An ignite template that can be used to construct a circle element.
*/
class circle extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "circle" , children );
this . tagNamespace = "http://www.w3.org/2000/svg" ;
}
}
2021-01-08 02:22:29 -08:00
/**
* An ignite template that can be used to construct a line element.
*/
class line extends IgniteTemplate {
/**
* @param {...String|Number|IgniteProperty|IgniteTemplate} children A series of children to be added to this template.
*/
constructor (... children ) {
super ( "line" , children );
this . tagNamespace = "http://www.w3.org/2000/svg" ;
}
}
2021-10-06 08:08:02 -07:00
/**
* Text is a special template that will construct a text element and automatically update the dom
* if it's content changes.
* @example
* new text(`<script>Will show up as text</script>`)
*/
class text extends IgniteTemplate {
/**
* Constructs a text template with the text to render.
* @param {String|IgniteProperty} text The text to render within this text template.
* @param {Function} converter An optional function that can be used to convert the text.
*/
constructor ( text , converter ) {
super ();
if ( text instanceof IgniteProperty ) {
this . _callbacks . push ( text . attachOnChange (( oldValue , newValue ) => this . onTextChanged ( converter != null ? converter ( newValue ) : newValue )));
this . _callbacks . push ( text . attachOnPush (( list , items ) => this . onTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( text . attachOnUnshift (( list , items ) => this . onTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( text . attachOnPop (( list ) => this . onTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( text . attachOnShift (( list ) => this . onTextChanged ( converter != null ? converter ( list ) : null )));
this . _callbacks . push ( text . attachOnSplice (( list , start , deleteCount , items ) => this . onTextChanged ( converter != null ? converter ( list ) : null )));
this . _text = ( converter != null ? converter ( text . value ) : text . value );
} else if ( Array . isArray ( text ) && text . length > 0 && text [ 0 ] instanceof IgniteProperty ) {
//There must be a converter for this to work correctly
if ( ! converter ) {
throw "Cannot pass an array of properties without using a converter!" ;
}
//Attack a callback for all the properties
text . forEach ( prop => {
if ( prop instanceof IgniteProperty ) {
this . _callbacks . push ( prop . attachOnChange (( oldValue , newValue ) => this . onTextChanged ( converter (... text . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPush (( list , items ) => this . onTextChanged ( converter (... text . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnUnshift (( list , items ) => this . onTextChanged ( converter (... text . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPop (( list ) => this . onTextChanged ( converter (... text . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnShift (( list ) => this . onTextChanged ( converter (... text . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnSplice (( list , start , deleteCount , items ) => this . onTextChanged ( converter (... text . getPropertyValues ()))));
}
});
this . _text = converter (... text . getPropertyValues ());
} else {
this . _text = ( converter != null ? converter ( text ) : text );
}
}
construct ( parent , sibling ) {
//Don't construct if we have no parent, no sibling and no element.
if ( ! parent && ! sibling && ! this . element ) {
return ;
}
if ( ! this . element ) {
this . element = window . document . createTextNode ( "" );
if ( sibling ) {
sibling . parentElement . insertBefore ( this . element , sibling );
} else {
parent . appendChild ( this . element );
}
}
this . element . data = this . _text ;
}
onTextChanged ( newValue ) {
if ( this . element ) {
this . element . data = newValue ;
}
this . _text = newValue ;
}
}
2020-08-30 21:55:21 -07:00
/**
* Html is a special template that can construct raw html or properties into the dom and automatically
* update the dom if the property changes.
*
* @example
* new html(`<h1>Hello world!</h1>`)
*/
2020-07-28 09:04:04 -07:00
class html extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {String|IgniteProperty} code HTML code to be constructed within this template. If an IgniteProperty is passed it's value will be used.
*/
2020-07-28 09:04:04 -07:00
constructor ( code ) {
2020-08-30 21:55:21 -07:00
super ();
2020-07-29 14:01:41 -07:00
if ( code instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( code . attachOnChange (( oldValue , newValue ) => this . onPropertyChanged ( oldValue , newValue )));
2020-07-29 14:01:41 -07:00
this . code = code . value ;
} else {
this . code = code ;
}
2020-07-28 22:23:49 -07:00
this . tagName = "shadow html" ;
2020-07-29 11:21:02 -07:00
this . elements = [];
2020-07-28 09:04:04 -07:00
}
2020-07-29 11:21:02 -07:00
construct ( parent , sibling ) {
//Don't construct if we have no parent, no sibling and no element.
if ( ! parent && ! sibling && ! this . element ) {
return ;
2020-07-28 09:04:04 -07:00
}
2020-07-29 11:21:02 -07:00
if ( ! this . element ) {
this . element = window . document . createTextNode ( "" );
if ( sibling ) {
sibling . parentElement . insertBefore ( this . element , sibling );
} else {
parent . appendChild ( this . element );
}
}
2020-07-29 14:01:41 -07:00
//Create a template to hold the elements that will be created from the
//properties value and then add them to the DOM and store their pointer.
2020-11-09 09:38:00 -08:00
if ( this . elements . length == 0 && this . code !== null && this . code !== undefined ) {
2020-09-25 09:36:39 -07:00
//If the code is an ignite template then reder that template.
if ( this . code instanceof IgniteTemplate ) {
this . code . construct ( parent , this . element );
this . elements . push ( this . code . element );
} else {
var template = window . document . createElement ( "template" );
2020-11-09 09:38:00 -08:00
template . innerHTML = this . code . toString ();
2020-09-25 09:36:39 -07:00
while ( template . content . childNodes . length > 0 ) {
var item = template . content . childNodes [ 0 ];
this . element . parentElement . insertBefore ( item , this . element );
this . elements . push ( item );
}
template . remove ();
2020-07-29 11:21:02 -07:00
}
}
2020-07-28 09:04:04 -07:00
}
2020-07-29 14:01:41 -07:00
onPropertyChanged ( oldValue , newValue ) {
//Update our code to the new value from the property.
this . code = newValue ;
//Remove any elements that already exist.
this . elements . forEach (( item ) => item . remove ());
this . elements = [];
2020-08-21 21:42:10 -07:00
//Reconstruct the html
2020-07-29 14:01:41 -07:00
this . construct ( null , null );
}
2020-07-28 09:04:04 -07:00
}
2020-08-30 21:55:21 -07:00
/**
* A special ignite template that constructs a list of items using a template
* that is dynamically created for each item.
*
* @example
* new list(["1", "2", "3"], (item) => {
* return new h1(item);
* })
*/
2020-07-28 09:04:04 -07:00
class list extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
* @param {Array|IgniteProperty} list The list of items to construct within this template.
2021-10-26 00:14:30 -07:00
* @param {Function(item, index, count)} forEach A function that constructs a template foreach item.
2021-03-16 22:26:33 -07:00
* @param {Boolean} reflect If true any items removed from the DOM will be removed from the list if they exist. By default this is false.
2020-08-30 21:55:21 -07:00
*/
2021-03-16 22:26:33 -07:00
constructor ( list , forEach , reflect = false ) {
2020-08-30 21:55:21 -07:00
super ();
2020-07-28 09:04:04 -07:00
if ( list instanceof IgniteProperty ) {
2021-03-16 22:26:33 -07:00
this . _callbacks . push ( list . attachOnChange (( oldValue , newValue ) => this . onListChanged ( newValue )));
this . _callbacks . push ( list . attachOnPush (( list , items ) => this . onListPush ( items )));
this . _callbacks . push ( list . attachOnUnshift (( list , items ) => this . onListUnshift ( items )));
this . _callbacks . push ( list . attachOnPop ( list => this . onListPop ()));
this . _callbacks . push ( list . attachOnShift ( list => this . onListShift ()));
this . _callbacks . push ( list . attachOnSplice (( list , start , deleteCount , items ) => this . onListSplice ( start , deleteCount , items )));
2020-07-28 09:04:04 -07:00
this . list = list . value ;
} else {
this . list = list ;
}
2021-03-16 22:26:33 -07:00
this . reflecting = reflect ;
this . reflectCallbacks = [];
2020-07-28 09:04:04 -07:00
this . forEach = forEach ;
this . elements = [];
2020-08-30 21:55:21 -07:00
this . tagName = "shadow list" ;
2020-07-28 09:04:04 -07:00
}
2020-07-28 22:23:49 -07:00
construct ( parent , sibling ) {
2020-07-29 11:21:02 -07:00
//Don't construct if we have no parent, no sibling and no element.
if ( ! parent && ! sibling && ! this . element ) {
return ;
}
2020-07-28 09:04:04 -07:00
if ( ! this . element ) {
this . element = window . document . createTextNode ( "" ); //Use a textnode as our placeholder
2020-07-29 11:21:02 -07:00
if ( sibling ) {
sibling . parentElement . insertBefore ( this . element , sibling );
} else {
parent . appendChild ( this . element );
}
2020-07-28 22:23:49 -07:00
} else {
parent = this . element . parentElement ;
2020-07-28 09:04:04 -07:00
}
2021-03-16 22:26:33 -07:00
//If we have any reflect callbacks, remove them.
//(If we dont do this, we will accidentally remove items from the list potentially)
if ( this . reflectCallbacks . length > 0 ) {
for ( var i = 0 ; i < this . reflectCallbacks . length ; i ++ ) {
this . reflectCallbacks [ i ]. disconnect ();
}
this . reflectCallbacks = [];
}
2020-07-28 09:04:04 -07:00
//If we already have elements we created, destroy them.
if ( this . elements . length > 0 ) {
for ( var i = 0 ; i < this . elements . length ; i ++ ) {
this . elements [ i ]. remove ();
}
this . elements = [];
}
2020-07-28 22:23:49 -07:00
//If we already have children elements, deconstruct them.
//(Because we are about to recreate them)
if ( this . children . length > 0 ) {
for ( var i = 0 ; i < this . children . length ; i ++ ) {
this . children [ i ]. deconstruct ();
}
this . children = [];
}
2020-07-28 09:04:04 -07:00
//Construct all the items in our list and use the container
if ( this . list ) {
for ( var i = 0 ; i < this . list . length ; i ++ ) {
2021-10-26 00:14:30 -07:00
var template = this . forEach ( this . list [ i ], i , this . list . length );
2021-07-21 09:36:55 -07:00
if ( template ) {
template . construct ( parent , this . element );
2020-07-28 22:23:49 -07:00
2021-07-21 09:36:55 -07:00
//If we are reflecting, attach to the elements disconnect event.
if ( this . reflecting ) {
this . reflectCallbacks . push ( template . element . attachOnDisconnect ( disconnect => this . onItemRemove ( this . list [ i ])));
}
2021-03-16 22:26:33 -07:00
2021-07-21 09:36:55 -07:00
this . children . push ( template );
this . elements . push ( template . element );
} else {
this . children . push ( null );
this . elements . push ( null );
}
2020-07-28 22:23:49 -07:00
}
}
}
2020-08-21 21:42:10 -07:00
2021-03-16 22:26:33 -07:00
onListChanged ( newValue ) {
2020-08-21 21:42:10 -07:00
this . list = newValue ;
IgniteRenderingContext . enter ();
try {
2021-10-27 11:26:19 -07:00
//Reset the list so it's scroll resets too. ScrollTop is unreliable.
this . element . parentElement . parentElement . replaceChild ( this . element . parentElement , this . element . parentElement );
2020-08-21 21:42:10 -07:00
this . construct ( null ); //The list changed, reconstruct this template.
2020-08-23 11:50:31 -07:00
} catch ( error ) {
2020-10-07 08:30:03 -07:00
console . error ( "An error occurred during onListChanged:" , error );
2020-08-23 11:50:31 -07:00
}
2020-08-21 21:42:10 -07:00
IgniteRenderingContext . leave ();
}
2020-08-22 16:15:45 -07:00
2021-03-16 22:26:33 -07:00
onListPush ( items ) {
2020-08-22 16:15:45 -07:00
IgniteRenderingContext . enter ();
try {
2020-10-07 08:30:03 -07:00
items . forEach ( item => {
2021-07-21 09:36:55 -07:00
var template = this . forEach ( item , this . children . length );
2020-08-22 18:11:37 -07:00
2020-10-07 08:30:03 -07:00
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ this . elements . length - 1 ]. nextSibling );
} else {
template . construct ( this . element . parentElement , this . element );
}
2020-08-22 16:15:45 -07:00
2021-03-16 22:26:33 -07:00
//If we are reflecting, attach to the elements disconnect event.
if ( this . reflecting ) {
this . reflectCallbacks . push ( template . element . attachOnDisconnect ( disconnect => this . onItemRemove ( item )));
}
2020-10-07 08:30:03 -07:00
this . children . push ( template );
this . elements . push ( template . element );
});
} catch ( error ) {
console . error ( "An error occurred during onListPush:" , error );
}
IgniteRenderingContext . leave ();
}
2021-03-16 22:26:33 -07:00
onListUnshift ( items ) {
2020-10-07 08:30:03 -07:00
IgniteRenderingContext . enter ();
try {
items . reverse ();
items . forEach ( item => {
2021-07-21 09:36:55 -07:00
var template = this . forEach ( item , 0 );
2020-10-07 08:30:03 -07:00
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ 0 ]);
} else {
template . construct ( this . element . parentElement , this . element );
}
2021-03-16 22:26:33 -07:00
if ( this . reflecting ) {
this . reflectCallbacks . unshift ( template . element . attachOnDisconnect ( disconnect => this . onItemRemove ( item )));
}
2020-10-07 08:30:03 -07:00
this . children . unshift ( template );
this . elements . unshift ( template . element );
});
} catch ( error ) {
console . error ( "An error occurred during onListUnshift:" , error );
}
2020-08-22 16:15:45 -07:00
IgniteRenderingContext . leave ();
}
2021-03-16 22:26:33 -07:00
onListPop () {
2020-09-25 09:36:39 -07:00
if ( this . children . length > 0 ) {
this . children [ this . children . length - 1 ]. deconstruct ();
this . children . pop ();
this . elements . pop ();
2021-03-16 22:26:33 -07:00
if ( this . reflecting ) {
this . reflectCallbacks [ this . reflectCallbacks . length - 1 ]. disconnect ();
this . reflectCallbacks . pop ();
}
2020-09-25 09:36:39 -07:00
}
2020-08-22 16:15:45 -07:00
}
2020-10-07 08:30:03 -07:00
2021-03-16 22:26:33 -07:00
onListShift () {
2020-10-07 08:30:03 -07:00
if ( this . children . length > 0 ) {
this . children [ 0 ]. deconstruct ();
this . children . shift ();
this . elements . shift ();
2021-03-16 22:26:33 -07:00
if ( this . reflecting ) {
this . reflectCallbacks [ 0 ]. disconnect ();
this . reflectCallbacks . shift ();
}
2020-10-07 08:30:03 -07:00
}
}
2021-03-16 22:26:33 -07:00
onListSplice ( start , deleteCount , items ) {
2020-10-07 08:30:03 -07:00
IgniteRenderingContext . enter ();
2021-03-16 22:26:33 -07:00
//Remove any items that will no longer exist.
2020-10-07 08:30:03 -07:00
if ( deleteCount > 0 && this . children . length > 0 ) {
for ( var i = start ; i < Math . min ( this . children . length , start + deleteCount ); i ++ ) {
this . children [ i ]. deconstruct ();
2021-03-16 22:26:33 -07:00
if ( this . reflecting ) {
this . reflectCallbacks [ i ]. disconnect ();
}
2020-10-07 08:30:03 -07:00
}
this . children . splice ( start , deleteCount );
this . elements . splice ( start , deleteCount );
2021-03-16 22:26:33 -07:00
if ( this . reflecting ) {
this . reflectCallbacks . splice ( start , deleteCount );
}
2020-10-07 08:30:03 -07:00
}
//If the start is greater than the length of the items adjust it.
if ( start > this . children . length ) {
start = Math . max ( this . children . length - 1 , 0 );
}
//Append any new items if there are any.
if ( items ) {
items . forEach ( item => {
2021-07-21 09:36:55 -07:00
var template = this . forEach ( item , start );
2020-10-07 08:30:03 -07:00
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ start ]);
} else {
template . construct ( this . element . parentElement , this . element );
}
2021-03-16 22:26:33 -07:00
if ( this . reflecting ) {
this . reflectCallbacks . splice ( start , 0 , template . element . attachOnDisconnect ( disconnect => this . onItemRemove ( item )));
}
2020-10-07 08:30:03 -07:00
this . children . splice ( start , 0 , template );
this . elements . splice ( start , 0 , template . element );
start += 1 ;
});
}
IgniteRenderingContext . leave ();
}
2021-03-16 22:26:33 -07:00
onItemRemove ( item ) {
var index = this . list . indexOf ( item );
if ( index >= 0 ) {
this . list . splice ( index , 1 );
}
}
2020-10-07 08:30:03 -07:00
onStyleChanged ( name , newValue ) {
this . elements . forEach (( element ) => {
2020-10-26 15:30:11 -07:00
element . style . setProperty ( name , newValue , this . _styles [ name ]. priority );
2020-10-07 08:30:03 -07:00
});
2020-10-26 15:30:11 -07:00
this . _styles [ name ]. value = newValue ;
2020-10-07 08:30:03 -07:00
}
2020-07-28 22:23:49 -07:00
}
2020-08-30 21:55:21 -07:00
/**
* A slot template that mimicks the functionality of a slot element in Web Components. This can
* be used to place children of a IgniteElement anywhere in the DOM. Slots don't actually construct an element,
2020-09-09 08:24:18 -07:00
* they simply just place children in place where the slot was used. If classes, styles, or attributes are applied
* to the slot they will be applied to the children of the slot.
2020-08-30 21:55:21 -07:00
*
* @example
2020-09-09 08:24:18 -07:00
* //You must pass the ignite element who owns the slot of the first param.
2020-08-30 21:55:21 -07:00
* new slot(this)
2020-09-09 08:24:18 -07:00
*
* @example
* //Slots can apply classes, attributes, and styles to children within the slot
* new slot(this).class("active") //< Would apply .active to all children
*
* @example
* //You can also use properties to have dynamic classes, styles, or attributes on slot children
* new slot(this).class(this.someClass)
2020-08-30 21:55:21 -07:00
*/
2020-07-28 22:46:22 -07:00
class slot extends IgniteTemplate {
2020-08-30 21:55:21 -07:00
/**
2021-06-10 00:01:35 -07:00
* Creates a new slot with the element who's children will be injected.
2020-08-30 21:55:21 -07:00
* @param {IgniteElement} element The parent IgniteElement that this slot is for.
*/
2020-07-28 22:46:22 -07:00
constructor ( element ) {
2020-08-30 21:55:21 -07:00
super ();
2020-07-28 22:46:22 -07:00
this . parent = element ;
}
2020-09-09 08:24:18 -07:00
/**
* Constructs this slot from this template.
* @param {HTMLElement} parent
* @param {HTMLElement} sibling
* @ignore
*/
2020-07-28 22:46:22 -07:00
construct ( parent , sibling ) {
2020-07-29 11:21:02 -07:00
//Don't construct if we have no parent, no sibling and no element.
if ( ! parent && ! sibling && ! this . element ) {
return ;
}
2020-07-28 22:46:22 -07:00
if ( ! this . element ) {
this . element = window . document . createTextNode ( "" );
if ( sibling ) {
2020-07-29 11:21:02 -07:00
sibling . parentElement . insertBefore ( this . element , sibling );
2020-07-28 22:46:22 -07:00
} else {
parent . appendChild ( this . element );
}
//Add any slot elements after this element.
2020-09-09 08:24:18 -07:00
this . parent . elements . forEach (( item ) => {
this . element . parentElement . insertBefore ( item , this . element );
//Set the classes on the item
2020-11-09 09:38:00 -08:00
if ( item . classList ) {
for ( var i = 0 ; i < this . _classes . length ; i ++ ) {
if ( this . _classes [ i ] !== null && this . _classes [ i ] !== undefined && this . _classes [ i ] !== "" ) {
item . classList . add ( this . _classes [ i ]);
}
2020-09-09 08:24:18 -07:00
}
}
//Set the attributes on the item
2020-10-26 15:30:11 -07:00
var keys = Object . keys ( this . _attributes );
2020-09-09 08:24:18 -07:00
for ( var i = 0 ; i < keys . length ; i ++ ) {
2020-10-26 15:30:11 -07:00
if ( this . _attributes [ keys [ i ]] !== null && this . _attributes [ keys [ i ]] !== undefined ) {
item . setAttribute ( keys [ i ], this . _attributes [ keys [ i ]]);
2020-09-09 08:24:18 -07:00
}
}
//Set the styles on the item
2020-11-09 09:38:00 -08:00
if ( item . style ) {
var keys = Object . keys ( this . _styles );
for ( var i = 0 ; i < keys . length ; i ++ ) {
var style = this . _styles [ keys [ i ]];
item . style . setProperty ( style . name , style . value , style . priority );
}
2020-09-09 08:24:18 -07:00
}
});
2020-07-28 22:46:22 -07:00
}
}
2020-09-09 08:24:18 -07:00
/**
* Called when a class on this slot changes and needs to be updated on the
* elements within this slot.
* @param {Any} oldValue
* @param {Any} newValue
* @param {Function} converter
* @ignore
*/
2020-09-29 14:28:27 -07:00
onClassChanged ( oldValue , newValue ) {
2020-09-09 08:24:18 -07:00
var oldClasses = ( oldValue != null && oldValue != "" ? oldValue . toString (). split ( " " ) : []);
var newClasses = ( newValue != null && newValue != "" ? newValue . toString (). split ( " " ) : []);
//Remove the old values from the template, but only remove one copy.
2020-10-26 15:30:11 -07:00
oldClasses . forEach (( cl ) => this . _classes . splice ( this . _classes . indexOf ( cl ), 1 ));
2020-09-09 08:24:18 -07:00
//Add the new classes to the template.
2020-10-26 15:30:11 -07:00
newClasses . forEach (( cl ) => this . _classes . push ( cl ));
2020-09-09 08:24:18 -07:00
//Add the classes to the elements
this . parent . elements . forEach (( element ) => {
2020-11-09 09:38:00 -08:00
//Only do this if the element has a class list.
if ( ! element . classList ) { return ; }
2020-09-09 08:24:18 -07:00
//Remove the old ones first.
oldClasses . forEach (( cl ) => element . classList . remove ( cl ));
//Add the new ones.
newClasses . forEach (( cl ) => element . classList . add ( cl ));
//Add any missing ones
2020-10-26 15:30:11 -07:00
this . _classes . forEach (( cl ) => {
2020-09-09 08:24:18 -07:00
if ( ! element . classList . contains ( cl )) {
element . classList . add ( cl );
}
});
});
}
/**
* Called when a attribute on this template was changed and needs to be updated
* on the template's element.
* @param {any} oldValue
* @param {any} newValue
* @param {string} attributeName
* @param {Function} converter Optional converter function for the value if needed.
* @ignore
*/
2021-10-13 07:46:40 -07:00
onAttributeChanged ( name , newValue ) {
2020-09-09 08:24:18 -07:00
this . parent . elements . forEach (( element ) => {
if ( newValue == null || newValue == undefined ) {
2021-10-13 07:46:40 -07:00
element . removeAttribute ( name );
2020-09-09 08:24:18 -07:00
} else {
2021-10-13 07:46:40 -07:00
element . setAttribute ( name , newValue );
2020-09-09 08:24:18 -07:00
}
});
2021-10-13 07:46:40 -07:00
this . _attributes [ name ] = newValue ;
2020-09-09 08:24:18 -07:00
}
/**
* Called when a css value was changed and we need to update the styling.
2020-09-25 09:36:39 -07:00
* @param {String} name
2020-09-09 08:24:18 -07:00
* @param {any} newValue
* @ignore
*/
2020-09-25 09:36:39 -07:00
onStyleChanged ( name , newValue ) {
2020-09-09 08:24:18 -07:00
this . parent . elements . forEach (( element ) => {
2020-10-26 15:30:11 -07:00
element . style . setProperty ( name , newValue , this . _styles [ name ]. priority );
2020-09-09 08:24:18 -07:00
});
2020-10-26 15:30:11 -07:00
this . _styles [ name ]. value = newValue ;
2020-09-09 08:24:18 -07:00
}
2020-07-28 22:46:22 -07:00
}
2020-10-20 13:18:26 -07:00
/**
* A pagination is a template that segments a list of items into pages based
* on the items, page size, current page.
*/
class pagination extends IgniteTemplate {
constructor ( list , pageSize , currentPage , forEach ) {
super ();
if ( list instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( list . attachOnChange (( oldValue , newValue ) => this . onListChanged ( oldValue , newValue )));
this . _callbacks . push ( list . attachOnPush (( list , items ) => this . onListPush ( list , items )));
this . _callbacks . push ( list . attachOnUnshift (( list , items ) => this . onListUnshift ( list , items )));
this . _callbacks . push ( list . attachOnPop ( list => this . onListPop ( list )));
this . _callbacks . push ( list . attachOnShift ( list => this . onListShift ( list )));
this . _callbacks . push ( list . attachOnSplice (( list , start , deleteCount , items ) => this . onListSplice ( list , start , deleteCount , items )));
2020-10-20 13:18:26 -07:00
this . list = list . value ;
} else {
this . list = list ;
}
if ( pageSize instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( pageSize . attachOnChange (( oldValue , newValue ) => this . onPageSizeChanged ( newValue )));
2020-10-20 13:18:26 -07:00
this . pageSize = pageSize . value ;
} else {
this . pageSize = pageSize ;
}
if ( currentPage instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( currentPage . attachOnChange (( oldValue , newValue ) => this . onCurrentPageChanged ( newValue )));
2020-10-20 13:18:26 -07:00
this . currentPage = currentPage . value ;
} else {
this . currentPage = currentPage ;
}
this . forEach = forEach ;
this . elements = [];
this . tagName = "shadow pagination" ;
this . pages = [];
}
recalculate () {
//Hide the elements in the current page.
this . pages [ this . currentPage ]. forEach ( item => item . style . setProperty ( "display" , "none" , "important" ));
//Recreate the pages.
var pages = parseInt (( this . list . length / this . pageSize )) + ( this . list . length % this . pageSize > 0 ? 1 : 0 );
this . pages = [];
for ( var i = 0 ; i < pages ; i ++ ) {
this . pages . push ([]);
}
//Add the elements to the correct pages.
for ( var i = 0 ; i < this . elements . length ; i ++ ) {
var page = parseInt ( i / this . pageSize );
this . pages [ page ]. push ( this . elements [ i ]);
}
//Adjust the current page if it's now incorrect.
if ( this . currentPage >= pages ) {
this . currentPage = pages - 1 ;
}
//Show the elements in the current page
this . pages [ this . currentPage ]. forEach ( item => item . style . removeProperty ( "display" ));
}
construct ( parent , sibling ) {
//Don't construct if we have no parent, no sibling and no element.
if ( ! parent && ! sibling && ! this . element ) {
return ;
}
if ( ! this . element ) {
this . element = window . document . createTextNode ( "" ); //Use a textnode as our placeholder
if ( sibling ) {
sibling . parentElement . insertBefore ( this . element , sibling );
} else {
parent . appendChild ( this . element );
}
} else {
parent = this . element . parentElement ;
}
//If we already have elements we created, destroy them.
if ( this . elements . length > 0 ) {
for ( var i = 0 ; i < this . elements . length ; i ++ ) {
this . elements [ i ]. remove ();
}
this . elements = [];
}
//If we already have children elements, deconstruct them.
//(Because we are about to recreate them)
if ( this . children . length > 0 ) {
for ( var i = 0 ; i < this . children . length ; i ++ ) {
this . children [ i ]. deconstruct ();
}
this . children = [];
}
//Init our pages to put elements into.
var pages = parseInt (( this . list . length / this . pageSize )) + ( this . list . length % this . pageSize > 0 ? 1 : 0 );
this . pages = [];
for ( var i = 0 ; i < pages ; i ++ ) {
this . pages . push ([]);
}
//Construct all the items in our list and use the container
if ( this . list ) {
for ( var i = 0 ; i < this . list . length ; i ++ ) {
var template = this . forEach ( this . list [ i ]);
template . construct ( parent , this . element );
var page = parseInt ( i / this . pageSize );
if ( page != this . currentPage ) {
template . element . style . setProperty ( "display" , "none" , "important" );
} else {
template . element . style . removeProperty ( "display" );
}
this . pages [ page ]. push ( template . element );
this . children . push ( template );
this . elements . push ( template . element );
}
}
}
onPageSizeChanged ( newValue ) {
//Set the new page size
this . pageSize = newValue ;
//Recalculate the pagination.
this . recalculate ();
}
onCurrentPageChanged ( newValue ) {
//If the new page is invalid don't do this.
if ( newValue >= this . pages . length ) {
return ;
} else if ( newValue < 0 ) {
return ;
}
//Hide all the elements in the current page
this . pages [ this . currentPage ]. forEach ( item => item . style . setProperty ( "display" , "none" , "important" ));
//Set the new current page.
this . currentPage = newValue ;
//Show the elements in the next page
this . pages [ this . currentPage ]. forEach ( item => item . style . removeProperty ( "display" ));
}
onListChanged ( oldValue , newValue ) {
this . list = newValue ;
IgniteRenderingContext . enter ();
try {
this . construct ( null ); //The list changed, reconstruct this template.
} catch ( error ) {
console . error ( "An error occurred during onListChanged:" , error );
}
IgniteRenderingContext . leave ();
}
onListPush ( list , items ) {
IgniteRenderingContext . enter ();
try {
items . forEach ( item => {
var template = this . forEach ( item );
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ this . elements . length - 1 ]. nextSibling );
} else {
template . construct ( this . element . parentElement , this . element );
}
this . children . push ( template );
this . elements . push ( template . element );
});
//Recalculate the pagination.
this . recalculate ();
} catch ( error ) {
console . error ( "An error occurred during onListPush:" , error );
}
IgniteRenderingContext . leave ();
}
onListUnshift ( list , items ) {
IgniteRenderingContext . enter ();
try {
items . reverse ();
items . forEach ( item => {
var template = this . forEach ( item );
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ 0 ]);
} else {
template . construct ( this . element . parentElement , this . element );
}
this . children . unshift ( template );
this . elements . unshift ( template . element );
});
//Recalculate the pagination.
this . recalculate ();
} catch ( error ) {
console . error ( "An error occurred during onListUnshift:" , error );
}
IgniteRenderingContext . leave ();
}
onListPop ( list ) {
if ( this . children . length > 0 ) {
this . children [ this . children . length - 1 ]. deconstruct ();
this . children . pop ();
this . elements . pop ();
}
//Recalculate the pagination.
this . recalculate ();
}
onListShift ( list ) {
if ( this . children . length > 0 ) {
this . children [ 0 ]. deconstruct ();
this . children . shift ();
this . elements . shift ();
}
//Recalculate the pagination.
this . recalculate ();
}
onListSplice ( list , start , deleteCount , items ) {
IgniteRenderingContext . enter ();
//Remove any items that are needed.
if ( deleteCount > 0 && this . children . length > 0 ) {
for ( var i = start ; i < Math . min ( this . children . length , start + deleteCount ); i ++ ) {
this . children [ i ]. deconstruct ();
}
this . children . splice ( start , deleteCount );
this . elements . splice ( start , deleteCount );
}
//If the start is greater than the length of the items adjust it.
if ( start > this . children . length ) {
start = Math . max ( this . children . length - 1 , 0 );
}
//Append any new items if there are any.
if ( items ) {
items . forEach ( item => {
var template = this . forEach ( item );
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ start ]);
} else {
template . construct ( this . element . parentElement , this . element );
}
this . children . splice ( start , 0 , template );
this . elements . splice ( start , 0 , template . element );
start += 1 ;
});
}
//Recalculate the pagination.
this . recalculate ();
IgniteRenderingContext . leave ();
}
}
/**
* An ignite template that can construct a population of items
* based on a count.
*/
class population extends IgniteTemplate {
/**
* Creates a new population with the number of items in it, a converter if needed, and a foreach function.
* @param {Number|IgniteProperty} count The number of items in this population.
* @param {Function} forEach A function to generate items in the population.
* @param {Function?} converter A converter to be used to convert the count if needed.
*/
constructor ( count , forEach , converter = null ) {
super ();
if ( count instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( count . attachOnChange (( oldValue , newValue ) => this . onCountChange ( converter != null ? converter ( newValue ) : newValue )));
2020-10-20 13:18:26 -07:00
this . count = count . value ;
} else if ( Array . isArray ( count ) && count . length > 0 && count [ 0 ] instanceof IgniteProperty ) {
//There must be a converter for this to work correctly
if ( ! converter ) {
throw "Cannot pass an array of properties without using a converter!" ;
}
//Attack a callback for all the properties
count . forEach ( prop => {
if ( prop instanceof IgniteProperty ) {
2020-10-26 15:30:11 -07:00
this . _callbacks . push ( prop . attachOnChange (( oldValue , newValue ) => this . onCountChange ( converter (... count . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPush (( list , items ) => this . onCountChange ( converter (... count . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnUnshift (( list , items ) => this . onCountChange ( converter (... count . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnPop (( list ) => this . onCountChange ( converter (... count . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnShift (( list ) => this . onCountChange ( converter (... count . getPropertyValues ()))));
this . _callbacks . push ( prop . attachOnSplice (( list , start , deleteCount , items ) => this . onCountChange ( converter (... count . getPropertyValues ()))));
2020-10-20 13:18:26 -07:00
}
});
this . count = converter (... count . getPropertyValues ());
} else {
this . count = ( converter != null ? converter ( count ) : count );
}
this . forEach = forEach ;
this . elements = [];
this . tagName = "shadow population" ;
}
construct ( parent , sibling ) {
//Don't construct if we have no parent, no sibling and no element.
if ( ! parent && ! sibling && ! this . element ) {
return ;
}
if ( ! this . element ) {
this . element = window . document . createTextNode ( "" ); //Use a textnode as our placeholder
if ( sibling ) {
sibling . parentElement . insertBefore ( this . element , sibling );
} else {
parent . appendChild ( this . element );
}
} else {
parent = this . element . parentElement ;
}
//If we already have elements we created, destroy them.
if ( this . elements . length > 0 ) {
this . elements . forEach ( item => item . remove ());
this . elements = [];
}
//Construct all the elements for this population.
for ( var i = 0 ; i < this . count ; i ++ ) {
var template = this . forEach ( i );
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ this . elements . length - 1 ]. nextSibling );
} else {
template . construct ( this . element . parentElement , this . element );
}
this . elements . push ( template . element );
}
}
onCountChange ( newValue ) {
IgniteRenderingContext . enter ();
if ( newValue != this . elements . length ) {
//Remove all our existing elements.
this . elements . forEach ( item => item . remove ());
this . elements = [];
//Create new elements.
for ( var i = 0 ; i < newValue ; i ++ ) {
var template = this . forEach ( i );
if ( this . elements . length > 0 ) {
template . construct ( this . element . parentElement , this . elements [ this . elements . length - 1 ]. nextSibling );
} else {
template . construct ( this . element . parentElement , this . element );
}
this . elements . push ( template . element );
}
//Set the new count
this . count = newValue ;
}
IgniteRenderingContext . leave ();
}
}
2020-07-28 09:04:04 -07:00
export {
IgniteTemplate ,
div ,
2021-10-06 08:08:02 -07:00
text ,
2020-07-28 09:04:04 -07:00
html ,
list ,
2020-07-28 22:46:22 -07:00
a ,
2020-08-21 22:13:06 -07:00
input ,
2020-09-29 14:28:27 -07:00
textarea ,
2020-08-30 21:55:21 -07:00
button ,
2020-08-23 11:50:31 -07:00
h1 ,
h2 ,
h3 ,
h4 ,
h5 ,
2020-09-25 09:36:39 -07:00
h6 ,
2020-09-28 09:02:57 -07:00
hr ,
2020-08-23 11:50:31 -07:00
p ,
span ,
2021-07-28 08:38:33 -07:00
small ,
2021-03-10 08:56:14 -08:00
strong ,
2020-08-23 11:50:31 -07:00
i ,
2020-09-09 08:24:18 -07:00
ul ,
li ,
2020-08-30 21:55:21 -07:00
br ,
img ,
2020-08-31 22:11:19 -07:00
label ,
2020-09-28 09:02:57 -07:00
select ,
option ,
script ,
2020-10-20 13:18:26 -07:00
slot ,
pagination ,
2020-12-09 20:41:11 -08:00
population ,
table ,
tr ,
th ,
td ,
tbody ,
thead ,
progress ,
svg ,
2021-01-06 23:42:55 -08:00
g ,
path ,
2021-01-05 10:29:14 -08:00
circle ,
2021-01-08 02:22:29 -08:00
line ,
2021-08-04 10:03:20 -07:00
form ,
header ,
footer
2020-07-28 09:04:04 -07:00
};