├── LICENSE ├── README.md ├── dist ├── es5 │ ├── alt-iframe.js │ └── alt-iframe.min.js └── es6 │ ├── alt-iframe.js │ └── alt-iframe.min.js ├── example ├── html-files │ ├── footer.html │ ├── header.html │ ├── home.html │ ├── nav-menu.html │ ├── profile.html │ └── search-result.html └── index.html ├── example2 ├── components │ ├── footer.html │ ├── header.html │ ├── home.html │ ├── home.js │ ├── nav-menu.html │ ├── profile │ │ ├── index.html │ │ ├── index.js │ │ ├── section1.html │ │ ├── section2.html │ │ ├── section3.html │ │ ├── subSection1.1.html │ │ ├── subSection1.2.html │ │ └── subSection1.3.html │ └── search-result.html └── index.html └── example3 ├── components ├── appRoot.html ├── asyncForm.html ├── contacts.html ├── home.html ├── myProfile.html ├── nav.html ├── profileCard.html ├── profileEdit.html ├── search.html ├── template-Handlebars.html ├── template-Mustache.html ├── template-doT.html ├── template-dust.html ├── template-ejs.html ├── template-lodash.html ├── template-nunjucks.html ├── template-nxT.html ├── template-template7.html └── templates.html ├── css └── style.css ├── index.html └── js └── common.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 FrontEndNeo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alt-iframe 2 | A simple javascript utility library to include partial html (iframe alternate) without a framework or jQuery. 3 | 4 | 5 | 6 | 7 | 8 | Single HTML Page 9 | 10 | 11 | ... 12 | ... 13 | 14 |
15 | ... 16 | ... 17 | 18 |
19 | ... 20 | ... 21 | ... 22 | 23 | Profile 24 | ... 25 | 26 | ... 27 | ... 28 | ... 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /dist/es5/alt-iframe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * alt-iframe 3 | * - A simple native JavaScript (ES5) utility library to include partial HTML(s). 4 | * - You don't need a framework or jQuery!!! 5 | * 6 | * version: 1.9.2-ES5 7 | * 8 | * License: MIT 9 | * 10 | * USAGE: 11 | * see example at https://github.com/FrontEndNeo/alt-iframe 12 | */ 13 | (function(_g){ 14 | 15 | var _doc = document, _loc = _doc.location, _htmlDir, _htmlExt, _pending; 16 | var _urlHash, _prvHash, _curHash, _hashLst, hashPathDelimiter = '/', hashNavPath = ''; 17 | var _urlHashOn = ((_doc.body.getAttribute('url-hash') || '').toLowerCase() != 'off'); 18 | var delayHashCheck; 19 | var _onReadyQ = [], nxtFn; 20 | 21 | if (_urlHashOn) { 22 | window.onhashchange = function() { 23 | _curHash = _loc.hash || ''; 24 | if (!_curHash) { 25 | (_loc.href.indexOf('#') < 0) && _loc.reload(); 26 | _prvHash = '#'; 27 | } else if (_curHash != _prvHash) { 28 | _urlHash = _curHash; 29 | loadUrlHash(); 30 | } 31 | } 32 | } 33 | 34 | // IE - Polyfill Begins 35 | if (!Element.prototype.matches) { 36 | Element.prototype.matches = 37 | Element.prototype.msMatchesSelector || 38 | Element.prototype.webkitMatchesSelector; 39 | } 40 | if (!Element.prototype.closest) { 41 | Element.prototype.closest = function(s) { 42 | var el = this; 43 | do { 44 | if (Element.prototype.matches.call(el, s)) return el; 45 | el = el.parentElement || el.parentNode; 46 | } while (el !== null && el.nodeType === 1); 47 | return null; 48 | }; 49 | } 50 | // IE - Polyfill Ends 51 | 52 | function _of ( x ) { 53 | return (Object.prototype.toString.call(x)).slice(8,-1).toLowerCase(); 54 | } 55 | function _is ( x, type ) { 56 | if ((''+type)[0] == '*') { 57 | return (_of(x).indexOf((''+type).toLowerCase().substring(1)) >= 0); 58 | } 59 | return ((''+type).toLowerCase().indexOf(_of(x)) >= 0); 60 | } 61 | function _isArr ( x ) { 62 | return _is(x, 'array'); 63 | } 64 | function _isObjLike ( x ) { 65 | return ((typeof x == 'object') || (typeof x == 'function')); 66 | } 67 | function _isUndef ( x ) { 68 | return _is(x, 'undefined'); 69 | } 70 | function _isFn ( x ) { 71 | return _is(x, 'function'); 72 | } 73 | function _toDottedPath ( srcStr ) { 74 | return (srcStr||'').trim().replace(/]/g,'').replace(/(\[)|(\\)|(\/)/g,'.').replace(/(\.+)/g,'.').replace(/\.+$/, '').replace(/^\.+/, ''); 75 | } 76 | function _findInObj ( objSrc, pathStr, ifUndefined ) { 77 | if (_isObjLike(objSrc) && pathStr) { 78 | var pathList = pathStr.split('|').map(function(path){ return path.trim(); } ); 79 | pathStr = pathList.shift(); 80 | var nxtPath = pathList.join('|'); 81 | 82 | var unDef, retValue; 83 | { var i = 0, path = _toDottedPath(pathStr).split('.'), len = path.length; 84 | for (retValue = objSrc; i < len; i++) { 85 | if (_isArr(retValue)) { 86 | retValue = retValue[ parseInt(path[i], 10) ]; 87 | } else if (_isObjLike(retValue)) { 88 | retValue = retValue[ path[i].trim() ]; 89 | } else { 90 | retValue = unDef; 91 | break; 92 | } 93 | } 94 | } 95 | 96 | if (_isUndef(retValue)) { 97 | if (nxtPath) { 98 | return _findInObj (objSrc, nxtPath, ifUndefined); 99 | } else { 100 | return (_isFn(ifUndefined))? ifUndefined.call(objSrc, objSrc, pathStr) : ifUndefined; 101 | } 102 | } else { 103 | return retValue; 104 | } 105 | 106 | } else { 107 | if (arguments.length == 3) { 108 | return (_isFn(ifUndefined))? ifUndefined.call(objSrc, objSrc, pathStr) : ifUndefined; 109 | } else { 110 | return objSrc; 111 | } 112 | } 113 | } 114 | function _callFn ( fnName, context, args ) { 115 | var fnRes, xFn = fnName; 116 | if (_is(fnName, 'string')) { 117 | var idxOfBrace = fnName.indexOf('('); 118 | var xFnName = (idxOfBrace>0? fnName.substring(0, idxOfBrace) : fnName).replace(/\s/g,''); 119 | if (xFnName) { 120 | xFn = _findInObj(window, xFnName); 121 | } 122 | } 123 | 124 | if (xFn && _isFn(xFn)) { 125 | try { 126 | fnRes = (xFn.apply(context, (_isUndef(args)? [] : (_isArr(args)? args : [args])))); 127 | } catch(e) { 128 | console.error('Error calling function:', xFn, ',', e); 129 | } 130 | } else { 131 | console.error('Invalid function:', fnName); 132 | } 133 | return fnRes; 134 | } 135 | 136 | function formData ( formX, asQryStr ) { 137 | var frmData = {}; 138 | var targetForm = (typeof formX === 'string') ? $1(formX) : formX; 139 | var append = function (key, val) { 140 | if (frmData.hasOwnProperty(key)) { 141 | if (!Array.isArray(frmData[key])) { 142 | frmData[key] = frmData[key] ? [frmData[key]] : [] 143 | }; 144 | (val && frmData[key].push(val)); 145 | } else { 146 | frmData[key] = val; 147 | } 148 | }; 149 | 150 | [].slice.call(targetForm.elements).forEach(function (el) { 151 | if (!el.name || el.disabled || el.matches('form fieldset[disabled] *')) return; 152 | if ((el.type === 'checkbox' || el.type === 'radio') && !el.checked) return; 153 | 154 | if (el.tagName === 'SELECT') { 155 | ((el.type === 'select-multiple') && el.selectedIndex >= 0 && append(el.name, [])); 156 | $$('option', el).forEach(function (opt) { 157 | opt.selected && append(el.name, opt.value); 158 | }); 159 | } else { 160 | append(el.name, el.value); 161 | } 162 | 163 | }); 164 | 165 | if (asQryStr) { 166 | return toUrlQryStr(frmData); 167 | } 168 | 169 | return frmData; 170 | } 171 | function toUrlQryStr ( dataObj ) { 172 | var qryStr = ''; 173 | Object.keys(dataObj).forEach(function (key) { 174 | if (Array.isArray(dataObj[key])) { 175 | dataObj[key].forEach(function (val) { 176 | qryStr += '&' + key + '=' + val; 177 | }); 178 | } else { 179 | qryStr += '&' + key + '=' + dataObj[key]; 180 | } 181 | }); 182 | return encodeURI(qryStr); 183 | } 184 | 185 | function $1 (selector, el) { 186 | return getElements(selector, el)[0]; 187 | } 188 | function $$ (selector, el) { 189 | return getElements (selector, el); 190 | } 191 | function getElements (selector, el) { 192 | el = ((typeof el == 'string') && _doc.querySelector(el)) || el || _doc; 193 | return Array.prototype.slice.call(el.querySelectorAll(selector)); 194 | } 195 | 196 | function renameAttr (el, oAttr, nAttr) { 197 | el.setAttribute(nAttr, el.getAttribute(oAttr)); 198 | el.removeAttribute(oAttr); 199 | } 200 | 201 | function cloneScriptNodeFrom (xScript) { 202 | var script = _doc.createElement('script'); 203 | script.text = xScript.innerHTML; 204 | for( var i = xScript.attributes.length-1; i >= 0; i-- ) { 205 | script.setAttribute( xScript.attributes[i].name, xScript.attributes[i].value ); 206 | } 207 | return script; 208 | } 209 | 210 | function parseElSrcPath ( el, attr, pContainer ) { 211 | var newSrc = oldSrc = (el.getAttribute(attr) || '').trim(); 212 | var cRoot, rxCompPath, pSrc, pPath, pRoot; 213 | 214 | ((arguments.length === 2) && (pContainer = el.closest('[x-src]'))); 215 | 216 | if (newSrc && pContainer && (!/^(\/\/|http:\/\/|https:\/\/)/i.test(newSrc))) { 217 | pRoot = getComponentsRootPath( pContainer.getAttribute('x-src') ); 218 | cRoot = (_htmlDir || pRoot).replace(/^\/+/,''); 219 | rxCompPath = new RegExp('^((\.){0,2}\/)*'+(cRoot)); 220 | if (rxCompPath.test(newSrc)) { 221 | newSrc = newSrc.replace(rxCompPath, _htmlDir||pRoot); 222 | // } else if (newSrc[0] !== '/') { 223 | } else if (newSrc[0] === '.') { 224 | pSrc = (pContainer && pContainer.getAttribute('x-src')) || ''; 225 | pPath = pSrc.substring(0, pSrc.lastIndexOf('/')+1) || ((_htmlDir||pRoot)+'/'); 226 | newSrc = (pPath+newSrc).replace(/\/\.?\//,'/'); 227 | } 228 | } 229 | 230 | (newSrc !== oldSrc && el.setAttribute(attr, newSrc)); 231 | } 232 | 233 | function processScripts (context, awaitScripts) { 234 | getElements('script:not([processed])', context).forEach(function(xScript){ 235 | xScript.setAttribute('processed',''); 236 | if (awaitScripts) { xScript.setAttribute('await',''); } 237 | var nScript = cloneScriptNodeFrom(xScript); 238 | 239 | if (nScript.hasAttribute('src')) { 240 | 241 | parseElSrcPath(nScript, 'src', xScript.closest('[x-src]')); 242 | var scriptSrc = nScript.getAttribute('src'); 243 | (!/\.js$/i.test(scriptSrc)) && nScript.setAttribute('src', scriptSrc+'.js'); 244 | 245 | var isAsync = !nScript.hasAttribute('await'); 246 | if (!awaitScripts && isAsync) { 247 | xScript.parentNode.replaceChild( nScript, xScript ); 248 | } else { 249 | renameAttr(xScript, 'src', 'x-src'); 250 | loadExternalSrc(nScript); 251 | } 252 | } else { 253 | xScript.parentNode.replaceChild( nScript, xScript ); 254 | } 255 | }); 256 | } 257 | 258 | function fixComponentElsSrcPath ( context ) { 259 | getElements('link[rel="stylesheet"][href]:not([processed])', context).forEach(function (xEl) { 260 | parseElSrcPath(xEl, 'href'); 261 | xEl.setAttribute('processed', ''); 262 | }); 263 | getElements('img[src]:not([processed])', context).forEach(function (xEl) { 264 | ((!/^data:/i.test(xEl.getAttribute('src'))) && (parseElSrcPath(xEl, 'src'))); 265 | xEl.setAttribute('processed', ''); 266 | }); 267 | } 268 | 269 | function handleHashNotFound () { 270 | var hashErrMode = (_doc.body.getAttribute('hash-error') || '').toLowerCase(); 271 | var redirectUrl = _loc.origin + _loc.pathname + _loc.search; 272 | var eMsg; 273 | if (hashErrMode == 'url') { 274 | eMsg = 'Page_route[' + (_urlHash.substring(1)) + ']_not_found!_Redirected_to_this_page_root.'; 275 | redirectUrl = _loc.origin + _loc.pathname + '?_error=' + eMsg + (_loc.search.replace(/^\?/,'&')); 276 | } else { 277 | eMsg = 'Page route[#' + (_urlHash.substring(1)) + '] not found! Redirecting to this page root.'; 278 | alert(eMsg); 279 | } 280 | _loc.href = redirectUrl; 281 | } 282 | 283 | function loadUrlHash ( forHash, hashPath ) { 284 | if (!_urlHashOn) return; 285 | 286 | forHash = forHash || _urlHash; 287 | if (forHash) { 288 | var elHash = getElements('[url-hash="'+forHash+'"][x-target^="#"],[href="'+forHash+'"]'); 289 | if (elHash.length) { 290 | if (hashPath) { 291 | elHash[0].setAttribute('skip-hash-update', '1'); 292 | } 293 | if (!hashPath || (delayHashCheck && hashPath == _urlHash)) { 294 | _urlHash = ''; 295 | } 296 | _prvHash = _curHash; 297 | onNavElClick.call(elHash[0], true, hashPath); 298 | } else if (!_pending) { 299 | if (_urlHash.indexOf(hashPathDelimiter) > 0) { 300 | var hashNavLength = ((hashNavPath && hashNavPath.split(hashPathDelimiter)) || []).length; 301 | var nxtHash = _hashLst[hashNavLength]; 302 | if (nxtHash || (hashNavLength <= _hashLst.length)) { 303 | hashNavPath += (hashNavPath? hashPathDelimiter : '') + nxtHash; 304 | delayHashCheck = (getElements('[url-hash="'+hashNavPath+'"][x-target^="#"]').length)? 0 : 250; 305 | setTimeout(function () { 306 | loadUrlHash(hashNavPath, _urlHash); 307 | }, delayHashCheck); 308 | } else { 309 | handleHashNotFound(); 310 | } 311 | } else if (!(getAltIframeElements().length)) { 312 | var localHashEl = $1(_urlHash); 313 | if (localHashEl) { 314 | localHashEl.scrollIntoView(true); 315 | _urlHash = ''; 316 | } else { 317 | handleHashNotFound(); 318 | } 319 | } 320 | } 321 | } else { 322 | var hashLockEls = getElements('[skip-on-hash]'); 323 | if (hashLockEls.length) { 324 | hashLockEls.forEach(function(el){ 325 | el.removeAttribute('skip-on-hash'); 326 | }); 327 | processIncludes(); 328 | } 329 | } 330 | } 331 | 332 | function updateElContent (targetEl, content) { 333 | _pending--; 334 | var appendScript = targetEl.getAttribute('x-js'); 335 | if (appendScript) { 336 | content += ''; 337 | targetEl.removeAttribute('x-js'); 338 | } 339 | if (targetEl.tagName == 'SCRIPT') { 340 | if (content.trim()) { 341 | var xScript = _doc.createElement( "script" ); 342 | xScript.id = (new Date()).getMilliseconds(); 343 | xScript.text = content; 344 | _doc.head.appendChild( xScript ).parentNode.removeChild( xScript ); 345 | } 346 | } else { 347 | var replaceTarget = (targetEl.hasAttribute('replace') || (targetEl.tagName.indexOf('REPLACE')>=0)), 348 | context = replaceTarget? targetEl.parentNode : targetEl, 349 | targetAttr = replaceTarget? 'outerHTML' : 'innerHTML', 350 | awaitScripts = targetEl.hasAttribute('await'); 351 | 352 | content = (content || ''); 353 | targetEl[targetAttr] = content; 354 | fixComponentElsSrcPath( context ); 355 | processScripts( context, awaitScripts ); 356 | processIncludes( context ); 357 | 358 | } 359 | loadUrlHash(); 360 | } 361 | 362 | function onXhrStateChange () { 363 | var thisXHR = this; 364 | if (thisXHR.readyState != 4) return; 365 | var xhrStatus = thisXHR.status; 366 | var xhrMethod = thisXHR.method || 'GET'; 367 | var isSuccess = ((xhrStatus >= 200 && xhrStatus < 300) || (xhrStatus == 304)); 368 | var resTxt = isSuccess? thisXHR.responseText : ('Could not '+xhrMethod+' '+thisXHR.reqUrl); 369 | if (isSuccess) { 370 | if (thisXHR.onSuccess) { 371 | resTxt = _callFn(thisXHR.onSuccess, thisXHR, [resTxt, xhrStatus, thisXHR]); 372 | } 373 | } else { 374 | if (thisXHR.onError) { 375 | resTxt = _callFn(thisXHR.onError, thisXHR, [resTxt, xhrStatus, thisXHR]); 376 | } 377 | } 378 | if (!_isUndef(resTxt)) { 379 | updateElContent(this.targetEl, resTxt); 380 | } 381 | } 382 | 383 | function getComponentsRootPath ( fromPath ) { 384 | var cRoot = ''; 385 | if (fromPath.indexOf('/')>=0) { 386 | var slashIdx1 = fromPath.indexOf('/'); 387 | var slashIdx2 = fromPath.indexOf('/', slashIdx1+1); 388 | if ((fromPath[0] === '/' || fromPath[0] === '.') && (slashIdx2 > slashIdx1)) { 389 | cRoot = fromPath.substring(0, slashIdx2); 390 | } else { 391 | cRoot = fromPath.substring(0, slashIdx1); 392 | } 393 | } 394 | return cRoot; 395 | } 396 | function setComponentsRootPath ( fromPath ) { 397 | (_htmlDir === '?' && fromPath.indexOf('/')>=0 && (_htmlDir = getComponentsRootPath(fromPath))); 398 | } 399 | function getSrcPath ( srcPath ) { 400 | var finalPath = (srcPath || '').trim(); 401 | var cRoot, rxCompPath, appendScript=''; 402 | 403 | if (!/^(\/\/|http:\/\/|https:\/\/)/i.test(finalPath)) { 404 | appendScript = /\+$/.test(finalPath)? '+':''; 405 | if (appendScript) finalPath = finalPath.substring(0, finalPath.length-1); 406 | 407 | setComponentsRootPath(finalPath); 408 | 409 | if (_htmlDir) { 410 | if (/^[^a-z0-9_\.\/]/gi.test(finalPath[0])) { 411 | finalPath = finalPath.substring(1); 412 | } else { 413 | cRoot = _htmlDir.replace(/^\/+/,''); 414 | rxCompPath = new RegExp('^((\.){0,2}\/)*'+(cRoot)); 415 | if (rxCompPath.test(finalPath)) { 416 | finalPath = finalPath.replace(rxCompPath, _htmlDir); 417 | } else { 418 | finalPath = (_htmlDir+'/'+finalPath).replace(/\/\.?\//,'/'); 419 | } 420 | } 421 | } 422 | 423 | //_htmlExt && (!((new RegExp(_htmlExt+'$')).test(finalPath))) && (finalPath = (finalPath[finalPath.length-1] == '/')? finalPath.substring(0, finalPath.length-1) : (finalPath+_htmlExt)); 424 | if (_htmlExt && (!((new RegExp(_htmlExt+'$')).test(finalPath)))) { 425 | if (/\/\/$/.test(srcPath)) { 426 | var cNames = finalPath.split('/'); 427 | var finalCompName = cNames[cNames.length-2]; 428 | finalPath = finalPath+finalCompName+_htmlExt; 429 | } else if (finalPath[finalPath.length-1] !== '/') { 430 | finalPath = finalPath+_htmlExt; 431 | } 432 | } 433 | } 434 | 435 | return finalPath+appendScript; 436 | } 437 | 438 | function loadExternalSrc (targetEl, srcPath, options) { 439 | options = options || {method: 'GET'}; 440 | srcPath = getSrcPath(srcPath || (targetEl.getAttribute('src')) ); 441 | targetEl.setAttribute('x-src', srcPath); 442 | targetEl.removeAttribute('src'); 443 | if (srcPath) { 444 | _pending++; 445 | if (/\+$/.test(srcPath)) { //appendScript 446 | targetEl.setAttribute('x-js', srcPath.replace(/\.[a-z]{3,4}\+$/, '.js')); 447 | srcPath = srcPath.substring(0, srcPath.length-1); 448 | } 449 | 450 | var xhrMethod = options.method || 'GET'; 451 | var xhrData = options.data; 452 | var xhrDataType = {}.toString.call(xhrData).slice(8,-1).toLowerCase(); 453 | var urlQryStr = (xhrDataType == 'string')? xhrData : ''; 454 | 455 | if (xhrData) { 456 | if (xhrMethod == 'GET') { 457 | if (xhrDataType === 'object') { 458 | urlQryStr = toUrlQryStr(xhrData); 459 | } 460 | srcPath = srcPath + ((urlQryStr && srcPath.indexOf('?')<0)? '?' : '') + urlQryStr; 461 | srcPath = srcPath.replace(/\?\&/,'?').replace(/\&\&/g, '&'); 462 | } else { 463 | if (xhrDataType === 'object') { 464 | xhrData = JSON.stringify(xhrData); 465 | } 466 | } 467 | } 468 | 469 | var xhr = new XMLHttpRequest(); 470 | xhr.targetEl = targetEl; 471 | xhr.method = xhrMethod; 472 | xhr.onSuccess = options.onSuccess; 473 | xhr.onError = options.onError; 474 | xhr.reqUrl = srcPath; 475 | xhr.onreadystatechange = onXhrStateChange; 476 | xhr.open(xhrMethod, srcPath, !targetEl.hasAttribute('await')); 477 | (xhrData)? xhr.send( xhrData ) : xhr.send(); 478 | } 479 | } 480 | 481 | function updateHistory ( clickedEl ) { 482 | if (!_urlHashOn) return; 483 | if (!clickedEl.getAttribute('skip-hash-update')) { 484 | var newHash = clickedEl.getAttribute('url-hash'); 485 | if ((newHash != '#') && (_prvHash != newHash)) { 486 | _prvHash = newHash; 487 | try { 488 | history.pushState(null, newHash, newHash); 489 | } catch (e) {} 490 | } 491 | } 492 | clickedEl.removeAttribute('skip-hash-update'); 493 | } 494 | 495 | function onNavElClick ( onHashNav, onHashPath ) { 496 | 497 | var clickedEl = this; 498 | var isForm = clickedEl.tagName == 'FORM'; 499 | 500 | if (onHashNav && onHashPath && !isForm) { 501 | clickedEl.click(); 502 | return; 503 | } 504 | 505 | if (isForm && (!clickedEl.checkValidity())) { 506 | clickedEl.reportValidity(); 507 | return false; 508 | } 509 | 510 | var ifCheck = clickedEl.getAttribute('if'); 511 | if (ifCheck) { 512 | var isOk = _callFn(ifCheck, clickedEl); 513 | if (!isOk) return false; 514 | } 515 | 516 | var targetEl = $1( clickedEl.getAttribute('x-target') ); 517 | 518 | if (targetEl) { 519 | targetEl[clickedEl.hasAttribute('replace')? 'setAttribute': 'removeAttribute']('replace', ''); 520 | 521 | if (clickedEl.hasAttribute('await')) { 522 | targetEl.setAttribute('await', ''); 523 | } 524 | if (clickedEl.hasAttribute('async')) { 525 | targetEl.removeAttribute('await', ''); 526 | } 527 | 528 | if (!isForm) { 529 | updateHistory( clickedEl ); 530 | } 531 | 532 | var xSrc = clickedEl.getAttribute('x-href').substring(1); 533 | (/^[! ]/.test(xSrc)) && (xSrc = xSrc.substring(1).trim()); 534 | 535 | if (isForm) { 536 | xSrc = xSrc || clickedEl.getAttribute('action'); 537 | var formMethod = clickedEl.getAttribute('method') || 'GET'; 538 | var dataType = clickedEl.hasAttribute('form-data')? 'FormData' : 'JSON'; 539 | var frmData = formMethod == 'GET'? formData(clickedEl, true) : (/FormData/gi.test(dataType)? new FormData( clickedEl ) : formData(clickedEl)); 540 | var onSuccess = clickedEl.onSuccess || clickedEl.getAttribute('onsuccess') || ''; 541 | var onError = clickedEl.onError || clickedEl.getAttribute('onerror') || ''; 542 | var options = { method:formMethod, data:frmData, onSuccess:onSuccess, onError:onError }; 543 | clickedEl.onSuccess = ''; 544 | clickedEl.onError = ''; 545 | 546 | loadExternalSrc(targetEl, xSrc, options); 547 | } else { 548 | loadExternalSrc(targetEl, xSrc); 549 | } 550 | } else { 551 | console.warn('Target element not found. Invalid target specified in element', clickedEl); 552 | } 553 | } 554 | 555 | function getAltIframeElements ( context ) { 556 | context = context || _doc; 557 | return getElements('[src]'+('audio embed iframe img input script source track video [processed] [skip-on-hash]'.split(' ').map(function(tag){ return ':not('+tag+')'; }).join('')), context); 558 | } 559 | 560 | function processIncludes (context) { 561 | context = context || _doc; 562 | var childAltFrameElements = getAltIframeElements(context); 563 | childAltFrameElements.forEach(function(el){ 564 | parseElSrcPath(el, 'src'); 565 | el.setAttribute('processed', ''); 566 | loadExternalSrc(el); 567 | }); 568 | 569 | getElements('form:not([onsubmit]):not([href])', context).forEach(function (formEl) { 570 | (!formEl.getAttribute('action') && formEl.setAttribute('onsubmit', 'return false;')); 571 | }); 572 | 573 | getElements('form[action][target^="#"]', context).forEach(function (formEl) { 574 | var formAction = formEl.getAttribute('action'); 575 | if (formAction) { 576 | formEl.setAttribute('href', '#'+(formAction.replace(/^#+/,''))); 577 | (!formEl.hasAttribute('onsubmit')) && formEl.setAttribute('onsubmit', 'return false;'); 578 | } 579 | }); 580 | 581 | getElements('[href^="#"][target^="#"]', context).forEach(function(el){ 582 | renameAttr(el, 'target', 'x-target'); 583 | renameAttr(el, 'href', 'x-href'); 584 | el.setAttribute('href', 'javascript:;'); 585 | 586 | var eHash = el.getAttribute('url-hash') || el.getAttribute('x-href'); 587 | (!/^#/.test(eHash)) && (eHash = '#'+eHash); 588 | (/^#[! ]+/.test(eHash)) && (eHash = '#'); 589 | eHash = eHash.replace(/[+ ]/g,'').replace(new RegExp('\\'+hashPathDelimiter+'+$'), ''); 590 | el.setAttribute('url-hash', eHash); 591 | 592 | var isFormEl = (el.tagName == 'FORM'); 593 | var defEvent = isFormEl? 'submit' : 'click'; 594 | var onEvent = (el.getAttribute('on') || defEvent).replace(/[^a-z]/gi,'_'); 595 | (isFormEl && !el.getAttribute('onsubmit') && el.setAttribute('onsubmit', 'return false;')); 596 | onEvent.split('_').forEach(function (eName) { 597 | eName = eName.trim().toLowerCase(); 598 | if (eName.length>2) { 599 | eName = eName.replace(/^on/,''); 600 | el.addEventListener(eName, onNavElClick); 601 | } 602 | }); 603 | }); 604 | 605 | (!childAltFrameElements.length && processOnReady()); 606 | } 607 | 608 | function _onDataXhrStateChange () { 609 | if (this.readyState != 4) return; 610 | var xhrStatus = this.status; 611 | var resTxt = ((xhrStatus >= 200 && xhrStatus < 300) || (xhrStatus == 304))? this.responseText : ('{"error":"Failed: [GET]'+this.reqUrl+'", "status": '+xhrStatus+'}'); 612 | this.callbackFn( JSON.parse(resTxt) ); 613 | } 614 | function getData(dataUrl, callbackFn) { 615 | var xhr = new XMLHttpRequest(); 616 | xhr.reqUrl = dataUrl; 617 | xhr.callbackFn = callbackFn; 618 | xhr.onreadystatechange = _onDataXhrStateChange; 619 | xhr.open('GET', dataUrl); 620 | xhr.send(); 621 | } 622 | 623 | function load (xSrc, target, onLoad) { 624 | var elTarget = getElements(target)[0]; 625 | if (elTarget) { 626 | (typeof onLoad === 'function' && _onReadyQ.push(onLoad)); 627 | loadExternalSrc(elTarget, xSrc); 628 | } else { 629 | console.error('Target container not found.', target); 630 | } 631 | } 632 | 633 | function submitForm ( formId, options ) { 634 | options = options || {method: '', url:'', target:'', onSuccess:'', onError:''} 635 | var targetForm = $1(formId); 636 | if (targetForm) { 637 | if (options.method) { 638 | targetForm.setAttribute('method', options.method); 639 | } 640 | if (options.url) { 641 | targetForm.setAttribute('x-href', '#'+(options.url.replace(/^#+/,'')) ); 642 | } 643 | if (options.target) { 644 | targetForm.setAttribute('x-target', options.target); 645 | } 646 | if (options.onSuccess) { 647 | targetForm.onSuccess = options.onSuccess; 648 | } 649 | if (options.onError) { 650 | targetForm.onError = options.onError; 651 | } 652 | var submitEvent = document.createEvent("Event"); 653 | submitEvent.initEvent("submit", true, true); 654 | targetForm.dispatchEvent(submitEvent); 655 | } else { 656 | console.error('Form NOT FOUND!', formId); 657 | } 658 | } 659 | 660 | function onReady ( fnX, delay ) { 661 | if (typeof fnX === 'function') { 662 | _onReadyQ.push({fn: fnX, delay: delay||0}); 663 | processOnReady(); 664 | } 665 | } 666 | 667 | function processOnReady ( fnRes ) { 668 | if (!_pending && !getAltIframeElements().length && _onReadyQ.length && (typeof fnRes === 'undefined' || fnRes)) { 669 | nxtFn = _onReadyQ.shift(); 670 | setTimeout(function () { 671 | var prevFnRes = nxtFn.fn(fnRes); 672 | ((typeof prevFnRes !== 'undefined' && !prevFnRes && (_onReadyQ = []))); 673 | processOnReady( prevFnRes ); 674 | }, nxtFn.delay); 675 | } 676 | } 677 | 678 | function onDocReady () { 679 | _pending = 0; 680 | _urlHash = _loc.hash || ''; 681 | _hashLst = (_urlHashOn && _urlHash && _urlHash.split(hashPathDelimiter)) || []; 682 | _htmlDir = (_doc.body.getAttribute('components-loc') || '').replace(/^\.\//,'').replace(/\/+$/g,'').trim(); 683 | _htmlExt = (_doc.body.getAttribute('components-ext') || '').trim(); 684 | processIncludes(); 685 | setTimeout(function () { 686 | (new MutationObserver(function(mutationsList) { 687 | (mutationsList && mutationsList[0] && mutationsList[0].type === 'childList' 688 | && mutationsList[0].target && processIncludes( mutationsList[0].target )); 689 | })).observe(_doc, { childList: true, subtree: true }); 690 | }); 691 | } 692 | 693 | if ( (_doc.readyState == 'complete') || (!(_doc.readyState == 'loading' || _doc.documentElement.doScroll)) ) { 694 | onDocReady(); 695 | } else { 696 | _doc.addEventListener('DOMContentLoaded', onDocReady); 697 | } 698 | 699 | _g.alt = _g.aif = { load:load, onReady:onReady, getData:getData, formData:formData, submitForm:submitForm }; 700 | 701 | })(this); -------------------------------------------------------------------------------- /dist/es5/alt-iframe.min.js: -------------------------------------------------------------------------------- 1 | (function(t){function e(t){return Object.prototype.toString.call(t).slice(8,-1).toLowerCase()}function r(t,r){return"*"==(""+r)[0]?e(t).indexOf((""+r).toLowerCase().substring(1))>=0:(""+r).toLowerCase().indexOf(e(t))>=0}function n(t){return r(t,"array")}function i(t){return"object"==typeof t||"function"==typeof t}function o(t){return r(t,"undefined")}function a(t){return r(t,"function")}function s(t){return(t||"").trim().replace(/]/g,"").replace(/(\[)|(\\)|(\/)/g,".").replace(/(\.+)/g,".").replace(/\.+$/,"").replace(/^\.+/,"")}function c(t,e,r){if(i(t)&&e){var u=e.split("|").map(function(t){return t.trim()});e=u.shift();var l,f,h=u.join("|"),p=0,d=s(e).split("."),g=d.length;for(f=t;p0?t.substring(0,l):t).replace(/\s/g,"");f&&(u=c(window,f))}if(u&&a(u))try{s=u.apply(e,o(i)?[]:n(i)?i:[i])}catch(t){console.error("Error calling function:",u,",",t)}else console.error("Invalid function:",t);return s}function l(t,e){var r={},n="string"==typeof t?h(t):t,i=function(t,e){r.hasOwnProperty(t)?(Array.isArray(r[t])||(r[t]=r[t]?[r[t]]:[]),e&&r[t].push(e)):r[t]=e};return[].slice.call(n.elements).forEach(function(t){!t.name||t.disabled||t.matches("form fieldset[disabled] *")||("checkbox"!==t.type&&"radio"!==t.type||t.checked)&&("SELECT"===t.tagName?("select-multiple"===t.type&&t.selectedIndex>=0&&i(t.name,[]),p("option",t).forEach(function(e){e.selected&&i(t.name,e.value)})):i(t.name,t.value))}),e?f(r):r}function f(t){var e="";return Object.keys(t).forEach(function(r){Array.isArray(t[r])?t[r].forEach(function(t){e+="&"+r+"="+t}):e+="&"+r+"="+t[r]}),encodeURI(e)}function h(t,e){return d(t,e)[0]}function p(t,e){return d(t,e)}function d(t,e){return e="string"==typeof e&&B.querySelector(e)||e||B,Array.prototype.slice.call(e.querySelectorAll(t))}function g(t,e,r){t.setAttribute(r,t.getAttribute(e)),t.removeAttribute(e)}function b(t){var e=B.createElement("script");e.text=t.innerHTML;for(var r=t.attributes.length-1;r>=0;r--)e.setAttribute(t.attributes[r].name,t.attributes[r].value);return e}function m(t,e,r){var n,i,o,a,s,c=oldSrc=(t.getAttribute(e)||"").trim();2===arguments.length&&(r=t.closest("[x-src]")),c&&r&&!/^(\/\/|http:\/\/|https:\/\/)/i.test(c)&&(s=S(r.getAttribute("x-src")),n=(G||s).replace(/^\/+/,""),i=new RegExp("^((.){0,2}/)*"+n),i.test(c)?c=c.replace(i,G||s):"."===c[0]&&(o=r&&r.getAttribute("x-src")||"",a=o.substring(0,o.lastIndexOf("/")+1)||(G||s)+"/",c=(a+c).replace(/\/\.?\//,"/"))),c!==oldSrc&&t.setAttribute(e,c)}function A(t,e){d("script:not([processed])",t).forEach(function(t){t.setAttribute("processed",""),e&&t.setAttribute("await","");var r=b(t);if(r.hasAttribute("src")){m(r,"src",t.closest("[x-src]"));var n=r.getAttribute("src");!/\.js$/i.test(n)&&r.setAttribute("src",n+".js");var i=!r.hasAttribute("await");!e&&i?t.parentNode.replaceChild(r,t):(g(t,"src","x-src"),L(r))}else t.parentNode.replaceChild(r,t)})}function v(t){d('link[rel="stylesheet"][href]:not([processed])',t).forEach(function(t){m(t,"href"),t.setAttribute("processed","")}),d("img[src]:not([processed])",t).forEach(function(t){!/^data:/i.test(t.getAttribute("src"))&&m(t,"src"),t.setAttribute("processed","")})}function E(){var t,e=(B.body.getAttribute("hash-error")||"").toLowerCase(),r=K.origin+K.pathname+K.search;"url"==e?(t="Page_route["+H.substring(1)+"]_not_found!_Redirected_to_this_page_root.",r=K.origin+K.pathname+"?_error="+t+K.search.replace(/^\?/,"&")):(t="Page route[#"+H.substring(1)+"] not found! Redirecting to this page root.",alert(t)),K.href=r}function y(t,e){if(Y)if(t=t||H,t){var r=d('[url-hash="'+t+'"][x-target^="#"],[href="'+t+'"]');if(r.length)e&&r[0].setAttribute("skip-hash-update","1"),(!e||V&&e==H)&&(H=""),P=z,C.call(r[0],!0,e);else if(!U)if(H.indexOf(Q)>0){var n=(W&&W.split(Q)||[]).length,i=J[n];i||n<=J.length?(W+=(W?Q:"")+i,V=d('[url-hash="'+W+'"][x-target^="#"]').length?0:250,setTimeout(function(){y(W,H)},V)):E()}else if(!N().length){var o=h(H);o?(o.scrollIntoView(!0),H=""):E()}}else{var a=d("[skip-on-hash]");a.length&&(a.forEach(function(t){t.removeAttribute("skip-on-hash")}),j())}}function x(t,e){U--;var r=t.getAttribute("x-js");if(r&&(e+='',t.removeAttribute("x-js")),"SCRIPT"==t.tagName){if(e.trim()){var n=B.createElement("script");n.id=(new Date).getMilliseconds(),n.text=e,B.head.appendChild(n).parentNode.removeChild(n)}}else{var i=t.hasAttribute("replace")||t.tagName.indexOf("REPLACE")>=0,o=i?t.parentNode:t,a=i?"outerHTML":"innerHTML",s=t.hasAttribute("await");e=e||"",t[a]=e,v(o),A(o,s),j(o)}y()}function w(){var t=this;if(4==t.readyState){var e=t.status,r=t.method||"GET",n=e>=200&&e<300||304==e,i=n?t.responseText:"Could not "+r+" "+t.reqUrl;n?t.onSuccess&&(i=u(t.onSuccess,t,[i,e,t])):t.onError&&(i=u(t.onError,t,[i,e,t])),o(i)||x(this.targetEl,i)}}function S(t){var e="";if(t.indexOf("/")>=0){var r=t.indexOf("/"),n=t.indexOf("/",r+1);e=("/"===t[0]||"."===t[0])&&n>r?t.substring(0,n):t.substring(0,r)}return e}function O(t){"?"===G&&t.indexOf("/")>=0&&(G=S(t))}function T(t){var e,r,n=(t||"").trim(),i="";if(!/^(\/\/|http:\/\/|https:\/\/)/i.test(n)&&(i=/\+$/.test(n)?"+":"",i&&(n=n.substring(0,n.length-1)),O(n),G&&(/^[^a-z0-9_\.\/]/gi.test(n[0])?n=n.substring(1):(e=G.replace(/^\/+/,""),r=new RegExp("^((.){0,2}/)*"+e),n=r.test(n)?n.replace(r,G):(G+"/"+n).replace(/\/\.?\//,"/"))),I&&!new RegExp(I+"$").test(n)))if(/\/\/$/.test(t)){var o=n.split("/"),a=o[o.length-2];n=n+a+I}else"/"!==n[n.length-1]&&(n+=I);return n+i}function L(t,e,r){if(r=r||{method:"GET"},e=T(e||t.getAttribute("src")),t.setAttribute("x-src",e),t.removeAttribute("src"),e){U++,/\+$/.test(e)&&(t.setAttribute("x-js",e.replace(/\.[a-z]{3,4}\+$/,".js")),e=e.substring(0,e.length-1));var n=r.method||"GET",i=r.data,o={}.toString.call(i).slice(8,-1).toLowerCase(),a="string"==o?i:"";i&&("GET"==n?("object"===o&&(a=f(i)),e=e+(a&&e.indexOf("?")<0?"?":"")+a,e=e.replace(/\?\&/,"?").replace(/\&\&/g,"&")):"object"===o&&(i=JSON.stringify(i)));var s=new XMLHttpRequest;s.targetEl=t,s.method=n,s.onSuccess=r.onSuccess,s.onError=r.onError,s.reqUrl=e,s.onreadystatechange=w,s.open(n,e,!t.hasAttribute("await")),i?s.send(i):s.send()}}function k(t){if(Y){if(!t.getAttribute("skip-hash-update")){var e=t.getAttribute("url-hash");if("#"!=e&&P!=e){P=e;try{history.pushState(null,e,e)}catch(t){}}}t.removeAttribute("skip-hash-update")}}function C(t,e){var r=this,n="FORM"==r.tagName;if(t&&e&&!n)r.click();else{if(n&&!r.checkValidity())return r.reportValidity(),!1;var i=r.getAttribute("if");if(i){var o=u(i,r);if(!o)return!1}var a=h(r.getAttribute("x-target"));if(a){a[r.hasAttribute("replace")?"setAttribute":"removeAttribute"]("replace",""),r.hasAttribute("await")&&a.setAttribute("await",""),r.hasAttribute("async")&&a.removeAttribute("await",""),n||k(r);var s=r.getAttribute("x-href").substring(1);if(/^[! ]/.test(s)&&(s=s.substring(1).trim()),n){s=s||r.getAttribute("action");var c=r.getAttribute("method")||"GET",f=r.hasAttribute("form-data")?"FormData":"JSON",p="GET"==c?l(r,!0):/FormData/gi.test(f)?new FormData(r):l(r),d=r.onSuccess||r.getAttribute("onsuccess")||"",g=r.onError||r.getAttribute("onerror")||"",b={method:c,data:p,onSuccess:d,onError:g};r.onSuccess="",r.onError="",L(a,s,b)}else L(a,s)}else console.warn("Target element not found. Invalid target specified in element",r)}}function N(t){return t=t||B,d("[src]"+"audio embed iframe img input script source track video [processed] [skip-on-hash]".split(" ").map(function(t){return":not("+t+")"}).join(""),t)}function j(t){t=t||B;var e=N(t);e.forEach(function(t){m(t,"src"),t.setAttribute("processed",""),L(t)}),d("form:not([onsubmit]):not([href])",t).forEach(function(t){!t.getAttribute("action")&&t.setAttribute("onsubmit","return false;")}),d('form[action][target^="#"]',t).forEach(function(t){var e=t.getAttribute("action");e&&(t.setAttribute("href","#"+e.replace(/^#+/,"")),!t.hasAttribute("onsubmit")&&t.setAttribute("onsubmit","return false;"))}),d('[href^="#"][target^="#"]',t).forEach(function(t){g(t,"target","x-target"),g(t,"href","x-href"),t.setAttribute("href","javascript:;");var e=t.getAttribute("url-hash")||t.getAttribute("x-href");!/^#/.test(e)&&(e="#"+e),/^#[! ]+/.test(e)&&(e="#"),e=e.replace(/[+ ]/g,"").replace(new RegExp("\\"+Q+"+$"),""),t.setAttribute("url-hash",e);var r="FORM"==t.tagName,n=r?"submit":"click",i=(t.getAttribute("on")||n).replace(/[^a-z]/gi,"_");r&&!t.getAttribute("onsubmit")&&t.setAttribute("onsubmit","return false;"),i.split("_").forEach(function(e){e=e.trim().toLowerCase(),e.length>2&&(e=e.replace(/^on/,""),t.addEventListener(e,C))})}),!e.length&&q()}function R(){if(4==this.readyState){var t=this.status,e=t>=200&&t<300||304==t?this.responseText:'{"error":"Failed: [GET]'+this.reqUrl+'", "status": '+t+"}";this.callbackFn(JSON.parse(e))}}function M(t,e){var r=new XMLHttpRequest;r.reqUrl=t,r.callbackFn=e,r.onreadystatechange=R,r.open("GET",t),r.send()}function _(t,e,r){var n=d(e)[0];n?("function"==typeof r&&Z.push(r),L(n,t)):console.error("Target container not found.",e)}function F(t,e){e=e||{method:"",url:"",target:"",onSuccess:"",onError:""};var r=h(t);if(r){e.method&&r.setAttribute("method",e.method),e.url&&r.setAttribute("x-href","#"+e.url.replace(/^#+/,"")),e.target&&r.setAttribute("x-target",e.target),e.onSuccess&&(r.onSuccess=e.onSuccess),e.onError&&(r.onError=e.onError);var n=document.createEvent("Event");n.initEvent("submit",!0,!0),r.dispatchEvent(n)}else console.error("Form NOT FOUND!",t)}function $(t,e){"function"==typeof t&&(Z.push({fn:t,delay:e||0}),q())}function q(t){U||N().length||!Z.length||void 0!==t&&!t||(X=Z.shift(),setTimeout(function(){var e=X.fn(t);void 0!==e&&!e&&(Z=[]),q(e)},X.delay))}function D(){U=0,H=K.hash||"",J=Y&&H&&H.split(Q)||[],G=(B.body.getAttribute("components-loc")||"").replace(/^\.\//,"").replace(/\/+$/g,"").trim(),I=(B.body.getAttribute("components-ext")||"").trim(),j(),setTimeout(function(){new MutationObserver(function(t){t&&t[0]&&"childList"===t[0].type&&t[0].target&&j(t[0].target)}).observe(B,{childList:!0,subtree:!0})})}var G,I,U,H,P,z,J,V,X,B=document,K=B.location,Q="/",W="",Y="off"!=(B.body.getAttribute("url-hash")||"").toLowerCase(),Z=[];Y&&(window.onhashchange=function(){z=K.hash||"",z?z!=P&&(H=z,y()):(K.href.indexOf("#")<0&&K.reload(),P="#")}),Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector),Element.prototype.closest||(Element.prototype.closest=function(t){var e=this;do{if(Element.prototype.matches.call(e,t))return e;e=e.parentElement||e.parentNode}while(null!==e&&1===e.nodeType);return null}),"complete"==B.readyState||"loading"!=B.readyState&&!B.documentElement.doScroll?D():B.addEventListener("DOMContentLoaded",D),t.alt=t.aif={load:_,onReady:$,getData:M,formData:l,submitForm:F}})(this); -------------------------------------------------------------------------------- /dist/es6/alt-iframe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * alt-iframe 3 | * - A simple native JavaScript (ES6+) utility library to include partial HTML(s). 4 | * - You don't need a framework or jQuery!!! 5 | * 6 | * version: 1.9.2-ES6 7 | * 8 | * License: MIT 9 | * 10 | * USAGE: 11 | * see example at https://github.com/FrontEndNeo/alt-iframe 12 | */ 13 | (function(_g){ 14 | 15 | let _doc = document, _loc = _doc.location, _htmlDir, _htmlExt, _pending; 16 | let _urlHash, _prvHash, _curHash, _hashLst, hashPathDelimiter = '/', hashNavPath = ''; 17 | let _urlHashOn = ((_doc.body.getAttribute('url-hash') || '').toLowerCase() != 'off'); 18 | let delayHashCheck; 19 | let _onReadyQ = [], nxtFn; 20 | 21 | if (_urlHashOn) { 22 | window.onhashchange = function() { 23 | _curHash = _loc.hash || ''; 24 | if (!_curHash) { 25 | (_loc.href.indexOf('#') < 0) && _loc.reload(); 26 | _prvHash = '#'; 27 | } else if (_curHash != _prvHash) { 28 | _urlHash = _curHash; 29 | loadUrlHash(); 30 | } 31 | } 32 | } 33 | 34 | function _of ( x ) { 35 | return (Object.prototype.toString.call(x)).slice(8,-1).toLowerCase(); 36 | } 37 | function _is ( x, type ) { 38 | if ((''+type)[0] == '*') { 39 | return (_of(x).indexOf((''+type).toLowerCase().substring(1)) >= 0); 40 | } 41 | return ((''+type).toLowerCase().indexOf(_of(x)) >= 0); 42 | } 43 | function _isArr ( x ) { 44 | return _is(x, 'array'); 45 | } 46 | function _isObjLike ( x ) { 47 | return ((typeof x == 'object') || (typeof x == 'function')); 48 | } 49 | function _isUndef ( x ) { 50 | return _is(x, 'undefined'); 51 | } 52 | function _isFn ( x ) { 53 | return _is(x, 'function'); 54 | } 55 | function _toDottedPath ( srcStr ) { 56 | return (srcStr||'').trim().replace(/]/g,'').replace(/(\[)|(\\)|(\/)/g,'.').replace(/(\.+)/g,'.').replace(/\.+$/, '').replace(/^\.+/, ''); 57 | } 58 | function _findInObj ( objSrc, pathStr, ifUndefined ) { 59 | if (_isObjLike(objSrc) && pathStr) { 60 | let pathList = pathStr.split('|').map(path=>path.trim()); 61 | pathStr = pathList.shift(); 62 | let nxtPath = pathList.join('|'); 63 | 64 | let unDef, retValue; 65 | { let i = 0, path = _toDottedPath(pathStr).split('.'), len = path.length; 66 | for (retValue = objSrc; i < len; i++) { 67 | if (_isArr(retValue)) { 68 | retValue = retValue[ parseInt(path[i], 10) ]; 69 | } else if (_isObjLike(retValue)) { 70 | retValue = retValue[ path[i].trim() ]; 71 | } else { 72 | retValue = unDef; 73 | break; 74 | } 75 | } 76 | } 77 | 78 | if (_isUndef(retValue)) { 79 | if (nxtPath) { 80 | return _findInObj (objSrc, nxtPath, ifUndefined); 81 | } else { 82 | return (_isFn(ifUndefined))? ifUndefined.call(objSrc, objSrc, pathStr) : ifUndefined; 83 | } 84 | } else { 85 | return retValue; 86 | } 87 | 88 | } else { 89 | if (arguments.length == 3) { 90 | return (_isFn(ifUndefined))? ifUndefined.call(objSrc, objSrc, pathStr) : ifUndefined; 91 | } else { 92 | return objSrc; 93 | } 94 | } 95 | } 96 | function _callFn ( fnName, context, args ) { 97 | let fnRes, xFn = fnName; 98 | if (_is(fnName, 'string')) { 99 | let idxOfBrace = fnName.indexOf('('); 100 | let xFnName = (idxOfBrace>0? fnName.substring(0, idxOfBrace) : fnName).replace(/\s/g,''); 101 | if (xFnName) { 102 | xFn = _findInObj(window, xFnName); 103 | } 104 | } 105 | 106 | if (xFn && _isFn(xFn)) { 107 | try { 108 | fnRes = (xFn.apply(context, (_isUndef(args)? [] : (_isArr(args)? args : [args])))); 109 | } catch(e) { 110 | console.error('Error calling function:', xFn, ',', e); 111 | } 112 | } else { 113 | console.error('Invalid function:', fnName); 114 | } 115 | return fnRes; 116 | } 117 | 118 | function formData ( formX, asQryStr ) { 119 | let frmData = {}; 120 | let targetForm = (typeof formX === 'string') ? $1(formX) : formX; 121 | let append = (key, val) => { 122 | if (frmData.hasOwnProperty(key)) { 123 | if (!Array.isArray(frmData[key])) { 124 | frmData[key] = frmData[key] ? [frmData[key]] : [] 125 | }; 126 | (val && frmData[key].push(val)); 127 | } else { 128 | frmData[key] = val; 129 | } 130 | }; 131 | 132 | [].slice.call(targetForm.elements).forEach(el=>{ 133 | if (!el.name || el.disabled || el.matches('form fieldset[disabled] *')) return; 134 | if ((el.type === 'checkbox' || el.type === 'radio') && !el.checked) return; 135 | 136 | if (el.tagName === 'SELECT') { 137 | ((el.type === 'select-multiple') && el.selectedIndex >= 0 && append(el.name, [])); 138 | $$('option', el).forEach(opt=>{ 139 | opt.selected && append(el.name, opt.value); 140 | }); 141 | } else { 142 | append(el.name, el.value); 143 | } 144 | 145 | }); 146 | 147 | if (asQryStr) { 148 | return toUrlQryStr(frmData); 149 | } 150 | 151 | return frmData; 152 | } 153 | function toUrlQryStr ( dataObj ) { 154 | let qryStr = ''; 155 | Object.keys(dataObj).forEach(key=>{ 156 | if (Array.isArray(dataObj[key])) { 157 | dataObj[key].forEach(val=>{ 158 | qryStr += '&' + key + '=' + val; 159 | }); 160 | } else { 161 | qryStr += '&' + key + '=' + dataObj[key]; 162 | } 163 | }); 164 | return encodeURI(qryStr); 165 | } 166 | 167 | function $1 (selector, el) { 168 | return getElements(selector, el)[0]; 169 | } 170 | function $$ (selector, el) { 171 | return getElements (selector, el); 172 | } 173 | function getElements (selector, el) { 174 | el = ((typeof el == 'string') && _doc.querySelector(el)) || el || _doc; 175 | return Array.prototype.slice.call(el.querySelectorAll(selector)); 176 | } 177 | 178 | function renameAttr (el, oAttr, nAttr) { 179 | el.setAttribute(nAttr, el.getAttribute(oAttr)); 180 | el.removeAttribute(oAttr); 181 | } 182 | 183 | function cloneScriptNodeFrom (xScript) { 184 | let script = _doc.createElement('script'); 185 | script.text = xScript.innerHTML; 186 | for( let i = xScript.attributes.length-1; i >= 0; i-- ) { 187 | script.setAttribute( xScript.attributes[i].name, xScript.attributes[i].value ); 188 | } 189 | return script; 190 | } 191 | 192 | function parseElSrcPath ( el, attr, pContainer ) { 193 | let newSrc = oldSrc = (el.getAttribute(attr) || '').trim(); 194 | let cRoot, rxCompPath, pSrc, pPath, pRoot; 195 | 196 | ((arguments.length === 2) && (pContainer = el.closest('[x-src]'))); 197 | 198 | if (newSrc && pContainer && (!/^(\/\/|http:\/\/|https:\/\/)/i.test(newSrc))) { 199 | pRoot = getComponentsRootPath( pContainer.getAttribute('x-src') ); 200 | cRoot = (_htmlDir || pRoot).replace(/^\/+/,''); 201 | rxCompPath = new RegExp('^((\.){0,2}\/)*'+(cRoot)); 202 | if (rxCompPath.test(newSrc)) { 203 | newSrc = newSrc.replace(rxCompPath, _htmlDir||pRoot); 204 | // } else if (newSrc[0] !== '/') { 205 | } else if (newSrc[0] === '.') { 206 | pSrc = (pContainer && pContainer.getAttribute('x-src')) || ''; 207 | pPath = pSrc.substring(0, pSrc.lastIndexOf('/')+1) || ((_htmlDir||pRoot)+'/'); 208 | newSrc = (pPath+newSrc).replace(/\/\.?\//,'/'); 209 | } 210 | } 211 | 212 | (newSrc !== oldSrc && el.setAttribute(attr, newSrc)); 213 | } 214 | 215 | function processScripts (context, awaitScripts) { 216 | getElements('script:not([processed])', context).forEach(xScript=>{ 217 | xScript.setAttribute('processed',''); 218 | if (awaitScripts) { xScript.setAttribute('await',''); } 219 | let nScript = cloneScriptNodeFrom(xScript); 220 | 221 | if (nScript.hasAttribute('src')) { 222 | 223 | parseElSrcPath(nScript, 'src', xScript.closest('[x-src]')); 224 | let scriptSrc = nScript.getAttribute('src'); 225 | (!/\.js$/i.test(scriptSrc)) && nScript.setAttribute('src', scriptSrc+'.js'); 226 | 227 | let isAsync = !nScript.hasAttribute('await'); 228 | if (!awaitScripts && isAsync) { 229 | xScript.parentNode.replaceChild( nScript, xScript ); 230 | } else { 231 | renameAttr(xScript, 'src', 'x-src'); 232 | loadExternalSrc(nScript); 233 | } 234 | } else { 235 | xScript.parentNode.replaceChild( nScript, xScript ); 236 | } 237 | }); 238 | } 239 | 240 | function fixComponentElsSrcPath ( context ) { 241 | getElements('link[rel="stylesheet"][href]:not([processed])', context).forEach(xEl => { 242 | parseElSrcPath(xEl, 'href'); 243 | xEl.setAttribute('processed', ''); 244 | }); 245 | getElements('img[src]:not([processed])', context).forEach( xEl => { 246 | ((!/^data:/i.test(xEl.getAttribute('src'))) && (parseElSrcPath(xEl, 'src'))); 247 | xEl.setAttribute('processed', ''); 248 | }); 249 | } 250 | 251 | function handleHashNotFound () { 252 | let hashErrMode = (_doc.body.getAttribute('hash-error') || '').toLowerCase(); 253 | let redirectUrl = _loc.origin + _loc.pathname + _loc.search; 254 | let eMsg; 255 | if (hashErrMode == 'url') { 256 | eMsg = 'Page_route[' + (_urlHash.substring(1)) + ']_not_found!_Redirected_to_this_page_root.'; 257 | redirectUrl = _loc.origin + _loc.pathname + '?_error=' + eMsg + (_loc.search.replace(/^\?/,'&')); 258 | } else { 259 | eMsg = 'Page route[#' + (_urlHash.substring(1)) + '] not found! Redirecting to this page root.'; 260 | alert(eMsg); 261 | } 262 | _loc.href = redirectUrl; 263 | } 264 | 265 | function loadUrlHash ( forHash, hashPath ) { 266 | if (!_urlHashOn) return; 267 | 268 | forHash = forHash || _urlHash; 269 | if (forHash) { 270 | let elHash = getElements('[url-hash="'+forHash+'"][x-target^="#"],[href="'+forHash+'"]'); 271 | if (elHash.length) { 272 | if (hashPath) { 273 | elHash[0].setAttribute('skip-hash-update', '1'); 274 | } 275 | if (!hashPath || (delayHashCheck && hashPath == _urlHash)) { 276 | _urlHash = ''; 277 | } 278 | _prvHash = _curHash; 279 | onNavElClick.call(elHash[0], true, hashPath); 280 | } else if (!_pending) { 281 | if (_urlHash.indexOf(hashPathDelimiter) > 0) { 282 | let hashNavLength = ((hashNavPath && hashNavPath.split(hashPathDelimiter)) || []).length; 283 | let nxtHash = _hashLst[hashNavLength]; 284 | if (nxtHash || (hashNavLength <= _hashLst.length)) { 285 | hashNavPath += (hashNavPath? hashPathDelimiter : '') + nxtHash; 286 | delayHashCheck = (getElements('[url-hash="'+hashNavPath+'"][x-target^="#"]').length)? 0 : 250; 287 | setTimeout(()=>{ 288 | loadUrlHash(hashNavPath, _urlHash); 289 | }, delayHashCheck); 290 | } else { 291 | handleHashNotFound(); 292 | } 293 | } else if (!(getAltIframeElements().length)) { 294 | let localHashEl = $1(_urlHash); 295 | if (localHashEl) { 296 | localHashEl.scrollIntoView(true); 297 | _urlHash = ''; 298 | } else { 299 | handleHashNotFound(); 300 | } 301 | } 302 | } 303 | } else { 304 | let hashLockEls = getElements('[skip-on-hash]'); 305 | if (hashLockEls.length) { 306 | hashLockEls.forEach(el=>{ 307 | el.removeAttribute('skip-on-hash'); 308 | }); 309 | processIncludes(); 310 | } 311 | } 312 | } 313 | 314 | function updateElContent (targetEl, content) { 315 | _pending--; 316 | let appendScript = targetEl.getAttribute('x-js'); 317 | if (appendScript) { 318 | content += ''; 319 | targetEl.removeAttribute('x-js'); 320 | } 321 | if (targetEl.tagName == 'SCRIPT') { 322 | if (content.trim()) { 323 | let xScript = _doc.createElement( "script" ); 324 | xScript.id = (new Date()).getMilliseconds(); 325 | xScript.text = content; 326 | _doc.head.appendChild( xScript ).parentNode.removeChild( xScript ); 327 | } 328 | } else { 329 | let replaceTarget = (targetEl.hasAttribute('replace') || (targetEl.tagName.indexOf('REPLACE')>=0)), 330 | context = replaceTarget? targetEl.parentNode : targetEl, 331 | targetAttr = replaceTarget? 'outerHTML' : 'innerHTML', 332 | awaitScripts = targetEl.hasAttribute('await'); 333 | 334 | content = (content || ''); 335 | targetEl[targetAttr] = content; 336 | fixComponentElsSrcPath( context ); 337 | processScripts( context, awaitScripts ); 338 | processIncludes( context ); 339 | 340 | } 341 | loadUrlHash(); 342 | } 343 | 344 | function onXhrStateChange ( resTxt, res, options) { 345 | if (_isUndef(resTxt)) { 346 | resTxt = ('Could not '+(options.method)+' '+res.url); 347 | if (options.onError) { 348 | resTxt = _callFn(options.onError, null, [resTxt, res.status, res]); 349 | } 350 | } else { 351 | if (options.onSuccess) { 352 | resTxt = _callFn(options.onSuccess, null, [resTxt, res.status, res]); 353 | } 354 | } 355 | if (!_isUndef(resTxt)) { 356 | updateElContent(options.targetEl, resTxt); 357 | } 358 | } 359 | 360 | function getComponentsRootPath ( fromPath ) { 361 | let cRoot = ''; 362 | if (fromPath.indexOf('/')>=0) { 363 | let slashIdx1 = fromPath.indexOf('/'); 364 | let slashIdx2 = fromPath.indexOf('/', slashIdx1+1); 365 | if ((fromPath[0] === '/' || fromPath[0] === '.') && (slashIdx2 > slashIdx1)) { 366 | cRoot = fromPath.substring(0, slashIdx2); 367 | } else { 368 | cRoot = fromPath.substring(0, slashIdx1); 369 | } 370 | } 371 | return cRoot; 372 | } 373 | function setComponentsRootPath ( fromPath ) { 374 | (_htmlDir === '?' && fromPath.indexOf('/')>=0 && (_htmlDir = getComponentsRootPath(fromPath))); 375 | } 376 | function getSrcPath ( srcPath ) { 377 | let finalPath = (srcPath || '').trim(); 378 | let cRoot, rxCompPath, appendScript=''; 379 | 380 | if (!/^(\/\/|http:\/\/|https:\/\/)/i.test(finalPath)) { 381 | appendScript = /\+$/.test(finalPath)? '+':''; 382 | if (appendScript) finalPath = finalPath.substring(0, finalPath.length-1); 383 | 384 | setComponentsRootPath(finalPath); 385 | 386 | if (_htmlDir) { 387 | if (/^[^a-z0-9_\.\/]/gi.test(finalPath[0])) { 388 | finalPath = finalPath.substring(1); 389 | } else { 390 | cRoot = _htmlDir.replace(/^\/+/,''); 391 | rxCompPath = new RegExp('^((\.){0,2}\/)*'+(cRoot)); 392 | if (rxCompPath.test(finalPath)) { 393 | finalPath = finalPath.replace(rxCompPath, _htmlDir); 394 | } else { 395 | finalPath = (_htmlDir+'/'+finalPath).replace(/\/\.?\//,'/'); 396 | } 397 | } 398 | } 399 | 400 | // _htmlExt && (!((new RegExp(_htmlExt+'$')).test(finalPath))) && (finalPath = (finalPath[finalPath.length-1] == '/')? finalPath.substring(0, finalPath.length-1) : (finalPath+_htmlExt)); 401 | if (_htmlExt && (!((new RegExp(_htmlExt+'$')).test(finalPath)))) { 402 | if (/\/\/$/.test(srcPath)) { 403 | let cNames = finalPath.split('/'); 404 | let finalCompName = cNames[cNames.length-2]; 405 | finalPath = finalPath+finalCompName+_htmlExt; 406 | } else if (finalPath[finalPath.length-1] !== '/') { 407 | finalPath = finalPath+_htmlExt; 408 | } 409 | } 410 | } 411 | 412 | return finalPath+appendScript; 413 | } 414 | 415 | function loadExternalSrc (targetEl, srcPath, options) { 416 | options = options || {method: 'GET'}; 417 | srcPath = getSrcPath(srcPath || (targetEl.getAttribute('src')) ); 418 | targetEl.setAttribute('x-src', srcPath); 419 | targetEl.removeAttribute('src'); 420 | if (srcPath) { 421 | _pending++; 422 | if (/\+$/.test(srcPath)) { //appendScript 423 | targetEl.setAttribute('x-js', srcPath.replace(/\.[a-z]{3,4}\+$/, '.js')); 424 | srcPath = srcPath.substring(0, srcPath.length-1); 425 | } 426 | 427 | let xhrMethod = options.method || 'GET'; 428 | let xhrData = options.data; 429 | let xhrDataType = {}.toString.call(xhrData).slice(8,-1).toLowerCase(); 430 | let urlQryStr = (xhrDataType == 'string')? xhrData : ''; 431 | 432 | if (xhrData) { 433 | if (xhrMethod == 'GET') { 434 | if (xhrDataType === 'object') { 435 | urlQryStr = toUrlQryStr(xhrData); 436 | } 437 | srcPath = srcPath + ((urlQryStr && srcPath.indexOf('?')<0)? '?' : '') + urlQryStr; 438 | srcPath = srcPath.replace(/\?\&/,'?').replace(/\&\&/g, '&'); 439 | } else { 440 | if (xhrDataType === 'object') { 441 | xhrData = JSON.stringify(xhrData); 442 | } 443 | } 444 | } 445 | 446 | options.targetEl = targetEl; 447 | options.method = xhrMethod; 448 | let fetchOptions = { method: xhrMethod }; 449 | if (xhrData) fetchOptions.body = xhrData; 450 | 451 | if (targetEl.hasAttribute('await')) { 452 | (async () => { 453 | let resTxt; 454 | const res = await fetch(srcPath, fetchOptions).catch( e => null ); 455 | if (res && res.ok) { 456 | resTxt = await res.text(); 457 | } 458 | onXhrStateChange(resTxt, res, options); 459 | })(); 460 | } else { 461 | let fetchRes; 462 | fetch(srcPath, fetchOptions) 463 | .then( res => { 464 | fetchRes = res; 465 | let resTxt; 466 | if (res && res.ok) { 467 | resTxt = res.text(); 468 | } 469 | return resTxt; 470 | }) 471 | .then( resTxt => { 472 | onXhrStateChange(resTxt, fetchRes, options); 473 | }) 474 | .catch( e => null ); 475 | } 476 | } 477 | } 478 | 479 | function updateHistory ( clickedEl ) { 480 | if (!_urlHashOn) return; 481 | if (!clickedEl.getAttribute('skip-hash-update')) { 482 | let newHash = clickedEl.getAttribute('url-hash'); 483 | if ((newHash != '#') && (_prvHash != newHash)) { 484 | _prvHash = newHash; 485 | try { 486 | history.pushState(null, newHash, newHash); 487 | } catch (e) {} 488 | } 489 | } 490 | clickedEl.removeAttribute('skip-hash-update'); 491 | } 492 | 493 | function onNavElClick ( onHashNav, onHashPath ) { 494 | 495 | let clickedEl = this; 496 | let isForm = clickedEl.tagName == 'FORM'; 497 | 498 | if (onHashNav && onHashPath && !isForm) { 499 | clickedEl.click(); 500 | return; 501 | } 502 | 503 | if (isForm && (!clickedEl.checkValidity())) { 504 | clickedEl.reportValidity(); 505 | return false; 506 | } 507 | 508 | let ifCheck = clickedEl.getAttribute('if'); 509 | if (ifCheck) { 510 | let isOk = _callFn(ifCheck, clickedEl); 511 | if (!isOk) return false; 512 | } 513 | 514 | let targetEl = $1( clickedEl.getAttribute('x-target') ); 515 | 516 | if (targetEl) { 517 | targetEl[clickedEl.hasAttribute('replace')? 'setAttribute': 'removeAttribute']('replace', ''); 518 | 519 | if (clickedEl.hasAttribute('await')) { 520 | targetEl.setAttribute('await', ''); 521 | } 522 | if (clickedEl.hasAttribute('async')) { 523 | targetEl.removeAttribute('await', ''); 524 | } 525 | 526 | if (!isForm) { 527 | updateHistory( clickedEl ); 528 | } 529 | 530 | let xSrc = clickedEl.getAttribute('x-href').substring(1); 531 | (/^[! ]/.test(xSrc)) && (xSrc = xSrc.substring(1).trim()); 532 | 533 | if (isForm) { 534 | xSrc = xSrc || clickedEl.getAttribute('action'); 535 | let formMethod = clickedEl.getAttribute('method') || 'GET'; 536 | let dataType = clickedEl.hasAttribute('form-data')? 'FormData' : 'JSON'; 537 | let frmData = formMethod == 'GET'? formData(clickedEl, true) : (/FormData/gi.test(dataType)? new FormData( clickedEl ) : formData(clickedEl)); 538 | let onSuccess = clickedEl.onSuccess || clickedEl.getAttribute('onsuccess') || ''; 539 | let onError = clickedEl.onError || clickedEl.getAttribute('onerror') || ''; 540 | let options = { method:formMethod, data:frmData, onSuccess:onSuccess, onError:onError }; 541 | clickedEl.onSuccess = ''; 542 | clickedEl.onError = ''; 543 | 544 | loadExternalSrc(targetEl, xSrc, options); 545 | } else { 546 | loadExternalSrc(targetEl, xSrc); 547 | } 548 | } else { 549 | console.warn('Target element not found. Invalid target specified in element', clickedEl); 550 | } 551 | } 552 | 553 | function getAltIframeElements ( context ) { 554 | context = context || _doc; 555 | return getElements('[src]'+('audio embed iframe img input script source track video [processed] [skip-on-hash]'.split(' ').map(function(tag){ return ':not('+tag+')'; }).join('')), context); 556 | } 557 | 558 | function processIncludes (context) { 559 | context = context || _doc; 560 | let childAltFrameElements = getAltIframeElements(context); 561 | childAltFrameElements.forEach(el=>{ 562 | parseElSrcPath(el, 'src'); 563 | el.setAttribute('processed', ''); 564 | loadExternalSrc(el); 565 | }); 566 | 567 | getElements('form:not([onsubmit]):not([href])', context).forEach(formEl=>{ 568 | (!formEl.getAttribute('action') && formEl.setAttribute('onsubmit', 'return false;')); 569 | }); 570 | 571 | getElements('form[action][target^="#"]', context).forEach(formEl=>{ 572 | let formAction = formEl.getAttribute('action'); 573 | if (formAction) { 574 | formEl.setAttribute('href', '#'+(formAction.replace(/^#+/,''))); 575 | (!formEl.hasAttribute('onsubmit')) && formEl.setAttribute('onsubmit', 'return false;'); 576 | } 577 | }); 578 | 579 | getElements('[href^="#"][target^="#"]', context).forEach(el=>{ 580 | renameAttr(el, 'target', 'x-target'); 581 | renameAttr(el, 'href', 'x-href'); 582 | el.setAttribute('href', 'javascript:;'); 583 | 584 | let eHash = el.getAttribute('url-hash') || el.getAttribute('x-href'); 585 | (!/^#/.test(eHash)) && (eHash = '#'+eHash); 586 | (/^#[! ]+/.test(eHash)) && (eHash = '#'); 587 | eHash = eHash.replace(/[+ ]/g,'').replace(new RegExp('\\'+hashPathDelimiter+'+$'), ''); 588 | el.setAttribute('url-hash', eHash); 589 | 590 | let isFormEl = (el.tagName == 'FORM'); 591 | let defEvent = isFormEl? 'submit' : 'click'; 592 | let onEvent = (el.getAttribute('on') || defEvent).replace(/[^a-z]/gi,'_'); 593 | (isFormEl && !el.getAttribute('onsubmit') && el.setAttribute('onsubmit', 'return false;')); 594 | onEvent.split('_').forEach(eName=>{ 595 | eName = eName.trim().toLowerCase(); 596 | if (eName.length>2) { 597 | eName = eName.replace(/^on/,''); 598 | el.addEventListener(eName, onNavElClick); 599 | } 600 | }); 601 | }); 602 | 603 | (!childAltFrameElements.length && processOnReady()); 604 | } 605 | 606 | function getData(dataUrl, callbackFn) { 607 | return fetch(dataUrl) 608 | .then( res => { 609 | let xhrStatus = res.status; 610 | return (res.ok && ((xhrStatus >= 200 && xhrStatus < 300) || (xhrStatus == 304)))? 611 | res.json() : {error: 'Failed: [GET]'+dataUrl, status: xhrStatus}; 612 | } ) 613 | .then( resData => callbackFn(resData) ) 614 | .catch( e => { return callbackFn({error: 'Failed: [GET]'+dataUrl, e: e}); } ); 615 | } 616 | 617 | function load (xSrc, target, onLoad) { 618 | let elTarget = getElements(target)[0]; 619 | if (elTarget) { 620 | (typeof onLoad === 'function' && _onReadyQ.push(onLoad)); 621 | loadExternalSrc(elTarget, xSrc); 622 | } else { 623 | console.error('Target container not found.', target); 624 | } 625 | } 626 | 627 | function submitForm ( formId, options ) { 628 | options = options || {method: '', url:'', target:'', onSuccess:'', onError:''} 629 | let targetForm = $1(formId); 630 | if (targetForm) { 631 | if (options.method) { 632 | targetForm.setAttribute('method', options.method); 633 | } 634 | if (options.url) { 635 | targetForm.setAttribute('x-href', '#'+(options.url.replace(/^#+/,'')) ); 636 | } 637 | if (options.target) { 638 | targetForm.setAttribute('x-target', options.target); 639 | } 640 | if (options.onSuccess) { 641 | targetForm.onSuccess = options.onSuccess; 642 | } 643 | if (options.onError) { 644 | targetForm.onError = options.onError; 645 | } 646 | let submitEvent = document.createEvent("Event"); 647 | submitEvent.initEvent("submit", true, true); 648 | targetForm.dispatchEvent(submitEvent); 649 | } else { 650 | console.error('Form NOT FOUND!', formId); 651 | } 652 | } 653 | 654 | function onReady ( fnX, delay ) { 655 | if (typeof fnX === 'function') { 656 | _onReadyQ.push({fn: fnX, delay: delay||0}); 657 | processOnReady(); 658 | } 659 | } 660 | 661 | function processOnReady ( fnRes ) { 662 | if (!_pending && !getAltIframeElements().length && _onReadyQ.length && (typeof fnRes === 'undefined' || fnRes)) { 663 | nxtFn = _onReadyQ.shift(); 664 | setTimeout(()=>{ 665 | let prevFnRes = nxtFn.fn(fnRes); 666 | ((typeof prevFnRes !== 'undefined' && !prevFnRes && (_onReadyQ = []))); 667 | processOnReady( prevFnRes ); 668 | }, nxtFn.delay); 669 | } 670 | } 671 | 672 | function onDocReady () { 673 | _pending = 0; 674 | _urlHash = _loc.hash || ''; 675 | _hashLst = (_urlHashOn && _urlHash && _urlHash.split(hashPathDelimiter)) || []; 676 | _htmlDir = (_doc.body.getAttribute('components-loc') || '').replace(/^\.\//,'').replace(/\/+$/g,'').trim(); 677 | _htmlExt = (_doc.body.getAttribute('components-ext') || '').trim(); 678 | processIncludes(); 679 | setTimeout(function () { 680 | (new MutationObserver(mutationsList=>{ 681 | (mutationsList && mutationsList[0] && mutationsList[0].type === 'childList' 682 | && mutationsList[0].target && processIncludes( mutationsList[0].target )); 683 | })).observe(_doc, { childList: true, subtree: true }); 684 | }); 685 | } 686 | 687 | if ( (_doc.readyState == 'complete') || (!(_doc.readyState == 'loading' || _doc.documentElement.doScroll)) ) { 688 | onDocReady(); 689 | } else { 690 | _doc.addEventListener('DOMContentLoaded', onDocReady); 691 | } 692 | 693 | _g.alt = _g.aif = { load, onReady, getData, formData, submitForm }; 694 | 695 | })(this); -------------------------------------------------------------------------------- /dist/es6/alt-iframe.min.js: -------------------------------------------------------------------------------- 1 | (function(t){function e(t){return Object.prototype.toString.call(t).slice(8,-1).toLowerCase()}function r(t,r){return"*"==(""+r)[0]?e(t).indexOf((""+r).toLowerCase().substring(1))>=0:(""+r).toLowerCase().indexOf(e(t))>=0}function n(t){return r(t,"array")}function i(t){return"object"==typeof t||"function"==typeof t}function o(t){return r(t,"undefined")}function s(t){return r(t,"function")}function a(t){return(t||"").trim().replace(/]/g,"").replace(/(\[)|(\\)|(\/)/g,".").replace(/(\.+)/g,".").replace(/\.+$/,"").replace(/^\.+/,"")}function c(t,e,r){if(i(t)&&e){let u=e.split("|").map(t=>t.trim());e=u.shift();let l,f,h=u.join("|");{let r=0,o=a(e).split("."),s=o.length;for(f=t;r0?t.substring(0,e):t).replace(/\s/g,"");r&&(u=c(window,r))}if(u&&s(u))try{a=u.apply(e,o(i)?[]:n(i)?i:[i])}catch(t){console.error("Error calling function:",u,",",t)}else console.error("Invalid function:",t);return a}function l(t,e){let r={},n="string"==typeof t?h(t):t,i=(t,e)=>{r.hasOwnProperty(t)?(Array.isArray(r[t])||(r[t]=r[t]?[r[t]]:[]),e&&r[t].push(e)):r[t]=e};return[].slice.call(n.elements).forEach(t=>{!t.name||t.disabled||t.matches("form fieldset[disabled] *")||("checkbox"!==t.type&&"radio"!==t.type||t.checked)&&("SELECT"===t.tagName?("select-multiple"===t.type&&t.selectedIndex>=0&&i(t.name,[]),g("option",t).forEach(e=>{e.selected&&i(t.name,e.value)})):i(t.name,t.value))}),e?f(r):r}function f(t){let e="";return Object.keys(t).forEach(r=>{Array.isArray(t[r])?t[r].forEach(t=>{e+="&"+r+"="+t}):e+="&"+r+"="+t[r]}),encodeURI(e)}function h(t,e){return d(t,e)[0]}function g(t,e){return d(t,e)}function d(t,e){return e="string"==typeof e&&B.querySelector(e)||e||B,Array.prototype.slice.call(e.querySelectorAll(t))}function p(t,e,r){t.setAttribute(r,t.getAttribute(e)),t.removeAttribute(e)}function b(t){let e=B.createElement("script");e.text=t.innerHTML;for(let r=t.attributes.length-1;r>=0;r--)e.setAttribute(t.attributes[r].name,t.attributes[r].value);return e}function m(t,e,r){let n,i,o,s,a,c=oldSrc=(t.getAttribute(e)||"").trim();2===arguments.length&&(r=t.closest("[x-src]")),c&&r&&!/^(\/\/|http:\/\/|https:\/\/)/i.test(c)&&(a=O(r.getAttribute("x-src")),n=(M||a).replace(/^\/+/,""),i=new RegExp("^((.){0,2}/)*"+n),i.test(c)?c=c.replace(i,M||a):"."===c[0]&&(o=r&&r.getAttribute("x-src")||"",s=o.substring(0,o.lastIndexOf("/")+1)||(M||a)+"/",c=(s+c).replace(/\/\.?\//,"/"))),c!==oldSrc&&t.setAttribute(e,c)}function A(t,e){d("script:not([processed])",t).forEach(t=>{t.setAttribute("processed",""),e&&t.setAttribute("await","");let r=b(t);if(r.hasAttribute("src")){m(r,"src",t.closest("[x-src]"));let n=r.getAttribute("src");!/\.js$/i.test(n)&&r.setAttribute("src",n+".js");let i=!r.hasAttribute("await");!e&&i?t.parentNode.replaceChild(r,t):(p(t,"src","x-src"),T(r))}else t.parentNode.replaceChild(r,t)})}function E(t){d('link[rel="stylesheet"][href]:not([processed])',t).forEach(t=>{m(t,"href"),t.setAttribute("processed","")}),d("img[src]:not([processed])",t).forEach(t=>{!/^data:/i.test(t.getAttribute("src"))&&m(t,"src"),t.setAttribute("processed","")})}function y(){let t,e=(B.body.getAttribute("hash-error")||"").toLowerCase(),r=K.origin+K.pathname+K.search;"url"==e?(t="Page_route["+z.substring(1)+"]_not_found!_Redirected_to_this_page_root.",r=K.origin+K.pathname+"?_error="+t+K.search.replace(/^\?/,"&")):(t="Page route[#"+z.substring(1)+"] not found! Redirecting to this page root.",alert(t)),K.href=r}function x(t,e){if(X)if(t=t||z,t){let r=d('[url-hash="'+t+'"][x-target^="#"],[href="'+t+'"]');if(r.length)e&&r[0].setAttribute("skip-hash-update","1"),(!e||J&&e==z)&&(z=""),H=V,C.call(r[0],!0,e);else if(!P)if(z.indexOf(Q)>0){let t=(W&&W.split(Q)||[]).length,e=q[t];e||t<=q.length?(W+=(W?Q:"")+e,J=d('[url-hash="'+W+'"][x-target^="#"]').length?0:250,setTimeout(()=>{x(W,z)},J)):y()}else if(!j().length){let t=h(z);t?(t.scrollIntoView(!0),z=""):y()}}else{let t=d("[skip-on-hash]");t.length&&(t.forEach(t=>{t.removeAttribute("skip-on-hash")}),N())}}function w(t,e){P--;let r=t.getAttribute("x-js");if(r&&(e+='',t.removeAttribute("x-js")),"SCRIPT"==t.tagName){if(e.trim()){let t=B.createElement("script");t.id=(new Date).getMilliseconds(),t.text=e,B.head.appendChild(t).parentNode.removeChild(t)}}else{let r=t.hasAttribute("replace")||t.tagName.indexOf("REPLACE")>=0,n=r?t.parentNode:t,i=r?"outerHTML":"innerHTML",o=t.hasAttribute("await");e=e||"",t[i]=e,E(n),A(n,o),N(n)}x()}function v(t,e,r){o(t)?(t="Could not "+r.method+" "+e.url,r.onError&&(t=u(r.onError,null,[t,e.status,e]))):r.onSuccess&&(t=u(r.onSuccess,null,[t,e.status,e])),o(t)||w(r.targetEl,t)}function O(t){let e="";if(t.indexOf("/")>=0){let r=t.indexOf("/"),n=t.indexOf("/",r+1);e=("/"===t[0]||"."===t[0])&&n>r?t.substring(0,n):t.substring(0,r)}return e}function S(t){"?"===M&&t.indexOf("/")>=0&&(M=O(t))}function k(t){let e,r,n=(t||"").trim(),i="";if(!/^(\/\/|http:\/\/|https:\/\/)/i.test(n)&&(i=/\+$/.test(n)?"+":"",i&&(n=n.substring(0,n.length-1)),S(n),M&&(/^[^a-z0-9_\.\/]/gi.test(n[0])?n=n.substring(1):(e=M.replace(/^\/+/,""),r=new RegExp("^((.){0,2}/)*"+e),n=r.test(n)?n.replace(r,M):(M+"/"+n).replace(/\/\.?\//,"/"))),G&&!new RegExp(G+"$").test(n)))if(/\/\/$/.test(t)){let t=n.split("/"),e=t[t.length-2];n=n+e+G}else"/"!==n[n.length-1]&&(n+=G);return n+i}function T(t,e,r){if(r=r||{method:"GET"},e=k(e||t.getAttribute("src")),t.setAttribute("x-src",e),t.removeAttribute("src"),e){P++,/\+$/.test(e)&&(t.setAttribute("x-js",e.replace(/\.[a-z]{3,4}\+$/,".js")),e=e.substring(0,e.length-1));let n=r.method||"GET",i=r.data,o={}.toString.call(i).slice(8,-1).toLowerCase(),s="string"==o?i:"";i&&("GET"==n?("object"===o&&(s=f(i)),e=e+(s&&e.indexOf("?")<0?"?":"")+s,e=e.replace(/\?\&/,"?").replace(/\&\&/g,"&")):"object"===o&&(i=JSON.stringify(i))),r.targetEl=t,r.method=n;let a={method:n};if(i&&(a.body=i),t.hasAttribute("await"))(async()=>{let t;const n=await fetch(e,a).catch(t=>null);n&&n.ok&&(t=await n.text()),v(t,n,r)})();else{let t;fetch(e,a).then(e=>{let r;return t=e,e&&e.ok&&(r=e.text()),r}).then(e=>{v(e,t,r)}).catch(t=>null)}}}function L(t){if(X){if(!t.getAttribute("skip-hash-update")){let e=t.getAttribute("url-hash");if("#"!=e&&H!=e){H=e;try{history.pushState(null,e,e)}catch(t){}}}t.removeAttribute("skip-hash-update")}}function C(t,e){let r=this,n="FORM"==r.tagName;if(t&&e&&!n)return void r.click();if(n&&!r.checkValidity())return r.reportValidity(),!1;let i=r.getAttribute("if");if(i){let t=u(i,r);if(!t)return!1}let o=h(r.getAttribute("x-target"));if(o){o[r.hasAttribute("replace")?"setAttribute":"removeAttribute"]("replace",""),r.hasAttribute("await")&&o.setAttribute("await",""),r.hasAttribute("async")&&o.removeAttribute("await",""),n||L(r);let t=r.getAttribute("x-href").substring(1);if(/^[! ]/.test(t)&&(t=t.substring(1).trim()),n){t=t||r.getAttribute("action");let e=r.getAttribute("method")||"GET",n=r.hasAttribute("form-data")?"FormData":"JSON",i="GET"==e?l(r,!0):/FormData/gi.test(n)?new FormData(r):l(r),s=r.onSuccess||r.getAttribute("onsuccess")||"",a=r.onError||r.getAttribute("onerror")||"",c={method:e,data:i,onSuccess:s,onError:a};r.onSuccess="",r.onError="",T(o,t,c)}else T(o,t)}else console.warn("Target element not found. Invalid target specified in element",r)}function j(t){return t=t||B,d("[src]"+"audio embed iframe img input script source track video [processed] [skip-on-hash]".split(" ").map(function(t){return":not("+t+")"}).join(""),t)}function N(t){t=t||B;let e=j(t);e.forEach(t=>{m(t,"src"),t.setAttribute("processed",""),T(t)}),d("form:not([onsubmit]):not([href])",t).forEach(t=>{!t.getAttribute("action")&&t.setAttribute("onsubmit","return false;")}),d('form[action][target^="#"]',t).forEach(t=>{let e=t.getAttribute("action");e&&(t.setAttribute("href","#"+e.replace(/^#+/,"")),!t.hasAttribute("onsubmit")&&t.setAttribute("onsubmit","return false;"))}),d('[href^="#"][target^="#"]',t).forEach(t=>{p(t,"target","x-target"),p(t,"href","x-href"),t.setAttribute("href","javascript:;");let e=t.getAttribute("url-hash")||t.getAttribute("x-href");!/^#/.test(e)&&(e="#"+e),/^#[! ]+/.test(e)&&(e="#"),e=e.replace(/[+ ]/g,"").replace(new RegExp("\\"+Q+"+$"),""),t.setAttribute("url-hash",e);let r="FORM"==t.tagName,n=r?"submit":"click",i=(t.getAttribute("on")||n).replace(/[^a-z]/gi,"_");r&&!t.getAttribute("onsubmit")&&t.setAttribute("onsubmit","return false;"),i.split("_").forEach(e=>{e=e.trim().toLowerCase(),e.length>2&&(e=e.replace(/^on/,""),t.addEventListener(e,C))})}),!e.length&&D()}function R(t,e){return fetch(t).then(e=>{let r=e.status;return e.ok&&(r>=200&&r<300||304==r)?e.json():{error:"Failed: [GET]"+t,status:r}}).then(t=>e(t)).catch(r=>e({error:"Failed: [GET]"+t,e:r}))}function _(t,e,r){let n=d(e)[0];n?("function"==typeof r&&Y.push(r),T(n,t)):console.error("Target container not found.",e)}function F(t,e){e=e||{method:"",url:"",target:"",onSuccess:"",onError:""};let r=h(t);if(r){e.method&&r.setAttribute("method",e.method),e.url&&r.setAttribute("x-href","#"+e.url.replace(/^#+/,"")),e.target&&r.setAttribute("x-target",e.target),e.onSuccess&&(r.onSuccess=e.onSuccess),e.onError&&(r.onError=e.onError);let t=document.createEvent("Event");t.initEvent("submit",!0,!0),r.dispatchEvent(t)}else console.error("Form NOT FOUND!",t)}function $(t,e){"function"==typeof t&&(Y.push({fn:t,delay:e||0}),D())}function D(t){P||j().length||!Y.length||void 0!==t&&!t||(U=Y.shift(),setTimeout(()=>{let e=U.fn(t);void 0!==e&&!e&&(Y=[]),D(e)},U.delay))}function I(){P=0,z=K.hash||"",q=X&&z&&z.split(Q)||[],M=(B.body.getAttribute("components-loc")||"").replace(/^\.\//,"").replace(/\/+$/g,"").trim(),G=(B.body.getAttribute("components-ext")||"").trim(),N(),setTimeout(function(){new MutationObserver(t=>{t&&t[0]&&"childList"===t[0].type&&t[0].target&&N(t[0].target)}).observe(B,{childList:!0,subtree:!0})})}let M,G,P,z,H,V,q,J,U,B=document,K=B.location,Q="/",W="",X="off"!=(B.body.getAttribute("url-hash")||"").toLowerCase(),Y=[];X&&(window.onhashchange=function(){V=K.hash||"",V?V!=H&&(z=V,x()):(K.href.indexOf("#")<0&&K.reload(),H="#")}),"complete"==B.readyState||"loading"!=B.readyState&&!B.documentElement.doScroll?I():B.addEventListener("DOMContentLoaded",I),t.alt=t.aif={load:_,onReady:$,getData:R,formData:l,submitForm:F}})(this); -------------------------------------------------------------------------------- /example/html-files/footer.html: -------------------------------------------------------------------------------- 1 |
2 | © 2020 - OpenSource. 3 |
-------------------------------------------------------------------------------- /example/html-files/header.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/html-files/home.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello, world!

3 |

This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.

4 |
5 |

It uses utility classes for typography and spacing to space content out within the larger container.

6 |

7 | Learn more 8 |

9 |
-------------------------------------------------------------------------------- /example/html-files/nav-menu.html: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /example/html-files/profile.html: -------------------------------------------------------------------------------- 1 |
2 | Card image cap 3 |
4 |
Card title
5 |

Some quick example text to build on the card title and make up the bulk of the card's content.

6 | Go somewhere 7 |
8 |
-------------------------------------------------------------------------------- /example/html-files/search-result.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | alt-iframe 8 | 9 | 10 | 11 | 12 | 13 | 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /example2/components/footer.html: -------------------------------------------------------------------------------- 1 |
2 | © 2020 - OpenSource. 3 |
-------------------------------------------------------------------------------- /example2/components/header.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example2/components/home.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello, world!

3 |

This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.

4 |
5 |

It uses utility classes for typography and spacing to space content out within the larger container.

6 |

7 | Learn more 8 |

9 |
-------------------------------------------------------------------------------- /example2/components/home.js: -------------------------------------------------------------------------------- 1 | console.log('inside home.js'); -------------------------------------------------------------------------------- /example2/components/nav-menu.html: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /example2/components/profile/index.html: -------------------------------------------------------------------------------- 1 |
2 | Card image cap 3 |
4 |
Card title
5 |

Some quick example text to build on the card title and make up the bulk of the card's content.

6 | Go somewhere 7 |
8 |
9 |
10 |
11 | 16 |
17 |
Container
18 |
19 | 20 | -------------------------------------------------------------------------------- /example2/components/profile/index.js: -------------------------------------------------------------------------------- 1 | console.log('inside profile index.js'); -------------------------------------------------------------------------------- /example2/components/profile/section1.html: -------------------------------------------------------------------------------- 1 |
2 |

Section - 1

3 |
4 |
5 |
6 | 11 |
12 |
Container
13 |
14 | -------------------------------------------------------------------------------- /example2/components/profile/section2.html: -------------------------------------------------------------------------------- 1 |
2 |

Section - 2

3 |
-------------------------------------------------------------------------------- /example2/components/profile/section3.html: -------------------------------------------------------------------------------- 1 |
2 |

Section - 3

3 |
-------------------------------------------------------------------------------- /example2/components/profile/subSection1.1.html: -------------------------------------------------------------------------------- 1 |
2 |

Sub Section - 1

3 |
4 | 5 |
6 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Cum enim incidunt quos fugit officiis. Ad repellendus delectus ut optio quia quasi enim, nihil facilis quae voluptatum maiores harum sequi asperiores.

7 |

Praesentium eum, itaque dolor doloremque, magnam possimus eos fuga doloribus, sint sit est delectus distinctio eius recusandae enim nesciunt debitis dicta! Asperiores fugit sunt magni blanditiis illum, expedita distinctio dolorum?

8 |

Similique ut enim architecto provident quibusdam sed facere doloribus modi eligendi sint? Commodi aut provident ipsam aliquam ratione aperiam minima totam, fuga magnam sapiente, perferendis laboriosam voluptatum asperiores unde iste.

9 |

Commodi, magni fugit culpa iste quidem tempora mollitia consequuntur voluptas obcaecati, maiores veritatis consequatur dicta nesciunt quam ut repellendus eveniet doloremque eos non placeat officia accusamus? Nulla enim qui laborum.

10 |

Iusto perspiciatis ipsa fuga magnam dolore molestiae itaque nostrum officia at, adipisci eos nobis deserunt ullam ab nulla a fugiat pariatur voluptatum cumque, animi culpa assumenda et error? Ex, dolorum!

11 |

Possimus, nobis nisi tempore odio itaque quisquam repellendus repudiandae dignissimos adipisci porro consectetur vel quaerat necessitatibus facilis quae fugiat quibusdam aspernatur eum illo asperiores harum ipsa atque! In, natus tempore?

12 |

Fuga, odio rerum. Saepe vero consequatur nostrum facilis. Quam praesentium corrupti minus voluptas? Quo quisquam sed dolorem veniam, minima nulla facere unde consequuntur magnam incidunt saepe. Numquam dolor nulla mollitia?

13 |

Quaerat, velit similique odit magnam nulla non praesentium corrupti unde asperiores voluptas, sit atque. Deleniti, corporis omnis tempore et aspernatur perspiciatis qui voluptatum distinctio exercitationem. Culpa ex eum voluptates amet.

14 |

Totam, illo. Quae optio quisquam, provident numquam sit fuga quo neque tempora quia molestias, ad magni aspernatur suscipit eos explicabo nisi alias. Tempore distinctio sed, dignissimos quasi ad placeat fuga.

15 |

Perferendis placeat nisi eligendi nostrum accusantium quasi esse rerum asperiores. Placeat inventore ab eaque, harum eligendi mollitia? Aut reiciendis, earum velit maxime distinctio repellendus, aliquam voluptatibus praesentium qui, id magnam!

16 |
17 | TOP 18 | 19 |
20 | 21 | -------------------------------------------------------------------------------- /example2/components/profile/subSection1.2.html: -------------------------------------------------------------------------------- 1 |
2 |

Sub Section - 2

3 |
4 | -------------------------------------------------------------------------------- /example2/components/profile/subSection1.3.html: -------------------------------------------------------------------------------- 1 |
2 |

Sub Section - 3

3 |
4 | -------------------------------------------------------------------------------- /example2/components/search-result.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | alt-iframe 8 | 9 | 10 | 11 | 12 | 13 | 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 |
35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example3/components/appRoot.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | © 2021. Open Source - MIT. 7 |
-------------------------------------------------------------------------------- /example3/components/asyncForm.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Async Form

4 | 5 |
8 | 13 | 14 |
15 | 16 |
17 | 21 |
22 | 23 |
24 | 28 |
29 | 30 |
31 | 34 |
35 | 36 |
37 | 40 |
41 | 42 |
43 | Fruits:
44 | 45 | 46 |
47 | 48 |
49 | Rating:
50 | 51 | 52 | 53 |
54 | 55 |
56 | 64 |
65 | 66 |
67 | 75 |
76 | 77 |
78 | 81 |
82 |
83 | 84 |
85 | 86 |
87 |
88 | Method: 89 | 90 | 91 |
92 | 93 |
94 | Response Type: 95 | 96 | 97 | 98 |
99 | 100 | 101 |
102 |
103 | 104 |
105 | 106 |

Response:

107 |
108 | 109 |
110 | 111 | 112 | -------------------------------------------------------------------------------- /example3/components/contacts.html: -------------------------------------------------------------------------------- 1 |

Contacts

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
AvatarFirst, Last NameemailAction
14 | 15 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /example3/components/home.html: -------------------------------------------------------------------------------- 1 |
2 |

Hello, world!

3 |

This is a simple Low-Code Single Page Application built using nano-javascript library (alt-iframe).

4 |

You can use this library to build rapid prototypes with low-code. It's component based, so it's easy to port to other frameworks for production.

5 |
6 |

It is built on vanilla javascript and works on all modern browsers including IE11.

7 | Learn more 8 |
9 | 10 | -------------------------------------------------------------------------------- /example3/components/myProfile.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | -------------------------------------------------------------------------------- /example3/components/nav.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example3/components/profileCard.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |

6 | Go somewhere 7 |
8 |
-------------------------------------------------------------------------------- /example3/components/profileEdit.html: -------------------------------------------------------------------------------- 1 |

Edit Profile

2 |
3 | ... 4 |
5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /example3/components/search.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | -------------------------------------------------------------------------------- /example3/components/template-Handlebars.html: -------------------------------------------------------------------------------- 1 |

Handlebars

2 |
3 |
4 | Template
5 | 10 |
11 |
12 | Data (JSON)
13 | 21 |
22 |
23 | Preview 24 |    cT: ms 25 |    rT: ms 26 |
27 | 28 |
29 |
-------------------------------------------------------------------------------- /example3/components/template-Mustache.html: -------------------------------------------------------------------------------- 1 |

Mustache

2 |
3 |
4 | Template
5 | 9 |
10 |
11 | Data (JSON)
12 | 21 |
22 |
23 | Preview 24 |    cT: ms 25 |    rT: ms 26 |
27 | 28 |
29 |
-------------------------------------------------------------------------------- /example3/components/template-doT.html: -------------------------------------------------------------------------------- 1 |

doT

2 |
3 |
4 | Template
5 | 9 |
10 |
11 | Data (JSON)
12 | 18 |
19 |
20 | Preview 21 |    cT: ms 22 |    rT: ms 23 |
24 | 25 |
26 |
27 | -------------------------------------------------------------------------------- /example3/components/template-dust.html: -------------------------------------------------------------------------------- 1 |

dust (LinkedIn)

2 |
3 |
4 | Template
5 | 8 |
9 |
10 | Data (JSON)
11 | 20 |
21 |
22 | Preview 23 |    cT: ms 24 |    rT: ms 25 |
26 | 27 |
28 |
-------------------------------------------------------------------------------- /example3/components/template-ejs.html: -------------------------------------------------------------------------------- 1 |

ejs

2 |
3 |
4 | Template
5 | 10 |
11 |
12 | Data (JSON)
13 | 24 |
25 |
26 | Preview 27 |    cT: ms 28 |    rT: ms 29 |
30 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /example3/components/template-lodash.html: -------------------------------------------------------------------------------- 1 |

_ (lodash)

2 |
3 |
4 | Template
5 | 10 |
11 |
12 | Data (JSON)
13 | 18 |
19 |
20 | Preview 21 |    cT: ms 22 |    rT: ms 23 |
24 | 25 |
26 |
27 | -------------------------------------------------------------------------------- /example3/components/template-nunjucks.html: -------------------------------------------------------------------------------- 1 |

Nunjucks (mozilla)

2 |
3 |
4 | Template
5 | 9 |
10 |
11 | Data (JSON)
12 | 20 |
21 |
22 | Preview 23 |    cT: ms 24 |    rT: ms 25 |
26 | 27 |
28 |
29 | -------------------------------------------------------------------------------- /example3/components/template-nxT.html: -------------------------------------------------------------------------------- 1 |

nxT (SPA.js)

2 |
3 |
4 | Template
5 | 10 |
11 |
12 | Data (JSON)
13 | 21 |
22 |
23 | Preview 24 |    cT: ms 25 |    rT: ms 26 |
27 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /example3/components/template-template7.html: -------------------------------------------------------------------------------- 1 |

Template7

2 |
3 |
4 | Template
5 | 8 |
9 |
10 | Data (JSON)
11 | 17 |
18 |
19 | Preview 20 |    cT: ms 21 |    rT: ms 22 |
23 | 24 |
25 |
26 | -------------------------------------------------------------------------------- /example3/components/templates.html: -------------------------------------------------------------------------------- 1 |
2 |

Templates Preview

3 | 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 | 32 |
33 | 34 | -------------------------------------------------------------------------------- /example3/css/style.css: -------------------------------------------------------------------------------- 1 | .fixed-bottom { 2 | height: 50px; 3 | padding: 10px; 4 | color: #aaa; 5 | background-color: #eee; 6 | text-align: right; 7 | position: fixed; 8 | left:0; 9 | bottom:0; 10 | width: 100%; 11 | } 12 | 13 | .nav-item.active { 14 | border-top: 2px solid orange; 15 | } -------------------------------------------------------------------------------- /example3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SPA - Ajax 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /example3/js/common.js: -------------------------------------------------------------------------------- 1 | function getProfile(pid) { 2 | 3 | $.ajax('https://reqres.in/api/users/' + pid) 4 | .done(function (apiData) { 5 | // console.log('🚀 ~ apiData', apiData); 6 | 7 | var profData = apiData.data; 8 | // console.log('🚀 ~ profData', profData); 9 | 10 | showProfile(profData); 11 | }); 12 | 13 | } 14 | 15 | // bind without template 16 | function showProfile(profData) { 17 | 18 | var fullName = profData.first_name + ' ' + profData.last_name; 19 | 20 | $('#profImg').attr({ 21 | src: profData.avatar, 22 | alt: fullName 23 | }); 24 | 25 | $('#profFullName').html(fullName); 26 | $('#profEmail').html(profData.email); 27 | 28 | } 29 | 30 | // Highlight nav menu item 31 | function setMenu(menuLink) { 32 | $(menuLink).addClass('active').siblings().removeClass('active'); 33 | } 34 | 35 | // Template Preview links click event listener 36 | $(document).on('click', '.btn-preview', function (e) { 37 | var btnPreview = e.target; 38 | var $section = $(btnPreview).closest('section'); 39 | // var tmplType = $section.data('type'); 40 | // var tmplContent = $section.find('textarea')[0].value; 41 | var tmplData = JSON.parse($section.find('textarea')[1].value.trim() || '{}'); 42 | var previewTarget = $section.find('.preview')[0]; 43 | var elTmplSrc = $section.find('textarea')[0]; 44 | 45 | // nxT(tmplType+':'+tmplContent, tmplData, previewTarget); //tmpl: template-content with type: prefix; Handlebars: ... 46 | // nxT('#tmpl-'+tmplType, tmplData, previewTarget); //tmpl: template-element-ID; #templateXyz 47 | // nxT('#tmpl-'+tmplType+':'+tmplType, tmplData, previewTarget); //tmpl: template-elementID with :type suffix; #templateXyz:Handlebars 48 | 49 | //tmpl: template-element 50 | nxT(elTmplSrc, tmplData, previewTarget, function () { 51 | $pT = $section.find('.performance-time'); 52 | $pT[0].innerHTML = (elTmplSrc.getAttribute('compile-time')); 53 | $pT[1].innerHTML = (previewTarget.getAttribute('render-time')); 54 | }); 55 | 56 | }); 57 | --------------------------------------------------------------------------------