2018-11-04 07:14:53 +00:00
function _typeof ( obj ) {
if ( typeof Symbol === "function" && typeof Symbol . iterator === "symbol" ) {
_typeof = function ( obj ) {
return typeof obj ;
} ;
} else {
_typeof = function ( obj ) {
return obj && typeof Symbol === "function" && obj . constructor === Symbol && obj !== Symbol . prototype ? "symbol" : typeof obj ;
} ;
}
return _typeof ( obj ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function _classCallCheck ( instance , Constructor ) {
2018-09-25 08:49:26 +00:00
if ( ! ( instance instanceof Constructor ) ) {
throw new TypeError ( "Cannot call a class as a function" ) ;
}
2018-11-04 07:14:53 +00:00
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function _defineProperties ( target , props ) {
for ( var i = 0 ; i < props . length ; i ++ ) {
var descriptor = props [ i ] ;
descriptor . enumerable = descriptor . enumerable || false ;
descriptor . configurable = true ;
if ( "value" in descriptor ) descriptor . writable = true ;
Object . defineProperty ( target , descriptor . key , descriptor ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function _createClass ( Constructor , protoProps , staticProps ) {
if ( protoProps ) _defineProperties ( Constructor . prototype , protoProps ) ;
if ( staticProps ) _defineProperties ( Constructor , staticProps ) ;
return Constructor ;
}
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
function _defineProperty ( obj , key , value ) {
if ( key in obj ) {
Object . defineProperty ( obj , key , {
value : value ,
enumerable : true ,
configurable : true ,
writable : true
} ) ;
} else {
obj [ key ] = value ;
}
return obj ;
}
function _objectSpread ( target ) {
for ( var i = 1 ; i < arguments . length ; i ++ ) {
var source = arguments [ i ] != null ? arguments [ i ] : { } ;
var ownKeys = Object . keys ( source ) ;
if ( typeof Object . getOwnPropertySymbols === 'function' ) {
ownKeys = ownKeys . concat ( Object . getOwnPropertySymbols ( source ) . filter ( function ( sym ) {
return Object . getOwnPropertyDescriptor ( source , sym ) . enumerable ;
} ) ) ;
}
ownKeys . forEach ( function ( key ) {
_defineProperty ( target , key , source [ key ] ) ;
} ) ;
}
return target ;
}
2018-11-04 07:14:53 +00:00
function _inherits ( subClass , superClass ) {
2018-09-25 08:49:26 +00:00
if ( typeof superClass !== "function" && superClass !== null ) {
2018-11-04 07:14:53 +00:00
throw new TypeError ( "Super expression must either be null or a function" ) ;
2018-09-25 08:49:26 +00:00
}
subClass . prototype = Object . create ( superClass && superClass . prototype , {
constructor : {
value : subClass ,
writable : true ,
configurable : true
}
} ) ;
2018-11-04 07:14:53 +00:00
if ( superClass ) _setPrototypeOf ( subClass , superClass ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function _getPrototypeOf ( o ) {
_getPrototypeOf = Object . setPrototypeOf ? Object . getPrototypeOf : function _getPrototypeOf ( o ) {
return o . _ _proto _ _ || Object . getPrototypeOf ( o ) ;
} ;
return _getPrototypeOf ( o ) ;
}
function _setPrototypeOf ( o , p ) {
_setPrototypeOf = Object . setPrototypeOf || function _setPrototypeOf ( o , p ) {
o . _ _proto _ _ = p ;
return o ;
} ;
return _setPrototypeOf ( o , p ) ;
}
function isNativeReflectConstruct ( ) {
if ( typeof Reflect === "undefined" || ! Reflect . construct ) return false ;
if ( Reflect . construct . sham ) return false ;
if ( typeof Proxy === "function" ) return true ;
try {
Date . prototype . toString . call ( Reflect . construct ( Date , [ ] , function ( ) { } ) ) ;
return true ;
} catch ( e ) {
return false ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function _construct ( Parent , args , Class ) {
if ( isNativeReflectConstruct ( ) ) {
_construct = Reflect . construct ;
} else {
_construct = function _construct ( Parent , args , Class ) {
var a = [ null ] ;
a . push . apply ( a , args ) ;
var Constructor = Function . bind . apply ( Parent , a ) ;
var instance = new Constructor ( ) ;
if ( Class ) _setPrototypeOf ( instance , Class . prototype ) ;
return instance ;
} ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
return _construct . apply ( null , arguments ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function _isNativeFunction ( fn ) {
return Function . toString . call ( fn ) . indexOf ( "[native code]" ) !== - 1 ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function _wrapNativeSuper ( Class ) {
var _cache = typeof Map === "function" ? new Map ( ) : undefined ;
_wrapNativeSuper = function _wrapNativeSuper ( Class ) {
if ( Class === null || ! _isNativeFunction ( Class ) ) return Class ;
if ( typeof Class !== "function" ) {
throw new TypeError ( "Super expression must either be null or a function" ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( typeof _cache !== "undefined" ) {
if ( _cache . has ( Class ) ) return _cache . get ( Class ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
_cache . set ( Class , Wrapper ) ;
}
function Wrapper ( ) {
return _construct ( Class , arguments , _getPrototypeOf ( this ) . constructor ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
Wrapper . prototype = Object . create ( Class . prototype , {
constructor : {
value : Wrapper ,
enumerable : false ,
writable : true ,
configurable : true
}
} ) ;
return _setPrototypeOf ( Wrapper , Class ) ;
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
return _wrapNativeSuper ( Class ) ;
}
function _assertThisInitialized ( self ) {
if ( self === void 0 ) {
throw new ReferenceError ( "this hasn't been initialised - super() hasn't been called" ) ;
}
return self ;
}
function _possibleConstructorReturn ( self , call ) {
if ( call && ( typeof call === "object" || typeof call === "function" ) ) {
return call ;
}
return _assertThisInitialized ( self ) ;
}
function _superPropBase ( object , property ) {
while ( ! Object . prototype . hasOwnProperty . call ( object , property ) ) {
object = _getPrototypeOf ( object ) ;
if ( object === null ) break ;
}
return object ;
}
function _get ( target , property , receiver ) {
if ( typeof Reflect !== "undefined" && Reflect . get ) {
_get = Reflect . get ;
} else {
_get = function _get ( target , property , receiver ) {
var base = _superPropBase ( target , property ) ;
if ( ! base ) return ;
var desc = Object . getOwnPropertyDescriptor ( base , property ) ;
if ( desc . get ) {
return desc . get . call ( receiver ) ;
}
return desc . value ;
} ;
}
return _get ( target , property , receiver || target ) ;
}
function _slicedToArray ( arr , i ) {
return _arrayWithHoles ( arr ) || _iterableToArrayLimit ( arr , i ) || _nonIterableRest ( ) ;
}
function _toConsumableArray ( arr ) {
return _arrayWithoutHoles ( arr ) || _iterableToArray ( arr ) || _nonIterableSpread ( ) ;
}
function _arrayWithoutHoles ( arr ) {
2018-09-25 08:49:26 +00:00
if ( Array . isArray ( arr ) ) {
2018-11-04 07:14:53 +00:00
for ( var i = 0 , arr2 = new Array ( arr . length ) ; i < arr . length ; i ++ ) arr2 [ i ] = arr [ i ] ;
2018-09-25 08:49:26 +00:00
return arr2 ;
}
2018-11-04 07:14:53 +00:00
}
function _arrayWithHoles ( arr ) {
if ( Array . isArray ( arr ) ) return arr ;
}
function _iterableToArray ( iter ) {
if ( Symbol . iterator in Object ( iter ) || Object . prototype . toString . call ( iter ) === "[object Arguments]" ) return Array . from ( iter ) ;
}
function _iterableToArrayLimit ( arr , i ) {
var _arr = [ ] ;
var _n = true ;
var _d = false ;
var _e = undefined ;
try {
for ( var _i = arr [ Symbol . iterator ] ( ) , _s ; ! ( _n = ( _s = _i . next ( ) ) . done ) ; _n = true ) {
_arr . push ( _s . value ) ;
if ( i && _arr . length === i ) break ;
}
} catch ( err ) {
_d = true ;
_e = err ;
} finally {
try {
if ( ! _n && _i [ "return" ] != null ) _i [ "return" ] ( ) ;
} finally {
if ( _d ) throw _e ;
}
}
return _arr ;
}
function _nonIterableSpread ( ) {
throw new TypeError ( "Invalid attempt to spread non-iterable instance" ) ;
}
function _nonIterableRest ( ) {
throw new TypeError ( "Invalid attempt to destructure non-iterable instance" ) ;
}
2018-09-25 08:49:26 +00:00
/ *
Possible todos :
0. Add XSLT to JML - string stylesheet ( or even vice versa )
0. IE problem : Add JsonML code to handle name attribute ( during element creation )
0. Element - specific : IE object - param handling
Todos inspired by JsonML : https : //github.com/mckamey/jsonml/blob/master/jsonml-html.js
0. duplicate attributes ?
0. expand ATTR _MAP
0. equivalent of markup , to allow strings to be embedded within an object ( e . g . , { $value : '<div>id</div>' } ) ; advantage over innerHTML in that it wouldn ' t need to work as the entire contents ( nor destroy any existing content or handlers )
0. More validation ?
0. JsonML DOM Level 0 listener
0. Whitespace trimming ?
JsonML element - specific :
0. table appending
0. canHaveChildren necessary ? ( attempts to append to script and img )
Other Todos :
0. Note to self : Integrate research from other jml notes
0. Allow Jamilih to be seeded with an existing element , so as to be able to add / modify attributes and children
0. Allow array as single first argument
0. Settle on whether need to use null as last argument to return array ( or fragment ) or other way to allow appending ? Options object at end instead to indicate whether returning array , fragment , first element , etc . ?
0. Allow building of generic XML ( pass configuration object )
0. Allow building content internally as a string ( though allowing DOM methods , etc . ? )
0. Support JsonML empty string element name to represent fragments ?
0. Redo browser testing of jml ( including ensuring IE7 can work even if test framework can ' t work )
* /
var win = typeof window !== 'undefined' && window ;
var doc = typeof document !== 'undefined' && document ;
2018-11-04 07:14:53 +00:00
var XmlSerializer = typeof XMLSerializer !== 'undefined' && XMLSerializer ; // STATIC PROPERTIES
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
var possibleOptions = [ '$plugins' , // '$mode', // Todo (SVG/XML)
// 'state', // Used internally
'$map' // Add any other options here
2018-09-25 08:49:26 +00:00
] ;
var NS _HTML = 'http://www.w3.org/1999/xhtml' ,
2019-05-24 12:17:17 +00:00
hyphenForCamelCase = /\x2D([a-z])/g ;
2018-09-25 08:49:26 +00:00
var ATTR _MAP = {
2019-05-24 12:17:17 +00:00
readonly : 'readOnly'
2018-11-04 07:14:53 +00:00
} ; // We define separately from ATTR_DOM for clarity (and parity with JsonML) but no current need
2018-09-25 08:49:26 +00:00
// We don't set attribute esp. for boolean atts as we want to allow setting of `undefined`
// (e.g., from an empty variable) on templates to have no effect
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
var BOOL _ATTS = [ 'checked' , 'defaultChecked' , 'defaultSelected' , 'disabled' , 'indeterminate' , 'open' , // Dialog elements
2019-05-24 12:17:17 +00:00
'readOnly' , 'selected' ] ; // From JsonML
var ATTR _DOM = BOOL _ATTS . concat ( [ 'accessKey' , // HTMLElement
2018-09-25 08:49:26 +00:00
'async' , 'autocapitalize' , // HTMLElement
'autofocus' , 'contentEditable' , // HTMLElement through ElementContentEditable
'defaultValue' , 'defer' , 'draggable' , // HTMLElement
'formnovalidate' , 'hidden' , // HTMLElement
'innerText' , // HTMLElement
'inputMode' , // HTMLElement through ElementContentEditable
'ismap' , 'multiple' , 'novalidate' , 'pattern' , 'required' , 'spellcheck' , // HTMLElement
'translate' , // HTMLElement
2018-11-04 07:14:53 +00:00
'value' , 'willvalidate' ] ) ; // Todo: Add more to this as useful for templating
2018-09-25 08:49:26 +00:00
// to avoid setting through nullish value
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
var NULLABLES = [ 'dir' , // HTMLElement
'lang' , // HTMLElement
'max' , 'min' , 'title' // HTMLElement
] ;
var $ = function $ ( sel ) {
2018-11-04 07:14:53 +00:00
return doc . querySelector ( sel ) ;
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
var $$ = function $$ ( sel ) {
2018-11-04 07:14:53 +00:00
return _toConsumableArray ( doc . querySelectorAll ( sel ) ) ;
2018-09-25 08:49:26 +00:00
} ;
/ * *
2019-05-24 12:17:17 +00:00
* Retrieve the ( lower - cased ) HTML name of a node .
2018-09-25 08:49:26 +00:00
* @ static
* @ param { Node } node The HTML node
2019-05-24 12:17:17 +00:00
* @ returns { string } The lower - cased node name
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _getHTMLNodeName ( node ) {
2018-11-04 07:14:53 +00:00
return node . nodeName && node . nodeName . toLowerCase ( ) ;
2018-09-25 08:49:26 +00:00
}
/ * *
2019-05-24 12:17:17 +00:00
* Apply styles if this is a style tag .
2018-09-25 08:49:26 +00:00
* @ static
* @ param { Node } node The element to check whether it is a style tag
2019-05-24 12:17:17 +00:00
* @ returns { void }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _applyAnyStylesheet ( node ) {
2018-11-04 07:14:53 +00:00
if ( ! doc . createStyleSheet ) {
return ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
if ( _getHTMLNodeName ( node ) === 'style' ) {
// IE
var ss = doc . createStyleSheet ( ) ; // Create a stylesheet to actually do something useful
ss . cssText = node . cssText ; // We continue to add the style tag, however
}
}
2018-09-25 08:49:26 +00:00
/ * *
2019-05-24 12:17:17 +00:00
* Need this function for IE since options weren ' t otherwise getting added .
2018-09-25 08:49:26 +00:00
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { Element } parent The parent to which to append the element
* @ param { Node } child The element or other node to append to the parent
* @ returns { void }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _appendNode ( parent , child ) {
2018-11-04 07:14:53 +00:00
var parentName = _getHTMLNodeName ( parent ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
var childName = _getHTMLNodeName ( child ) ;
if ( doc . createStyleSheet ) {
if ( parentName === 'script' ) {
parent . text = child . nodeValue ;
return ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( parentName === 'style' ) {
parent . cssText = child . nodeValue ; // This will not apply it--just make it available within the DOM cotents
return ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
}
if ( parentName === 'template' ) {
2019-05-24 12:17:17 +00:00
parent . content . append ( child ) ;
2018-11-04 07:14:53 +00:00
return ;
}
try {
2019-05-24 12:17:17 +00:00
parent . append ( child ) ; // IE9 is now ok with this
2018-11-04 07:14:53 +00:00
} catch ( e ) {
if ( parentName === 'select' && childName === 'option' ) {
try {
// Since this is now DOM Level 4 standard behavior (and what IE7+ can handle), we try it first
parent . add ( child ) ;
} catch ( err ) {
// DOM Level 2 did require a second argument, so we try it too just in case the user is using an older version of Firefox, etc.
parent . add ( child , null ) ; // IE7 has a problem with this, but IE8+ is ok
}
return ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
throw e ;
}
}
2018-09-25 08:49:26 +00:00
/ * *
2019-05-24 12:17:17 +00:00
* Attach event in a cross - browser fashion .
2018-09-25 08:49:26 +00:00
* @ static
2019-05-24 12:17:17 +00:00
* @ param { Element } el DOM element to which to attach the event
* @ param { string } type The DOM event ( without 'on' ) to attach to the element
2018-09-25 08:49:26 +00:00
* @ param { Function } handler The event handler to attach to the element
2019-05-24 12:17:17 +00:00
* @ param { boolean } [ capturing ] Whether or not the event should be
* capturing ( W3C - browsers only ) ; default is false ; NOT IN USE
* @ returns { void }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _addEvent ( el , type , handler , capturing ) {
2019-05-24 12:17:17 +00:00
el . addEventListener ( type , handler , Boolean ( capturing ) ) ;
2018-09-25 08:49:26 +00:00
}
/ * *
2019-05-24 12:17:17 +00:00
* Creates a text node of the result of resolving an entity or character reference .
2018-09-25 08:49:26 +00:00
* @ param { 'entity' | 'decimal' | 'hexadecimal' } type Type of reference
2019-05-24 12:17:17 +00:00
* @ param { string } prefix Text to prefix immediately after the "&"
* @ param { string } arg The body of the reference
2018-09-25 08:49:26 +00:00
* @ returns { Text } The text node of the resolved reference
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _createSafeReference ( type , prefix , arg ) {
2018-11-04 07:14:53 +00:00
// For security reasons related to innerHTML, we ensure this string only contains potential entity characters
2019-05-24 12:17:17 +00:00
if ( ! arg . match ( /^[0-9A-Z_a-z]+$/ ) ) {
2018-11-04 07:14:53 +00:00
throw new TypeError ( 'Bad ' + type ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
var elContainer = doc . createElement ( 'div' ) ; // Todo: No workaround for XML?
elContainer . innerHTML = '&' + prefix + arg + ';' ;
return doc . createTextNode ( elContainer . innerHTML ) ;
}
2018-09-25 08:49:26 +00:00
/ * *
2019-05-24 12:17:17 +00:00
* @ param { string } n0 Whole expression match ( including "-" )
* @ param { string } n1 Lower - case letter match
* @ returns { string } Uppercased letter
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _upperCase ( n0 , n1 ) {
2018-11-04 07:14:53 +00:00
return n1 . toUpperCase ( ) ;
2019-05-24 12:17:17 +00:00
} // Todo: Make as public utility
/ * *
* @ param { * } o
* @ returns { boolean }
* /
function _isNullish ( o ) {
return o === null || o === undefined ;
} // Todo: Make as public utility, but also return types for undefined, boolean, number, document, etc.
2018-09-25 08:49:26 +00:00
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { string | object | Array | Element | DocumentFragment } item
* @ returns { "string" | "null" | "array" | "element" | "fragment" | "object" }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _getType ( item ) {
2018-11-04 07:14:53 +00:00
if ( typeof item === 'string' ) {
return 'string' ;
}
if ( _typeof ( item ) === 'object' ) {
if ( item === null ) {
return 'null' ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( Array . isArray ( item ) ) {
return 'array' ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( 'nodeType' in item ) {
if ( item . nodeType === 1 ) {
return 'element' ;
}
if ( item . nodeType === 11 ) {
return 'fragment' ;
}
}
return 'object' ;
}
return undefined ;
}
2018-09-25 08:49:26 +00:00
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { DocumentFragment } frag
* @ param { Node } node
* @ returns { DocumentFragment }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _fragReducer ( frag , node ) {
2019-05-24 12:17:17 +00:00
frag . append ( node ) ;
2018-11-04 07:14:53 +00:00
return frag ;
2018-09-25 08:49:26 +00:00
}
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { Object < { string : string } > } xmlnsObj
* @ returns { string }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _replaceDefiner ( xmlnsObj ) {
2018-11-04 07:14:53 +00:00
return function ( n0 ) {
var retStr = xmlnsObj [ '' ] ? ' xmlns="' + xmlnsObj [ '' ] + '"' : n0 || '' ; // Preserve XHTML
for ( var ns in xmlnsObj ) {
2019-05-24 12:17:17 +00:00
if ( { } . hasOwnProperty . call ( xmlnsObj , ns ) ) {
2018-11-04 07:14:53 +00:00
if ( ns !== '' ) {
retStr += ' xmlns:' + ns + '="' + xmlnsObj [ ns ] + '"' ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
}
}
return retStr ;
} ;
2018-09-25 08:49:26 +00:00
}
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { JamilihArray } args
* @ returns { Element }
* /
2018-09-25 08:49:26 +00:00
function _optsOrUndefinedJML ( ) {
2018-11-04 07:14:53 +00:00
for ( var _len = arguments . length , args = new Array ( _len ) , _key = 0 ; _key < _len ; _key ++ ) {
args [ _key ] = arguments [ _key ] ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
return jml . apply ( void 0 , _toConsumableArray ( args [ 0 ] === undefined ? args . slice ( 1 ) : args ) ) ;
2018-09-25 08:49:26 +00:00
}
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { string } arg
* @ returns { Element }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _jmlSingleArg ( arg ) {
2018-11-04 07:14:53 +00:00
return jml ( arg ) ;
2018-09-25 08:49:26 +00:00
}
2019-05-24 12:17:17 +00:00
/ * *
* @ typedef { Array } AttributeArray
* @ property { string } 0 The key
* @ property { string } 1 The value
* /
2018-09-25 08:49:26 +00:00
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ todo Deprecate as now there is predictable iteration order ?
* @ param { AttributeArray } attArr
* @ returns { PlainObject }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _copyOrderedAtts ( attArr ) {
2018-11-04 07:14:53 +00:00
var obj = { } ; // Todo: Fix if allow prefixed attributes
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
obj [ attArr [ 0 ] ] = attArr [ 1 ] ; // array of ordered attribute-value arrays
return obj ;
}
2019-05-24 12:17:17 +00:00
/ * *
* @ callback ChildrenToJMLCallback
* @ param { JamilihArray | Jamilih } childNodeJML
* @ param { Integer } i
* /
2018-09-25 08:49:26 +00:00
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { Node } node
* @ returns { ChildrenToJMLCallback }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _childrenToJML ( node ) {
2018-11-04 07:14:53 +00:00
return function ( childNodeJML , i ) {
var cn = node . childNodes [ i ] ;
var j = Array . isArray ( childNodeJML ) ? jml . apply ( void 0 , _toConsumableArray ( childNodeJML ) ) : jml ( childNodeJML ) ;
cn . parentNode . replaceChild ( j , cn ) ;
} ;
2018-09-25 08:49:26 +00:00
}
2019-05-24 12:17:17 +00:00
/ * *
* @ callback JamilihAppender
* @ param { JamilihArray } childJML
* @ returns { void }
* /
2018-09-25 08:49:26 +00:00
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { Node } node
* @ returns { JamilihAppender }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _appendJML ( node ) {
2018-11-04 07:14:53 +00:00
return function ( childJML ) {
2019-05-24 12:17:17 +00:00
node . append ( jml . apply ( void 0 , _toConsumableArray ( childJML ) ) ) ;
2018-11-04 07:14:53 +00:00
} ;
2018-09-25 08:49:26 +00:00
}
2019-05-24 12:17:17 +00:00
/ * *
* @ callback appender
* @ param { string | JamilihArray } childJML
* @ returns { void }
* /
2018-09-25 08:49:26 +00:00
/ * *
* @ private
* @ static
2019-05-24 12:17:17 +00:00
* @ param { Node } node
* @ returns { appender }
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
function _appendJMLOrText ( node ) {
2018-11-04 07:14:53 +00:00
return function ( childJML ) {
if ( typeof childJML === 'string' ) {
2019-05-24 12:17:17 +00:00
node . append ( childJML ) ;
2018-11-04 07:14:53 +00:00
} else {
2019-05-24 12:17:17 +00:00
node . append ( jml . apply ( void 0 , _toConsumableArray ( childJML ) ) ) ;
2018-11-04 07:14:53 +00:00
}
} ;
2018-09-25 08:49:26 +00:00
}
/ * *
* @ private
* @ static
function _DOMfromJMLOrString ( childNodeJML ) {
if ( typeof childNodeJML === 'string' ) {
return doc . createTextNode ( childNodeJML ) ;
}
return jml ( ... childNodeJML ) ;
}
* /
/ * *
2019-05-24 12:17:17 +00:00
* @ typedef { Element | DocumentFragment } JamilihReturn
* /
/ * *
* @ typedef { GenericArray } JamilihArray
* @ property { string } 0 The element to create ( by lower - case name )
* @ property { Object } [ 1 ] Attributes to add with the key as the attribute name
* and value as the attribute value ; important for IE where the input
* element ' s type cannot be added later after already added to the page
* @ param { Element [ ] } [ children ] The optional children of this element
* ( but raw DOM elements required to be specified within arrays since
* could not otherwise be distinguished from siblings being added )
* @ param { Element } [ parent ] The optional parent to which to attach the element
* ( always the last unless followed by null , in which case it is the
* second - to - last )
* @ param { null } [ returning ] Can use null to indicate an array of elements
* should be returned
* /
/ * *
* Creates an XHTML or HTML element ( XHTML is preferred , but only in browsers
* that support ) ; any element after element can be omitted , and any subsequent
* type or types added afterwards .
* @ param { JamilihArray } args
* @ returns { JamilihReturn } The newly created ( and possibly already appended )
* element or array of elements
2018-09-25 08:49:26 +00:00
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
var jml = function jml ( ) {
2018-11-04 07:14:53 +00:00
for ( var _len2 = arguments . length , args = new Array ( _len2 ) , _key2 = 0 ; _key2 < _len2 ; _key2 ++ ) {
args [ _key2 ] = arguments [ _key2 ] ;
}
var elem = doc . createDocumentFragment ( ) ;
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { Object < { string : string } > } atts
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function _checkAtts ( atts ) {
var att ;
for ( att in atts ) {
2019-05-24 12:17:17 +00:00
if ( ! { } . hasOwnProperty . call ( atts , att ) ) {
2018-11-04 07:14:53 +00:00
continue ;
}
var attVal = atts [ att ] ;
att = att in ATTR _MAP ? ATTR _MAP [ att ] : att ;
if ( NULLABLES . includes ( att ) ) {
2019-05-24 12:17:17 +00:00
if ( ! _isNullish ( attVal ) ) {
2018-11-04 07:14:53 +00:00
elem [ att ] = attVal ;
}
continue ;
} else if ( ATTR _DOM . includes ( att ) ) {
elem [ att ] = attVal ;
continue ;
}
switch ( att ) {
/ *
Todos :
0. JSON mode to prevent event addition
0. { $xmlDocument : [ ] } // doc.implementation.createDocument
0. Accept array for any attribute with first item as prefix and second as value ?
0. { $ : [ 'xhtml' , 'div' ] } for prefixed elements
case '$' : // Element with prefix?
nodes [ nodes . length ] = elem = doc . createElementNS ( attVal [ 0 ] , attVal [ 1 ] ) ;
break ;
* /
case '#' :
{
// Document fragment
nodes [ nodes . length ] = _optsOrUndefinedJML ( opts , attVal ) ;
break ;
}
case '$shadow' :
{
var open = attVal . open ,
closed = attVal . closed ;
var content = attVal . content ,
template = attVal . template ;
var shadowRoot = elem . attachShadow ( {
mode : closed || open === false ? 'closed' : 'open'
} ) ;
if ( template ) {
if ( Array . isArray ( template ) ) {
if ( _getType ( template [ 0 ] ) === 'object' ) {
// Has attributes
template = jml . apply ( void 0 , [ 'template' ] . concat ( _toConsumableArray ( template ) , [ doc . body ] ) ) ;
} else {
// Array is for the children
template = jml ( 'template' , template , doc . body ) ;
}
} else if ( typeof template === 'string' ) {
template = $ ( template ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
jml ( template . content . cloneNode ( true ) , shadowRoot ) ;
} else {
if ( ! content ) {
content = open || closed ;
}
if ( content && typeof content !== 'boolean' ) {
if ( Array . isArray ( content ) ) {
jml ( {
'#' : content
} , shadowRoot ) ;
} else {
jml ( content , shadowRoot ) ;
}
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
break ;
}
case 'is' :
{
// Not yet supported in browsers
// Handled during element creation
break ;
}
case '$custom' :
{
Object . assign ( elem , attVal ) ;
break ;
}
case '$define' :
{
var _ret = function ( ) {
var localName = elem . localName . toLowerCase ( ) ; // Note: customized built-ins sadly not working yet
var customizedBuiltIn = ! localName . includes ( '-' ) ;
var def = customizedBuiltIn ? elem . getAttribute ( 'is' ) : localName ;
if ( customElements . get ( def ) ) {
return "break" ;
}
2019-05-24 12:17:17 +00:00
var getConstructor = function getConstructor ( cnstrct ) {
var baseClass = options && options [ "extends" ] ? doc . createElement ( options [ "extends" ] ) . constructor : customizedBuiltIn ? doc . createElement ( localName ) . constructor : HTMLElement ;
return cnstrct ?
2018-11-04 07:14:53 +00:00
/*#__PURE__*/
function ( _baseClass ) {
_inherits ( _class , _baseClass ) ;
function _class ( ) {
var _this ;
_classCallCheck ( this , _class ) ;
_this = _possibleConstructorReturn ( this , _getPrototypeOf ( _class ) . call ( this ) ) ;
2019-05-24 12:17:17 +00:00
cnstrct . call ( _assertThisInitialized ( _this ) ) ;
2018-11-04 07:14:53 +00:00
return _this ;
}
return _class ;
} ( baseClass ) :
/*#__PURE__*/
function ( _baseClass2 ) {
_inherits ( _class2 , _baseClass2 ) ;
function _class2 ( ) {
_classCallCheck ( this , _class2 ) ;
return _possibleConstructorReturn ( this , _getPrototypeOf ( _class2 ) . apply ( this , arguments ) ) ;
}
return _class2 ;
} ( baseClass ) ;
} ;
2019-05-24 12:17:17 +00:00
var cnstrctr = void 0 ,
2018-11-04 07:14:53 +00:00
options = void 0 ,
prototype = void 0 ;
if ( Array . isArray ( attVal ) ) {
if ( attVal . length <= 2 ) {
var _attVal = _slicedToArray ( attVal , 2 ) ;
2019-05-24 12:17:17 +00:00
cnstrctr = _attVal [ 0 ] ;
2018-11-04 07:14:53 +00:00
options = _attVal [ 1 ] ;
if ( typeof options === 'string' ) {
options = {
2019-05-24 12:17:17 +00:00
"extends" : options
2018-11-04 07:14:53 +00:00
} ;
2019-05-24 12:17:17 +00:00
} else if ( ! { } . hasOwnProperty . call ( options , 'extends' ) ) {
2018-11-04 07:14:53 +00:00
prototype = options ;
}
2019-05-24 12:17:17 +00:00
if ( _typeof ( cnstrctr ) === 'object' ) {
prototype = cnstrctr ;
cnstrctr = getConstructor ( ) ;
2018-11-04 07:14:53 +00:00
}
} else {
var _attVal2 = _slicedToArray ( attVal , 3 ) ;
2019-05-24 12:17:17 +00:00
cnstrctr = _attVal2 [ 0 ] ;
2018-11-04 07:14:53 +00:00
prototype = _attVal2 [ 1 ] ;
options = _attVal2 [ 2 ] ;
if ( typeof options === 'string' ) {
options = {
2019-05-24 12:17:17 +00:00
"extends" : options
2018-11-04 07:14:53 +00:00
} ;
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
} else if ( typeof attVal === 'function' ) {
2019-05-24 12:17:17 +00:00
cnstrctr = attVal ;
2018-11-04 07:14:53 +00:00
} else {
prototype = attVal ;
2019-05-24 12:17:17 +00:00
cnstrctr = getConstructor ( ) ;
2018-11-04 07:14:53 +00:00
}
2019-05-24 12:17:17 +00:00
if ( ! cnstrctr . toString ( ) . startsWith ( 'class' ) ) {
cnstrctr = getConstructor ( cnstrctr ) ;
2018-11-04 07:14:53 +00:00
}
if ( ! options && customizedBuiltIn ) {
options = {
2019-05-24 12:17:17 +00:00
"extends" : localName
2018-11-04 07:14:53 +00:00
} ;
}
if ( prototype ) {
2019-05-24 12:17:17 +00:00
Object . assign ( cnstrctr . prototype , prototype ) ;
2018-11-04 07:14:53 +00:00
}
2019-05-24 12:17:17 +00:00
customElements . define ( def , cnstrctr , customizedBuiltIn ? options : undefined ) ;
2018-11-04 07:14:53 +00:00
return "break" ;
} ( ) ;
if ( _ret === "break" ) break ;
}
case '$symbol' :
{
var _attVal3 = _slicedToArray ( attVal , 2 ) ,
symbol = _attVal3 [ 0 ] ,
func = _attVal3 [ 1 ] ;
if ( typeof func === 'function' ) {
var funcBound = func . bind ( elem ) ;
if ( typeof symbol === 'string' ) {
2019-05-24 12:17:17 +00:00
elem [ Symbol [ "for" ] ( symbol ) ] = funcBound ;
2018-11-04 07:14:53 +00:00
} else {
elem [ symbol ] = funcBound ;
}
} else {
var obj = func ;
obj . elem = elem ;
if ( typeof symbol === 'string' ) {
2019-05-24 12:17:17 +00:00
elem [ Symbol [ "for" ] ( symbol ) ] = obj ;
2018-11-04 07:14:53 +00:00
} else {
elem [ symbol ] = obj ;
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
break ;
}
case '$data' :
{
setMap ( attVal ) ;
break ;
}
case '$attribute' :
{
// Attribute node
var node = attVal . length === 3 ? doc . createAttributeNS ( attVal [ 0 ] , attVal [ 1 ] ) : doc . createAttribute ( attVal [ 0 ] ) ;
node . value = attVal [ attVal . length - 1 ] ;
nodes [ nodes . length ] = node ;
break ;
}
case '$text' :
{
// Todo: Also allow as jml(['a text node']) (or should that become a fragment)?
var _node = doc . createTextNode ( attVal ) ;
nodes [ nodes . length ] = _node ;
break ;
}
case '$document' :
{
// Todo: Conditionally create XML document
var _node2 = doc . implementation . createHTMLDocument ( ) ;
if ( attVal . childNodes ) {
2019-05-24 12:17:17 +00:00
// eslint-disable-next-line unicorn/no-fn-reference-in-iterator
2018-11-04 07:14:53 +00:00
attVal . childNodes . forEach ( _childrenToJML ( _node2 ) ) ; // Remove any extra nodes created by createHTMLDocument().
var j = attVal . childNodes . length ;
while ( _node2 . childNodes [ j ] ) {
var cn = _node2 . childNodes [ j ] ;
2019-05-24 12:17:17 +00:00
cn . remove ( ) ;
2018-11-04 07:14:53 +00:00
j ++ ;
}
} else {
if ( attVal . $DOCTYPE ) {
var dt = {
$DOCTYPE : attVal . $DOCTYPE
} ;
var doctype = jml ( dt ) ;
_node2 . firstChild . replaceWith ( doctype ) ;
}
var html = _node2 . childNodes [ 1 ] ;
var head = html . childNodes [ 0 ] ;
var _body = html . childNodes [ 1 ] ;
if ( attVal . title || attVal . head ) {
var meta = doc . createElement ( 'meta' ) ;
meta . setAttribute ( 'charset' , 'utf-8' ) ;
2019-05-24 12:17:17 +00:00
head . append ( meta ) ;
2018-11-04 07:14:53 +00:00
}
if ( attVal . title ) {
_node2 . title = attVal . title ; // Appends after meta
}
if ( attVal . head ) {
2019-05-24 12:17:17 +00:00
// eslint-disable-next-line unicorn/no-fn-reference-in-iterator
2018-11-04 07:14:53 +00:00
attVal . head . forEach ( _appendJML ( head ) ) ;
}
if ( attVal . body ) {
2019-05-24 12:17:17 +00:00
// eslint-disable-next-line unicorn/no-fn-reference-in-iterator
2018-11-04 07:14:53 +00:00
attVal . body . forEach ( _appendJMLOrText ( _body ) ) ;
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
nodes [ nodes . length ] = _node2 ;
break ;
}
case '$DOCTYPE' :
{
/ *
// Todo:
if ( attVal . internalSubset ) {
node = { } ;
}
else
* /
var _node3 = void 0 ;
if ( attVal . entities || attVal . notations ) {
_node3 = {
name : attVal . name ,
nodeName : attVal . name ,
nodeValue : null ,
nodeType : 10 ,
2019-05-24 12:17:17 +00:00
// eslint-disable-next-line unicorn/no-fn-reference-in-iterator
2018-11-04 07:14:53 +00:00
entities : attVal . entities . map ( _jmlSingleArg ) ,
2019-05-24 12:17:17 +00:00
// eslint-disable-next-line unicorn/no-fn-reference-in-iterator
2018-11-04 07:14:53 +00:00
notations : attVal . notations . map ( _jmlSingleArg ) ,
publicId : attVal . publicId ,
systemId : attVal . systemId // internalSubset: // Todo
} ;
} else {
_node3 = doc . implementation . createDocumentType ( attVal . name , attVal . publicId || '' , attVal . systemId || '' ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
nodes [ nodes . length ] = _node3 ;
break ;
}
case '$ENTITY' :
{
/ *
// Todo: Should we auto-copy another node's properties/methods (like DocumentType) excluding or changing its non-entity node values?
const node = {
nodeName : attVal . name ,
nodeValue : null ,
publicId : attVal . publicId ,
systemId : attVal . systemId ,
notationName : attVal . notationName ,
nodeType : 6 ,
childNodes : attVal . childNodes . map ( _DOMfromJMLOrString )
} ;
* /
break ;
}
case '$NOTATION' :
{
// Todo: We could add further properties/methods, but unlikely to be used as is.
var _node4 = {
nodeName : attVal [ 0 ] ,
publicID : attVal [ 1 ] ,
systemID : attVal [ 2 ] ,
nodeValue : null ,
nodeType : 12
} ;
nodes [ nodes . length ] = _node4 ;
break ;
}
case '$on' :
{
// Events
for ( var p2 in attVal ) {
2019-05-24 12:17:17 +00:00
if ( { } . hasOwnProperty . call ( attVal , p2 ) ) {
2018-11-04 07:14:53 +00:00
var val = attVal [ p2 ] ;
if ( typeof val === 'function' ) {
val = [ val , false ] ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( typeof val [ 0 ] === 'function' ) {
_addEvent ( elem , p2 , val [ 0 ] , val [ 1 ] ) ; // element, event name, handler, capturing
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
}
}
break ;
}
case 'className' :
case 'class' :
2019-05-24 12:17:17 +00:00
if ( ! _isNullish ( attVal ) ) {
2018-11-04 07:14:53 +00:00
elem . className = attVal ;
}
break ;
case 'dataset' :
{
var _ret2 = function ( ) {
// Map can be keyed with hyphenated or camel-cased properties
2019-05-24 12:17:17 +00:00
var recurse = function recurse ( atVal , startProp ) {
2018-11-04 07:14:53 +00:00
var prop = '' ;
var pastInitialProp = startProp !== '' ;
2019-05-24 12:17:17 +00:00
Object . keys ( atVal ) . forEach ( function ( key ) {
var value = atVal [ key ] ;
2018-11-04 07:14:53 +00:00
if ( pastInitialProp ) {
prop = startProp + key . replace ( hyphenForCamelCase , _upperCase ) . replace ( /^([a-z])/ , _upperCase ) ;
} else {
prop = startProp + key . replace ( hyphenForCamelCase , _upperCase ) ;
}
if ( value === null || _typeof ( value ) !== 'object' ) {
2019-05-24 12:17:17 +00:00
if ( ! _isNullish ( value ) ) {
2018-11-04 07:14:53 +00:00
elem . dataset [ prop ] = value ;
}
prop = startProp ;
return ;
}
recurse ( value , prop ) ;
} ) ;
} ;
recurse ( attVal , '' ) ;
return "break" ; // Todo: Disable this by default unless configuration explicitly allows (for security)
} ( ) ;
2019-05-24 12:17:17 +00:00
if ( _ret2 === "break" ) break ;
2018-11-04 07:14:53 +00:00
}
// #if IS_REMOVE
// Don't remove this `if` block (for sake of no-innerHTML build)
case 'innerHTML' :
2019-05-24 12:17:17 +00:00
if ( ! _isNullish ( attVal ) ) {
2018-11-04 07:14:53 +00:00
elem . innerHTML = attVal ;
}
break ;
// #endif
case 'htmlFor' :
case 'for' :
if ( elStr === 'label' ) {
2019-05-24 12:17:17 +00:00
if ( ! _isNullish ( attVal ) ) {
2018-11-04 07:14:53 +00:00
elem . htmlFor = attVal ;
}
break ;
}
elem . setAttribute ( att , attVal ) ;
break ;
case 'xmlns' :
// Already handled
break ;
default :
2019-05-24 12:17:17 +00:00
{
if ( att . startsWith ( 'on' ) ) {
elem [ att ] = attVal ; // _addEvent(elem, att.slice(2), attVal, false); // This worked, but perhaps the user wishes only one event
2018-11-04 07:14:53 +00:00
break ;
}
2019-05-24 12:17:17 +00:00
if ( att === 'style' ) {
if ( _isNullish ( attVal ) ) {
break ;
}
if ( _typeof ( attVal ) === 'object' ) {
for ( var _p in attVal ) {
if ( { } . hasOwnProperty . call ( attVal , _p ) && ! _isNullish ( attVal [ _p ] ) ) {
// Todo: Handle aggregate properties like "border"
if ( _p === 'float' ) {
elem . style . cssFloat = attVal [ _p ] ;
elem . style . styleFloat = attVal [ _p ] ; // Harmless though we could make conditional on older IE instead
} else {
elem . style [ _p . replace ( hyphenForCamelCase , _upperCase ) ] = attVal [ _p ] ;
}
2018-11-04 07:14:53 +00:00
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
break ;
} // setAttribute unfortunately erases any existing styles
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
elem . setAttribute ( att , attVal ) ;
/ *
// The following reorders which is troublesome for serialization, e.g., as used in our testing
if ( elem . style . cssText !== undefined ) {
elem . style . cssText += attVal ;
} else { // Opera
elem . style += attVal ;
}
* /
break ;
2018-11-04 07:14:53 +00:00
}
2019-05-24 12:17:17 +00:00
var matchingPlugin = opts && opts . $plugins && opts . $plugins . find ( function ( p ) {
return p . name === att ;
} ) ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
if ( matchingPlugin ) {
matchingPlugin . set ( {
element : elem ,
attribute : {
name : att ,
value : attVal
}
} ) ;
break ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
elem . setAttribute ( att , attVal ) ;
2018-11-04 07:14:53 +00:00
break ;
}
}
}
}
var nodes = [ ] ;
var elStr ;
var opts ;
var isRoot = false ;
if ( _getType ( args [ 0 ] ) === 'object' && Object . keys ( args [ 0 ] ) . some ( function ( key ) {
return possibleOptions . includes ( key ) ;
} ) ) {
opts = args [ 0 ] ;
if ( opts . state !== 'child' ) {
isRoot = true ;
opts . state = 'child' ;
}
if ( opts . $map && ! opts . $map . root && opts . $map . root !== false ) {
opts . $map = {
root : opts . $map
} ;
}
if ( '$plugins' in opts ) {
if ( ! Array . isArray ( opts . $plugins ) ) {
2019-05-24 12:17:17 +00:00
throw new TypeError ( '$plugins must be an array' ) ;
2018-11-04 07:14:53 +00:00
}
opts . $plugins . forEach ( function ( pluginObj ) {
if ( ! pluginObj ) {
throw new TypeError ( 'Plugin must be an object' ) ;
}
if ( ! pluginObj . name || ! pluginObj . name . startsWith ( '$_' ) ) {
throw new TypeError ( 'Plugin object name must be present and begin with `$_`' ) ;
}
if ( typeof pluginObj . set !== 'function' ) {
throw new TypeError ( 'Plugin object must have a `set` method' ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
} ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
args = args . slice ( 1 ) ;
}
var argc = args . length ;
var defaultMap = opts && opts . $map && opts . $map . root ;
var setMap = function setMap ( dataVal ) {
var map , obj ; // Boolean indicating use of default map and object
if ( dataVal === true ) {
var _defaultMap = _slicedToArray ( defaultMap , 2 ) ;
map = _defaultMap [ 0 ] ;
obj = _defaultMap [ 1 ] ;
} else if ( Array . isArray ( dataVal ) ) {
// Array of strings mapping to default
if ( typeof dataVal [ 0 ] === 'string' ) {
dataVal . forEach ( function ( dVal ) {
setMap ( opts . $map [ dVal ] ) ;
} ) ; // Array of Map and non-map data object
} else {
map = dataVal [ 0 ] || defaultMap [ 0 ] ;
obj = dataVal [ 1 ] || defaultMap [ 1 ] ;
} // Map
2019-05-24 12:17:17 +00:00
/* eslint-disable-next-line unicorn/no-unsafe-regex */
2018-11-04 07:14:53 +00:00
} else if ( /^\[object (?:Weak)?Map\]$/ . test ( [ ] . toString . call ( dataVal ) ) ) {
map = dataVal ;
obj = defaultMap [ 1 ] ; // Non-map data object
} else {
map = defaultMap [ 0 ] ;
obj = dataVal ;
}
map . set ( elem , obj ) ;
} ;
for ( var i = 0 ; i < argc ; i ++ ) {
var arg = args [ i ] ;
switch ( _getType ( arg ) ) {
2019-05-24 12:17:17 +00:00
default :
// Todo: Throw here instead?
break ;
2018-11-04 07:14:53 +00:00
case 'null' :
// null always indicates a place-holder (only needed for last argument if want array returned)
if ( i === argc - 1 ) {
_applyAnyStylesheet ( nodes [ 0 ] ) ; // We have to execute any stylesheets even if not appending or otherwise IE will never apply them
// Todo: Fix to allow application of stylesheets of style tags within fragments?
2019-05-24 12:17:17 +00:00
return nodes . length <= 1 ? nodes [ 0 ] // eslint-disable-next-line unicorn/no-fn-reference-in-iterator
: nodes . reduce ( _fragReducer , doc . createDocumentFragment ( ) ) ; // nodes;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
break ;
case 'string' :
// Strings indicate elements
switch ( arg ) {
case '!' :
nodes [ nodes . length ] = doc . createComment ( args [ ++ i ] ) ;
break ;
case '?' :
2019-05-24 12:17:17 +00:00
{
arg = args [ ++ i ] ;
var procValue = args [ ++ i ] ;
var val = procValue ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
if ( _typeof ( val ) === 'object' ) {
procValue = [ ] ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
for ( var p in val ) {
if ( { } . hasOwnProperty . call ( val , p ) ) {
procValue . push ( p + '=' + '"' + // https://www.w3.org/TR/xml-stylesheet/#NT-PseudoAttValue
val [ p ] . replace ( /"/g , '"' ) + '"' ) ;
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
procValue = procValue . join ( ' ' ) ;
} // Firefox allows instructions with ">" in this method, but not if placed directly!
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
try {
nodes [ nodes . length ] = doc . createProcessingInstruction ( arg , procValue ) ;
} catch ( e ) {
// Getting NotSupportedError in IE, so we try to imitate a processing instruction with a comment
// innerHTML didn't work
// var elContainer = doc.createElement('div');
// elContainer.innerHTML = '<?' + doc.createTextNode(arg + ' ' + procValue).nodeValue + '?>';
// nodes[nodes.length] = elContainer.innerHTML;
// Todo: any other way to resolve? Just use XML?
nodes [ nodes . length ] = doc . createComment ( '?' + arg + ' ' + procValue + '?' ) ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
break ; // Browsers don't support doc.createEntityReference, so we just use this as a convenience
}
2018-11-04 07:14:53 +00:00
case '&' :
nodes [ nodes . length ] = _createSafeReference ( 'entity' , '' , args [ ++ i ] ) ;
break ;
case '#' :
// // Decimal character reference - ['#', '01234'] // Ӓ // probably easier to use JavaScript Unicode escapes
nodes [ nodes . length ] = _createSafeReference ( 'decimal' , arg , String ( args [ ++ i ] ) ) ;
break ;
case '#x' :
// Hex character reference - ['#x', '123a'] // ሺ // probably easier to use JavaScript Unicode escapes
nodes [ nodes . length ] = _createSafeReference ( 'hexadecimal' , arg , args [ ++ i ] ) ;
break ;
case '![' :
// '![', ['escaped <&> text'] // <![CDATA[escaped <&> text]]>
// CDATA valid in XML only, so we'll just treat as text for mutual compatibility
// Todo: config (or detection via some kind of doc.documentType property?) of whether in XML
try {
nodes [ nodes . length ] = doc . createCDATASection ( args [ ++ i ] ) ;
} catch ( e2 ) {
nodes [ nodes . length ] = doc . createTextNode ( args [ i ] ) ; // i already incremented
}
break ;
case '' :
nodes [ nodes . length ] = doc . createDocumentFragment ( ) ;
break ;
default :
{
// An element
elStr = arg ;
2019-05-24 12:17:17 +00:00
var atts = args [ i + 1 ] ; // Todo: Fix this to depend on XML/config, not availability of methods
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
if ( _getType ( atts ) === 'object' && atts . is ) {
var is = atts . is ;
2018-11-04 07:14:53 +00:00
if ( doc . createElementNS ) {
elem = doc . createElementNS ( NS _HTML , elStr , {
is : is
} ) ;
2018-09-25 08:49:26 +00:00
} else {
2018-11-04 07:14:53 +00:00
elem = doc . createElement ( elStr , {
is : is
} ) ;
2018-09-25 08:49:26 +00:00
}
2019-05-24 12:17:17 +00:00
} else if ( doc . createElementNS ) {
elem = doc . createElementNS ( NS _HTML , elStr ) ;
2018-11-04 07:14:53 +00:00
} else {
2019-05-24 12:17:17 +00:00
elem = doc . createElement ( elStr ) ;
2018-11-04 07:14:53 +00:00
}
nodes [ nodes . length ] = elem ; // Add to parent
break ;
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
break ;
case 'object' :
2019-05-24 12:17:17 +00:00
{
// Non-DOM-element objects indicate attribute-value pairs
var _atts = arg ;
if ( _atts . xmlns !== undefined ) {
// We handle this here, as otherwise may lose events, etc.
// As namespace of element already set as XHTML, we need to change the namespace
// elem.setAttribute('xmlns', atts.xmlns); // Doesn't work
// Can't set namespaceURI dynamically, renameNode() is not supported, and setAttribute() doesn't work to change the namespace, so we resort to this hack
var replacer = void 0 ;
if ( _typeof ( _atts . xmlns ) === 'object' ) {
replacer = _replaceDefiner ( _atts . xmlns ) ;
} else {
replacer = ' xmlns="' + _atts . xmlns + '"' ;
} // try {
// Also fix DOMParser to work with text/html
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
elem = nodes [ nodes . length - 1 ] = new DOMParser ( ) . parseFromString ( new XmlSerializer ( ) . serializeToString ( elem ) // Mozilla adds XHTML namespace
. replace ( ' xmlns="' + NS _HTML + '"' , replacer ) , 'application/xml' ) . documentElement ; // }catch(e) {alert(elem.outerHTML);throw e;}
} // eslint-disable-next-line unicorn/no-fn-reference-in-iterator
var orderedArr = _atts . $a ? _atts . $a . map ( _copyOrderedAtts ) : [ _atts ] ; // eslint-disable-next-line unicorn/no-fn-reference-in-iterator
orderedArr . forEach ( _checkAtts ) ;
break ;
}
2018-11-04 07:14:53 +00:00
case 'fragment' :
case 'element' :
/ *
1 ) Last element always the parent ( put null if don ' t want parent and want to return array ) unless only atts and children ( no other elements )
2 ) Individual elements ( DOM elements or sequences of string [ / o b j e c t / a r r a y ] ) g e t a d d e d t o p a r e n t f i r s t - i n , f i r s t - a d d e d
* /
if ( i === 0 ) {
// Allow wrapping of element
elem = arg ;
}
if ( i === argc - 1 || i === argc - 2 && args [ i + 1 ] === null ) {
// parent
var elsl = nodes . length ;
for ( var k = 0 ; k < elsl ; k ++ ) {
_appendNode ( arg , nodes [ k ] ) ;
} // Todo: Apply stylesheets if any style tags were added elsewhere besides the first element?
_applyAnyStylesheet ( nodes [ 0 ] ) ; // We have to execute any stylesheets even if not appending or otherwise IE will never apply them
} else {
nodes [ nodes . length ] = arg ;
}
break ;
case 'array' :
2019-05-24 12:17:17 +00:00
{
// Arrays or arrays of arrays indicate child nodes
var child = arg ;
var cl = child . length ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
for ( var j = 0 ; j < cl ; j ++ ) {
// Go through children array container to handle elements
var childContent = child [ j ] ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
var childContentType = _typeof ( childContent ) ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
if ( childContent === undefined ) {
throw String ( 'Parent array:' + JSON . stringify ( args ) + '; child: ' + child + '; index:' + j ) ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
switch ( childContentType ) {
// Todo: determine whether null or function should have special handling or be converted to text
case 'string' :
case 'number' :
case 'boolean' :
_appendNode ( elem , doc . createTextNode ( childContent ) ) ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
break ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
default :
if ( Array . isArray ( childContent ) ) {
// Arrays representing child elements
_appendNode ( elem , _optsOrUndefinedJML . apply ( void 0 , [ opts ] . concat ( _toConsumableArray ( childContent ) ) ) ) ;
} else if ( childContent [ '#' ] ) {
// Fragment
_appendNode ( elem , _optsOrUndefinedJML ( opts , childContent [ '#' ] ) ) ;
} else {
// Single DOM element children
_appendNode ( elem , childContent ) ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
break ;
}
2018-11-04 07:14:53 +00:00
}
2019-05-24 12:17:17 +00:00
break ;
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
}
var ret = nodes [ 0 ] || elem ;
if ( opts && isRoot && opts . $map && opts . $map . root ) {
setMap ( true ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
return ret ;
} ;
2018-09-25 08:49:26 +00:00
/ * *
2019-05-24 12:17:17 +00:00
* Converts a DOM object or a string of HTML into a Jamilih object ( or string ) .
2018-09-25 08:49:26 +00:00
* @ param { string | HTMLElement } [ dom = document . documentElement ] Defaults to converting the current document .
* @ param { object } [ config = { stringOutput : false } ] Configuration object
* @ param { boolean } [ config . stringOutput = false ] Whether to output the Jamilih object as a string .
2019-05-24 12:17:17 +00:00
* @ returns { Array | string } Array containing the elements which represent a Jamilih object , or ,
2018-09-25 08:49:26 +00:00
if ` stringOutput ` is true , it will be the stringified version of
such an object
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . toJML = function ( dom , config ) {
2018-11-04 07:14:53 +00:00
config = config || {
stringOutput : false
} ;
if ( typeof dom === 'string' ) {
dom = new DOMParser ( ) . parseFromString ( dom , 'text/html' ) ; // todo: Give option for XML once implemented and change JSDoc to allow for Element
}
var ret = [ ] ;
var parent = ret ;
var parentIdx = 0 ;
2019-05-24 12:17:17 +00:00
/ * *
*
* @ throws { DOMException }
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function invalidStateError ( ) {
// These are probably only necessary if working with text/html
2019-05-24 12:17:17 +00:00
// eslint-disable-next-line no-shadow
var DOMException = function DOMException ( ) {
_classCallCheck ( this , DOMException ) ;
} ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
{
// INVALID_STATE_ERR per section 9.3 XHTML 5: http://www.w3.org/TR/html5/the-xhtml-syntax.html
// Since we can't instantiate without this (at least in Mozilla), this mimicks at least (good idea?)
var e = new DOMException ( ) ;
e . code = 11 ;
throw e ;
}
}
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { DocumentType | Entity | Notation } obj
* @ param { Node } node
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function addExternalID ( obj , node ) {
if ( node . systemId . includes ( '"' ) && node . systemId . includes ( "'" ) ) {
invalidStateError ( ) ;
}
2019-05-24 12:17:17 +00:00
var publicId = node . publicId ,
systemId = node . systemId ;
2018-11-04 07:14:53 +00:00
if ( systemId ) {
obj . systemId = systemId ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
if ( publicId ) {
obj . publicId = publicId ;
}
}
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { * } val
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function set ( val ) {
parent [ parentIdx ] = val ;
parentIdx ++ ;
}
2019-05-24 12:17:17 +00:00
/ * *
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function setChildren ( ) {
set ( [ ] ) ;
parent = parent [ parentIdx - 1 ] ;
parentIdx = 0 ;
}
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { string } prop1
* @ param { string } prop2
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function setObj ( prop1 , prop2 ) {
parent = parent [ parentIdx - 1 ] [ prop1 ] ;
parentIdx = 0 ;
if ( prop2 ) {
parent = parent [ prop2 ] ;
}
}
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { Node } node
* @ param { object < { string : string } > } namespaces
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function parseDOM ( node , namespaces ) {
// namespaces = clone(namespaces) || {}; // Ensure we're working with a copy, so different levels in the hierarchy can treat it differently
/ *
if ( ( node . prefix && node . prefix . includes ( ':' ) ) || ( node . localName && node . localName . includes ( ':' ) ) ) {
invalidStateError ( ) ;
}
* /
var type = 'nodeType' in node ? node . nodeType : null ;
2019-05-24 12:17:17 +00:00
namespaces = _objectSpread ( { } , namespaces ) ;
var xmlChars = /([\t\n\r -\uD7FF\uE000-\uFFFD]|(?:[\uD800-\uDBFF](?![\uDC00-\uDFFF]))(?:(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))*$/ ; // eslint-disable-line no-control-regex
2018-11-04 07:14:53 +00:00
if ( [ 2 , 3 , 4 , 7 , 8 ] . includes ( type ) && ! xmlChars . test ( node . nodeValue ) ) {
invalidStateError ( ) ;
}
var children , start , tmpParent , tmpParentIdx ;
2019-05-24 12:17:17 +00:00
/ * *
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function setTemp ( ) {
tmpParent = parent ;
tmpParentIdx = parentIdx ;
}
2019-05-24 12:17:17 +00:00
/ * *
* @ returns { void }
* /
2018-11-04 07:14:53 +00:00
function resetTemp ( ) {
parent = tmpParent ;
parentIdx = tmpParentIdx ;
parentIdx ++ ; // Increment index in parent container of this element
}
switch ( type ) {
case 1 :
2019-05-24 12:17:17 +00:00
{
// ELEMENT
setTemp ( ) ;
var nodeName = node . nodeName . toLowerCase ( ) ; // Todo: for XML, should not lower-case
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
setChildren ( ) ; // Build child array since elements are, except at the top level, encapsulated in arrays
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
set ( nodeName ) ;
start = { } ;
var hasNamespaceDeclaration = false ;
if ( namespaces [ node . prefix || '' ] !== node . namespaceURI ) {
namespaces [ node . prefix || '' ] = node . namespaceURI ;
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
if ( node . prefix ) {
start [ 'xmlns:' + node . prefix ] = node . namespaceURI ;
} else if ( node . namespaceURI ) {
start . xmlns = node . namespaceURI ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
hasNamespaceDeclaration = true ;
2018-11-04 07:14:53 +00:00
}
2019-05-24 12:17:17 +00:00
if ( node . attributes . length ) {
set ( _toConsumableArray ( node . attributes ) . reduce ( function ( obj , att ) {
obj [ att . name ] = att . value ; // Attr.nodeName and Attr.nodeValue are deprecated as of DOM4 as Attr no longer inherits from Node, so we can safely use name and value
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
return obj ;
} , start ) ) ;
} else if ( hasNamespaceDeclaration ) {
set ( start ) ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
children = node . childNodes ;
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
if ( children . length ) {
setChildren ( ) ; // Element children array container
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
_toConsumableArray ( children ) . forEach ( function ( childNode ) {
parseDOM ( childNode , namespaces ) ;
} ) ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
resetTemp ( ) ;
break ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
case undefined : // Treat as attribute node until this is fixed: https://github.com/tmpvar/jsdom/issues/1641 / https://github.com/tmpvar/jsdom/pull/1822
case 2 :
// ATTRIBUTE (should only get here if passing in an attribute node)
set ( {
$attribute : [ node . namespaceURI , node . name , node . value ]
} ) ;
break ;
case 3 :
// TEXT
2019-05-24 12:17:17 +00:00
if ( config . stripWhitespace && /^[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+$/ . test ( node . nodeValue ) ) {
2018-11-04 07:14:53 +00:00
return ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
set ( node . nodeValue ) ;
break ;
case 4 :
// CDATA
if ( node . nodeValue . includes ( ']]' + '>' ) ) {
invalidStateError ( ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
set ( [ '![' , node . nodeValue ] ) ;
break ;
case 5 :
// ENTITY REFERENCE (probably not used in browsers since already resolved)
set ( [ '&' , node . nodeName ] ) ;
break ;
case 6 :
// ENTITY (would need to pass in directly)
setTemp ( ) ;
start = { } ;
if ( node . xmlEncoding || node . xmlVersion ) {
// an external entity file?
start . $ENTITY = {
name : node . nodeName ,
version : node . xmlVersion ,
encoding : node . xmlEncoding
} ;
} else {
start . $ENTITY = {
name : node . nodeName
} ;
if ( node . publicId || node . systemId ) {
// External Entity?
addExternalID ( start . $ENTITY , node ) ;
if ( node . notationName ) {
start . $ENTITY . NDATA = node . notationName ;
}
}
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
set ( start ) ;
children = node . childNodes ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
if ( children . length ) {
start . $ENTITY . childNodes = [ ] ; // Set position to $ENTITY's childNodes array children
setObj ( '$ENTITY' , 'childNodes' ) ;
2019-05-24 12:17:17 +00:00
_toConsumableArray ( children ) . forEach ( function ( childNode ) {
2018-11-04 07:14:53 +00:00
parseDOM ( childNode , namespaces ) ;
} ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
resetTemp ( ) ;
break ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
case 7 :
// PROCESSING INSTRUCTION
if ( /^xml$/i . test ( node . target ) ) {
invalidStateError ( ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( node . target . includes ( '?>' ) ) {
invalidStateError ( ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( node . target . includes ( ':' ) ) {
invalidStateError ( ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
if ( node . data . includes ( '?>' ) ) {
invalidStateError ( ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
set ( [ '?' , node . target , node . data ] ) ; // Todo: Could give option to attempt to convert value back into object if has pseudo-attributes
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
break ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
case 8 :
// COMMENT
if ( node . nodeValue . includes ( '--' ) || node . nodeValue . length && node . nodeValue . lastIndexOf ( '-' ) === node . nodeValue . length - 1 ) {
invalidStateError ( ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
set ( [ '!' , node . nodeValue ] ) ;
break ;
case 9 :
2019-05-24 12:17:17 +00:00
{
// DOCUMENT
setTemp ( ) ;
var docObj = {
$document : {
childNodes : [ ]
}
} ;
if ( config . xmlDeclaration ) {
docObj . $document . xmlDeclaration = {
version : doc . xmlVersion ,
encoding : doc . xmlEncoding ,
standAlone : doc . xmlStandalone
} ;
2018-11-04 07:14:53 +00:00
}
2019-05-24 12:17:17 +00:00
set ( docObj ) ; // doc.implementation.createHTMLDocument
// Set position to fragment's array children
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
setObj ( '$document' , 'childNodes' ) ;
children = node . childNodes ;
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
if ( ! children . length ) {
invalidStateError ( ) ;
} // set({$xmlDocument: []}); // doc.implementation.createDocument // Todo: use this conditionally
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
_toConsumableArray ( children ) . forEach ( function ( childNode ) {
// Can't just do documentElement as there may be doctype, comments, etc.
// No need for setChildren, as we have already built the container array
parseDOM ( childNode , namespaces ) ;
} ) ;
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
resetTemp ( ) ;
break ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
case 10 :
2019-05-24 12:17:17 +00:00
{
// DOCUMENT TYPE
setTemp ( ) ; // Can create directly by doc.implementation.createDocumentType
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
start = {
$DOCTYPE : {
name : node . name
}
} ;
if ( node . internalSubset ) {
start . internalSubset = node . internalSubset ;
2018-11-04 07:14:53 +00:00
}
2019-05-24 12:17:17 +00:00
var pubIdChar = /^( |\r|\n|[0-9A-Za-z]|[!#-%'-\/:;=\?@_])*$/ ; // eslint-disable-line no-control-regex
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
if ( ! pubIdChar . test ( node . publicId ) ) {
invalidStateError ( ) ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
addExternalID ( start . $DOCTYPE , node ) ; // Fit in internal subset along with entities?: probably don't need as these would only differ if from DTD, and we're not rebuilding the DTD
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
set ( start ) ; // Auto-generate the internalSubset instead? Avoid entities/notations in favor of array to preserve order?
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
var entities = node . entities ; // Currently deprecated
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
if ( entities && entities . length ) {
start . $DOCTYPE . entities = [ ] ;
setObj ( '$DOCTYPE' , 'entities' ) ;
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
_toConsumableArray ( entities ) . forEach ( function ( entity ) {
parseDOM ( entity , namespaces ) ;
} ) ; // Reset for notations
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
parent = tmpParent ;
parentIdx = tmpParentIdx + 1 ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
var notations = node . notations ; // Currently deprecated
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
if ( notations && notations . length ) {
start . $DOCTYPE . notations = [ ] ;
setObj ( '$DOCTYPE' , 'notations' ) ;
_toConsumableArray ( notations ) . forEach ( function ( notation ) {
parseDOM ( notation , namespaces ) ;
} ) ;
}
resetTemp ( ) ;
break ;
}
2018-11-04 07:14:53 +00:00
case 11 :
// DOCUMENT FRAGMENT
setTemp ( ) ;
set ( {
'#' : [ ]
} ) ; // Set position to fragment's array children
setObj ( '#' ) ;
children = node . childNodes ;
2019-05-24 12:17:17 +00:00
_toConsumableArray ( children ) . forEach ( function ( childNode ) {
2018-11-04 07:14:53 +00:00
// No need for setChildren, as we have already built the container array
parseDOM ( childNode , namespaces ) ;
} ) ;
2019-05-24 12:17:17 +00:00
2018-11-04 07:14:53 +00:00
resetTemp ( ) ;
break ;
case 12 :
// NOTATION
start = {
$NOTATION : {
name : node . nodeName
}
} ;
addExternalID ( start . $NOTATION , node ) ;
set ( start ) ;
break ;
default :
throw new TypeError ( 'Not an XML type' ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
}
parseDOM ( dom , { } ) ;
if ( config . stringOutput ) {
return JSON . stringify ( ret [ 0 ] ) ;
}
return ret [ 0 ] ;
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . toJMLString = function ( dom , config ) {
2018-11-04 07:14:53 +00:00
return jml . toJML ( dom , Object . assign ( config || { } , {
stringOutput : true
} ) ) ;
2018-09-25 08:49:26 +00:00
} ;
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { JamilihArray } args
* @ returns { JamilihReturn }
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . toDOM = function ( ) {
2018-11-04 07:14:53 +00:00
// Alias for jml()
return jml . apply ( void 0 , arguments ) ;
2018-09-25 08:49:26 +00:00
} ;
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { JamilihArray } args
* @ returns { string }
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . toHTML = function ( ) {
2018-11-04 07:14:53 +00:00
// Todo: Replace this with version of jml() that directly builds a string
var ret = jml . apply ( void 0 , arguments ) ; // Todo: deal with serialization of properties like 'selected', 'checked', 'value', 'defaultValue', 'for', 'dataset', 'on*', 'style'! (i.e., need to build a string ourselves)
return ret . outerHTML ;
2018-09-25 08:49:26 +00:00
} ;
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { JamilihArray } args
* @ returns { string }
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . toDOMString = function ( ) {
2018-11-04 07:14:53 +00:00
// Alias for jml.toHTML for parity with jml.toJMLString
return jml . toHTML . apply ( jml , arguments ) ;
2018-09-25 08:49:26 +00:00
} ;
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { JamilihArray } args
* @ returns { string }
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . toXML = function ( ) {
2018-11-04 07:14:53 +00:00
var ret = jml . apply ( void 0 , arguments ) ;
return new XmlSerializer ( ) . serializeToString ( ret ) ;
2018-09-25 08:49:26 +00:00
} ;
2019-05-24 12:17:17 +00:00
/ * *
*
* @ param { JamilihArray } args
* @ returns { string }
* /
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . toXMLDOMString = function ( ) {
2018-11-04 07:14:53 +00:00
// Alias for jml.toXML for parity with jml.toJMLString
return jml . toXML . apply ( jml , arguments ) ;
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
var JamilihMap =
/*#__PURE__*/
function ( _Map ) {
_inherits ( JamilihMap , _Map ) ;
function JamilihMap ( ) {
_classCallCheck ( this , JamilihMap ) ;
return _possibleConstructorReturn ( this , _getPrototypeOf ( JamilihMap ) . apply ( this , arguments ) ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
_createClass ( JamilihMap , [ {
key : "get" ,
2019-05-24 12:17:17 +00:00
value : function get ( elem ) {
2018-11-04 07:14:53 +00:00
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
return _get ( _getPrototypeOf ( JamilihMap . prototype ) , "get" , this ) . call ( this , elem ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
} , {
key : "set" ,
value : function set ( elem , value ) {
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
return _get ( _getPrototypeOf ( JamilihMap . prototype ) , "set" , this ) . call ( this , elem , value ) ;
}
} , {
key : "invoke" ,
value : function invoke ( elem , methodName ) {
var _this$get ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
for ( var _len3 = arguments . length , args = new Array ( _len3 > 2 ? _len3 - 2 : 0 ) , _key3 = 2 ; _key3 < _len3 ; _key3 ++ ) {
args [ _key3 - 2 ] = arguments [ _key3 ] ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
return ( _this$get = this . get ( elem ) ) [ methodName ] . apply ( _this$get , [ elem ] . concat ( args ) ) ;
}
} ] ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
return JamilihMap ;
} ( _wrapNativeSuper ( Map ) ) ;
var JamilihWeakMap =
/*#__PURE__*/
function ( _WeakMap ) {
_inherits ( JamilihWeakMap , _WeakMap ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
function JamilihWeakMap ( ) {
_classCallCheck ( this , JamilihWeakMap ) ;
return _possibleConstructorReturn ( this , _getPrototypeOf ( JamilihWeakMap ) . apply ( this , arguments ) ) ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
_createClass ( JamilihWeakMap , [ {
key : "get" ,
2019-05-24 12:17:17 +00:00
value : function get ( elem ) {
2018-11-04 07:14:53 +00:00
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
return _get ( _getPrototypeOf ( JamilihWeakMap . prototype ) , "get" , this ) . call ( this , elem ) ;
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
} , {
key : "set" ,
value : function set ( elem , value ) {
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
return _get ( _getPrototypeOf ( JamilihWeakMap . prototype ) , "set" , this ) . call ( this , elem , value ) ;
}
} , {
key : "invoke" ,
value : function invoke ( elem , methodName ) {
var _this$get2 ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
for ( var _len4 = arguments . length , args = new Array ( _len4 > 2 ? _len4 - 2 : 0 ) , _key4 = 2 ; _key4 < _len4 ; _key4 ++ ) {
args [ _key4 - 2 ] = arguments [ _key4 ] ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
return ( _this$get2 = this . get ( elem ) ) [ methodName ] . apply ( _this$get2 , [ elem ] . concat ( args ) ) ;
}
} ] ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
return JamilihWeakMap ;
} ( _wrapNativeSuper ( WeakMap ) ) ;
2018-09-25 08:49:26 +00:00
jml . Map = JamilihMap ;
jml . WeakMap = JamilihWeakMap ;
jml . weak = function ( obj ) {
2018-11-04 07:14:53 +00:00
var map = new JamilihWeakMap ( ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
for ( var _len5 = arguments . length , args = new Array ( _len5 > 1 ? _len5 - 1 : 0 ) , _key5 = 1 ; _key5 < _len5 ; _key5 ++ ) {
args [ _key5 - 1 ] = arguments [ _key5 ] ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
var elem = jml . apply ( void 0 , [ {
$map : [ map , obj ]
} ] . concat ( args ) ) ;
return [ map , elem ] ;
2018-09-25 08:49:26 +00:00
} ;
jml . strong = function ( obj ) {
2018-11-04 07:14:53 +00:00
var map = new JamilihMap ( ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
for ( var _len6 = arguments . length , args = new Array ( _len6 > 1 ? _len6 - 1 : 0 ) , _key6 = 1 ; _key6 < _len6 ; _key6 ++ ) {
args [ _key6 - 1 ] = arguments [ _key6 ] ;
}
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
var elem = jml . apply ( void 0 , [ {
$map : [ map , obj ]
} ] . concat ( args ) ) ;
return [ map , elem ] ;
2018-09-25 08:49:26 +00:00
} ;
2019-05-24 12:17:17 +00:00
jml . symbol = jml . sym = jml [ "for" ] = function ( elem , sym ) {
2018-11-04 07:14:53 +00:00
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
2019-05-24 12:17:17 +00:00
return elem [ _typeof ( sym ) === 'symbol' ? sym : Symbol [ "for" ] ( sym ) ] ;
2018-09-25 08:49:26 +00:00
} ;
jml . command = function ( elem , symOrMap , methodName ) {
2019-05-24 12:17:17 +00:00
var _func3 ;
2018-11-04 07:14:53 +00:00
elem = typeof elem === 'string' ? $ ( elem ) : elem ;
var func ;
for ( var _len7 = arguments . length , args = new Array ( _len7 > 3 ? _len7 - 3 : 0 ) , _key7 = 3 ; _key7 < _len7 ; _key7 ++ ) {
args [ _key7 - 3 ] = arguments [ _key7 ] ;
}
if ( [ 'symbol' , 'string' ] . includes ( _typeof ( symOrMap ) ) ) {
var _func ;
func = jml . sym ( elem , symOrMap ) ;
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
if ( typeof func === 'function' ) {
return func . apply ( void 0 , [ methodName ] . concat ( args ) ) ; // Already has `this` bound to `elem`
2018-09-25 08:49:26 +00:00
}
2018-11-04 07:14:53 +00:00
return ( _func = func ) [ methodName ] . apply ( _func , args ) ;
2019-05-24 12:17:17 +00:00
}
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
func = symOrMap . get ( elem ) ;
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
if ( typeof func === 'function' ) {
var _func2 ;
2018-09-25 08:49:26 +00:00
2019-05-24 12:17:17 +00:00
return ( _func2 = func ) . call . apply ( _func2 , [ elem , methodName ] . concat ( args ) ) ;
}
2018-11-04 07:14:53 +00:00
2019-05-24 12:17:17 +00:00
return ( _func3 = func ) [ methodName ] . apply ( _func3 , [ elem ] . concat ( args ) ) ; // return func[methodName].call(elem, ...args);
2018-09-25 08:49:26 +00:00
} ;
jml . setWindow = function ( wind ) {
2018-11-04 07:14:53 +00:00
win = wind ;
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . setDocument = function ( docum ) {
2018-11-04 07:14:53 +00:00
doc = docum ;
if ( docum && docum . body ) {
body = docum . body ;
}
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . setXMLSerializer = function ( xmls ) {
2018-11-04 07:14:53 +00:00
XmlSerializer = xmls ;
2018-09-25 08:49:26 +00:00
} ;
jml . getWindow = function ( ) {
2018-11-04 07:14:53 +00:00
return win ;
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . getDocument = function ( ) {
2018-11-04 07:14:53 +00:00
return doc ;
2018-09-25 08:49:26 +00:00
} ;
2018-11-04 07:14:53 +00:00
2018-09-25 08:49:26 +00:00
jml . getXMLSerializer = function ( ) {
2018-11-04 07:14:53 +00:00
return XmlSerializer ;
2018-09-25 08:49:26 +00:00
} ;
2019-05-24 12:17:17 +00:00
/ * *
* Does not run Jamilih so can be further processed .
* @ param { Array } jmlArray
* @ param { string | Array | Element } glu
* @ returns { Element }
* /
function glue ( jmlArray , glu ) {
return _toConsumableArray ( jmlArray ) . reduce ( function ( arr , item ) {
arr . push ( item , glu ) ;
return arr ;
} , [ ] ) . slice ( 0 , - 1 ) ;
}
var body = doc && doc . body ; // eslint-disable-line import/no-mutable-exports
2018-09-25 08:49:26 +00:00
2018-11-04 07:14:53 +00:00
var nbsp = "\xA0" ; // Very commonly needed in templates
2018-09-25 08:49:26 +00:00
export default jml ;
2019-05-24 12:17:17 +00:00
export { $ , $$ , body , glue , jml , nbsp } ;