diff --git a/.gitignore b/.gitignore index 26c5e80..14ca1ba 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,3 @@ sign.sh AIO\.sh -app/files/tweaks/cmu-autorun/ diff --git a/app/assets/css/index.css b/app/assets/css/index.css index c32bb36..062edab 100644 --- a/app/assets/css/index.css +++ b/app/assets/css/index.css @@ -315,7 +315,7 @@ input[type=checkbox]#bgrotator, .accordion-content input[type=checkbox] { visibility: visible; } tr.bgrotator-button { - height: 100%; + height: 100%; } img.loader {} #bg-img { @@ -348,11 +348,25 @@ span.test-panel-toggle, .footer-donate { left: 10px; z-index: 99999; } +.footer-donate { + opacity: 0; + bottom: 40px; + transition: .4s ease .2s; +} +.footer-donate:hover { + opacity: 1; + transition: .2s ease-in 0s; +} +.footer-secret:hover+.footer-donate { + opacity: 1; + transition: .2s linear 0s; +} .copyright { position: fixed; right: 0; left: 0; margin: auto; + max-width: 200px; } .copyleft { font-weight: 500 @@ -370,6 +384,11 @@ footer .contact-form { footer a { cursor: pointer; } +footer .footer-secret { + width: 120px; + position: fixed; + left: 10px; +} footer .footer-secret a { color: transparent; left: 100px; @@ -1013,9 +1032,9 @@ body.w3-black { font-weight: 900; } .bootbox-body .w3-center h3 a, .bootbox-body .w3-center h3 button { - letter-spacing: 2.4px; + letter-spacing: 1.4px; font-weight: 600; - min-width: 350px; + width: 350px; text-overflow: ellipsis; } .compFinishBox .bootbox-body { @@ -1943,7 +1962,7 @@ select#spdOp-barThemeStart { bottom: 10%; } ::-webkit-scrollbar-button:single-button:start { - height: 0px!important; + height: 0px !important; } } @media only screen and (max-height: 580px) { @@ -2521,7 +2540,7 @@ input:disabled { cursor: not-allowed; } .slide-pop { - bottom: 20%; + bottom: 40%; right: 10px; position: absolute; border: 3px groove #524a8a; @@ -2568,16 +2587,64 @@ input:disabled { display: initial; } .isink input[type=checkbox].w3-check { - height: 15px; - width: 15px; + height: 15px; + width: 15px; } .isink { - text-align: center; + text-align: center; } div#goog-gt-tt { - display: none!important; + display: none !important; } .goog-text-highlight { - box-shadow:none!important; - background: transparent!important; + box-shadow: none !important; + background: transparent !important; +} +.ppdonate { + opacity: 0.5; +} +.ppdonate:hover { + opacity: 1; +} +div#serial-window { + background: #fff; + padding-top: 100px; + padding-bottom: 100px; +} +.serial-img { + width: 46.6%; + max-width: 46.6%; + width: 600px; + height: auto; +} +.copied-msg { + color: #ff0000; + font-size: 10px; + font-style: oblique; + display: inline; + font-weight: 600; +} +span.one-liner code input, span.one-liner code { + width: 65px; + color: #000; + text-align: center; +} +pre code input, pre code { + width: 100%; +} +#serial-window pre button { + background: #32aeff; +} +pre button.w3-btn { + background: #fff; + color: #000; + display: block; + transition: 1s ease-in-out .5s; +} +#serial-window pre button.w3-btn:hover { + background: #0000ff; + color: #00ff00; +} +.gritter-item-wrapper img { + max-width: 100%; } diff --git a/app/assets/images/btn_donate_LG.gif b/app/assets/images/btn_donate_LG.gif new file mode 100644 index 0000000..c7d2bf8 Binary files /dev/null and b/app/assets/images/btn_donate_LG.gif differ diff --git a/app/assets/js/build-tweaks.js b/app/assets/js/build-tweaks.js index 3d79af1..f0ef0e7 100644 --- a/app/assets/js/build-tweaks.js +++ b/app/assets/js/build-tweaks.js @@ -80,7 +80,7 @@ function buildTweaksConfig (user, apps) { try { mkdirp.sync(`${tmpdir}/config/`) } catch (e) { - m = `${e} - Error occured while creating '_copy_to_usb' folder. Try closing all other running programs and folders before compiling.` + var m = `${e} - Error occured while creating '_copy_to_usb' folder. Try closing all other running programs and folders before compiling.` aioLog(e.message, m) return } @@ -591,7 +591,7 @@ function buildTweak (user) { var offBG = user.mainOps.includes(10) ? `${varDir}/OffScreenBackground.png` : path.resolve(approot, '../background-images/default/OffScreenBackground.png') var inStrOff = fs.createReadStream(offBG) inStrOff.on('error', (err) => { - aioLog('ERROR: No Off Screen Background Chosen... Skipping') + aioLog('ERROR: No Off-Screen Background Chosen... ', err) }) inStrOff.on('open', () => { addTweak(`00_offbackground-${user.mainOps.includes(10) ? 'i' : 'u'}.txt`) @@ -600,7 +600,7 @@ function buildTweak (user) { aioLog('Off Screen Background Copy Successful!') }) outOff.on('error', (err) => { - aioLog(err, 'ERROR: Copy Off Screen Background Failed!') + aioLog('ERROR: Copy Off Screen Background Failed!', err) }) inStrOff.pipe(outOff) }) @@ -609,31 +609,31 @@ function buildTweak (user) { if (user.mainOps.includes(2)) { var inStrbg = fs.createReadStream(`${getBackground}`) inStrbg.on('error', (err) => { - aioLog('ERROR: No Background Chosen... Skipping') + aioLog('ERROR: No Background Chosen...', err) }) inStrbg.on('open', () => { - if (user.mainOps.includes(6)) { - addTweak('00_bgrotator-i.txt') - } var out = fs.createWriteStream(`${tmpdir}/config/background.png`, { flags: 'w' }) out.on('close', () => { aioLog('Background Copy Successful!') }) out.on('error', (err) => { - aioLog(err, 'Background Copy Failed!') + aioLog('Background Copy Failed!', err) }) inStrbg.pipe(out) - addTweak('00_background.txt') }) + if (user.mainOps.includes(6)) { + addTweak('00_bgrotator-i.txt') + } + addTweak('00_background.txt') } if (user.mainOps.includes(5)) { addTweak('00_sd-cid.txt') addTweakDir('get_sd_cid', true) } - /*if (user.multictrlbtns) { + /* if (user.multictrlbtns) { addTweak('00_multicontroller-i.txt') addTweakDir('multicontroller', true) - }*/ + } */ if (user.options.includes(19) || user.options.includes(17) || user.options.includes(25) || user.options.includes(27) || user.options.includes(28) || user.options.includes(119) || user.options.includes(117) || user.options.includes(125) || user.options.includes(127) || user.options.includes(128)) { addTweakDir('bin', true) if (user.options.includes(19) || user.options.includes(17) || user.options.includes(25) || user.options.includes(27) || user.options.includes(28)) { @@ -665,10 +665,8 @@ function buildTweak (user) { if (user.destruct || copySwapfile) { addTweak('99_self-destruct.txt') } - // Add root files to tmp and write tweaks.sh addRootFiles(user.dataDump) - setTimeout(() => { // Finish with the end script addTweak(user.options.includes(11) ? '00_factory-reset-end.txt' : '00_end.txt') @@ -753,7 +751,6 @@ function writeSpeedoConfigFile (user) { speedoConfig.push(`${builddir}/config/speedometer_config/config-start.js`) speedoConfig.push(`${varDir}/spdConf.txt`) speedoConfig.push(`${builddir}/config/speedometer_config/config-end.js`) - var config = fs.createWriteStream(`${tmpdir}/config/speedometer/speedometer-config.js`) new appender(speedoConfig).pipe(config) config.on('close', () => { @@ -1050,7 +1047,8 @@ function aioLog (logMsg, err) { userView.innerHTML = logMsg } if (err) { - AIO_LOG_HTML += `
  • ${err}: ${logMsg}
  • \n` + AIO_LOG_HTML += `
  • ${err}
  • ${logMsg}
  • \n` + $('#sidePanel').append(`

    ${logMsg}

    ${err}
    `) errFlag = true printAIOlog() // dialog.showErrorBox(err) @@ -1098,94 +1096,92 @@ function appendAIOlog (logMsg) { } } // Returns the available usb drives -function usbDrives () { +async function usbDrives () { + var dsklst = await drivelist.list() var disks = [] var usbDriveLst = [] try { - drivelist.list((error, dsklst) => { - if (error) { throw error } - dsklst.forEach((drive) => { - if (!drive.isSystem) { - disks.push({ 'desc': drive.description.replace(' USB Device', ''), 'mp': `${drive.mountpoints[0].path}` }) - usbDriveLst.push({ 'text': ` ${drive.mountpoints[0].path.replace(/\\/g, '/')} ${drive.description.replace(' USB Device', '')}`, 'value': drive.mountpoints[0].path }) - } - }) - introJs().hideHints() - var usb = disks - var lst = '' - if (usb.length < 1) { - appendAIOlog(`
  • No USB Drives Found
  • `) - unzipSwapfile(null) - } else if (usb.length > 1) { - lst += `

    ${usb.length} ${langObj.popupMsgs[6].msg}:

    ` - var usbuttons = '' - for (var j = 0; j < usb.length; j++) { - var mpLoc = (process.platform === 'win32') ? `${usb[j].mp.replace(/\\/g, '')}` : `${usb[j].mp}` - lst += `

    ${mpLoc} ${usb[j].desc} ` - lst += `

    ` - appendAIOlog(`
  • Found USB Drive #${j + 1} - ${mpLoc} ${usb[j].desc}
  • `) - } - lst += `
    ${langObj.popupMsgs[8].msg}:
    ${langObj.popupMsgs[2].msg}` - lst += usbuttons - lst += `` - bootbox.prompt({ - title: lst, - inputType: 'select', - inputOptions: usbDriveLst, - className: 'copytoUSBMulti', - buttons: { - confirm: { - label: ` ${langObj.popupMsgs[3].msg}` - }, - cancel: { - label: ` ${langObj.popupMsgs[4].msg}` - } + dsklst.forEach((drive) => { + if (!drive.isSystem && drive.mountpoints && drive.mountpoints[0] && drive.mountpoints[0].path) { + disks.push({ 'desc': drive.description.replace(' USB Device', ''), 'mp': `${drive.mountpoints[0].path}` }) + usbDriveLst.push({ 'text': ` ${drive.mountpoints[0].path.replace(/\\/g, '/')} ${drive.description.replace(' USB Device', '')}`, 'value': drive.mountpoints[0].path }) + } + }) + introJs().hideHints() + var usb = disks + var lst = '' + if (usb.length < 1) { + appendAIOlog(`
  • No USB Drives Found
  • `) + unzipSwapfile(null) + } else if (usb.length > 1) { + lst += `

    ${usb.length} ${langObj.popupMsgs[6].msg}:

    ` + var usbuttons = '' + for (var j = 0; j < usb.length; j++) { + var mpLoc = (process.platform === 'win32') ? `${usb[j].mp.replace(/\\/g, '')}` : `${usb[j].mp}` + lst += `

    ${mpLoc} ${usb[j].desc} ` + lst += `

    ` + appendAIOlog(`
  • Found USB Drive #${j + 1} - ${mpLoc} ${usb[j].desc}
  • `) + } + lst += `
    ${langObj.popupMsgs[8].msg}:
    ${langObj.popupMsgs[2].msg}` + lst += usbuttons + lst += `` + bootbox.prompt({ + title: lst, + inputType: 'select', + inputOptions: usbDriveLst, + className: 'copytoUSBMulti', + buttons: { + confirm: { + label: ` ${langObj.popupMsgs[3].msg}` }, - callback: function (result) { - if (!result) { - unzipSwapfile(null) - } else { - settings.set('delCopyFolder', $('#rmCpDirCheck').prop('checked')) - copyToUSB(result) - } + cancel: { + label: ` ${langObj.popupMsgs[4].msg}` + } + }, + callback: function (result) { + if (!result) { + unzipSwapfile(null) + } else { + settings.set('delCopyFolder', $('#rmCpDirCheck').prop('checked')) + copyToUSB(result) } - }) - $('#rmCpDirCheck').prop('checked', settings.get('delCopyFolder', false)) - } else if (usb.length === 1) { - lst = `

    ${langObj.popupMsgs[6].msg}:

    ` - for (var k = 0; k < usb.length; k++) { - lst += `

    ${usb[k].mp.replace(/\\/g, '/')} ${usb[k].desc}

    ` - appendAIOlog(`
  • USB Drive - ${usb[k].mp.replace(/\\/g, '/')} ${usb[k].desc}
  • `) } - var mpLocation = (process.platform === 'win32') ? `${usb[0].mp.replace(/\\/g, '/')}` : `${usb[0].mp}` - lst += `${langObj.popupMsgs[7].msg} ${mpLocation.replace(/[\/:]/g, '')}?
    ${langObj.popupMsgs[2].msg}` - lst += `` - lst += `` - bootbox.confirm({ - title: `Copy files to USB drive?`, - message: lst, - className: 'copytoUSB1', - buttons: { - confirm: { - label: ` ${langObj.popupMsgs[3].msg}` - }, - cancel: { - label: ` ${langObj.popupMsgs[4].msg}` - } + }) + $('#rmCpDirCheck').prop('checked', settings.get('delCopyFolder', false)) + } else if (usb.length === 1) { + lst = `

    ${langObj.popupMsgs[6].msg}:

    ` + for (var k = 0; k < usb.length; k++) { + lst += `

    ${usb[k].mp.replace(/\\/g, '/')} ${usb[k].desc}

    ` + appendAIOlog(`
  • USB Drive - ${usb[k].mp.replace(/\\/g, '/')} ${usb[k].desc}
  • `) + } + var mpLocation = (process.platform === 'win32') ? `${usb[0].mp.replace(/\\/g, '/')}` : `${usb[0].mp}` + lst += `${langObj.popupMsgs[7].msg} ${mpLocation.replace(/[\/:]/g, '')}?
    ${langObj.popupMsgs[2].msg}` + lst += `` + lst += `` + bootbox.confirm({ + title: `Copy files to USB drive?`, + message: lst, + className: 'copytoUSB1', + buttons: { + confirm: { + label: ` ${langObj.popupMsgs[3].msg}` }, - callback: function (result) { - if (!result) { - unzipSwapfile(null) - } else { - settings.set('delCopyFolder', $('#rmCpDirCheck').prop('checked')) - copyToUSB(mpLocation) - } + cancel: { + label: ` ${langObj.popupMsgs[4].msg}` } - }) - $('#rmCpDirCheck').prop('checked', settings.get('delCopyFolder', false)) - return usb - } - }) + }, + callback: function (result) { + if (!result) { + unzipSwapfile(null) + } else { + settings.set('delCopyFolder', $('#rmCpDirCheck').prop('checked')) + copyToUSB(mpLocation) + } + } + }) + $('#rmCpDirCheck').prop('checked', settings.get('delCopyFolder', false)) + return usb + } } catch (e) { bootbox.alert({ title: '
    Error Locating Available USB Drives
    ', @@ -1216,7 +1212,7 @@ function copyToUSB (mp) { className: 'copyingtoUSB', closeButton: false }) - if (!keeplog) { + if (userOps.autorun.installer && userOps.autorun.serial) { mp = `${mp}/XX` mkdirp.sync(mp) } @@ -1279,7 +1275,7 @@ function unzipSwapfile (dest) { fs.unlinkSync(`${swapdest}/swapfile`) appendAIOlog(`
  • Swapfile Error: ${err}
  • `) console.error(err.toString(), err) - dialog.showErrorBox('Swapfile Error',`CANNOT UNZIP SWAPFILE - ${err.toString()}`) + dialog.showErrorBox('Swapfile Error', `CANNOT UNZIP SWAPFILE - ${err.toString()}`) } else { appendAIOlog(`
  • Swapfile Unzipped.
  • `) } @@ -1317,7 +1313,7 @@ function finishedMessage (mp) { bootbox.hideAll() if (errFlag) { bootbox.dialog({ - message: `
    ×

    An Error Has Occured. Please Try Again.


    ${strtOver}

    ${saveBtn}

    ${viewLog}

    `, + message: `
    ×

    An Error Has Occured.

    ${$('#AIO-ERR').html()}

    ${strtOver}

    ${saveBtn}

    ${viewLog}

    Please Try Again.

    `, className: 'finishedMessage', closeButton: false }) @@ -1496,9 +1492,14 @@ function buildAutorunInstaller (user) { aioLog('ERROR COPYING ID7RECOVERY FILES', err) } else { rimraf.sync(`${tmpdir}/**/*.md`) - rimraf.sync(`${tmpdir}/00-*/*.txt`) - if (!user.autorun.serial) { + rimraf.sync(`${tmpdir}/02-*/*.txt`) + if (user.autorun.serial) { + fs.unlinkSync(`${tmpdir}/tweaks.sh`) + } else { fs.unlinkSync(`${tmpdir}/run.sh`) + if (!user.backups.skipconfirm) { + replaceInFile(`${tmpdir}/tweaks.sh`, '# confirmation ', '') + } } aioLog('ID7_recovery Pack Copied Successfully!') addWifiAP(user) @@ -1522,11 +1523,11 @@ function addWifiAP (user) { aioLog('ERROR COPYING AUTORUN FILES', err) } if (!user.autorun.autoADB) { - rimraf.sync(`${tmpdir}/00-start-adb/`) + rimraf.sync(`${tmpdir}/*-start-adb/`) rimraf.sync(`${tmpdir}/adb`) } if (!user.autorun.autoWIFI) { - rimraf.sync(`${tmpdir}/00-start-wifiAP/`) + rimraf.sync(`${tmpdir}/*-start-wifiAP/`) } }) } @@ -1550,12 +1551,12 @@ function addWifiAP (user) { title: 'Values Were Not Changed', message: 'WiFi AP Will not be installed', callback: () => { - rimraf.sync(`${tmpdir}/00-start-wifiAP/`) + rimraf.sync(`${tmpdir}/*-start-wifiAP/`) serialCheck(user) } }) } else { - fs.writeFileSync(`${tmpdir}/00-start-wifiAP/wifiAP.config`, result + '\n') + fs.writeFileSync(`${tmpdir}/*-start-wifiAP/wifiAP.config`, result + '\n') serialCheck(user) } } diff --git a/app/assets/js/events.js b/app/assets/js/events.js index 2e70ebe..0348daf 100644 --- a/app/assets/js/events.js +++ b/app/assets/js/events.js @@ -77,15 +77,18 @@ ipc.on('already-downloaded', function (event, filename) { }) }) ipc.on('selected-joined-bg', function (event, filepath) { - var outFile = `${getBackground}` - clipboard.writeImage(filepath[0]) - joinedPhoto(filepath[0]) - let bgNotification = new Notification('Background', { - body: `Your Infotainment Background Will Be Changed To: ${filepath}`, - icon: 'favicon.ico', - silent: true - }) - bgNotification.onclick = () => {} + if(filepath && filepath[0]) { + var outFile = `${getBackground}` + clipboard.writeImage(filepath[0]) + joinedPhoto(filepath[0]) + let bgNotification = new Notification('Background', { + body: `Your Infotainment Background Will Be Changed To: ${filepath[0]}`, + icon: 'favicon.ico', + silent: true + }) + bgNotification.onclick = () => {} + //snackbar(`Your Infotainment Background Will Be Changed To: ${filepath[0]}`) + } }) ipc.on('selected-bg', function (event, filepath) { var outFile = `${getBackground}` @@ -97,6 +100,7 @@ ipc.on('selected-bg', function (event, filepath) { icon: 'favicon.ico', silent: true }) + snackbar(`Your Infotainment Background: ${filepath}`) bgNotification.onclick = () => { $('#imgframe').click() } @@ -111,6 +115,7 @@ ipc.on('selected-offscreen-bg', function (event, filepath) { silent: true }) bgNotification.onclick = () => {} + snackbar(`Your Infotainment Off-Screen Background: ${filepath}`) }) ipc.on('set-bg', (prev) => { var bgNoCache = `${getBackground}?` + new Date().getTime() @@ -127,8 +132,9 @@ ipc.on('selected-album-art', function (event, filepath) { settings.set('blank-album-art', `${filepath}`) fs.writeFileSync(`${outFile}`, nativeImage.createFromPath(`${filepath}`).resize({ 'width': 146, 'height': 146 }).toPNG()) setTimeout(function () { - var bgNoCache = `${varDir}/no_artwork_icon.png?` + new Date().getTime() - $('#blnk-albm-img').html(``) + var bgNoCache = `` + $('#blnk-albm-img').html(`${bgNoCache}`) + snackbar(`Blank Album Art: ${bgNoCache}`) }, 2000) }) ipc.on('aio-info', function (event) { diff --git a/app/assets/js/index.js b/app/assets/js/index.js index 5be9c96..ed4e2de 100644 --- a/app/assets/js/index.js +++ b/app/assets/js/index.js @@ -10,7 +10,7 @@ ** ** ** ************************************************************************** ** \* ************************************************************************** */ -/* jshint esversion:6, -W033, -W117, -W097, -W116 */ +/* jshint esversion:8, -W033, -W117, -W097, -W116 */ const { electron, nativeImage, remote, clipboard, shell } = require('electron') const { app, BrowserWindow, dialog } = remote const _ = require('lodash') @@ -37,7 +37,7 @@ const mkdirp = require('mkdirp') // Equiv of Unix command mkdir -p const rimraf = require('rimraf') // Equiv of Unix command rm -rf var copyFolderLocation = persistantData.get('copyFolderLocation', app.getPath('desktop')) var visits = persistantData.get('visits', 0) -var hasSpeedCamFiles = fs.existsSync(`${app.getPath('userData')}/speedcam-patch/`) +var hasSpeedCamFiles = false // fs.existsSync(`${app.getPath('userData')}/speedcam-patch/`) var translateSchema, langPath, lang, langDefault var colordir = `${app.getPath('userData')}/color-schemes/` // Location of downloaded color theme files (userData) var hasColorFiles = fs.existsSync(`${colordir}`) @@ -47,9 +47,11 @@ var logFileName = 'MZD_LOG' // Name of log file (without extension) var varDir = `${app.getPath('userData')}/background/` // Location of files with saved variables var getBackground = `${varDir}/background.png` var date = function () { return new Date() } +var dataURL = '' +var aioURL = '' process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true var helpClick = false -var updateVer = 284 +var updateVer = 285 // require('./lib/log')('MZD-AIO-LOG') // var output = process.stdout // var errorOutput = process.stderr @@ -95,7 +97,6 @@ fs.readdir(testFolder, (err, files) => { }) */ - function saveMenuLock () { persistantData.set('menuLock', !persistantData.get('menuLock')) $('body, .hideNav, .w3-overlay').toggleClass('showNav') @@ -110,7 +111,7 @@ function helpMessageFreeze (item) { } function runAAPatcher (apk) { - //require('./assets/js/aapatcher.js')(apk) + // require('./assets/js/aapatcher.js')(apk) } function runInstallCSApp () { @@ -171,12 +172,20 @@ function myStance () { } function announcement () { + if (persistantData.get('visits', 0) % 20 === 0) { + showAnnouncement() + } +} -// announcement +function dataCheck () { + persistantData.delete('updateAvailable') + localStorage.setItem(`dat${updateVer}`, true) } -function showAnnouncement() { -//announcement +function showAnnouncement () { + if (persistantData.get('anon', false)) { + $.featherlight(aioURL, { closeSpeed: 1000, variant: 'announcementWindow' }) + } } function hideAnnouncement (anonNum) { @@ -190,6 +199,7 @@ function anonData (anonNum) { } function updateNotes () { + bootbox.hideAll() $.get('views/update.htm', function (data) { $('#changelog').html(data) }) bootbox.dialog({ title: `
    Welcome To MZD-AIO-TI v${app.getVersion()} | MZD All In One Tweaks Installer
    `, @@ -201,6 +211,7 @@ function updateNotes () { setTimeout(() => { $('.modal-dialog').animate({ 'margin-top': '40px', 'margin-bottom': '60px' }, 3000) $('#upVerBtn').fadeIn(5000) + persistantData.set('updated', true) }, 2000) } @@ -209,6 +220,9 @@ function firstTimeVisit () { myStance() settings.set('reset', true) lastView.clear() + if(persistantData.has('updateVer')) { + updateNotes() + } persistantData.set('updateVer', updateVer) persistantData.set('updated', false) persistantData.delete('ver270') @@ -232,7 +246,6 @@ function updateNotesCallback () { if (visits > 0) { if (!persistantData.get('updated', false)) { updateNotes() - persistantData.set('updated', true) } } else { persistantData.set('visits', 1) @@ -243,7 +256,7 @@ function updateNotesCallback () { closeButton: false, className: 'first-time-dialog' }) - setTimeout(() => { $('#super-overlay').remove() }, 3000) + setTimeout(() => { $('#super-overlay').remove() }, 9000) setTimeout(() => { $('#first-time-msg-btn').html(`
    `) $('#newVerBtn').fadeIn(10000) @@ -278,11 +291,12 @@ function helpDropdown () { } function closeHelpDrop () { - var x, y - if (x = document.getElementById('helpDrop')) { + var x = document.getElementById('helpDrop'), + y = document.getElementById('helpDropBtn') + if (x) { x.className = x.className.replace(' w3-show', '') } - if (y = document.getElementById('helpDropBtn')) { + if (y) { y.innerHTML = "" } } @@ -340,25 +354,19 @@ function cleanArray (actual) { return newArray } +function copyCode (x) { + $(x).select() + var copyText = document.execCommand('Copy') + if (copyText) snackbar('Copied "' + $(x).val() + '" to clipboard') +} + function donate () { shell.openExternal('http://trevelopment.win/donate') - /*let donatewin = new remote.BrowserWindow({ - width: 500, - height: 600, - resizable: false, - movable: false, - parent: remote.BrowserWindow.fromId(1), - icon: './app/favicon.ico', - autoHideMenuBar: true - }) - donatewin.loadURL('http://trevelopment.win/donate') - donatewin.on('closed', () => { - remote.BrowserWindow.fromId(1).focus() - })*/ } // Returns list of USB Drives -function getUSBDrives () { +async function getUSBDrives () { var disks = [] + var dsklst = await drivelist.list() drivelist.list(function (error, dsklst) { if (error) { console.error('Error finding USB drives') @@ -377,8 +385,8 @@ function getParameterByName (name, url) { if (!url) url = window.location.href url = url.toLowerCase() // This is just to avoid case sensitiveness name = name.replace(/[[\]]/g, '\\$&').toLowerCase() // This is just to avoid case sensitiveness for query parameter name - var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), - results = regex.exec(url) + var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)') + var results = regex.exec(url) if (!results) return '' // url.substr(url.lastIndexOf('/') + 1) if (!results[2]) return '' return decodeURIComponent(results[2].replace(/\+/g, ' ')) @@ -469,8 +477,9 @@ function showCompatibility () {
    -

    **AIO IS COMPATIBLE WITH ALL FW V55, V56, V58, V59 AND UP TO V70.00.100**

    +

    **AIO IS COMPATIBLE WITH ALL FW V55, V56, V58, V59 AND UP TO V70.00.352**

    NOTE: FW v59.00.502+ Requires Additional Steps To Install Tweaks. If updating to v59.00.502+ install Autorun & Recovery Scripts to allow Tweaks to be installed after updating.

    +

    WARNING: FW v70.00.335+ Requires Making A Serial Connection Before Updating.

    `).insertAfter($('#mzd-title')) } $(function () { @@ -501,21 +510,21 @@ function numberReplacer (key, value) { } function replaceInFile (someFile, toReplace, replacement, callback) { - fs.readFile(someFile, 'utf8', function (err,data) { + fs.readFile(someFile, 'utf8', function (err, data) { if (err) { err = err.toString() + dialog.showErrorBox('ERROR', err) return console.error(err) - dialog.showErrorBox("ERROR",err) } - var re = new RegExp(toReplace,"g"); + var re = new RegExp(toReplace, 'g') var result = data.replace(re, replacement) fs.writeFile(someFile, result, 'utf8', function (err) { - if (err){ + if (err) { err = err.toString() + dialog.showErrorBox('ERROR', err) return console.error(err) - dialog.showErrorBox("ERROR",err) } - if(typeof callback === "function") callback() + if (typeof callback === 'function') callback() }) }) } diff --git a/app/assets/vendor/showdown.min.js b/app/assets/vendor/showdown.min.js index 65ee602..91121d0 100644 --- a/app/assets/vendor/showdown.min.js +++ b/app/assets/vendor/showdown.min.js @@ -1,62 +1,2 @@ -// -// showdown.js -- A javascript port of Markdown. -// -// Copyright (c) 2007 John Fraser. -// -// Original Markdown Copyright (c) 2004-2005 John Gruber -// -// -// Redistributable under a BSD-style open source license. -// See license.txt for more information. -// -// The full source distribution is at: -// -// A A L -// T C A -// T K B -// -// -// -// -// Wherever possible, Showdown is a straight, line-by-line port -// of the Perl version of Markdown. -// -// This is not a normal parser design; it's basically just a -// series of string substitutions. It's hard to read and -// maintain this way, but keeping Showdown close to the original -// design makes it easier to port new features. -// -// More importantly, Showdown behaves like markdown.pl in most -// edge cases. So web applications can do client-side preview -// in Javascript, and then build identical HTML on the server. -// -// This port needs the new RegExp functionality of ECMA 262, -// 3rd Edition (i.e. Javascript 1.5). Most modern web browsers -// should do fine. Even with the new regular expression features, -// We do a lot of work to emulate Perl's regex functionality. -// The tricky changes in this file mostly have the "attacklab:" -// label. Major or self-explanatory changes don't. -// -// Smart diff tools like Araxis Merge will be able to match up -// this file with markdown.pl in a useful way. A little tweaking -// helps: in a copy of markdown.pl, replace "#" with "//" and -// replace "$text" with "text". Be sure to ignore whitespace -// and line endings. -// -// -// Showdown usage: -// -// var text = "Markdown *rocks*."; -// -// var converter = new Showdown.converter(); -// var html = converter.makeHtml(text); -// -// alert(html); -// -// Note: move the sample code to the bottom of this -// file before uncommenting it. -// -// -// Showdown namespace -// -var Showdown={extensions:{}},forEach=Showdown.forEach=function(a,b){if(typeof a.forEach=="function")a.forEach(b);else{var c,d=a.length;for(c=0;c?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|(?=~0))/gm,function(a,d,e,f,g){return d=d.toLowerCase(),b[d]=G(e),f?f+g:(g&&(c[d]=g.replace(/"/g,""")),"")}),a=a.replace(/~0/,""),a},m=function(a){a=a.replace(/\n/g,"\n\n");var b="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del|style|section|header|footer|nav|article|aside",c="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside";return a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,n),a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside)\b[^\r]*?<\/\2>[ \t]*(?=\n+)\n)/gm,n),a=a.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,n),a=a.replace(/(\n\n[ ]{0,3}[ \t]*(?=\n{2,}))/g,n),a=a.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,n),a=a.replace(/\n\n/g,"\n"),a},n=function(a,b){var c=b;return c=c.replace(/\n\n/g,"\n"),c=c.replace(/^\n/,""),c=c.replace(/\n+$/g,""),c="\n\n~K"+(d.push(c)-1)+"K\n\n",c},o=function(a){a=v(a);var b=A("
    ");return a=a.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,b),a=x(a),a=y(a),a=E(a),a=m(a),a=F(a),a},p=function(a){return a=B(a),a=q(a),a=H(a),a=t(a),a=r(a),a=I(a),a=G(a),a=D(a),a=a.replace(/ +\n/g,"
    \n"),a},q=function(a){var b=/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;return a=a.replace(b,function(a){var b=a.replace(/(.)<\/?code>(?=.)/g,"$1`");return b=N(b,"\\`*_"),b}),a},r=function(a){return a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,s),a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,s),a=a.replace(/(\[([^\[\]]+)\])()()()()()/g,s),a},s=function(a,d,e,f,g,h,i,j){j==undefined&&(j="");var k=d,l=e,m=f.toLowerCase(),n=g,o=j;if(n==""){m==""&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m;if(b[m]!=undefined)n=b[m],c[m]!=undefined&&(o=c[m]);else{if(!(k.search(/\(\s*\)$/m)>-1))return k;n=""}}n=N(n,"*_");var p='",p},t=function(a){return a=a.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,u),a=a.replace(/(!\[(.*?)\]\s?\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,u),a},u=function(a,d,e,f,g,h,i,j){var k=d,l=e,m=f.toLowerCase(),n=g,o=j;o||(o="");if(n==""){m==""&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m;if(b[m]==undefined)return k;n=b[m],c[m]!=undefined&&(o=c[m])}l=l.replace(/"/g,"""),n=N(n,"*_");var p=''+l+''+p(c)+"")}),a=a.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,function(a,c){return A('

    '+p(c)+"

    ")}),a=a.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,function(a,c,d){var e=c.length;return A("'+p(d)+"")}),a},w,x=function(a){a+="~0";var b=/^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;return e?a=a.replace(b,function(a,b,c){var d=b,e=c.search(/[*+-]/g)>-1?"ul":"ol";d=d.replace(/\n{2,}/g,"\n\n\n");var f=w(d);return f=f.replace(/\s+$/,""),f="<"+e+">"+f+"\n",f}):(b=/(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g,a=a.replace(b,function(a,b,c,d){var e=b,f=c,g=d.search(/[*+-]/g)>-1?"ul":"ol",f=f.replace(/\n{2,}/g,"\n\n\n"),h=w(f);return h=e+"<"+g+">\n"+h+"\n",h})),a=a.replace(/~0/,""),a};w=function(a){return e++,a=a.replace(/\n{2,}$/,"\n"),a+="~0",a=a.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,function(a,b,c,d,e){var f=e,g=b,h=c;return g||f.search(/\n{2,}/)>-1?f=o(L(f)):(f=x(L(f)),f=f.replace(/\n$/,""),f=p(f)),"
  • "+f+"
  • \n"}),a=a.replace(/~0/g,""),e--,a};var y=function(a){return a+="~0",a=a.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,function(a,b,c){var d=b,e=c;return d=C(L(d)),d=M(d),d=d.replace(/^\n+/g,""),d=d.replace(/\n+$/g,""),d="
    "+d+"\n
    ",A(d)+e}),a=a.replace(/~0/,""),a},z=function(a){return a+="~0",a=a.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g,function(a,b,c){var d=b,e=c;return e=C(e),e=M(e),e=e.replace(/^\n+/g,""),e=e.replace(/\n+$/g,""),e="
    "+e+"\n
    ",A(e)}),a=a.replace(/~0/,""),a},A=function(a){return a=a.replace(/(^\n+|\n+$)/g,""),"\n\n~K"+(d.push(a)-1)+"K\n\n"},B=function(a){return a=a.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(a,b,c,d,e){var f=d;return f=f.replace(/^([ \t]*)/g,""),f=f.replace(/[ \t]*$/g,""),f=C(f),b+""+f+""}),a},C=function(a){return a=a.replace(/&/g,"&"),a=a.replace(//g,">"),a=N(a,"*_{}[]\\",!1),a},D=function(a){return a=a.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"$2"),a=a.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"$2"),a},E=function(a){return a=a.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(a,b){var c=b;return c=c.replace(/^[ \t]*>[ \t]?/gm,"~0"),c=c.replace(/~0/g,""),c=c.replace(/^[ \t]+$/gm,""),c=o(c),c=c.replace(/(^|\n)/g,"$1 "),c=c.replace(/(\s*
    [^\r]+?<\/pre>)/gm,function(a,b){var c=b;return c=c.replace(/^  /mg,"~0"),c=c.replace(/~0/g,""),c}),A("
    \n"+c+"\n
    ")}),a},F=function(a){a=a.replace(/^\n+/g,""),a=a.replace(/\n+$/g,"");var b=a.split(/\n{2,}/g),c=[],e=b.length;for(var f=0;f=0?c.push(g):g.search(/\S/)>=0&&(g=p(g),g=g.replace(/^([ \t]*)/g,"

    "),g+="

    ",c.push(g))}e=c.length;for(var f=0;f=0){var h=d[RegExp.$1];h=h.replace(/\$/g,"$$$$"),c[f]=c[f].replace(/~K\d+K/,h)}return c.join("\n\n")},G=function(a){return a=a.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&"),a=a.replace(/<(?![a-z\/?\$!])/gi,"<"),a},H=function(a){return a=a.replace(/\\(\\)/g,O),a=a.replace(/\\([`*_{}\[\]()>#+-.!])/g,O),a},I=function(a){return a=a.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,'
    $1'),a=a.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,function(a,b){return J(K(b))}),a},J=function(a){var b=[function(a){return"&#"+a.charCodeAt(0)+";"},function(a){return"&#x"+a.charCodeAt(0).toString(16)+";"},function(a){return a}];return a="mailto:"+a,a=a.replace(/./g,function(a){if(a=="@")a=b[Math.floor(Math.random()*2)](a);else if(a!=":"){var c=Math.random();a=c>.9?b[2](a):c>.45?b[1](a):b[0](a)}return a}),a=''+a+"",a=a.replace(/">.+:/g,'">'),a},K=function(a){return a=a.replace(/~E(\d+)E/g,function(a,b){var c=parseInt(b);return String.fromCharCode(c)}),a},L=function(a){return a=a.replace(/^(\t|[ ]{1,4})/gm,"~0"),a=a.replace(/~0/g,""),a},M=function(a){return a=a.replace(/\t(?=\t)/g," "),a=a.replace(/\t/g,"~A~B"),a=a.replace(/~B(.+?)~A/g,function(a,b,c){var d=b,e=4-d.length%4;for(var f=0;fc;c++)b(a[c],c,a)}},stdExtName=function(a){return a.replace(/[_-]||\s/g,"").toLowerCase()};Showdown.converter=function(a){var b,c,d,e=0,f=[],g=[];if("undefined"!=typeof module&&"undefined"!=typeof exports&&"undefined"!=typeof require){var h=require("fs");if(h){var i=h.readdirSync((__dirname||".")+"/extensions").filter(function(a){return~a.indexOf(".js")}).map(function(a){return a.replace(/\.js$/,"")});Showdown.forEach(i,function(a){var b=stdExtName(a);Showdown.extensions[b]=require("./extensions/"+a)})}}if(this.makeHtml=function(a){return b={},c={},d=[],a=a.replace(/~/g,"~T"),a=a.replace(/\$/g,"~D"),a=a.replace(/\r\n/g,"\n"),a=a.replace(/\r/g,"\n"),a="\n\n"+a+"\n\n",a=M(a),a=a.replace(/^[ \t]+$/gm,""),Showdown.forEach(f,function(b){a=l(b,a)}),a=z(a),a=n(a),a=m(a),a=p(a),a=K(a),a=a.replace(/~D/g,"$$"),a=a.replace(/~T/g,"~"),Showdown.forEach(g,function(b){a=l(b,a)}),a},a&&a.extensions){var j=this;Showdown.forEach(a.extensions,function(a){var b=a;if("string"==typeof a&&(a=Showdown.extensions[stdExtName(a)]),"function"!=typeof a)throw"Extension '"+b+"' could not be loaded. It was either not found or is not a valid extension.";Showdown.forEach(a(j),function(a){a.type?"language"===a.type||"lang"===a.type?f.push(a):("output"===a.type||"html"===a.type)&&g.push(a):g.push(a)})})}var k,l=function(a,b){if(a.regex){var c=new RegExp(a.regex,"g");return b.replace(c,a.replace)}return a.filter?a.filter(b):void 0},m=function(a){return a+="~0",a=a.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|(?=~0))/gm,function(a,d,e,f,g){return d=d.toLowerCase(),b[d]=G(e),f?f+g:(g&&(c[d]=g.replace(/"/g,""")),"")}),a=a.replace(/~0/,"")},n=function(a){a=a.replace(/\n/g,"\n\n");return a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,o),a=a.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|style|section|header|footer|nav|article|aside)\b[^\r]*?<\/\2>[ \t]*(?=\n+)\n)/gm,o),a=a.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,o),a=a.replace(/(\n\n[ ]{0,3}[ \t]*(?=\n{2,}))/g,o),a=a.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,o),a=a.replace(/\n\n/g,"\n")},o=function(a,b){var c=b;return c=c.replace(/\n\n/g,"\n"),c=c.replace(/^\n/,""),c=c.replace(/\n+$/g,""),c="\n\n~K"+(d.push(c)-1)+"K\n\n"},p=function(a){a=w(a);var b=A("
    ");return a=a.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,b),a=a.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,b),a=x(a),a=y(a),a=E(a),a=n(a),a=F(a)},q=function(a){return a=B(a),a=r(a),a=H(a),a=u(a),a=s(a),a=I(a),a=G(a),a=D(a),a=a.replace(/ +\n/g,"
    \n")},r=function(a){var b=/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|)/gi;return a=a.replace(b,function(a){var b=a.replace(/(.)<\/?code>(?=.)/g,"$1`");return b=N(b,"\\`*_")})},s=function(a){return a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,t),a=a.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,t),a=a.replace(/(\[([^\[\]]+)\])()()()()()/g,t)},t=function(a,d,e,f,g,h,i,j){void 0===j&&(j="");var k=d,l=e,m=f.toLowerCase(),n=g,o=j;if(""===n)if(""===m&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m,void 0!==b[m])n=b[m],void 0!==c[m]&&(o=c[m]);else{if(!(k.search(/\(\s*\)$/m)>-1))return k;n=""}n=N(n,"*_");var p='"},u=function(a){return a=a.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,v),a=a.replace(/(!\[(.*?)\]\s?\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,v)},v=function(a,d,e,f,g,h,i,j){var k=d,l=e,m=f.toLowerCase(),n=g,o=j;if(o||(o=""),""===n){if(""===m&&(m=l.toLowerCase().replace(/ ?\n/g," ")),n="#"+m,void 0===b[m])return k;n=b[m],void 0!==c[m]&&(o=c[m])}l=l.replace(/"/g,"""),n=N(n,"*_");var p=''+l+''+q(c)+"")}),a=a.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,function(a,c){return A('

    '+q(c)+"

    ")}),a=a.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,function(a,c,d){var e=c.length;return A("'+q(d)+"")})},x=function(a){a+="~0";var b=/^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;return e?a=a.replace(b,function(a,b,c){var d=b,e=c.search(/[*+-]/g)>-1?"ul":"ol";d=d.replace(/\n{2,}/g,"\n\n\n");var f=k(d);return f=f.replace(/\s+$/,""),f="<"+e+">"+f+"\n"}):(b=/(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g,a=a.replace(b,function(a,b,c,d){var e=b,f=c,g=d.search(/[*+-]/g)>-1?"ul":"ol";f=f.replace(/\n{2,}/g,"\n\n\n");var h=k(f);return h=e+"<"+g+">\n"+h+"\n"})),a=a.replace(/~0/,"")};k=function(a){return e++,a=a.replace(/\n{2,}$/,"\n"),a+="~0",a=a.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,function(a,b,c,d,e){var f=e,g=b;return g||f.search(/\n{2,}/)>-1?f=p(L(f)):(f=x(L(f)),f=f.replace(/\n$/,""),f=q(f)),"
  • "+f+"
  • \n"}),a=a.replace(/~0/g,""),e--,a};var y=function(a){return a+="~0",a=a.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,function(a,b,c){var d=b,e=c;return d=C(L(d)),d=M(d),d=d.replace(/^\n+/g,""),d=d.replace(/\n+$/g,""),d="
    "+d+"\n
    ",A(d)+e}),a=a.replace(/~0/,"")},z=function(a){return a+="~0",a=a.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g,function(a,b,c){var d=b,e=c;return e=C(e),e=M(e),e=e.replace(/^\n+/g,""),e=e.replace(/\n+$/g,""),e="
    "+e+"\n
    ",A(e)}),a=a.replace(/~0/,"")},A=function(a){return a=a.replace(/(^\n+|\n+$)/g,""),"\n\n~K"+(d.push(a)-1)+"K\n\n"},B=function(a){return a=a.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(a,b,c,d,e){var f=d;return f=f.replace(/^([ \t]*)/g,""),f=f.replace(/[ \t]*$/g,""),f=C(f),b+""+f+""})},C=function(a){return a=a.replace(/&/g,"&"),a=a.replace(//g,">"),a=N(a,"*_{}[]\\",!1)},D=function(a){return a=a.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"$2"),a=a.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"$2")},E=function(a){return a=a.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(a,b){var c=b;return c=c.replace(/^[ \t]*>[ \t]?/gm,"~0"),c=c.replace(/~0/g,""),c=c.replace(/^[ \t]+$/gm,""),c=p(c),c=c.replace(/(^|\n)/g,"$1 "),c=c.replace(/(\s*
    [^\r]+?<\/pre>)/gm,function(a,b){var c=b;return c=c.replace(/^  /gm,"~0"),c=c.replace(/~0/g,"")}),A("
    \n"+c+"\n
    ")})},F=function(a){a=a.replace(/^\n+/g,""),a=a.replace(/\n+$/g,"");for(var b=a.split(/\n{2,}/g),c=[],e=b.length,f=0;e>f;f++){var g=b[f];g.search(/~K(\d+)K/g)>=0?c.push(g):g.search(/\S/)>=0&&(g=q(g),g=g.replace(/^([ \t]*)/g,"

    "),g+="

    ",c.push(g))}for(e=c.length,f=0;e>f;f++)for(;c[f].search(/~K(\d+)K/)>=0;){var h=d[RegExp.$1];h=h.replace(/\$/g,"$$$$"),c[f]=c[f].replace(/~K\d+K/,h)}return c.join("\n\n")},G=function(a){return a=a.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&"),a=a.replace(/<(?![a-z\/?\$!])/gi,"<")},H=function(a){return a=a.replace(/\\(\\)/g,O),a=a.replace(/\\([`*_{}\[\]()>#+-.!])/g,O)},I=function(a){return a=a.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,'
    $1'),a=a.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,function(a,b){return J(K(b))})},J=function(a){var b=[function(a){return"&#"+a.charCodeAt(0)+";"},function(a){return"&#x"+a.charCodeAt(0).toString(16)+";"},function(a){return a}];return a="mailto:"+a,a=a.replace(/./g,function(a){if("@"==a)a=b[Math.floor(2*Math.random())](a);else if(":"!=a){var c=Math.random();a=c>.9?b[2](a):c>.45?b[1](a):b[0](a)}return a}),a=''+a+"",a=a.replace(/">.+:/g,'">')},K=function(a){return a=a.replace(/~E(\d+)E/g,function(a,b){var c=parseInt(b);return String.fromCharCode(c)})},L=function(a){return a=a.replace(/^(\t|[ ]{1,4})/gm,"~0"),a=a.replace(/~0/g,"")},M=function(a){return a=a.replace(/\t(?=\t)/g," "),a=a.replace(/\t/g,"~A~B"),a=a.replace(/~B(.+?)~A/g,function(a,b,c){for(var d=b,e=4-d.length%4,f=0;e>f;f++)d+=" ";return d}),a=a.replace(/~A/g," "),a=a.replace(/~B/g,"")},N=function(a,b,c){var d="(["+b.replace(/([\[\]\\])/g,"\\$1")+"])";c&&(d="\\\\"+d);var e=new RegExp(d,"g");return a=a.replace(e,O)},O=function(a,b){var c=b.charCodeAt(0);return"~E"+c+"E"}},"undefined"!=typeof module&&(module.exports=Showdown),"function"==typeof define&&define.amd&&define("showdown",function(){return Showdown}),"undefined"!=typeof angular&&"undefined"!=typeof Showdown&&!function(a,b){function c(){function a(){var a=new b.converter(c);this.makeHtml=function(b){return a.makeHtml(b)},this.stripHtml=function(a){return String(a).replace(/<[^>]+>/gm,"")}}var c={extensions:[],stripHtml:!0};this.setOption=function(a,b){return c.key=b,this},this.getOption=function(a){return c.hasOwnProperty(a)?c.key:null},this.loadExtension=function(a){return c.extensions.push(a),this},this.$get=function(){return new a}}function d(a,b){var c=function(c,d){c.$watch("model",function(c){var e;e="string"==typeof c?b(a.makeHtml(c)):typeof c,d.html(e)})};return{restrict:"A",link:c,scope:{model:"=sdModelToHtml"}}}function e(){return function(a){return String(a).replace(/<[^>]+>/gm,"")}}a.provider("$Showdown",c).directive("sdModelToHtml",["$Showdown","$sanitize",d]).filter("sdStripHtml",e)}(angular.module("Showdown",["ngSanitize"]),Showdown); diff --git a/app/controllers/home.js b/app/controllers/home.js index dc9c55b..2e3c45d 100644 --- a/app/controllers/home.js +++ b/app/controllers/home.js @@ -64,7 +64,7 @@ advancedOps: false, dataDump: false, aaBetaVer: false, - aaWifi: true, + aaWifi: false, aaHUD: false, autosort: true, barautosort: true, @@ -176,7 +176,7 @@ $scope.user.vpOps = { shuffle: true, repeat: 2, - fullscreen: 1, + fullscreen: 2, v4lsink: true } $scope.vpOpsRepeat = { @@ -193,14 +193,14 @@ On: true, Off: false } - $scope.user.rmvallbg = function () { + /* $scope.user.rmvallbg = function () { $scope.user.uistyle.nobtnbg = true $scope.user.uistyle.nonpbg = true $scope.user.uistyle.nolistbg = true $scope.user.uistyle.nocallbg = true $scope.user.uistyle.notextbg = true $scope.$apply() - } + } */ if ($scope.loc.toLowerCase().includes('en-us')) { // console.log('ENGLISH') $scope.user.speedoOps.lang.id = 0 @@ -571,6 +571,12 @@ $scope.user.copydir = loc snackbar(`Save _copy_to_usb folder to ${persistantData.get('copyFolderLocation')}`, 3) }) + $scope.autorestore = function (win) { + $scope.user.restore.full = win === 'restore' + $scope.user.autorun.serial = win === 'serial' + $scope.user.autorun.installer = (win === 'autorun' || win === 'serial') + } + $scope.instAll = function () { $scope.user.mainOps = [0, 2, 3, 4, 5, 7, 8, 9] $scope.user.options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 22, 26] @@ -705,7 +711,7 @@ var armsg = '
    CMU-Autorun Scripts
    Installer/Uninstaller For Autorun Scripts.
    ' armsg += '
    ' armsg += '' - bootbox.prompt({ + var autoPrompt = bootbox.prompt({ title: armsg, className: 'confirmAutorunCompile', inputType: 'checkbox', @@ -733,26 +739,16 @@ ], callback: function (results) { if (results === null) { return } - if (results.includes('autow')) { - $scope.user.autorun.autoWIFI = true - } - if (results.includes('autoa')) { - $scope.user.autorun.autoADB = true - } - if (results.includes('id7')) { - $scope.user.autorun.id7recovery = true - } - if (results.includes('dryrun')) { - $scope.user.autorun.dryrun = true - } - if (results.includes('serial')) { - $scope.user.autorun.serial = true - $scope.user.autorun.id7recovery = true - } + $scope.user.autorun.autoWIFI = results.includes('autow') + $scope.user.autorun.autoADB = results.includes('autoa') + $scope.user.autorun.dryrun = results.includes('dryrun') + $scope.user.autorun.serial = results.includes('serial') + $scope.user.autorun.id7recovery = (results.includes('id7') || results.includes('serial')) $('#confirmAutorunCompile').hide() $scope.compileTweaks() } }) + autoPrompt.on('shown.bs.modal', function () { $('.bootbox-input[value=serial]').prop('checked', $scope.user.autorun.serial) }) } $scope.startCompile = function () { bootbox.hideAll() @@ -842,7 +838,14 @@ setTimeout(function () { introJs().hideHints() }, 4000) - $scope.compileTweaks() + rimraf(`${tmpdir}`, (err) => { + if (err) { + let m = `Error occured while deleting old '_copy_to_usb' folder: ${err}\n Try closing all other running programs and folders before compiling.` + aioLog(m, m) + return + } + $scope.compileTweaks() + }) } } }) @@ -957,14 +960,14 @@ } $scope.visibleApps = { simpledashboard: true, - clock: true, - multidash: true, vdd: true, + clock: true, tetris: true, snake: true, + breakout: true, simplespeedo: true, - breakout: casdkApps.get('breakout', false), - gpsspeed: casdkApps.get('gpsspeed', false), + gpsspeed: true, + multidash: true, background: casdkApps.get('background', false), terminal: casdkApps.get('terminal', false), devtools: casdkApps.get('devtools', false), @@ -1031,9 +1034,7 @@ break case 'reset': casdkApps.set('terminal', false) - casdkApps.set('gpsspeed', false) casdkApps.set('aio', false) - casdkApps.set('breakout', false) casdkApps.set('background', false) casdkApps.set('multicontroller', false) casdkApps.set('devtools', false) diff --git a/app/files/img/11-11.jpg b/app/files/img/11-11.jpg new file mode 100644 index 0000000..525302c Binary files /dev/null and b/app/files/img/11-11.jpg differ diff --git a/app/files/img/11-11_fixed.jpg b/app/files/img/11-11_fixed.jpg new file mode 100644 index 0000000..dc36757 Binary files /dev/null and b/app/files/img/11-11_fixed.jpg differ diff --git a/app/files/img/cmu-back.jpg b/app/files/img/cmu-back.jpg new file mode 100644 index 0000000..0db22ca Binary files /dev/null and b/app/files/img/cmu-back.jpg differ diff --git a/app/files/img/cmu-rx-tx.jpg b/app/files/img/cmu-rx-tx.jpg new file mode 100644 index 0000000..78ae379 Binary files /dev/null and b/app/files/img/cmu-rx-tx.jpg differ diff --git a/app/files/img/ls-l_output.png b/app/files/img/ls-l_output.png new file mode 100644 index 0000000..da6ff5c Binary files /dev/null and b/app/files/img/ls-l_output.png differ diff --git a/app/files/img/thebolt.jpg b/app/files/img/thebolt.jpg new file mode 100644 index 0000000..080efe7 Binary files /dev/null and b/app/files/img/thebolt.jpg differ diff --git a/app/files/tweaks/00_59patch.txt b/app/files/tweaks/00_59patch.txt index 6e386e5..aee62f3 100644 --- a/app/files/tweaks/00_59patch.txt +++ b/app/files/tweaks/00_59patch.txt @@ -12,6 +12,6 @@ then cp -a ${MYDIR}/config/jci/gui/apps/system/js/systemApp.70.js /jci/gui/apps/system/js/systemApp.js log_message "=== Patched systemApp.js for AIO + CASDK apps for v70 ===" else - log_message "=== FW > v70.00.100 DETECTED VISIT MAZDATWEAKS.COM FOR MORE DETAILS ===" + log_message "=== FW > v70.00.342 DETECTED VISIT MAZDATWEAKS.COM FOR MORE DETAILS ===" fi fi diff --git a/app/files/tweaks/00___fullRestore.sh b/app/files/tweaks/00___fullRestore.sh index caf9a5b..a41f7f8 100644 --- a/app/files/tweaks/00___fullRestore.sh +++ b/app/files/tweaks/00___fullRestore.sh @@ -62,7 +62,7 @@ fi rm -f /jci/nng/2 if [ -e /mnt/sd_nav/content/speedcam/speedcam.txt ] || [ -e /mnt/sd_nav/content/speedcam/speedcam.spdb ] then - # cp -a /mnt/sd_nav/content/speedcam/speedcam.txt ${MYDIR} + # cp /mnt/sd_nav/content/speedcam/speedcam.txt ${MYDIR} # log_message "=== Copied speedcam.txt to USB ===" # rm -f /mnt/sd_nav/content/speedcam/speedcam.txt # rm -f /mnt/sd_nav/content/speedcam/speedcam.spdb diff --git a/app/files/tweaks/00__casdkapps-i.txt b/app/files/tweaks/00__casdkapps-i.txt index 758eb74..9498554 100644 --- a/app/files/tweaks/00__casdkapps-i.txt +++ b/app/files/tweaks/00__casdkapps-i.txt @@ -108,7 +108,7 @@ then cp -a ${MYDIR}/casdk/patch/systemApp.70.js /jci/gui/apps/system/js/systemApp.js log_message "=== Patched systemApp.js for AIO + CASDK apps for v70 ===" else - log_message "=== FW > v70.00.100 DETECTED VISIT MAZDATWEAKS.COM FOR MORE DETAILS ===" + log_message "=== FW > v70.00.335 DETECTED VISIT MAZDATWEAKS.COM FOR MORE DETAILS ===" fi fi diff --git a/app/files/tweaks/00_background.txt b/app/files/tweaks/00_background.txt index a5d80c8..dce049c 100644 --- a/app/files/tweaks/00_background.txt +++ b/app/files/tweaks/00_background.txt @@ -9,8 +9,14 @@ then log_message "=== Previous Infotainment Background Saved To: === " log_message "=== ${MYDIR}/bakups/background.png ===" fi -cp -a "${MYDIR}/config/background.png" /jci/gui/common/images -log_message "=== Background Image Changed ===" +if [ -s ${MYDIR}/config/background.png ] +then + cp -a "${MYDIR}/config/background.png" /jci/gui/common/images + log_message "=== Background Image Changed ===" +else + show_message "ERROR MISSING BACKGROUND IMAGE FILE!!!" + log_message "=== ERROR: Mising Background Image File ===" +fi log_message "======*********** END INSTALLATION OF BACKGROUND IMAGE ***********=======" log_message " " diff --git a/app/files/tweaks/00_end.txt b/app/files/tweaks/00_end.txt index 86d01d5..e58f6c2 100644 --- a/app/files/tweaks/00_end.txt +++ b/app/files/tweaks/00_end.txt @@ -1,4 +1,5 @@ show_message "========== END OF TWEAKS INSTALLATION ==========" +[ -s /etc/profile ] || restore_org /etc/profile if [ -f "${MYDIR}/AIO_log.txt" ] then END_ROOTFS=$(df -h | (grep 'rootfs' || echo 0) | awk '{ print $5 " " $1 }') diff --git a/app/files/tweaks/00_factory-reset-end.txt b/app/files/tweaks/00_factory-reset-end.txt index 83dc7b7..f3218c3 100644 --- a/app/files/tweaks/00_factory-reset-end.txt +++ b/app/files/tweaks/00_factory-reset-end.txt @@ -8,9 +8,11 @@ if [ -e "${MYDIR}/AIO_log.txt" ] then END_ROOTFS=$(df -h | (grep 'rootfs' || echo 0) | awk '{ print $5 " " $1 }') END_RESOURCES=$(df -h | (grep 'resources' || echo 0) | awk '{ print $5 " " $1 }') + END_ROOTFS="$(echo $END_ROOTFS | awk '{ print $1}' | cut -d'%' -f1)" + END_RESOURCES="$(echo $END_RESOURCES | awk '{ print $1}' | cut -d'%' -f1)" sleep 2 - log_message "======================== rootfs $(echo $END_ROOTFS | awk '{ print $1}' | cut -d'%' -f1)% used ================================" - log_message "====================== resources $(echo $END_RESOURCES | awk '{ print $1}' | cut -d'%' -f1)% used ===============================" + log_message "======================== rootfs $END_ROOTFS% used ================================" + log_message "====================== resources $END_RESOURCES% used ===============================" # a window will appear before the system reboots automatically sleep 3 log_message " " diff --git a/app/files/tweaks/00_intro.txt b/app/files/tweaks/00_intro.txt index dfe5c86..03f7f0a 100644 --- a/app/files/tweaks/00_intro.txt +++ b/app/files/tweaks/00_intro.txt @@ -1,23 +1,24 @@ #!/bin/sh -# tweaks.sh - MZD-AIO-TI Version 2.8.4 +# tweaks.sh - MZD-AIO-TI Version 2.8.5 # Special thanks to Siutsch for collecting all the tweaks and for the original AIO -# Big Thanks to Modfreakz, khantaena, Xep, ID7, Doog, Diginix, oz_paulb, VIC_BAM85, & lmagder +# Big Thanks to Modfreakz, khantaena, Xep, ID7, Doog, Diginix, oz_paulb, +# Albuyeh, VIC_BAM85, lmagder, ameridan, anderml1955 & Tristan-cx5 # For more information visit https://mazdatweaks.com # Enjoy, Trezdog44 - Trevelopment.com -# (C) 2019 Trevor G Martin +# (C) 2020 Trevor G Martin # Time hwclock --hctosys # AIO Variables -AIO_VER=2.8.4 -AIO_DATE=2019.28.02 +AIO_VER=2.8.5 +AIO_DATE=2020.02.02 # Android Auto Headunit App Version -AA_VER=1.11 +AA_VER=1.12 # Video Player Version VP_VER=3.7 # Speedometer Version -SPD_VER=5.8 +SPD_VER=6.1 # AIO Tweaks App Version AIO_TWKS_VER=1.0 # CASDK Version diff --git a/app/files/tweaks/00_offbackground-i.txt b/app/files/tweaks/00_offbackground-i.txt index 9895297..009fbd2 100644 --- a/app/files/tweaks/00_offbackground-i.txt +++ b/app/files/tweaks/00_offbackground-i.txt @@ -2,9 +2,14 @@ backup_org /jci/gui/apps/system/controls/OffScreen/images/OffScreenBackground.pn # change off screen background image show_message "CHANGING OFF SCREEN BACKGROUND IMAGE ..." log_message "=====********** INSTALL OFF SCREEN BACKGROUND IMAGE ... ***********=====" - -cp -a ${MYDIR}/config/OffScreenBackground.png /jci/gui/apps/system/controls/OffScreen/images/ -log_message "=== Replaced Off Screen Background Image ===" +if [ -s ${MYDIR}/config/OffScreenBackground.png ] +then + cp -a ${MYDIR}/config/OffScreenBackground.png /jci/gui/apps/system/controls/OffScreen/images/ + log_message "=== Replaced Off Screen Background Image ===" +else + show_message "ERROR MISSING OFF-SCREEN BACKGROUND FILE!!!" + log_message "=== ERROR: Off Screen Background Image not found ===" +fi log_message "====********* END INSTALLATION OFF SCREEN BACKGROUND IMAGE **********====" log_message " " diff --git a/app/files/tweaks/00_start.txt b/app/files/tweaks/00_start.txt index bb327c4..abe48fc 100644 --- a/app/files/tweaks/00_start.txt +++ b/app/files/tweaks/00_start.txt @@ -71,7 +71,7 @@ remove_casdk_app() fi } # Compatibility check falls into 7 groups: -# 70.00.100+ ($COMPAT_GROUP=7 *Temporary, until tested*) +# 70.00.336+ ($COMPAT_GROUP=7 *Temporary, until tested*) # 70.00.XXX ($COMPAT_GROUP=6) # 59.00.5XX ($COMPAT_GROUP=5) # 59.00.4XX ($COMPAT_GROUP=4) @@ -106,11 +106,11 @@ compatibility_check() fi elif [ $_VER -eq 70 ] then - if [ $_VER_EXT -le 100 ] + if [ $_VER_EXT -le 360 ] then - echo 6 && return # v70.00.100 For Integrity check + echo 6 && return # v70.00.352 For Integrity check else - echo 7 && return # Past v70.00.100 is unknown and cannot be trusted + echo 7 && return # Past v70.00.352 is unknown and cannot be trusted fi else echo 0 @@ -275,6 +275,7 @@ v70_integrity_check() fi [ -e ${NEW_BKUP_DIR} ] || mkdir -p ${NEW_BKUP_DIR} orgs=$(find /jci -type f -name "*.org") + [ -e /etc/profile.org ] && orgs="${orgs} /etc/profile.org" for i in $orgs; do ORG_FILE="$i" FILENAME=$(basename -- $ORG_FILE) @@ -611,7 +612,7 @@ fi if [ $COMPAT_GROUP -gt 6 ] then sleep 2 - show_message_OK "WARNING! VERSION ${CMU_SW_VER} DETECTED\nAIO COMPATIBILITY HAS ONLY BEEN TESTED UP TO V70.00.100\nIF YOU ARE RUNNING A LATER FW VERSION\nUSE EXTREME CAUTION!!" + show_message_OK "WARNING! VERSION ${CMU_SW_VER} DETECTED\nAIO COMPATIBILITY HAS ONLY BEEN TESTED UP TO V70.00.352\nIF YOU ARE RUNNING A LATER FW VERSION\n***** USE EXTREME CAUTION!! *****\n***** CONTINUE AT YOUR OWN RISK *****" elif [ $COMPAT_GROUP -ne 0 ] then if [ $SKIPCONFIRM -eq 1 ] diff --git a/app/files/tweaks/02_disclaimer-i.txt b/app/files/tweaks/02_disclaimer-i.txt index 13be965..569dfa1 100644 --- a/app/files/tweaks/02_disclaimer-i.txt +++ b/app/files/tweaks/02_disclaimer-i.txt @@ -1,6 +1,5 @@ backup_org /jci/gui/apps/system/js/systemApp.js # no-more-disclaimer -show_message "REMOVE DISCLAIMER ..." log_message "========*********** INSTALL NO-MORE-DISCLAIMER ... ***********========" TRACKORDER_DISCLAIMER=2 @@ -18,13 +17,19 @@ then TRACKORDER_DISCLAIMER=1 TRACKORDER_DISCLAIMER_FILE=70 log_message "=== FW ${CMU_SW_VER} detected, copy matching systemApp.js ===" +elif [ $COMPAT_GROUP -gt 6 ] +then + killall -q jci-dialog + /jci/tools/jci-dialog --confirm --title="NO MORE DISCLAIMER TWEAK" --text="YOUR FW VERSION IS ${CMU_SW_VER}\nNO MORE DISCLAIMER TWEAK HAS ONLY\n BEEN TESTED UP TO V70.00.335\n\n***** INSTALL AT YOUR OWN RISK! *****" --ok-label="INSTALL" --cancel-label="SKIP" + TRACKORDER_DISCLAIMER=$(($?+1)) + TRACKORDER_DISCLAIMER_FILE=70 fi +[ $TRACKORDER_DISCLAIMER -le 1 ] && show_message "REMOVE DISCLAIMER ..." # Compatibility check falls into 3 groups: # 70.00.XXX ($COMPAT_GROUP=6) # 58.00.XXX - 59.00.XXX ($COMPAT_GROUP=2-5) # 55.XX.XXX - 56.XX.XXX ($COMPAT_GROUP=1) -# If your firmware version falls out of those ranges email the address below if [ $TRACKORDER_DISCLAIMER -ne 2 ] then cp -a "${MYDIR}/config/audio_order_AND_no_More_Disclaimer/systemApp.js.disclaimer" /jci/gui/apps/system/js/ @@ -53,11 +58,9 @@ then fi fi else - # 2 Means unknown firmware version if your firmware version is unknown email the address below - show_message "=== NO MORE DISCLIMER PATCH HAS NOT BEEN MADE FOR YOUR FW:${CMU_SW_VER}\nPlease Email ${MYDIR}/systemApp.js to aio@mazdatweaks.com ===" - log_message "********** Removed Disclaimer Mod Is Not Compatible With your FW Version *************" - log_message "********** Please Email ${MYDIR}/systemApp.js FW:${CMU_SW_VER} to aio@mazdatweaks.com **********" - cp -a /jci/gui/apps/system/js/systemApp.js "${MYDIR}/" + show_message "=== NO MORE DISCLIMER PATCH INSTALLATION SKIPPED ===" + log_message "********** Remove Disclaimer Mod Skipped *************" + cp /jci/gui/apps/system/js/systemApp.js "${MYDIR}" fi if [ $TESTBKUPS -eq 1 ] then diff --git a/app/files/tweaks/05_mainloop-i.txt b/app/files/tweaks/05_mainloop-i.txt index adf77d8..f45a82a 100644 --- a/app/files/tweaks/05_mainloop-i.txt +++ b/app/files/tweaks/05_mainloop-i.txt @@ -3,7 +3,7 @@ backup_org /jci/gui/apps/system/controls/MainMenu/js/MainMenuCtrl.js show_message "INSTALL MAIN_MENU_LOOP ..." log_message "=====***************** INSTALL MAIN_MENU_LOOP ... *****************=====" -if [ $COMPAT_GROUP -le 6 ] +if [ $COMPAT_GROUP -le 7 ] then # Copy modified MainMenuCtrl.js cp -a "${MYDIR}/config/main-menu-loop/jci/gui/apps/system/controls/MainMenu/js/MainMenuCtrl.js" /jci/gui/apps/system/controls/MainMenu/js/ diff --git a/app/files/tweaks/06_listloop-i.txt b/app/files/tweaks/06_listloop-i.txt index 917c5c3..12cd359 100644 --- a/app/files/tweaks/06_listloop-i.txt +++ b/app/files/tweaks/06_listloop-i.txt @@ -9,8 +9,8 @@ then SHORTER_DELAY_MOD=1 fi -# NO MORE COMPATIBILITY CHECK NEEDED - UNIVERSAL COMPATIBILITY FROM v55 - v70.00.100 -# v70.00.100+ will not install mod/needs verification of compatibility +# NO MORE COMPATIBILITY CHECK NEEDED - UNIVERSAL COMPATIBILITY FROM v55 - v70.00.xxx +# v70.00.335+ will not install mod/needs verification of compatibility if [ $COMPAT_GROUP -le 6 ] then cp -a "${MYDIR}/config/list-loop/jci/gui/common/controls/List2/js/List2Ctrl.js" /jci/gui/common/controls/List2/js/ diff --git a/app/files/tweaks/09_audioorder-i.txt b/app/files/tweaks/09_audioorder-i.txt index 623551c..e2a615e 100644 --- a/app/files/tweaks/09_audioorder-i.txt +++ b/app/files/tweaks/09_audioorder-i.txt @@ -1,6 +1,5 @@ backup_org /jci/gui/apps/system/js/systemApp.js # change order of the audio source list -show_message "CHANGE ORDER OF AUDIO SOURCE LIST ..." log_message "======****** INSTALL CHANGE ORDER OF AUDIO SOURCE LIST ... *******=======" TRACKORDER_AUDIO=2 # Compatibility Check @@ -17,7 +16,14 @@ then TRACKORDER_AUDIO=1 TRACKORDER_AUDIO_FILE=70 log_message "=== FW ${CMU_SW_VER} detected, copy matching systemApp.js ===" +elif [ $COMPAT_GROUP -gt 6 ] +then + killall -q jci-dialog + /jci/tools/jci-dialog --confirm --title="ORDER OF AUDIO SOURCES TWEAK" --text="YOUR FW VERSION IS ${CMU_SW_VER}\nORDER OF AUDIO SOURCES TWEAK HAS ONLY\n BEEN TESTED UP TO V70.00.335\n\n***** INSTALL AT YOUR OWN RISK! *****" --ok-label="INSTALL" --cancel-label="SKIP" + TRACKORDER_AUDIO=$(($?+1)) + TRACKORDER_AUDIO_FILE=70 fi +[ $TRACKORDER_AUDIO -le 1 ] && show_message "CHANGE ORDER OF AUDIO SOURCE LIST ..." # Compatibility check falls into 3 groups: # 70.00.XXX ($COMPAT_GROUP=6) @@ -49,11 +55,8 @@ then fi fi else - # 2 Means unknown firmware version email the address below - show_message "******* AUDIO ORDER PATCH HAS NOT BEEN MADE FOR YOUR FW:${CMU_SW_VER}\nPlease Email ${MYDIR}/systemApp.js to aio@mazdatweaks.com ===" - log_message "******** Audio Source List Order Tweak Is Not Compatible With your FW Version ********" - log_message "******** Please Email ${MYDIR}/systemApp.js FW:${CMU_SW_VER} to aio@mazdatweaks.com ********" - cp -a /jci/gui/apps/system/js/systemApp.js "${MYDIR}/" + show_message "=== ORDER OF AUDIO SOURCES PATCH SKIPPED ===" + log_message "******** Audio Source List Order Tweak Skipped ********" fi if [ $TESTBKUPS -eq 1 ] then diff --git a/app/files/tweaks/17_videoplayer-i.txt b/app/files/tweaks/17_videoplayer-i.txt index 76d4d63..8d28288 100644 --- a/app/files/tweaks/17_videoplayer-i.txt +++ b/app/files/tweaks/17_videoplayer-i.txt @@ -19,6 +19,7 @@ pkill websocketd # Remove previous files rm -fr /jci/gui/apps/_videoplayer rm -fr /tmp/mnt/resources/aio/apps/_videoplayer +rm -fr ${AIO_APP_DIR}/_videoplayer sed -i '/Video/d' ${STAGE_WIFI} sed -i '/--port=9998/d' ${STAGE_WIFI} log_message "=== Removed Old VideoPlayer Files ===" @@ -73,7 +74,7 @@ addon_common # symlink to resources if [ $APPS2RESOURCES -eq 1 ] then - ln -sf /tmp/mnt/resources/aio/apps/_videoplayer /jci/gui/apps/_videoplayer + ln -sf ${AIO_APP_DIR}/_videoplayer /jci/gui/apps/_videoplayer log_message "=== Created Symlink To Resources Partition ===" fi diff --git a/app/files/tweaks/17_videoplayer-u.txt b/app/files/tweaks/17_videoplayer-u.txt index 990026d..24d06f7 100644 --- a/app/files/tweaks/17_videoplayer-u.txt +++ b/app/files/tweaks/17_videoplayer-u.txt @@ -11,30 +11,8 @@ then [ -f ${ADDITIONAL_APPS_JSON} ] && cp ${ADDITIONAL_APPS_JSON} "${MYDIR}/bakups/test/additionalApps_videoplayer-before.json" fi -sed -i '/Speedo-Compass-Video_Tweak/d' ${STAGE_WIFI} -sed -i '/v3.2/d' ${STAGE_WIFI} -sed -i '/Removed requirement/d' ${STAGE_WIFI} -sed -i '/# mount /d' ${STAGE_WIFI} -sed -i '/Added additional/d' ${STAGE_WIFI} -sed -i '/get-vehicle-speed.sh/d' ${STAGE_WIFI} -sed -i '/get-vehicle-data-other.sh/d' ${STAGE_WIFI} -sed -i '/get-gps-data.sh/d' ${STAGE_WIFI} -sed -i '/Need to set defaults/d' ${STAGE_WIFI} -sed -i '/myVideoList /d' ${STAGE_WIFI} -sed -i '/playbackAction /d' ${STAGE_WIFI} -sed -i '/playbackOption /d' ${STAGE_WIFI} -sed -i '/playbackStatus /d' ${STAGE_WIFI} -sed -i '/playback/d' ${STAGE_WIFI} -sed -i '/myVideoList/d' ${STAGE_WIFI} -sed -i '/Video player action watch/d' ${STAGE_WIFI} -sed -i '/playback-action.sh/d' ${STAGE_WIFI} -sed -i '/Log data collection/d' ${STAGE_WIFI} -sed -i '/get-log-data/d' ${STAGE_WIFI} -sed -i '/### Video player/d' ${STAGE_WIFI} -sed -i '/_videoplayer/d' ${STAGE_WIFI} -sed -i '/addon-player.sh &/d' ${STAGE_WIFI} - sed -i '/Video/d' ${STAGE_WIFI} +sed -i '/_videoplayer/d' ${STAGE_WIFI} sed -i '/--port=9998/d' ${STAGE_WIFI} # delete videoplayer entry from additionalApps.json @@ -50,7 +28,7 @@ then || grep -Fq "_speedometer" ${ADDITIONAL_APPS_JSON} \ || grep -Fq "_mzdmeter" ${ADDITIONAL_APPS_JSON} then - log_message "=== Found other apps in additionalApps.json ===" + log_message "=== Found other apps in additionalApps.json ===" ADDIT_APPS=1 fi fi @@ -69,19 +47,9 @@ then log_message "=== Removed addon-common because no more AIO apps ===" fi -rm -fr /jci/gui/addon-player -rm -fr /jci/gui/addon-speedometer -rm -fr /jci/gui/speedometer +rm -fr ${AIO_APP_DIR}/_videoplayer rm -fr /jci/gui/apps/_videoplayer rm -fr /tmp/mnt/resources/aio/apps/_videoplayer -rm -f /jci/opera/opera_dir/userjs/addon-startup.js -rm -f /jci/opera/opera_dir/userjs/mySpeedometer* -rm -f /jci/scripts/get-gps-data* -rm -f /jci/scripts/get-log-data* -rm -f /jci/scripts/get-vehicle-data-other* -rm -f /jci/scripts/get-vehicle-gear* -rm -f /jci/scripts/get-vehicle-speed* -rm -f ${STAGE_WIFI}.bak? log_message "=== Removed Video Player Files ===" if [ $TESTBKUPS -eq 1 ] diff --git a/app/files/tweaks/19_speedo-i1.txt b/app/files/tweaks/19_speedo-i1.txt index da5f4d9..706ea61 100644 --- a/app/files/tweaks/19_speedo-i1.txt +++ b/app/files/tweaks/19_speedo-i1.txt @@ -25,37 +25,8 @@ rm -fr /jci/gui/addon-speedometer rm -fr /jci/gui/speedometer rm -fr /jci/gui/apps/_speedometer rm -fr /tmp/mnt/resources/aio/apps/_speedometer +rm -fr ${AIO_APP_DIR}/_speedometer -sed -i '/Speedo-Compass-Video/d' ${STAGE_WIFI} -sed -i '/v3.2/d' ${STAGE_WIFI} -sed -i '/Removed requirement/d' ${STAGE_WIFI} -sed -i '/# mount /d' ${STAGE_WIFI} -sed -i '/Added additional/d' ${STAGE_WIFI} -sed -i '/get-vehicle-speed/d' ${STAGE_WIFI} -sed -i '/get-vehicle-data-other/d' ${STAGE_WIFI} -sed -i '/get-gps-data/d' ${STAGE_WIFI} -sed -i '/Need to set defaults/d' ${STAGE_WIFI} -sed -i '/myVideoList /d' ${STAGE_WIFI} -sed -i '/playbackAction /d' ${STAGE_WIFI} -sed -i '/playbackOption /d' ${STAGE_WIFI} -sed -i '/playbackStatus /d' ${STAGE_WIFI} -sed -i '/playback/d' ${STAGE_WIFI} -sed -i '/myVideoList/d' ${STAGE_WIFI} -sed -i '/Video player action watch/d' ${STAGE_WIFI} -sed -i '/playback-action.sh/d' ${STAGE_WIFI} -sed -i '/Log data collection/d' ${STAGE_WIFI} -sed -i '/get-log-data.sh/d' ${STAGE_WIFI} -sed -i '/addon-speedometer.sh &/d' ${STAGE_WIFI} -sed -i '/addon-player.sh &/d' ${STAGE_WIFI} -sed -i '/stage_vehSpeed.sh/d' ${STAGE_WIFI} -sed -i '/mount of SD card/d' ${STAGE_WIFI} -sed -i '/sleep 40/d' ${STAGE_WIFI} -sed -i '/sleep 55/d' ${STAGE_WIFI} -sed -i '/sleep 50/d' ${STAGE_WIFI} -sed -i '/umount -l/d' ${STAGE_WIFI} -sed -i '/sleep 25/d' ${STAGE_WIFI} -sed -i '/sleep 4/d' ${STAGE_WIFI} -sed -i '/sleep 6/d' ${STAGE_WIFI} sed -i '/55554/d' ${STAGE_WIFI} sed -i '/9969/d' ${STAGE_WIFI} sed -i '/## Speedometer/d' ${STAGE_WIFI} @@ -76,7 +47,7 @@ log_message "=== Copied Speedometer Files # symlink to resources if [ $APPS2RESOURCES -eq 1 ] then - ln -sf /tmp/mnt/resources/aio/apps/_speedometer /jci/gui/apps/_speedometer + ln -sf ${AIO_APP_DIR}/_speedometer /jci/gui/apps/_speedometer log_message "=== Created Symlink To Resources Partition ===" fi diff --git a/app/files/tweaks/19_speedo-u.txt b/app/files/tweaks/19_speedo-u.txt index 1acbbd1..3053bcc 100644 --- a/app/files/tweaks/19_speedo-u.txt +++ b/app/files/tweaks/19_speedo-u.txt @@ -10,37 +10,7 @@ then [ -f ${ADDITIONAL_APPS_JSON} ] && cp ${ADDITIONAL_APPS_JSON} "${MYDIR}/bakups/test/additionalApps_speedometer-before.json" fi -sed -i '/Speedo-Compass-Video_Tweak/d' ${STAGE_WIFI} -sed -i '/v3.2/d' ${STAGE_WIFI} -sed -i '/Removed requirement/d' ${STAGE_WIFI} -sed -i '/# mount /d' ${STAGE_WIFI} -sed -i '/Added additional/d' ${STAGE_WIFI} -sed -i '/get-vehicle-speed.sh/d' ${STAGE_WIFI} -sed -i '/get-vehicle-data-other.sh/d' ${STAGE_WIFI} -sed -i '/get-gps-data.sh/d' ${STAGE_WIFI} -sed -i '/Need to set defaults/d' ${STAGE_WIFI} -sed -i '/myVideoList /d' ${STAGE_WIFI} -sed -i '/playbackAction /d' ${STAGE_WIFI} -sed -i '/playbackOption /d' ${STAGE_WIFI} -sed -i '/playbackStatus /d' ${STAGE_WIFI} -sed -i '/playback/d' ${STAGE_WIFI} -sed -i '/myVideoList/d' ${STAGE_WIFI} -sed -i '/Video player action watch/d' ${STAGE_WIFI} -sed -i '/playback-action.sh/d' ${STAGE_WIFI} -sed -i '/Log data collection/d' ${STAGE_WIFI} -sed -i '/get-log-data/d' ${STAGE_WIFI} sed -i '/### Speedometer/d' ${STAGE_WIFI} -sed -i '/addon-speedometer.sh &/d' ${STAGE_WIFI} -sed -i '/speedometer.sh &/d' ${STAGE_WIFI} -sed -i '/addon-player.sh &/d' ${STAGE_WIFI} -sed -i '/mount of SD card/d' ${STAGE_WIFI} -sed -i '/umount -l/d' ${STAGE_WIFI} -sed -i '/sleep 40/d' ${STAGE_WIFI} -sed -i '/sleep 55/d' ${STAGE_WIFI} -sed -i '/sleep 50/d' ${STAGE_WIFI} -sed -i '/sleep 25/d' ${STAGE_WIFI} -sed -i '/sleep 4/d' ${STAGE_WIFI} -sed -i '/sleep 6/d' ${STAGE_WIFI} sed -i '/9969/d' ${STAGE_WIFI} sed -i '/55554/d' ${STAGE_WIFI} @@ -51,21 +21,12 @@ then then log_message "=== Found CASDK ===" ADDIT_APPS=1 - elif grep -Fq "_aiotweaks" ${ADDITIONAL_APPS_JSON} + elif grep -Fq "_aiotweaks" ${ADDITIONAL_APPS_JSON} \ + || grep -Fq "_androidauto" ${ADDITIONAL_APPS_JSON} \ + || grep -Fq "_videoplayer" ${ADDITIONAL_APPS_JSON} \ + || grep -Fq "_mzdmeter" ${ADDITIONAL_APPS_JSON} then - log_message "=== Found AIOTweaksApp entry in additionalApps.json ===" - ADDIT_APPS=1 - elif grep -Fq "_androidauto" ${ADDITIONAL_APPS_JSON} - then - log_message "=== Found androidauto entry in additionalApps.json ===" - ADDIT_APPS=1 - elif grep -Fq "_videoplayer" ${ADDITIONAL_APPS_JSON} - then - log_message "=== Found videoplayer entry in additionalApps.json ===" - ADDIT_APPS=1 - elif grep -Fq "_mzdmeter" ${ADDITIONAL_APPS_JSON} - then - log_message "=== Found mzd meter entry in additionalApps.json ===" + log_message "=== Found other apps in additionalApps.json ===" ADDIT_APPS=1 fi fi @@ -84,21 +45,10 @@ then rm -rf /tmp/mnt/resources/aio/addon-common log_message "=== Removed addon-common because no more AIO apps ===" fi -rm -fr /jci/gui/addon-player -rm -fr /jci/gui/addon-speedometer +rm -fr ${AIO_APP_DIR}/_speedometer rm -fr /jci/gui/apps/_speedometer -rm -fr /jci/gui/speedometer rm -fr /tmp/mnt/resources/aio/apps/_speedometer -rm -f /jci/opera/opera_dir/userjs/addon-startup.js rm -f /jci/opera/opera_dir/userjs/speedometer-startup.js -rm -f ${STAGE_WIFI}.bak? -rm -f /jci/scripts/get-vehicle-speed.sh -rm -f /jci/scripts/stage_vehSpeed.sh -rm -f /jci/scripts/get-vehicle-fuel.sh -rm -f /jci/scripts/get-gps-speed.sh -rm -f /jci/scripts/get-engine-speed.sh -rm -f /jci/scripts/get-gear-position.sh -rm -f /jci/scripts/get-temp.sh log_message "=== cleanup old versions ===" if [ $TESTBKUPS -eq 1 ] diff --git a/app/files/tweaks/20_date-iv3.3.txt b/app/files/tweaks/20_date-iv3.3.txt index 53256a4..ef3fe58 100644 --- a/app/files/tweaks/20_date-iv3.3.txt +++ b/app/files/tweaks/20_date-iv3.3.txt @@ -104,15 +104,21 @@ else # if [ $DATE_FORMAT -eq 0 ] fi # StatusBarCtrl.js is the file that needs to be compatability checked because of minor changes in FW v59+ -# Compatibility has been fixed now compatible with all FW v55 - v70.00.100 -# if [ $STATUSBAR_COPY -eq 1 ] -if [ $COMPAT_GROUP -le 6 ] +# Compatibility has been fixed now compatible with all FW v55 - v70.00.335 +STATUSBAR_COPY=0 +if [ $COMPAT_GROUP -gt 6 ] +then + killall -q jci-dialog + /jci/tools/jci-dialog --confirm --title="DATE TO STATUSBAR" --text="YOUR FW VERSION IS ${CMU_SW_VER}\nDATE TO STATUSBAR TWEAK HAS ONLY\n BEEN TESTED UP TO V70.00.335\n\n***** INSTALL AT YOUR OWN RISK! *****" --ok-label="INSTALL" --cancel-label="SKIP" + STATUSBAR_COPY=$? +fi +if [ $STATUSBAR_COPY -eq 0 ] then cp -a "${MYDIR}/config/date-to-statusbar_mod/jci/gui/common/controls/StatusBar/js/StatusBarCtrl.js" /jci/gui/common/controls/StatusBar/js log_message "=== Copied StatusBarCtrl.js ===" -else # only v70.00.100+ will fail because compatibility is unknown - log_message "***** date_to_statusbar_mod v3.4 not compatible to your FW, no installation made! ******" - log_message "*********** Please email your FW version:${CMU_SW_VER} to aio@mazdatweaks.com **********" +else # only v70.00.335+ will be skipped if choice is made + log_message "***** date_to_statusbar_mod v3.4 installation skipped ******" + show_message "DATE_TO_STATUSBAR INSTALLATION SKIPPED ..." fi log_message "======********* END INSTALLATION OF DATE TO STATUSBAR MOD ********======" diff --git a/app/files/tweaks/24_castscreen-i.txt b/app/files/tweaks/24_castscreen-i.txt index b6ad492..6bdc18e 100644 --- a/app/files/tweaks/24_castscreen-i.txt +++ b/app/files/tweaks/24_castscreen-i.txt @@ -5,7 +5,7 @@ show_message "INSTALL CASTSCREEN-RECEIVER ..." log_message "=====************** INSTALL CASTSCREEN-RECEIVER ... *************=====" cp -a ${MYDIR}/config/castscreen-receiver/*.sh /jci/scripts cp -a ${MYDIR}/config/castscreen-receiver/cs_receiver_arm /jci/scripts -cp -a ${MYDIR}/config/castscreen-receiver/adb /tmp/mnt/resources/dev/bin +cp -a ${MYDIR}/config/castscreen-receiver/adb /jci/scripts rm -f /jci/scripts/cs_receiver_conn_arm rm -f /jci/scripts/adb rm -f /jci/scripts/castscreen-1.0.apk @@ -14,11 +14,19 @@ log_message "=== Copied castscreen-receiver files to /jci/scripts/ chmod 777 /jci/scripts/wait_adb_arm.sh chmod 777 /jci/scripts/cs_receiver_arm chmod 777 /jci/scripts/mirroring.sh +chmod 777 /jci/scripts/adb +if [ ! -L /bin/adb ]; then + ln -fs /jci/scripts/adb /bin/adb + log_message "=== Created symlink for adb ===" +fi + if [ $TESTBKUPS -eq 1 ] then cp ${STAGE_WIFI} ${MYDIR}/bakups/test/stage_wifi_castscreen-before.sh fi +sed -i '/mirroring.sh/d' ${STAGE_WIFI} +sed -i '/### Castscreen/d' ${STAGE_WIFI} #add castscreen-receiver to stage_wifi if [ -e ${STAGE_WIFI} ] then diff --git a/app/files/tweaks/25_androidauto-i.txt b/app/files/tweaks/25_androidauto-i.txt index 3669d26..b4acae2 100644 --- a/app/files/tweaks/25_androidauto-i.txt +++ b/app/files/tweaks/25_androidauto-i.txt @@ -14,6 +14,7 @@ fi killall -q -9 headunit-wrapper killall -q -9 headunit +rm -fr ${AIO_APP_DIR}/_androidauto rm -fr /jci/gui/apps/_androidauto rm -fr /tmp/mnt/resources/aio/apps/_androidauto rm -fr /tmp/mnt/data_persist/dev/androidauto @@ -61,7 +62,7 @@ log_message "=== Copied Android Auto Headunit App files # symlink to resources if [ $APPS2RESOURCES -eq 1 ] then - ln -sf /tmp/mnt/resources/aio/apps/_androidauto /jci/gui/apps/_androidauto + ln -sf ${AIO_APP_DIR}/_androidauto /jci/gui/apps/_androidauto log_message "=== Created Symlink To Resources Partition ===" fi diff --git a/app/files/tweaks/25_androidautocargps.txt b/app/files/tweaks/25_androidautocargps.txt index f84ad87..5ef5e30 100644 --- a/app/files/tweaks/25_androidautocargps.txt +++ b/app/files/tweaks/25_androidautocargps.txt @@ -1,2 +1,2 @@ sed -i 's/"carGPS": true/"carGPS": false/g' /tmp/mnt/data_persist/dev/bin/headunit.json -log_message "=== Only use phone GPS ===" +log_message "=== DISABLE AA USE OF CAR GPS ===" diff --git a/app/files/tweaks/27_aioapp-i.txt b/app/files/tweaks/27_aioapp-i.txt index 471f712..7781ecd 100644 --- a/app/files/tweaks/27_aioapp-i.txt +++ b/app/files/tweaks/27_aioapp-i.txt @@ -17,6 +17,7 @@ pkill websocketd # Remove previous files rm -fr /jci/gui/apps/_aiotweaks rm -fr /tmp/mnt/resources/aio/apps/_aiotweaks +rm -fr ${AIO_APP_DIR}/_aiotweaks rm -fr /tmp/mnt/data_persist/dev/system_restore # Remove old aio-startup rm -f /jci/opera/opera_dir/userjs/aio-startup.js @@ -68,7 +69,7 @@ cp -a ${MYDIR}/config/aio-app/data_persist/* /tmp/mnt/data_persist/ # symlink to resources if [ $APPS2RESOURCES -eq 1 ] then - ln -sf /tmp/mnt/resources/aio/apps/_aiotweaks /jci/gui/apps/_aiotweaks + ln -sf ${AIO_APP_DIR}/_aiotweaks /jci/gui/apps/_aiotweaks log_message "=== Created Symlink To Resources Partition ===" fi diff --git a/app/files/tweaks/cmu-autorun/installer/autorun b/app/files/tweaks/cmu-autorun/installer/autorun new file mode 100644 index 0000000..c6a27d6 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/installer/autorun @@ -0,0 +1,37 @@ +#!/bin/sh +### autorun +# this script search in this dir and subdirs for *.autorun files +# *.autorun files not need to have x (execute) bit set +# and run all *.autorun files in alphabetical order (path+filename) +# wait for every script to finish and run next script +# THIS FILE NEED TO BE IN /tmp/mnt/data_persist/dev/bin/ +# THIS FILE NEED TO HAVE x (execute) bit SET TO BE EXECUTED BY CMU !!! + +/bin/chmod +x $0 +/usr/bin/find `dirname $0` -iname \*.autorun -type f | /usr/bin/sort | /usr/bin/xargs -n 1 /bin/sh + +# Run the run.sh script +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +sleep 40 +if [ -e /mnt/sd_nav/run.sh ] +then + chmod +x /mnt/sd_nav/run.sh + sh /mnt/sd_nav/run.sh +fi + +for USB in a b c d e +do + RUNSH="/tmp/mnt/sd${USB}/run.sh" + if [ -e "${RUNSH}" ]; then + /bin/sh "${RUNSH}" + break + fi + RUNSH="/tmp/mnt/sd${USB}1/run.sh" + if [ -e "${RUNSH}" ]; then + /bin/sh "${RUNSH}" + break + fi +done + +exit 0 +### END autorun \ No newline at end of file diff --git a/app/files/tweaks/cmu-autorun/installer/autorun.temp b/app/files/tweaks/cmu-autorun/installer/autorun.temp new file mode 100644 index 0000000..484c392 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/installer/autorun.temp @@ -0,0 +1,33 @@ +### autorun +# this script search in his dir and subdirs for *.autorun files +# *.autorun files not need to have x (execute) bit set +# and run all *.autorun files in alphabetical order (path+filename) +# wait for every script to finish and run next script +# THIS FILE NEED TO BE IN /tmp/mnt/data_persist/dev/bin/ +# THIS FILE NEED TO HAVE x (execute) bit SET TO BE EXECUTED BY CMU !!! + +/bin/chmod +x $0 +/usr/bin/find `dirname $0` -iname \*.autorun -type f | /usr/bin/sort | /usr/bin/xargs -n 1 /bin/sh + +# Run the run.sh script +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +sleep 40 +if [ -e /mnt/sd_nav/run.sh ] +then + chmod +x /mnt/sd_nav/run.sh + sh /mnt/sd_nav/run.sh +fi + +for USB in a b c d e +do + RUNSH="/tmp/mnt/sd${USB}1/run.sh" + if [ -e "${RUNSH}" ] + then + chmod +x "${RUNSH}" + sh "${RUNSH}" + break + fi +done + +exit 0 +### END autorun diff --git a/app/files/tweaks/cmu-autorun/installer/cmu_dataretrieval.up b/app/files/tweaks/cmu-autorun/installer/cmu_dataretrieval.up new file mode 100644 index 0000000..8edfa1d Binary files /dev/null and b/app/files/tweaks/cmu-autorun/installer/cmu_dataretrieval.up differ diff --git a/app/files/tweaks/cmu-autorun/installer/dataRetrieval_config.txt b/app/files/tweaks/cmu-autorun/installer/dataRetrieval_config.txt new file mode 100644 index 0000000..b72d26d --- /dev/null +++ b/app/files/tweaks/cmu-autorun/installer/dataRetrieval_config.txt @@ -0,0 +1,20 @@ +CMU_STATUS=no +DATA_PERSIST=no +SCREENSHOT=no +MEMINFO=no +TOP_LOG=no +SMEVENTS=no +NVRAM_DATA=no +THREAD_INFO=no +VUI_LOG=no +GPIO_DATA=no +SETTINGS_BIN=no +SMAPS_VALUE=no +TEST_MODE=no +VUI_ECO_FILES=no +BDS_DATA=no +FLASHINFO=no +SCI_LOG=no +LOG_TIMEOUT=120 +TMP_FILTER= +CMD_LINE=sh /mnt/sd*/tweaks.sh \ No newline at end of file diff --git a/app/files/tweaks/cmu-autorun/installer/jci-autoupdate b/app/files/tweaks/cmu-autorun/installer/jci-autoupdate new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/installer/jci-autoupdate @@ -0,0 +1 @@ + diff --git a/app/files/tweaks/cmu-autorun/installer/tweaks.sh b/app/files/tweaks/cmu-autorun/installer/tweaks.sh new file mode 100644 index 0000000..26e278b --- /dev/null +++ b/app/files/tweaks/cmu-autorun/installer/tweaks.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +# disable watchdog and allow write access +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +mount -o rw,remount / + +MYDIR=$(dirname "$(readlink -f "$0")") +NAME="autorun" +CONF_DIR="/tmp/mnt/data_persist/dev/bin" +CONF_FILE=${CONF_DIR}/${NAME} +SRC_FILE=${MYDIR}/${NAME} + +. "${MYDIR}"/utils.sh + +CMU_SW_VER=$(get_cmu_sw_version) +CMU_VER=${CMU_SW_VER:0:2} +rm -f "${MYDIR}/AIO_log.txt" + +if [ ! -e ${CONF_DIR} ]; then + mkdir -p ${CONF_DIR} +fi +choice=0 +# confirmation /jci/tools/jci-dialog --3-button-dialog --title="Tweaks Selection for AUTORUN" --text="Choose Installation Method" --ok-label="Install" --cancel-label="Uninstall" --button3-label="Skip" +# confirmation choice=$? +if [ "$choice" -eq 0 ]; then + msg="Install.." + # Remove old files + rm -rf ${CONF_DIR}/00-* ${CONF_DIR}/01-* + rm -rf ${CONF_DIR}/02-* ${CONF_DIR}/44-* + rm -f ${CONF_DIR}/tweaks.sh + cat ${SRC_FILE} > ${CONF_FILE} + show_message "INSTALLING RECOVERY FILES" + cp -a "${MYDIR}"/02-* ${CONF_DIR} + cp -a "${MYDIR}"/44-* ${CONF_DIR} + if [ -e "${MYDIR}"/adb ]; then + show_message "INSTALLING ADB" + cp -a "${MYDIR}"/adb ${CONF_DIR} + fi + chmod +x ${CONF_FILE} + sleep 2 + killall jci-dialog + reboot=0 + # confirmation /jci/tools/jci-dialog --question --title="CMU-AUTORUN" --text="autorun installation complete\n\nReboot?" --ok-label="Now" --cancel-label="Later" + # confirmation reboot=$? + show_message "AUTORUN & RECOVERY INSTALLATION COMPLETE" + if [ "$reboot" -eq 0 ]; then + reboot + fi +elif [ "$choice" -eq 1 ]; then + if [ "$CMU_VER" -ge 59 ]; then + show_message_OK "WARNING: UNINSTALLING AUTORUN WILL PERMANENTLY\nREMOVE YOUR ABILITY TO INSTALL TWEAKS\nAND YOU WILL LOSE ALL ACCESS TO MODIFY YOUR SYSTEM\nDO NOT CONTINUE IF THIS IS NOT YOUR INTENTION!!!" + fi + show_message "UNINSTALLING AUTORUN AND RECOVERY FILES..." + if [ -e ${CONF_FILE} ]; then + if grep -Fq "### ${NAME}" ${CONF_FILE} + then + t=$(cat ${CONF_FILE}.temp) + # sed -i "/### ${NAME}/,/### END ${NAME}/d" ${CONF_FILE} + else + echo "Clean" + fi + else + show_message "NO AUTORUN" + fi + rm -rf ${CONF_DIR}/00-* ${CONF_DIR}/01-* + rm -rf ${CONF_DIR}/02-* ${CONF_DIR}/44-* + + chmod -R 777 ${CONF_DIR} + killall jci-dialog + show_message "REBOOTING" + sleep 5 + reboot +else + show_message "INSTALLATION ABORTED PLEASE UNPLUG USB DRIVE" +fi + +chmod 777 -R /tmp/mnt/data_persist +sleep 2 +killall jci-dialog +exit 0 diff --git a/app/files/tweaks/cmu-autorun/installer/utils.sh b/app/files/tweaks/cmu-autorun/installer/utils.sh new file mode 100644 index 0000000..9681830 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/installer/utils.sh @@ -0,0 +1,123 @@ +#!/bin/sh + +MYDIR=$(dirname "$(readlink -f "$0")") + +get_cmu_sw_version() +{ + _ver=$(/bin/grep "^JCI_SW_VER=" /jci/version.ini | /bin/sed 's/^.*_\([^_]*\)\"$/\1/') + _patch=$(/bin/grep "^JCI_SW_VER_PATCH=" /jci/version.ini | /bin/sed 's/^.*\"\([^\"]*\)\"$/\1/') + _flavor=$(/bin/grep "^JCI_SW_FLAVOR=" /jci/version.ini | /bin/sed 's/^.*_\([^_]*\)\"$/\1/') + + if [ ! -z "${_flavor}" ]; then + echo "${_ver}${_patch}-${_flavor}" + else + echo "${_ver}${_patch}" + fi +} + +log_message() +{ + echo "$*" 1>&2 + echo "$*" >> "${MYDIR}/AIO_log.txt" + /bin/fsync "${MYDIR}/AIO_log.txt" +} + +show_message() +{ + sleep 5 + killall jci-dialog +# log_message "= POPUP: $* " + /jci/tools/jci-dialog --info --title="MESSAGE" --text="$*" --no-cancel & +} + +show_message_OK() +{ + sleep 4 + killall jci-dialog +# log_message "= POPUP: $* " + /jci/tools/jci-dialog --confirm --title="CONTINUE INSTALLATION?" --text="$*" --ok-label="YES - GO ON" --cancel-label="NO - ABORT" + if [ $? != 1 ] + then + killall jci-dialog + return + else + show_message "INSTALLATION ABORTED! PLEASE UNPLUG USB DRIVE" + sleep 5 + exit + fi +} + +add_app_json() +# script by vic_bam85 +{ + # check if entry in additionalApps.json still exists, if so nothing is to do + count=$(grep -c '{ "name": "'"${1}"'"' /jci/opera/opera_dir/userjs/additionalApps.json) + if [ "$count" = "0" ] + then + log_message "=== No entry of ${2} found in additionalApps.json, seems to be the first installation ===" + mv /jci/opera/opera_dir/userjs/additionalApps.json /jci/opera/opera_dir/userjs/additionalApps.json.old + sleep 2 + # delete last line with "]" from additionalApps.json + grep -v "]" /jci/opera/opera_dir/userjs/additionalApps.json.old > /jci/opera/opera_dir/userjs/additionalApps.json + sleep 2 + cp /jci/opera/opera_dir/userjs/additionalApps.json "${MYDIR}/additionalApps${1}-2._delete_last_line.json" + # check, if other entrys exists + count=$(grep -c '}' /jci/opera/opera_dir/userjs/additionalApps.json) + if [ "$count" != "0" ] + then + # if so, add "," to the end of last line to additionalApps.json + echo "$(cat /jci/opera/opera_dir/userjs/additionalApps.json)", > /jci/opera/opera_dir/userjs/additionalApps.json + sleep 2 + cp /jci/opera/opera_dir/userjs/additionalApps.json "${MYDIR}/additionalApps${1}-3._add_comma_to_last_line.json" + log_message "=== Found existing entrys in additionalApps.json ===" + fi + # add app entry and "]" again to last line of additionalApps.json + log_message "=== Add ${2} to last line of additionalApps.json ===" + echo '{ "name": "'"${1}"'", "label": "'"${2}"'" }' >> /jci/opera/opera_dir/userjs/additionalApps.json + sleep 2 + cp /jci/opera/opera_dir/userjs/additionalApps.json "${MYDIR}/additionalApps${1}-4._add_entry_to_last_line.json" + echo "]" >> /jci/opera/opera_dir/userjs/additionalApps.json + sleep 2 + cp /jci/opera/opera_dir/userjs/additionalApps.json "${MYDIR}/additionalApps${1}-5._after.json" + rm -f /jci/opera/opera_dir/userjs/additionalApps.json.old + else + log_message "=== ${2} already exists in additionalApps.json, no modification necessary ===" + fi +} + +remove_app_json() +# script by vic_bam85 +{ + # check if app entry in additionalApps.json still exists, if so, then it will be deleted + count=$(grep -c '{ "name": "'"${1}"'"' /jci/opera/opera_dir/userjs/additionalApps.json) + if [ "$count" -gt "0" ] + then + log_message "=== ${count} entry(s) of ${1} found in additionalApps.json, app is already installed and will be deleted now ===" + mv /jci/opera/opera_dir/userjs/additionalApps.json /jci/opera/opera_dir/userjs/additionalApps.json.old + # delete last line with "]" from additionalApps.json + grep -v "]" /jci/opera/opera_dir/userjs/additionalApps.json.old > /jci/opera/opera_dir/userjs/additionalApps.json + sleep 2 + cp /jci/opera/opera_dir/userjs/additionalApps.json "${MYDIR}/additionalApps${1}-2._delete_last_line.json" + # delete all app entrys from additionalApps.json + sed -i "/${1}/d" /jci/opera/opera_dir/userjs/additionalApps.json + sleep 2 + cp /jci/opera/opera_dir/userjs/additionalApps.json "${MYDIR}/additionalApps${1}-3._delete_app_entry.json" + json="$(cat /jci/opera/opera_dir/userjs/additionalApps.json)" + # check if last sign is comma + rownend=$(echo -n "$json" | tail -c 1) + if [ "$rownend" = "," ] + then + # if so, remove "," from back end + echo "${json%,*}" > /jci/opera/opera_dir/userjs/additionalApps.json + sleep 2 + log_message "=== Found comma at last line of additionalApps.json and deleted it ===" + fi + # add "]" again to last line of additionalApps.json + echo "]" >> /jci/opera/opera_dir/userjs/additionalApps.json + rm -f /jci/opera/opera_dir/userjs/additionalApps.json.old + sleep 2 + cp /jci/opera/opera_dir/userjs/additionalApps.json "${MYDIR}/additionalApps${1}-4._after.json" + else + log_message "=== ${1} not found in additionalApps.json, no modification necessary ===" + fi +} diff --git a/app/files/tweaks/cmu-autorun/sdcard/README.md b/app/files/tweaks/cmu-autorun/sdcard/README.md new file mode 100644 index 0000000..68da5be --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/README.md @@ -0,0 +1,11 @@ +# Autorun scripts + +## Works with SD Card and USB Drives + +### Master Run Script +- Runs all the autorun scripts, one at a time. +- Copy the entire contence of this folder to the root of an SD Card or USB Drives. +- Edit 'autorun.conf' to choose which scripts run (1 = run, 0 = do not run) +- **For testing and development** NOTE: certain combinations of scripts may be conflicting + +##### NOTE: Does not run [Recovery Scripts](recovery). \ No newline at end of file diff --git a/app/files/tweaks/cmu-autorun/sdcard/WifiAP-toggle/run.sh b/app/files/tweaks/cmu-autorun/sdcard/WifiAP-toggle/run.sh new file mode 100644 index 0000000..fc583c9 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/WifiAP-toggle/run.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +# disable watchdog and allow write access +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +mount -o rw,remount / + +MYDIR=$(dirname "$(readlink -f "$0")") + +# Start Wifi AP Toggle + +/jci/scripts/jci-fw.sh stop +killall wpa_supplicant +sleep 2 +/jci/scripts/jci-wifiap.sh start +sleep 2 +/jci/scripts/jci-wifiap.sh status > ${MYDIR}/wifiAPToggle.log diff --git a/app/files/tweaks/cmu-autorun/sdcard/adb/README.md b/app/files/tweaks/cmu-autorun/sdcard/adb/README.md new file mode 100644 index 0000000..8dd62c7 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/adb/README.md @@ -0,0 +1,17 @@ +# SSH Access Via USB cable Over ADB - Android Debug Bridge +### Allows for SSH connection using a USB cable and an Android phone over ADB. + +##### This is the fastest SSH connection you can make with the CMU. The pre-req is SSH must be enabled if it is not for your FW version try SSH_Bringback tweak from [AIO Tweaks](http://mazdatweaks.com). Also an Android phone to connect to ADB. + +## Connect to SSH with a USB cable and Android phone or tablet. +1. Copy `cmu-autorun/sdcard/adb/*` to the root of your SD card +2. Plug SD card to car +3. Plug Android phone to car USB port (debugging mode must be activated in developer options) +4. Start car +5. A message will pop up prompting to connect via SSH +> Host: localhost (or 127.0.0.1) +> Port: 2222 +> User: cmu (or root for FW < v56.00.513) +> Pass: jci + +Example: ssh cmu:jci@localhost -p 2222 diff --git a/app/files/tweaks/cmu-autorun/sdcard/adb/adb b/app/files/tweaks/cmu-autorun/sdcard/adb/adb new file mode 100644 index 0000000..2f98fe4 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/adb/adb differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/adb/adb.sh b/app/files/tweaks/cmu-autorun/sdcard/adb/adb.sh new file mode 100644 index 0000000..777eadf --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/adb/adb.sh @@ -0,0 +1,42 @@ +#!/bin/sh +MYDIR=$(dirname $(readlink -f $0)) +INSTALLDIR=/data_persist/dev/bin +SYMDIR=/usr/bin +TIMESTAMP=$(date "+%m%d%Y-%H%M%S") +LOGFILE=${MYDIR}/adb_log.txt + +echo "Start adb ssh script" >> ${LOGFILE} + +if [ ! -f ${INSTALLDIR}/adb ]; then + mkdir -p ${INSTALLDIR} + if [ ! -f ${MYDIR}/adb ]; then + /jci/tools/jci-dialog --title="SSH" --text="adb not found please install adb to use adb SSH " --ok-label='OK' --no-cancel & + exit + else + /jci/tools/jci-dialog --title="SSH" --text="Installing adb... " --ok-label='OK' --no-cancel & + fi + echo "Disabling Watchdog Service" >> ${LOGFILE} + echo 1 > /sys/class/gpio/Watchdog\ Disable/value + echo "Mounting filesystem read/write" >> ${LOGFILE} + mount -o rw,remount / >> ${LOGFILE} 2>&1 + echo "Install adb files" >> ${LOGFILE} + mv ${MYDIR}/adb ${INSTALLDIR}/adb >> ${LOGFILE} 2>&1 + chmod 755 ${INSTALLDIR}/adb >> ${LOGFILE} 2>&1 + ln -sf ${INSTALLDIR}/adb ${SYMDIR}/adb + killall jci-dialog >> ${LOGFILE} +fi + +/jci/tools/jci-dialog --title="SSH" --text="Connect Android to Mazda USB port" --ok-label='OK' --no-cancel & +echo "Wait for device" >> ${LOGFILE} +adb wait-for-device >> ${LOGFILE} 2>&1 +killall jci-dialog >> ${LOGFILE} +echo "adb reverse tcp:2222 tcp:22" >> ${LOGFILE} + adb reverse tcp:2222 tcp:22 >> ${LOGFILE} 2>&1 +/jci/tools/jci-dialog --title="SSH" --text="on Android do ssh cmu@localhost -p 2222\nCMU Firmware < v56.00.513 use root@localhost -p 2222\n(password: jci)" --ok-label='OK' --no-cancel +echo "Disconnected" >> ${LOGFILE} +sleep 5 +killall jci-dialog >> ${LOGFILE} +/jci/tools/jci-dialog --title="SSH" --text="SSH DISCONNECTED" --ok-label='OK' --no-cancel & +sleep 5 +killall jci-dialog >> ${LOGFILE} +exit diff --git a/app/files/tweaks/cmu-autorun/sdcard/adb/run.sh b/app/files/tweaks/cmu-autorun/sdcard/adb/run.sh new file mode 100644 index 0000000..7d7fef2 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/adb/run.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# Disable watchdog +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +mount -o rw,remount / +# Set environment +DIR=$(dirname $(readlink -f $0)) + +sh ${DIR}/adb.sh & + diff --git a/app/files/tweaks/cmu-autorun/sdcard/autorun.conf b/app/files/tweaks/cmu-autorun/sdcard/autorun.conf new file mode 100644 index 0000000..ddc5aa2 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/autorun.conf @@ -0,0 +1,36 @@ +###################################### +## autorun.conf +## Config file for the Master Autorun Script +## Do Not Run Script = 0 +## Run Script = 1 +## By: Trezdog44 +###################################### + +### RUN_DRYRUN +## Dry Run Script +RUN_DRYRUN=1 + +### RUN_ADB +## SSH over USB via ADB +RUN_ADB=0 + +### RUN_SSH +## Temporary SSH Access Script +RUN_SSH=0 + +### RUN_WIFI +## Wifi AP Toggle Script +RUN_WIFI=0 + +### RUN_SS +## Take Screenshots +RUN_SS=0 + +### RUN_AA +## Run Android Auto Headunit App +RUN_AA=0 + +### RUN_ML +## Memory Logging +RUN_ML=0 + diff --git a/app/files/tweaks/cmu-autorun/sdcard/dryrun/run.sh b/app/files/tweaks/cmu-autorun/sdcard/dryrun/run.sh new file mode 100644 index 0000000..1e87d87 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/dryrun/run.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# dry run example : run.sh +DIR=$(dirname $(readlink -f $0)) +/jci/tools/jci-dialog --title="SUCCESS" --text="AUTORUN ACTIVATED!\n${DIR}" --ok-label='OK' --no-cancel & +sleep 30 +killall jci-dialog diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/README.md b/app/files/tweaks/cmu-autorun/sdcard/headunit/README.md new file mode 100644 index 0000000..592350f --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/headunit/README.md @@ -0,0 +1,51 @@ +# Changlog + +- [20180930] : autorun-headunit-1.3 +* HUD support (Need tester) +* source : https://github.com/silverchris/ +* Improved start script + +- [20180811] : support config file +* support config file github/@Peck07 +* Improve USB/WIFI switch machanism +* support config file for Reverse direction +* support config file for Car GPS/ Phone GPS + +# Instructions + +After activating autorun. + +1. copy `cmu-autorun/sdcard/headunit/*` to SDCARD +2. plug SDCARD to car +3. plug Android phone to car USB port +4. Start car + +Android Auto should automatically start. +## Wireless Mode + +### Initial wireless connection +1. Vehicle : Start car +2. PHONE: Share personal hotspot +3. Vehicle : Connect to personal hotspot +4. PHONE: Enable Developer Settings on Android Auto + +### Instructions: +1. Phone: Create Hotspot +2. Vehicle: Turn on Wifi, connect to phone hotspot +3. Phone: In Android Auto app go to about screen menu and start headunit server +Android Auto will start automatically, if it does not or you get a black screen for more than 5 minutes you can open Android Auto from the applications menu. + +### Stop + +1. Vehicle: Exit Headunit +2. Vehicle: Disconnect personal hotspot +3. PHONE: Stop Head unit Server. Disable developer mode (options). +4. PHONE: disable personal hotspot + +Permanent stop headunit-wirelss can do by disable personal hotspot or unplug SDcard/USB. + +# Compile source +* + +# Compile script +* diff --git a/app/files/tweaks/config/androidautohud/check-usb.sh b/app/files/tweaks/cmu-autorun/sdcard/headunit/check-usb.sh similarity index 64% rename from app/files/tweaks/config/androidautohud/check-usb.sh rename to app/files/tweaks/cmu-autorun/sdcard/headunit/check-usb.sh index d195764..f0ede23 100644 --- a/app/files/tweaks/config/androidautohud/check-usb.sh +++ b/app/files/tweaks/cmu-autorun/sdcard/headunit/check-usb.sh @@ -1,8 +1,8 @@ #!/bin/sh -#sleep 20 +LIST="/tmp/root/.aa/usb-allow.list" -LIST="/tmp/mnt/data_persist/dev/bin/usb-allow.list" +DEBUG=0 while [ true ]; do while IFS='' read -r line || [[ -n "$line" ]]; do @@ -13,15 +13,18 @@ while IFS='' read -r line || [[ -n "$line" ]]; do done < "$LIST" if [ $count -gt 0 ]; then - echo "USB Connected" + [ $DEBUG -eq 1 ] && echo "USB Connected" if ! [ -e /tmp/root/usb_connect ]; then touch /tmp/root/usb_connect fi else - echo "USB disconnect" + [ $DEBUG -eq 1 ] && echo "USB disconnect" if [ -e /tmp/root/usb_connect ]; then rm -f /tmp/root/usb_connect fi fi -sleep 2 +RAND=`expr $RANDOM % 4` +[ $DEBUG -eq 1 ] && echo "go sleep $RAND" +sleep $RAND + done diff --git a/app/files/tweaks/config/androidautowifi/headunit b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit similarity index 99% rename from app/files/tweaks/config/androidautowifi/headunit rename to app/files/tweaks/cmu-autorun/sdcard/headunit/headunit index bfba7ba..5fc1cda 100644 Binary files a/app/files/tweaks/config/androidautowifi/headunit and b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit-wrapper.start b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit-wrapper.start new file mode 100644 index 0000000..dfae3fd --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit-wrapper.start @@ -0,0 +1,113 @@ +#!/bin/sh + +SCRIPT="/tmp/root/.aa/headunit" +SCRIPTPATH="/tmp/root/.aa" +LOGPATH=/tmp/root/headunit.log + +export LD_LIBRARY_PATH="${SCRIPTPATH}/headunit_libs:/jci/lib:/jci/opera/3rdpartylibs/freetype:/usr/lib/imx-mm/audio-codec:/usr/lib/imx-mm/parser" + #override some GST plugins with these +export GST_PLUGIN_PATH="/usr/lib/gstreamer-0.10/:${SCRIPTPATH}/headunit_libs" + +DEBUG=0 + +# Testing this: +[ $DEBUG -eq 1 ] && sysctl -a | grep "mem" 2>&1 >> ${LOGPATH} +[ $DEBUG -eq 1 ] && echo "****************************" >> ${LOGPATH} + +echo 41943040 > /proc/sys/net/core/rmem_max +echo 41943040 > /proc/sys/net/core/wmem_max +echo 17825792 > /proc/sys/net/core/rmem_default +echo 17825792 > /proc/sys/net/core/wmem_default +echo 4096 17825792 41943040 > /proc/sys/net/ipv4/tcp_rmem +echo 4096 17825792 41943040 > /proc/sys/net/ipv4/tcp_wmem +# echo 4096 17825792 41943040 > /proc/sys/net/ipv4/tcp_mem + +[ $DEBUG -eq 1 ] && echo "sysctl -a | grep mem" >> ${LOGPATH} +[ $DEBUG -eq 1 ] && sysctl -a | grep "mem" >> ${LOGPATH} 2>&1 +[ $DEBUG -eq 1 ] && echo "****************************" >> ${LOGPATH} +hwclock --hctosys +[ $DEBUG -eq 1 ] && echo "START HEADUNIT LOG - $(date +'%D %T')" >> ${LOGPATH} + +if ! [ -e /tmp/root/headunit.json ]; then + cp "${SCRIPTPATH}/headunit.json" /tmp/root/ +fi + +start_headunit() +{ + rm -f /tmp/root/headunit-wireless.status + sed -i 's."wifiTransport": true."wifiTransport": false.g' /tmp/root/headunit.json + taskset 0xFFFFFFFF "${SCRIPTPATH}/headunit" "$@" > /dev/null 2>&1 & + sleep 2 + touch /tmp/root/headunit.status + [ $DEBUG -eq 1 ] && echo "=== headunit-usb ===" + [ $DEBUG -eq 1 ] && cat /tmp/root/headunit.json >> ${LOGPATH} + [ $DEBUG -eq 1 ] && echo "====================" +} + +start_AAwireless() +{ + rm -f /tmp/root/headunit.status + sed -i 's."wifiTransport": false."wifiTransport": true.g' /tmp/root/headunit.json + taskset 0xFFFFFFFF "${SCRIPTPATH}/headunit" "$@" > /dev/null 2>&1 & + sleep 2 + touch /tmp/root/headunit-wireless.status + [ $DEBUG -eq 1 ] && echo "=== headunit-wifi ===" + [ $DEBUG -eq 1 ] && cat /tmp/root/headunit.json >> ${LOGPATH} + [ $DEBUG -eq 1 ] && echo "====================" +} + +rm -f /tmp/root/headunit.status /tmp/root/headunit-wireless.status + +# prevent conflict by Official AA and CP +killall -q -9 aap_service carplayd L_jciCARPLAY L_jciAAPA + +#default USB +start_headunit + +# loop forever. every 5 seconds, +while true +do + NET_CHECK=`netstat -rn|awk '$2=="192.168.43.1" {print}'|wc -l|awk '{print $1}'` + + if [ -e /tmp/root/usb_connect ]; then + USBCHECK=1 + [ $DEBUG -eq 1 ] && echo "USB attach" >> ${LOGPATH} + else + USBCHECK=0 + [ $DEBUG -eq 1 ] && echo "USB detach" >> ${LOGPATH} + fi + + if [ $NET_CHECK == 1 ] && [ $USBCHECK == 0 ]; then + [ $DEBUG -eq 1 ] && echo "WLAN Mode" >> ${LOGPATH} + if [ -e /tmp/root/headunit.status ]; then + killall -q headunit + fi + + if ! [ -e /tmp/root/headunit-wireless.status ]; then + [ $DEBUG -eq 1 ] && echo "Start WIRELESS" >> ${LOGPATH} + start_AAwireless + fi + + else + #echo "USB" + [ $DEBUG -eq 1 ] && echo "USB Mode" >> /tmp/root/headunit.log + check_headunit=`ps|grep 'bin/headunit'|grep -v wrapper|grep -v grep|wc -l|awk '{print $1}'` + [ $DEBUG -eq 1 ] && echo "check_headunit = $check_headunit" >> ${LOGPATH} + + [ $check_headunit -eq 0 ] && rm -f /tmp/root/headunit-wireless.status /tmp/root/headunit.status + + if [ -e /tmp/root/headunit-wireless.status ]; then + killall -q headunit + fi + if ! [ -e /tmp/root/headunit.status ]; then + [ $DEBUG -eq 1 ] && echo "Start USB" >> ${LOGPATH} + start_headunit + fi + fi + + # Performance issue when $RANDOM=0 many times in a row + RAND=`expr $RANDOM % 5 + 3` + echo "go sleep $RAND" + sleep $RAND + +done diff --git a/app/files/tweaks/config/androidautohud/headunit.json b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit.json similarity index 100% rename from app/files/tweaks/config/androidautohud/headunit.json rename to app/files/tweaks/cmu-autorun/sdcard/headunit/headunit.json diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libgsth264parse.so b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libgsth264parse.so new file mode 100644 index 0000000..1f0f1ee Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libgsth264parse.so differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libmfw_gst_isink.so b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libmfw_gst_isink.so new file mode 100644 index 0000000..0d64cb5 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libmfw_gst_isink.so differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so new file mode 100644 index 0000000..53ee4d8 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so.8 b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so.8 new file mode 100644 index 0000000..53ee4d8 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so.8 differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so.8.0.1 b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so.8.0.1 new file mode 100644 index 0000000..53ee4d8 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/headunit/headunit_libs/libunwind.so.8.0.1 differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/run.sh b/app/files/tweaks/cmu-autorun/sdcard/headunit/run.sh new file mode 100644 index 0000000..82910cd --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/headunit/run.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +VERSION=1.3 +MYDIR=$(dirname "$(readlink -f "$0")") +SCRIPTPATH=${MYDIR} +ROOT=/tmp/root/.aa + + +conf='{ + "launchOnDevice": true, + "carGPS": true, + "wifiTransport": false, + "reverseGPS": false +}' + +if ! [ -e /tmp/root/headunit.json ]; then + printf "%s" "$conf" > /tmp/root/headunit.json +fi + + +log_message() +{ + mount -o rw,remount ${MYDIR} + echo "$*" 1>&2 + echo "$*" >> "${MYDIR}/AIO_log.txt" + /bin/fsync "${MYDIR}/AIO_log.txt" + mount -o ro,remount ${MYDIR} +} + +show_message() +{ + sleep 5 + killall jci-dialog + /jci/tools/jci-dialog --info --title="MESSAGE" --text="$*" --no-cancel & +} + +mount -o rw,remount ${MYDIR} +mkdir -p ${ROOT} +cp -a ${MYDIR}/* ${ROOT} + +chmod 755 ${ROOT}/headunit +chmod 755 ${ROOT}/headunit_libs/libgsth264parse.so +chmod 755 ${ROOT}/headunit_libs/libmfw_gst_isink.so +mount -o ro,remount ${MYDIR} + +cd ${ROOT} +pkill check-usb.sh +nohup ./check-usb.sh >/dev/null 2>&1 & +sleep 1 + +show_message "CMU-AUTORUN: Start autorun-headunit-${VERSION} USB/WIFI" +sleep 4 +killall jci-dialog + +nohup ./headunit-wrapper.start >/dev/null 2>&1 & + diff --git a/app/files/tweaks/cmu-autorun/sdcard/headunit/usb-allow.list b/app/files/tweaks/cmu-autorun/sdcard/headunit/usb-allow.list new file mode 100644 index 0000000..67f54b8 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/headunit/usb-allow.list @@ -0,0 +1,2 @@ +18d1:2d00 +2717:ff40 diff --git a/app/files/tweaks/cmu-autorun/sdcard/memory-log/README.md b/app/files/tweaks/cmu-autorun/sdcard/memory-log/README.md new file mode 100644 index 0000000..55e3d5b --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/memory-log/README.md @@ -0,0 +1,7 @@ +# Memory Log +### Logs swap details & memory usage + +* Starts 60 seconds after the autorun script is executed +* Log file location 'memLog/memory.log' +* Log entry once every 60 seconds +* Logs swap usage (/proc/swaps) and memory info (/proc/meminfo) \ No newline at end of file diff --git a/app/files/tweaks/cmu-autorun/sdcard/memory-log/memLog/monitor.sh b/app/files/tweaks/cmu-autorun/sdcard/memory-log/memLog/monitor.sh new file mode 100644 index 0000000..ba0679f --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/memory-log/memLog/monitor.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# Momory Monitor Log - 20 entries, 60 seconds apart +MYDIR=$(dirname "$(readlink -f "$0")") +LOGFILE="${MYDIR}/memory.log" +# rm -f "${LOGFILE}" +echo "**** START MEMORY LOG - ${timestamp} ****" >> "${LOGFILE}" +sleep 60 +for i in $(seq 1 20) +do + sleep 60 + timestamp=$(date +%s) + echo "********* LOG - ${timestamp} ********" >> "${LOGFILE}" + cat /proc/swaps >> "${LOGFILE}" + cat /proc/meminfo >> "${LOGFILE}" +done +exit diff --git a/app/files/tweaks/cmu-autorun/sdcard/memory-log/run.sh b/app/files/tweaks/cmu-autorun/sdcard/memory-log/run.sh new file mode 100644 index 0000000..c0aefe1 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/memory-log/run.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# Disable watchdog +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +mount -o rw,remount / +# Set environment +DIR=$(dirname $(readlink -f $0)) + +sh ${DIR}/memLog/monitor.sh & + diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-adb/ssh-over-adb.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-adb/ssh-over-adb.sh new file mode 100644 index 0000000..36296a5 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-adb/ssh-over-adb.sh @@ -0,0 +1,23 @@ +#!/bin/sh +if ! which adb > /dev/null; then + echo "adb not found~!" + exit 1 +fi + +adb start-server + +echo "wait adb device" +adb wait-for-device +echo "adb device presents, reverse porting ssh on port 2222" +adb reverse tcp:2222 tcp:22 +while [ true ] +do + if [ "$(adb get-state)" = "device" ]; then + sleep 5 + else + sleep 1 + echo "adb disconnected" + break + fi +done +exit 0 diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-adb/start-adb-ssh.autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-adb/start-adb-ssh.autorun new file mode 100644 index 0000000..914afde --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-adb/start-adb-ssh.autorun @@ -0,0 +1,6 @@ +#!/bin/sh + +# Run in the background, watch for Android device +if which adb > /dev/null 2>&1; then + watch `dirname $0`/ssh-over-adb.sh & +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-wifiAP/jci-wifiap.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-wifiAP/jci-wifiap.sh new file mode 100644 index 0000000..aae7e7a --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-wifiAP/jci-wifiap.sh @@ -0,0 +1,215 @@ +#!/bin/sh + +#include variables from config file +. `dirname $0`/wifiAP.config + +#channel: 9 +#mode: only G +#WPA2 Personal + AES (no tkip) + +NETWORK_INTERFACE_NAME=wlan0 +NETWORK_DRIVER_NAME=nl80211 + +HOSTAPD_CONF_FILE=/tmp/current-session-hostapd.conf +UDHCPD_CONF_FILE=/tmp/current-session-udhcpd.conf + +DHCP_DEAMON=udhcpd +WIFI_AP_DEAMON=hostapd + +NETWORK_IP_ADDRESS=192.168.53.1 +NETWORK_MASK=255.255.255.0 +DHCP_START_ADDRESS=192.168.53.20 +DHCP_END_ADDRESS=192.168.53.254 + +#configures interface +configure_interface() +{ + ifconfig $NETWORK_INTERFACE_NAME $NETWORK_IP_ADDRESS netmask $NETWORK_MASK +} + +# create the 'hostapd.conf' +create_wifi_ap_configuration() +{ + # obtain the MAC address + MAC_ADDRESS=`ifconfig | grep "$NETWORK_INTERFACE_NAME" | awk '{print $5}'` + + # create the file + echo 'interface='$NETWORK_INTERFACE_NAME'' > $HOSTAPD_CONF_FILE + echo 'driver='$NETWORK_DRIVER_NAME'' >> $HOSTAPD_CONF_FILE + echo 'channel=9' >> $HOSTAPD_CONF_FILE + echo 'hw_mode=g' >> $HOSTAPD_CONF_FILE + echo 'wpa=2' >> $HOSTAPD_CONF_FILE + echo 'auth_algs=1' >> $HOSTAPD_CONF_FILE + echo 'wpa_key_mgmt=WPA-PSK' >> $HOSTAPD_CONF_FILE + echo 'wpa_passphrase='$NETWORK_WIFI_PASSWORD'' >> $HOSTAPD_CONF_FILE + echo 'rsn_pairwise=CCMP' >> $HOSTAPD_CONF_FILE + echo 'ssid='$NETWORK_WIFI_SSID'' >> $HOSTAPD_CONF_FILE +# echo 'ssid=CMU-'$MAC_ADDRESS'' >> $HOSTAPD_CONF_FILE +} + +#create the 'udhcpd.conf' +create_dhcp_confifuration() +{ + # create the file + echo '# The start and end of the IP lease block' > $UDHCPD_CONF_FILE + echo 'start '$DHCP_START_ADDRESS' #default: 192.168.0.20' >> $UDHCPD_CONF_FILE + echo 'end '$DHCP_END_ADDRESS' #default: 192.168.0.254' >> $UDHCPD_CONF_FILE + echo ''>>$UDHCPD_CONF_FILE + echo '# The interface that udhcpd will use' >> $UDHCPD_CONF_FILE + echo 'interface '$NETWORK_INTERFACE_NAME' #default: eth0' >> $UDHCPD_CONF_FILE + echo '' >> $UDHCPD_CONF_FILE + echo '#JCI configuration' >> $UDHCPD_CONF_FILE + echo 'opt dns 192.168.0.1' >> $UDHCPD_CONF_FILE + echo 'option subnet '$NETWORK_MASK'' >> $UDHCPD_CONF_FILE + echo 'opt router '$NETWORK_IP_ADDRESS'' >> $UDHCPD_CONF_FILE + echo 'option lease 864000 # 10 days of seconds' >> $UDHCPD_CONF_FILE +} + +# Start DHCP deamon +start_dhcp_deamon() +{ + DHCPD_PID=$(pidof $DHCP_DEAMON) + if [ "$DHCPD_PID" == "" ] ; then + create_dhcp_confifuration + $DHCP_DEAMON $UDHCPD_CONF_FILE & + sleep 2 + get_dhcp_status + else + echo "DHCP deamon already started." + fi +} + +# start WiFi AP deamon +start_wifi_ap_deamon() +{ + AP_DEAMON_PID=$(pidof $WIFI_AP_DEAMON) + if [ "$AP_DEAMON_PID" == "" ] ; then + create_wifi_ap_configuration + $WIFI_AP_DEAMON -dd $HOSTAPD_CONF_FILE & # '-dd' provides extra debug information + sleep 2 + get_wifi_ap_status + else + echo "WiFi AP mode already active." + fi + +} + +# stop DHCP +stop_dhcp_deamon() +{ + DHCPD_PID=$(pidof $DHCP_DEAMON) + if [ "$DHCPD_PID" == "" ] ; then + echo "DHCP deamon already stopped" + else + kill $DHCPD_PID + sleep 2 + get_dhcp_status + fi +} + +# stop WiFi AP deamon +stop_wifi_ap_deamon() +{ + AP_DEAMON_PID=$(pidof $WIFI_AP_DEAMON) + if [ "$AP_DEAMON_PID" == "" ] ; then + echo "AP deamon already stopped" + else + kill $AP_DEAMON_PID + sleep 2 + get_wifi_ap_status + fi +} + +#get WiFi status +get_wifi_ap_status() +{ + AP_DEAMON_PID=$(pidof $WIFI_AP_DEAMON) + if [ "$AP_DEAMON_PID" == "" ] ; then + echo "WiFi AP mode : stopped" + else + echo "WiFi AP mode : started" + fi +} + +# get DHCP status +get_dhcp_status() +{ + DHCPD_PID=$(pidof $DHCP_DEAMON) + if [ "$DHCPD_PID" == "" ] ; then + echo "DHCP : stopped" + else + echo "DHCP : started" + fi +} + +display_usage() +{ + echo "JCI WiFi Access Point control script." + echo "" + echo "Usage:" + echo -e "\t$0 [ ...]" + echo -e "\t$0 help" +} + +display_help() +{ + echo "JCI WiFi Access Point control script." + echo "" + echo "Usage:" + echo -e "\t$0 ]" + echo "" + echo "Commands:" + echo -e "\tstatus - display current status." + echo -e "\tstart - start logging daemon" + echo -e "\tstop - stop logging daemon" + echo -e "\trestart - restart logging daemon" + echo -e "\thelp - display this help screen" +} + + +CMD="$1" +#shift + +if [ "$CMD" == "" ] ; then + display_usage + exit 1 +fi + +case "$CMD" in + status) + get_wifi_ap_status + get_dhcp_status + ;; + + start) + configure_interface + start_dhcp_deamon + start_wifi_ap_deamon + ;; + + stop) + stop_dhcp_deamon + stop_wifi_ap_deamon + ;; + + restart) + stop_dhcp_deamon + stop_wifi_ap_deamon + sleep 1 + configure_interface + start_dhcp_deamon + start_wifi_ap_deamon + ;; + + help) + display_help + ;; + + *) + echo -e "ERROR: Unknown command.\n" + display_usage + exit 2 + ;; +esac + +exit 0 diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-wifiAP/start-WiFi-AP.autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-wifiAP/start-WiFi-AP.autorun new file mode 100644 index 0000000..d08ad5c --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/02-start-wifiAP/start-WiFi-AP.autorun @@ -0,0 +1,11 @@ +#!/bin/sh +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +dos2unix `dirname $0`/wifiAP.config +. `dirname $0`/wifiAP.config +if [ $NETWORK_WIFI_PASSWORD == "YourSSIDpassword" ]; then + /jci/tools/jci-dialog --info --title="WiFi AP NOT started!" --text="Modify default password in wifiAP.config" --no-cancel & +else + #/jci/tools/jci-dialog --info --title="WiFi AP" --text="Started" --no-cancel & + /bin/sh /jci/scripts/start_wifi.sh >/dev/null + /bin/sh `dirname $0`/jci-wifiap.sh start >/dev/null +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/adb b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/adb new file mode 100644 index 0000000..2f98fe4 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/recovery-extra/adb differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/99-run-tweaks.rules b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/99-run-tweaks.rules new file mode 100644 index 0000000..714b18a --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/99-run-tweaks.rules @@ -0,0 +1 @@ +ACTION=="add",KERNEL=="sd[abcdef]*", RUN+="/bin/sh /tmp/mnt/data_persist/dev/bin/02-run-tweaks-from-usb/udev_add_action_handler.sh %k" diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/README.md b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/README.md new file mode 100644 index 0000000..4d02e6b --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/README.md @@ -0,0 +1,24 @@ +# Install udev handler for tweaks installer + +##### install-udev-handler-if-not-installed.autorun: +- this script install a callback function "99-run-tweaks.rules" in /etc/udev/rules.d to run a script whern usb storage inserted +- if this script is installed not do anything + +##### /etc/udev/rules.d/99-run-tweaks.rules: +- run "udev_add_action_handler.sh" when usb storage is inserted, got a paramenter sda, sdb,... + +##### udev_add_action_handler.sh: +- is executed for every inserted usb storage by /etc/udev/rules.d/99-run-tweaks.rules +- this script run "run-tweak-from-usb.sh" in background and return +- the system finish installing usb storage and mounting it +- on CMU apear "USB storage connected" + +##### "run-tweak-from-usb.sh": +- wait 2sec to system finish mounting the usb storage +- search the usb storage for "dataRetrieval_config.txt" +- search it for "CMD_LINE=[script]" lines +- if found execute [script] + +****** *__WARNING__* ***** +*jcidialog not working if executed by this script +__BUT the script is executed ! (copy/modify files,...)__* diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/_readme.txt b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/_readme.txt new file mode 100644 index 0000000..bb47f49 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/_readme.txt @@ -0,0 +1,23 @@ + +install-udev-handler-if-not-installed.autorun: +this script install a callback function "99-run-tweaks.rules" in /etc/udev/rules.d to run a script whern usb storage inserted +if this script is installed not do anything + +/etc/udev/rules.d/99-run-tweaks.rules: +run "udev_add_action_handler.sh" when usb storage is inserted, got a paramenter sda, sdb,... + +udev_add_action_handler.sh: +is executed for every inserted usb storage by /etc/udev/rules.d/99-run-tweaks.rules +-this script run "run-tweak-from-usb.sh" in background and return +-the system finish installing usb storage and mounting it +-on CMU apear "USB storage connected" + +"run-tweak-from-usb.sh": +-wait 2sec to system finish mounting the usb storage +-search the usb storage for "dataRetrieval_config.txt" +-search it for "CMD_LINE=[script]" lines +-if found execute [script] + +****** WARNING ***** +jcidialog not working if executed by this script +BUT the script is executed ! (copy/modify files,...) diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/install-udev-handler-if-not-installed.autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/install-udev-handler-if-not-installed.autorun new file mode 100644 index 0000000..bb4793d --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/install-udev-handler-if-not-installed.autorun @@ -0,0 +1,41 @@ +#!/bin/sh +_VER=$(grep "^JCI_SW_VER=" /jci/version.ini | sed 's/^.*_\([^_]*\)\"$/\1/' | cut -d '.' -f 1) +_VER_EXT=$(grep "^JCI_SW_VER=" /jci/version.ini | sed 's/^.*_\([^_]*\)\"$/\1/' | cut -d '.' -f 3) +NEED_UPDATE=0 +if [ $_VER -gt 59 ] || ( [ $_VER -eq 59 ] && [ $_VER_EXT -gt 500 ] ); then + + FileName="99-run-tweaks.rules" + DestinationPath="/etc/udev/rules.d/" + if [ ! -d $DestinationPath ]; then + if [ ! -e /mnt/a ]; then + echo "Mounting Root File System..." + mkdir -p /mnt/a + mount /dev/ffx01p1 /mnt/a + fi + DestinationPath=/mnt/a/$DestinationPath + fi + + SrcPath=`dirname $0` + SrcFileName=$SrcPath/$FileName + DstFileName=$DestinationPath/$FileName + + if [ -f $DstFileName ]; then + MD5Src=`/usr/bin/md5sum $SrcFileName | /usr/bin/awk '{print $1}'` + MD5Dst=`/usr/bin/md5sum $DstFileName | /usr/bin/awk '{print $1}'` + if [ "$MD5Src" != "$MD5Dst" ]; then + NEED_UPDATE=1 + fi + else + NEED_UPDATE=1 + fi + + if [ $NEED_UPDATE == 1 ]; then + /bin/mount -o rw,remount / + /bin/cp "$SrcFileName" "$DstFileName" + /bin/chown 1018:3015 "$DstFileName" + sync + /bin/mount -o ro,remount / + fi + + watch -n 5 /bin/sh $SrcPath/watch-if-something-need-to-be-executed.sh >/dev/null 2>&1 & +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/run-tweak-from-usb.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/run-tweak-from-usb.sh new file mode 100644 index 0000000..16f5101 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/run-tweak-from-usb.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +sleep 3 + +RUN=0 +if [ -f `dirname $0`/usb-serial.config ]; then + ID=`dirname $0`/usb-serial.config + if [ `cat $ID` == `udevadm info -q all -n /dev/$1 | grep "ID_SERIAL=" | awk -F = '{print $2}'` ]; then + RUN=1 + else + echo "/jci/tools/jci-dialog --info --title='NOT ALLOWED $1' --text='Executing of autorun scripts from this drive are not allowed' --no-cancel \& " >/tmp/mnt/data_persist/dev/bin/02-run-tweaks-from-usb/run-this + fi +else + RUN=1 +fi + +if [ $RUN == 1 ]; then + grep CMD_LINE= /tmp/mnt/$1/dataRetrieval_config.txt 2>/dev/null | awk -F = '{print $2}' | dos2unix >/tmp/mnt/data_persist/dev/bin/02-run-tweaks-from-usb/run-this + if [ -s /tmp/mnt/data_persist/dev/bin/02-run-tweaks-from-usb/run-this ]; then + /bin/mount -o rw,remount /tmp/mnt/$1 + udevadm info -q all -n /dev/$1 | grep "ID_SERIAL=" | awk -F = '{print $2}' >/tmp/mnt/$1/usb-serial.config + sync + fi +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/udev_add_action_handler.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/udev_add_action_handler.sh new file mode 100644 index 0000000..d29037b --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/udev_add_action_handler.sh @@ -0,0 +1,2 @@ +#!/bin/sh +/bin/sh `dirname $0`/run-tweak-from-usb.sh $1 & diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/watch-if-something-need-to-be-executed.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/watch-if-something-need-to-be-executed.sh new file mode 100644 index 0000000..1bd0332 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-run-tweaks-from-usb/watch-if-something-need-to-be-executed.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -f `dirname $0`/run-this ]; then + mv `dirname $0`/run-this `dirname $0`/run-this.sh + /bin/sh `dirname $0`/run-this.sh >/dev/null 2>&1 + rm -f `dirname $0`/run-this.sh +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/README.md b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/README.md new file mode 100644 index 0000000..0d02d33 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/README.md @@ -0,0 +1,16 @@ +# Open firewall & Start sshd + +### this script runs a new sshd server on port 24000 and openup firewall on eth and wifi + +##### start-sshd-and-open-firewall.autorun: +- this script run "start_fw_in_background" in background because we need to openup the firewall two times with 90 sec difference + +##### start_fw_in_background: +- start a new sshd config with our config file with modified settings: accept password auth, port 24000 (original sshd is on 36000 and not acceptd password auth) +- "sshd_config" is a modified copy of /etc/ssh/sshd_config + +##### "jci-fw.sh": +- open up firewall for tcp port 24000,36000 and icmp on eth and wifi +- wait 90sec +- CMUs start his firewall and close opened ports +- run "jci-fw.sh" again to open the firewall diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/_readme.txt b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/_readme.txt new file mode 100644 index 0000000..cf21927 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/_readme.txt @@ -0,0 +1,14 @@ +this script run a new sshd server on port 24000 and openup firewall on eth and wifi + +start-sshd-and-open-firewall.autorun: +this script run "start_fw_in_background" in background because we need to openup the firewall two times with 90 sec difference + +start_fw_in_background: +start a new sshd config with our config file "sshd_config" from this dir with modified settings: accept password auth, port 24000 (original sshd is on 36000 and not acceptd password auth) +"sshd_config" is a modified copy of /etc/ssh/sshd_config + +"jci-fw.sh": +open up firewall for tcp port 24000,36000 and icmp on eth and wifi +wait 90sec +CMUs start his firewall and close opened ports +run "jci-fw.sh" again to open again the firewall diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/jci-fw.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/jci-fw.sh new file mode 100644 index 0000000..d560ad4 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/jci-fw.sh @@ -0,0 +1,170 @@ +#!/bin/sh + +# +# JCI firewall control script. +# +# $Archive$ +# $Author$ +# $Date$ +# $Modtime$ +# $Revision$ +# $Workfile +# +# (C) Johnson Controls, Inc. +# + + +LOG_TAG=FW +IPTABLES=/usr/sbin/iptables + + +log() +{ + local MSG="$1" + logger -s -t FW "$MSG" +} + + +display_usage() +{ + echo "JCI firewall control script." + echo "" + echo "Usage:" + echo -e "\t$1 " + echo -e "\t$1 help" +} + + +display_help() +{ + echo "JCI firewall control script." + echo "" + echo "Usage:" + echo -e "\t$1 " + echo "" + echo "Commands:" + echo -e "\tstatus - display current status and configuration." + echo -e "\tstart - start the firewall" + echo -e "\tstop - stop the firewall" + echo -e "\trestart - restart the firewall" + echo "" + echo -e "\thelp - display this help screen" +} + + +do_status() +{ + $IPTABLES -L -n -v --line-numbers +} + + +do_start() +{ + # load modules explicitly as otherwise it takes about 2 seconds for modprobe to resolve... + insmod /lib/modules/3.0.35/kernel/net/netfilter/x_tables.ko + insmod /lib/modules/3.0.35/kernel/net/ipv4/netfilter/ip_tables.ko + insmod /lib/modules/3.0.35/kernel/net/ipv4/netfilter/iptable_filter.ko + insmod /lib/modules/3.0.35/kernel/net/netfilter/nf_conntrack.ko + insmod /lib/modules/3.0.35/kernel/net/netfilter/xt_state.ko + insmod /lib/modules/3.0.35/kernel/net/ipv4/netfilter/nf_defrag_ipv4.ko + insmod /lib/modules/3.0.35/kernel/net/ipv4/netfilter/nf_conntrack_ipv4.ko + insmod /lib/modules/3.0.35/kernel/net/netfilter/xt_tcpudp.ko + insmod /lib/modules/3.0.35/kernel/net/netfilter/xt_limit.ko + + $IPTABLES -F + $IPTABLES -X + + # Accept anything on the loopback interface + $IPTABLES -A INPUT -i lo -j ACCEPT + $IPTABLES -A OUTPUT -o lo -j ACCEPT + + # Set Default Chain Policies (Reject all incoming and allow all outgoing packets) + $IPTABLES -P INPUT DROP + $IPTABLES -P OUTPUT ACCEPT + $IPTABLES -P FORWARD DROP + + # Drop any invalid packets + $IPTABLES -A INPUT -m state --state INVALID -j DROP + $IPTABLES -A OUTPUT -m state --state INVALID -j DROP + + # Accept incoming packets on already esablished connections + $IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + + # Allow incoming SSH connections on any interface but wlan0 + # Note that iptables with kernel 2.4/2.6 allows for a filter rule based upon + # different connection states (NEW, ESTABLISHED, RELATED, INVALID). + #$IPTABLES -A INPUT -p tcp -i wlan0 --dport 36000 -m state --state NEW,ESTABLISHED -j DROP + $IPTABLES -A INPUT -p tcp -m multiport --destination-ports 22,24000,36000 -m state --state NEW,ESTABLISHED -j ACCEPT + + # Allow incoming DHCP packets on wlan0 interface + $IPTABLES -A INPUT -p udp -i wlan0 --sport 68 --dport 67 -j ACCEPT + $IPTABLES -A INPUT -p tcp -i wlan0 --sport 68 --dport 67 -j ACCEPT + + # Allow incoming DNS packets on the wlan0 interface + $IPTABLES -A INPUT -p udp -i wlan0 --dport 53 -m state --state NEW -j ACCEPT + $IPTABLES -A INPUT -p tcp -i wlan0 --dport 53 -m state --state NEW -j ACCEPT + + # Allow incoming ICMP echo and trace + # To prevent DoS attacks, limit responses to x per second + $IPTABLES -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT + + # Disable ICMP services CI-2952 + #$IPTABLES -A INPUT -p icmp -icmp-type echo-request -j DROP + + # KGT: Reject nicely anything else + #$IPTABLES -A INPUT -p tcp -j REJECT --reject-with tcp-reset + #$IPTABLES -A INPUT -j REJECT --reject-with icmp-port-unreachable +} + + +do_stop() +{ + log 'Stopping firewall...' + + # Accept all incoming and outgoing packets + $IPTABLES -F + $IPTABLES -X + $IPTABLES -P INPUT ACCEPT + $IPTABLES -P OUTPUT ACCEPT + $IPTABLES -P FORWARD ACCEPT +} + + +CMD="$1" +shift + +if [ "$CMD" == "" ] ; then + display_usage "$0" + exit 0 +fi + +case "$CMD" in + status) + do_status $* + ;; + + start) + do_start $* + ;; + + stop) + do_stop $* + ;; + + restart) + do_stop + do_start + ;; + + help) + display_help "$0" + ;; + + *) + echo -e "ERROR: Unknown command.\n" + display_usage "$0" + exit 1 + ;; +esac + +exit 0 diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/sshd_config b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/sshd_config new file mode 100644 index 0000000..f1989e6 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/sshd_config @@ -0,0 +1,120 @@ +# Trezdog44_restored $OpenBSD: sshd_config,v 1.90 2017/07/11 04:20:00 pst Exp $ +# Restore SSH access over multiple ports +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options change a +# open ssh ports +Port 22 +Port 24000 +Port 36000 +AddressFamily inet +ListenAddress 0.0.0.0 +#ListenAddress :: + +# Disable legacy (protocol version 1) support in the server for new +# installations. In future the default will change to require explicit +# activation of protocol 1 +Protocol 2 + +# HostKey for protocol version 1 +#HostKey /etc/ssh/ssh_host_key +# HostKeys for protocol version 2 +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_dsa_key + +# Lifetime and size of ephemeral version 1 server key +#KeyRegenerationInterval 1h +#ServerKeyBits 1024 + +# Logging +# obsoletes QuietMode and FascistLogging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin yes +StrictModes no +#MaxAuthTries 6 +#MaxSessions 10 + +#RSAAuthentication yes +#PubkeyAuthentication yes +#AuthorizedKeysFile .ssh/authorized_keys + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#RhostsRSAAuthentication no +# similar for protocol version 2 +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# RhostsRSAAuthentication and HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +PasswordAuthentication yes +PermitEmptyPasswords yes + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +#UsePAM no + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +UsePrivilegeSeparation no +#PermitUserEnvironment no +Compression no +ClientAliveInterval 15 +ClientAliveCountMax 4 +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10 +#PermitTunnel no +#ChrootDirectory none + +# no default banner path +#Banner /config-mfg/fgsn.dat + +# override default of no subsystems +Subsystem sftp /usr/libexec/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# ForceCommand cvs server diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/start-sshd-and-open-firewall.autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/start-sshd-and-open-firewall.autorun new file mode 100644 index 0000000..a36b18b --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/start-sshd-and-open-firewall.autorun @@ -0,0 +1,3 @@ +#!/bin/sh +#start startup script in background (bacause script need over 100sec to run) +/bin/sh `dirname $0`/start_fw_in_background & diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/start_fw_in_background b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/start_fw_in_background new file mode 100644 index 0000000..13e447f --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-start-sshd-and-open-firewall/start_fw_in_background @@ -0,0 +1,20 @@ +#!/bin/sh +echo 1 > /sys/class/gpio/Watchdog\ Disable/value + +# sshd_config is fixed +# /usr/sbin/sshd -f `dirname $0`/sshd_config + +DIR=$(dirname "$(readlink -f "$0")") + +if [ -f /jci/scripts/jci-fw.sh ] && ! grep -Fq "multiport" /jci/scripts/jci-fw.sh +then + mount -o rw,remount / + sleep 2 + cp -a ${DIR}/jci-fw.sh /jci/scripts/ + sleep 2 + mount -o ro,remount / + sleep 60 + /bin/sh /jci/scripts/jci-fw.sh start >/dev/null +fi + +exit 0 diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/config-update.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/config-update.sh new file mode 100644 index 0000000..656cb97 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/config-update.sh @@ -0,0 +1,221 @@ +#!/bin/sh + +_mtd_name="config" +CONFIG_DEV_SIZE="0" +CONFIG_BLOCK_DEV="/dev/mtdblock5" +CONFIG_MNT="/config-mfg" +CONFIG_TMP="/tmp/configtmp" +CONFIG_IMG="/tmp/config-squash.img" + +find_mtd_by_name() +{ + echo "Looking for MTD partition named $1" + CONFIG_MTD=$(find /sys/class/mtd -follow -maxdepth 2 -path '/sys/class/mtd/mtd[[:digit:]+]/name' | xargs grep ^$1$) + if [[ -n "$CONFIG_MTD" ]]; then + #echo "CONFIG_MTD: $CONFIG_MTD" + CONFIG_MTD=${CONFIG_MTD%%/name*} + if [[ -n "$CONFIG_MTD" ]]; then + #echo "CONFIG_MTD: $CONFIG_MTD" + CONFIG_MTD=${CONFIG_MTD##*/} + echo "CONFIG_MTD: $CONFIG_MTD" + fi + fi +} + +find_mtd_by_name $_mtd_name +CONFIG_DEV=/dev/$CONFIG_MTD + +# BEFORE WE DO ANYTHING, $CONFIG_DEV should be writable; i.e. not read-only. +# get CONFIG_DEV writable status +res="`mtdinfo $CONFIG_DEV | grep writable | grep -o false`" +if [ "$res" == "false" ]; then + echo "error: $CONFIG_DEV must be writable -- it is not!" + exit 1 +fi + +# get CONFIG_DEV size +res="`cat /sys/class/mtd/$CONFIG_MTD/size`" +if [ "$?" == "0" ]; then + CONFIG_DEV_SIZE="$res" + echo "size of $CONFIG_DEV is $CONFIG_DEV_SIZE bytes" +else + echo "error: could not get size of $CONFIG_DEV" + exit 1 +fi + + +# +# function: is_squash_mount +# desc: verifies if the specified path is a squash mount +# +is_squash_mount() { + + local _mount_path="$1" + + if [ ! -d "$_mount_path" ]; then + return 0 + fi + + res="`mount | grep $_mount_path | grep -o squashfs`" + if [ "$res" == "squashfs" ]; then + return 1 + else + return 0 + fi +} + +# +# function: unsquash +# desc: unsquashes a file system directly from a mtd device +# +copy_squashfs() { + local _squashfs_mount="$1" + local _squashfs_tmp="$2" + + if [ ! -d "$_squashfs_tmp" ]; then + mkdir $_squashfs_tmp + fi + + cp -R $_squashfs_mount/* $_squashfs_tmp + return $? +} + +# +# function: cleanup +# desc: removes all files created by `--start` +# +cleanup() { + rm $CONFIG_IMG + rm -rf $CONFIG_TMP +} + +# +# function: print_usage +# desc: exactly what it says... print the usage +# +print_usage() { + echo "$0:" + echo "--start Setup for making changes to $CONFIG_MNT SquashFS" + echo " (make changes in $CONFIG_TMP)" + echo "--commit Generates SquashFS image from $CONFIG_TMP and" + echo "--clean Removes any files generated by this script" + echo "--help Prints this help message" + echo "" + echo "example:" + echo " $ $0 --start" + echo " $ cp /src/passwd $CONFIG_TMP/etc/passwd" + echo " $ cp /src/file2 $CONFIG_TMP/etc/file2" + echo " $ cp /src/file3 $CONFIG_TMP/etc/file3" + echo " $ $0 --commit" +} + +# +# function: print_usage +# desc: run the start command to begin an update +# +cmd_start() { + # make sure we are working with a squash mount + is_squash_mount $CONFIG_MNT + if [ "$?" -eq "1" ]; then + # Copy the squashfs contents + copy_squashfs $CONFIG_MNT $CONFIG_TMP + else + # Just create the temporary directory + mkdir $CONFIG_TMP + fi +} + +# +# function: cmd_commit +# desc: commits config changes as SquashFS image +# +cmd_commit() { + + # Make sure the image doesn't exist + rm $CONFIG_IMG 2>/dev/null + + # Create the SquashFS image + echo "Generating new SquashFS image" + mksquashfs $CONFIG_TMP $CONFIG_IMG >/dev/null + if [ "$?" -ne "0" ]; then + echo "error: could not generate $CONFIG_IMG" + exit 1 + fi + + # Unmount the SquashFS + umount $CONFIG_MNT + + # make sure $CONFIG_MNT is not mounted + is_squash_mount $CONFIG_MNT + if [ "$?" -eq "1" ]; then + echo "error: could not unmount $CONFIG_MNT" + exit 1 + fi + + # Erase the current SquashFS + flash_erase $CONFIG_DEV 0 0 + if [ "$?" -ne "0" ]; then + echo "error: could not erase $CONFIG_DEV" + exit 1 + fi + + # Write the SquashFS image to the mtd config device + echo "Writing new SquashFS image" + dd if=$CONFIG_IMG of=$CONFIG_DEV 2>/dev/null + if [ "$?" -ne "0" ]; then + echo "error: could not dd $CONFIG_IMG to $CONFIG_DEV" + exit 1 + fi + + # Make sure we are all synced up + sync + + # Remount the SquashFS config-mfg + mount -t squashfs $CONFIG_BLOCK_DEV $CONFIG_MNT + if [ "$?" -ne "0" ]; then + echo "could not mount $CONFIG_MNT" + exit 1 + fi + + # Clean up after committing + # cleanup +} + +# If no arguments, print usage and exit +if [ "$#" -eq "0" ]; then + print_usage $0 + exit 0 +fi + +# Run getopt +ARGS=`getopt -l "start,commit,help,clean" -n "$0" -- "$@"` + +# Bad args +if [ "$?" -ne "0" ]; then + exit 1 +fi + +case "$1" in + --start) + cmd_start + echo "make your changes in $CONFIG_TMP" + ;; + + --commit) + cmd_commit + ;; + + --clean) + cleanup + ;; + + --help) + print_usage $0 + ;; + + *) + print_usage $0 + ;; +esac + + diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/passwd b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/passwd new file mode 100644 index 0000000..3a66ab3 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/passwd @@ -0,0 +1,6 @@ +cmu:$5$tDn5yi8Rsf8e$OeOTL/ZnIkwNgIRU8vAiZwvavRqfkAIw3pVZ5P9DYwD:0:0:root:/root:/bin/sh +jci:2bcady0EejTjI:0:0:root:/root:/bin/sh +service:x:1001:1001:Service User:/root:/bin/false +hmi:x:1002:1002:HMI User:/root:/bin/false +browser:x:1003:1003:Browser User:/root:/bin/false +user:WxKYMo36qB5CA:0:0:Linux User,,,:/tmp/user:/bin/sh diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/passwd_update.autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/passwd_update.autorun new file mode 100644 index 0000000..b4f8bf9 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-etc-passwd-if-needed/passwd_update.autorun @@ -0,0 +1,29 @@ +#!/bin/sh + +FileName="passwd" +DestinationPath="/config-mfg/" + +SrcPath=`dirname $0` +SrcFileName=$SrcPath/$FileName +DstFileName=$DestinationPath/$FileName + +NEED_UPDATE=0 +if [ -f $DstFileName ]; then + if [ -f $SrcFileName ]; then + MD5Src=`/usr/bin/md5sum $SrcFileName | /usr/bin/awk '{print $1}'` + MD5Dst=`/usr/bin/md5sum $DstFileName | /usr/bin/awk '{print $1}'` + if [ "$MD5Src" != "$MD5Dst" ]; then + NEED_UPDATE=1 + fi + fi +else + NEED_UPDATE=1 +fi + +if [ $NEED_UPDATE == 1 ]; then + if [ `df /config-mfg | grep dev | wc -l` == "1" ]; then + /bin/sh `dirname $0`/config-update.sh --start + cp $SrcFileName /tmp/configtmp/passwd + /bin/sh `dirname $0`/config-update.sh --commit + fi +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-sshd-config-if-needed/sshd_config b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-sshd-config-if-needed/sshd_config new file mode 100644 index 0000000..a50fe2f --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-sshd-config-if-needed/sshd_config @@ -0,0 +1,73 @@ +# Trezdog44_restored $OpenBSD: sshd_config,v 1.90 2017/07/11 04:20:00 pst Exp $ +# Part of the ID7_Restore Pack, Restores SSH access over multiple ports +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. +# open ssh ports +Port 22 +Port 24000 +Port 36000 +AddressFamily inet +ListenAddress 0.0.0.0 +Protocol 2 + +# HostKey for protocol version 1 +#HostKey /etc/ssh/ssh_host_key +# HostKeys for protocol version 2 +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_dsa_key + +# Lifetime and size of ephemeral version 1 server key +#KeyRegenerationInterval 1h +#ServerKeyBits 1024 + +# Logging +# obsoletes QuietMode and FascistLogging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin yes +StrictModes no +#MaxAuthTries 6 +#MaxSessions 10 + +# Allow key authentication (CI-2954) +RSAAuthentication yes +PubkeyAuthentication yes +AuthorizedKeysFile /config-mfg/authorized_keys + +# To disable tunneled clear text passwords, change to no here! +PasswordAuthentication yes +PermitEmptyPasswords yes + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +AllowAgentForwarding yes +AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +UsePrivilegeSeparation no +#PermitUserEnvironment no +Compression no +ClientAliveInterval 15 +ClientAliveCountMax 4 +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10 +#PermitTunnel no +#ChrootDirectory none + +# no default banner path +#Banner /config-mfg/fgsn.dat + +# override default of no subsystems +Subsystem sftp /usr/libexec/sftp-server diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-sshd-config-if-needed/update-sshd-config-if-needed.autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-sshd-config-if-needed/update-sshd-config-if-needed.autorun new file mode 100644 index 0000000..40ed093 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/02-update-sshd-config-if-needed/update-sshd-config-if-needed.autorun @@ -0,0 +1,29 @@ +#!/bin/sh + +FileName="sshd_config" +DestinationPath="/etc/ssh/" + +SrcPath=`dirname $0` +SrcFileName=$SrcPath/$FileName +DstFileName=$DestinationPath/$FileName + +NEED_UPDATE=0 +if [ -f $DstFileName ]; then + if [ -f $SrcFileName ]; then + MD5Src=`/usr/bin/md5sum $SrcFileName | /usr/bin/awk '{print $1}'` + MD5Dst=`/usr/bin/md5sum $DstFileName | /usr/bin/awk '{print $1}'` + if [ "$MD5Src" != "$MD5Dst" ]; then + NEED_UPDATE=1 + fi + fi +else + NEED_UPDATE=1 +fi + +if [ $NEED_UPDATE == 1 ]; then + /bin/mount -o rw,remount / + /bin/cp "$SrcFileName" "$DstFileName" + /bin/chown 1018:3015 "$DstFileName" + sync + /bin/mount -o ro,remount / +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/adb b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/adb new file mode 100644 index 0000000..2f98fe4 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/adb differ diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/anti-neutralizeid7.autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/anti-neutralizeid7.autorun new file mode 100644 index 0000000..a51bf74 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/anti-neutralizeid7.autorun @@ -0,0 +1,5 @@ +#!/bin/sh + +SrcPath=`dirname $0` + +/bin/sh $SrcPath/watch-for-missing-recovery.sh & diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/autorun b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/autorun new file mode 100644 index 0000000..c6a27d6 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/autorun @@ -0,0 +1,37 @@ +#!/bin/sh +### autorun +# this script search in this dir and subdirs for *.autorun files +# *.autorun files not need to have x (execute) bit set +# and run all *.autorun files in alphabetical order (path+filename) +# wait for every script to finish and run next script +# THIS FILE NEED TO BE IN /tmp/mnt/data_persist/dev/bin/ +# THIS FILE NEED TO HAVE x (execute) bit SET TO BE EXECUTED BY CMU !!! + +/bin/chmod +x $0 +/usr/bin/find `dirname $0` -iname \*.autorun -type f | /usr/bin/sort | /usr/bin/xargs -n 1 /bin/sh + +# Run the run.sh script +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +sleep 40 +if [ -e /mnt/sd_nav/run.sh ] +then + chmod +x /mnt/sd_nav/run.sh + sh /mnt/sd_nav/run.sh +fi + +for USB in a b c d e +do + RUNSH="/tmp/mnt/sd${USB}/run.sh" + if [ -e "${RUNSH}" ]; then + /bin/sh "${RUNSH}" + break + fi + RUNSH="/tmp/mnt/sd${USB}1/run.sh" + if [ -e "${RUNSH}" ]; then + /bin/sh "${RUNSH}" + break + fi +done + +exit 0 +### END autorun \ No newline at end of file diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/recover-autorun.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/recover-autorun.sh new file mode 100644 index 0000000..26f2203 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/recover-autorun.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +MY_DIR=`dirname $0` +START_NORM=/jci/scripts/start_normal_mode.sh +CONF_NAME=autorun +CONF_DIR=/mnt/data_persist/dev/bin +CONF_ADB=${CONF_DIR}/adb +CONF_FILE=${CONF_DIR}/${CONF_NAME} +MY_CONF=${MY_DIR}/${CONF_NAME} +MY_ADB=${MY_DIR}/adb +UDEV_HANDLR=${CONF_DIR}/02-run-tweaks-from-usb/install-udev-handler-if-not-installed +UDEV_AUTO=${CONF_DIR}/02-run-tweaks-from-usb/install-udev-handler-if-not-installed.autorun +REC_LOG=${MY_DIR}/recovery.log + +sleep 5 +echo "*** Begin Autorun Recovery ***" >> ${REC_LOG} + +while true +do + if [ ! -e ${CONF_FILE} ] + then + echo "Recover Autorun & Files" >> ${REC_LOG} + cp -a ${MY_CONF} ${CONF_FILE} + cp -a ${MY_ADB} ${CONF_ADB} + cp -a ${MY_DIR}/02-* ${CONF_DIR} + mv ${UDEV_HANDLR} ${UDEV_AUTO} + fi + sleep 5 +done diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/watch-for-missing-recovery.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/watch-for-missing-recovery.sh new file mode 100644 index 0000000..2c0d627 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/44-recovery-recovery/watch-for-missing-recovery.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +MY_DIR=`dirname $0` +REC_LOG=${MY_DIR}/recovery.log +START_NORM=jci/scripts/start_normal_mode.sh +START_NORM_BIN=jci/bin/start_normal_mode.sh +EMMC_MOUNT=usr/sbin/emmc_mount_data_persist.sh +RECOVERY=/tmp/recover-autorun.sh +CONF_DIR=/mnt/data_persist/dev/bin +CONF_NAME=autorun +CONF_FILE=${CONF_DIR}/${CONF_NAME} +_FS=/ + +check_for_autocode () +{ + local _CONF_FILE=$1 + if [ -f ${_CONF_FILE} ] && ! grep -Fq "autorun" ${_CONF_FILE} + then + mount -o rw,remount ${_FS} + echo "" >> ${_CONF_FILE} + echo "if [ -e /data_persist/dev/bin/autorun ] ; then" >> ${_CONF_FILE} + echo " /data_persist/dev/bin/autorun &" >> ${_CONF_FILE} + echo "fi" >> ${_CONF_FILE} + fi +} +cp -a ${MY_DIR}/* /tmp +if [ ! -e ${_FS}${START_NORM} ]; then + _FS=/mnt/a/ + if [ ! -e ${_FS} ]; then + echo "Mounting Root File System.." + mkdir -p ${_FS} + mount /dev/ffx01p1 ${_FS} + fi +fi +check_for_autocode ${_FS}${START_NORM} +check_for_autocode ${_FS}${START_NORM_BIN} +check_for_autocode ${_FS}${EMMC_MOUNT} +# while true +# do + # sleep 10 + # if [ ! -e ${CONF_FILE} ]; then + # sleep 5 + # /bin/sh ${RECOVERY} & + # break + # fi +# done diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/README.md b/app/files/tweaks/cmu-autorun/sdcard/recovery/README.md new file mode 100644 index 0000000..2128c5e --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/README.md @@ -0,0 +1,11 @@ +# Autorun Recovery Scripts + +**These scripts attempt to recover a damaged system that has lost SSH access and help you regain access to your system.** + +**Place the entire contents of this directory on an SD card or USB drive to install. Scripts will run on next boot.** + +##### Scripts to help you regain system access: +- fix passwd configuration +- fix sshd configuration +- open firewall configuration +- add udev handler to run tweaks installer diff --git a/app/files/tweaks/cmu-autorun/sdcard/recovery/run.sh b/app/files/tweaks/cmu-autorun/sdcard/recovery/run.sh new file mode 100644 index 0000000..b2a5f99 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/recovery/run.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +MYDIR=$(dirname "$(readlink -f "$0")") + +get_cmu_sw_version() +{ + _ver=$(/bin/grep "^JCI_SW_VER=" /jci/version.ini | /bin/sed 's/^.*_\([^_]*\)\"$/\1/') + _patch=$(/bin/grep "^JCI_SW_VER_PATCH=" /jci/version.ini | /bin/sed 's/^.*\"\([^\"]*\)\"$/\1/') + _flavor=$(/bin/grep "^JCI_SW_FLAVOR=" /jci/version.ini | /bin/sed 's/^.*_\([^_]*\)\"$/\1/') + + if [ ! -z "${_flavor}" ]; then + echo "${_ver}${_patch}-${_flavor}" + else + echo "${_ver}${_patch}" + fi +} + +show_message() +{ + sleep 5 + killall jci-dialog + /jci/tools/jci-dialog --info --title="MESSAGE" --text="$*" --no-cancel & +} + +# disable watchdog and allow write access +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +mount -o rw,remount / + +CMU_SW_VER=$(get_cmu_sw_version) + +show_message "INSTALLING RECOVERY FILES" + +cp -a "${MYDIR}"/00-* /tmp/mnt/data_persist/dev/bin/ +cp -a "${MYDIR}"/01-* /tmp/mnt/data_persist/dev/bin/ +chmod -R +x /tmp/mnt/data_persist/dev/bin/ + +show_message "RECOVERY FILES INSTALLED" + +exit 0 diff --git a/app/files/tweaks/cmu-autorun/sdcard/run.sh b/app/files/tweaks/cmu-autorun/sdcard/run.sh new file mode 100644 index 0000000..51124b8 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/run.sh @@ -0,0 +1,52 @@ +#!/bin/sh +## Master Run Script +### Runs all cmu-autorun scripts + +# Disable watchdog +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +mount -o rw,remount / +# Set environment +DIR=$(dirname $(readlink -f $0)) +CONFIGFILE="${DIR}/autorun.conf" + +# Exits if no config file is found +if [ -e "${CONFIGFILE}" ]; then + . "${CONFIGFILE}" +else + exit 1 # exit 1 to show error has occured +fi + +if [ ${RUN_DRYRUN} = "1" ]; then + sh ${DIR}/dryrun/run.sh +fi + +if [ ${RUN_ADB} = "1" ]; then + sh ${DIR}/adb/run.sh & + sleep 5 +fi + +if [ ${RUN_SSH} = "1" ]; then + sh ${DIR}/temporary-ssh-access/run.sh & + sleep 5 +fi + +if [ ${RUN_WIFI} = "1" ]; then + sh ${DIR}/WifiAP-toggle/run.sh & + sleep 5 +fi + +if [ ${RUN_SS} = "1" ]; then + sh ${DIR}/screenshots/run.sh & + sleep 5 +fi + +if [ ${RUN_AA} = "1" ]; then + sh ${DIR}/headunit/run.sh & + sleep 5 +fi + +if [ ${RUN_ML} = "1" ]; then + sh ${DIR}/memory-log/run.sh & +fi + +exit 0 diff --git a/app/files/tweaks/cmu-autorun/sdcard/screenshots/README.md b/app/files/tweaks/cmu-autorun/sdcard/screenshots/README.md new file mode 100644 index 0000000..0950766 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/screenshots/README.md @@ -0,0 +1,8 @@ +# Screenshots + +### Takes X screenshots over an interval amount of time + +* **Set variables in the `ss/screenshots.conf` file to change amount & frequency of screenshots.** +* Starts 60 seconds after the `autorun` script is executed. +* Intervals have an added 1-5 seconds for screenshot saving and copying operations. +* Default is 10 screenshots at 60 second intervals. diff --git a/app/files/tweaks/cmu-autorun/sdcard/screenshots/run.sh b/app/files/tweaks/cmu-autorun/sdcard/screenshots/run.sh new file mode 100644 index 0000000..f164adc --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/screenshots/run.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# Disable watchdog +echo 1 > /sys/class/gpio/Watchdog\ Disable/value +mount -o rw,remount / +# Set environment +DIR=$(dirname $(readlink -f $0)) + +sh ${DIR}/ss/screenshots.sh & + diff --git a/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/.gitignore b/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/.gitignore new file mode 100644 index 0000000..a06d41d --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/.gitignore @@ -0,0 +1 @@ +/screenshots \ No newline at end of file diff --git a/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/screenshots.conf b/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/screenshots.conf new file mode 100644 index 0000000..0bce69d --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/screenshots.conf @@ -0,0 +1,29 @@ +###################################### +## screenshots.conf +## Config file for screenshots.sh +## By: Trezdog44 +###################################### + +### NUMSCRNSHOTS +## Number of screenshots +NUMSCRNSHOTS=10 + +### SSGAP +## Half of the time between screenshots in seconds +## It goes screenshot gap save gap shot gap save... +SSGAP=20 + +### DONE_MSG +## A Pop-up meesage when the screenshots have all finished +## 1 = Message 0 = No Message +DONE_MSG=1 + +### SSRESET +## Restart the filename count to 1 on each run +## 1 = Reset 0 = Continue +SSRESET=0 + +### IMG_COUNT +## Number of the last screenshot to continue numbering +## To restart numbering, reset to 0 or set SSRESET to 1 +IMG_COUNT=0 \ No newline at end of file diff --git a/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/screenshots.sh b/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/screenshots.sh new file mode 100644 index 0000000..bad4e45 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/screenshots/ss/screenshots.sh @@ -0,0 +1,68 @@ +#!/bin/sh + +########################################## +## screenshots.sh - Takes X screenshots +## Set options in screenshots.conf +## By: Trezdog44 +########################################## + +show_message() +{ + sleep 5 + killall jci-dialog + /jci/tools/jci-dialog --info --title="SCREENSHOTS" --text="$*" --no-cancel & +} +MYDIR=$(dirname "$(readlink -f "$0")") +CONFIGFILE="${MYDIR}/screenshots.conf" + +# Exits if no config file is found +if [ -e "${CONFIGFILE}" ] +then + . "${CONFIGFILE}" +else + exit 1 +fi + +# Reset or continue numbering for filenames +if [ $SSRESET = 1 ] +then + MAX=0 +else + MAX=$IMG_COUNT +fi + +# echo "=${NUMSCRNSHOTS}= =${SSGAP}= =${IMG_COUNT}=" >> ${MYDIR}/ss.log +# 60 seconds then start +sleep 60 + +if [ $DONE_MSG = 1 ] +then + show_message "${NUMSCRNSHOTS} SCREENSHOTS" + sleep 5 + killall jci-dialog +fi + +if [ ! -e "${MYDIR}/screenshots" ] +then + mkdir -p "${MYDIR}/screenshots" +fi + +for i in $(seq 1 $NUMSCRNSHOTS) +do + /usr/bin/screenshot + sleep $SSGAP + cp /wayland-screenshot.png "${MYDIR}/screenshots/screenshot$((i+MAX)).png" + # echo "${MYDIR}/screenshots/screenshot$((i+MAX)).png" >> ${MYDIR}/ss.log + NEWMAX=$((i+MAX)) + sleep $SSGAP +done + +# Set starting point for next run to continue file numbering +sed -i s/IMG_COUNT=.*/IMG_COUNT=$NEWMAX/g "${CONFIGFILE}" + +if [ $DONE_MSG = 1 ] +then + show_message "${NUMSCRNSHOTS} SCREENSHOTS TAKEN" + sleep 15 + killall jci-dialog +fi diff --git a/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/README.md b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/README.md new file mode 100644 index 0000000..01a7289 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/README.md @@ -0,0 +1,22 @@ +# temporary-ssh-access + +SSH on demand. + +![SSH](ssh.png) + +http://mazda3revolution.com/forums/2014-2016-mazda-3-skyactiv-audio-electronics/57714-infotainment-project-584.html + +# Description +[README.txt](README.txt) + + +# Step + +1. Download `cmu-autorun/sdcard/temporary-ssh-access/*` to USB +2. Plug USB in cars and wait dialog +3. On PC connect WiFi name : CMU-XX:XX:XX:XX:XX:XX +4. use ssh client connect to 192.168.53.1 with key `mazda-ssh` in `cmu-autorun/sdcard/temporary-ssh-access/mazda-ssh` + +```bash +ssh -i mazda-ssh -p7777 cmu@192.168.53.1 +``` diff --git a/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/README.txt b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/README.txt new file mode 100644 index 0000000..01e1d1b --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/README.txt @@ -0,0 +1,29 @@ +This will (temporarily, until the next reboot) open up SSH (root) access to +the Mazda CMU running v56. It does not make any changes to files on the CMU. + +NOTE: I've only tested this using a USB Ethernet dongle (in particular this + one: http://www.dx.com/p/414475). However, the tweak does disable + (again, temporarily) the firewall, so it _should_ work over wifi as + well. + +Steps: + +1. Copy the contents of this directory to a USB stick. + +2. Insert the stick into your Mazda. + +3. Wait for the dialog to appear. + +4. ssh to your car: + + $ ssh -p 7777 -i mazda-ssh cmu@192.168.42.1 + + Where `mazda-pub` is the file named as such in this directory (containing + the private SSH key). + +192.168.42.1 is the default IP-address that the CMU will use if you're not +using a DHCP daemon. You should be able to reach it if you assign a static +IP-number (like 192.168.42.2) to your ethernet interface. + +If you're using wifi, the IP-address may be different (I believe that you +can look it up somewhere in the CMU settings). diff --git a/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/mazda-ssh b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/mazda-ssh new file mode 100644 index 0000000..0d661ae --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/mazda-ssh @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAvUMlOxlxxV7MN75Mk79mdvyWjV0GSk58/pWBlwUAJWZ9x/cG +NFEuNsiy2HrhQRTOLJ55NZLo2cGMyqpSjqK7gjE4VS/IMFnQp/QUjzZOqz2w4j5f +UknbN0A4zUxvizoqfqrAaO6w96XFl1ePYTZyYikXS1vlGCqTViKtaw7JL241+sU8 +gC1SyZB31fZFgMxYrgjmy50BJLmWikT3lwe5mbVTDl2Oh3QYCqrtNVXddJutXZf4 +d24J45eMxji8SPUj5Hb7kspvenH+AIJu3BTi2TFq+tunzEcAax0/5OZMLG9oV9Wy +2JquTXwuUtGSGdV6GBPyZ0D/Rg8KlpALOr/PQQIDAQABAoIBADb86DdIiD6g8VKM +zrDqnjmZ36AI1AgIz9Yj1/fpswYqxgawJbRTlcrC+vtckE+ZXOGn1W2UVmTWEDLd +04ivjS0hYc2WSWKK5c22Y7bMP4UPMnI5TvaYkMF3vkkfmRTpfGk68RZLq0z4c/Up +snW7HPaaG7OAaopf7FjNUHdXX2qQ6eOoCOB5ZebhlPwKzv/s1DkXnidaML0YeyA9 +gIyKPmpmPSN+g8iFH684PeDBLwvfU9rjonma7gkXLKSka9rkI+5w2LgtJh/X4QDw +rN6OOL4g5/CDQMGVAZDW3DiiHpSS03qrOTt861JENuowuIxI4Ml7xc21G0gyR2Xe +I1JQdtUCgYEA3Si6kokZSzIM/1x/5SEpJw9RXc7WZniboDhr9cRrb0bTux7Elba5 +PMMDh2bCVOCOJjgZkfrPSokQnbExQ8va9fJwCK9dwtihoO+9YfpsnmdkUMqskElv +ue9+qk9vJx4riJAmUNBFnoGGf4Nnfh/1tf79xxq/eVOSNd+PJqQ5lZsCgYEA2xQH +dPkNCIrsPyo1dwt9VOZdoJVNDLg6TPKOjakAhV02HOhGXTg930Sycqj78o/aY1cj +alQo3pJme2gaWo5/7l8GrYAHojL52xkp3Gx8WmGsG7A6edIdKKNGiMqUqpejJ+P9 +eI5mh2Xk3HMN6xc7RPy5aRWIKkAfgOKmsKiYylMCgYBfwN2eyls4MnBsM8lwFD50 +Ge65te8gKMIAycz8eNGnOTw8/SJSS+3BwBGME1K6WwtQwuNXUAdmFxgpnmldGCsy +Z4hYSk1HKnI4cvRFMp7KqqtFS6sRQaptD6OA66mNf0OL+hWM0dACw8PO+77YXdAN +v1xzU0JprmRUjPm22k3QVwKBgQCR3gApDjpzWax7UitPHENS6B+m8EHhGjkXStlH +0SMbqTiCftV69BueMStv1LwMgWOziS13epnLuEasHGCPsxnTKUpU804h3TcnftW0 +gjc6JpZlySzmN9RaXnx0UA40l8p2oQL/5jC2Lk33ylOWGF3KTUtWgJOtLgzL0B2U +um0hKQKBgQCo+O3eiqpOiyNVl/2oY9R3gZWZtWRTX9Z8yRHzdJRR2jsSNUjHaMg/ +qTiBIsZYFkmW9wNAYG/RR9x8W7lwKiXh+pkVP9/Ey2J6RW4HhYjDlXu2RddwS2cY +//Uut+GZtkg/EWlop3NCLfINI0Xlngq540jkNV6PG29ZPFNSJJtjgg== +-----END RSA PRIVATE KEY----- diff --git a/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/mazda-ssh.pub b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/mazda-ssh.pub new file mode 100644 index 0000000..a7c5ba0 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/mazda-ssh.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9QyU7GXHFXsw3vkyTv2Z2/JaNXQZKTnz+lYGXBQAlZn3H9wY0US42yLLYeuFBFM4snnk1kujZwYzKqlKOoruCMThVL8gwWdCn9BSPNk6rPbDiPl9SSds3QDjNTG+LOip+qsBo7rD3pcWXV49hNnJiKRdLW+UYKpNWIq1rDskvbjX6xTyALVLJkHfV9kWAzFiuCObLnQEkuZaKRPeXB7mZtVMOXY6HdBgKqu01Vd10m61dl/h3bgnjl4zGOLxI9SPkdvuSym96cf4Agm7cFOLZMWr626fMRwBrHT/k5kwsb2hX1bLYmq5NfC5S0ZIZ1XoYE/JnQP9GDwqWkAs6v89B diff --git a/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/run.sh b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/run.sh new file mode 100644 index 0000000..8522657 --- /dev/null +++ b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/run.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +DEBUG=1 + +sleep 5 + +show_message() +{ + sleep 5 + killall jci-dialog + /jci/tools/jci-dialog --info --title="MESSAGE" --text="$*" --no-cancel & +} + +# Disable watchdog +echo 1 > /sys/class/gpio/Watchdog\ Disable/value + +# Set environment +DIR=$(dirname $(readlink -f $0)) +PATH=$PATH:/bin:/sbin:/usr/bin:/usr/sbin + +mount -o rw,remount ${DIR} + +# Log all stdout/stderr to file +exec > $DIR/installer.log 2>&1 + +# Stop firewall +#/jci/scripts/jci-fw.sh stop >>$DIR/installer.log + +# Start WiFiAP +killall wpa_supplicant >> $DIR/installer.log +/jci/scripts/jci-fw.sh stop >> $DIR/installer.log +sleep 1 +/jci/scripts/jci-wifiap.sh start >> $DIR/installer.log + +iptables -A INPUT -p tcp --dport 7777 -j ACCEPT >> $DIR/installer.log + +# Start sshd on port 7777 using our public key +/usr/sbin/sshd -D -p 7777 -o "AuthorizedKeysFile ${DIR}/mazda-ssh.pub" -o "StrictModes no" >> $DIR/installer.log & + +/jci/tools/jci-dialog --title="SUCCESS" --text="WiFi-AP and SSHD STARTED!\nssh -i mazda-ssh -p7777 cmu@192.168.53.1" --ok-label='OK' --no-cancel diff --git a/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/ssh.png b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/ssh.png new file mode 100644 index 0000000..c7c8cf6 Binary files /dev/null and b/app/files/tweaks/cmu-autorun/sdcard/temporary-ssh-access/ssh.png differ diff --git a/app/files/tweaks/config/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/js/FuelConsumptionCtrl.MPG.js b/app/files/tweaks/config/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/js/FuelConsumptionCtrl.MPG.js deleted file mode 100644 index c0afec8..0000000 --- a/app/files/tweaks/config/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/js/FuelConsumptionCtrl.MPG.js +++ /dev/null @@ -1,2454 +0,0 @@ -/* - Copyright 2012 by Johnson Controls - __________________________________________________________________________ - - Filename: FuelConsumptionCtrl.js - __________________________________________________________________________ - - Project: JCI-IHU - Language: EN - Author: apeter9 - Date: 1-08-2013 - __________________________________________________________________________ - - Description: IHU GUI FuelConsumptionCtrl) - - Revisions: - v0.1 (01-08-2013) Initial implementation (to 0.3.05 spec) (apeter9) - v0.2 (02-20-2013) Changes in layout and bar images (atiwarc) - v0.3 (03-14-2013) Implementation of UMP Control panel (atiwarc) - v0.4 (04-24-2013) Spec Migration to 3.56 (UMP3 support and Spec changes)(atiwarc) - v0.5 (05-15-2013) Go back implementation (atiwarc) -__________________________________________________________________________ - - */ - -log.addSrcFile("FuelConsumptionCtrl.js", "common"); -// Alternative logging for development (avoid spew from "common") -//log.addSrcFile("FuelConsumptionCtrl.js", "FuelConsumptionCtrl"); -//log.setLogLevel("FuelConsumptionCtrl", "debug"); - -function FuelConsumptionCtrl(uiaId, parentDiv, controlId, properties) -{ -// log.debug("FuelConsumptionCtrl constructor called..."); - - this.uiaId = uiaId; - this.parentDiv = parentDiv; - this.controlId = controlId; - this.divElt = null; - this._switchViewButtonCtrl = null; - this._umpPanelStatus = false; - this._cumulativeBarValue = null; - - this._initialEVMode = new Array(); - /******************************************************/ - /* Values required by _createStructure (before _init) */ - /******************************************************/ - - // Total # of bars available in Current Drive Fuel Economy (CDFE) graph - // (15 historical + 1 slot for new data to be animated into position) - this._totalCDFEBars = 11; - - // The index of the youngest historical data in the CDFE graph - this._youngestCDFEDataIdx = this._totalCDFEBars - 2; - - // The index of the slot for new data in the CDFE graph - this._newCDFEDataIdx = this._totalCDFEBars - 1; - - // The current bar of CDFE graph - this._currentCDFEDataIdx = this._totalCDFEBars; - /**********************New Initialization of CDFE Bars *************************************************/ - - this._totalCDFEBarsRight = 6; - - // The index of the youngest historical data in the CDFE graph - this._youngestCDFEDataIdxRight = this._totalCDFEBarsRight - 2; - - // The index of the slot for new data in the CDFE graph - this._newCDFEDataIdxRight = this._totalCDFEBarsRight - 1; - - /************************End of Initialization of CFER Bars ******************************************/ - - // Total # of bars (historical + current + new) available in Cumulative Fuel Economy by Reset (CFER) graph - this._totalCFERBars = 6; - - // The index of the youngest historical data in the CFER graph - this._youngestCFERDataIdx = this._totalCFERBars - 2; - - // The index of the slot for new data in the CFER graph - this._newCFERDataIdx = this._totalCFERBars - 1; - - // The index of the current data in the CFER graph - this._currentCFERDataIdx = this._totalCFERBars; - - // Has the current CFER data been initialized yet? - this._currentCFERDataInitialized = false; - - - - // Table of numerical values used in setting CSS styles programmatically - // NOTE: Changing these values requires matching changes in SCSS source file! - this._CSSConstants = - { - // - // CDFE Graph Constants - // - - // Width (in pixels) of a bar - "CDFEGraphBarWidth" : 21, - - // Space between/around bars - "CDFEGraphBarSpacing" : 2, - "CDFEGraphBarMargin" : 3, - - // Width/height (in pixels) of the visible graph area - // (no labels, title or "hidden" bar) - "CDFEGraphVisibleWidth" : (((this._totalCDFEBars - 1) * 21) + // Bars - ((this._totalCDFEBars - 1) * 1) + // Space between bars - (1 * 1)), // Left & right margins (e.g. 500) - "CDFEGraphVisibleHeight" : 109, - - // Width (in pixels) of the active graph area - // (including "hidden" bar, but no labels or title) - "CDFEGraphActiveWidth" : ((this._totalCDFEBars * 21) + // Bars - ((this._totalCDFEBars - 1) * 1) + // Space between bars - (1 * 1)), // Left & right margins (e.g. 533) - - /*******************************************New CDFE Graph Constants************************************************/ - // - // CDFE Graph Constants - // - - // Width (in pixels) of a bar - "CDFEGraphBarWidthRight" : 44, - // Space between/around bars - "CDFEGraphBarSpacingRight" : 3, - "CDFEGraphBarMarginRight" : 2, - - // Width/height (in pixels) of the visible graph area - // (no labels, title or "hidden" bar) - "CDFEGraphVisibleWidthRight" : (((this._totalCDFEBarsRight - 1) * 44) + // Bars - ((this._totalCDFEBarsRight - 2) * 3) + // Space between bars - (2 * 2)), // Left & right margins (e.g. 500) - "CDFEGraphVisibleHeightRight" : 109, - - // Width (in pixels) of the active graph area - // (including "hidden" bar, but no labels or title) - "CDFEGraphActiveWidthRight" : ((this._totalCDFEBarsRight * 44) + // Bars - ((this._totalCDFEBarsRight - 1) * 3) + // Space between bars - (2 * 2)), // Left & right margins (e.g. 533) - -/*******************************************End of New CDFE Graph Constants************************************************/ - - // - // CFER Graph Constants - // - - // Width (in pixels) of a bar - "CFERGraphBarWidth" :50, - - // Space between/around bars - "CFERGraphBarSpacing" : 28, - "CFERGraphBarMargin" : 17, - - // Width/height (in pixels) of the visible graph area - // (including "hidden" bar, but no labels or title) - "CFERGraphVisibleWidth" : (((this._totalCFERBars - 1) * 50) + // Bars - ((this._totalCFERBars - 2) * 28) + // Space between bars - (1 * 17)), // Left & right margins (e.g. 500) - "CFERGraphVisibleHeight" : 109, - - // Width (in pixels) of the active graph area - // (including "hidden" bar, but no labels or title) - "CFERGraphActiveWidth" : ((this._totalCFERBars * 50) + // Bars - ((this._totalCFERBars - 1) * 28) + // Space between bars - (1 * 17)), // Left & right margins (e.g. 580) - }; - - /******************************************************/ - /******************************************************/ - /******************************************************/ - - this._cbCDFELineFadeAnimationEnd = null; - this._cbCDFELeftAnimationEnd = null; - this._cbCFERLeftAnimationEnd = null; - - this._CDFELineGraphCanvasDC = null; - this._CDFELineGraphInTransition = false; - - this._CDFEGraphBarValues = null; - this._CDFEGraphLineValues = null; - this._CFERGraphBarValues = null; - - /**************************************Initialization of functions********************************************/ - - this._cbCDFELineFadeAnimationEndRight = null; - this._cbCDFELeftAnimationEndRight = null; - this._cbCFERLeftAnimationEndRight = null; - - this._CDFELineGraphCanvasDCRight = null; - this._CDFELineGraphInTransitionRight = false; - - this._CDFEGraphBarValuesRight = null; - this._CDFEGraphLineValuesRight = null; - this._CFERGraphBarValuesRight = null; - this._CDFEDiscBarValuesRight = null; - this._CDFEEvModeRight = new Array(); - - /**************************************End ofInitialization of functions********************************************/ - - - //@formatter:off - this.properties = - { - "subMap" : null, - "mode" : "", - "fuelEfficientyTitleId" : "", - "fuelEfficientyTitleText" : "", - "switchViewLabelId" : "", - "switchViewLabelText" : "", - "switchViewButtonCallback" : null, - "fuelEfficiencyData" : null, - "currentFuelConfig" : null, - "cumulativeFuelConfig" : null, - "umpButtonConfig" : null, - "defaultSelectCallback" : null, - "defaultSlideCallback" : null, - "defaultHoldStartCallback" : null, - "defaultHoldStopCallback" : null, - "dataList" : null, - "umpStyle" : null, - "hasScrubber" : false, - "umpPanelStatus" : false - }; - //@formatter:on - - // Copy properties from the app - for (var key in properties) - { - this.properties[key] = properties[key]; - } - - //preload images - this.imagesCount = 0; - this._preload('FuelConsBar_Narrow.png','FuelConsBar_NarrowCurrent.png','FuelConsBar_NarrowGreen.png', 'FuelConsBar_NarrowGreenCurrent.png', 'FuelConsBar_wide.png', 'FuelConsBar_wide_green.png','FuelConsBar_WideCurrent.png','FuelConsBarCap_Narrow.png','FuelConsBarCap_wide.png','GeneratedEnergy_NarrowCurrent.png','GeneratedEnergy_NarrowGreen.png','GeneratedEnergy_NarrowGreenCurrent.png','GeneratedEnergy_NarrowPurple.png','GeneratedEnergy_Wide_Green.png','GeneratedEnergy_WidePurple.png'); - - // Create DOM elements - this._createStructure(); -} - -/*******************/ -/* Private Methods */ -/*******************/ - -FuelConsumptionCtrl.prototype._init = function() -{ -// log.debug("FuelConsumptionCtrl: _init() called..."); - - // Historical data displayed by CDFE graph - this._CDFEGraphBarValues = new Array(); - this._CDFEGraphLineValues = new Array(); - this._CDFEDiscValues = new Array(); - /************************************Historical data displayed by CDFE graph Right***********************************/ - - this._CDFEGraphBarValuesRight = new Array(); - this._CDFEDiscBarValuesRight = new Array(); - - /************************************End of Historical data displayed by CDFE graph Right ***********************************/ - // Historical/current data displayed by CFER graph - this._CFERGraphBarValues = new Array(); - - // The callback function used to remove the animation on the CDFE line graph at the end of its fade-in - this._cbCDFELineFadeAnimationEnd = this._onCDFELineFadeAnimationEnd.bind(this); - - // The callback function used to reset the CDFE graph after left animation (insertion) completes - this._cbCDFELeftAnimationEnd = this._onCDFELeftAnimationEnd.bind(this); - - /**********************************New function Added ****************************************/ - - // The callback function used to reset the CDFE graph after left animation (insertion) completes - this._cbCDFELeftAnimationEndRight = this._onCDFELeftAnimationEndRight.bind(this); - - /***********************************End of New function ****************************************/ - - // The callback function used to reset the CFER graph after left animation (insertion) completes - this._cbCFERLeftAnimationEnd = this._onCFERLeftAnimationEnd.bind(this); - - // Set the canvas' width & height attributes to match CSS, so pixels are 1:1 - this.CDFELineGraphCanvas.width = this._CSSConstants["CDFEGraphActiveWidth"]; - this.CDFELineGraphCanvas.height = this._CSSConstants["CDFEGraphVisibleHeight"]; - - // The drawing context for the CDFE line graph canvas overlay - this._CDFELineGraphCanvasDC = this.CDFELineGraphCanvas.getContext("2d"); - - // Now that the DOM structure is established, - // set the horizontal positions of the graph bars - this._setCDFEGraphBarPositions(); - - /**********************************New Function Added*****************************************/ - - - this._setCDFEGraphBarPositionsRight(); - - - /********************************End of New Function Added*****************************************/ - - this._setCFERGraphBarPositions(); - - // Set the CDFE graph title text - this.properties.currentFuelConfig.titleText = this._translateString(this.properties.currentFuelConfig.titleId, - this.properties.currentFuelConfig.titleText, - this.properties.subMap); - this.CDFEGraphTitle.innerHTML = this._stringToHTML(this.properties.currentFuelConfig.titleText); - - - - // Set the CFER graph title text - this.properties.cumulativeFuelConfig.titleText = this._translateString(this.properties.cumulativeFuelConfig.titleId, - this.properties.cumulativeFuelConfig.titleText, - this.properties.subMap); - this.CFERGraphTitle.innerHTML = this._stringToHTML(this.properties.cumulativeFuelConfig.titleText); - - // Set the fuel efficiency title text - this.properties.fuelEfficiencyTitleText = this._translateString(this.properties.fuelEfficiencyTitleId, - this.properties.fuelEfficiencyTitleText, - this.properties.subMap); - this.properties.fuelEfficiencyTypeText = this._translateString(this.properties.fuelEfficiencyTypeId, - this.properties.fuelEfficiencyTypeText, - this.properties.subMap); - - this.fuelEfficiencyTitle.innerHTML = this._stringToHTML(this.properties.fuelEfficiencyTitleText); - this.fuelEfficiencyThisDrive.innerHTML = this._stringToHTML(this.properties.fuelEfficiencyTypeText); - // Initialize the graphs - this.initializeCurrentDriveFuelGraphRight(this.properties.currentFuelConfig.initialBarValues); - this.initializeCumulativeFuelGraph(this.properties.cumulativeFuelConfig.initialBarValues); - - // Set the fuel efficiency data - this.setFuelEfficiency(this.properties.fuelEfficiencyData); -} - -FuelConsumptionCtrl.prototype._next = function(count) -{ - this.imagesCount++; - if(this.imagesCount >= count) - { - this.divElt.className = "FuelConsumptionCtrl"; - } -} - -FuelConsumptionCtrl.prototype._preload = function() -{ - var images = new Array(); - var prefix = './apps/ecoenergy/controls/FuelConsumption/images/'; - for(var i = 0; i < this._preload.arguments.length; i++) - { - images[i] = new Image(); - images[i].src = prefix + this._preload.arguments[i]; - images[i].onload = this._next.bind(this, this._preload.arguments.length); - } -} - -FuelConsumptionCtrl.prototype._createStructure = function() -{ -// log.debug("FuelConsumptionCtrl: _createStructure() called..."); - - // Create the div for control - this.divElt = document.createElement('div'); - this.divElt.className = "FuelConsumptionCtrl FuelConsumptionCtrlHiddenOpacity"; - // Create the div for ump panel - this.umpPanelDiv = document.createElement('div'); - //(this.properties.umpPanelStatus) ? this.umpPanelDiv.className = "UmpPanelDivEnable" : this.umpPanelDiv.className = "UmpPanelDivDisable"; - this.umpPanelDiv.className = "UmpPanelDivDisable"; - this.umpPanelDiv.style.left = "-60px"; - // Create the container div for all of the graphs - this.graphsArea = document.createElement('div'); - this.graphsArea.className = 'FuelConsumptionCtrlGraphsArea'; - - /***************************************/ - /* Create DOM structure for CDFE graph */ - /***************************************/ - - // CDFE graph top-level DIV - this.CDFEGraph = document.createElement('div'); - this.CDFEGraph.className = 'FuelConsumptionCtrlCDFEGraph'; - - /******************************Created New graph Div *****************************************/ - - // CDFE graph top-level DIV 2 - this.CDFEGraphRight = document.createElement('div'); - this.CDFEGraphRight.className = 'FuelConsumptionCtrlCDFEGraphRight'; - - /******************************End of Created New graph Div **********************************/ - - // CDFE graph X-axis label - this.CDFEGraphXAxisLabel = document.createElement('div'); - this.CDFEGraphXAxisLabel.className = 'FuelConsumptionCtrlCDFEGraphXAxisLabel'; - this.CDFEGraph.appendChild(this.CDFEGraphXAxisLabel); - - // CDFE graph Y-axis label - this.CDFEGraphYAxisLabel = document.createElement('div'); - this.CDFEGraphYAxisLabel.className = 'FuelConsumptionCtrlCDFEGraphYAxisLabel'; - this.CDFEGraph.appendChild(this.CDFEGraphYAxisLabel); - - // Add axis labels to CDFE graph - this._addCDFEGraphAxisLabels(this.CDFEGraphXAxisLabel, - this.CDFEGraphYAxisLabel); - - // CDFE graph title - this.CDFEGraphTitle = document.createElement('h2'); - this.CDFEGraphTitle.className = 'FuelConsumptionCtrlCDFEGraphTitle'; - this.CDFEGraph.appendChild(this.CDFEGraphTitle); - - // Clipping mask for active CDFE graph area - this.CDFEGraphClipMask = document.createElement('div'); - this.CDFEGraphClipMask.className = 'FuelConsumptionCtrlCDFEGraphClipMask'; - - /*****************************************New Mask for CDFE graph*********************************/ - - // Clipping mask for active CDFE graph Right area - this.CDFEGraphClipMaskRight = document.createElement('div'); - this.CDFEGraphClipMaskRight.className = 'FuelConsumptionCtrlCDFEGraphClipMaskRight'; - - /*****************************************End of New Mask for CDFE graph*********************************/ - - // Active graphing area for CDFE graph - this.CDFEGraphArea = document.createElement('div'); - this.CDFEGraphArea.className = 'FuelConsumptionCtrlCDFEGraphArea'; - - /***************************************New Active Graphing Area for CDFE graph right***************/ - - // Active graphing area for CDFE graph Right - this.CDFEGraphAreaRight = document.createElement('div'); - this.CDFEGraphAreaRight.className = 'FuelConsumptionCtrlCDFEGraphAreaRight'; - - /***************************************End of Active Graphing Area for CDFE graph right***************/ - // Create CDFE graph bars - for (var i = 1; i <= this._totalCDFEBars; i++) - { - var curCDFEBar = document.createElement('div'); - curCDFEBar.id = 'CDFEBar' + i; - - var CDFEBarCap = document.createElement('div'); - CDFEBarCap.className = 'FuelConsumptionCtrlCDFEBarGraphCap'; - - switch (i) - { - case this._newCDFEDataIdx: - curCDFEBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - this.CDFECurrentBar = curCDFEBar; - - break; - case this._currentCDFEDataIdx: - curCDFEBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - - break; - default: - curCDFEBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - break; - } - - curCDFEBar.appendChild(CDFEBarCap); - this.CDFEGraphArea.appendChild(curCDFEBar); - } - - /*************************************New CDFE Graph Bars**********************************/ - - // Create CDFE graph Right bars - for (var i = 1; i <= this._totalCDFEBarsRight; i++) - { - var curCDFEBarRight = document.createElement('div'); - curCDFEBarRight.id = 'CDFEBarRight' + i; - curCDFEBarRight.className = 'FuelConsumptionCtrlCDFEBarGraphCoreRight'; - var CDFEBarCapRight = document.createElement('div'); - CDFEBarCapRight.className = 'FuelConsumptionCtrlCDFEBarGraphCapRight'; - curCDFEBarRight.appendChild(CDFEBarCapRight); - this.CDFEGraphAreaRight.appendChild(curCDFEBarRight); - } - - /*************************************End of New CDFE Graph Bars**********************************/ - // Create canvas for drawing line graphs - this.CDFELineGraphCanvas = document.createElement('canvas'); - this.CDFELineGraphCanvas.id = 'FuelConsumptionCtrlCDFELineGraphCanvas'; - this.CDFELineGraphCanvas.className = 'FuelConsumptionCtrlHiddenCDFELineGraphCanvas'; - this.CDFEGraphArea.appendChild(this.CDFELineGraphCanvas); - - // Attach the active graphing area to the CDEF graph clip mask - this.CDFEGraphClipMask.appendChild(this.CDFEGraphArea); - - /**************************New CDFE Clip Mask Attach*******************************************/ - - // Attach the active graphing area to the CDEF graph clip mask - this.CDFEGraphClipMaskRight.appendChild(this.CDFEGraphAreaRight); - - /**************************End of New CDFE Clip Mask Attach*******************************************/ - - // Attach the clip mask to the CDFE graph - this.CDFEGraph.appendChild(this.CDFEGraphClipMask); - - /**************************New clip mask to the CDFE graph*******************************************/ - - // Attach the clip mask to the CDFE graph Right - this.CDFEGraphRight.appendChild(this.CDFEGraphClipMaskRight); - - /**************************End of New clip mask to the CDFE graph*******************************************/ - - // Attach the CDFE graph to its parent - this.graphsArea.appendChild(this.CDFEGraph); - - /**************************New CDFE graph to its parent*******************************************/ - - // Start stand alone graph for the hev disc graph - if(this.properties.ctrlStyle === "hevstyle") - { - // CDFE Disc graph top-level DIV - this.CDFEDiscGraph = document.createElement('div'); - this.CDFEDiscGraph.className = 'FuelConsumptionCtrlCDFEDiscGraph'; - - // Clipping Disc mask for active CDFE graph area - this.CDFEDiscGraphClipMask = document.createElement('div'); - this.CDFEDiscGraphClipMask.className = 'FuelConsumptionCtrlCDFEDiscGraphClipMask'; - - // Active graphing area for CDFE Disc graph - this.CDFEDiscGraphArea = document.createElement('div'); - this.CDFEDiscGraphArea.className = 'FuelConsumptionCtrlCDFEDiscGraphArea'; - - // Create Disc CDFE graph bars - for (var i = 1; i <= this._totalCDFEBars; i++) - { - var curCDFEDiscBar = document.createElement('div'); - curCDFEDiscBar.id = 'CDFEDiscBar' + i; - - switch (i) - { - case this._newCDFEDataIdx: - curCDFEDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - this.CDFECurrentDiscBar = curCDFEDiscBar; - - break; - case this._currentCDFEDataIdx: - curCDFEDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - - break; - default: - curCDFEDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - break; - } - - - - this.CDFEDiscGraphArea.appendChild(curCDFEDiscBar); - } - - // Attach the active graphing area to the CDEF Disc graph clip mask - this.CDFEDiscGraphClipMask.appendChild(this.CDFEDiscGraphArea); - - // Attach the clip mask to the CDFE Disc graph - this.CDFEDiscGraph.appendChild(this.CDFEDiscGraphClipMask); - - // Attach the CDFE Disc graph to its parent - this.graphsArea.appendChild(this.CDFEDiscGraph); - - - /************* For the 10 Min bar graph data with Discs *************/ - // CDFE Disc graph top-level DIV - this.CDFEDiscGraphRight = document.createElement('div'); - this.CDFEDiscGraphRight.className = 'FuelConsumptionCtrlCDFEDiscGraphRight'; - - // Clipping Disc mask for active CDFE graph area - this.CDFEDiscGraphClipMaskRight = document.createElement('div'); - this.CDFEDiscGraphClipMaskRight.className = 'FuelConsumptionCtrlCDFEDiscGraphClipMaskRight'; - - // Active graphing area for CDFE Disc graph - this.CDFEDiscGraphAreaRight = document.createElement('div'); - this.CDFEDiscGraphAreaRight.className = 'FuelConsumptionCtrlCDFEDiscGraphAreaRight'; - - // Create Disc CDFE graph bars - for (var k = 1; k <= this._totalCDFEBarsRight; k++) - { - var curCDFEDiscBarRight = document.createElement('div'); - curCDFEDiscBarRight.id = 'CDFEDiscBarRight' + k; - curCDFEDiscBarRight.className = 'FuelConsumptionCtrlHevCDFEDiscGraphCoreRight'; - this.CDFEDiscGraphAreaRight.appendChild(curCDFEDiscBarRight); - } - - // Attach the active graphing area to the CDEF Disc graph clip mask - this.CDFEDiscGraphClipMaskRight.appendChild(this.CDFEDiscGraphAreaRight); - - // Attach the clip mask to the CDFE Disc graph - this.CDFEDiscGraphRight.appendChild(this.CDFEDiscGraphClipMaskRight); - - // Attach the CDFE Disc graph to its parent - this.graphsArea.appendChild(this.CDFEDiscGraphRight); - - } - // Attach the CDFE graph to its parent Right - this.graphsArea.appendChild(this.CDFEGraphRight); - /**************************End of CDFE graph to its parent*******************************************/ - - /***************************************/ - /* Create DOM structure for CFER graph */ - /***************************************/ - - // CFER graph top-level DIV - this.CFERGraph = document.createElement('div'); - this.CFERGraph.className = 'FuelConsumptionCtrlCFERGraph'; - - // CFER graph X-axis label - this.CFERGraphXAxisLabel = document.createElement('div'); - this.CFERGraphXAxisLabel.className = 'FuelConsumptionCtrlCFERGraphXAxisLabel'; - this.CFERGraph.appendChild(this.CFERGraphXAxisLabel); - - // CFER graph Y-axis label - this.CFERGraphYAxisLabel = document.createElement('div'); - this.CFERGraphYAxisLabel.className = 'FuelConsumptionCtrlCFERGraphYAxisLabel'; - this.CFERGraph.appendChild(this.CFERGraphYAxisLabel); - - // Add axis labels to CFER graph - this._addCFERGraphAxisLabels(this.CFERGraphXAxisLabel, - this.CFERGraphYAxisLabel); - - // CFER graph title - this.CFERGraphTitle = document.createElement('h2'); - this.CFERGraphTitle.className = 'FuelConsumptionCtrlCFERGraphTitle'; - this.CFERGraph.appendChild(this.CFERGraphTitle); - - // Clipping mask for active CFER graph area - this.CFERGraphClipMask = document.createElement('div'); - this.CFERGraphClipMask.className = 'FuelConsumptionCtrlCFERGraphClipMask'; - - // Active graphing area for CFER graph - this.CFERGraphArea = document.createElement('div'); - this.CFERGraphArea.className = 'FuelConsumptionCtrlCFERGraphArea'; - - // Create CFER graph bars - for (var j = 0; j < this._totalCFERBars; j++) { - var curCFERBar = document.createElement('div'); - curCFERBar.id = 'CFERBar' + (j + 1); - //var currentValue = document.createElement('div'); - //currentValue.id = 'CFERBarValueCurrent'; - //currentValue.className = 'FuelConsumptionCtrlCFERBarValueCurrent'; - var CFERBarCap = document.createElement('div'); - CFERBarCap.className = 'FuelConsumptionCtrlCFERBarGraphCap'; - switch (j) - { - case this._newCFERDataIdx: - curCFERBar.className = 'FuelConsumptionCtrlCFERBarGraphCore'; - break; - case this._currentCFERDataIdx: - curCFERBar.className = 'FuelConsumptionCtrlCFERBarGraphCore'; - - //this.CFERCurrentBar = curCFERBar; - break; - default: - curCFERBar.className = 'FuelConsumptionCtrlCFERBarGraphCore'; - break; - } - CFERBarCap.style.marginTop = '-3px'; - curCFERBar.appendChild(CFERBarCap); - this.CFERGraphArea.appendChild(curCFERBar); - } - - this.CFERCurrenBarMask = document.createElement('div'); - this.CFERCurrenBarMask.className = 'FuelConsumptionCtrlCFERBarGraphCurrentMask'; - - var CurrentCFERBarCap = document.createElement('div'); - CurrentCFERBarCap.className = 'FuelConsumptionCtrlCFERBarGraphCap'; - CurrentCFERBarCap.style.marginTop = '-3px'; - - this.CFERCurrentBar = document.createElement('div'); - this.CFERCurrentBar.id = 'CFERBar10'; - this.CFERCurrentBar.className = 'FuelConsumptionCtrlCFERBarGraphCoreCurrent'; - - this.CFERCurrentBar.appendChild(CurrentCFERBarCap); - - this.CFERCurrenBarMask.appendChild(this.CFERCurrentBar); - - // Create a div for the current Graph value and attach to the parent div - this.CFERCurrentBarValue = document.createElement('div'); - this.CFERCurrentBarValue.className = 'FuelConsumptionCtrlCFERCurrentBarValue'; - - // Create a div for text of bar value and attach to CFERCurrentBarValueCFERCurrentBarValue - this.CFERCurrentBarValueText = document.createElement('div'); - this.CFERCurrentBarValueText.className = 'FuelConsumptionCtrlCFERBarValueCurrent'; - this.CFERCurrentBarValueText.id = 'CFERBarValueCurrent'; - this.CFERCurrentBarValue.appendChild(this.CFERCurrentBarValueText); - - // Attach the active graphing area to the CFER graph clip mask - this.CFERGraphClipMask.appendChild(this.CFERGraphArea); - - // Attach the clip mask to the CFER graph - this.CFERGraph.appendChild(this.CFERGraphClipMask); - - // Attach the CFER graph to its parent - this.graphsArea.appendChild(this.CFERGraph); - - /*********************************************************/ - /* Create DOM structure for Avg. Fuel Efficiency display */ - /*********************************************************/ - - // Fuel efficiency top-level DIV - this.fuelEfficiencyArea = document.createElement('div'); - this.fuelEfficiencyArea.className = 'FuelConsumptionCtrlFuelEfficiencyArea'; - - // Fuel efficiency title - this.fuelEfficiencyTitle = document.createElement('h2'); - // Fuel efficiency value display - this.fuelEfficiencyValue = document.createElement('div'); - this.fuelEfficiencyUnit = document.createElement('div'); - this.fuelEfficiencyThisDrive = document.createElement('div'); - - //TODO::Fuel Consumption HEV Style - if(this.properties.ctrlStyle === "hevstyle"){ - this.fuelEfficiencyTitle.className = 'FuelConsumptionCtrlFuelEfficiencyTitleHev'; - this.fuelEfficiencyThisDrive.className = 'FuelConsumptionCtrlFuelEfficiencyThisDriveHev'; - this.fuelEfficiencyValue.className = 'FuelConsumptionCtrlFuelEfficiencyValueHev'; - this.fuelEfficiencyUnit.className = 'FuelConsumptionCtrlFuelEfficiencyUnitHev'; - //Fuel efficiency HR region - this.fuelEfficiencyHevDivider = document.createElement("div"); - this.fuelEfficiencyHevDivider.className = 'FuelConsumptionCtrlFuelEfficiencyHevDivider'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevDivider); - - //Fuel Efficiency OneDrive Title - this.fuelEfficiencyHevOneDriveTitle = document.createElement("div"); - this.fuelEfficiencyHevOneDriveTitle.className = 'FuelConsumptionCtrlHevOneDriveText'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevOneDriveTitle); - this.properties.oneDriveText = - this._translateString(this.properties.oneDriveTextId, - this.properties.oneDriveText, - this.properties.subMap); - this.fuelEfficiencyHevOneDriveTitle.innerHTML = this.properties.oneDriveText; - - //Fuel Efficiency EVDistance Title - this.fuelEfficiencyHevEVDistanceTitle = document.createElement("div"); - this.fuelEfficiencyHevEVDistanceTitle.className = 'FuelConsumptionCtrlHevEVDistanceText'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevEVDistanceTitle); - this.properties.evDistanceText = - this._translateString(this.properties.evDistanceTextId, - this.properties.evDistanceText, - this.properties.subMap); - this.fuelEfficiencyHevEVDistanceTitle.innerHTML = this.properties.evDistanceText; - - //Fuel Efficiency Distance Value - this.fuelEfficiencyHevDistanceValue = document.createElement("div"); - this.fuelEfficiencyHevDistanceValue.className = 'FuelConsumptionCtrlHevDistanceValue'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevDistanceValue); - - //Fuel Efficiency Distance Unit - this.fuelEfficiencyHevDistanceUnit = document.createElement("div"); - this.fuelEfficiencyHevDistanceUnit.className = 'FuelConsumptionCtrlHevDistanceUnit'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevDistanceUnit); - - //Fuel Efficiency Percent Value - this.fuelEfficiencyHevPercentValue = document.createElement("div"); - this.fuelEfficiencyHevPercentValue.className = 'FuelConsumptionCtrlHevPercentValue'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevPercentValue); - - // 20 special case for HEV - - this.halfKmLabel1 = document.createElement('div'); - this.halfKmLabel1.className = 'FuelConsumptionCtrlHalfWayLabel1'; - this.halfKmLabel1.innerHTML = '20'; - - this.halfKmLabel2 = document.createElement('div'); - this.halfKmLabel2.className = 'FuelConsumptionCtrlHalfWayLabel2'; - this.halfKmLabel2.innerHTML = '20'; - - this.divElt.appendChild(this.halfKmLabel1); - this.divElt.appendChild(this.halfKmLabel2); - } - else{ - this.fuelEfficiencyTitle.className = 'FuelConsumptionCtrlFuelEfficiencyTitle'; - this.fuelEfficiencyThisDrive.className = 'FuelConsumptionCtrlFuelEfficiencyThisDrive'; - this.fuelEfficiencyValue.className = 'FuelConsumptionCtrlFuelEfficiencyValue'; - this.fuelEfficiencyUnit.className = 'FuelConsumptionCtrlFuelEfficiencyUnit'; - } - - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyTitle); - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyThisDrive); - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyValue); - - // create container for disc value indicator - if(this.properties.ctrlStyle === 'hevstyle') - { - this.oneDiscValue = document.createElement('div'); - this.oneDiscValue.className = 'FuelConsumptionCtrlOneDiscValue'; - - this.properties.whText = - this._translateString(this.properties.whUnitId, - this.properties.whText, - this.properties.subMap); - this.oneDiscValue.innerHTML = '=30'+this.properties.whText; - this.oneDiscImage = document.createElement('div'); - this.oneDiscImage.className = 'FuelConsumptionCtrlOneDiscIndicator'; - - this.divElt.appendChild(this.oneDiscValue); - this.divElt.appendChild(this.oneDiscImage); - } - - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyUnit); - - // Add graphs area to control's top-level container - this.divElt.appendChild(this.graphsArea); - - // Add fuel efficiency area to control's top-level container - this.divElt.appendChild(this.fuelEfficiencyArea); - this.divElt.appendChild(this.CFERCurrentBarValue); - this.divElt.appendChild(this.CFERCurrenBarMask); - // Attach control to parent - this.parentDiv.appendChild(this.divElt); - this.parentDiv.appendChild(this.umpPanelDiv); - - var umpConfig = { - "buttonConfig" : this.properties['umpButtonConfig'], - "defaultSelectCallback" : this.properties['defaultSelectCallback'], - "defaultLongPressCallback" : this.properties['defaultLongPressCallback'], - "defaultScrubberCallback" : this.properties['defaultScrubberCallback'], - "defaultHoldStartCallback" : this.properties['defaultHoldStartCallback'], - "defaultHoldStopCallback" : this.properties['defaultHoldStopCallback'], - "umpStyle" : this.properties['umpStyle'], - "hasScrubber" : this.properties['hasScrubber'], - "scrubberConfig" : this.properties['scrubberConfig'], - "retracted" : true - }; - //@formatter:on - log.debug("Instantiating umpCtrl..."); - this.umpCtrl = framework.instantiateControl(this.uiaId, this.umpPanelDiv, "Ump3Ctrl", umpConfig); - - // "Switch View" button control - //@formatter:off - var btnInstanceProperties = - { - "selectCallback" : this._switchViewButtonHandler.bind(this), - "enabledClass" : "FuelConsumptionCtrlSwitchView", - "disabledClass" : null, - "focusedClass": null, - "downClass" : "FuelConsumptionCtrlSwitchViewDown", - "heldClass" : null, - "appData" : this.properties.appData, - "label" : this.properties.switchViewLabelText, - "labelId" : this.properties.switchViewLabelId, - "subMap" : this.properties.subMap, - }; - //@formatter:on - if(this.properties.mode !== 'ending' ) - { - this._switchViewButtonCtrl = framework.instantiateControl(this.uiaId, - this.fuelEfficiencyArea, - "ButtonCtrl", - btnInstanceProperties); - } - - - this._init(); -} - - -/****************************************/ -/* Translation & text utility functions */ -/****************************************/ - -/* - * Utility function to look up a translatable string ID and/or accept a default text string. - */ -FuelConsumptionCtrl.prototype._translateString = function(strId, strText, subMap) -{ -// log.debug("_translateString called: strId = " + strId + ", strText = " + strText); - - var translatedText = null; - - if (strId) - { - translatedText = framework.localize.getLocStr(this.uiaId, strId, subMap); - } - else if (strText) - { - translatedText = strText; - } - - return translatedText; -} - -/* - * Utility function to make a text string suitable for HTML block-rendering - */ -FuelConsumptionCtrl.prototype._stringToHTML = function(textStr) -{ -// log.debug("_stringToHTML called: textStr = " + textStr); - - var htmlText; - - if (textStr) - { - htmlText = textStr + "
    "; - } - else - { - htmlText = ""; - } - - return htmlText; -} - - -/*********************************************************/ -/* Utility functions for the CDFE graph & its animations */ -/*********************************************************/ - -/* - * Utility function to add axis labels to the CDFE graph - */ -FuelConsumptionCtrl.prototype._addCDFEGraphAxisLabels = function(xDiv, yDiv) -{ -// log.debug("FuelConsumptionCtrl: _addCDFEGraphAxisLabels() called..."); - - // NOTE: We're assuming 15 labels. Should this change, - // we'd need to revisit this - var barVal = 60; - for (var i = 0; i < 6; i++) - { - var barLabel = document.createElement('span'); - barLabel.innerHTML = barVal; - barLabel.style.position = 'absolute'; - barLabel.style.left = this._CSSConstants["CDFEGraphBarMarginRight"] + - (i * (this._CSSConstants["CDFEGraphBarWidthRight"] + - this._CSSConstants["CDFEGraphBarSpacingRight"]) - 18) + 'px'; - barLabel.style.width = this._CSSConstants["CDFEGraphBarWidthRight"] + 'px'; - xDiv.appendChild(barLabel); - barVal -= 10; - } - - var barLabel = document.createElement('span'); - barLabel.innerHTML = (this._totalCDFEBarsRight - 1); - barLabel.style.position = 'absolute'; - barLabel.style.left = this._CSSConstants["CDFEGraphBarMarginRight"] + - (8 * (this._CSSConstants["CDFEGraphBarWidthRight"] )+ - this._CSSConstants["CDFEGraphBarSpacingRight"] - 19) + 'px'; - barLabel.style.width = this._CSSConstants["CDFEGraphBarWidthRight"] + 'px'; - xDiv.appendChild(barLabel); - - - this.yLimitValueLabelCDFE = document.createElement('span'); - this.yLimitValueLabelCDFE.innerHTML = this.properties.currentFuelConfig.yAxisLimitValue; - yDiv.appendChild(this.yLimitValueLabelCDFE); - - var yUnitLabel = document.createElement('span'); - yUnitLabel.style.position = 'absolute'; - yUnitLabel.style.width = '100px'; - yUnitLabel.style.top = '90px'; - - var yZeroLabel = document.createElement('span'); - this.properties.currentFuelConfig.yAxisLabelText = - this._translateString(this.properties.currentFuelConfig.yAxisLabelId, - this.properties.currentFuelConfig.yAxisLabelText, - this.properties.subMap); - yUnitLabel.innerHTML = this.properties.currentFuelConfig.yAxisLabelText; - var xAxisLabelMinuteText = this._translateString(this.properties.xAxisLabelMinuteId, - this.properties.xAxisLabelMinuteText, this.properties.subMap); - - yZeroLabel.innerHTML = '0'+xAxisLabelMinuteText; - yZeroLabel.style.position = 'absolute'; - yZeroLabel.style.width = '60px'; - yZeroLabel.style.top = '115px'; - yZeroLabel.style.left = '466px'; - this.yZeroLabelCDFE = yUnitLabel; - yDiv.appendChild(yUnitLabel); - yDiv.appendChild(yZeroLabel); -} - -/* - * Utility function to set the horizontal positions of the CDFE graph bars - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarPositions = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarPositions() called..."); - - var leftInc = this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]; - var currentLeft = this._CSSConstants["CDFEGraphBarMargin"]; - - for (var i = 1; i <= this._totalCDFEBars; i++) - { - var bar = document.getElementById('CDFEBar' + i); - if (bar) - { - bar.style.left = currentLeft + 'px'; - } - - - // Adding new disc logic for hevstyle - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + i); - if(disc) - { - disc.style.left = currentLeft + 'px'; - } - } - - currentLeft += leftInc; - } -} -/**********************************New Defination of function**********************************/ - -FuelConsumptionCtrl.prototype._setCDFEGraphBarPositionsRight = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarPositions() called..."); - - var leftIncRight = this._CSSConstants["CDFEGraphBarWidthRight"] + - this._CSSConstants["CDFEGraphBarSpacingRight"]; - var currentLeftMarginRight = this._CSSConstants["CDFEGraphBarMarginRight"]; - - for (var i = 1; i <= this._totalCDFEBarsRight; i++) - { - var barRight = document.getElementById('CDFEBarRight' + i); - if (barRight) - { - barRight.style.left = currentLeftMarginRight + 'px'; - } - - // Adding new disc logic for hevstyle - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBarRight' + i); - if(disc) - { - disc.style.left = currentLeftMarginRight + 'px'; - } - } - - currentLeftMarginRight += leftIncRight; - } -} - -/**********************************End of New Defination of function**********************************/ -/* - * Utility function to enable/disable fade transitions for the CDFE line graph - */ -FuelConsumptionCtrl.prototype._setCDFELineGraphFadeTransitions = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCDFELineGraphFadeTransitions() called: isEnabled = " + isEnabled); - - var lineGraphCanvas = document.getElementById('FuelConsumptionCtrlCDFELineGraphCanvas'); - if (lineGraphCanvas) - { - var transitionStr; - - if (isEnabled) - { - log.debug (' enabling canvas opacity transition'); - transitionStr = 'opacity 0.6s linear 0s'; - } - else - { - log.debug (' disabling canvas opacity transition'); - transitionStr = 'none'; - } - - lineGraphCanvas.style.OTransition = transitionStr; - } -} - -/* - * Utility function to enable/disable height transitions for the CDFE graph bars - * (except the "hidden" new value bar) - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightTransitions = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeightTransitions() called: isEnabled = " + isEnabled); - - var transitionStr; - - // TODO: Figure out why this needs to be backwards to work! - if (!isEnabled) - { - transitionStr = 'height 0.6s ease 0s'; - } - else - { - transitionStr = 'none'; - } - - for (var i = 0; i <= this._youngestCDFEDataIdx; i++) - { - var bar = document.getElementById('CDFEBar' + (i + 1)); - if (bar) - { - bar.style.OTransition = transitionStr; - } - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + (i + 1)); - if (disc) - { - disc.style.OTransition = transitionStr; - } - } - } -} - -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightTransitionsRight = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeightTransitions() called: isEnabled = " + isEnabled); - - var transitionStr; - - // TODO: Figure out why this needs to be backwards to work! - if (!isEnabled) - { - transitionStr = 'height 0.6s ease 0s'; - } - else - { - transitionStr = 'none'; - } - - for (var i = 0; i <= this._youngestCDFEDataIdxRight; i++) - { - var bar = document.getElementById('CDFEBarRight' + (i + 1)); - if (bar) - { - bar.style.OTransition = transitionStr; - } - - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBarRight' + (i + 1)); - if (disc) - { - disc.style.OTransition = transitionStr; - } - } - } -} - - - -/* - * Utility function to set the height of a single CDFE graph bar (e.g. the just-inserted one) - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeight = function(barIdx,HEVMode) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CDFEBar' + (barIdx + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CDFEGraphVisibleHeight"], - this._CDFEGraphBarValues[barIdx], - this.properties.currentFuelConfig.yAxisLimitValue, - false) + 'px'; - - - } - - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + (barIdx + 1)); - if (disc) - { - /*disc.style.height = this._scaleDataToGraphY(this._CSSConstants["CDFEGraphVisibleHeight"], - this._CDFEDiscValues[barIdx], - this.properties.currentFuelConfig.yAxisLimitValue, - false) + 'px';*/ - if(HEVMode) - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreenHighLighted'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrentGreenHighLighted'; - } - else - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - } - disc.style.height = this._CDFEDiscValues[barIdx]+'px'; - - } - } -} - - -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightRight = function(barIdx) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CDFEBarRight' + (barIdx + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CDFEGraphVisibleHeightRight"], - this._CDFEGraphBarValuesRight[barIdx], - this.properties.currentFuelConfig.yAxisLimitValue, - false) + 'px'; - } -} - -/* - * Utility function to set the heights of all of the CDFE graph bars - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeights = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeights() called..."); - - // Cache reused values - var graphHeight = this._CSSConstants["CDFEGraphVisibleHeight"]; - var yLimit = this.properties.currentFuelConfig.yAxisLimitValue; - - for (var i = 0; i < this._totalCDFEBars; i++) - { - var bar = document.getElementById('CDFEBar' + (i + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphBarValues[i], - yLimit, - false) + 'px'; - } - - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + (i + 1)); - if (disc) - { - /*disc.style.height = this._scaleDataToGraphY(graphHeight, - this._CDFEDiscValues[i], - yLimit, - false) + 'px'; */ - disc.style.height = this._CDFEDiscValues[i]+'px'; - } - } - } -} - -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightsRight = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeights() called..."); - - // Cache reused values - var graphHeight = this._CSSConstants["CDFEGraphVisibleHeightRight"]; - var yLimit = this.properties.currentFuelConfig.yAxisLimitValue; - - for (var i = 0; i < this._totalCDFEBarsRight; i++) - { - var bar = document.getElementById('CDFEBarRight' + (i + 1)); - - if (bar) - { - bar.style.height = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphBarValuesRight[i], - yLimit, - false) + 'px'; - } - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBarRight' + (i + 1)); - if (disc) - { - disc.style.height = this._CDFEDiscBarValuesRight[i]+ 'px'; - } - } - } -} - -/* - * Utility function to render an interval of the CDFE line graph, using a canvas overlay - */ -FuelConsumptionCtrl.prototype._drawCDFELineGraphInterval = function(startIdx, endIdx, clearCanvas) -{ -// log.debug("FuelConsumptionCtrl: _drawCDFELineGraphInterval() called..."); - - if ((typeof(startIdx) === 'number') && - (typeof(endIdx) === 'number') && - (startIdx < endIdx) && - (startIdx >= 0) && - (endIdx < this._totalCDFEBars)) - { - // Horizontal distance between bar centers - var barInterval = this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]; - - // Center of leftmost (oldest) bar in interval - var leftX = (this._CSSConstants["CDFEGraphBarSpacing"] + - (this._CSSConstants["CDFEGraphBarWidth"] / 2)) + - (barInterval * startIdx); - - // Center of next bar - var rightX = leftX + barInterval; - var leftY; - var rightY; - - // Constants - var graphHeight = this._CSSConstants["CDFEGraphVisibleHeight"]; - var yLimit = this.properties.currentFuelConfig.yAxisLimitValue; - - // Reset the canvas (if needed) - if (clearCanvas) - { - this.CDFELineGraphCanvas.width = this.CDFELineGraphCanvas.width; - } - - // Set up for drawing - this._CDFELineGraphCanvasDC.lineWidth = 2; - this._CDFELineGraphCanvasDC.beginPath(); - this._CDFELineGraphCanvasDC.strokeStyle = "#00CC00"; - - // Initialize leftY & rightY - if (this._CDFEGraphLineValues[startIdx]) - { - leftY = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphLineValues[startIdx], - yLimit, - true); - } - else - { - leftY = null; - } - - for (var i = startIdx + 1; i <= endIdx; i++) - { - // Scale value as rightY - if (this._CDFEGraphLineValues[i]) - { - rightY = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphLineValues[i], - yLimit, - true); - } - else - { - rightY = null; - } - - // If we have both endpoints, ... - if (leftY && rightY) - { - // ... draw the line segment between them - this._CDFELineGraphCanvasDC.moveTo(leftX, leftY); - this._CDFELineGraphCanvasDC.lineTo(rightX, rightY); - } - - // Advance to next value - leftY = rightY; - leftX = rightX; - rightX += barInterval; - } - - // Stroke the path - this._CDFELineGraphCanvasDC.stroke(); - } -} - -/* - * Shortcut utility function to render the entire CDFE line graph - */ -FuelConsumptionCtrl.prototype._drawCDFELineGraph = function() -{ -// log.debug("FuelConsumptionCtrl: _drawCDFELineGraph() called..."); - - this._drawCDFELineGraphInterval(0, this._newCDFEDataIdx, true); -} - -/* - * Utility function for resetting the CDFE graph - * (redraw it with the "new" bar hidden on the right-hand side) - */ -// -FuelConsumptionCtrl.prototype._resetCDFEGraph = function(animateBars) -{ -// log.debug("FuelConsumptionCtrl: _resetCDFEGraph() called: animateBars = " + animateBars); - - // Make sure left transitions are OFF for the CDFE graph active area while we redraw it - this.CDFEGraphArea.style.OTransition = 'none'; - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphArea.style.OTransition = 'none'; - } - - // Enable/disable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitions(animateBars); - if(this.properties.ctrlStyle === 'hevstyle') - { - - for(var i = 0; i <= 10; i++) - { - var bar = document.getElementById('CDFEBar'+(i+1)); - var disc = document.getElementById('CDFEDiscBar' +(i+1)); - if(this._initialEVMode[i] && bar) - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreen'; - disc.className = 'FuelConsumptionCtrlHevCDFEDiscBg_Green'; - if(i == 9) - { - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrentGreenHighLighted'; - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreenHighLighted'; - break; - } - - } - else - { - if(i == 9 || i == 10) - { - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - } - else - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - } - } - } - } - else - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - } - // Reposition the CDFE graph active area & reconstruct the bar/line graph - // (should be no visible difference afterwards) - this.CDFEGraphArea.style.left = '0px'; - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphArea.style.left = '0px'; - } - this._setCDFEGraphBarHeights(); - - - // Disable/enable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitions(!animateBars); -} - -FuelConsumptionCtrl.prototype._resetCDFEGraphRight = function(animateBars) -{ -// log.debug("FuelConsumptionCtrl: _resetCDFEGraph() called: animateBars = " + animateBars); - - // Make sure left transitions are OFF for the CDFE graph active area while we redraw it - this.CDFEGraphAreaRight.style.OTransition = 'none'; - - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphAreaRight.style.OTransition = 'none'; - } - - // Enable/disable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitionsRight(animateBars); - - if(this.properties.ctrlStyle === 'hevstyle') - { - for(var i = 0; i < 5; i++) - { - var bar = document.getElementById('CDFEBarRight'+(i+1)); - var disc = document.getElementById('CDFEDiscBarRight' +(i+1)); - if(this._CDFEEvModeRight[i] && bar) - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreGreenRight'; - disc.className = 'FuelConsumptionCtrlHevCDFEDiscGraphCoreGreenRight'; - } - else - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreRight'; - disc.className = 'FuelConsumptionCtrlHevCDFEDiscGraphCoreRight'; - } - } - } - - - // Reposition the CDFE graph active area & reconstruct the bar/line graph - // (should be no visible difference afterwards) - this.CDFEGraphAreaRight.style.left = '0px'; - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphAreaRight.style.left = '0px'; - } - this._setCDFEGraphBarHeightsRight(); - - // Disable/enable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitionsRight(!animateBars); -} - -/* - * Callback function for removing the animation on the CDFE line graph at the end of its fade-in - */ -FuelConsumptionCtrl.prototype._onCDFELineFadeAnimationEnd = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCDFELineFadeAnimationEnd() called"); - - // Remove the event listener that got us here - this.CDFELineGraphCanvas.removeEventListener('oTransitionEnd', this._cbCDFELineFadeAnimationEnd, false); - - // Stop propagating the event - e.stopPropagation(); - - // Disable the line graph fade animation - this._setCDFELineGraphFadeTransitions(false); -} - -/* - * Callback function for resetting the CDFE graph at the end of a slide-left (insertion) animation - */ -FuelConsumptionCtrl.prototype._onCDFELeftAnimationEnd = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCDFELeftAnimationEnd() called..."); - - // Remove the event listener that got us here - this.CDFEGraphArea.removeEventListener('oTransitionEnd', this._cbCDFELeftAnimationEnd, false); - - // Stop propagating the event - e.stopPropagation(); - - // We're no longer in the transition - this._CDFELineGraphInTransition = false; - - // Reset the CDFE graph without bar animations - this._resetCDFEGraph(false); -} - - -/************************************ New Function Added************************************************/ -FuelConsumptionCtrl.prototype._onCDFELeftAnimationEndRight = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCDFELeftAnimationEndRight() called..."); - - // Remove the event listener that got us here - this.CDFEGraphAreaRight.removeEventListener('oTransitionEnd', this._cbCDFELeftAnimationEndRight, false); - - // Stop propagating the event - e.stopPropagation(); - - // We're no longer in the transition - this._CDFELineGraphInTransition = false; - - // Reset the CDFE graph without bar animations - this._resetCDFEGraph(false); -} -/************************************End of New Function Added************************************************/ - - -/*********************************************************/ -/* Utility functions for the CFER graph & its animations */ -/*********************************************************/ - -/* - * Utility function to add axis labels to the CFER graphadd - */ -FuelConsumptionCtrl.prototype._addCFERGraphAxisLabels = function(xDiv, yDiv) -{ -// log.debug("FuelConsumptionCtrl: _addCFERGraphAxisLabels() called..."); - - var leftInc = this._CSSConstants["CFERGraphBarWidth"] + - this._CSSConstants["CFERGraphBarSpacing"]; - var currentLeft = this._CSSConstants["CFERGraphBarMargin"]; - - for (var i = 0; i <= this._currentCFERDataIdx; i++) - { - var span = document.createElement('span'); - - span.style.position = 'absolute'; - span.style.left = currentLeft + 'px'; - span.style.width = this._CSSConstants["CFERGraphBarWidth"] + 'px'; - span.style.textAlign = 'center'; - - if (i === (this._currentCFERDataIdx - 1)) - { - this.properties.cumulativeFuelConfig.xAxisLabelText = - this._translateString(this.properties.cumulativeFuelConfig.xAxisLabelId, - this.properties.cumulativeFuelConfig.xAxisLabelText, - this.properties.subMap); - span.innerHTML = this._stringToHTML(this.properties.cumulativeFuelConfig.xAxisLabelText); - span.style.marginLeft = '-8px'; - span.style.width = '71px'; - } - else - { - if(i != this._currentCFERDataIdx) - { - span.innerHTML = (this._currentCFERDataIdx - i) + ''; - } - - } - - - currentLeft += leftInc; - xDiv.appendChild(span); - } - - - this.yLimitValueLabelCFER = document.createElement('span'); - this.yLimitValueLabelCFER.innerHTML = this.properties.cumulativeFuelConfig.yAxisLimitValue; - yDiv.appendChild(this.yLimitValueLabelCFER); - - var yZeroLabel = document.createElement('span'); - this.properties.cumulativeFuelConfig.yAxisLabelText = - this._translateString(this.properties.cumulativeFuelConfig.yAxisLabelId, - this.properties.cumulativeFuelConfig.yAxisLabelText, - this.properties.subMap); - yZeroLabel.innerHTML = this._stringToHTML(this.properties.cumulativeFuelConfig.yAxisLabelText); - yZeroLabel.style.position = 'absolute'; - yZeroLabel.style.width = '60px'; - if(this.properties.ctrlStyle === "hevstyle") - { - yZeroLabel.style.top = '90px'; - } - else - { - yZeroLabel.style.top = (this._CSSConstants["CFERGraphVisibleHeight"] - 47) + 'px'; - } - this.yZeroLabelCFER = yZeroLabel; - yDiv.appendChild(yZeroLabel); -} - -/* - * Utility function to set the horizontal positions of the CFER graph bars - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarPositions = function() -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarPositions() called..."); - - var leftInc = this._CSSConstants["CFERGraphBarWidth"] + - this._CSSConstants["CFERGraphBarSpacing"]; - var currentLeft = this._CSSConstants["CFERGraphBarMargin"]; - - for (var i = 1; i <= this._totalCFERBars; i++) - { - var bar = document.getElementById('CFERBar' + i); - if (bar) - { - bar.style.left = currentLeft + 'px'; - } - - currentLeft += leftInc; - } -} - -/* - * Utility function to enable/disable height transitions for the CFER graph bars - * (except the "hidden" new value bar) - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarHeightTransitions = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeightTransitions() called: isEnabled = " + isEnabled); - - var transitionStr; - - // TODO: Figure out why this needs to be backwards to work! - if (!isEnabled) - { - transitionStr = "height 0.6s ease 0s"; - } - else - { - transitionStr = "none"; - } - - for (var i = 0; i <= this._currentCFERDataIdx; i++) - { - var bar = document.getElementById('CFERBar' + (i + 1)); - if (bar) - { - bar.style.OTransition = transitionStr; - if(i==5) - { - bar.style.OTransition = "none"; - } - } - } -} - -/* - * Utility function to set the height of single CFER graph bar (e.g. the just-inserted one) - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarHeight = function(barIdx) -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CFERBar' + (barIdx + 1)); - if (bar) - { - - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CFERGraphVisibleHeight"], - this._CFERGraphBarValues[barIdx], - this.properties.cumulativeFuelConfig.yAxisLimitValue, - false) + 'px'; - - } -} - -FuelConsumptionCtrl.prototype._setCFERGraphBarHeightNew = function(barIdx) -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CFERBar' + (barIdx + 1)); - if (bar) - { - - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CFERGraphVisibleHeight"], - this._CFERGraphBarValues[barIdx + 1], - this.properties.cumulativeFuelConfig.yAxisLimitValue, - false) + 'px'; - - // Set the height of the current bar value to retain its display positioon on top of current bar - this.CFERCurrentBarValue.style.height = this._scaleDataToGraphY(this._CSSConstants["CFERGraphVisibleHeight"], - this._CFERGraphBarValues[barIdx + 1], - this.properties.cumulativeFuelConfig.yAxisLimitValue, - false) + 'px'; - } -} - - - -/* - * Utility function to set the heights of all of the CFER graph bars - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarHeights = function() -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeights() called..."); - - // Cache reused values - var graphHeight = this._CSSConstants["CFERGraphVisibleHeight"]; - var yLimit = this.properties.cumulativeFuelConfig.yAxisLimitValue; - - for (var i = 0; i < this._totalCFERBars; i++) - { - var bar = document.getElementById('CFERBar' + (i + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(graphHeight, - this._CFERGraphBarValues[i], - yLimit, - false) + 'px'; - } - } -} - -/* - * Utility function for resetting the CFER graph - * (redraw it with the "new" bar hidden on the right-hand side) - */ -FuelConsumptionCtrl.prototype._resetCFERGraph = function(animateBars) -{ -// log.debug("FuelConsumptionCtrl: _resetCFERGraph() called: animateBars = " + animateBars); - - // Make sure left transitions are OFF for the CFER graph active area while we redraw it - this.CFERGraphArea.style.OTransition = 'none'; - - // Enable/disable height transitions for the CFER graph bars - this._setCFERGraphBarHeightTransitions(animateBars); - - // Reposition the CFER graph active area & reconstruct the bar graph - // (should be no visible difference afterwards) - this.CFERGraphArea.style.left = '0px'; - this._setCFERGraphBarHeights(); - - // Disable/enable height transitions for the CFER graph bars - this._setCFERGraphBarHeightTransitions(!animateBars); -} - -/* - * Callback function for resetting the CFER graph at the end of a slide-left (insertion) animation - */ -FuelConsumptionCtrl.prototype._onCFERLeftAnimationEnd = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCFERLeftAnimationEnd() called..."); - - // Remove the event listener that got us here - this.CFERGraphArea.removeEventListener('oTransitionEnd', this._cbCFERLeftAnimationEnd, false); - - // Stop propagating the event - e.stopPropagation(); - - // Reset the CFER graph without bar animations - this._resetCFERGraph(false); -} - - -/***************************/ -/* Other utility functions */ -/***************************/ - -/* - * Utility function to convert a graph's data point to a Y-coordinate - */ -FuelConsumptionCtrl.prototype._scaleDataToGraphY = function(maxY, dataValue, maxDataValue, invertY) -{ -// log.debug("FuelConsumptionCtrl: _scaleDataToGraphY() called: maxY = " + maxY + -// "dataValue = " + dataValue + ", maxDataValue = " + maxDataValue + -// "invertY = " + invertY); - - var yVal = Math.floor(dataValue / maxDataValue * maxY); - - if (invertY) - { - yVal = maxY - yVal; - } - - return yVal; -} - -/* - * Callback for "Switch View" button selections -- when called, trigger the - * configured application callback. - */ -FuelConsumptionCtrl.prototype._switchViewButtonHandler = function(buttonObj, appData, params) -{ -// log.debug("FuelConsumptionCtrl: _onCFERLeftAnimationEnd() called: buttonObj = " + buttonObj + -// ", appData = " + appData + ", params = " + params); - - if (typeof(this.properties.switchViewButtonCallback) === "function") - { - this.properties.switchViewButtonCallback(this, appData, null); - } - else - { - log.warn("FuelConsumptionCtrl: no valid switchViewButtonCallback configured"); - } -} - -/******************/ -/* Public Methods */ -/******************/ - -FuelConsumptionCtrl.prototype.initializeCurrentDriveFuelGraph = function(initialBarValues) -{ - log.debug("FuelConsumptionCtrl: initializeCurrentDriveFuelGraph() called: initialBarValues = " + - initialBarValues); - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdx; ibvIdx++) - { - if (initialBarValues[ibvIdx]) - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = initialBarValues[ibvIdx]; - } - else - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = 0; - } - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraph(true); - -} - -// to initialise the HEV fuel eco bar graph with the disc -FuelConsumptionCtrl.prototype.initialiseHEVFuelGraph = function(initialBarValues, intialDiscValues, initialEVModes, initialHalfDiscs) -{ - - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdx; ibvIdx++) - { - if ((initialBarValues[ibvIdx] !== null) && (initialBarValues[ibvIdx] !== undefined)) - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = initialBarValues[ibvIdx]; - //this._initialHalfDisc[this._youngestCDFEDataIdx - ibvIdx] = initialHalfDiscs[ibvIdx]; - this._initialEVMode[this._youngestCDFEDataIdx - ibvIdx] = initialEVModes[ibvIdx]; - } - else - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = 0; - //this._initialHalfDisc[this._youngestCDFEDataIdx - ibvIdx] = 0; - this._initialEVMode[this._youngestCDFEDataIdx - ibvIdx] = false; - } - if(intialDiscValues) - { - if(initialHalfDiscs[ibvIdx]) - { - this._CDFEDiscValues[this._youngestCDFEDataIdx - ibvIdx] = intialDiscValues[ibvIdx] * 13 + 7; - } - else - { - this._CDFEDiscValues[this._youngestCDFEDataIdx - ibvIdx] = intialDiscValues[ibvIdx] * 13; - } - } - else - { - this._CDFEDiscValues[this._youngestCDFEDataIdx - ibvIdx] = 0; - } - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - this._CDFEDiscValues[this._newCDFEDataIdx] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraph(true); - -} - - -FuelConsumptionCtrl.prototype.initializeCurrentDriveFuelGraphRight = function(initialBarValues) -{ - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdxRight; ibvIdx++) - { - if (initialBarValues[ibvIdx]) - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialBarValues[ibvIdx]; - } - else - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = 0; - } - - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraphRight(true); - -} - -FuelConsumptionCtrl.prototype.initializeHEVCurrentDriveFuelGraphRight = function(initialBarValues, initialLDiscValues, initialHalfDiscs, evModes) -{ - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdxRight; ibvIdx++) - { - //if (initialBarValues[ibvIdx]) - if (typeof(initialBarValues[ibvIdx]) === 'number') - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialBarValues[ibvIdx]; - //if(initialHalfDiscs[ibvIdx]) - if(initialHalfDiscs[ibvIdx]=== true) - { - this._CDFEDiscBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialLDiscValues[ibvIdx] * 13 + 7; - } - else if(initialHalfDiscs[ibvIdx]=== false) - { - this._CDFEDiscBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialLDiscValues[ibvIdx] * 13; - } - this._CDFEEvModeRight[this._youngestCDFEDataIdxRight - ibvIdx] = evModes[ibvIdx]; - } - else - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = 0; - this._CDFEDiscBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = 0; - } - - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = 0; - this._CDFEDiscBarValuesRight[this._newCDFEDataIdxRight] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraphRight(true); -} - - -FuelConsumptionCtrl.prototype.insertCurrentDriveFuelGraph = function(currentBarValue) -{ - log.debug("FuelConsumptionCtrl: insertCurrentDriveFuelGraph() called: currentBarValue = " + - currentBarValue); - - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = currentBarValue; - } - else - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - } - - - // Update the new value's bar in the CDFE graph - this._setCDFEGraphBarHeight(this._newCDFEDataIdx); - - - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - - // Turn on left transitions for the CDFE graph (for the next animation) - this.CDFEGraphArea.style.OTransition = 'left 0.6s ease 0s'; - - - // Attach an event listener to the CDFE graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CDFEGraphArea.addEventListener('oTransitionEnd', this._cbCDFELeftAnimationEnd, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CDFEGraphArea.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]) + 'px'; - this._CDFELineGraphInTransition = true; - - // Update the data sets to discard the oldest historical data - for (var i = 0; i <= this._youngestCDFEDataIdx; i++) - { - this._CDFEGraphBarValues[i] = this._CDFEGraphBarValues[i + 1]; - } - - // Re-initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; -} - -// inser new bar graph for HEV disc bars -FuelConsumptionCtrl.prototype.insertHEVFuelGraph = function(currentBarValue, currentDiscs, currentHEVMode, currentHalfDisc) -{ - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = currentBarValue; - //if(currentHalfDisc) - if(currentHalfDisc===true) - { - this._CDFEDiscValues[this._newCDFEDataIdx] = currentDiscs * 13 + 7; - } - else if(currentHalfDisc===false) - { - this._CDFEDiscValues[this._newCDFEDataIdx] = currentDiscs * 13; - } - this._initialEVMode[this._newCDFEDataIdx] = currentHEVMode; - } - else - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - this._CDFEDiscValues[this._newCDFEDataIdx] = 0; - this._initialEVMode[this._newCDFEDataIdx] = false; - } - - if(currentHEVMode) - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreen'; - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEDiscBg_Green'; - } - else - { - // this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - // this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - } - // Update the new value's bar in the CDFE graph - this._setCDFEGraphBarHeight(this._newCDFEDataIdx,currentHEVMode); - - // Turn on left transitions for the CDFE graph (for the next animation) - this.CDFEGraphArea.style.OTransition = 'left 0.6s ease 0s'; - this.CDFEDiscGraphArea.style.OTransition = 'left 0.6s ease 0s'; - - // Attach an event listener to the CDFE graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CDFEGraphArea.addEventListener('oTransitionEnd', this._cbCDFELeftAnimationEnd, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CDFEGraphArea.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]) + 'px'; - - this.CDFEDiscGraphArea.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]) + 'px'; - - this._CDFELineGraphInTransition = true; - // Update the data sets to discard the oldest historical data - for (var i = 0; i <= this._youngestCDFEDataIdx; i++) - { - this._CDFEGraphBarValues[i] = this._CDFEGraphBarValues[i + 1]; - this._CDFEDiscValues[i] = this._CDFEDiscValues[i + 1]; - this._initialEVMode[i] = this._initialEVMode[i+1]; - } - - //if(currentHEVMode) - if(this._initialEVMode[8]) - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreen'; - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEDiscBg_Green'; - } - else - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - } - // Re-initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - this._CDFEDiscValues[this._newCDFEDataIdx] = 0; -} - - -FuelConsumptionCtrl.prototype.insertCurrentDriveFuelGraphRight = function(currentBarValue) -{ - log.debug("FuelConsumptionCtrl: insertCurrentDriveFuelGraph() called: currentBarValue = " + - currentBarValue + ", currentLineValue = "); - - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = currentBarValue; - } - else - { - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = 0; - } - - // Update the new value's bar in the CDFE graph - this._setCDFEGraphBarHeightRight(this._newCDFEDataIdxRight); - - // Turn on left transitions for the CDFE graph (for the next animation) - this.CDFEGraphAreaRight.style.OTransition = 'left 0.6s ease 0s'; - - // Attach an event listener to the CDFE graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CDFEGraphAreaRight.addEventListener('oTransitionEnd', this._cbCDFELeftAnimationEndRight, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CDFEGraphAreaRight.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidthRight"] + - this._CSSConstants["CDFEGraphBarSpacingRight"]) + 'px'; - - // Update the data sets to discard the oldest historical data - for (var i = 0; i <= this._youngestCDFEDataIdxRight; i++) - { - this._CDFEGraphBarValuesRight[i] = this._CDFEGraphBarValuesRight[i + 1]; - } - - // Re-initialize the "hidden" slot for new data - this._CDFEGraphBarValuesRight[this._newCDFEDataIdx] = 0; -} - -FuelConsumptionCtrl.prototype.initializeCumulativeFuelGraph = function(initialBarValues) -{ - log.debug("FuelConsumptionCtrl: initializeCumulativeFuelGraph() called: initialBarValues = " + - initialBarValues); - - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CFERGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCFERDataIdx; ibvIdx++) - { - if (initialBarValues[ibvIdx]) - { - this._CFERGraphBarValues[this._youngestCFERDataIdx - ibvIdx] = initialBarValues[ibvIdx]; - } - else - { - this._CFERGraphBarValues[this._youngestCFERDataIdx - ibvIdx] = 0; - } - } - - // Initialize the "hidden" slot for new data - this._CFERGraphBarValues[this._newCFERDataIdx] = 0; - } - - // Initialize the CFER graph with bar animations - this._resetCFERGraph(true); -} - -FuelConsumptionCtrl.prototype.insertCurrentCumulativeFuelGraph = function(newResetValue) -{ - var currentBarValue = 0.0; - this._cumulativeBarValue = '0.0'; - this.updateCurrentCumulativeFuelGraph(currentBarValue); - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CFERGraphBarValues[this._newCFERDataIdx] = newResetValue; - } - else - { - this._CFERGraphBarValues[this._newCFERDataIdx] = 0.0; - } - - // Update the new value's bar in the CFER graph - this._setCFERGraphBarHeight(this._newCFERDataIdx); - - // Turn on left transitions for the CFER graph (for the next animation) - this.CFERGraphArea.style.OTransition = 'left 0.6s ease 0s'; - - // Attach an event listener to the CFER graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CFERGraphArea.addEventListener('oTransitionEnd', this._cbCFERLeftAnimationEnd, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CFERGraphArea.style.left = '-' + (this._CSSConstants["CFERGraphBarWidth"] + - this._CSSConstants["CFERGraphBarSpacing"]) + 'px'; - - // Update the data set to discard the oldest historical data - for (var i = 0; i <= this._currentCFERDataIdx; i++) - { - this._CFERGraphBarValues[i] = this._CFERGraphBarValues[i + 1]; - } - - // Re-initialize the "hidden" slot for new data - this._CFERGraphBarValues[this._newCFERDataIdx] = 0; -} - -FuelConsumptionCtrl.prototype.updateCurrentCumulativeFuelGraph = function(currentBarValue, unitRange) -{ - log.debug("FuelConsumptionCtrl: updateCurrentCumulativeFuelGraph() called: currentBarValue = " + - currentBarValue); - - // Save the current bar value - var tempNumber = currentBarValue; - - if(currentBarValue == null) - { - currentBarValue = 0; - tempNumber = '--.-'; - } - else if( currentBarValue == 0) - { - tempNumber = '0.0'; - } - - currentBarValue = parseFloat(currentBarValue); - this._cumulativeBarValue = tempNumber; - - // Check if current bar value exceeds the unit range - if(currentBarValue > unitRange) - { - currentBarValue = unitRange; - } - - if (typeof(currentBarValue) === 'number') - { - this._CFERGraphBarValues[10] = currentBarValue; - } - else - { - this._CFERGraphBarValues[10] = 0.0; - tempNumber = '0.0'; - } - - - - var currentValueDiv = document.getElementById("CFERBarValueCurrent"); - currentValueDiv.className = 'FuelConsumptionCtrlCFERBarValueCurrent'; - - currentValueDiv.innerHTML = this._stringToHTML(tempNumber); - // Update the current bar - var bar = document.getElementById('CFERBar' + 10); - if (bar) - { - // Make sure transitions are enabled for the current bar - bar.style.OTransition = 'height 0.6s ease 0s'; - this.CFERCurrentBarValue.style.OTransition = 'height 0.6s ease 0s'; - // Set the bar's height - this._setCFERGraphBarHeightNew(9); - } -} - -FuelConsumptionCtrl.prototype.setFuelEfficiency = function(fuelEfficiencyData) -{ - log.debug("FuelConsumptionCtrl: setFuelEfficiency() called: fuelEfficiency = " + - fuelEfficiencyData.fuelEfficiency + " " + - fuelEfficiencyData.fuelEfficiencyUnit); - - // Purge any "remembered" data - this.properties.fuelEfficiencyData = new Object(); - - if (fuelEfficiencyData && - (fuelEfficiencyData.fuelEfficiency || fuelEfficiencyData.fuelEfficiency == 0) && - fuelEfficiencyData.fuelEfficiencyUnit) - { - // Remember the passed-in data - this.properties.fuelEfficiencyData.fuelEfficiency = fuelEfficiencyData.fuelEfficiency; - this.properties.fuelEfficiencyData.fuelEfficiencyUnit = fuelEfficiencyData.fuelEfficiencyUnit; - - // Translate the fuel efficiency unit (e.g. "MPG" or "KML") into a readable unit string (e.g. "mpg" or "km/L") - var fuelEfficiencyUnitText = this._translateString(this.properties.fuelEfficiencyData.fuelEfficiencyUnit, - this.properties.fuelEfficiencyData.fuelEfficiencyUnit, - this.properties.subMap); - - // Set the displayed data/unit string - // **** Add the fuel efficiency "km/L" - // calculate km/L if the fuel efficiency unit is "L/100km" - if (fuelEfficiencyUnitText == "L/100km") - { - // Prevent Divide-By-Zero Error - if (parseFloat(this.properties.fuelEfficiencyData.fuelEfficiency) > 0) - { - this.fuelEfficiencyValue.innerHTML = this.properties.fuelEfficiencyData.fuelEfficiency + - "
    " + "
    " + "
    " + ((235.214/parseFloat(this.properties.fuelEfficiencyData.fuelEfficiency)).toFixed(1)).toString(); - } - else - { - this.fuelEfficiencyValue.innerHTML = this.properties.fuelEfficiencyData.fuelEfficiency + "
    " + "
    " + "
    " + "0.0"; - } - } - // calculate km/L if the fuel efficiency unit is "mpg" - else - { - this.fuelEfficiencyValue.innerHTML = this.properties.fuelEfficiencyData.fuelEfficiency + - "
    " + "
    " + "
    " + ((parseFloat(this.properties.fuelEfficiencyData.fuelEfficiency)*0.4251).toFixed(1)).toString(); - } - this.fuelEfficiencyUnit.innerHTML = fuelEfficiencyUnitText + "
    " + "
    " + "
    " + "MPG"; - // **** End of the fuel efficiency "km/L" - } - else - { - log.warn("Invalid fuel efficiency data received -- blanking display"); - - this.fuelEfficiencyValue.innerHTML = "--.-"; - this.fuelEfficiencyUnit.innerHTML = ""; - } -} - -FuelConsumptionCtrl.prototype.setEvDrvDistance = function(evObj) -{ - - var driveDisUnit = this._translateString(evObj.unitId, evObj.unitId, this.properties.subMap); - this.fuelEfficiencyHevDistanceUnit.innerHTML = this._stringToHTML(driveDisUnit); - - if(evObj.driveDistance !== null) - { - this.fuelEfficiencyHevDistanceValue.innerHTML = evObj.driveDistance; - } - else - { - this.fuelEfficiencyHevDistanceValue.innerHTML = "--.-" ; - } - - if(evObj.percentValue !== null) - { - this.fuelEfficiencyHevPercentValue.innerHTML = "("+evObj.percentValue+"%)"; - } - else - { - this.fuelEfficiencyHevPercentValue.innerHTML = "(--)" ; - } -} - -FuelConsumptionCtrl.prototype.setUnitInformation = function(obj) -{ - this.properties.cumulativeFuelConfig.yAxisLimitValue = obj.yAxisLimitValue; - this.properties.currentFuelConfig.yAxisLimitValue = obj.yAxisLimitValue; - this.properties.cumulativeFuelConfig.yAxisLabelId = obj.yAxisLabelId; - this.properties.currentFuelConfig.yAxisLabelId = obj.yAxisLabelId; - - this.properties.cumulativeFuelConfig.yAxisLabelText = - this._translateString(this.properties.cumulativeFuelConfig.yAxisLabelId, - this.properties.cumulativeFuelConfig.yAxisLabelText, - this.properties.subMap); - - this.properties.currentFuelConfig.yAxisLabelText = - this._translateString(this.properties.currentFuelConfig.yAxisLabelId, - this.properties.currentFuelConfig.yAxisLabelText, - this.properties.subMap); - - this.yZeroLabelCDFE.innerHTML = this.properties.currentFuelConfig.yAxisLabelText; - this.yLimitValueLabelCDFE.innerHTML = this.properties.currentFuelConfig.yAxisLimitValue; - this.yZeroLabelCFER.innerHTML = '
    ' + this.properties.cumulativeFuelConfig.yAxisLabelText; - this.yLimitValueLabelCFER.innerHTML = this.properties.cumulativeFuelConfig.yAxisLimitValue; -} -/* - * toggle Ump panel | status == "hidePanel" OR status == "showPanel" - */ -FuelConsumptionCtrl.prototype.toggleUmpPanel = function(status) -{ - if(status == "hidePanel") - { - this.umpPanelDiv.className = "UmpPanelDivDisable"; - this.umpCtrl.setRetracted(true); - this._umpPanelStatus = false; - } - else if(status == "showPanel") - { - this.umpPanelDiv.className = "UmpPanelDivEnable"; - this.umpCtrl.setRetracted(false); - this._umpPanelStatus = true; - } - else - { - log.warn("_triggerUmpPanel called with an unxpected argument: "+status); - } -} - -/** - * Context capture - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ - -FuelConsumptionCtrl.prototype.getContextCapture = function() -{ - log.debug("FuelConsumptionCtrl: getContextCapture() called..."); - var controlContextCapture = this.umpCtrl.getContextCapture(); - return controlContextCapture; -}; - - -FuelConsumptionCtrl.prototype.finishPartialActivity = function() -{ - log.debug("FuelConsumptionCtrl: finishPartialActivity() called..."); - this.umpCtrl.finishPartialActivity(); -} - - -/** - * Context restore - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ - -FuelConsumptionCtrl.prototype.restoreContext = function(controlContextCapture) -{ - log.debug("EcoEffectCtrl: restoreContext() "+ controlContextCapture); - this.umpCtrl.restoreContext(controlContextCapture); -}; - - -/* - * Forward all multicontroller events to our only child control, the "SwitchView" button - */ -FuelConsumptionCtrl.prototype.handleControllerEvent = function(eventId) -{ - log.debug("FuelConsumptionCtrl: handleControllerEvent() called: " + eventId); - - // Pass-through - if(this._umpPanelStatus && this.umpCtrl) - { - response = this.umpCtrl.handleControllerEvent(eventId); - return response; - } - else if(!this._umpPanelStatus && this._switchViewButtonCtrl) - { - response = this._switchViewButtonCtrl.handleControllerEvent(eventId); - return response; - } -} - -FuelConsumptionCtrl.prototype.cleanUp = function() -{ - // Clean up the "Switch View" child button control - if (this._switchViewButtonCtrl) - { - this._switchViewButtonCtrl.cleanUp(); - } - if(this.umpCtrl) - { - this.umpCtrl.cleanUp(); - } -} - -framework.registerCtrlLoaded("FuelConsumptionCtrl"); diff --git a/app/files/tweaks/config/aio-app/data_persist/dev/system_restore/restore.sh b/app/files/tweaks/config/aio-app/data_persist/dev/system_restore/restore.sh index 1f0645b..32b51a5 100644 --- a/app/files/tweaks/config/aio-app/data_persist/dev/system_restore/restore.sh +++ b/app/files/tweaks/config/aio-app/data_persist/dev/system_restore/restore.sh @@ -220,7 +220,7 @@ fi rm -f /jci/nng/2 if [ -e /mnt/sd_nav/content/speedcam ] then - # cp -a /mnt/sd_nav/content/speedcam/speedcam.txt ${MYDIR} + # cp /mnt/sd_nav/content/speedcam/speedcam.txt ${MYDIR} # log_message "=== Copied speedcam.txt to USB ===" # rm -f /mnt/sd_nav/content/speedcam/speedcam.txt # rm -f /mnt/sd_nav/content/speedcam/speedcam.spdb diff --git a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/AIO-startup.js b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/AIO-startup.js index 3106c7e..042c79b 100644 --- a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/AIO-startup.js +++ b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/AIO-startup.js @@ -1,3 +1,12 @@ +/* **************************** +** AIO Tweaks App +** Copyright 2019 Trezdog44 + __________________________________________________________________________ + + Filename: AIO-startup.js + __________________________________________________________________________ +*/ +/* jshint -W117 */ var turnScreenOff = false; var turnWifiOn = false; // this is experimental and may not work yet var AIOlonghold = false; diff --git a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/_aiotweaksApp.js b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/_aiotweaksApp.js index 5731fac..efbe455 100644 --- a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/_aiotweaksApp.js +++ b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/_aiotweaksApp.js @@ -1,5 +1,6 @@ -/* -Copyright 2017 Trez +/* **************************** +** AIO Tweaks App +** Copyright 2019 Trezdog44 __________________________________________________________________________ Filename: _aiotweaksApp.js diff --git a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/mzd.js b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/mzd.js index f5ea342..87fd1da 100644 --- a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/mzd.js +++ b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/js/mzd.js @@ -1,10 +1,14 @@ // ***************************** -// ** AIO Tweaks App v0.9 - mzd.js +// ** AIO Tweaks App v1.0 - mzd.js // ** All the functions for Buttons in AIO Tweaks App // ** By Trezdog44 +// __________________________________________________________________________ +// +// Filename: mzd.js +// __________________________________________________________________________ // ***************************** /* jshint -W117 */ -var aioTweaksVer = 0.9; +var aioTweaksVer = 1.0; var AArunning = false; var appListData = []; var globalAIOerror = null; @@ -48,6 +52,7 @@ function StartAIOApp() { $("#systemTab").on("click", settingsSystemTab); $("#wifiSettings").on("click", wifiSettings); $("#runTweaksBtn").on("click", runTweaks); + $("#runRemountBtn").on("click", runRemount); $("#fullRestoreConfirmBtn").on("click", fullSystemRestoreConfirm); $("#headunitLogBtn").on("click", showHeadunitLog); $("#scrollUpBtn").on("click", scrollUp); diff --git a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/templates/AIOTweaks/js/AIOTweaksTmplt.js b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/templates/AIOTweaks/js/AIOTweaksTmplt.js index 484062a..8f60fca 100644 --- a/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/templates/AIOTweaks/js/AIOTweaksTmplt.js +++ b/app/files/tweaks/config/aio-app/jci/gui/apps/_aiotweaks/templates/AIOTweaks/js/AIOTweaksTmplt.js @@ -149,7 +149,7 @@ function AIOTweaksTmplt(uiaId, parentDiv, templateID, controlProperties) { $("
    '; - for (speedo in this.classicTemplate) { + for (var speedo in this.classicTemplate) { this.valuetable += '
    ' + '' + this.classicTemplate[speedo].name; if (this.classicTemplate[speedo].unitClass !== null) { diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_1_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_1_sm.png deleted file mode 100644 index 4d30992..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_2_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_2_sm.png deleted file mode 100644 index 3f95106..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_3_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_3_sm.png deleted file mode 100644 index 5e52aea..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_4_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_4_sm.png deleted file mode 100644 index 9e4e0bc..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackCtr_4_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_1_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_1_sm.png deleted file mode 100644 index bd47164..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_2_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_2_sm.png deleted file mode 100644 index b375348..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_3_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_3_sm.png deleted file mode 100644 index f669169..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackLt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_1_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_1_sm.png deleted file mode 100644 index ca5aad3..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_2_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_2_sm.png deleted file mode 100644 index 44236e7..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_3_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_3_sm.png deleted file mode 100644 index c3fca02..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/BackRt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Background_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Background_sm.png deleted file mode 100644 index 92bcc2f..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Background_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Background_sm_4s.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Background_sm_4s.png deleted file mode 100644 index ab76af5..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Background_sm_4s.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Car_Ds_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Car_Ds_sm.png deleted file mode 100644 index 51005a9..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Car_Ds_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Car_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Car_sm.png deleted file mode 100644 index c2156d6..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/Car_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_1_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_1_sm.png deleted file mode 100644 index ec6f1d3..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_2_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_2_sm.png deleted file mode 100644 index ca04f66..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_3_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_3_sm.png deleted file mode 100644 index 3abfbda..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_4_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_4_sm.png deleted file mode 100644 index 43562ef..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontCtr_4_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_1_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_1_sm.png deleted file mode 100644 index 67d9043..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_2_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_2_sm.png deleted file mode 100644 index 467d6e7..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_3_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_3_sm.png deleted file mode 100644 index 543c590..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontLt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_1_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_1_sm.png deleted file mode 100644 index 9c4ba36..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_2_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_2_sm.png deleted file mode 100644 index 5db74e7..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_3_sm.png b/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_3_sm.png deleted file mode 100644 index e1bdac6..0000000 Binary files a/app/files/tweaks/config/transparent-parking-sensor/jci/nativegui/images/MiniView-transparent/FrontRt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/_videoplayerApp.js b/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/_videoplayerApp.js index 7dc53e7..5997940 100644 --- a/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/_videoplayerApp.js +++ b/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/_videoplayerApp.js @@ -1,3 +1,4 @@ +/* jshint -W117 */ /* Copyright 2016 Herko ter Horst __________________________________________________________________________ diff --git a/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/videoplayer-v3.js b/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/videoplayer-v3.js index 999dd8a..3783969 100644 --- a/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/videoplayer-v3.js +++ b/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/js/videoplayer-v3.js @@ -1,3 +1,4 @@ +/* jshint -W116, -W117 */ /* * v2.0 Initial Version * v2.1 Included more video types diff --git a/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/templates/VideoPlayer/js/VideoPlayerTmplt.js b/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/templates/VideoPlayer/js/VideoPlayerTmplt.js index 0c9bd42..8cbd6f3 100644 --- a/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/templates/VideoPlayer/js/VideoPlayerTmplt.js +++ b/app/files/tweaks/config/videoplayer/jci/gui/apps/_videoplayer/templates/VideoPlayer/js/VideoPlayerTmplt.js @@ -1,11 +1,11 @@ /* - Copyright 2016 Herko ter Horst + Copyright 2019 Trezdog44 & VIC_BAM85 __________________________________________________________________________ Filename: VideoPlayerTmplt.js __________________________________________________________________________ - */ - +*/ +/* jshint -W117 */ log.addSrcFile("VideoPlayerTmplt.js", "videoplayer"); /* diff --git a/app/files/tweaks/config_org/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/css/FuelConsumptionCtrl.css b/app/files/tweaks/config_org/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/css/FuelConsumptionCtrl.css deleted file mode 100644 index 5d01e14..0000000 --- a/app/files/tweaks/config_org/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/css/FuelConsumptionCtrl.css +++ /dev/null @@ -1,869 +0,0 @@ -/* CSS Document */ -/* - * Numerical values that are also used in setting CSS styles programmatically - * NOTE: Changing these values requires matching changes in JS source file! - */ -/* $CDFEGraphVisibleWidth: 500px; */ -/* Left & right margins */ -/* $CDFEGraphActiveWidth: 533px; */ -/* $CFERGraphVisibleWidth: 500px; */ -/* Left & right margins */ -/* $CFERGraphActiveWidth: 580px; */ -/* - * End JS-matching values - */ -.FuelConsumptionCtrl { - position: absolute; - width: 800px; - height: 416px; - left: -60px; - top: 0px; - background: url('../images/FuelConsBG.png') center no-repeat; -} - -.FuelConsumptionCtrlHiddenOpacity { - - opacity: 0; -} - -.UmpPanelDivDisable -{ - position: inherit; - top: 0px; - left: 0px; - width: 800px; - height: 100px; - background: none; - z-index: 10; -} - -.UmpPanelDivEnable -{ - position: inherit; - top: 0px; - left: 0px; - width: 800px; - height: 100px; - background: none; - z-index: 10; -} - -.FuelConsumptionCtrlGraphsArea { - margin: 0px; - float: left; - width: 600px; - height: 416px; - } - -.FuelConsumptionCtrlFuelEfficiencyArea { - float: right; - width: 148px; - height: 420px; - } - -/********************** Average fuel economy display **********************/ -h2.FuelConsumptionCtrlFuelEfficiencyTitle { - position: absolute; - top: 160px; - left:648px; - height:35px; - width:148px; - top:130px; - text-align: left; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 27px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; - } - -.FuelConsumptionCtrlFuelEfficiencyThisDrive { - - position: absolute; - top: 165px; - left:648px; - height:30px; - width:148px; - text-align: left; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 27px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; -} - -.FuelConsumptionCtrlFuelEfficiencyValue { - position: absolute; - left:679px; - top: 197px; - width: 74px; - height:45px; - text-align: center; - font-family: "Tipperary Semibold", Arial, Helvetica, sans-serif; - font-size: 40px; - color: #ffffff; - } - -.FuelConsumptionCtrlFuelEfficiencyUnit { - position:absolute; - font-size: 28px; - width:120px; - height: 35px; - top:238px; - left:666px; - text-align:right; - overflow: hidden; - text-overflow: ellipsis; - -o-text-overflow: ellipsis; - white-space: nowrap;} - - -.FuelConsumptionCtrlSwitchView { - position:absolute; - width: 60px; - height: 70px; - top: 340px; - left: 10px; - cursor: pointer; - background: url("../images/AdjustBtn3_Focus.png") center no-repeat; - text-indent: -9999px;} - -.FuelConsumptionCtrlSwitchViewDown { - position:absolute; - width: 60px; - height: 70px; - top: 340px; - left: 10px; - cursor: pointer; - background: url("../images/AdjustBtn3_Focus.png") center no-repeat; - text-indent: -9999px; -} - -/********************** Graph for current drive fuel economy **********************/ -.FuelConsumptionCtrlCDFEGraph { - position: absolute; - top: 58px; - left: 76px; - width: 473px; - height: 111px; - background: url('../images/FuelConsBgBars1.png') center no-repeat; - } - - .FuelConsumptionCtrlCDFEGraphRight { - position: absolute; - top: 58px; - left: 76px; - width: 473px; - height: 111px; - } - -/*.FuelConsumptionCtrlCDFEGraphClipMask {/* - position: absolute; - top: 1px; - left: 240px; - width: 230px; - height: 109px; - overflow: hidden; - }*/ - - .FuelConsumptionCtrlCDFEGraphClipMask { - position: absolute; - top: 1px; - left: 237px; - width: 234px; - height: 109px; - overflow: hidden; - } - - .FuelConsumptionCtrlCDFEGraphClipMaskRight { - position: absolute; - top: 1px; - left: 1px; - width: 240px; - height: 109px; - overflow: hidden; - } - -.FuelConsumptionCtrlCDFEGraphArea { - position: absolute; - top: 1px; - left:10px; - width: 290px; - /* include 16th "hidden" bar & spacer for new values */ - height: 109px; - } - - .FuelConsumptionCtrlCDFEGraphAreaRight { - position: absolute; - top: 1px; - left: 1px; - width: 300px; - /* include 16th "hidden" bar & spacer for new values */ - height: 109px; - } - - - -h2.FuelConsumptionCtrlCDFEGraphTitle { - position: absolute; - left: 0px; - top: -39px; - width:400px; - height:31px; - line-height: 30px; - font-family: "Tipperary Semibold", Arial, Helvetica, sans-serif; - font-size: 28px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; - } - -.FuelConsumptionCtrlCDFEGraphXAxisLabel { - position: absolute; - top: 115px; - left: -5px; - width: 473px; - text-align: center; - color: #fff; - font-size:21px; - font-family: Tipperary, Arial, Helvetica, sans-serif; - - } - -.FuelConsumptionCtrlCDFEGraphYAxisLabel span { - position: absolute; - top: -10px; - left: 478px; - width: 48px; - color: #fff; - font-size:21px; - font-family: Tipperary, Arial, Helvetica, sans-serif; - - } - -.FuelConsumptionCtrlCDFEBarGraphCore { - position: absolute; - width: 21px; - height: 0px; - bottom: -3px; - background: url("../images/FuelConsBar_Narrow.png") center repeat-y; - background-size: 21px 100%; - } - - .FuelConsumptionCtrlCDFEBarGraphCoreRight { - position: absolute; - width: 44px; - height: 0px; - bottom: -3px; - background:url("../images/FuelConsBar_wide.png") center repeat-y; - background-size: 44px 100%; - } - - .FuelConsumptionCtrlCDFEBarGraphCoreGreenRight { - position: absolute; - width: 44px; - height: 0px; - bottom: -3px; - background:url("../images/FuelConsBar_wide_green.png") center repeat-y; - background-size: 44px 100%; - } - - .FuelConsumptionCtrlCDFEBarGraphCoreCurrent { - position: absolute; - width: 21px; - height: 0px; - bottom: -3px; - background:url("../images/FuelConsBar_NarrowCurrent.png") center repeat-y; - background-size: 21px 100%; - } - -.FuelConsumptionCtrlCDFEBarGraphCap { - width: 21px; - height:2px; - margin-top: -3px; - background: url('../images/FuelConsBarCap_Narrow.png')no-repeat center; - background-size: 21px 2px; -} - -.FuelConsumptionCtrlCDFEBarGraphCapRight { - width: 44px; - height:2px; - margin-top: -3px; - background: url('../images/FuelConsBarCap_wide.png')no-repeat center; - background-size: 44px 2px; -} - -/********************** Graph for cumulative fuel economy **********************/ -.FuelConsumptionCtrlCFERGraph { - position: absolute; - top: 257px; - left: 76px; - width: 473px; - height: 111px; - background: url('../images/FuelConsBgBars2.png') no-repeat; - - } - -.FuelConsumptionCtrlCFERGraphClipMask { - position: absolute; - top: 0px; - left: 0px; - width: 393px; - height: 109px; - overflow: hidden; - } - - -.FuelConsumptionCtrlCFERGraphArea { - position: absolute; - top: 0px; - left: 0px; - width: 580px; - /* include 7th "hidden" bar & spacer for new values */ - height: 109px; -} - -h2.FuelConsumptionCtrlCFERGraphTitle { - position: absolute; - width: 400px; - left: 0px; - top: -39px; - line-height: 30px; - height:31px; - font-family: "Tipperary Semibold", Arial, Helvetica, sans-serif; - font-size: 28px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; - } - -.FuelConsumptionCtrlCFERGraphXAxisLabel { - position: absolute; - top: 115px; - left:0px; - width: 473px; - font-size:21px; - font-family: Tipperary, Arial, Helvetica, sans-serif; - color: #fff; - - } - -.FuelConsumptionCtrlCFERGraphYAxisLabel span { - position: absolute; - top: -10px; - left: 478px; - width: 48px; - font-size:21px; - font-family: Tipperary, Arial, Helvetica, sans-serif; - color: #fff; - } - -.FuelConsumptionCtrlCFERBarGraphCore { - position: absolute; - width: 50px; - height: 0px; - bottom: -3px; - background: url("../images/FuelConsBar_wide.png") center repeat-y; - background-size: 44px 100%; - } - -.FuelConsumptionCtrlCFERBarGraphCoreCurrent { - position: absolute; - width: 50px; - height: 0px; - bottom: -3px; - background: url("../images/FuelConsBar_WideCurrent.png") center repeat-y; - background-size: 44px 100%; -} - -.FuelConsumptionCtrlCFERBarValueCurrent { - height: 31px; - width:50px; - text-align:center; - margin-top:-30px; - color: #fff; - font-size:24px; - font-family: Tipperary, Arial, Helvetica, sans-serif; - overflow: visible; -} -.FuelConsumptionCtrlHidden { - display:none; -} - -.FuelConsumptionCtrlCFERBarGraphCap { - width: 50px; - height:2px; - margin-top: -3px; - background: url('../images/FuelConsBarCap_wide.png')no-repeat center; - background-size: 44px 2px; -} - -.FuelConsumptionCtrlCFERCurrentBarValue { - - position: absolute; - width:50px; - height: 0px; - bottom: 50px; - left: 483px; -} - -.FuelConsumptionCtrlHevCDFEDisc_1 { - - width:22px; - height:13px; - -} - -.FuelConsumptionCtrlHevCDFEDisc_2 { - width:22px; - height:26px; -} - -.FuelConsumptionCtrlHevCDFEDisc_3 { - - width:22px; - height:39px; -} - -.FuelConsumptionCtrlHevCDFEDisc_4 { - - width:22px; - height:52px; -} - -.FuelConsumptionCtrlHevCDFEDisc_5 { - width:22px; - height:65px; -} - -.FuelConsumptionCtrlHevCDFEDisc_6 { - width:21px; - height:78px; -} - -.FuelConsumptionCtrlHevCDFEDisc_7 { - width:22px; - height:91px; -} - -.FuelConsumptionCtrlHevCDFEDisc_8 { - width:22px; - height:104px; -} - -.FuelConsumptionCtrlHevCDFEDiscBg_Blue { - - position: relative; - background: url('../images/GeneratedEnergy_NarrowPurple.png') center repeat-y; - bottom: 0px; -} - -.FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreen { - - position: absolute; - width: 21px; - height: 0px; - bottom: -3px; - background:url("../images/FuelConsBar_NarrowGreen.png") center repeat-y; - background-size: 21px 100%; -} - -.FuelConsumptionCtrlHevCDFEDiscBg_Green { - - position: absolute; - width: 21px; - height: 0px; - bottom: 0px; - background: url('../images/GeneratedEnergy_NarrowGreen.png') center bottom repeat-y; -} - -.FuelConsumptionCtrlHevCDFEDiscBg_White { - - background: url('../images/GeneratedEnergy_NarrowCurrent.png') center repeat-y; -} - -.FuelConsumptionCtrlHevCDFEDiscWide_1 { - - width:44px; - height:13px; - -} - -.FuelConsumptionCtrlHevCDFEDiscWide_2 { - width:44px; - height:26px; -} - -.FuelConsumptionCtrlHevCDFEDiscWide_3 { - - width:44px; - height:39px; -} - -.FuelConsumptionCtrlHevCDFEDiscWide_4 { - - width:44px; - height:52px; -} - -.FuelConsumptionCtrlHevCDFEDiscWide_5 { - width:44px; - height:65px; -} - -.FuelConsumptionCtrlHevCDFEDiscWide_6 { - width:44px; - height:78px; -} - -.FuelConsumptionCtrlHevCDFEDiscWide_7 { - width:44px; - height:91px; -} - -.FuelConsumptionCtrlHevCDFEDiscWide_8 { - width:44px; - height:104px; -} - -.FuelConsumptionCtrlHevAverageText { - -} - -.FuelConsumptionCtrlHevThisDriveText { - -} - -.FuelConsumptionCtrlFuelEfficiencyTitleHev{ - position: absolute; - left:648px; - height:35px; - width:148px; - top:67px; - text-align: left; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 27px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; - -} - -.FuelConsumptionCtrlFuelEfficiencyThisDriveHev { - position: absolute; - left:648px; - height:30px; - width:148px; - top:102px; - text-align: left; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 27px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; -} -.FuelConsumptionCtrlFuelEfficiencyValueHev{ - position: absolute; - left:645px; - top: 134px; - width: 74px; - height:45px; - text-align: center; - font-family: "Tipperary Semibold", Arial, Helvetica, sans-serif; - font-size: 40px; - color: #ffffff; - } - - .FuelConsumptionCtrlFuelEfficiencyHevDivider{ - position:absolute; - top:205px; - left:643px; - background:url("../images/HEVFuelCons_divider_h2.png"); - width:146px; - height:1px; - } - - .FuelConsumptionCtrlHevOneDriveText { - position: absolute; - left:648px; - height:65px; - width:138px; - top:241px; - text-align: left; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 27px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; -} - -.FuelConsumptionCtrlHevEVDistanceText { - position: absolute; - left:648px; - height:65px; - width:138px; - top:271px; - text-align: left; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 26px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; -} - -.FuelConsumptionCtrlHevDistanceValue { - position: absolute; - top:308px; - left:645px; - height:45px; - width:99px; - text-align: right; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 40px; - color: #ffffff; -} - -.FuelConsumptionCtrlHevDistanceUnit { - position: absolute; - top:318px; - left:745px; - height:31px; - width:38px; - text-align: right; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 28px; - color: #ffffff; -} - -.FuelConsumptionCtrlHevPercentValue { - position: absolute; - top:349px; - left:687px; - height:31px; - width:59px; - text-align: center; - line-height: 120%; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 28px; - color: #ffffff; -} - -.FuelConsumptionCtrlCDFEDiscGraph { - position: absolute; - top: 58px; - left: 76px; - width: 473px; - height: 111px; -} - -/*.FuelConsumptionCtrlCDFEDiscGraphClipMask {/* - position: absolute; - top: 1px; - left: 240px; - width: 230px; - height: 109px; - overflow: hidden; -}*/ - -.FuelConsumptionCtrlCDFEDiscGraphClipMask { - position: absolute; - top: 1px; - left: 237px; - width: 234px; - height: 109px; - overflow: hidden; -} - -.FuelConsumptionCtrlCDFEDiscGraphArea { - position: absolute; - top: 1px; - left:10px; - width: 290px; - /* include 16th "hidden" bar & spacer for new values */ - height: 109px; -} - -.FuelConsumptionCtrlHevCDFEBarGraphCore { - position: absolute; - width: 21px; - height: 0px; - bottom: 0px/*-3px*/; - background: url("../images/GeneratedEnergy_NarrowPurple.png") center bottom repeat-y; - z-index: 9; -} - -.FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent { - position: absolute; - width: 21px; - height: 0px; - bottom: 0px/*-3px*/; - background:url("../images/GeneratedEnergy_NarrowCurrent.png")center bottom repeat-y; - z-index: 9; -} - -.FuelConsumptionCtrlCDFEDiscGraphRight { - position: absolute; - top: 58px; - left: 76px; - width: 473px; - height: 111px; -} - -.FuelConsumptionCtrlCDFEDiscGraphClipMaskRight { - position: absolute; - top: 1px; - left: 1px; - width: 240px; - height: 109px; - overflow: hidden; -} - - -.FuelConsumptionCtrlCDFEDiscGraphAreaRight { - position: absolute; - top: 1px; - left: 1px; - width: 300px; - height: 109px; -} - -.FuelConsumptionCtrlHevCDFEDiscGraphCoreRight{ - position: absolute; - width: 44px; - height: 0px; - bottom: 0px; - background: url("../images/GeneratedEnergy_WidePurple.png") center bottom repeat-y; - z-index: 9; -} - -.FuelConsumptionCtrlHevCDFEDiscGraphCoreGreenRight{ - position: absolute; - width: 44px; - height: 0px; - bottom: 0px; - background: url("../images/GeneratedEnergy_Wide_Green.png") center bottom repeat-y; - z-index: 9; -} - -.FuelConsumptionCtrlCFERBarGraphCurrentMask { - - position: absolute; - width:50px; - height: 109px; - left:483px; - top: 256px; - overflow:hidden; -} - -.FuelConsumptionCtrlFuelEfficiencyUnitHev{ - position:absolute; - font-size: 28px; - width:80px; - height: 31px; - top:146px; - left:705px; - text-align:right; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; - } - - .FuelConsumptionCtrlOneDiscValue { - - position:absolute; - width: 95px; - height: 31px; - left: 461px; - top: 19px; - text-align: right; - line-height: 31px; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 28px; - color: #ffffff; - overflow:hidden; - text-overflow:ellipsis; - -o-text-overflow:ellipsis; - white-space:nowrap; - } - - .FuelConsumptionCtrlOneDiscIndicator { - - position:absolute; - width: 19px; - height: 13px; - background: url('../images/GeneratedEnergy_NarrowCurrent.png') center no-repeat; - left:437px; - top:27px; - } - - .FuelConsumptionCtrlHalfWayLabel1 { - - position:absolute; - width: 24px; - height: 24px; - left: 553px; - top: 102px; - text-align: left; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 21px; - color: #ffffff; - - } - - .FuelConsumptionCtrlHalfWayLabel2 { - - position:absolute; - width: 24px; - height: 24px; - left: 553px; - top: 301px; - text-align: left; - font-family: Tipperary, Arial, Helvetica, sans-serif; - font-size: 21px; - color: #ffffff; - } - - .FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreenHighLighted { - position: absolute; - width: 21px; - height: 0px; - bottom: -3px; - background:url("../images/FuelConsBar_NarrowGreenCurrent.png") center repeat-y; - background-size: 21px 100%; - } - - - - .FuelConsumptionCtrlHevCDFEBarGraphCoreCurrentGreenHighLighted { - position: absolute; - width: 21px; - height: 0px; - bottom: 0px/*-3px*/; - background:url("../images/GeneratedEnergy_NarrowGreenCurrent.png")center bottom repeat-y; - z-index: 9; -} \ No newline at end of file diff --git a/app/files/tweaks/config_org/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/js/FuelConsumptionCtrl.js b/app/files/tweaks/config_org/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/js/FuelConsumptionCtrl.js deleted file mode 100644 index 72a7ebd..0000000 --- a/app/files/tweaks/config_org/FuelConsumptionTweak/jci/gui/apps/ecoenergy/controls/FuelConsumption/js/FuelConsumptionCtrl.js +++ /dev/null @@ -1,2433 +0,0 @@ -/* - Copyright 2012 by Johnson Controls - __________________________________________________________________________ - - Filename: FuelConsumptionCtrl.js - __________________________________________________________________________ - - Project: JCI-IHU - Language: EN - Author: apeter9 - Date: 1-08-2013 - __________________________________________________________________________ - - Description: IHU GUI FuelConsumptionCtrl) - - Revisions: - v0.1 (01-08-2013) Initial implementation (to 0.3.05 spec) (apeter9) - v0.2 (02-20-2013) Changes in layout and bar images (atiwarc) - v0.3 (03-14-2013) Implementation of UMP Control panel (atiwarc) - v0.4 (04-24-2013) Spec Migration to 3.56 (UMP3 support and Spec changes)(atiwarc) - v0.5 (05-15-2013) Go back implementation (atiwarc) -__________________________________________________________________________ - - */ - -log.addSrcFile("FuelConsumptionCtrl.js", "common"); -// Alternative logging for development (avoid spew from "common") -//log.addSrcFile("FuelConsumptionCtrl.js", "FuelConsumptionCtrl"); -//log.setLogLevel("FuelConsumptionCtrl", "debug"); - -function FuelConsumptionCtrl(uiaId, parentDiv, controlId, properties) -{ -// log.debug("FuelConsumptionCtrl constructor called..."); - - this.uiaId = uiaId; - this.parentDiv = parentDiv; - this.controlId = controlId; - this.divElt = null; - this._switchViewButtonCtrl = null; - this._umpPanelStatus = false; - this._cumulativeBarValue = null; - - this._initialEVMode = new Array(); - /******************************************************/ - /* Values required by _createStructure (before _init) */ - /******************************************************/ - - // Total # of bars available in Current Drive Fuel Economy (CDFE) graph - // (15 historical + 1 slot for new data to be animated into position) - this._totalCDFEBars = 11; - - // The index of the youngest historical data in the CDFE graph - this._youngestCDFEDataIdx = this._totalCDFEBars - 2; - - // The index of the slot for new data in the CDFE graph - this._newCDFEDataIdx = this._totalCDFEBars - 1; - - // The current bar of CDFE graph - this._currentCDFEDataIdx = this._totalCDFEBars; - /**********************New Initialization of CDFE Bars *************************************************/ - - this._totalCDFEBarsRight = 6; - - // The index of the youngest historical data in the CDFE graph - this._youngestCDFEDataIdxRight = this._totalCDFEBarsRight - 2; - - // The index of the slot for new data in the CDFE graph - this._newCDFEDataIdxRight = this._totalCDFEBarsRight - 1; - - /************************End of Initialization of CFER Bars ******************************************/ - - // Total # of bars (historical + current + new) available in Cumulative Fuel Economy by Reset (CFER) graph - this._totalCFERBars = 6; - - // The index of the youngest historical data in the CFER graph - this._youngestCFERDataIdx = this._totalCFERBars - 2; - - // The index of the slot for new data in the CFER graph - this._newCFERDataIdx = this._totalCFERBars - 1; - - // The index of the current data in the CFER graph - this._currentCFERDataIdx = this._totalCFERBars; - - // Has the current CFER data been initialized yet? - this._currentCFERDataInitialized = false; - - - - // Table of numerical values used in setting CSS styles programmatically - // NOTE: Changing these values requires matching changes in SCSS source file! - this._CSSConstants = - { - // - // CDFE Graph Constants - // - - // Width (in pixels) of a bar - "CDFEGraphBarWidth" : 21, - - // Space between/around bars - "CDFEGraphBarSpacing" : 2, - "CDFEGraphBarMargin" : 3, - - // Width/height (in pixels) of the visible graph area - // (no labels, title or "hidden" bar) - "CDFEGraphVisibleWidth" : (((this._totalCDFEBars - 1) * 21) + // Bars - ((this._totalCDFEBars - 1) * 1) + // Space between bars - (1 * 1)), // Left & right margins (e.g. 500) - "CDFEGraphVisibleHeight" : 109, - - // Width (in pixels) of the active graph area - // (including "hidden" bar, but no labels or title) - "CDFEGraphActiveWidth" : ((this._totalCDFEBars * 21) + // Bars - ((this._totalCDFEBars - 1) * 1) + // Space between bars - (1 * 1)), // Left & right margins (e.g. 533) - - /*******************************************New CDFE Graph Constants************************************************/ - // - // CDFE Graph Constants - // - - // Width (in pixels) of a bar - "CDFEGraphBarWidthRight" : 44, - // Space between/around bars - "CDFEGraphBarSpacingRight" : 3, - "CDFEGraphBarMarginRight" : 2, - - // Width/height (in pixels) of the visible graph area - // (no labels, title or "hidden" bar) - "CDFEGraphVisibleWidthRight" : (((this._totalCDFEBarsRight - 1) * 44) + // Bars - ((this._totalCDFEBarsRight - 2) * 3) + // Space between bars - (2 * 2)), // Left & right margins (e.g. 500) - "CDFEGraphVisibleHeightRight" : 109, - - // Width (in pixels) of the active graph area - // (including "hidden" bar, but no labels or title) - "CDFEGraphActiveWidthRight" : ((this._totalCDFEBarsRight * 44) + // Bars - ((this._totalCDFEBarsRight - 1) * 3) + // Space between bars - (2 * 2)), // Left & right margins (e.g. 533) - -/*******************************************End of New CDFE Graph Constants************************************************/ - - // - // CFER Graph Constants - // - - // Width (in pixels) of a bar - "CFERGraphBarWidth" :50, - - // Space between/around bars - "CFERGraphBarSpacing" : 28, - "CFERGraphBarMargin" : 17, - - // Width/height (in pixels) of the visible graph area - // (including "hidden" bar, but no labels or title) - "CFERGraphVisibleWidth" : (((this._totalCFERBars - 1) * 50) + // Bars - ((this._totalCFERBars - 2) * 28) + // Space between bars - (1 * 17)), // Left & right margins (e.g. 500) - "CFERGraphVisibleHeight" : 109, - - // Width (in pixels) of the active graph area - // (including "hidden" bar, but no labels or title) - "CFERGraphActiveWidth" : ((this._totalCFERBars * 50) + // Bars - ((this._totalCFERBars - 1) * 28) + // Space between bars - (1 * 17)), // Left & right margins (e.g. 580) - }; - - /******************************************************/ - /******************************************************/ - /******************************************************/ - - this._cbCDFELineFadeAnimationEnd = null; - this._cbCDFELeftAnimationEnd = null; - this._cbCFERLeftAnimationEnd = null; - - this._CDFELineGraphCanvasDC = null; - this._CDFELineGraphInTransition = false; - - this._CDFEGraphBarValues = null; - this._CDFEGraphLineValues = null; - this._CFERGraphBarValues = null; - - /**************************************Initialization of functions********************************************/ - - this._cbCDFELineFadeAnimationEndRight = null; - this._cbCDFELeftAnimationEndRight = null; - this._cbCFERLeftAnimationEndRight = null; - - this._CDFELineGraphCanvasDCRight = null; - this._CDFELineGraphInTransitionRight = false; - - this._CDFEGraphBarValuesRight = null; - this._CDFEGraphLineValuesRight = null; - this._CFERGraphBarValuesRight = null; - this._CDFEDiscBarValuesRight = null; - this._CDFEEvModeRight = new Array(); - - /**************************************End ofInitialization of functions********************************************/ - - - //@formatter:off - this.properties = - { - "subMap" : null, - "mode" : "", - "fuelEfficientyTitleId" : "", - "fuelEfficientyTitleText" : "", - "switchViewLabelId" : "", - "switchViewLabelText" : "", - "switchViewButtonCallback" : null, - "fuelEfficiencyData" : null, - "currentFuelConfig" : null, - "cumulativeFuelConfig" : null, - "umpButtonConfig" : null, - "defaultSelectCallback" : null, - "defaultSlideCallback" : null, - "defaultHoldStartCallback" : null, - "defaultHoldStopCallback" : null, - "dataList" : null, - "umpStyle" : null, - "hasScrubber" : false, - "umpPanelStatus" : false - }; - //@formatter:on - - // Copy properties from the app - for (var key in properties) - { - this.properties[key] = properties[key]; - } - - //preload images - this.imagesCount = 0; - this._preload('FuelConsBar_Narrow.png','FuelConsBar_NarrowCurrent.png','FuelConsBar_NarrowGreen.png', 'FuelConsBar_NarrowGreenCurrent.png', 'FuelConsBar_wide.png', 'FuelConsBar_wide_green.png','FuelConsBar_WideCurrent.png','FuelConsBarCap_Narrow.png','FuelConsBarCap_wide.png','GeneratedEnergy_NarrowCurrent.png','GeneratedEnergy_NarrowGreen.png','GeneratedEnergy_NarrowGreenCurrent.png','GeneratedEnergy_NarrowPurple.png','GeneratedEnergy_Wide_Green.png','GeneratedEnergy_WidePurple.png'); - - // Create DOM elements - this._createStructure(); -} - -/*******************/ -/* Private Methods */ -/*******************/ - -FuelConsumptionCtrl.prototype._init = function() -{ -// log.debug("FuelConsumptionCtrl: _init() called..."); - - // Historical data displayed by CDFE graph - this._CDFEGraphBarValues = new Array(); - this._CDFEGraphLineValues = new Array(); - this._CDFEDiscValues = new Array(); - /************************************Historical data displayed by CDFE graph Right***********************************/ - - this._CDFEGraphBarValuesRight = new Array(); - this._CDFEDiscBarValuesRight = new Array(); - - /************************************End of Historical data displayed by CDFE graph Right ***********************************/ - // Historical/current data displayed by CFER graph - this._CFERGraphBarValues = new Array(); - - // The callback function used to remove the animation on the CDFE line graph at the end of its fade-in - this._cbCDFELineFadeAnimationEnd = this._onCDFELineFadeAnimationEnd.bind(this); - - // The callback function used to reset the CDFE graph after left animation (insertion) completes - this._cbCDFELeftAnimationEnd = this._onCDFELeftAnimationEnd.bind(this); - - /**********************************New function Added ****************************************/ - - // The callback function used to reset the CDFE graph after left animation (insertion) completes - this._cbCDFELeftAnimationEndRight = this._onCDFELeftAnimationEndRight.bind(this); - - /***********************************End of New function ****************************************/ - - // The callback function used to reset the CFER graph after left animation (insertion) completes - this._cbCFERLeftAnimationEnd = this._onCFERLeftAnimationEnd.bind(this); - - // Set the canvas' width & height attributes to match CSS, so pixels are 1:1 - this.CDFELineGraphCanvas.width = this._CSSConstants["CDFEGraphActiveWidth"]; - this.CDFELineGraphCanvas.height = this._CSSConstants["CDFEGraphVisibleHeight"]; - - // The drawing context for the CDFE line graph canvas overlay - this._CDFELineGraphCanvasDC = this.CDFELineGraphCanvas.getContext("2d"); - - // Now that the DOM structure is established, - // set the horizontal positions of the graph bars - this._setCDFEGraphBarPositions(); - - /**********************************New Function Added*****************************************/ - - - this._setCDFEGraphBarPositionsRight(); - - - /********************************End of New Function Added*****************************************/ - - this._setCFERGraphBarPositions(); - - // Set the CDFE graph title text - this.properties.currentFuelConfig.titleText = this._translateString(this.properties.currentFuelConfig.titleId, - this.properties.currentFuelConfig.titleText, - this.properties.subMap); - this.CDFEGraphTitle.innerHTML = this._stringToHTML(this.properties.currentFuelConfig.titleText); - - - - // Set the CFER graph title text - this.properties.cumulativeFuelConfig.titleText = this._translateString(this.properties.cumulativeFuelConfig.titleId, - this.properties.cumulativeFuelConfig.titleText, - this.properties.subMap); - this.CFERGraphTitle.innerHTML = this._stringToHTML(this.properties.cumulativeFuelConfig.titleText); - - // Set the fuel efficiency title text - this.properties.fuelEfficiencyTitleText = this._translateString(this.properties.fuelEfficiencyTitleId, - this.properties.fuelEfficiencyTitleText, - this.properties.subMap); - this.properties.fuelEfficiencyTypeText = this._translateString(this.properties.fuelEfficiencyTypeId, - this.properties.fuelEfficiencyTypeText, - this.properties.subMap); - - this.fuelEfficiencyTitle.innerHTML = this._stringToHTML(this.properties.fuelEfficiencyTitleText); - this.fuelEfficiencyThisDrive.innerHTML = this._stringToHTML(this.properties.fuelEfficiencyTypeText); - // Initialize the graphs - this.initializeCurrentDriveFuelGraphRight(this.properties.currentFuelConfig.initialBarValues); - this.initializeCumulativeFuelGraph(this.properties.cumulativeFuelConfig.initialBarValues); - - // Set the fuel efficiency data - this.setFuelEfficiency(this.properties.fuelEfficiencyData); -} - -FuelConsumptionCtrl.prototype._next = function(count) -{ - this.imagesCount++; - if(this.imagesCount >= count) - { - this.divElt.className = "FuelConsumptionCtrl"; - } -} - -FuelConsumptionCtrl.prototype._preload = function() -{ - var images = new Array(); - var prefix = './apps/ecoenergy/controls/FuelConsumption/images/'; - for(var i = 0; i < this._preload.arguments.length; i++) - { - images[i] = new Image(); - images[i].src = prefix + this._preload.arguments[i]; - images[i].onload = this._next.bind(this, this._preload.arguments.length); - } -} - -FuelConsumptionCtrl.prototype._createStructure = function() -{ -// log.debug("FuelConsumptionCtrl: _createStructure() called..."); - - // Create the div for control - this.divElt = document.createElement('div'); - this.divElt.className = "FuelConsumptionCtrl FuelConsumptionCtrlHiddenOpacity"; - // Create the div for ump panel - this.umpPanelDiv = document.createElement('div'); - //(this.properties.umpPanelStatus) ? this.umpPanelDiv.className = "UmpPanelDivEnable" : this.umpPanelDiv.className = "UmpPanelDivDisable"; - this.umpPanelDiv.className = "UmpPanelDivDisable"; - this.umpPanelDiv.style.left = "-60px"; - // Create the container div for all of the graphs - this.graphsArea = document.createElement('div'); - this.graphsArea.className = 'FuelConsumptionCtrlGraphsArea'; - - /***************************************/ - /* Create DOM structure for CDFE graph */ - /***************************************/ - - // CDFE graph top-level DIV - this.CDFEGraph = document.createElement('div'); - this.CDFEGraph.className = 'FuelConsumptionCtrlCDFEGraph'; - - /******************************Created New graph Div *****************************************/ - - // CDFE graph top-level DIV 2 - this.CDFEGraphRight = document.createElement('div'); - this.CDFEGraphRight.className = 'FuelConsumptionCtrlCDFEGraphRight'; - - /******************************End of Created New graph Div **********************************/ - - // CDFE graph X-axis label - this.CDFEGraphXAxisLabel = document.createElement('div'); - this.CDFEGraphXAxisLabel.className = 'FuelConsumptionCtrlCDFEGraphXAxisLabel'; - this.CDFEGraph.appendChild(this.CDFEGraphXAxisLabel); - - // CDFE graph Y-axis label - this.CDFEGraphYAxisLabel = document.createElement('div'); - this.CDFEGraphYAxisLabel.className = 'FuelConsumptionCtrlCDFEGraphYAxisLabel'; - this.CDFEGraph.appendChild(this.CDFEGraphYAxisLabel); - - // Add axis labels to CDFE graph - this._addCDFEGraphAxisLabels(this.CDFEGraphXAxisLabel, - this.CDFEGraphYAxisLabel); - - // CDFE graph title - this.CDFEGraphTitle = document.createElement('h2'); - this.CDFEGraphTitle.className = 'FuelConsumptionCtrlCDFEGraphTitle'; - this.CDFEGraph.appendChild(this.CDFEGraphTitle); - - // Clipping mask for active CDFE graph area - this.CDFEGraphClipMask = document.createElement('div'); - this.CDFEGraphClipMask.className = 'FuelConsumptionCtrlCDFEGraphClipMask'; - - /*****************************************New Mask for CDFE graph*********************************/ - - // Clipping mask for active CDFE graph Right area - this.CDFEGraphClipMaskRight = document.createElement('div'); - this.CDFEGraphClipMaskRight.className = 'FuelConsumptionCtrlCDFEGraphClipMaskRight'; - - /*****************************************End of New Mask for CDFE graph*********************************/ - - // Active graphing area for CDFE graph - this.CDFEGraphArea = document.createElement('div'); - this.CDFEGraphArea.className = 'FuelConsumptionCtrlCDFEGraphArea'; - - /***************************************New Active Graphing Area for CDFE graph right***************/ - - // Active graphing area for CDFE graph Right - this.CDFEGraphAreaRight = document.createElement('div'); - this.CDFEGraphAreaRight.className = 'FuelConsumptionCtrlCDFEGraphAreaRight'; - - /***************************************End of Active Graphing Area for CDFE graph right***************/ - // Create CDFE graph bars - for (var i = 1; i <= this._totalCDFEBars; i++) - { - var curCDFEBar = document.createElement('div'); - curCDFEBar.id = 'CDFEBar' + i; - - var CDFEBarCap = document.createElement('div'); - CDFEBarCap.className = 'FuelConsumptionCtrlCDFEBarGraphCap'; - - switch (i) - { - case this._newCDFEDataIdx: - curCDFEBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - this.CDFECurrentBar = curCDFEBar; - - break; - case this._currentCDFEDataIdx: - curCDFEBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - - break; - default: - curCDFEBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - break; - } - - curCDFEBar.appendChild(CDFEBarCap); - this.CDFEGraphArea.appendChild(curCDFEBar); - } - - /*************************************New CDFE Graph Bars**********************************/ - - // Create CDFE graph Right bars - for (var i = 1; i <= this._totalCDFEBarsRight; i++) - { - var curCDFEBarRight = document.createElement('div'); - curCDFEBarRight.id = 'CDFEBarRight' + i; - curCDFEBarRight.className = 'FuelConsumptionCtrlCDFEBarGraphCoreRight'; - var CDFEBarCapRight = document.createElement('div'); - CDFEBarCapRight.className = 'FuelConsumptionCtrlCDFEBarGraphCapRight'; - curCDFEBarRight.appendChild(CDFEBarCapRight); - this.CDFEGraphAreaRight.appendChild(curCDFEBarRight); - } - - /*************************************End of New CDFE Graph Bars**********************************/ - // Create canvas for drawing line graphs - this.CDFELineGraphCanvas = document.createElement('canvas'); - this.CDFELineGraphCanvas.id = 'FuelConsumptionCtrlCDFELineGraphCanvas'; - this.CDFELineGraphCanvas.className = 'FuelConsumptionCtrlHiddenCDFELineGraphCanvas'; - this.CDFEGraphArea.appendChild(this.CDFELineGraphCanvas); - - // Attach the active graphing area to the CDEF graph clip mask - this.CDFEGraphClipMask.appendChild(this.CDFEGraphArea); - - /**************************New CDFE Clip Mask Attach*******************************************/ - - // Attach the active graphing area to the CDEF graph clip mask - this.CDFEGraphClipMaskRight.appendChild(this.CDFEGraphAreaRight); - - /**************************End of New CDFE Clip Mask Attach*******************************************/ - - // Attach the clip mask to the CDFE graph - this.CDFEGraph.appendChild(this.CDFEGraphClipMask); - - /**************************New clip mask to the CDFE graph*******************************************/ - - // Attach the clip mask to the CDFE graph Right - this.CDFEGraphRight.appendChild(this.CDFEGraphClipMaskRight); - - /**************************End of New clip mask to the CDFE graph*******************************************/ - - // Attach the CDFE graph to its parent - this.graphsArea.appendChild(this.CDFEGraph); - - /**************************New CDFE graph to its parent*******************************************/ - - // Start stand alone graph for the hev disc graph - if(this.properties.ctrlStyle === "hevstyle") - { - // CDFE Disc graph top-level DIV - this.CDFEDiscGraph = document.createElement('div'); - this.CDFEDiscGraph.className = 'FuelConsumptionCtrlCDFEDiscGraph'; - - // Clipping Disc mask for active CDFE graph area - this.CDFEDiscGraphClipMask = document.createElement('div'); - this.CDFEDiscGraphClipMask.className = 'FuelConsumptionCtrlCDFEDiscGraphClipMask'; - - // Active graphing area for CDFE Disc graph - this.CDFEDiscGraphArea = document.createElement('div'); - this.CDFEDiscGraphArea.className = 'FuelConsumptionCtrlCDFEDiscGraphArea'; - - // Create Disc CDFE graph bars - for (var i = 1; i <= this._totalCDFEBars; i++) - { - var curCDFEDiscBar = document.createElement('div'); - curCDFEDiscBar.id = 'CDFEDiscBar' + i; - - switch (i) - { - case this._newCDFEDataIdx: - curCDFEDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - this.CDFECurrentDiscBar = curCDFEDiscBar; - - break; - case this._currentCDFEDataIdx: - curCDFEDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - - break; - default: - curCDFEDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - break; - } - - - - this.CDFEDiscGraphArea.appendChild(curCDFEDiscBar); - } - - // Attach the active graphing area to the CDEF Disc graph clip mask - this.CDFEDiscGraphClipMask.appendChild(this.CDFEDiscGraphArea); - - // Attach the clip mask to the CDFE Disc graph - this.CDFEDiscGraph.appendChild(this.CDFEDiscGraphClipMask); - - // Attach the CDFE Disc graph to its parent - this.graphsArea.appendChild(this.CDFEDiscGraph); - - - /************* For the 10 Min bar graph data with Discs *************/ - // CDFE Disc graph top-level DIV - this.CDFEDiscGraphRight = document.createElement('div'); - this.CDFEDiscGraphRight.className = 'FuelConsumptionCtrlCDFEDiscGraphRight'; - - // Clipping Disc mask for active CDFE graph area - this.CDFEDiscGraphClipMaskRight = document.createElement('div'); - this.CDFEDiscGraphClipMaskRight.className = 'FuelConsumptionCtrlCDFEDiscGraphClipMaskRight'; - - // Active graphing area for CDFE Disc graph - this.CDFEDiscGraphAreaRight = document.createElement('div'); - this.CDFEDiscGraphAreaRight.className = 'FuelConsumptionCtrlCDFEDiscGraphAreaRight'; - - // Create Disc CDFE graph bars - for (var k = 1; k <= this._totalCDFEBarsRight; k++) - { - var curCDFEDiscBarRight = document.createElement('div'); - curCDFEDiscBarRight.id = 'CDFEDiscBarRight' + k; - curCDFEDiscBarRight.className = 'FuelConsumptionCtrlHevCDFEDiscGraphCoreRight'; - this.CDFEDiscGraphAreaRight.appendChild(curCDFEDiscBarRight); - } - - // Attach the active graphing area to the CDEF Disc graph clip mask - this.CDFEDiscGraphClipMaskRight.appendChild(this.CDFEDiscGraphAreaRight); - - // Attach the clip mask to the CDFE Disc graph - this.CDFEDiscGraphRight.appendChild(this.CDFEDiscGraphClipMaskRight); - - // Attach the CDFE Disc graph to its parent - this.graphsArea.appendChild(this.CDFEDiscGraphRight); - - } - // Attach the CDFE graph to its parent Right - this.graphsArea.appendChild(this.CDFEGraphRight); - /**************************End of CDFE graph to its parent*******************************************/ - - /***************************************/ - /* Create DOM structure for CFER graph */ - /***************************************/ - - // CFER graph top-level DIV - this.CFERGraph = document.createElement('div'); - this.CFERGraph.className = 'FuelConsumptionCtrlCFERGraph'; - - // CFER graph X-axis label - this.CFERGraphXAxisLabel = document.createElement('div'); - this.CFERGraphXAxisLabel.className = 'FuelConsumptionCtrlCFERGraphXAxisLabel'; - this.CFERGraph.appendChild(this.CFERGraphXAxisLabel); - - // CFER graph Y-axis label - this.CFERGraphYAxisLabel = document.createElement('div'); - this.CFERGraphYAxisLabel.className = 'FuelConsumptionCtrlCFERGraphYAxisLabel'; - this.CFERGraph.appendChild(this.CFERGraphYAxisLabel); - - // Add axis labels to CFER graph - this._addCFERGraphAxisLabels(this.CFERGraphXAxisLabel, - this.CFERGraphYAxisLabel); - - // CFER graph title - this.CFERGraphTitle = document.createElement('h2'); - this.CFERGraphTitle.className = 'FuelConsumptionCtrlCFERGraphTitle'; - this.CFERGraph.appendChild(this.CFERGraphTitle); - - // Clipping mask for active CFER graph area - this.CFERGraphClipMask = document.createElement('div'); - this.CFERGraphClipMask.className = 'FuelConsumptionCtrlCFERGraphClipMask'; - - // Active graphing area for CFER graph - this.CFERGraphArea = document.createElement('div'); - this.CFERGraphArea.className = 'FuelConsumptionCtrlCFERGraphArea'; - - // Create CFER graph bars - for (var j = 0; j < this._totalCFERBars; j++) { - var curCFERBar = document.createElement('div'); - curCFERBar.id = 'CFERBar' + (j + 1); - //var currentValue = document.createElement('div'); - //currentValue.id = 'CFERBarValueCurrent'; - //currentValue.className = 'FuelConsumptionCtrlCFERBarValueCurrent'; - var CFERBarCap = document.createElement('div'); - CFERBarCap.className = 'FuelConsumptionCtrlCFERBarGraphCap'; - switch (j) - { - case this._newCFERDataIdx: - curCFERBar.className = 'FuelConsumptionCtrlCFERBarGraphCore'; - break; - case this._currentCFERDataIdx: - curCFERBar.className = 'FuelConsumptionCtrlCFERBarGraphCore'; - - //this.CFERCurrentBar = curCFERBar; - break; - default: - curCFERBar.className = 'FuelConsumptionCtrlCFERBarGraphCore'; - break; - } - CFERBarCap.style.marginTop = '-3px'; - curCFERBar.appendChild(CFERBarCap); - this.CFERGraphArea.appendChild(curCFERBar); - } - - this.CFERCurrenBarMask = document.createElement('div'); - this.CFERCurrenBarMask.className = 'FuelConsumptionCtrlCFERBarGraphCurrentMask'; - - var CurrentCFERBarCap = document.createElement('div'); - CurrentCFERBarCap.className = 'FuelConsumptionCtrlCFERBarGraphCap'; - CurrentCFERBarCap.style.marginTop = '-3px'; - - this.CFERCurrentBar = document.createElement('div'); - this.CFERCurrentBar.id = 'CFERBar10'; - this.CFERCurrentBar.className = 'FuelConsumptionCtrlCFERBarGraphCoreCurrent'; - - this.CFERCurrentBar.appendChild(CurrentCFERBarCap); - - this.CFERCurrenBarMask.appendChild(this.CFERCurrentBar); - - // Create a div for the current Graph value and attach to the parent div - this.CFERCurrentBarValue = document.createElement('div'); - this.CFERCurrentBarValue.className = 'FuelConsumptionCtrlCFERCurrentBarValue'; - - // Create a div for text of bar value and attach to CFERCurrentBarValueCFERCurrentBarValue - this.CFERCurrentBarValueText = document.createElement('div'); - this.CFERCurrentBarValueText.className = 'FuelConsumptionCtrlCFERBarValueCurrent'; - this.CFERCurrentBarValueText.id = 'CFERBarValueCurrent'; - this.CFERCurrentBarValue.appendChild(this.CFERCurrentBarValueText); - - // Attach the active graphing area to the CFER graph clip mask - this.CFERGraphClipMask.appendChild(this.CFERGraphArea); - - // Attach the clip mask to the CFER graph - this.CFERGraph.appendChild(this.CFERGraphClipMask); - - // Attach the CFER graph to its parent - this.graphsArea.appendChild(this.CFERGraph); - - /*********************************************************/ - /* Create DOM structure for Avg. Fuel Efficiency display */ - /*********************************************************/ - - // Fuel efficiency top-level DIV - this.fuelEfficiencyArea = document.createElement('div'); - this.fuelEfficiencyArea.className = 'FuelConsumptionCtrlFuelEfficiencyArea'; - - // Fuel efficiency title - this.fuelEfficiencyTitle = document.createElement('h2'); - // Fuel efficiency value display - this.fuelEfficiencyValue = document.createElement('div'); - this.fuelEfficiencyUnit = document.createElement('div'); - this.fuelEfficiencyThisDrive = document.createElement('div'); - - //TODO::Fuel Consumption HEV Style - if(this.properties.ctrlStyle === "hevstyle"){ - this.fuelEfficiencyTitle.className = 'FuelConsumptionCtrlFuelEfficiencyTitleHev'; - this.fuelEfficiencyThisDrive.className = 'FuelConsumptionCtrlFuelEfficiencyThisDriveHev'; - this.fuelEfficiencyValue.className = 'FuelConsumptionCtrlFuelEfficiencyValueHev'; - this.fuelEfficiencyUnit.className = 'FuelConsumptionCtrlFuelEfficiencyUnitHev'; - //Fuel efficiency HR region - this.fuelEfficiencyHevDivider = document.createElement("div"); - this.fuelEfficiencyHevDivider.className = 'FuelConsumptionCtrlFuelEfficiencyHevDivider'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevDivider); - - //Fuel Efficiency OneDrive Title - this.fuelEfficiencyHevOneDriveTitle = document.createElement("div"); - this.fuelEfficiencyHevOneDriveTitle.className = 'FuelConsumptionCtrlHevOneDriveText'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevOneDriveTitle); - this.properties.oneDriveText = - this._translateString(this.properties.oneDriveTextId, - this.properties.oneDriveText, - this.properties.subMap); - this.fuelEfficiencyHevOneDriveTitle.innerHTML = this.properties.oneDriveText; - - //Fuel Efficiency EVDistance Title - this.fuelEfficiencyHevEVDistanceTitle = document.createElement("div"); - this.fuelEfficiencyHevEVDistanceTitle.className = 'FuelConsumptionCtrlHevEVDistanceText'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevEVDistanceTitle); - this.properties.evDistanceText = - this._translateString(this.properties.evDistanceTextId, - this.properties.evDistanceText, - this.properties.subMap); - this.fuelEfficiencyHevEVDistanceTitle.innerHTML = this.properties.evDistanceText; - - //Fuel Efficiency Distance Value - this.fuelEfficiencyHevDistanceValue = document.createElement("div"); - this.fuelEfficiencyHevDistanceValue.className = 'FuelConsumptionCtrlHevDistanceValue'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevDistanceValue); - - //Fuel Efficiency Distance Unit - this.fuelEfficiencyHevDistanceUnit = document.createElement("div"); - this.fuelEfficiencyHevDistanceUnit.className = 'FuelConsumptionCtrlHevDistanceUnit'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevDistanceUnit); - - //Fuel Efficiency Percent Value - this.fuelEfficiencyHevPercentValue = document.createElement("div"); - this.fuelEfficiencyHevPercentValue.className = 'FuelConsumptionCtrlHevPercentValue'; - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyHevPercentValue); - - // 20 special case for HEV - - this.halfKmLabel1 = document.createElement('div'); - this.halfKmLabel1.className = 'FuelConsumptionCtrlHalfWayLabel1'; - this.halfKmLabel1.innerHTML = '20'; - - this.halfKmLabel2 = document.createElement('div'); - this.halfKmLabel2.className = 'FuelConsumptionCtrlHalfWayLabel2'; - this.halfKmLabel2.innerHTML = '20'; - - this.divElt.appendChild(this.halfKmLabel1); - this.divElt.appendChild(this.halfKmLabel2); - } - else{ - this.fuelEfficiencyTitle.className = 'FuelConsumptionCtrlFuelEfficiencyTitle'; - this.fuelEfficiencyThisDrive.className = 'FuelConsumptionCtrlFuelEfficiencyThisDrive'; - this.fuelEfficiencyValue.className = 'FuelConsumptionCtrlFuelEfficiencyValue'; - this.fuelEfficiencyUnit.className = 'FuelConsumptionCtrlFuelEfficiencyUnit'; - } - - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyTitle); - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyThisDrive); - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyValue); - - // create container for disc value indicator - if(this.properties.ctrlStyle === 'hevstyle') - { - this.oneDiscValue = document.createElement('div'); - this.oneDiscValue.className = 'FuelConsumptionCtrlOneDiscValue'; - - this.properties.whText = - this._translateString(this.properties.whUnitId, - this.properties.whText, - this.properties.subMap); - this.oneDiscValue.innerHTML = '=30'+this.properties.whText; - this.oneDiscImage = document.createElement('div'); - this.oneDiscImage.className = 'FuelConsumptionCtrlOneDiscIndicator'; - - this.divElt.appendChild(this.oneDiscValue); - this.divElt.appendChild(this.oneDiscImage); - } - - this.fuelEfficiencyArea.appendChild(this.fuelEfficiencyUnit); - - // Add graphs area to control's top-level container - this.divElt.appendChild(this.graphsArea); - - // Add fuel efficiency area to control's top-level container - this.divElt.appendChild(this.fuelEfficiencyArea); - this.divElt.appendChild(this.CFERCurrentBarValue); - this.divElt.appendChild(this.CFERCurrenBarMask); - // Attach control to parent - this.parentDiv.appendChild(this.divElt); - this.parentDiv.appendChild(this.umpPanelDiv); - - var umpConfig = { - "buttonConfig" : this.properties['umpButtonConfig'], - "defaultSelectCallback" : this.properties['defaultSelectCallback'], - "defaultLongPressCallback" : this.properties['defaultLongPressCallback'], - "defaultScrubberCallback" : this.properties['defaultScrubberCallback'], - "defaultHoldStartCallback" : this.properties['defaultHoldStartCallback'], - "defaultHoldStopCallback" : this.properties['defaultHoldStopCallback'], - "umpStyle" : this.properties['umpStyle'], - "hasScrubber" : this.properties['hasScrubber'], - "scrubberConfig" : this.properties['scrubberConfig'], - "retracted" : true - }; - //@formatter:on - log.debug("Instantiating umpCtrl..."); - this.umpCtrl = framework.instantiateControl(this.uiaId, this.umpPanelDiv, "Ump3Ctrl", umpConfig); - - // "Switch View" button control - //@formatter:off - var btnInstanceProperties = - { - "selectCallback" : this._switchViewButtonHandler.bind(this), - "enabledClass" : "FuelConsumptionCtrlSwitchView", - "disabledClass" : null, - "focusedClass": null, - "downClass" : "FuelConsumptionCtrlSwitchViewDown", - "heldClass" : null, - "appData" : this.properties.appData, - "label" : this.properties.switchViewLabelText, - "labelId" : this.properties.switchViewLabelId, - "subMap" : this.properties.subMap, - }; - //@formatter:on - if(this.properties.mode !== 'ending' ) - { - this._switchViewButtonCtrl = framework.instantiateControl(this.uiaId, - this.fuelEfficiencyArea, - "ButtonCtrl", - btnInstanceProperties); - } - - - this._init(); -} - - -/****************************************/ -/* Translation & text utility functions */ -/****************************************/ - -/* - * Utility function to look up a translatable string ID and/or accept a default text string. - */ -FuelConsumptionCtrl.prototype._translateString = function(strId, strText, subMap) -{ -// log.debug("_translateString called: strId = " + strId + ", strText = " + strText); - - var translatedText = null; - - if (strId) - { - translatedText = framework.localize.getLocStr(this.uiaId, strId, subMap); - } - else if (strText) - { - translatedText = strText; - } - - return translatedText; -} - -/* - * Utility function to make a text string suitable for HTML block-rendering - */ -FuelConsumptionCtrl.prototype._stringToHTML = function(textStr) -{ -// log.debug("_stringToHTML called: textStr = " + textStr); - - var htmlText; - - if (textStr) - { - htmlText = textStr + "
    "; - } - else - { - htmlText = ""; - } - - return htmlText; -} - - -/*********************************************************/ -/* Utility functions for the CDFE graph & its animations */ -/*********************************************************/ - -/* - * Utility function to add axis labels to the CDFE graph - */ -FuelConsumptionCtrl.prototype._addCDFEGraphAxisLabels = function(xDiv, yDiv) -{ -// log.debug("FuelConsumptionCtrl: _addCDFEGraphAxisLabels() called..."); - - // NOTE: We're assuming 15 labels. Should this change, - // we'd need to revisit this - var barVal = 60; - for (var i = 0; i < 6; i++) - { - var barLabel = document.createElement('span'); - barLabel.innerHTML = barVal; - barLabel.style.position = 'absolute'; - barLabel.style.left = this._CSSConstants["CDFEGraphBarMarginRight"] + - (i * (this._CSSConstants["CDFEGraphBarWidthRight"] + - this._CSSConstants["CDFEGraphBarSpacingRight"]) - 18) + 'px'; - barLabel.style.width = this._CSSConstants["CDFEGraphBarWidthRight"] + 'px'; - xDiv.appendChild(barLabel); - barVal -= 10; - } - - var barLabel = document.createElement('span'); - barLabel.innerHTML = (this._totalCDFEBarsRight - 1); - barLabel.style.position = 'absolute'; - barLabel.style.left = this._CSSConstants["CDFEGraphBarMarginRight"] + - (8 * (this._CSSConstants["CDFEGraphBarWidthRight"] )+ - this._CSSConstants["CDFEGraphBarSpacingRight"] - 19) + 'px'; - barLabel.style.width = this._CSSConstants["CDFEGraphBarWidthRight"] + 'px'; - xDiv.appendChild(barLabel); - - - this.yLimitValueLabelCDFE = document.createElement('span'); - this.yLimitValueLabelCDFE.innerHTML = this.properties.currentFuelConfig.yAxisLimitValue; - yDiv.appendChild(this.yLimitValueLabelCDFE); - - var yUnitLabel = document.createElement('span'); - yUnitLabel.style.position = 'absolute'; - yUnitLabel.style.width = '100px'; - yUnitLabel.style.top = '90px'; - - var yZeroLabel = document.createElement('span'); - this.properties.currentFuelConfig.yAxisLabelText = - this._translateString(this.properties.currentFuelConfig.yAxisLabelId, - this.properties.currentFuelConfig.yAxisLabelText, - this.properties.subMap); - yUnitLabel.innerHTML = this.properties.currentFuelConfig.yAxisLabelText; - var xAxisLabelMinuteText = this._translateString(this.properties.xAxisLabelMinuteId, - this.properties.xAxisLabelMinuteText, this.properties.subMap); - - yZeroLabel.innerHTML = '0'+xAxisLabelMinuteText; - yZeroLabel.style.position = 'absolute'; - yZeroLabel.style.width = '60px'; - yZeroLabel.style.top = '115px'; - yZeroLabel.style.left = '466px'; - this.yZeroLabelCDFE = yUnitLabel; - yDiv.appendChild(yUnitLabel); - yDiv.appendChild(yZeroLabel); -} - -/* - * Utility function to set the horizontal positions of the CDFE graph bars - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarPositions = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarPositions() called..."); - - var leftInc = this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]; - var currentLeft = this._CSSConstants["CDFEGraphBarMargin"]; - - for (var i = 1; i <= this._totalCDFEBars; i++) - { - var bar = document.getElementById('CDFEBar' + i); - if (bar) - { - bar.style.left = currentLeft + 'px'; - } - - - // Adding new disc logic for hevstyle - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + i); - if(disc) - { - disc.style.left = currentLeft + 'px'; - } - } - - currentLeft += leftInc; - } -} -/**********************************New Defination of function**********************************/ - -FuelConsumptionCtrl.prototype._setCDFEGraphBarPositionsRight = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarPositions() called..."); - - var leftIncRight = this._CSSConstants["CDFEGraphBarWidthRight"] + - this._CSSConstants["CDFEGraphBarSpacingRight"]; - var currentLeftMarginRight = this._CSSConstants["CDFEGraphBarMarginRight"]; - - for (var i = 1; i <= this._totalCDFEBarsRight; i++) - { - var barRight = document.getElementById('CDFEBarRight' + i); - if (barRight) - { - barRight.style.left = currentLeftMarginRight + 'px'; - } - - // Adding new disc logic for hevstyle - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBarRight' + i); - if(disc) - { - disc.style.left = currentLeftMarginRight + 'px'; - } - } - - currentLeftMarginRight += leftIncRight; - } -} - -/**********************************End of New Defination of function**********************************/ -/* - * Utility function to enable/disable fade transitions for the CDFE line graph - */ -FuelConsumptionCtrl.prototype._setCDFELineGraphFadeTransitions = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCDFELineGraphFadeTransitions() called: isEnabled = " + isEnabled); - - var lineGraphCanvas = document.getElementById('FuelConsumptionCtrlCDFELineGraphCanvas'); - if (lineGraphCanvas) - { - var transitionStr; - - if (isEnabled) - { - log.debug (' enabling canvas opacity transition'); - transitionStr = 'opacity 0.6s linear 0s'; - } - else - { - log.debug (' disabling canvas opacity transition'); - transitionStr = 'none'; - } - - lineGraphCanvas.style.OTransition = transitionStr; - } -} - -/* - * Utility function to enable/disable height transitions for the CDFE graph bars - * (except the "hidden" new value bar) - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightTransitions = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeightTransitions() called: isEnabled = " + isEnabled); - - var transitionStr; - - // TODO: Figure out why this needs to be backwards to work! - if (!isEnabled) - { - transitionStr = 'height 0.6s ease 0s'; - } - else - { - transitionStr = 'none'; - } - - for (var i = 0; i <= this._youngestCDFEDataIdx; i++) - { - var bar = document.getElementById('CDFEBar' + (i + 1)); - if (bar) - { - bar.style.OTransition = transitionStr; - } - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + (i + 1)); - if (disc) - { - disc.style.OTransition = transitionStr; - } - } - } -} - -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightTransitionsRight = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeightTransitions() called: isEnabled = " + isEnabled); - - var transitionStr; - - // TODO: Figure out why this needs to be backwards to work! - if (!isEnabled) - { - transitionStr = 'height 0.6s ease 0s'; - } - else - { - transitionStr = 'none'; - } - - for (var i = 0; i <= this._youngestCDFEDataIdxRight; i++) - { - var bar = document.getElementById('CDFEBarRight' + (i + 1)); - if (bar) - { - bar.style.OTransition = transitionStr; - } - - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBarRight' + (i + 1)); - if (disc) - { - disc.style.OTransition = transitionStr; - } - } - } -} - - - -/* - * Utility function to set the height of a single CDFE graph bar (e.g. the just-inserted one) - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeight = function(barIdx,HEVMode) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CDFEBar' + (barIdx + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CDFEGraphVisibleHeight"], - this._CDFEGraphBarValues[barIdx], - this.properties.currentFuelConfig.yAxisLimitValue, - false) + 'px'; - - - } - - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + (barIdx + 1)); - if (disc) - { - /*disc.style.height = this._scaleDataToGraphY(this._CSSConstants["CDFEGraphVisibleHeight"], - this._CDFEDiscValues[barIdx], - this.properties.currentFuelConfig.yAxisLimitValue, - false) + 'px';*/ - if(HEVMode) - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreenHighLighted'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrentGreenHighLighted'; - } - else - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - } - disc.style.height = this._CDFEDiscValues[barIdx]+'px'; - - } - } -} - - -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightRight = function(barIdx) -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CDFEBarRight' + (barIdx + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CDFEGraphVisibleHeightRight"], - this._CDFEGraphBarValuesRight[barIdx], - this.properties.currentFuelConfig.yAxisLimitValue, - false) + 'px'; - } -} - -/* - * Utility function to set the heights of all of the CDFE graph bars - */ -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeights = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeights() called..."); - - // Cache reused values - var graphHeight = this._CSSConstants["CDFEGraphVisibleHeight"]; - var yLimit = this.properties.currentFuelConfig.yAxisLimitValue; - - for (var i = 0; i < this._totalCDFEBars; i++) - { - var bar = document.getElementById('CDFEBar' + (i + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphBarValues[i], - yLimit, - false) + 'px'; - } - - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBar' + (i + 1)); - if (disc) - { - /*disc.style.height = this._scaleDataToGraphY(graphHeight, - this._CDFEDiscValues[i], - yLimit, - false) + 'px'; */ - disc.style.height = this._CDFEDiscValues[i]+'px'; - } - } - } -} - -FuelConsumptionCtrl.prototype._setCDFEGraphBarHeightsRight = function() -{ -// log.debug("FuelConsumptionCtrl: _setCDFEGraphBarHeights() called..."); - - // Cache reused values - var graphHeight = this._CSSConstants["CDFEGraphVisibleHeightRight"]; - var yLimit = this.properties.currentFuelConfig.yAxisLimitValue; - - for (var i = 0; i < this._totalCDFEBarsRight; i++) - { - var bar = document.getElementById('CDFEBarRight' + (i + 1)); - - if (bar) - { - bar.style.height = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphBarValuesRight[i], - yLimit, - false) + 'px'; - } - if(this.properties.ctrlStyle === 'hevstyle') - { - var disc = document.getElementById('CDFEDiscBarRight' + (i + 1)); - if (disc) - { - disc.style.height = this._CDFEDiscBarValuesRight[i]+ 'px'; - } - } - } -} - -/* - * Utility function to render an interval of the CDFE line graph, using a canvas overlay - */ -FuelConsumptionCtrl.prototype._drawCDFELineGraphInterval = function(startIdx, endIdx, clearCanvas) -{ -// log.debug("FuelConsumptionCtrl: _drawCDFELineGraphInterval() called..."); - - if ((typeof(startIdx) === 'number') && - (typeof(endIdx) === 'number') && - (startIdx < endIdx) && - (startIdx >= 0) && - (endIdx < this._totalCDFEBars)) - { - // Horizontal distance between bar centers - var barInterval = this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]; - - // Center of leftmost (oldest) bar in interval - var leftX = (this._CSSConstants["CDFEGraphBarSpacing"] + - (this._CSSConstants["CDFEGraphBarWidth"] / 2)) + - (barInterval * startIdx); - - // Center of next bar - var rightX = leftX + barInterval; - var leftY; - var rightY; - - // Constants - var graphHeight = this._CSSConstants["CDFEGraphVisibleHeight"]; - var yLimit = this.properties.currentFuelConfig.yAxisLimitValue; - - // Reset the canvas (if needed) - if (clearCanvas) - { - this.CDFELineGraphCanvas.width = this.CDFELineGraphCanvas.width; - } - - // Set up for drawing - this._CDFELineGraphCanvasDC.lineWidth = 2; - this._CDFELineGraphCanvasDC.beginPath(); - this._CDFELineGraphCanvasDC.strokeStyle = "#00CC00"; - - // Initialize leftY & rightY - if (this._CDFEGraphLineValues[startIdx]) - { - leftY = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphLineValues[startIdx], - yLimit, - true); - } - else - { - leftY = null; - } - - for (var i = startIdx + 1; i <= endIdx; i++) - { - // Scale value as rightY - if (this._CDFEGraphLineValues[i]) - { - rightY = this._scaleDataToGraphY(graphHeight, - this._CDFEGraphLineValues[i], - yLimit, - true); - } - else - { - rightY = null; - } - - // If we have both endpoints, ... - if (leftY && rightY) - { - // ... draw the line segment between them - this._CDFELineGraphCanvasDC.moveTo(leftX, leftY); - this._CDFELineGraphCanvasDC.lineTo(rightX, rightY); - } - - // Advance to next value - leftY = rightY; - leftX = rightX; - rightX += barInterval; - } - - // Stroke the path - this._CDFELineGraphCanvasDC.stroke(); - } -} - -/* - * Shortcut utility function to render the entire CDFE line graph - */ -FuelConsumptionCtrl.prototype._drawCDFELineGraph = function() -{ -// log.debug("FuelConsumptionCtrl: _drawCDFELineGraph() called..."); - - this._drawCDFELineGraphInterval(0, this._newCDFEDataIdx, true); -} - -/* - * Utility function for resetting the CDFE graph - * (redraw it with the "new" bar hidden on the right-hand side) - */ -// -FuelConsumptionCtrl.prototype._resetCDFEGraph = function(animateBars) -{ -// log.debug("FuelConsumptionCtrl: _resetCDFEGraph() called: animateBars = " + animateBars); - - // Make sure left transitions are OFF for the CDFE graph active area while we redraw it - this.CDFEGraphArea.style.OTransition = 'none'; - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphArea.style.OTransition = 'none'; - } - - // Enable/disable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitions(animateBars); - if(this.properties.ctrlStyle === 'hevstyle') - { - - for(var i = 0; i <= 10; i++) - { - var bar = document.getElementById('CDFEBar'+(i+1)); - var disc = document.getElementById('CDFEDiscBar' +(i+1)); - if(this._initialEVMode[i] && bar) - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreen'; - disc.className = 'FuelConsumptionCtrlHevCDFEDiscBg_Green'; - if(i == 9) - { - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrentGreenHighLighted'; - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreenHighLighted'; - break; - } - - } - else - { - if(i == 9 || i == 10) - { - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCoreCurrent'; - } - else - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - disc.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - } - } - } - } - else - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrent'; - } - // Reposition the CDFE graph active area & reconstruct the bar/line graph - // (should be no visible difference afterwards) - this.CDFEGraphArea.style.left = '0px'; - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphArea.style.left = '0px'; - } - this._setCDFEGraphBarHeights(); - - - // Disable/enable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitions(!animateBars); -} - -FuelConsumptionCtrl.prototype._resetCDFEGraphRight = function(animateBars) -{ -// log.debug("FuelConsumptionCtrl: _resetCDFEGraph() called: animateBars = " + animateBars); - - // Make sure left transitions are OFF for the CDFE graph active area while we redraw it - this.CDFEGraphAreaRight.style.OTransition = 'none'; - - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphAreaRight.style.OTransition = 'none'; - } - - // Enable/disable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitionsRight(animateBars); - - if(this.properties.ctrlStyle === 'hevstyle') - { - for(var i = 0; i < 5; i++) - { - var bar = document.getElementById('CDFEBarRight'+(i+1)); - var disc = document.getElementById('CDFEDiscBarRight' +(i+1)); - if(this._CDFEEvModeRight[i] && bar) - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreGreenRight'; - disc.className = 'FuelConsumptionCtrlHevCDFEDiscGraphCoreGreenRight'; - } - else - { - bar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreRight'; - disc.className = 'FuelConsumptionCtrlHevCDFEDiscGraphCoreRight'; - } - } - } - - - // Reposition the CDFE graph active area & reconstruct the bar/line graph - // (should be no visible difference afterwards) - this.CDFEGraphAreaRight.style.left = '0px'; - if(this.properties.ctrlStyle === 'hevstyle') - { - this.CDFEDiscGraphAreaRight.style.left = '0px'; - } - this._setCDFEGraphBarHeightsRight(); - - // Disable/enable height transitions for the CDFE graph bars - this._setCDFEGraphBarHeightTransitionsRight(!animateBars); -} - -/* - * Callback function for removing the animation on the CDFE line graph at the end of its fade-in - */ -FuelConsumptionCtrl.prototype._onCDFELineFadeAnimationEnd = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCDFELineFadeAnimationEnd() called"); - - // Remove the event listener that got us here - this.CDFELineGraphCanvas.removeEventListener('oTransitionEnd', this._cbCDFELineFadeAnimationEnd, false); - - // Stop propagating the event - e.stopPropagation(); - - // Disable the line graph fade animation - this._setCDFELineGraphFadeTransitions(false); -} - -/* - * Callback function for resetting the CDFE graph at the end of a slide-left (insertion) animation - */ -FuelConsumptionCtrl.prototype._onCDFELeftAnimationEnd = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCDFELeftAnimationEnd() called..."); - - // Remove the event listener that got us here - this.CDFEGraphArea.removeEventListener('oTransitionEnd', this._cbCDFELeftAnimationEnd, false); - - // Stop propagating the event - e.stopPropagation(); - - // We're no longer in the transition - this._CDFELineGraphInTransition = false; - - // Reset the CDFE graph without bar animations - this._resetCDFEGraph(false); -} - - -/************************************ New Function Added************************************************/ -FuelConsumptionCtrl.prototype._onCDFELeftAnimationEndRight = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCDFELeftAnimationEndRight() called..."); - - // Remove the event listener that got us here - this.CDFEGraphAreaRight.removeEventListener('oTransitionEnd', this._cbCDFELeftAnimationEndRight, false); - - // Stop propagating the event - e.stopPropagation(); - - // We're no longer in the transition - this._CDFELineGraphInTransition = false; - - // Reset the CDFE graph without bar animations - this._resetCDFEGraph(false); -} -/************************************End of New Function Added************************************************/ - - -/*********************************************************/ -/* Utility functions for the CFER graph & its animations */ -/*********************************************************/ - -/* - * Utility function to add axis labels to the CFER graphadd - */ -FuelConsumptionCtrl.prototype._addCFERGraphAxisLabels = function(xDiv, yDiv) -{ -// log.debug("FuelConsumptionCtrl: _addCFERGraphAxisLabels() called..."); - - var leftInc = this._CSSConstants["CFERGraphBarWidth"] + - this._CSSConstants["CFERGraphBarSpacing"]; - var currentLeft = this._CSSConstants["CFERGraphBarMargin"]; - - for (var i = 0; i <= this._currentCFERDataIdx; i++) - { - var span = document.createElement('span'); - - span.style.position = 'absolute'; - span.style.left = currentLeft + 'px'; - span.style.width = this._CSSConstants["CFERGraphBarWidth"] + 'px'; - span.style.textAlign = 'center'; - - if (i === (this._currentCFERDataIdx - 1)) - { - this.properties.cumulativeFuelConfig.xAxisLabelText = - this._translateString(this.properties.cumulativeFuelConfig.xAxisLabelId, - this.properties.cumulativeFuelConfig.xAxisLabelText, - this.properties.subMap); - span.innerHTML = this._stringToHTML(this.properties.cumulativeFuelConfig.xAxisLabelText); - span.style.marginLeft = '-8px'; - span.style.width = '71px'; - } - else - { - if(i != this._currentCFERDataIdx) - { - span.innerHTML = (this._currentCFERDataIdx - i) + ''; - } - - } - - - currentLeft += leftInc; - xDiv.appendChild(span); - } - - - this.yLimitValueLabelCFER = document.createElement('span'); - this.yLimitValueLabelCFER.innerHTML = this.properties.cumulativeFuelConfig.yAxisLimitValue; - yDiv.appendChild(this.yLimitValueLabelCFER); - - var yZeroLabel = document.createElement('span'); - this.properties.cumulativeFuelConfig.yAxisLabelText = - this._translateString(this.properties.cumulativeFuelConfig.yAxisLabelId, - this.properties.cumulativeFuelConfig.yAxisLabelText, - this.properties.subMap); - yZeroLabel.innerHTML = this._stringToHTML(this.properties.cumulativeFuelConfig.yAxisLabelText); - yZeroLabel.style.position = 'absolute'; - yZeroLabel.style.width = '60px'; - if(this.properties.ctrlStyle === "hevstyle") - { - yZeroLabel.style.top = '90px'; - } - else - { - yZeroLabel.style.top = (this._CSSConstants["CFERGraphVisibleHeight"] - 47) + 'px'; - } - this.yZeroLabelCFER = yZeroLabel; - yDiv.appendChild(yZeroLabel); -} - -/* - * Utility function to set the horizontal positions of the CFER graph bars - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarPositions = function() -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarPositions() called..."); - - var leftInc = this._CSSConstants["CFERGraphBarWidth"] + - this._CSSConstants["CFERGraphBarSpacing"]; - var currentLeft = this._CSSConstants["CFERGraphBarMargin"]; - - for (var i = 1; i <= this._totalCFERBars; i++) - { - var bar = document.getElementById('CFERBar' + i); - if (bar) - { - bar.style.left = currentLeft + 'px'; - } - - currentLeft += leftInc; - } -} - -/* - * Utility function to enable/disable height transitions for the CFER graph bars - * (except the "hidden" new value bar) - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarHeightTransitions = function(isEnabled) -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeightTransitions() called: isEnabled = " + isEnabled); - - var transitionStr; - - // TODO: Figure out why this needs to be backwards to work! - if (!isEnabled) - { - transitionStr = "height 0.6s ease 0s"; - } - else - { - transitionStr = "none"; - } - - for (var i = 0; i <= this._currentCFERDataIdx; i++) - { - var bar = document.getElementById('CFERBar' + (i + 1)); - if (bar) - { - bar.style.OTransition = transitionStr; - if(i==5) - { - bar.style.OTransition = "none"; - } - } - } -} - -/* - * Utility function to set the height of single CFER graph bar (e.g. the just-inserted one) - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarHeight = function(barIdx) -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CFERBar' + (barIdx + 1)); - if (bar) - { - - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CFERGraphVisibleHeight"], - this._CFERGraphBarValues[barIdx], - this.properties.cumulativeFuelConfig.yAxisLimitValue, - false) + 'px'; - - } -} - -FuelConsumptionCtrl.prototype._setCFERGraphBarHeightNew = function(barIdx) -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeight() called: barIdx = " + barIdx); - - var bar = document.getElementById('CFERBar' + (barIdx + 1)); - if (bar) - { - - bar.style.height = this._scaleDataToGraphY(this._CSSConstants["CFERGraphVisibleHeight"], - this._CFERGraphBarValues[barIdx + 1], - this.properties.cumulativeFuelConfig.yAxisLimitValue, - false) + 'px'; - - // Set the height of the current bar value to retain its display positioon on top of current bar - this.CFERCurrentBarValue.style.height = this._scaleDataToGraphY(this._CSSConstants["CFERGraphVisibleHeight"], - this._CFERGraphBarValues[barIdx + 1], - this.properties.cumulativeFuelConfig.yAxisLimitValue, - false) + 'px'; - } -} - - - -/* - * Utility function to set the heights of all of the CFER graph bars - */ -FuelConsumptionCtrl.prototype._setCFERGraphBarHeights = function() -{ -// log.debug("FuelConsumptionCtrl: _setCFERGraphBarHeights() called..."); - - // Cache reused values - var graphHeight = this._CSSConstants["CFERGraphVisibleHeight"]; - var yLimit = this.properties.cumulativeFuelConfig.yAxisLimitValue; - - for (var i = 0; i < this._totalCFERBars; i++) - { - var bar = document.getElementById('CFERBar' + (i + 1)); - if (bar) - { - bar.style.height = this._scaleDataToGraphY(graphHeight, - this._CFERGraphBarValues[i], - yLimit, - false) + 'px'; - } - } -} - -/* - * Utility function for resetting the CFER graph - * (redraw it with the "new" bar hidden on the right-hand side) - */ -FuelConsumptionCtrl.prototype._resetCFERGraph = function(animateBars) -{ -// log.debug("FuelConsumptionCtrl: _resetCFERGraph() called: animateBars = " + animateBars); - - // Make sure left transitions are OFF for the CFER graph active area while we redraw it - this.CFERGraphArea.style.OTransition = 'none'; - - // Enable/disable height transitions for the CFER graph bars - this._setCFERGraphBarHeightTransitions(animateBars); - - // Reposition the CFER graph active area & reconstruct the bar graph - // (should be no visible difference afterwards) - this.CFERGraphArea.style.left = '0px'; - this._setCFERGraphBarHeights(); - - // Disable/enable height transitions for the CFER graph bars - this._setCFERGraphBarHeightTransitions(!animateBars); -} - -/* - * Callback function for resetting the CFER graph at the end of a slide-left (insertion) animation - */ -FuelConsumptionCtrl.prototype._onCFERLeftAnimationEnd = function(e) -{ -// log.debug("FuelConsumptionCtrl: _onCFERLeftAnimationEnd() called..."); - - // Remove the event listener that got us here - this.CFERGraphArea.removeEventListener('oTransitionEnd', this._cbCFERLeftAnimationEnd, false); - - // Stop propagating the event - e.stopPropagation(); - - // Reset the CFER graph without bar animations - this._resetCFERGraph(false); -} - - -/***************************/ -/* Other utility functions */ -/***************************/ - -/* - * Utility function to convert a graph's data point to a Y-coordinate - */ -FuelConsumptionCtrl.prototype._scaleDataToGraphY = function(maxY, dataValue, maxDataValue, invertY) -{ -// log.debug("FuelConsumptionCtrl: _scaleDataToGraphY() called: maxY = " + maxY + -// "dataValue = " + dataValue + ", maxDataValue = " + maxDataValue + -// "invertY = " + invertY); - - var yVal = Math.floor(dataValue / maxDataValue * maxY); - - if (invertY) - { - yVal = maxY - yVal; - } - - return yVal; -} - -/* - * Callback for "Switch View" button selections -- when called, trigger the - * configured application callback. - */ -FuelConsumptionCtrl.prototype._switchViewButtonHandler = function(buttonObj, appData, params) -{ -// log.debug("FuelConsumptionCtrl: _onCFERLeftAnimationEnd() called: buttonObj = " + buttonObj + -// ", appData = " + appData + ", params = " + params); - - if (typeof(this.properties.switchViewButtonCallback) === "function") - { - this.properties.switchViewButtonCallback(this, appData, null); - } - else - { - log.warn("FuelConsumptionCtrl: no valid switchViewButtonCallback configured"); - } -} - -/******************/ -/* Public Methods */ -/******************/ - -FuelConsumptionCtrl.prototype.initializeCurrentDriveFuelGraph = function(initialBarValues) -{ - log.debug("FuelConsumptionCtrl: initializeCurrentDriveFuelGraph() called: initialBarValues = " + - initialBarValues); - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdx; ibvIdx++) - { - if (initialBarValues[ibvIdx]) - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = initialBarValues[ibvIdx]; - } - else - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = 0; - } - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraph(true); - -} - -// to initialise the HEV fuel eco bar graph with the disc -FuelConsumptionCtrl.prototype.initialiseHEVFuelGraph = function(initialBarValues, intialDiscValues, initialEVModes, initialHalfDiscs) -{ - - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdx; ibvIdx++) - { - if ((initialBarValues[ibvIdx] !== null) && (initialBarValues[ibvIdx] !== undefined)) - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = initialBarValues[ibvIdx]; - //this._initialHalfDisc[this._youngestCDFEDataIdx - ibvIdx] = initialHalfDiscs[ibvIdx]; - this._initialEVMode[this._youngestCDFEDataIdx - ibvIdx] = initialEVModes[ibvIdx]; - } - else - { - this._CDFEGraphBarValues[this._youngestCDFEDataIdx - ibvIdx] = 0; - //this._initialHalfDisc[this._youngestCDFEDataIdx - ibvIdx] = 0; - this._initialEVMode[this._youngestCDFEDataIdx - ibvIdx] = false; - } - if(intialDiscValues) - { - if(initialHalfDiscs[ibvIdx]) - { - this._CDFEDiscValues[this._youngestCDFEDataIdx - ibvIdx] = intialDiscValues[ibvIdx] * 13 + 7; - } - else - { - this._CDFEDiscValues[this._youngestCDFEDataIdx - ibvIdx] = intialDiscValues[ibvIdx] * 13; - } - } - else - { - this._CDFEDiscValues[this._youngestCDFEDataIdx - ibvIdx] = 0; - } - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - this._CDFEDiscValues[this._newCDFEDataIdx] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraph(true); - -} - - -FuelConsumptionCtrl.prototype.initializeCurrentDriveFuelGraphRight = function(initialBarValues) -{ - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdxRight; ibvIdx++) - { - if (initialBarValues[ibvIdx]) - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialBarValues[ibvIdx]; - } - else - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = 0; - } - - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraphRight(true); - -} - -FuelConsumptionCtrl.prototype.initializeHEVCurrentDriveFuelGraphRight = function(initialBarValues, initialLDiscValues, initialHalfDiscs, evModes) -{ - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CDFEGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCDFEDataIdxRight; ibvIdx++) - { - //if (initialBarValues[ibvIdx]) - if (typeof(initialBarValues[ibvIdx]) === 'number') - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialBarValues[ibvIdx]; - //if(initialHalfDiscs[ibvIdx]) - if(initialHalfDiscs[ibvIdx]=== true) - { - this._CDFEDiscBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialLDiscValues[ibvIdx] * 13 + 7; - } - else if(initialHalfDiscs[ibvIdx]=== false) - { - this._CDFEDiscBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = initialLDiscValues[ibvIdx] * 13; - } - this._CDFEEvModeRight[this._youngestCDFEDataIdxRight - ibvIdx] = evModes[ibvIdx]; - } - else - { - this._CDFEGraphBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = 0; - this._CDFEDiscBarValuesRight[this._youngestCDFEDataIdxRight - ibvIdx] = 0; - } - - } - - // Initialize the "hidden" slot for new data - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = 0; - this._CDFEDiscBarValuesRight[this._newCDFEDataIdxRight] = 0; - } - - // Initialize the CDFE graph with bar animations - this._resetCDFEGraphRight(true); -} - - -FuelConsumptionCtrl.prototype.insertCurrentDriveFuelGraph = function(currentBarValue) -{ - log.debug("FuelConsumptionCtrl: insertCurrentDriveFuelGraph() called: currentBarValue = " + - currentBarValue); - - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = currentBarValue; - } - else - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - } - - - // Update the new value's bar in the CDFE graph - this._setCDFEGraphBarHeight(this._newCDFEDataIdx); - - - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - - // Turn on left transitions for the CDFE graph (for the next animation) - this.CDFEGraphArea.style.OTransition = 'left 0.6s ease 0s'; - - - // Attach an event listener to the CDFE graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CDFEGraphArea.addEventListener('oTransitionEnd', this._cbCDFELeftAnimationEnd, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CDFEGraphArea.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]) + 'px'; - this._CDFELineGraphInTransition = true; - - // Update the data sets to discard the oldest historical data - for (var i = 0; i <= this._youngestCDFEDataIdx; i++) - { - this._CDFEGraphBarValues[i] = this._CDFEGraphBarValues[i + 1]; - } - - // Re-initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; -} - -// inser new bar graph for HEV disc bars -FuelConsumptionCtrl.prototype.insertHEVFuelGraph = function(currentBarValue, currentDiscs, currentHEVMode, currentHalfDisc) -{ - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = currentBarValue; - //if(currentHalfDisc) - if(currentHalfDisc===true) - { - this._CDFEDiscValues[this._newCDFEDataIdx] = currentDiscs * 13 + 7; - } - else if(currentHalfDisc===false) - { - this._CDFEDiscValues[this._newCDFEDataIdx] = currentDiscs * 13; - } - this._initialEVMode[this._newCDFEDataIdx] = currentHEVMode; - } - else - { - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - this._CDFEDiscValues[this._newCDFEDataIdx] = 0; - this._initialEVMode[this._newCDFEDataIdx] = false; - } - - if(currentHEVMode) - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreen'; - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEDiscBg_Green'; - } - else - { - // this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - // this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - } - // Update the new value's bar in the CDFE graph - this._setCDFEGraphBarHeight(this._newCDFEDataIdx,currentHEVMode); - - // Turn on left transitions for the CDFE graph (for the next animation) - this.CDFEGraphArea.style.OTransition = 'left 0.6s ease 0s'; - this.CDFEDiscGraphArea.style.OTransition = 'left 0.6s ease 0s'; - - // Attach an event listener to the CDFE graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CDFEGraphArea.addEventListener('oTransitionEnd', this._cbCDFELeftAnimationEnd, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CDFEGraphArea.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]) + 'px'; - - this.CDFEDiscGraphArea.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidth"] + - this._CSSConstants["CDFEGraphBarSpacing"]) + 'px'; - - this._CDFELineGraphInTransition = true; - // Update the data sets to discard the oldest historical data - for (var i = 0; i <= this._youngestCDFEDataIdx; i++) - { - this._CDFEGraphBarValues[i] = this._CDFEGraphBarValues[i + 1]; - this._CDFEDiscValues[i] = this._CDFEDiscValues[i + 1]; - this._initialEVMode[i] = this._initialEVMode[i+1]; - } - - //if(currentHEVMode) - if(this._initialEVMode[8]) - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCoreCurrentGreen'; - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEDiscBg_Green'; - } - else - { - this.CDFECurrentBar.className = 'FuelConsumptionCtrlCDFEBarGraphCore'; - this.CDFECurrentDiscBar.className = 'FuelConsumptionCtrlHevCDFEBarGraphCore'; - } - // Re-initialize the "hidden" slot for new data - this._CDFEGraphBarValues[this._newCDFEDataIdx] = 0; - this._CDFEDiscValues[this._newCDFEDataIdx] = 0; -} - - -FuelConsumptionCtrl.prototype.insertCurrentDriveFuelGraphRight = function(currentBarValue) -{ - log.debug("FuelConsumptionCtrl: insertCurrentDriveFuelGraph() called: currentBarValue = " + - currentBarValue + ", currentLineValue = "); - - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = currentBarValue; - } - else - { - this._CDFEGraphBarValuesRight[this._newCDFEDataIdxRight] = 0; - } - - // Update the new value's bar in the CDFE graph - this._setCDFEGraphBarHeightRight(this._newCDFEDataIdxRight); - - // Turn on left transitions for the CDFE graph (for the next animation) - this.CDFEGraphAreaRight.style.OTransition = 'left 0.6s ease 0s'; - - // Attach an event listener to the CDFE graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CDFEGraphAreaRight.addEventListener('oTransitionEnd', this._cbCDFELeftAnimationEndRight, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CDFEGraphAreaRight.style.left = '-' + (this._CSSConstants["CDFEGraphBarWidthRight"] + - this._CSSConstants["CDFEGraphBarSpacingRight"]) + 'px'; - - // Update the data sets to discard the oldest historical data - for (var i = 0; i <= this._youngestCDFEDataIdxRight; i++) - { - this._CDFEGraphBarValuesRight[i] = this._CDFEGraphBarValuesRight[i + 1]; - } - - // Re-initialize the "hidden" slot for new data - this._CDFEGraphBarValuesRight[this._newCDFEDataIdx] = 0; -} - -FuelConsumptionCtrl.prototype.initializeCumulativeFuelGraph = function(initialBarValues) -{ - log.debug("FuelConsumptionCtrl: initializeCumulativeFuelGraph() called: initialBarValues = " + - initialBarValues); - - if (initialBarValues) - { - // Initial bar values are in youngest-first order, while displayed values are - // in left-to-right order (oldest first). Copy the initialBarValues array to - // this._CFERGraphBarValues, reversing the order & initializing any omitted - // data to zero. - for (var ibvIdx = 0; ibvIdx <= this._youngestCFERDataIdx; ibvIdx++) - { - if (initialBarValues[ibvIdx]) - { - this._CFERGraphBarValues[this._youngestCFERDataIdx - ibvIdx] = initialBarValues[ibvIdx]; - } - else - { - this._CFERGraphBarValues[this._youngestCFERDataIdx - ibvIdx] = 0; - } - } - - // Initialize the "hidden" slot for new data - this._CFERGraphBarValues[this._newCFERDataIdx] = 0; - } - - // Initialize the CFER graph with bar animations - this._resetCFERGraph(true); -} - -FuelConsumptionCtrl.prototype.insertCurrentCumulativeFuelGraph = function(newResetValue) -{ - var currentBarValue = 0.0; - // Add the new bar value to the data set - if (typeof(currentBarValue) === 'number') - { - this._CFERGraphBarValues[this._newCFERDataIdx] = newResetValue; - } - else - { - this._CFERGraphBarValues[this._newCFERDataIdx] = 0.0; - } - - // Update the new value's bar in the CFER graph - this._setCFERGraphBarHeight(this._newCFERDataIdx); - - // Turn on left transitions for the CFER graph (for the next animation) - this.CFERGraphArea.style.OTransition = 'left 0.6s ease 0s'; - - // Attach an event listener to the CFER graph area so we can detect when - // the slide animation ends (and reset the graph for the next animation) - this.CFERGraphArea.addEventListener('oTransitionEnd', this._cbCFERLeftAnimationEnd, false); - - // Set the graph's position, triggering the animation - // ("normal" left - (width of one bar + bar spacing)) - this.CFERGraphArea.style.left = '-' + (this._CSSConstants["CFERGraphBarWidth"] + - this._CSSConstants["CFERGraphBarSpacing"]) + 'px'; - - // Update the data set to discard the oldest historical data - for (var i = 0; i <= this._currentCFERDataIdx; i++) - { - this._CFERGraphBarValues[i] = this._CFERGraphBarValues[i + 1]; - } - - // Re-initialize the "hidden" slot for new data - this._CFERGraphBarValues[this._newCFERDataIdx] = 0; -} - -FuelConsumptionCtrl.prototype.updateCurrentCumulativeFuelGraph = function(currentBarValue, unitRange) -{ - log.debug("FuelConsumptionCtrl: updateCurrentCumulativeFuelGraph() called: currentBarValue = " + - currentBarValue); - - // Save the current bar value - var tempNumber = currentBarValue; - - if(currentBarValue == null) - { - currentBarValue = 0; - tempNumber = '--.-'; - } - else if( currentBarValue == 0) - { - tempNumber = '0.0'; - } - - currentBarValue = parseFloat(currentBarValue); - this._cumulativeBarValue = tempNumber; - - // Check if current bar value exceeds the unit range - if(currentBarValue > unitRange) - { - currentBarValue = unitRange; - } - - if (typeof(currentBarValue) === 'number') - { - this._CFERGraphBarValues[10] = currentBarValue; - } - else - { - this._CFERGraphBarValues[10] = 0.0; - tempNumber = '0.0'; - } - - - - var currentValueDiv = document.getElementById("CFERBarValueCurrent"); - currentValueDiv.className = 'FuelConsumptionCtrlCFERBarValueCurrent'; - - currentValueDiv.innerHTML = this._stringToHTML(tempNumber); - // Update the current bar - var bar = document.getElementById('CFERBar' + 10); - if (bar) - { - // Make sure transitions are enabled for the current bar - bar.style.OTransition = 'height 0.6s ease 0s'; - this.CFERCurrentBarValue.style.OTransition = 'height 0.6s ease 0s'; - // Set the bar's height - this._setCFERGraphBarHeightNew(9); - } -} - -FuelConsumptionCtrl.prototype.setFuelEfficiency = function(fuelEfficiencyData) -{ - log.debug("FuelConsumptionCtrl: setFuelEfficiency() called: fuelEfficiency = " + - fuelEfficiencyData.fuelEfficiency + " " + - fuelEfficiencyData.fuelEfficiencyUnit); - - // Purge any "remembered" data - this.properties.fuelEfficiencyData = new Object(); - - if (fuelEfficiencyData && - (fuelEfficiencyData.fuelEfficiency || fuelEfficiencyData.fuelEfficiency == 0) && - fuelEfficiencyData.fuelEfficiencyUnit) - { - // Remember the passed-in data - this.properties.fuelEfficiencyData.fuelEfficiency = fuelEfficiencyData.fuelEfficiency; - this.properties.fuelEfficiencyData.fuelEfficiencyUnit = fuelEfficiencyData.fuelEfficiencyUnit; - - // Translate the fuel efficiency unit (e.g. "MPG" or "KML") into a readable unit string (e.g. "mpg" or "km/L") - var fuelEfficiencyUnitText = this._translateString(this.properties.fuelEfficiencyData.fuelEfficiencyUnit, - this.properties.fuelEfficiencyData.fuelEfficiencyUnit, - this.properties.subMap); - - // Set the displayed data/unit string - this.fuelEfficiencyValue.innerHTML = this.properties.fuelEfficiencyData.fuelEfficiency; - - this.fuelEfficiencyUnit.innerHTML = fuelEfficiencyUnitText; - - } - else - { - log.warn("Invalid fuel efficiency data received -- blanking display"); - - this.fuelEfficiencyValue.innerHTML = "--.-"; - this.fuelEfficiencyUnit.innerHTML = ""; - } -} - -FuelConsumptionCtrl.prototype.setEvDrvDistance = function(evObj) -{ - - var driveDisUnit = this._translateString(evObj.unitId, evObj.unitId, this.properties.subMap); - this.fuelEfficiencyHevDistanceUnit.innerHTML = this._stringToHTML(driveDisUnit); - - if(evObj.driveDistance !== null) - { - this.fuelEfficiencyHevDistanceValue.innerHTML = evObj.driveDistance; - } - else - { - this.fuelEfficiencyHevDistanceValue.innerHTML = "--.-" ; - } - - if(evObj.percentValue !== null) - { - this.fuelEfficiencyHevPercentValue.innerHTML = "("+evObj.percentValue+"%)"; - } - else - { - this.fuelEfficiencyHevPercentValue.innerHTML = "(--)" ; - } -} - -FuelConsumptionCtrl.prototype.setUnitInformation = function(obj) -{ - this.properties.cumulativeFuelConfig.yAxisLimitValue = obj.yAxisLimitValue; - this.properties.currentFuelConfig.yAxisLimitValue = obj.yAxisLimitValue; - this.properties.cumulativeFuelConfig.yAxisLabelId = obj.yAxisLabelId; - this.properties.currentFuelConfig.yAxisLabelId = obj.yAxisLabelId; - - this.properties.cumulativeFuelConfig.yAxisLabelText = - this._translateString(this.properties.cumulativeFuelConfig.yAxisLabelId, - this.properties.cumulativeFuelConfig.yAxisLabelText, - this.properties.subMap); - - this.properties.currentFuelConfig.yAxisLabelText = - this._translateString(this.properties.currentFuelConfig.yAxisLabelId, - this.properties.currentFuelConfig.yAxisLabelText, - this.properties.subMap); - - this.yZeroLabelCDFE.innerHTML = this.properties.currentFuelConfig.yAxisLabelText; - this.yLimitValueLabelCDFE.innerHTML = this.properties.currentFuelConfig.yAxisLimitValue; - this.yZeroLabelCFER.innerHTML = '
    ' + this.properties.cumulativeFuelConfig.yAxisLabelText; - this.yLimitValueLabelCFER.innerHTML = this.properties.cumulativeFuelConfig.yAxisLimitValue; -} -/* - * toggle Ump panel | status == "hidePanel" OR status == "showPanel" - */ -FuelConsumptionCtrl.prototype.toggleUmpPanel = function(status) -{ - if(status == "hidePanel") - { - this.umpPanelDiv.className = "UmpPanelDivDisable"; - this.umpCtrl.setRetracted(true); - this._umpPanelStatus = false; - } - else if(status == "showPanel") - { - this.umpPanelDiv.className = "UmpPanelDivEnable"; - this.umpCtrl.setRetracted(false); - this._umpPanelStatus = true; - } - else - { - log.warn("_triggerUmpPanel called with an unxpected argument: "+status); - } -} - -/** - * Context capture - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ - -FuelConsumptionCtrl.prototype.getContextCapture = function() -{ - log.debug("FuelConsumptionCtrl: getContextCapture() called..."); - var controlContextCapture = this.umpCtrl.getContextCapture(); - return controlContextCapture; -}; - - -FuelConsumptionCtrl.prototype.finishPartialActivity = function() -{ - log.debug("FuelConsumptionCtrl: finishPartialActivity() called..."); - this.umpCtrl.finishPartialActivity(); -} - - -/** - * Context restore - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ - -FuelConsumptionCtrl.prototype.restoreContext = function(controlContextCapture) -{ - log.debug("EcoEffectCtrl: restoreContext() "+ controlContextCapture); - this.umpCtrl.restoreContext(controlContextCapture); -}; - - -/* - * Forward all multicontroller events to our only child control, the "SwitchView" button - */ -FuelConsumptionCtrl.prototype.handleControllerEvent = function(eventId) -{ - log.debug("FuelConsumptionCtrl: handleControllerEvent() called: " + eventId); - - // Pass-through - if(this._umpPanelStatus && this.umpCtrl) - { - response = this.umpCtrl.handleControllerEvent(eventId); - return response; - } - else if(!this._umpPanelStatus && this._switchViewButtonCtrl) - { - response = this._switchViewButtonCtrl.handleControllerEvent(eventId); - return response; - } -} - -FuelConsumptionCtrl.prototype.cleanUp = function() -{ - // Clean up the "Switch View" child button control - if (this._switchViewButtonCtrl) - { - this._switchViewButtonCtrl.cleanUp(); - } - if(this.umpCtrl) - { - this.umpCtrl.cleanUp(); - } -} - -framework.registerCtrlLoaded("FuelConsumptionCtrl"); \ No newline at end of file diff --git a/app/files/tweaks/config_org/androidauto/usr/lib/gstreamer-0.10/libgstalsa.so b/app/files/tweaks/config_org/androidauto/usr/lib/gstreamer-0.10/libgstalsa.so deleted file mode 100644 index 9a22086..0000000 Binary files a/app/files/tweaks/config_org/androidauto/usr/lib/gstreamer-0.10/libgstalsa.so and /dev/null differ diff --git a/app/files/tweaks/config_org/list-loop/jci/gui/common/controls/List2/js/List2Ctrl.58.js b/app/files/tweaks/config_org/list-loop/jci/gui/common/controls/List2/js/List2Ctrl.58.js deleted file mode 100644 index 8bf6ddd..0000000 --- a/app/files/tweaks/config_org/list-loop/jci/gui/common/controls/List2/js/List2Ctrl.58.js +++ /dev/null @@ -1,13702 +0,0 @@ -/* - Copyright 2012 by Johnson Controls - __________________________________________________________________________ - - Filename: List2Ctrl.js - __________________________________________________________________________ - - Project: JCI-IHU - Language: EN - Author: avorotp - Date: - __________________________________________________________________________ - - Description: IHU GUI List 2 Control - - Revisions: - v0.1 - Initial revision - __________________________________________________________________________ - -*/ - -log.addSrcFile("List2Ctrl.js", "common"); - -/** - * ========================= - * CONSTRUCTOR - * ========================= - * Standard control constructor - * TAG: framework - * ========================= - * @param {string} - uiaid of the owning app - * @param {html element} - control parent - * @param {string} - control id - * @param {object} - control properties - * @return {List2Ctrl} - */ -function List2Ctrl(uiaId, parentDiv, controlId, properties) -{ - - /* - * --------------------------------------- - * DEFAULT CONTROL CONFIGURATION - * --------------------------------------- - */ - - // set default properties - this.properties = { - - /* CONFIGURATION PROVIDED BY APPS, CONTROLS OR FWK */ - // title config - title : {}, /* {object} If the value of the titleStyle property is “listTitle” this gives the - parameters of the list title – what style it has, what are its elements, etc. */ - titleConfiguration : 'noTitle', /* {string} The style of the top part of the list control. It can be either a textual content, - tabs that can be selected to change the list content, or no title to be shown. */ - - // tabs configuration - tabsButtonConfig : {}, /* {object} If the value of the titleStyle property is “tabsTitle” - this gives the parameters of the tabs control that will appear on the top of the list. */ - - // dataList - dataList : null, /* {object} Preset dataList of the control */ - protectDataList : false, /* {boolean} Wheter the list clones the dataList items array protecting the owning app's private - instance of that array from modifications by the list. */ - - // layout config - inDialog : false, /* {boolean} Indicates whether the list is contained in a dialog. - When set to true, special list control styling is implemented, with 3.5 lines. - The thickItems property must be false if inDialog is true. */ - dialogStyle : null, /* {string} Defines the list style when embedded in a dialog. - Requires inDialog property set to true. */ - numberedList : false, /* {boolean} Whether the numbered chrome arc is shown, with numbers on the left of each list line. */ - - // items config - thickItems : false, /* {boolean} Indicates whether the items in the list will be thin or thick. - Must be set to true if any items in the list are one of the two-line item styles. */ - smallItemText : false, /* {boolean} When True, all B Rank text in single-line item styles will be displayed as C Rank instead */ - listReorder : false, /* {boolean} Indicates whether the items in the list can be reordered by long press and dragging. */ - scrollTo : 0, /* {integer} Set the initial position of the list (where the list is initially scrolled to on display). - It accepts positive integers not exceeding the item count. - When higher number than the item count is provided, it is automatically lowered to the item count. - Requires having a dataList preset in the configuration. - Normally the specified item will be placed at the first visible list position. - However, if the specified item is near the end of the list it may be positioned - farther down to maintain normal “bottom of list” scroll positioning. */ - - focussedItem : 0, /* {integer} Which item has initial focus on list instantiation. - Requires the list to have a dataList preset in the configuration. */ - - hasLetterIndex : false, /* {boolean} Indicates whether the list will have a letter index showing on the right, containing - letters for quick jump to their respective list items (scroll positions) defined in letterIndexData. */ - letterIndexData : [], /* {array} Contains information for the scroll position of each letter as well as the letter label itself. */ - listBackground : null, /* {string} URL for a custom list background */ - - // callbacks - selectCallback : null, /* {function} Called when a list item is selected either by touch or by multicontroller or by voice. */ - longPressCallback : null, /* {function} Called on long press on an item. */ - holdStartCallback : null, /* {function} Called on start of hold (after longPress timeout expires) */ - holdStopCallback : null, /* {function} Called on end of hold (when the finger is lifted) */ - selectDisabledCallback : null, /* {function} Called when a disabled list item is selected. */ - slideCallback : null, /* {function} Called when the slider handle is being dragged on slider items */ - needDataCallback : null, /* {function} Called when the list has reached a point, when being scrolled, - where no more data for rendering the list items is available */ - loadingConfig: { /* {object} gives the app the ability to change the loading text while waiting the fitst items to come */ - loadingText: null, - loadingTextId: "common.Loading", - loadingSubMap: null, - image: null, - }, - - - /* CONFIGURATION USED INTERNALLY BY THE LIST */ - itemHeight : 64, - visibleItems : 6, - itemsBefore : 5, /* {integer} items before the top one */ - itemsAfter : 9, /* {integer} items after and including the top one */ - selectThreshold : 20, - hitTimeout : 0, - letterIndexHeight : 64, - visibleLetterIndexItems : 6, - letterIndexSelectTimeout : 1000, - - eventFilterThreshold : (guiConfig.debugMode) ? 0 : 50, - - longPressTimeout : 1500, - listReorderScrollTimeout : 0, // @SW00155245, needs faster scroll during re-oreder - - // multicontroller hold timeouts and intervals - autoscrollTier1Timeout : 1500, - autoscrollTier2Timeout : 5000, - autoscrollTier1Interval : 500, - autoscrollTier2Interval : 1000, - - hvThreshold : 45 * (Math.PI/180), - - sliderReferencePointRight : 665, - sliderReferencePointLeft : 94, - sliderWidth : 346, // {integer} will be passed to SliderCtrl - sliderHandleWidth : 43, // {integer} will be passed to SliderCtrl - indentOffset : 38, // defined in List2Ctrl_mixins.scss - // open/closed loop handling for sliders - minChangeInterval : 250, // {integer} will be passed to SliderCtrl - settleTime : 1000, // {integer} will be passed to SliderCtrl - rotationIdleDetectTime : 500, // {integer} will be passed to SliderCtrl - - toggleButtonWidth : 120, /* styles CSV-dependent */ - toggleReferencePointRight : 675, /* styles CSV-dependent */ - // open/closed loop handling for toggles - toggleMinChangeInterval : 250, /* {integer} number of ms that must occur between toggle callbacks. This is used for Outgoing Event Filtering */ - toggleSettleTime : 1000, /* {integer} number of ms between when the user last toggles the item, and when the item will - update to its last cached value. This is used for Incoming Event Filtering. */ - checkMinChangeInterval : 250, - checkSettleTime : 1000, - - stepMinChangeInterval : 0, /* {integer} number of ms that must occur between step callbacks. This is used for Outgoing Event Filtering */ - - wrapTextThreshold : 604, /* styles CSV-dependent */ - - poolsize : 15, /* {integer} has to be more than (itemsBefore + itemsAfter), preferably (itemsBefore + itemsAfter + 1) */ - showScrollIndicator : true, - scrollIndicatorMinSize : 20, - scrollIndicatorFadeTimeout : 0, - scrollIndicatorFadeOutDuration : 700, - scrollIndicatorFadeInDuration : 200, - - // flicking - swipeThreshold : 300, - swipeAnimationDuration : 300, - deceleration : 0.0006, - - scrollingDuringLoading : false, - loadingOverlayEnabled : true, - showLoadingOverlayTimeout : 200, /* {integer} the time that needs to pass before showing the loading overlay */ - hideLoadingOverlayTimeout : 0, /* {integer} the min time that needs to have passed before hiding the loading overlay */ - enableSecondaryItemRequest : true, - enableItemRequestOnScroll : false, - secondaryRequestLimit : 5, /* {integer} number of retries to get needed data to fill all the elements in the DOM */ - needDataTimeout : 3000, /* {integer} number of ms to wait before unlocking the list after needDataCallback is fired */ - requestSize : 20, /* has to be more than the poolsize, ideally poolsize + 5 */ - - }; - - // Merge with user configuration - for (var i in properties) - { - this.properties[i] = properties[i]; - } - - - /* - * --------------------------------------- - * INTERNAL CONTROL CONFIGURATION - * The following configuration should not be changed by - * the application or some other place outside this control. - * --------------------------------------- - */ - - /* - * the following list item types have a secondary multicontroller behavior - * i.e. when focussed and the user press select, the focus goes to - * an inner subwidget (slider, button or icon) and any subsequent - * multicontroller interaction is on these subwidget. The user - * exits this mode by pressing select again. At this point the - * respective callback should be fired. - */ - this._secondaryMulticontrollerTypes = [ - 'style12', // slider - 'style13', // slider - deprecated - 'styleStep', - 'styleLock', - ]; - - /* - * The following table contains items, that are okay to be displayed, even if they don't contain text. - */ - this._itemsWithNoText = [ - 'style28', - ]; - - /* - * Normally sliders are positioned to the right part of a listItem, and there is text/image on the left. - * So, clicks in different position of the list item have to be treated differently. - * However, for some slider items, that are positioned to the right an exception has to be made, in order - *for them to behave correctly. This table contains such items, and new ones can be added with ease. - */ - this._rightHittableArea = [ - 'style28', - ]; - - if (true === this.properties.inDialog) - { - this.properties.itemHeight = 64; // set item height regardless of the thickItems property - this.properties.thickItems = false; // update thickItems if set wrong - - // set visible items - switch (this.properties.dialogStyle) - { - case 'DialogStyle01' : - this.properties.visibleItems = 4; - break; - case 'DialogStyle02' : - this.properties.visibleItems = 3; - break; - case 'DialogStyle03' : - this.properties.visibleItems = 2; - break; - case 'DialogStyle04' : - this.properties.visibleItems = 5; - break; - default : - log.error('List2: Unsupported dialogStyle property set: ' + this.properties.dialogStyle); - break; - } - } - else - { - - this.properties.itemHeight = (this.properties.thickItems) ? 82 : 64; // set item height - - // set visible items - switch (this.properties.titleConfiguration) - { - case 'tabsTitle' : - this.properties.visibleItems = (this.properties.thickItems) ? 4 : 5; - this.properties.visibleLetterIndexItems = 5; - break; - case 'listTitle' : - switch (this.properties.title.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style03a' : - this.properties.visibleItems = (this.properties.thickItems) ? 4 : 5; - break; - case 'style05' : - this.properties.visibleItems = (this.properties.thickItems) ? 3 : 4; - break; - case 'style06' : - case 'style07' : - this.properties.visibleItems = (this.properties.thickItems) ? 2 : 3; - break; - case 'style08' : - this.properties.visibleItems = (this.properties.thickItems) ? 3 : 4; - break; - default : - this.properties.visibleItems = (this.properties.thickItems) ? 4 : 5; - break; - } - this.properties.visibleLetterIndexItems = 5; - break; - case 'noTitle' : - this.properties.visibleItems = (this.properties.thickItems) ? 5 : 6; - this.properties.visibleLetterIndexItems = 6; - break; - default : - log.error('Unknown title configuration set: ' + this.properties.titleConfiguration); - } - - } - - /* - * --------------------------------------- - * CONTROL PUBLIC PROPERTIES - * --------------------------------------- - */ - // set list properties - this.id = controlId; // control's id - this.parentDiv = parentDiv; // control's immediate parent DOM element - this.uiaId = uiaId; // uiaId of the owning app - - // list DOM elements - this.divElt = null; // control's container - this.title = null; // control's title - this.titleCanvas = null; // control's title preview image if supplied in the title config - this.mask = null; // control's mask (hides everything outside) - this.scroller = null; // control's main scrolling element - this.scrollIndicatorWrapper = null; // control's scroll indicator wrapper - this.scrollIndicator = null; // control's scroll indicator - this.loading = null; // control's loading item - //this.arc = null; // control's right most arc - this.activeArea = null; // control's hit-test area - this.letterIndexWrapper = null; // control's letter index area wrapper - this.letterIndex = null; // control's letter index area - this.listBackground = null; // control's custom background image - - // tabs - this.tabsCtrl = null; // reference to tabs control - - // animation callbacks - this.scrollerAnimationEndCallback = null; // fired when the scroller animation finishes - this.scrollIndicatorAnimationEndCallback = null; // fired when scrollIndicator animation finishes - this.letterIndexAnimationEndCallback = null; // fired when letter index animation finishes - this.firstFocusAnimationEndCallback = null; // fired when the first focus animation finishes - - // handlers - this.touchHandler = null; // fired on any mouse/touch event - - // dataList and items - this.pool = null; // {object} pool of list items - this.dataList = null; // {object} holds all the list data - this.items = new Array(); // {array} holds currently displayed list items. Usually these extend the visible range - - // letter index - this.letterIndexData = new Array(); // {array} holds letter index data - - /* - * --------------------------------------- - * CONTROL PRIVATE PROPERTIES - * These change a lot during interactions - * --------------------------------------- - */ - this._inDrag = false; // {boolean} indicates whether the list is currently being dragged - this._inScroll = false; // {boolean} indicates whether the list is currently being scrolled - - this._scrollerH = 0; // {integer} height of the scroller - this._maskPositionY = 0; // {integer} position of the mask - this._maskPositionX = 0; // {integer} position of the mask - this._maskH = 0; // {integer} height of the mask - this._maskW = 0; // {integer} width of the mask - this._startY = 0; // {integer} y position of the drag start - this._startX = 0; // {integer} x position of the drag start - this._startTime = 0; // {integer} when the dragging started - this._y = 0; // {integer} current position of the list - this._startItem = -1; // {integer} index of the item when dragging starts - this._startDOMItem = null; // {HMTL element} reference to the HTML element when dragging starts - - // inline buttons - this._startButton = null; // {integer} index of the toggle button that has first gained hit highlight - this._startLockButton = null; // {integer} index of the lock button that has first gained hit highlight - - this._minScrollY = 0; // {integer} top-most position of the list - this._maxScrollY = 0; // {integer} bottom-most position of the list - this._stopSelect = false; // {boolean} indicates whether to stop select (e.g. when the list is scrolling) - - this._initialScrollMode = null; // {string} Carries information about the nature of the initial scroll and focus restore if any - // possible values: 'init', 'config', 'restore' - - this._currentTitle = null; // {object} holds current title object as set with the setTitle method - this._leftBtnStyle = ''; // {string} left button numbers style based on list configuration - - // letter index - this._scrollerHIndex = 0; // {integer} height of the letter index scroller - this._inDragIndex = false; // {boolean} indicates whether the letter index is currently being dragged - this._startIndexY = 0; // {integer} y position of the letter index drag start - this._startIndexX = 0; // {integer} x position of the letter index drag start - this._startTimeIndex = 0; // {integer} when the letter index dragging started - this._yIndex = 0; // {integer} current position of the letter index - this._minScrollYIndex = 0; // {integer} top-most position of the letter index - this._maxScrollYIndex = 0; // {integer} bottom-most position of the letter index - this._topLetterIndex = 0; // {integer} the letter index that is currently on top - this._prevTopLetterIndex = 0; // {integer} the letter index that has been previously at top - - this._trackedEvents = []; // {array} tracks the events - this._indicatorMin = 0; // {integer} top-most position of the scroll indicator - this._indicatorMax = 0; // {integer} bottom-most position of the scroll indicator - this._topItem = 0; // {integer} the item currently on top (expressed as index in the this.dataList.items array) - this._prevTopItem = 0; // {integer} the item that has been previously on top - this._hasFill = false; // {boolean} whether the control has initially filled any items TODO: Think of how to remove this - this._inLoading = false; // {boolean} whether there's a loading in progress - this._secondaryRequestCount = 0; // {integer} current count of the secondary needDataCallback() calls - this._scrollNature = null; // {string} the nature of the scrolling action - this._lastControllerEvent = null; // {string} keeps the last received controller event - - this._isScrollable = false; // {boolean} indicates whether the list can be scrolled. It is unscrollable when the items are lte than the visible items - this._inputMode = 'controller';// {string} indicates the input mode. 'touch' || 'controller' - this._hasFocus = false; // {boolean} indicates whether the control currently has focus - this._showFocusAnimation = false; // {boolean} wheter the show the focus entry animation - this._focusStolen = false; // {boolean} flag that shows whether the focus placement is a result of a stolen focus - this._lastItemWithFocus = 0; // {integer} stores the last item index with focus when multicontroller lostFocus event comes in - this._inLetterIndexMulticontroller = false; // {boolean} indicates whether the multicontroller events should be directed to the letter index area if present - - // sorted letter index data - this._letterIndexDataSorted = new Array(); // {array} holds sorted letter index data - - // list loading - this._loadingData = { // {object} contains internal data for the loading overlay - timeStarted : 0, - timeShown : 0, - startTimeoutId : null, - endTimeoutId : null, - }; - - // horizontal drag - this._inHorizontalDrag = null; // {boolean|null} whether the drag is horizontal (or vertical). The default value is 'null' (it's has different meaning than 'false') - this._hDragItem = null; // {integer} index of the item currently being draagged horizontally - - // sliders - this._sliders = {}; // {object} hash with slider references - this._activeSlider = null; // {object} contains currently active slider - - // secondary multicontroller - this._currentSecondaryMulticontrollerItem = null; // {integer} - this._inSecondaryMulticontroller = false; // {boolean} indicates whether the multicontroller events should be directed to the subwidgets of the focussed item - - // longpress - this._inLongPress = false; // {boolean} indicates whether the list is in long press - this._longPressIssued = false; // {boolean} indicates whether the longPress/holdStart callback has been issued - - // list reordering - this._inListReorder = false; // {boolean} indicates whether the list is currently in reorder mode - this._reorderItem = null; // {object} copy of the list item that is going to be reordered - this._reorderItemIndex = null; // {integer} copy of the old index of the list item that is going to be reordered - this._reorderCurrentIndex = null; // {integer} current index of the reorder item before committing the change - this._reorderTouchElt = null; // {HTML DOM Element} the actual DOM list item - this._releaseReorderByTouch = false; // {boolean} indicates wheter the user is about to release the list reorder by touch - - // timeouts and intervals - this._makeHitTimeoutId = null; // {timeout} enter into hit state after some time - this._longPressTimeoutId = null; // {timeout} enter into longpress state after some time - this._touchReorderTimeoutId = null; // {timeout} enter into list reorder after some time - this._scrollIndicatorTimeoutId = null; // {timeout} fade out scroll indicator after some time - this._indexSelectTimeoutId = null; // {timeout} scroll the list some time after a letter index is selected by multicontroller - this._tiltHoldTimeoutId = null; // {timeout} - timeout after which next autoscroll tier starts - this._tiltHoldIntervalId = null; // {interval} - repeated autoscroll action for the current autoscroll tier - this._needDataTimeoutId = null; // {timeout} timeout after which the list will no longer wait for items - this._radioSettleTimeoutId = null; // {timeout} settle timeout for radio group items - this is reset on every user input and checked on every API call - this._tickSettleTimeoutId = null; // {timeout} settle timeout for tick group items - this is reset on every user input and checked on every API call - // Note: checkboxes, onOff and toggle items have their own timeouts for every item - - // event filtering - this._lastEventTime = 0; // {integer} timestamp of the last handled move event - - // list event API - this._eventListeners = {}; // {object} has of the registered listeners - - /* - * --------------------------------------- - * SETTERS AND GETTERS - * These control various public and private properties - * --------------------------------------- - */ - // focussedItem - the currently (or most recently) focussed item - this.__defineGetter__('focussedItem', function() { - return this._getFocussedIndex(); - }); - - // focussedItem - set focus on a list item - this.__defineSetter__('focussedItem', function(focussedItem) { - this._manageFocus(focussedItem); - }); - - // topItem - current list position expressed in item index - this.__defineGetter__('topItem', function() { - return this._topItem; - }); - - // topItem - perform scroll to a new list position - this.__defineSetter__('topItem', function(topItem) { - this._scrollTo(topItem, 0); - }); - - /* ====== scrollTo is a topItem alias ====== */ - // scrollTo - current list position expressed in item index - this.__defineGetter__('scrollTo', function() { - return this.topItem; - }); - // scrollTo - perform scroll to a new list position - this.__defineSetter__('scrollTo', function(scrollTo) { - this.topItem = scrollTo; - }); - /* ====== scrollTo is a topItem alias ====== */ - - // inLoading - current loading state of the list - this.__defineGetter__('inLoading', function() { - return this._inLoading; - }); - - - - // initialize - this.init(); -} - - -/** - * ========================= - * LIST EVENTS AND PROTOTYPE PROPERTIES - * ========================= - */ -List2Ctrl.prototype._USER_EVENT_START = 'mousedown'; -List2Ctrl.prototype._USER_EVENT_END = 'mouseup'; -List2Ctrl.prototype._USER_EVENT_MOVE = 'mousemove'; -List2Ctrl.prototype._USER_EVENT_OUT = 'mouseleave'; -List2Ctrl.prototype._VENDOR = ('opera' in window) ? 'O' : 'webkit'; - -List2Ctrl.prototype._EVENT_START = 'start'; -List2Ctrl.prototype._EVENT_MOVE = 'move'; -List2Ctrl.prototype._EVENT_END = 'end'; -List2Ctrl.prototype._EVENT_OUT = 'out'; - -List2Ctrl.prototype._EVENTS = { - ITEM_SELECT : 'itemSelect', - LETTER_SELECT : 'letterSelect', - DATALIST_CHANGE : 'dataListChange', - SCROLL_START : 'scrollStart', - SCROLL_END : 'scrollEnd', - CLEAN_UP : 'cleanUp', -}; - -/** - * ========================= - * INIT ROUTINE - * Any initialization code goes here - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype.init = function() -{ - /* CREATE ELEMENTS */ - - // container - this.divElt = document.createElement('div'); - this.divElt.id = this.id; - this.divElt.className = 'List2Ctrl'; - - // add it to the DOM - this.parentDiv.appendChild(this.divElt); - - // additional container classes - if (this.properties.titleConfiguration) - { - this.divElt.classList.add(this.properties.titleConfiguration); - } - this.divElt.classList.add((this.properties.inDialog) ? 'inDialog' : 'noDialog'); - if (this.properties.inDialog && this.properties.dialogStyle) - { - this.divElt.classList.add(this.properties.dialogStyle); - } - if (this.properties.numberedList) - { - this.divElt.classList.add('numberedList'); - } - if (this.properties.hasLetterIndex) - { - this.divElt.classList.add('letterIndex'); - } - this.divElt.classList.add((this.properties.thickItems) ? 'thickItems' : 'normalItems'); - if (this.properties.smallItemText) - { - this.divElt.classList.add('smallItemText'); - } - - - /* TITLE AREA */ - switch (this.properties.titleConfiguration) - { - case 'listTitle' : - // normal title - this.title = document.createElement('h1'); - this.title.className = 'List2CtrlTitle'; - this.divElt.appendChild(this.title); - this.setTitle(this.properties.title); - if (this.properties.title && this.properties.title.titleStyle == 'style06') - { - // special title style having tabs control - this.tabsCtrl = this._createTabsControl(); - } - break; - - case 'tabsTitle' : - log.debug('List has tabs'); - this.tabsCtrl = this._createTabsControl(); - break; - - case 'noTitle' : - // nothing to do - break; - - default : - log.error('List2: Wrong title configuration: ' + this.properties.titleConfiguration); - break; - } - - // mask - this.mask = document.createElement('div'); - this.mask.className = 'List2CtrlMask'; - this.divElt.appendChild(this.mask); - - // list items container - this.scroller = document.createElement('ul'); - this.scroller.className = 'List2CtrlScroller'; - this.mask.appendChild(this.scroller); - - // arc - // MPP 8/9/2013 Commented out in favor of right chrome global control w/ transitions - //this.arc = document.createElement('div'); - //this.arc.className = 'List2CtrlArc'; - //this.divElt.appendChild(this.arc); - - // active area - this.activeArea = document.createElement('div'); - this.activeArea.className = 'List2CtrlActiveArea'; - this.divElt.appendChild(this.activeArea); - - // letter index - if (this.properties.hasLetterIndex) - { - this.letterIndexWrapper = document.createElement('div'); - this.letterIndexWrapper.className = 'List2CtrlLetterIndexWrapper'; - this.divElt.appendChild(this.letterIndexWrapper); - - this.letterIndex = document.createElement('ol'); - this.letterIndex.className = 'List2CtrlLetterIndex'; - this.letterIndexWrapper.appendChild(this.letterIndex); - } - - // loading - this.loading = document.createElement('div'); - this.loading.className = 'List2CtrlLoading'; - var loadingImage1 = document.createElement('span'); - loadingImage1.className = "loadingImage1"; - loadingImage1.style.backgroundImage = 'url(' + this.properties.loadingConfig.loadingImage1 + ')'; - this.loading.appendChild(loadingImage1); - var loadingText = document.createElement('span'); - loadingText.className = 'loadingText'; - if (null !== this.properties.loadingConfig.loadingTextId && undefined !== this.properties.loadingConfig.loadingTextId && "" !== this.properties.loadingConfig.loadingTextId) - { - this.properties.loadingConfig.loadingText = this._getLocalizedString(this.properties.loadingConfig.loadingTextId, this.properties.loadingConfig.loadingSubMap); - } - loadingText.appendChild(document.createTextNode(this.properties.loadingConfig.loadingText)); - this.loading.appendChild(loadingText); - var loadingImage = document.createElement('span'); - loadingImage.className = 'loadingImage'; - this.loading.appendChild(loadingImage); - - - - /* ATTACH HANDLERS */ - - // Primary event handlers - // keep reference to the handler - this.touchHandler = this._touch.bind(this); - // start - this.divElt.addEventListener(this._USER_EVENT_START, this.touchHandler, false); - - /* CREATE POOL */ - this._createPool(); - - /* SET DATALIST */ - if (this.properties.dataList) - { - // bind dataList - this.setDataList(this.properties.dataList); - - if (true === this.properties.dataList.itemCountKnown) - { - // show items - this.updateItems(0, this.properties.dataList.itemCount-1); - - /* - * Perform initial scroll if it is set in the config properties. - * Focussed item has precedence over the scroll position, i.e. when - * the focussed item contradicts the scroll position, it is considered - * as a primary clue for scrolling the list to that position that the - * focussed item becomes visible on the screen. This logic is followed - * throughout all auto-scroll / auto-focus logic implemented in the list. - */ - - // first check if the focussed item and the scroll position are all on the same screen - // scroll to that position and show the focus according to the config - if ( (this.properties.focussedItem > 0 || this.properties.scrollTo > 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 2)) ) - { - log.debug('Lis2: Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // set initial focus to a particular item if the list is populated - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem > 0) - { - log.debug('Lis2: Focus is not visible and has priority'); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // scroll (no animation) to a particular item if the list is populated - // the focus will be placed on the top item - else if (this.properties.scrollTo > 0) - { - log.debug('Lis2: Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this._topItem); - this._initialScrollMode = 'init'; - } - - // enter list reorder if the list is reordable - if (true === this.properties.listReorder) - { - this._enterListReorder(true); - } - - } - } - else - { - this._setLoading(true); - } - - - /* SET LETTER INDEX DATA */ - if (this.properties.hasLetterIndex && this.properties.letterIndexData) - { - // bind letter index data - this.setLetterIndexData(this.properties.letterIndexData); - } - - /* SET CUSTOM LIST BACKGROUND */ - if (null != this.properties.listBackground && '' != this.properties.listBackground) - { - this.setListBackground(this.properties.listBackground); - } - -}; - - -/** - * ========================= - * LIST ITEMS - * 1. pool (_createPool) - * 2. default items configuration (_prepareItems, _prepareListItem) for every item style - * 3. items localization (_localizeItems, _getLocalizedString) - * 4. pool operations (_setText, _setImage, _getListItem, _returnListItem, _putToScroller, _emptyScroller) - * 5. dynamic list items (_updateRange, _updateDisplay, _requestMore, _fill) - * 6. set internal properties (_checkScrollable, _setTopListItem, _setLoading) - * 7. default title configuration (_prepareTitle) - * ========================= - */ - -/** 1. POOL **/ - -/** - * Create list items pool - * Add HTML elements to each item in the pool - * depending on its style - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._createPool = function() -{ - this.pool = { - empty : new Array(), // 'empty' is internal style - draggable : new Array(), // 'draggable' is internal style - ghost : new Array(), // 'ghost' is internal style - - style01 : new Array(), - style02 : new Array(), - style03 : new Array(), - style03a : new Array(), - style04 : new Array(), - style05 : new Array(), - style06 : new Array(), - style07 : new Array(), - style09 : new Array(), - style10 : new Array(), - style11 : new Array(), - style12 : new Array(), - style13 : new Array(), // deprecated - style14 : new Array(), - style17 : new Array(), - style18 : new Array(), - style19 : new Array(), - style20 : new Array(), - style21 : new Array(), - style22 : new Array(), - // TODO: style23 - same as style12 - // TODO: style24 - same as style12 - style25 : new Array(), - styleOnOff : new Array(), // not official name - styleStep : new Array(), // TODO: rename this to style26 - styleLock : new Array(), // not official name - style28 : new Array(), - style29 : new Array(), - - }; - - // the pool size (this.properties.poolsize) should be at least 3 times - // the visible items (one for above and two for below the top item) - var line1, line2, - image1, image2, - label1, label2, - button1, button2, button3, - caret; - - for (var i in this.pool) - { - for (var j=0; j no content - break; - - case 'draggable' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - button1 = document.createElement('span'); - button1.className = 'button buttonOk'; - li.appendChild(button1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'ghost' : - // ghost item -> no contet - break; - - case 'style01' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style02' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style04' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style05' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style06' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style07' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style09' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style10' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - break; - - case 'style11' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - button3 = document.createElement('span'); - button3.className = 'button button3'; - buttonsWrapper.appendChild(button3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style12' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style13' : - // style13 is deprecated - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style14' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style17' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - // label is inside line1 element to allow natural text flow - label1 = document.createElement('span'); - label1.className = 'label1'; - line1.appendChild(label1); - - break; - - case 'style18' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - break; - - case 'style19' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style20' : - button1 = document.createElement('span'); - button1.className = 'button1'; - li.appendChild(button1); - - break; - - case 'style21' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style22' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style25' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'styleOnOff' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'styleStep' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - var plusSign = document.createElement('span'); - plusSign.className = 'plus'; - li.appendChild(plusSign); - - var minusSign = document.createElement('span'); - minusSign.className = 'minus'; - li.appendChild(minusSign); - - break; - - case 'styleLock' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2 buttonLock'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3 buttonDelete'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style28' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style29' : - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - break; - - default : - log.error('List2: unknown list item style in pool: ' + i); - break; - - } - - // add common elements - caret = document.createElement('span'); - caret.className = 'caret'; - li.appendChild(caret); - - - this.pool[i].push(li); - } - } - -}; - -/** 2. DEFAULT ITEMS CONFIGURATION **/ - -/** - * Prepare items - * Extend the whole dataList so that every item - * meet the required structure. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._prepareItems = function(firstItem, lastItem) -{ - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) || (lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - for (var i=firstItem, l=lastItem; i<=l; i++) - { - this.dataList.items[i] = this._prepareListItem(this.dataList.items[i]); - } - -}; - -/** - * Prepare list item - * A list item can be defined with minimal set of properties - * that are needed for its proper display. In fact these - * properties extend the default list item structure defined below. - * This function sets default configuration for a valid list item and merge - * it with the custom configuration passed to the item. - * TAG: internal - * ========================= - * @param {object} - the list item that will be set a default set of properties and will be returned - * @return {object} - the complete list item - */ -List2Ctrl.prototype._prepareListItem = function(item) -{ - // The itemStyle property is required - if (!item.hasOwnProperty('itemStyle')) - { - log.error('List2: list item should have itemStyle property: ' + item); - return; - } - - /* - * All types of list items extend this - * default structure by overriding the - * values and adding specific ones. The - * extended structure is then returned to be - * fed in the dataList container. - */ - var completeItem = { - appData : null, // Any kind of data that will be passed in the callbacks - text1Id : null, // String ID of the label - text1SubMap : null, // String Sub Map of the label - text1 : '', // Textual content of the label - hasCaret : true, // Show the caret icon on the right of the item - disabled : false, // Whether the list item is disabled - styleMod : '', // Style modifier, 'hint', 'bold', or ''/omitted - disabledStyleMod: "normal", // Disabled style modifier, 'normal' or 'white' - background : 'normal', // Background modifier, 'normal' or 'grey' - itemStyle : '', // String indicating the list type - itemBehavior : 'shortPressOnly', // String "hold" behavior for the item ('shortPressOnly', 'shortAndHold', or 'shortAndLong') - vuiSelectable: true, // Boolean for some items that cannot be selected by vui even when they are enabled - _data : { // Object containing any item-specific data used ONLY by the control - eventTimeout : null, - lastEvent : null, - settleTimeout : null, - lastUpdated : null, - settleValue : null, - } - }; - - // extend the default structure with default specific properties - var specificItem = {}; - switch (item.itemStyle) - { - case 'empty' : - specificItem = { hasCaret : false }; - break; - case 'draggable' : - specificItem = { image1:'', button1Id:null, button1SubMap:null, button1:'' }; - break; - case 'ghost' : - specificItem = {}; - break; - case 'style01' : - specificItem = { image1:'', indented:false }; - break; - case 'style02' : - specificItem = { image1:'', image2:'' }; - break; - case 'style03' : - specificItem = { image1:'', image2:'', image3:'', checked:false, indented:false }; - break; - case 'style03a' : - specificItem = { image1: '', label1Id: null, label1SubMap: null, label1: '', checked: false, labelWidth: 'wide2', label1Align:'right', styleMod: "hint"}; - break; - case 'style04' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style05' : - specificItem = { image1:'', image2:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style06' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', labelWidth:'normal', label1Align:'right', label1Warning:false }; - break; - case 'style07' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style09' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style10' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', value:1, indeterminate:false, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style11' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', button3Id:null, button3SubMap:null, button3:'', value:1, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style12' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime }; - break; - case 'style13' : - // deprecated - issue a warning - log.warn(this.uiaId + ': List2 style13 has been deprecated. Please use style12 instead. Setting pivot=True. Check SDD for details.'); - specificItem = { min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:true }; - break; - case 'style14' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', text1Align:'left' }; - break; - case 'style17' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'' }; - break; - case 'style18' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'' }; - break; - case 'style19' : - specificItem = { image1:'' }; - break; - case 'style20' : - // nothing specific for this style - break; - case 'style21' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style22' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', indented:false }; - case 'style25' : - specificItem = { image1:'', image2:'', image3:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'styleOnOff' : - specificItem = { image1:'', value:2, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'styleStep' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2:'', min:0, max:36, increment:1, value:0, warning:false }; - break; - case 'styleLock' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', locked:false }; - break; - case 'style28' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime, indented : false }; - break; - case 'style29' : - specificItem = { label1Id:null, label1SubMap:null, label1:'',label2Id:null, label2SubMap:null, label2:'', image1:'' }; - default : - log.error('List2: unknown item style: ' + item.itemStyle); - break; - } - - // Extend default structure with the specific one - for (var i in specificItem) - { - completeItem[i] = specificItem[i]; - } - - // Extend default structure with the supplied item - for (var j in item) - { - completeItem[j] = item[j]; - } - - return completeItem; -}; - - -List2Ctrl.prototype._updateModifiedTimestamps = function(firstItem, lastItem) -{ - // update lastModified timestamp - var now = new Date().getTime(); - for (var i=firstItem; i<=lastItem; i++) - { - if (this._hasData(i)) - { - this.dataList.items[i]._data.lastUpdated = now; - } - } -}; - - -/** 3. ITEMS LOCALIZATION **/ - -/** - * Localize items - * Localize text in known list items using localization framework. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._localizeItems = function(firstItem, lastItem) -{ - log.debug('Localizing...'); - - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) ||(lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - // iterate through the dataList - for (var i=firstItem, l=lastItem; i<=l; i++) - { - switch (this.dataList.items[i].itemStyle) - { - // no elements - case 'empty' : - // do nothing - break; - - // text1, button1 - case 'draggable' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - break; - - // no elements - case 'ghost' : - // do nothing - break; - - // text1 - case 'style01' : - case 'style02' : - case 'style03' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - case 'style03a' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style04' : - case 'style05' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1, label1 - case 'style06' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style07' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, text2, label1, label2 - case 'style09' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, button1, button2 - case 'style10' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - break; - - // text1, button1, button2, button3 - case 'style11' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - if (this.dataList.items[i].button3Id) - { - var button3 = this._getLocalizedString(this.dataList.items[i].button3Id, this.dataList.items[i].button3SubMap); - this.dataList.items[i].button3 = button3; - } - break; - - // text1, labelLeft, labelRight - case 'style12' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, labelLeft, labelCenter, labelRight - case 'style13' : - // style13 is deprecated - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1 - case 'style14' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style17' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style18' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1 - case 'style19' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1 - case 'style20' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, text2, label1 - case 'style21' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style22' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style25' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1 - case 'styleOnOff' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1, label2 - case 'styleStep' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label2 = label2; - } - else - { - log.warn(this.uiaId + ' possible issue. Lis2: item ' + i + ' does not specify label2Id'); - } - break; - - // text1, text2 - case 'styleLock' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - case 'style29' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - } - - } -}; - -/** - * Get localization entry for a string id - * TAG: internal - * ========================= - * @return {string} - */ -List2Ctrl.prototype._getLocalizedString = function(labelId, subMap) -{ - return framework.localize.getLocStr(this.uiaId, labelId, subMap); -}; - -/** 4. POOL OPERATIONS **/ - -/** - * Set line 1 content - * This helper function clears any previous content for the supplied - * element class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - textual content to be inserted - * @param {boolean} - do not remove child html tags when inserting textual content - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setText = function(li, className, content, preserveHTML) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - if (!content) - { - content = ''; - } - li.querySelector(className).innerText = ''; - li.querySelector(className).appendChild(document.createTextNode(content)); - return li; -}; - -/** - * Set image background - * This helper function clears any previous path for the supplied - * image class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - path to the image - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setImage = function(li, className, url) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - li.querySelector(className).style.backgroundImage = ''; - if ('' != url) - { - li.querySelector(className).style.backgroundImage = 'url(' + url + ')'; - } - return li; -}; - -/** - * Set slider - * This helper function clears any previous slider in the list item - * and cleans up local references. It then creates a new slider control - * inside the list item and sets its values - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setSlider = function(li, className, sliderProperties, itemIndex) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - - // get current item poolid - var poolId = li.getAttribute('data-poolid'); - - // get previous itemIndex for this particular li - var prevItemIndex = li.getAttribute('data-ref'); - - // destruct any previous sliders for this poolid and previous index - if (prevItemIndex != 'undefined') - { - var hashKey = 'slider_'+prevItemIndex+'_'+poolId; - - // remove slider from the hash and the DOM - if (this._sliders.hasOwnProperty(hashKey)) - { - this._sliders[hashKey]['slider'].cleanUp(); - this._sliders[hashKey]['slider'].divElt.parentElement.removeChild(this._sliders[hashKey]['slider'].divElt); - } - } - - // add slider to the hash and the DOM - var sliderCont = li.querySelector(className); - if (sliderProperties && sliderCont) - { - var hashKey = 'slider_'+itemIndex+'_'+poolId; - - // instantiate slider and add it to the _sliders hash - this._sliders[hashKey] = {}; - this._sliders[hashKey]['itemIndex'] = itemIndex; - this._sliders[hashKey]['poolId'] = poolId; - this._sliders[hashKey]['slider'] = framework.instantiateControl(this.uiaId, sliderCont, 'SliderCtrl', sliderProperties); - } - return li; -}; - -/** - * Set toggle - * This helper function clears any previous toggled buttons in - * the supplied list item and sets initial toggle value - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setToggle = function(li, className, value) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - var buttons = li.querySelectorAll(className); - for (var i=0; i element wit proper elements inside - */ -List2Ctrl.prototype._getListItem = function(listItem, dataListIndex) -{ - - // get it from the pool - var li = this.pool[listItem.itemStyle].shift(); - - // remove any residual touch classes - li.classList.remove('hit'); - li.classList.remove('focus'); - li.classList.remove('longpress'); - li.classList.remove('secondaryFocus'); - - // add content to it following style definitions - switch (listItem.itemStyle) - { - case 'empty' : - // empty item -> no content - break; - - case 'draggable' : - // listItem : { text1:String, image1:String, button1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.buttonOk', listItem.button1); - break; - - case 'ghost' : - // list item : {} - break; - - case 'style01' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style02' : - // listItem : { text1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.image2 === 'indeterminate') - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - this._setImage(li, '.image2', listItem.image2); - } - break; - - case 'style03' : - // listItem : { text1:String, image1:String, image2:String, checked:Boolean } - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style03a' : - // listItem : { text1:String, image1:String, label1: String} - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - this._setText(li, '.label1', listItem.label1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style04' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style05' : - // listItem : { text1:String, text2:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - break; - - case 'style06' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style07' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style09' : - // listItem : { text1:String, text2:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style10' : - // listItem : { text1:String, button1:String, button2:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 2), 0) ); - if (listItem.indeterminate) - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - } - break; - - case 'style11' : - // listItem : { text1:String, button1:String, button2:String, button3:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setText(li, '.button3', listItem.button3); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 3), 0) ); - break; - - case 'style12' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style13' : - // TODO: style13 has been depricated - // listItem : { text1:String, labelLeft:String, labelCenter:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: this.properties.minChangeInterval, - settleTime: this.properties.settleTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style14' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - if ('right' == listItem.text1Align) - { - li.classList.add('text1AlignRight'); - } - else - { - li.classList.remove('text1AlignRight'); - } - - break; - - case 'style17' : - // listItem : { text1:String, label1:String, image1:String } - li.querySelector('.line1').innerText = ''; - var label1 = document.createElement('span'); - label1.className = 'label1'; - label1.appendChild(document.createTextNode(listItem.label1)); - li.querySelector('.line1').appendChild(label1); - li.querySelector('.line1').appendChild(document.createTextNode(listItem.text1)); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style18' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style19' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style20' : - // listItem : { text1:String } - this._setText(li, '.button1', listItem.text1); - break; - - case 'style21' : - // listItem : { text1:String, text2:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style22' : - // listItem : { text1:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style25' : - // listItem : { text1:String, text2:String, image1:String, image2:String, image3:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - break; - - case 'styleOnOff' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.value === 1) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - break; - - case 'styleStep' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - li.classList.remove('maxReached'); - li.classList.remove('minReached'); - if (listItem.value === listItem.max) - { - li.classList.add('maxReached'); - } - else if (listItem.value === listItem.min) - { - li.classList.add('minReached'); - } - - // configure label warning - if (listItem.warning) - li.classList.add('warning'); - else - li.classList.remove('warning'); - - break; - - case 'styleLock' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - if (listItem.locked) - { - li.classList.add('locked'); - } - else - { - li.classList.remove('locked'); - } - break; - - case 'style28' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setImage(li, '.image1', listItem.image1); - - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - - - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style29': - - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - break; - } - - /* ITEM MODIFICATORS */ - // add/remove hasCaret class - if (listItem.hasCaret) - { - li.classList.add('hasCaret'); - } - else - { - li.classList.remove('hasCaret'); - } - - // add/remove disabled class - if (listItem.disabled) - { - li.classList.add('disabled'); - } - else - { - li.classList.remove('disabled'); - } - - // add/remove styleMod class (hint/bold/'') - if ('hint' == listItem.styleMod) - { - li.classList.remove('bold'); - li.classList.add('hint'); - } - else if ('bold' == listItem.styleMod) - { - li.classList.remove('hint'); - li.classList.add('bold'); - } - else if ('both' == listItem.styleMod) - { - li.classList.add('hint'); - li.classList.add('bold'); - } - else - { - li.classList.remove('hint'); - li.classList.remove('bold'); - } - - // add/remove background modifier class (normal/grey) - if ('grey' == listItem.background) - { - li.classList.remove('bgLightGrey'); - li.classList.add('bgGrey'); - } - else if('lightGrey' == listItem.background) - { - li.classList.remove('bgGrey'); - li.classList.add('bgLightGrey'); - } - else - { - li.classList.remove('bgLightGrey'); - li.classList.remove('bgGrey'); - } - - // add disabled style mod - if ('white' === listItem.disabledStyleMod) - { - li.classList.add("disabledWhite"); - } - - // return it - return li; - -}; - -/** - * Return list item to the pool - * This will result in increasing the pool contents - * with one item. The returned item will be removed from the DOM. - * However, its content will not be reset as this is done in the - * process of any subsequent pool extraction (see _getListItem() above) - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @return {void} - */ -List2Ctrl.prototype._returnListItem = function(li) -{ - // get the style - var itemStyle = li.getAttribute('data-itemStyle'); - // reset it - li.style.top = '0px'; - // remove it - li.parentNode.removeChild(li); - - // put it back to the pool - this.pool[itemStyle].push(li); -}; - -/** - * Put a list item to the scroller - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._putToScroller = function(li, index, operation) -{ - li.style.top = index * this.properties.itemHeight + 'px'; - li.setAttribute('data-ref', index); - - - if (operation == 'prepend') - { - this.items.unshift({ref:index, domElt:li}); - this.scroller.insertBefore(li, this.scroller.firstChild); - - this._wrapInlineElement(li); - } - else if (operation == 'append') - { - this.items.push({ref:index, domElt:li}); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else if (!isNaN(operation)) - { - this.items.splice(operation, 0, {ref:index, domElt:li}); - - // insertBefore breaks in Opera - use appendChild instead - // this.scroller.insertBefore(li, this.items[operation+1]); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else - { - log.error('Lis2: unknown _putToScroller() operation: ' + li + ' ' + index + ' ' + operation); - } - -}; - -/** - * Return everything into the pool and empty the scroller - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._emptyScroller = function() -{ - for (var i=0, l=this.items.length; i itemsOnScreen) - { - // return everything into the pool - var itemsLength = this.items.length; - for (var i=0; i < itemsLength; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - var dataListIndex = 0; - - if (topItem < this.dataList.items.length - Math.round(itemsOnScreen / 2) && - topItem > Math.round((itemsOnScreen / 2)) ) - { - - - // WE ARE IN THE MIDDLE - - for (var i=0; i < itemsLength; i++) - { - dataListIndex = (topItem - itemsBefore) + i; - - // we've reached the end of the dataList. No more items to add -> break - if (dataListIndex >= this.dataList.items.length) - { - break; - } - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'middle'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else - { - - if (numOfScrolledElements > 0) - { - - // PRESSED END BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = (this.dataList.items.length - itemsLength) + i; - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'down'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else if (numOfScrolledElements < 0) - { - - // PRESSED HOME BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = i; - - - // request it if it is empty - if (this.dataList.items[dataListIndex].itemStyle === 'empty' || (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex]))) - { - this._requestMore(dataListIndex, 'down'); - log.debug('Requesting items ' + dataListIndex); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - - } - - } - - } - - - } - else - { - - - - if (numOfScrolledElements > 0) - { - - /* SCROLL DOWN BOF */ - - // return to pool - var firstItemRef = this.items[0].ref; - var bottomDifference = topItem - firstItemRef; - var extraEls = bottomDifference - itemsBefore; - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Down - extraEls ' + extraEls); - - if (extraEls > 0) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - } - - // lastItemRef = this.items[this.items.length-1].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var topDifference = this.items[this.items.length-1].ref - ( topItem - 1 ); - var newEls = ( itemsAfter + 1 ) - topDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Down - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i break - log.debug('end of list'); - break; - } - - } - - } - - /* SCROLL DOWN EOF */ - - } - else if (numOfScrolledElements < 0) - { - - /* SCROLL UP BOF */ - - // return to pool - var topDifference = this.items[this.items.length-1].ref - topItem + 1; - var extraEls = topDifference - ( itemsAfter + 1 ); - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Up - extraEls ' + extraEls); - - if ( extraEls > 0 ) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.pop(); - this._returnListItem(item.domElt); - } - - } - - - // firstItemRef = this.items[0].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var bottomDifference = topItem - this.items[0].ref; - var newEls = itemsBefore - bottomDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Up - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i= 0) - { - - // if empty item is encountered, request more data - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'up'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'prepend'); - - } - else - { - // we've reached the beginning of the dataList array => break - log.debug('beginning of list'); - break; - } - - } // for - - } - else - { - log.debug('no new elements'); - } - - /* SCROLL UP EOF */ - - } - else - { - // there's no scroll => do nothing - } - - - - } // closes if (this.m.abs(numOfScrolledElements) > itemsOnScreen) - -}; - - -/** - * Redraw updated items that are currently visible - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._updateDisplay = function(firstItem, lastItem) -{ - - var firstItemRef = this.items[0].ref; - var lastItemRef = this.items[this.items.length-1].ref; - - // update only when the updated items overlap with the visible items - if ( (firstItem >= firstItemRef && firstItem <= lastItemRef) || - (firstItem <= firstItemRef && lastItem >= firstItemRef) ) - { - - var firstToUpdate = this.m.max(firstItem, firstItemRef); - var lastToUpdate = this.m.min(lastItem, lastItemRef); - var firstToUpdateIndex = firstToUpdate - firstItemRef; - var lastToUpdateIndex = (lastToUpdate - firstToUpdate) + firstToUpdateIndex; - - for (var i=firstToUpdateIndex; i<=lastToUpdateIndex; i++ ) - { - - var returnItem = this.items.splice(i,1); - var dataListIndex = returnItem[0].ref; - - // return to pool - this._returnListItem(returnItem[0].domElt); - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // recover secondary focus - if (this._inSecondaryMulticontroller && this._currentSecondaryMulticontrollerItem === dataListIndex) - { - li.classList.add('focus'); - li.classList.add('secondaryFocus'); - } - - // put it to scroller - this._putToScroller(li, dataListIndex, i); - - } - - } - - // update _isScrollable flag - this._checkScrollable(); - -}; - -/** - * Request more list items - * TAG: internal - * ========================= - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._requestMore = function(index, direction) -{ - - // do not request more if a previous request is pending - if (!this._inLoading) - { - // indicate loading is in progress - this._setLoading(true); - - if (direction == 'up') - { - // we add 1 to the requestSize to include the last element in the way up - index = this.m.max(index - this.properties.requestSize + 1, 0); - - } - else if (direction == 'middle') - { - // we request 25 items on each direction from the topItem - index = this.m.max(index, 0); - - } - - // build additional data - var additionalParams = { - topItem : this._topItem, - visibleItems : this.properties.visibleItems, - ranges : this.getEmptyRange(), - }; - - log.debug('Request items from ' + index + ' to ' + index+this.properties.requestSize + ' ' + direction); - - // call needDataCallback if it is defined. The first empty item is - if (typeof this.properties.needDataCallback == 'function') - { - this.properties.needDataCallback(index, additionalParams); - } - - // set timeout for data population - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = setTimeout(this._needDataTimeoutCallback.bind(this, index), this.properties.needDataTimeout); - } - -}; - -List2Ctrl.prototype._needDataTimeoutCallback = function(index) -{ - log.warn('Lis2: control has requested items from index ' + index + ' but has not receieved them yet. Enabling the list.'); - this._setLoading(false); -}; - -/** - * Initial pool operation - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._fill = function(firstItem, lastItem) -{ - - log.debug('Start pool operation'); - log.debug('POOL | ITEMS'); - - // get items from the pool - for (var i=firstItem; i<=lastItem; i++) - { - // get it from the pool - var li = this._getListItem(this.dataList.items[i], i); - - // put it to scroller - this._putToScroller(li, i, 'append'); - - log.debug(this.pool[this.dataList.items[i].itemStyle].length + ' -> ' + this.items.length); - } - - this._hasFill = true; - - // update _isScrollable flag - var scrollable = this._checkScrollable(); - - // show/hide scroll indicator - if (!scrollable || (scrollable && this.properties.hasLetterIndex)) - { - this._hideScrollIndicator(); - } - else - { - this._showScrollIndicator(); - } - - log.debug('End pool operation'); - -}; - -/** SET INTERNAL PROPERTIES **/ - -/** - * Update _isScrollable flag - * TAG: internal - * ========================= - * @return {boolean} - returns _isScrollable - */ -List2Ctrl.prototype._checkScrollable = function() -{ - if (this.dataList.items.length > this.properties.visibleItems) - { - this._isScrollable = true; - } - else - { - this._isScrollable = false; - } - - return this._isScrollable; -}; - -/** - * Update _topItem property - * TAG: internal - * ========================= - * @param {integer} - top item index - * @return {integer} - returns _topItem - */ -List2Ctrl.prototype._setTopListItem = function(pos) -{ - // pos should be number for proper topItem calculation - if (!isNaN(pos)) - { - this._prevTopItem = this._topItem; - this._topItem = -(Math.round(pos / this.properties.itemHeight)); - - // throw out of bounds exception - if (this._topItem < 0 || this._topItem > this.dataList.items.length - 1) - { - log.error('Lis2: _topItem is out of bounds'); - } - } - - if (this.properties.enableItemRequestOnScroll) - { - // check for empty items in DOM - var emptyDOMItem = this._getEmptyDOMElement(); - if (null != emptyDOMItem) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - } - } - - return this._topItem; - -}; - -/** - * Indicate loading activity in the list - * and update _inLoading property - * TAG: internal - * ========================= - * @param {boolean} - show or hide loading activity - * @return {boolean} - returns _inLoading - */ -List2Ctrl.prototype._setLoading = function(show) -{ - if (show) - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - // update start time - this._loadingData.timeStarted = new Date().getTime(); - - if (this.properties.showLoadingOverlayTimeout > 0) - { - // delayed show overlay - this._loadingData.startTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, true), this.properties.showLoadingOverlayTimeout); - } - else - { - // show overlay immediately - this._setLoadingOverlay(true); - } - } - - // update flag - this._inLoading = true; - } - else - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - if (this.properties.hideLoadingOverlayTimeout > 0) - { - // delayed hide overlay - var now = new Date().getTime(); - if (now - this._loadingData.timeStarted < this.properties.showLoadingOverlayTimeout) - { - // no overlay has been shown -> reset everything - this._setLoadingOverlay(false); - } - else if (now - this._loadingData.timeShown < this.properties.hideLoadingOverlayTimeout) - { - // the overlay has been visible less than the hideLoadingOverlayTimeout -> hide it in hideLoadingOverlayTimeout ms after it has been made visible - this._loadingData.endTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, false), this.properties.hideLoadingOverlayTimeout - (now - this._loadingData.timeShown)); - } - else - { - // the overlay has been visible long enough -> hide it immediately - this._setLoadingOverlay(false); - } - } - else - { - // hide overlay immediately - this._setLoadingOverlay(false); - } - } - - // update flag - this._inLoading = false; - } - - return this._inLoading; -}; - -List2Ctrl.prototype._setLoadingOverlay = function(show) -{ - if (show) - { - // show loading - this.mask.appendChild(this.loading); - - this._loadingData.timeShown = new Date().getTime(); - } - else - { - // hide loading - if (null != this.loading.parentElement) - { - this.loading.parentElement.removeChild(this.loading); - } - - // reset loading data - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - this._loadingData.timeStarted = 0; - this._loadingData.timeShown = 0; - this._loadingData.startTimeoutId = null; - this._loadingData.endTimeoutId = null; - } -}; - -/** 7. DEFAULT TITLE CONFIGURATION **/ - -/** - * Prepare title - * A list title can be defined with minimal set of properties - * that are needed for its proper display. This function sets - * default configuration for a valid title and merge it with the - * custom configuration passed to the title. - * TAG: internal - * ========================= - * @param {object} - the title object that will be set a default set of properties and will be returned - * @return {object} - the complete title object - */ -List2Ctrl.prototype._prepareTitle = function(titleObj) -{ - // The itemStyle property is required - if (!titleObj.hasOwnProperty('titleStyle')) - { - log.error('Lis2: title should have titleStyle property: ' + titleObj); - return; - } - - // default properties - var title = {}; - switch (titleObj.titleStyle) - { - case 'style02' : - title = { text1:'', text1Id:null, text1SubMap:null, styleMod:'' }; - break; - case 'style02a' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - case 'style03' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'' }; - break; - case 'style05' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null, image1:'' }; - break; - case 'style06' : - title = { image1:'' }; - break; - case 'style07' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null }; - break; - case 'style08' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - default : - log.error('Lis2: unknown title style: ' + titleObj.titleStyle); - break; - } - - // Extend default structure with the supplied item - for (var i in titleObj) - { - title[i] = titleObj[i]; - } - - // Perform localization - switch (title.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style08' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - break; - case 'style05' : - case 'style07' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - if (title.text2Id) - { - title.text2 = this._getLocalizedString(title.text2Id, title.text2SubMap); - } - break; - } - - return title; -}; - - -/** - * ========================= - * SCROLL INDICATOR - * - reset - * - create - * - visual update - * ========================= - */ - -/** - * Remove any scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorReset = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // remove any scroll indicator - if (this.scrollIndicatorWrapper) - { - // remove wrapper (and scroll indicator) - this.scrollIndicatorWrapper.parentElement.removeChild(this.scrollIndicatorWrapper); - - // nullify elements - this.scrollIndicatorWrapper = null; - this.scrollIndicator = null; - - // reset scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = 0; - } -}; - -/** - * Create scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorBuild = function(visible) -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator size - var indicatorSize = Math.round(this.mask.offsetHeight * (this.mask.offsetHeight / this.scroller.offsetHeight)); - - // add scroll indicator wrapper - this.scrollIndicatorWrapper = document.createElement('div'); - this.scrollIndicatorWrapper.className = 'List2CtrlScrollIndicatorWrapper'; - this.divElt.appendChild(this.scrollIndicatorWrapper); - - // add scroll indicator - this.scrollIndicator = document.createElement('div'); - this.scrollIndicator.className = 'List2CtrlScrollIndicator'; - if(!visible) - { - this.scrollIndicatorWrapper.style.visibility = 'hidden'; - } - else - { - this.scrollIndicatorWrapper.style.visibility = 'visible'; - } - this.scrollIndicator.style.height = this.m.max(indicatorSize, this.properties.scrollIndicatorMinSize) + 'px'; - this.scrollIndicator.style.top = '0px'; - this.scrollIndicatorWrapper.appendChild(this.scrollIndicator); - - // set scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = this.mask.offsetHeight - this.scrollIndicator.offsetHeight; - - if (this.properties.hasLetterIndex) - { - // hide scroll indicator when letterIndex is enabled - this._hideScrollIndicator(); - } - else - { - // fade out scroll indicator - this._fadeOutScrollIndicator(); - } -}; - -/** - * Update scroll indicator position on drag - * This is fired on _USER_EVENT_MOVE when the - * list is being dragged by touch. - * TAG: touch-only, internal - * ========================= - * @return {integer} scroll indicator position - */ -List2Ctrl.prototype._dragUpdateScrollIndicator = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator position - var indicatorPos = Math.round(this._indicatorMax * (this.scroller.offsetTop / this._maxScrollY)); - - // constrain position - indicatorPos = this.m.max(indicatorPos, this._indicatorMin); - - // set new position - this.scrollIndicator.style.top = indicatorPos + 'px'; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return indicatorPos; -}; - -/** - * Update scroll indicator position on drag - * Called on scroll animation (flick or scroll ad-hoc) - * TAG: internal - * ========================= - * @param {integer} the new position of the scroller - * @param {integer} the time for animation to the new position - * @return {integer} the new scroll indicator position - */ -List2Ctrl.prototype._updateScrollIndicator = function(pos, time) -{ - // check for time - if (time == undefined || time == null) - { - // get default time - time = this.properties.swipeAnimationDuration; - } - - // determine scroll indicator new position - var newRelativePos = pos / this._maxScrollY; - var newPos = Math.round(newRelativePos * (this._indicatorMax - this._indicatorMin)); - - // start animation - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollIndicatorAnimationEndCallback = this._scrollIndicatorAnimationEnd.bind(this); - this.scrollIndicator.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicator.style.top = newPos + 'px'; - - // clear any previously scheduled scroll indicator fade out - clearTimeout(this._scrollIndicatorTimeoutId); - this._scrollIndicatorTimeoutId = null; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return newPos; - -}; - - -List2Ctrl.prototype._fadeInScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeInDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -List2Ctrl.prototype._fadeOutScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - // clear any previously-scheduled hiding - clearTimeout(this._scrollIndicatorTimeoutId); - - // schedule hide - this._scrollIndicatorTimeoutId = setTimeout(function() { - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeOutDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 0; - this._scrollIndicatorTimeoutId = null; - }.bind(this), this.properties.scrollIndicatorFadeTimeout); -}; - -List2Ctrl.prototype._hideScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 0; -}; - -List2Ctrl.prototype._showScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -/** - * ========================= - * TOUCH EVENT HANDLERS - * - Event detection and custom event dispatching - * - Start/Move/End/Out event handling - * - Hit state control - * ========================= - */ - -/** - * Handle any touch event and dispatch appropriate - * custom event. Actual event processing is done in the - * respective handlers of the custom events. The original - * event object is attached to the custom event in its - * event property. - * ========================= - * @param {event} - any touch event - * @return {Boolean} - True if event was processed - */ -List2Ctrl.prototype._touch = function(e) -{ - var touchResult = false; - - switch(e.type) - { - case this._USER_EVENT_START : - // route to letter index first, otherwise route to list - touchResult = this._startIndex(e) || this._start(e); - /* - * Attach temporary listeners to document if we have a positive start. - * These listeners will be removed on _USER_EVENT_END - */ - if (touchResult) - { - document.addEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - } - break; - - case this._USER_EVENT_MOVE : - // route to letter index first, otherwise route to list - touchResult = this._moveIndex(e) || this._move(e); - break; - - case this._USER_EVENT_END : - /* - * Remove the document event listeners no matter of these have been - * attached or not. This will prevent any non-existent callbacks firing. - */ - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - // route to letter index first, otherwise route to list - touchResult = this._endIndex(e) || this._end(e); - break; - - case this._USER_EVENT_OUT : - this._out(e); - break; - } - - return touchResult; -}; - -/** - * Start Touch on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._start = function(e) -{ - // abort any ongoing scroll - this._abortScroll(e); - - // get mask position and dimensions - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - this._maskH = this.mask.offsetHeight; - this._maskW = this.mask.offsetWidth; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - // reset letter index multicontroller - this._focusStolen = false; - if (relativeY >= 0) - { - this._setLetterIndexMulticontroller(false, true); - - // steal focus - var canGainFocus = this._canGainFocus(e); - if (!this._hasFocus && -1 !== canGainFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - this._focusStolen = true; - } - } - - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by start reorder rather than regular start - this._startReorder(e); - return true; - } - - this._startItem = this._getTargetItem(e); - this._startDOMItem = this._getDOMItem(this._startItem); - - // make hit - if (this.properties.hitTimeout > 0) - { - // after some time - this._makeHitTimeoutId = setTimeout(this._itemMakeHit.bind(this, e), this.properties.hitTimeout); - } - else - { - // immediately - this._itemMakeHit(e); - } - - // Place focus on the reported available item when focus is stolen - if (this._focusStolen) - { - this._showFocus(canGainFocus, true); - } - - // make toggles hit - this._buttonMakeHit(e); - - // make locks hit - this._lockMakeHit(e); - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return false; - } - - // check relative mouse position - if (relativeY < 0) - { - return false; - } - - // check for a valid target item - if (this._startItem == -1) - { - return false; - } - - // get current y - this._y = this.scroller.offsetTop; - this._startY = relativeY; - this._startX = relativeX; - this._startTime = new Date().getTime(); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, e), this.properties.longPressTimeout); - - // raise _inDrag - this._inDrag = true; - - // Release secondary MC mode - if (this._inSecondaryMulticontroller && null != this._currentSecondaryMulticontrollerItem && this._startItem != this._currentSecondaryMulticontrollerItem) - { - var temp = this._currentSecondaryMulticontrollerItem; - - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - - // Commit the value - if (!this._isLock(temp)) // locks do not commit the value - { - this._triggerFocus(temp); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(temp, 'clear'); - } - } - - // dispatch scroll start event - this._listEvent(this._EVENTS.SCROLL_START, {scrollPosition:this._topItem}); - - // user touched the list -> return True - return true; - -}; - -/** - * Touch move on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._move = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by move reorder rather than regular move - this._moveReorder(e); - return true; - } - - if (!this._inDrag) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._end(e); - return true; - } - - // calculate travelled distance - var deltaY = relativeY - this._startY; - var deltaX = relativeX - this._startX; - - if (this._inLongPress) - { - return false; - } - - /* - * DRAG DETECTION - * determine whether this is a horizontal or vertical drag - * and raise the horizontal flag - */ - if (null == this._inHorizontalDrag) { - - var alpha = Math.atan2(this.m.abs(deltaX), this.m.abs(deltaY)); - if (alpha < this.properties.hvThreshold) - { - // vertical - this._inHorizontalDrag = false; - } - else - { - // horizontal - this._inHorizontalDrag = true; - this._hDragItem = this._getTargetItem(e); - - // set slideStart - this._slideStart(e); - } - } - - // drag slider - if (this._inHorizontalDrag == true) - { - // we have a horizontal drag -> move sliders - this._slideMove(e); - } - // drag list if scrollable - else if (false == this._inHorizontalDrag && this._isScrollable) - { - // we have a vertical drag and the list can be scrolled - // calculate the scroller's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollY, this.m.min(this._y + deltaY, this._minScrollY)); - - // drag the scroller if in bounds - this.scroller.style.top = newPos + 'px'; - - // update scroll indicator - this._dragUpdateScrollIndicator(); - - // raise _stopClick flag and remove hit and long press - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit and prevent delayed hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); - - // remove long press and prevent long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); - } - } - // control hit state when not scrollable or when no scrolling occurs (e.g. when we are one of the list extremities) - if (!this._isScrollable || this.m.abs(deltaY) > this.properties.selectThreshold) - { - var targetTop = this._startDOMItem.offsetTop; - if (relativeY < targetTop || relativeY > targetTop + this.properties.itemHeight) - { - // remove hit - this._itemRemoveHit(e); - - // prevent select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = true; - } - } - else - { - // make hit - if (this._stopSelect && !this._isScrollable) - { - this._itemMakeHit(e); - } - - // enable select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = false; - } - } - } - - // user touched the list -> return True - return true; -}; - -/** - * Touch end on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._end = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by end reorder rather than regular end - this._endReorder(e); - return true; - } - - - // remove hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); // clear hit timeout - // remove long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - this._startItem = null; - this._startDOMItem = null; - - // reset drag flag and hDrag item - this._inHorizontalDrag = null; - this._hDragItem = null; - - if (!this._inDrag) - { - // this is called without having a drag - return false; - } - - // end any drag of sliders - this._slideEnd(e); - - // set scroll nature - this._scrollNature = 'touch'; - - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTime; - if (this._focusStolen && !this._stopSelect) - { - // slight drag -> scroll to show focus on the available item when stealing focus - // decide whether to allow offscrean - var focussedIndex = this._getFocussedIndex(); - var allowOffScreen = (focussedIndex > this._topItem && focussedIndex < this._topItem + this.properties.visibleItems); - this._showFocus(focussedIndex, allowOffScreen); - this._focusStolen = false; - } - else if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startY; - - // swipte detected - this._startSwipe(deltaY, velocity); - } - else - { - // regular drag -> snap to item bounds - this._snap(this.scroller.offsetTop); - } - - // call touch select logic - this._touchSelectItem(e); - - // reset any previously set flags - this._inDrag = false; - this._stopSelect = false; - this._startTime = 0; - - // user touched the list -> return True - return true; -}; - -/** - * Touch leave on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._out = function(e) -{ - return this._end(e); -}; - - -/** - * Start Touch on letter index - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {boolean} - True if letter index is touched - */ -List2Ctrl.prototype._startIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // get mask position - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - if (relativeY < 0) - { - return false; - } - - // hit test letter index - if (relativeX <= this.letterIndexWrapper.offsetLeft) - { - return false; - } - - // steal focus - if (!this._hasFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - } - - // Enter into letter index multicontroller mode if not already - if (!this._inLetterIndexMulticontroller) - { - this._setLetterIndexMulticontroller(true); - } - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - - // make hit - this._indexMakeHit(e); - - // get start coordinates and time - this._yIndex = this.letterIndex.offsetTop; - this._startIndexY = relativeY; - this._startIndexX = relativeX; - this._startTimeIndex = new Date().getTime(); - - this._inDragIndex = true; - - return true; - -}; - - -List2Ctrl.prototype._moveIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - if (!this._inDragIndex) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._endIndex(e); - - return false; - } - - // calculate travelled distance - var deltaY = relativeY - this._startIndexY; - var deltaX = relativeX - this._startIndexX; - - // calculate the letter index's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollYIndex, this.m.min(this._yIndex + deltaY, this._minScrollYIndex)); - - // drag the letter index if in bounds - this.letterIndex.style.top = newPos + 'px'; - - // raise _stopClick flag - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit - this._indexRemoveHit(e); - } - - return true; - -}; - - -List2Ctrl.prototype._endIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // remove hit - this._indexRemoveHit(e); - - if (!this._inDragIndex) - { - return false; - } - - if (!this._stopSelect) - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // select letter index - var letterIndex = this._getTargetLetterIndex(e); - this._letterIndexSelect(letterIndex, 'Touch'); - } - else - { - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTimeIndex; - if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startIndexY; - - // swipte detected - this._startSwipeIndex(deltaY, velocity); - } - else - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // schedule letter index select if letter is enabled - var letterIndex = this._getTargetLetterIndex(e); - if (!this.letterIndexData[letterIndex].disabled) - { - this._scheduleLetterIndexSelect(letterIndex); - } - } - } - - // reset flags - this._inDragIndex = false; - this._stopSelect = false; - - return true; -}; - - - -/** - * Select item - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {void} - */ -List2Ctrl.prototype._touchSelectItem = function(e) -{ - // clear any hit timeout - clearTimeout(this._makeHitTimeoutId); - - // if we are not allowed to select (when in drag) - if (this._stopSelect) - { - this._stopSelect = false; - return; - } - - // select during loading is not allowed - if (this._inLoading) - { - return; - } - - var itemIndex; - var fireSelect = true; - var additionalModifier = null; - var params = {}; - - // determine target item - itemIndex = this._getTargetItem(e); - - // only valid list items can fire the select callback - if (itemIndex == -1) - { - return; - } - - // ensure that we end up on the same item where we started so that the select is valid - if (itemIndex != this._getFocussedIndex()) - { - return; - } - - // perform any additional touch processing for some items before issuing select callback - if (this._isToggle(itemIndex)) - { - // the target contains toggle buttons -> select toggle buttons - var toggleSelected = this._buttonSelect(e); - if ('cancel' == toggleSelected) - { - fireSelect = false; - } - else if (null != toggleSelected) - { - params = { additionalData:toggleSelected }; - additionalModifier = 'preventSimpleSelect'; - } - - } - - if (this._isSlider(itemIndex)) - { - // the target contains a slider -> disable select only if the slider is adjustable - if (this.dataList.items[itemIndex].allowAdjust) - { - fireSelect = false; - } - } - - if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && this._inSecondaryMulticontroller) - { - // if we are in secondary multicontroller and the item is a step item - var stepResult = this._stepAdjust(e); - if ('commit' === stepResult) - { - params = { finalAdjust:true, value:this.dataList.items[itemIndex].value }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - else if (null != stepResult) - { - params = { finalAdjust:false, value:stepResult }; - } - else - { - fireSelect = false; - } - } - else if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && !this._inSecondaryMulticontroller) - { - // if we are not in secondary multicontroller and the item is step item - this._setSecondaryMulticontroller(true, itemIndex); - fireSelect = false; - - // produce beep - this._beep('Short', 'Touch'); - } - - if (this._isLock(itemIndex) && this._hasSecondaryMulticontroller(itemIndex)) - { - // the target is a lock item - var lockAction = this._lockSelect(e); - if (null == lockAction) - { - fireSelect = false; - } - else - { - // prepare params - params = { additionalData:lockAction }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - } - - // prevent select on disabled items - if (this.dataList.items[itemIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Touch'); - - this._itemSelect(itemIndex, params, additionalModifier); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior) - { - this._itemHoldStop(itemIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - -}; - -/** - * Exit hit state of the currently hit item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._itemRemoveHit = function() -{ - var hitItems = this.scroller.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i= this.dataList.itemCount || this.dataList.items[itemIndex].disabled) - { - return; - } - - var returnValue = null; - - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'styleOnOff' : - // get and update current value - var currentValue = this.dataList.items[itemIndex].value; - var newValue = (1 === currentValue) ? 2 : 1; - this.dataList.items[itemIndex].value = newValue; - - // get and update DOM item - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (1 === newValue) - { - domItem.classList.add('checked'); - } - else - { - domItem.classList.remove('checked'); - } - } - returnValue = newValue; - break; - - case 'style10' : - case 'style11' : - // Note: settle timeout is registered in this._buttonActivate - this._buttonSelectRight(itemIndex); - returnValue = this.dataList.items[itemIndex].value; - break; - - case 'style03' : - case 'style03a' : - var currentValue = this.dataList.items[itemIndex].checked; - switch (this.dataList.items[itemIndex].image1) - { - case 'tick' : - if (!currentValue) - this._setTick(itemIndex, !currentValue); - break; - case 'radio' : - if (!currentValue) - this._setRadio(itemIndex, !currentValue); - break; - case 'checkbox' : - this._setCheckBox(itemIndex, !currentValue); - break; - } - returnValue = this.dataList.items[itemIndex].checked; - break; - - default : - log.warn('Lis2: No simple select behavior for item style ' + this.dataList.items[itemIndex].itemStyle); - break; - } - - return returnValue; - -}; - -/** - * Fire select callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid selectCallback - */ -List2Ctrl.prototype._itemSelect = function(itemIndex, paramsModifier, additionalModifier) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - // get paramsModifier - var paramsModifier = paramsModifier || {}; - - // get additionalModifier - var additionalModifier = additionalModifier || null; - - var appData = null; - var additionalData = null; - var params = {}; - - // event filtering - var filterEvent = false; - - if (this._isSlider(itemIndex)) - { - // the item contains a slider - additionalData = this.dataList.items[itemIndex].value; - } - - if (this._isSimpleSelectItem(itemIndex)) - { - // the item is simple select item - if ('preventSimpleSelect' != additionalModifier) - { - // process simple select behavior before firing the select callback - additionalData = this._simpleSelect(itemIndex); - } - - // apply event filter - var filterType = (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) ? 'toggle' : (this._isCheckBox(itemIndex)) ? 'check' : null; - filterEvent = this._applyEventFilter(itemIndex, filterType); - } - else if (this._isStep(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - this._setSecondaryMulticontroller(false, itemIndex); - } - else if (this._isLock(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - // restore focus and remove any secondary multicontroler - this._showFocus(this._lastItemWithFocus); - this._lockShowFocus(itemIndex, 'clear'); - this._setSecondaryMulticontroller(false, itemIndex); - } - else if (this._isStep(itemIndex)) - { - // apply event filter - var filterType = "step"; - filterEvent = this._applyEventFilter(itemIndex, filterType); - } - - // is this filtered event? - if (filterEvent) - { - return false; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - // merge params with params modifier - for (var i in paramsModifier) - { - params[i] = paramsModifier[i]; - } - - // return value - var result = false; - - // do not fire select on disabled items but instead fire select disabled - if (this.dataList.items[itemIndex].disabled) - { - // fire select disabled callback - if (typeof this.properties.selectDisabledCallback == 'function') - { - /* - * Handles touches on disabled list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectDisabledCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - } - else - { - // fire select callback - if (typeof this.properties.selectCallback == 'function') - { - /* - * Handles select on list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - - // dispatch select event - this._listEvent(this._EVENTS.ITEM_SELECT, params); - } - - if (this._hasData(itemIndex)) - { - // record this event and clear any timeouts - this.dataList.items[itemIndex]._data.lastEvent = new Date().getTime(); - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = null; - } - - return result; -}; - -/** - * Fire long press callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {event|integer} - raw touch/mouse event or directly the index of the item - * @return {boolean} - true if there's a valid longPressCallback - */ -List2Ctrl.prototype._itemLongPress = function(e) -{ - var eventCause = null; - var itemIndex = -1; - - // the parameter is an event - if (typeof e == 'object') - { - // determine target item - itemIndex = this._getTargetItem(e);var itemIndex = this._getTargetItem(e); - eventCause = 'Touch'; - } - // the parameter is an index - else if (!isNaN(e)) - { - itemIndex = e; - eventCause = 'Multicontroller'; - } - - // if the item is short-press-only -> prevent any longpress activity - if ('shortPressOnly' === this.dataList.items[itemIndex].itemBehavior) - { - return; - } - // if the item has itemBehavior other than shortAndLong and shortAndHold -> this is invalid property and prevent any longpress activity - else if ('shortAndLong' != this.dataList.items[itemIndex].itemBehavior && 'shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - log.warn('Lis2: Invalid itemBehavior property. Item behavior can be shortPressOnly / shortAndLong / shortAndHold'); - return; - } - - // make it long-pressed - this._itemMakeLongPress(e); - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // produce beep - this._beep('Long', eventCause); - - // fire long press callback - if ('shortAndLong' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.longPressCallback == 'function') - { - /* - * Handles long press on list items - * @param ctrlObj Object Reference to the list control that was long-pressed - * @param btnData Object Data that was attached to the long-pressed item - * @param params Object Object containing extra data - */ - this.properties.longPressCallback(this, appData, params); - - result = true; - } - // fire hold start callback - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.holdStartCallback == 'function') - { - /* - * Handles hold start on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStartCallback(this, appData, params); - - result = true; - } - - // raise the flag for long-press/hold-start issued callback - this._longPressIssued = true; - - // enter into list reorder on long press if the list supports it - if (this.properties.listReorder) - { - this._enterListReorder(); - this._startReorder(e); - } - - return result; -}; - - -/** - * Fire hold stop on an item. - * This function is called whenever the user ends touch - * on an item that has itemBehavior = shortAndHold - * TAG: internal, touch-only - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid holdStopCallback - */ -List2Ctrl.prototype._itemHoldStop = function(itemIndex) -{ - // validate item behavior property - if ('shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - return; - } - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // fire hold stop callback - if (typeof this.properties.holdStopCallback == 'function') - { - /* - * Handles hold stop on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStopCallback(this, appData, params); - - result = true; - } - - return result; -}; - -/** - * Perform outbound event filtering - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {boolean} - whethet to filter the event or not - */ -List2Ctrl.prototype._applyEventFilter = function(itemIndex, filterType) -{ - var filter = false; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return filter; - } - - var now = new Date().getTime(); - - switch (filterType) - { - case 'toggle' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.dataList.items[itemIndex].minChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.dataList.items[itemIndex].minChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - } - break; - - case 'check' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.properties.checkMinChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.properties.checkMinChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - } - break; - - case 'step' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - - if (this.properties.stepMinChangeInterval !== 0 && difference < this.properties.stepMinChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.properties.stepMinChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - } - break; - } - - return filter; -}; - -/** - * Timeout callback that is run if a select event - * is scheduled by the outbound filtering mechanism - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {void} - */ -List2Ctrl.prototype._filterTimeoutCallback = function(itemIndex, filterType) -{ - switch (filterType) - { - case 'toggle' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].value }, 'preventSimpleSelect'); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - break; - - case 'check' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].checked }, 'preventSimpleSelect'); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - break; - case 'step' : - this._itemSelect(itemIndex, { value : this.dataList.items[itemIndex].value }, 'preventSimpleSelect'); - break; - } -}; - -/** - * Register a settle timeout on any new user input. - * Any previous settle timeout should get cleared - * before setting a new one. The timeout state should - * be checked when public API call is made and depending - * on whether the timeout is running or not, the value - * will be cached or applied to the item. - * The settle time acts as an inbound event filtering mechanism. - * TAG: internal - * ========================= - * @param {integer} - itemIndex - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._registerSettleTimeout = function(itemIndex, itemType) -{ - log.debug('Settle scheduled'); - this._clearSettleTimeout(itemIndex, itemType); - - // schedule settle item - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._radioSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._tickSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.dataList.items[itemIndex].settleTime); - } - break; - } -}; - -/** - * Clear any settle timeouts on any user input. - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._clearSettleTimeout = function(itemIndex, itemType) -{ - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._radioSettleTimeoutId); - this._radioSettleTimeoutId = null; - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._tickSettleTimeoutId); - this._tickSettleTimeoutId = null; - } - break; - - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - } -}; - -/** - * Performs a check whether a settlie timeout - * is running for a particular item, radio group - * or tick group. - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {Boolean} - True if a settle timeout is running - */ -List2Ctrl.prototype._hasSettleTimeout = function(itemIndex, itemType) -{ - var timeoutRunning = false; - - switch (itemType) - { - case 'radio' : - if (null !== this._radioSettleTimeoutId && this._radioSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'tick' : - if (null !== this._tickSettleTimeoutId && this._tickSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'checkbox' : - case 'toggle' : - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return timeoutRunning; - } - - if (null !== this.dataList.items[itemIndex]._data.settleTimeout && this.dataList.items[itemIndex]._data.settleTimeout >= 0) - { - timeoutRunning = true; - } - break; - } - - return timeoutRunning; -}; - -/** - * Settle an item after the settle time expires. - * The cached value (if any) gets assigned as a - * real value to the item and the item is updated. - * This is the settleTimeout callback. - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item is successfully settled - */ -List2Ctrl.prototype._settleItem = function(itemIndex) -{ - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return false; - } - - // exit if the item index is out of range - if (isNaN(itemIndex) || itemIndex < 0 || itemIndex >= this.dataList.items.length) - { - return false; - } - - var item = this.dataList.items[itemIndex]; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return false; - } - - // get settle value and set it as real value, and update item - var settleValue = item._data.settleValue; - - - - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - if (null != item._data.settleValue) - { - // set real value - item.value = settleValue; - this.updateItems(itemIndex, itemIndex); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - } - else if (this._isCheckBox(itemIndex)) - { - // Note: setting the real value is done in the helpers - switch (item.image1) - { - case 'checkbox' : - if (null != item._data.settleValue) - { - // set real value - this._setCheckBox(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - break; - - case 'radio' : - if (null != item._data.settleValue) - { - // set real value - this._setRadio(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._radioSettleTimeoutId = null; - break; - - case 'tick' : - if (null != item._data.settleValue) - { - // set real value - this._setTick(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._tickSettleTimeoutId = null; - break; - } - } - else - { - // item does not support settlement - return false; - } - - log.debug('Settle item: ' + itemIndex + ', value: ' + settleValue); - - // return success - return true; - -}; - - -/** - * ========================= - * MULTICONTROLLER AND VUI - * ========================= - */ - -/** - * Main multicontroller handler - * TAG: multicontroller-only, public - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype.handleControllerEvent = function(eventID) -{ - log.debug("handleController() called, eventID: " + eventID); - - /* - * eventID - * - acceptFocusInit (sent on instantiation) - * - acceptFocusFromLeft - * - acceptFocusFromRight - * - acceptFocusFromTop - * - acceptFocusFromBottom - * - lostFocus - * - touchActive - * ... - */ - - var response; - - // ignore certain MC events when the list is in motion by touch - if (this._inDrag || (this._inScroll && 'touch' === this._scrollNature)) - { - switch (eventID) - { - case "acceptFocusInit" : - case "acceptFocusFromLeft" : - case "acceptFocusFromRight" : - case "acceptFocusFromTop" : - case "acceptFocusFromBottom" : - case "lostFocus" : - case "touchActive" : - case "controllerActive" : - // pass these events - break; - default : - // ignore everything else - return "ignored"; - break; - } - } - - if (!this._inSecondaryMulticontroller) - { - // we are in primary multicontroller mode - switch (eventID) - { - case "acceptFocusInit": - // consume event by default - response = "consumed"; - - // Input mode change to multicontroller - this._inputMode = 'controller'; - /* - * this event is received every time a template is displayed - * if we already have preset a focus item, do not set it again - */ - // Show focus animation - this._showFocusAnimation = true; - if ('restore' != this._initialScrollMode) - { - this._hasFocus = true; - var itemToGainFocus = this._canGainFocus('controllerActive'); - if (-1 !== itemToGainFocus) - { - this._showFocus(itemToGainFocus); - } - else - { - if (this.hasDataList()) - { - // we have data list and there are no enabled items -> give focus to the left - response = 'giveFocusLeft'; - } - else - { - // we probably dont't have a data list -> wait untul we get it - this._showFocus(this.properties.focussedItem); - } - } - } - else - { - this._showFocus(this.properties.focussedItem); - } - break; - - case "acceptFocusFromLeft": - // Show focus animation - this._showFocusAnimation = true; - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromRight": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromTop": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromBottom": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "lostFocus": - this._hideFocus(); - this._hideFocusLetterIndex(); - this._hasFocus = false; - response = "consumed"; - break; - - case "touchActive": - // Input mode change to touch - this._inputMode = 'touch'; - this._hideFocus(); - response = "consumed"; - break; - - case "controllerActive": - response = "consumed"; - break; - - case "cw": - // Rotate Right (CW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCW(); - break; - - case "ccw": - // Rotate Left (CCW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCCW(); - break; - - case "downStart": - // Tilt Down Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCDown(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCDown(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCDown.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll down for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollDownPage(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollDownPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll down for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "down" : - // Tilt Down Stop - - if ('downStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any downs without downStarts - response = "ignored"; - } - - break; - - case "upStart": - // Tilt Up Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCUp(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCUp(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCUp.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll up for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollUpPage(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollUpPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll up for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "up": - // Tilt Up Stop - - if ('upStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any ups without upStarts - response = "ignored"; - } - - break; - - case "leftStart": - // Tilt Left Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && this._inLetterIndexMulticontroller) - { - // Exit letter index multicontroller mode - this._setLetterIndexMulticontroller(false); - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusLeft..."); - response = "giveFocusLeft"; - } - break; - - case "left": - // Tilt Left Stop - - if ('leftStart' === this._lastControllerEvent) - { - response = "ignored"; - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any lefts without leftStarts - response = "ignored"; - } - break; - - case "rightStart": - // Tilt Right Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && !this._inLetterIndexMulticontroller) - { - // Enter into letter index multicontroller mode - this._setLetterIndexMulticontroller(true); - response = "consumed"; - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusRight..."); - response = "giveFocusRight"; - } - break; - - - case "right": - // Tilt Right Stop - - if ('rightStart' === this._lastControllerEvent) - { - response = "ignored"; - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any rights without rightStarts - response = "ignored"; - } - break; - - - case "selectStart": - // SelectStart (press down) - - if (this._inLetterIndexMulticontroller) - { - // get the focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - - // make focussed letter index hit - this._indexMakeHit(focussedLetterIndex); - } - else - { - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // make focussed index hit - this._itemMakeHit(focussedIndex); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, focussedIndex), this.properties.longPressTimeout); - } - - // always consume selectStart - response = "consumed"; - - break; - - case "select": - // Select (press down) - - if ('selectStart' === this._lastControllerEvent) - { - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // remove long press - this._itemRemoveLongPress(); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // fire letter index select - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._letterIndexSelect(currentFocussedLetterIndex, 'Multicontroller'); - } - else - { - if (this.properties.listReorder) - { - // if we are reordering lists (hence pressing down does not produce select event) - if (!this._inListReorder) - { - - // get focussed index - var focussedIndex = this._getFocussedIndex(); - - // check if focussed index is indeed eligable for list reorder - if ('shortAndLong' === this.dataList.items[focussedIndex].itemBehavior) - { - // we are about to begin list reorder - this._enterListReorder(); - } - - } - else - { - // we finish list reorder - this._releaseListReorder(); - } - - } - else - { - // if we are in normal mode - not reordering list - - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // does the element have secondary multicontroller behavior? - if (this._hasSecondaryMulticontroller(focussedIndex) && this._isSlider(focussedIndex)) - { - if (this.dataList.items[focussedIndex].allowAdjust) - { - // this item has secondary select and is adjustable slider -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this item has secondary select but is not adjustable -> trigger focus - this._triggerFocus(); - } - } - else if (this._hasSecondaryMulticontroller(focussedIndex)) - { - // this item has secondary select -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this is a regular item -> trigger focus - this._triggerFocus(); - } - - } - } - - // consume Select only after selectStart is consumed - response = "consumed"; - } - else - { - // ignore any selects without selectStarts - response = "ignored"; - } - - break; - - default: - // No action - response = "ignored"; - break; - } - - } - else - { - // we are in secondary multicontroller mode - response = this._handleControllerEventSecondary(eventID); - } - - // keep track of the last consumed event - if ('consumed' === response) - { - this._lastControllerEvent = eventID; - } - - /* - * returns - * - giveFocusLeft (control retains highlight unless it later gets lostFocus event) - * - giveFocusRight - * - giveFocusUp - * - giveFocusDown - * - consumed (always returned on select event, and if control adjusted highlight) - * - ignored (returned only if control doesn't know about focus) - */ - - log.debug("Event: " + eventID + " -> " + "Response: " + response); - - return response; - -}; - -/** - * Handle multicontroller clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - } - else - { - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller counter clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller down tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCDown = function() -{ - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - else - { - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - - -/** - * Handle multicontroller up tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCUp = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - // if we are in list reorder mode - push the draggable item up and set focus on it - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - var rfi = this._getRelativeFocussedIndex(); - } - else - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - - -/** - * handle controller event and apply it on items that are in secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype._handleControllerEventSecondary = function(eventID) -{ - // get the index - var focussedIndex = this._getFocussedIndex(); - - // handle event - switch (eventID) - { - case "up" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus up - this._showFocus('up'); - - // get relative focussed index after moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // we need to go back to the beginning in order to scroll up - if (rfi < 1) - { - this._scrollUpOne(); - } - break; - - - case "down" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus down - this._showFocus('down'); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleItems - 2; - // get relative focussed index after moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // we need to go to the end in order to scroll down - if (rfi >= bottomFocusThreshold) - { - this._scrollDownOne(); - } - break; - - case "leftStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('leftStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepDown(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "left" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('left'); - } - break; - - case "ccw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepDown(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "rightStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('rightStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepUp(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "right" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('right'); - } - - break; - - case "cw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepUp(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "select": - // leave secondary multicontroller mode and trigger focus - this._setSecondaryMulticontroller(false); - this._showFocus(this._lastItemWithFocus); - this._triggerFocus(); - break; - } - - // the secondary multicontroller events are always consumed - return "consumed"; -}; - -/** - * Set secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @param {integer} - focussed index - * @return {void} - */ -List2Ctrl.prototype._setSecondaryMulticontroller = function(state, focussedIndex) -{ - // get focussed index - if (isNaN(focussedIndex)) - { - var focussedIndex = this._getFocussedIndex(); - } - - // do not set secondary multicontroller to true if the item is disabled - if (state && this.dataList.items[focussedIndex].disabled) - { - return; - } - - if (state) - { - // flag as we are in secondary multicontroller mode - this._inSecondaryMulticontroller = true; - - // add secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.add('secondaryFocus'); - } - - /** - * Fire select callback to notify apps that we are - * entering into secondary multicontroller mode. - * In most cases apps will ignore this event. - * Transition focus to subcontrols. - */ - if (this._isSlider(focussedIndex)) - { - // the target is a slider and can be adjusted -> set currently active slider - this._activeSlider = { - itemIndex : focussedIndex, // currently active slider index - slider : this._getSlider(focussedIndex) // currently active slider instance - }; - - // transition focus - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - - // fire select callback for app notification - this._itemSelect(focussedIndex); - } - - /** - * Place focus highlight on the lock inline button - * if the target is a lock item - */ - if (this._isLock(focussedIndex)) - { - this._lockShowFocus(focussedIndex, 1); - } - - this._currentSecondaryMulticontrollerItem = focussedIndex; - } - else - { - this._inSecondaryMulticontroller = false; - - // remove secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.remove('secondaryFocus'); - } - - /** - * Transition focus from subcontrols. - */ - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // transition focus - this._activeSlider.slider.handleControllerEvent('lostFocus'); - } - - this._currentSecondaryMulticontrollerItem = null; - } - -}; - -/** - * Set letter index multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {boolean} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexMulticontroller = function(state, isTouch) -{ - if (state) - { - // hide focus from the main list and show it in the letter index - this._hideFocus(); - this._showFocusLetterIndex(this._getCurrentLetterIndex()); - this._inLetterIndexMulticontroller = true; - } - else - { - // hide focus from the letter index and show it in the main list - if (!isTouch) - { - this._showFocus(this._lastItemWithFocus); - } - this._inLetterIndexMulticontroller = false; - this._hideFocusLetterIndex(); - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - } - -}; - -/** - * Manage focus highlight - * This is the single point for managing focus when requested from outside List2. - * (focusedItem setter, restoreContext) Manages reorder and focus as required. - * TAG: internal - * ========================= - * @param {number} - item index - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._manageFocus = function(item) -{ - if (this._inListReorder && !isNaN(item)) - { - this._reorderToIndex(item); - } - return this._showFocus(item); -} - -/** - * Show focus highlight - * This is the single point for showing the - * focus highlight - * TAG: internal - * ========================= - * @param {strig | number} - direction (up|down) or item index - * @param {boolean} - simulation mode: use to perform check on where the focus will end - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._showFocus = function(item, allowOffscreen, simulationMode, abortMode) -{ - log.debug("List2: _showFocus item, allowOffscreen, simulationMode, abortMode ", item, allowOffscreen, simulationMode, abortMode); - if (!this._hasFocus) - { - return; - } - - if (this._inputMode != 'controller') - { - // do not show the focus if the input mode is other than 'controller' - return; - } - - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return; - } - - // do not show focus when in list reorder by touch - if (this._reorderTouchElt) - { - return; - } - - var abortMode = (true === abortMode); - - // do not change focussed index when we are in loading and no scrolling is allowed during that time - if (!this.properties.scrollingDuringLoading && this._inLoading && !abortMode) - { - return; - } - - var simulationMode = (true === simulationMode); - - // get the last focussed index (real and relative) - var lastFocussedIndex = this._getFocussedIndex(); - var lastRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // if we don't have previous focus, select the topmost - if (lastFocussedIndex == null) - { - lastFocussedIndex = this._topItem; - } - - // hide the focus only in real mode - if (!simulationMode) - { - this._hideFocus(); - } - - - var nextFocussedIndex = -1; - var useTransition = true; - var useRelativeIndeces = true; - - // find the next focussed element index - // NOTE: 'down' and 'up' are ued primarily when focussing with multicontroller - switch (item) - { - case 'down' : - // 'down' uses relative positioning - // the next one but not exceeding the visible items - - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.min(lastFocussedIndex+1, this.dataList.itemCount-1); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex >= this.dataList.itemCount-1) { - // we have reached the end of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the next one - nextRealFocussedIndex++; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.min(lastRelativeFocussedIndex+1, this.properties.visibleItems-1); - } - break; - - case 'up' : - // 'up' uses relative positioning - // the previous one but not lower than the first one - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.max(lastFocussedIndex-1, 0); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex <= 0) { - // we have reached the beginning of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the previous one - nextRealFocussedIndex--; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.max(lastRelativeFocussedIndex-1, 0); - } - break; - - default : - // move highlight instantly when jumping to an item - useTransition = false; - // absolute indeces use real positioning - useRelativeIndeces = false; - - if (!isNaN(item)) - { - // specific one -> make sure it is within the list bounds - nextFocussedIndex = this.m.max(this.m.min(item, this.dataList.itemCount-1), 0); - } - else - { - // the top one - nextFocussedIndex = this._topItem; - } - } - - // if we are in simulation -> return the would-be focussed index - if (simulationMode) - { - return nextFocussedIndex; - } - - // From here on, perform actual focus change - // ----------------------------------------- - var pos = 0; - if (useRelativeIndeces) - { - // convert relative nextFocussedIndex to position - pos = nextFocussedIndex * this.properties.itemHeight; - // convert nextFocussedIndex back to real one - nextFocussedIndex = this._relativeToRealIndex(nextFocussedIndex); - } - else - { - // are we allowed to focus off screen? - if (!allowOffscreen) - { - // check if focus is outside the screen and scroll the list so that it is inside - if (this._realToRelativeIndex(nextFocussedIndex) < 0) - { - // scrollt up - this._scrollTo(nextFocussedIndex, 0); - } - else if (this._realToRelativeIndex(nextFocussedIndex) > this.properties.visibleItems - 2) - { - // scroll down - this._scrollTo((nextFocussedIndex + 2) - this.properties.visibleItems, 0); - } - } - - // convert absolute nextFocussedIndex to position - pos = (nextFocussedIndex - this._topItem) * this.properties.itemHeight; - } - - - - - // find the new focussed element - var focussedElement = this._getDOMItem(nextFocussedIndex); - - - // do we have a focussed element? - if (focussedElement) - { - focussedElement.classList.add('focus'); - - // create first focus animation - if (this._showFocusAnimation) - { - this._showFocusAnimation = false; - this.firstFocusAnimationEndCallback = this._firstFocusAnimationEndCallback.bind(this); - focussedElement.addEventListener("animationend", this.firstFocusAnimationEndCallback, false); - focussedElement.classList.add('firstFocus'); - } - } - - // set letter index position - this._setLetterIndexPosition(nextFocussedIndex); - - // store focussed item - this._lastItemWithFocus = nextFocussedIndex; - - return nextFocussedIndex; -}; - -/** - * First focus animation end callback that is fired - * when the first focus animation finishes. - * It removes the firstFocus class from the event's target - * and clears any subsequent animation callbacks - * TAG: internal - * ========================= - * @param {AnimationEvent} - * @return {void} - */ -List2Ctrl.prototype._firstFocusAnimationEndCallback = function(e) -{ - e.target.classList.remove('firstFocus'); - e.target.removeEventListener("animationend", this.firstFocusAnimationEndCallback, false); - this.firstFocusAnimationEndCallback = null; -}; - -/** - * Hide focus highlight - * This is the single point for hiding the - * focus highlight - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._hideFocus = function() -{ - // Preserve focussed element - this._lastItemWithFocus = this._getFocussedIndex(); - - for (var i=0; i disable select only if the slider is adjustable - if (this.dataList.items[focussedIndex].allowAdjust) - { - fireSelect = false; - } - - // reset currently active slider - this._activeSlider = null; - } - - if (this._isStep(focussedIndex)) - { - params = { - value : this.dataList.items[focussedIndex].value, - finalAdjustment : true, - }; - } - - /** - * Trigger the currently selected button - */ - if (this._isLock(focussedIndex)) - { - var focussedButton = this._lockGetFocus(focussedIndex); - var actionResult = this._lockActivate(focussedIndex, focussedButton); - this._lockShowFocus(focussedIndex, 'clear'); - params = { additionalData : actionResult }; - } - - // prevent select on disabled items - if (this.dataList.items[focussedIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Multicontroller'); - - this._itemSelect(focussedIndex, params); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[focussedIndex].itemBehavior) - { - this._itemHoldStop(focussedIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - - } -}; - -/** - * Check whether the list can gain focus. In certain cases focus cannot be - * shown (e.g. when there are no items available) or if it can gain it - * it should be restored on the nearest available item if the one that - * previously had focus is disabled. - * TAG: internal - * ========================= - * @param {MouseEvent|Number} - optional argument. If passed a check will be performed whether the target item is disabled - * @return {integer} - the item that will have focus. If no item can have focus, return -1 - */ -List2Ctrl.prototype._canGainFocus = function(e) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return -1; - } - - var itemToGainFocus = -1; - - // check if we are touching the element - if (typeof e === 'object') - { - var targetItem = this._getTargetItem(e); - - // the item is enabled and can gain focus - if (-1 !== targetItem && !this.dataList.items[targetItem].disabled) - { - itemToGainFocus = targetItem; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(targetItem); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - else if (typeof e === 'number') - { - if (-1 !== e && !this.dataList.items[e].disabled) - { - itemToGainFocus = e; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(e); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - // check whether this is called from the controllerActive event handler - else if ('controllerActive' === e && this.properties.focussedItem > 0 && this.dataList.items[this.properties.focussedItem] && !this.dataList.items[this.properties.focussedItem].disabled) - { - itemToGainFocus = this.properties.focussedItem; - } - // check if last item with focus is disabled - else if (this.dataList.items[this._lastItemWithFocus] && !this.dataList.items[this._lastItemWithFocus].disabled) - { - itemToGainFocus = this._lastItemWithFocus; - } - else - { - // show focus on the closest available item to the last with focus - var nearestItem = this._getNearestEnabledItem(this._lastItemWithFocus); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - - // if we have tabs and no enabled items, always show focus on the first line allowing tabs navigation - if (this.tabsCtrl && -1 === itemToGainFocus) - { - itemToGainFocus = this._topItem; - } - } - - return itemToGainFocus; -}; - -/** - * Get focussed index - * TAG: internal, helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getFocussedIndex = function() -{ - var focussedIndex = this._lastItemWithFocus; - - for (var i=0; i - */ -List2Ctrl.prototype._getFocussedElement = function() -{ - var focussedElement = null; - var focussedIndex = this._getFocussedIndex(); - for (var i=0; i= this.dataList.itemCount) - { - currentItem = null; - } - else - { - while (this.dataList.items[currentItem].disabled) - { - if (currentItem >= this.dataList.itemCount-1 || currentItem <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentItem = null; - break; - } - currentItem = ('down' === direction) ? currentItem+1 : currentItem-1; - } - } - return currentItem; -}; - -/** - * Get nearest enabled item in all directions - * If there are two enabled items in both directions that are - * at equal distances from the reference item, the one below is - * returned. - * TAG: internal, helper - * ========================= - * @param {integer} - from which item to search - * @return {integer} - the next enabled item. - * If nothing is found, return Null - */ -List2Ctrl.prototype._getNearestEnabledItem = function(fromItem) -{ - var nearestEnabledItem = null; - - var nearestDown = this._getNearestEnabledItemByDirection(fromItem, 'down'); - var nearestUp = this._getNearestEnabledItemByDirection(fromItem, 'up'); - - if (null === nearestDown === nearestUp) - { - // no enabled item is found - nearestEnabledItem = null; - } - else if (null === nearestDown) - { - // nothing is found below -> return the one above - nearestEnabledItem = nearestUp; - } - else if (null === nearestUp) - { - // nothing is found above -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - var differenceDown = this.m.abs(fromItem - nearestDown); - var differenceUp = this.m.abs(fromItem - nearestUp); - if (differenceDown === differenceUp) - { - // equally spaced -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - // differently spaced -> return the closer one - nearestEnabledItem = (differenceDown < differenceUp) ? nearestDown : nearestUp; - } - } - - return nearestEnabledItem; -}; - -/** - * Get secondary select status of an item - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {boolean} - whether the item has secondary multicontroller - */ -List2Ctrl.prototype._hasSecondaryMulticontroller = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var hasSecondaryMulticontroller = false; - - var type = this.dataList.items[itemIndex].itemStyle; - for (var i=0; i return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+this.properties.visibleItems-2, 'down'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi + 2 - this.properties.visibleItems; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll up by one element - * If the element that will be placed at the top - * position is disabled, the list will be scrolled to - * the nearest available enabled item - * TAG: internal - * ========================= - * @return {integer} - new position of the scroller in px - */ -List2Ctrl.prototype._scrollUpOne = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topItem === 0) - { - // we can't scroll up any more -> return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi - 1; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.min(newPos, 0); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll down by one page (screen) - * TAG: internal - * ========================= - * @return {string} - paged | atlimit | onepage - */ -List2Ctrl.prototype._scrollDownPage = function() -{ - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = 'onepage'; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the bottom - case 'bottom' : - // place focus on the last available item - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'up'); - if (null != nei && nei >= this._topItem) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the bottom - case 'bottomclose' : - // search for enabled item in the bottom screen - var nei = this._getNearestEnabledItemByDirection(this.dataList.itemCount - 1, 'up'); - if (null != nei && nei >= this.dataList.itemCount - this.properties.visibleItems) - { - // place focus on the last available item and scroll to the bottom - this._showFocus(nei); - this._scrollTo(this.dataList.itemCount - this.properties.visibleItems); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.min(this._topItem + this.properties.visibleItems + currentRelativeFocussedIndex, this.dataList.itemCount-1); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem + this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future top item down - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'down'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atLimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll up by one page (screen) - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollUpPage = function() -{ - - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = ''; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the top - case 'top' : - // place focus on the first available item - var nei = this._getNearestEnabledItemByDirection(-1, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the top - case 'topclose' : - // search for enabled item in the top screen - var nei = this._getNearestEnabledItemByDirection(0, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - // place focus on the last available item and scroll to the top - this._showFocus(nei); - this._scrollTo(0); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.max(this._topItem - this.properties.visibleItems + currentRelativeFocussedIndex, 0); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem - this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.min(newPos, 0); // constrain it to the min scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future bottom item up - var nei = this._getNearestEnabledItemByDirection(this._topItem - this.properties.visibleItems, 'up'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atlimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll to the top - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollTop = function() -{ - this._performScroll(0); // do the scroll -}; - -/** - * Scroll to the bottom - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollBottom = function() -{ - this._performScroll(this._maxScrollY); // do the scroll -}; - -/** - * Do the actual scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._performScroll = function(pos, duration) -{ - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return; - } - - // if menu can be scrolled (it has enough list items) - if (this._isScrollable) - { - // make it snappy - var newPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(pos, duration); - } -}; - -/** - * Animate the scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateScroll = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - if (null !== this.scrollerAnimationEndCallback) - { - // remove any redundant animationEnd listeners - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scrollerAnimationEndCallback = null; - } - - // animate scroller or directly call the animation end callback if the time is 0 - this.scroller.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollerAnimationEndCallback = this._scrollerAnimationEnd.bind(this); - this.scroller.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scroller.style.top = pos + 'px'; - - this._inScroll = false; - if (time > 0) - { - this._inScroll = true; - } - - // set top item and update display - this._updateScrollIndicator(pos, time); - this._setTopListItem(pos); - this._updateRange(); -}; - -/** - * Abort any ongoing scroll and reset any flags - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._abortScroll = function(e) -{ - // aborting scroll is possible only while the list is scrolling - if (false === this._inScroll) - { - return; - } - - // get target item - var targetItem = this._getTargetItem(e); - - // check if target item is enabled - if (this.dataList.items[targetItem] && !this.dataList.items[targetItem].disabled) - { - // show focus there - this._showFocus(targetItem, true, false, true); - } - else - { - // restore focus - this._restoreFocus(); - } - - // get current snapped position - var snapPos = this._getSnapPosition(this.scroller.offsetTop); - this._animateScroll(snapPos, 0); - - // reset any touch flags - this._inDrag = false; - this._inScroll = false; - this._scrollNature = null; - this._inHorizontalDrag = null; - this._hDragItem = null; - this._stopSelect = false; - this._startTime = 0; - this._startItem = null; - this._startDOMItem = null; - this._activeSlider = null; - this._startY = 0; - this._startX = 0; -}; - - -/** 2. LIST SNAPPING **/ - -/** - * Get snap position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getSnapPosition = function(pos) -{ - return this.properties.itemHeight * (Math.round(pos / this.properties.itemHeight)); -}; - -/** - * Get snap (above) position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest above item edge - */ -List2Ctrl.prototype._getSnapPositionAbove = function(pos) -{ - return this.properties.itemHeight * (Math.floor(pos / this.properties.itemHeight)); -}; - -/** - * Scroll list to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {void} - */ -List2Ctrl.prototype._snap = function(pos) -{ - // the snap position is the same as the current - if (pos == this._y) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - return; - } - else if (pos === this._minScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex > this._topItem + this.properties.visibleItems - 1) - { - this._restoreFocus(); - } - return; - } - - var snapPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(snapPos); -}; - -/** 3. LIST SWIPING AND PHYSICS **/ - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipe = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._y, this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0, 0); - - /* ANIMATE THE SCROLLER */ - var newPos = this.m.min(this.m.max(this._y + momentumY.dist, this._maxScrollY), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.scroller.offsetTop) // only if newPos is a number and the list is worth scrolling - { - this._animateScroll(newPos, swipeDuration); - } - else - { - // set top item and bring focus on the screen - this._setTopListItem(newPos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - } -}; - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipeIndex = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._yIndex, this._maxScrollYIndex < 0 ? this._scrollerHIndex - this._maskH + this._yIndex - this._minScrollYIndex : 0, 0); - - /* ANIMATE THE LETTER INDEX SCROLLER */ - var newPos = this.m.min(this.m.max(this._yIndex + momentumY.dist, this._maxScrollYIndex), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getIndexSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.letterIndex.offsetTop) // only if newPos is a number and the letter index is worth scrolling - { - // start animation - this._animateLetterIndex(newPos, swipeDuration); - } - else - { - // set top letter index and bring focus on the screen - this._setTopLetterIndex(newPos); - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (focussedLetterIndex < this._topLetterIndex) - { - this._showFocusLetterIndex(this._topLetterIndex); - } - } -}; - -/** - * @param {integer} - dragged distance - * @param {time} - time dragged - * @param {integer} - this._y - * @param {integer} - this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0 - * @param {integer} - 0 - */ -List2Ctrl.prototype._momentum = function (dist, time, maxDistUpper, maxDistLower, size) -{ - var deceleration = this.properties.deceleration, - speed = this.m.abs(dist) / time, - newDist = (speed * speed) / (2 * deceleration), - newTime = 0, outsideDist = 0; - - // Proportinally reduce speed if we are outside of the boundaries - if (dist > 0 && newDist > maxDistUpper) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistUpper = maxDistUpper + outsideDist; - speed = speed * maxDistUpper / newDist; - newDist = maxDistUpper; - } else if (dist < 0 && newDist > maxDistLower) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistLower = maxDistLower + outsideDist; - speed = speed * maxDistLower / newDist; - newDist = maxDistLower; - } - - newDist = newDist * (dist < 0 ? -1 : 1); - newTime = speed / deceleration; - - return { dist: newDist, time: Math.round(newTime) }; -}; - - -/** - * ========================= - * LETTER INDEX - * ========================= - */ - -/** - * Letter index select - * scrolls list to letter index - * TAG: internal - * ========================= - * @param {integer} - the new position of the scroller in element index. - * @return {void} - */ -List2Ctrl.prototype._letterIndexSelect = function(letterIndex, eventCause) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // check if if letterIndex is a valid index - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - return; - } - - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - - // set scroll nature - this._scrollNature = 'letterIndex'; - - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - - // set letter index active position - this._setLetterIndexPosition(this.letterIndexData[letterIndex].itemIndex); - - // update last item with focus so that focus gets restored in the correct place - this._lastItemWithFocus = this.letterIndexData[letterIndex].itemIndex; - - // set proper event cause - var eventCause = ('Multicontroller' != eventCause && 'Touch' != eventCause) ? null : eventCause; - // produce beep - this._beep('Short', eventCause); - - // dispatch letter select event - var eventData = { - index : letterIndex, - label : this.letterIndexData[letterIndex].label, - itemIndex : this.letterIndexData[letterIndex].itemIndex, - }; - this._listEvent(this._EVENTS.LETTER_SELECT, eventData); -}; - -/** - * Schedule letter index select after some time - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - - if (!clear) - { - // if no letter index is passed, get the currently focussed one - if (undefined === letterIndex) - { - // check whether we already have focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex) - { - // if yes, schedule to that one - letterIndex = focussedLetterIndex; - } - } - - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - this._letterIndexSelect(letterIndex); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; - -/** - * Schedule background letter index select after some time. - * Background select occurs without affecting the letter index - * scroll position. This is intended to be used only programatically. - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleBackgroundLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - // check for a valid letter index item - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - log.warn('List2: a valid letter index expected. Letter index passed": ' + letterIndex); - return; - } - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - if (!clear) - { - // activate the new index - this._setCurrentLetterIndex(letterIndex); - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - // set scroll nature - this._scrollNature = 'letterIndex'; - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; -/** - * Animate the letter index - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @param {integer} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateLetterIndex = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - // animate letter index - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.letterIndexAnimationEndCallback = this._letterIndexAnimationEnd.bind(this); - this.letterIndex.addEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndex.style.top = pos + 'px'; - - // set top letter index - this._setTopLetterIndex(pos); -}; - -/** - * Set top letter index item depending on the position - * TAG: internal - * ========================= - * @param {integer} - position in px at which the letter should be - * @return {void} - */ -List2Ctrl.prototype._setTopLetterIndex = function(pos) -{ - // pos should be number for proper topLetterIndex calculation - if (!isNaN(pos)) - { - this._prevTopLetterIndex = this._topLetterIndex; - this._topLetterIndex = -(Math.round(pos / this.properties.letterIndexHeight)); - } -}; - -/** - * Get snap position of letter index - * depending on the new letter index position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getIndexSnapPosition = function(pos) -{ - return this.properties.letterIndexHeight * (Math.round(pos / this.properties.letterIndexHeight)); -}; - -/** - * Scroll letter index to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {void} - */ -List2Ctrl.prototype._snapIndex = function(pos) -{ - // the snap position is the same as the current - if (pos == this._yIndex) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollYIndex) - { - // set top item and bring focus on the screen - this._setTopLetterIndex(pos); - var focussedIndex = this._getFocussedLetterIndex(); - if (focussedIndex < this._topLetterIndex) - { - this._restoreLetterIndexFocus(); - } - return; - } - - var snapPos = this._getIndexSnapPosition(pos); - - // start animation - this._animateLetterIndex(snapPos); -}; - -/** - * Scroll to a specific index item - * TAG: internal - * ========================= - * @param {integer | string} - letter or letter index - * @return {void} - */ -List2Ctrl.prototype._scrollToIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - var targetIndex = -1; - - if (!isNaN(letter)) - { - // we are going to a letter index - targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - } - else if (typeof letter === 'string'); - { - // we are searching for the letter index of the letter - for (var i=0, l=this.letterIndexData.length; i above or below the visible range - // NOTE: if the letter is within the visible range this should not get called at all - if (-1 != targetIndex && targetIndex >= this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // look below -> find closest target index so that the focus is visible and apply target index correction - targetIndex = targetIndex - this.properties.visibleLetterIndexItems + 1; - } - else if (-1 != targetIndex && targetIndex <= this._topLetterIndex) - { - // look above -> find closest target index so that the focus is visible - // correction: the taget index is the top item whereas the item in question is the second one - targetIndex--; - } - else - { - // we don't scroll if the target is visible - return; - } - - // do the scroll - var newPos = -(targetIndex) * this.properties.letterIndexHeight; // calculate new position - newPos = this.m.max(this.m.min(newPos, this._minScrollYIndex), this._maxScrollYIndex); // constrain it to scroll bounds - this._animateLetterIndex(newPos); // start animation - - -}; - -/** - * Scroll down by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollDownOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the bottom-most position - if (this._topLetterIndex === this.letterIndexData.length - this.properties.visibleLetterIndexItems) - { - // we can't scroll down any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+this.properties.visibleLetterIndexItems-2, 'down'); - // do not scroll if no enabled letters are found - if (null != bi) - { - var newTopLetter = bi + 2 - this.properties.visibleLetterIndexItems; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.max(newPos, this._maxScrollYIndex); // constrain it to the max scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Scroll up by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollUpOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topLetterIndex === 0) - { - // we can't scroll up any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopLetter = bi - 1; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.min(newPos, this._minScrollYIndex); // constrain it to the min scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Set letter index position relative to the - * focussed item in the scroller - * TAG: internal - * ========================= - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexPosition = function(index) -{ - // check for letter index - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return false; - } - - // get focussed item - var focussedIndex; - if (!isNaN(index)) - { - focussedIndex = index; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // get the new index - var targetIndex = -1; - for (var i=this._letterIndexDataSorted.length-1; i>=0; i--) - { - if (focussedIndex >= this._letterIndexDataSorted[i].itemIndex) - { - targetIndex = this._letterIndexDataSorted[i].publicIndex; - break; - } - } - - // show focus on target index - if (targetIndex > -1) - { - this._setCurrentLetterIndex(targetIndex); - } - - // check if letter index scrolling is needed - if (targetIndex >= this._topLetterIndex && targetIndex < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - return; - } - - // scroll to target index - if (targetIndex > -1) - { - this._scrollToIndex(targetIndex); - } -}; - -/** - * Set currently active letter index - * TAG: internal - * ========================= - * @param {integer} - letter item index - * @return {integer} - the currently active letter index - */ -List2Ctrl.prototype._setCurrentLetterIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return null; - } - - var targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - - - // remove any previously active letter index - for (var i=0, l=this.letterIndexData.length; i= this.letterIndexData.length-1) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - case 'up' : - // we are searching for the previous - targetIndex = lastFocussedIndex; - while (targetIndex > 0) - { - targetIndex--; - if (-1 != this.letterIndexData[targetIndex].itemIndex) - { - break; - } - else if (targetIndex <= 0) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - default : - // we are searching for the index of the letter - for (var i=0, l=this.letterIndexData.length; i= letterIndexCount) - { - currentLetter = null; - } - else - { - while (this.letterIndexData[currentLetter].disabled) - { - if (currentLetter >= letterIndexCount-1 || currentLetter <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentLetter = null; - break; - } - currentLetter = ('down' === direction) ? currentLetter+1 : currentLetter-1; - } - } - return currentLetter; -}; - -/** - * Exit hit state of the currently hit index item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._indexRemoveHit = function() -{ - for (var i=0, l=this.letterIndexData.length; i bring back reorder item - if (this._inListReorder && this._reorderTouchElt) - { - this._bringReorderItem(); - } - - // Focus adjust after animation ends - - // get list position - var listPosition = null; - if (0 === this._topItem) - listPosition = 'top'; - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; - else - listPosition = 'middle'; - - // get scroll direction - var scrollDirection = null; - if (this._prevTopItem > this._topItem) - scrollDirection = 'up'; - else if (this._prevTopItem < this._topItem) - scrollDirection = 'down'; - else - scrollDirection = 'none'; - - // get scroll size - var scrollSize = this.m.abs(this._prevTopItem - this._topItem); - - if ('page' === this._scrollNature) - { - // do not place focus, it should have been done by the paging function - } - else if ('item' === this._scrollNature) - { - // show focus - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // check if focussed index is outside the screen and we actually have a scroll - if (scrollSize > this.properties.visibleItems-1 && !this._inLetterIndexMulticontroller) - { - // restore focus - this._restoreFocus(); - } - else if (scrollSize > 0 && !this._inLetterIndexMulticontroller) - { - // check if the focus is just slightly outside the visible range - if (this._lastItemWithFocus < this._topItem || this._lastItemWithFocus >= this._topItem + this.properties.visibleItems) - { - // restore focus - this._restoreFocus(); - } - else - { - // else the focus remains on the screen -> only set letter index position - this._setLetterIndexPosition(this._getFocussedIndex()); - } - } - else - { - // we don't have a scroll -> nothing to do here - } - } - - // lower _inScroll flag - this._inScroll = false; - - // reset scroll nature - this._scrollNature = null; - - // dispatch scroll end event - this._listEvent(this._EVENTS.SCROLL_END, {scrollPosition:this._topItem}); -}; - -/** - * Restore focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreFocus = function() -{ - // check if the top item is enabled - if (!this.dataList.items[this._topItem].disabled) - { - this._showFocus(this._topItem, false, false, true); - } - // top item is disabled, find the nearest enabled item below the top one - else - { - var neiDown = this._getNearestEnabledItem(this._topItem, 'down'); - // check if the item is on screen - if (null != neiDown && neiDown >= this._topItem && neiDown < this._topItem + this.properties.visibleItems) - { - this._showFocus(neiDown, true, false, true); - } - // there's no enabled item or it is off screen - else - { - this._showFocus(this._topItem, false, false, true); - } - } -}; - -/** - * Scroll indicator animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorAnimationEnd = function() -{ - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicatorAnimationEndCallback = null; - - // fadeOut scroll indicator - this._fadeOutScrollIndicator(); -}; - -/** - * Letter index animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._letterIndexAnimationEnd = function() -{ - // remove animation end callbacks - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndexAnimationEndCallback = null; - - // restore focus - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex && (focussedLetterIndex < this._topLetterIndex || focussedLetterIndex > this._topLetterIndex + this.properties.visibleLetterIndexItems - 1)) - { - // focus is off screen - this._restoreLetterIndexFocus(); - } - else if (null != focussedLetterIndex) - { - // schedule letter index select if letter is enabled - if (!this.letterIndexData[focussedLetterIndex].disabled) - { - this._scheduleLetterIndexSelect(focussedLetterIndex); - } - } -}; - -/** - * Restore letter index focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreLetterIndexFocus = function() -{ - // check if the top letter index is enabled - if (!this.letterIndexData[this._topLetterIndex].disabled) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule letter index select - this._scheduleLetterIndexSelect(this._topLetterIndex); - } - else - { - // look for enabled item down and up - var neiDown = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'down'); - var neiUp = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'up'); - // determine scroll direction - var scrollDirection = (this._topLetterIndex - this._prevTopLetterIndex < 0) ? 'up' : 'down'; - - // check whether we have an enabled item on screen - if (null != neiDown && neiDown >= this._topLetterIndex && neiDown < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // there is an enabled item on screen -> place the focus there - this._showFocusLetterIndex(neiDown); - // schedule letter index select - this._scheduleLetterIndexSelect(neiDown); - } - else if ('down' === scrollDirection) - { - // we are scrolling down -> look for enabled item up - if (null != neiUp) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiUp); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - else if ('up' === scrollDirection) - { - // we are scrolling up -> look for enabled item down - if (null != neiDown) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiDown); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - } -}; - - -/** - * ========================= - * SLIDERS AND TOGGLE CONTROL - * ========================= - */ - -/** - * Passes START (mousedown) event to the currently - * targeted slider instance and returns it. - * TAG: internal - * ========================= - * @param {MouseEvent} - * @param {Boolean} - * @return {SliderCtrl} - */ -List2Ctrl.prototype._slideStart = function(e, skipActiveSlider) -{ - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // check if slider can be adjusted - if (!this.dataList.items[itemIndex].allowAdjust) - { - return; - } - - // check if we are in the hittable area - if(!this._hasRightHittableArea(this.dataList.items[itemIndex])) - { - var relativeX = e.pageX - this._maskPositionX; - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight; - var leftBoundary = this.properties.sliderReferencePointRight - this.properties.sliderWidth; - } - else if(this.dataList.items[itemIndex].indented) - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)) + (this.properties.indentOffset * 2); - var leftBoundary = this.properties.sliderReferencePointLeft; - } else - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)); - var leftBoundary = this.properties.sliderReferencePointLeft; - } - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> exit - return; - } - - var sliderInstance = this._getSlider(itemIndex); - var skipActiveSlider = (true === skipActiveSlider); - if (!skipActiveSlider) - { - // set currently active slider - this._activeSlider = { - itemIndex : itemIndex, // currently active slider index - slider : sliderInstance // currently active slider instance - }; - - // transition focus to slider and hide focus on the item - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - this._hideFocus(); - - // pass the event to the SliderCtrl - this._activeSlider.slider._onDownHandler(e); - } - - return sliderInstance; -}; - -List2Ctrl.prototype._slideMove = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - return; - } - - // determine target item - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // pass the event to the SliderCtrl - this._activeSlider.slider._onMoveHandler(e); -}; - -List2Ctrl.prototype._slideEnd = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - var sliderInstance = this._slideStart(e, true); - if (sliderInstance && !this._stopSelect) - { - // pass the event to the SliderCtrl - sliderInstance._onDownHandler(e); - sliderInstance._onUpHandler(e); - } - return; - } - else - { - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - if (this._inSecondaryMulticontroller && itemIndex == this._currentSecondaryMulticontrollerItem) - { - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // pass the event to the SliderCtrl - this._activeSlider.slider._onUpHandler(e); - - // transition focus back to item and remove it from the slider - this._activeSlider.slider.handleControllerEvent('lostFocus'); - this._showFocus(this._lastItemWithFocus, true); - } - } - - // reset currently active slider - this._activeSlider = null; -}; - -List2Ctrl.prototype._slideCallback = function() -{ - // get item index from the first argument - var itemIndex = arguments[0]; - - // get value and final adjustment from fourth argument - var value = arguments[3].value; - var finalAdjustment = arguments[3].finalAdjustment; - - // update local value - this.dataList.items[itemIndex].value = value; - - // Fire slide callback passing forward anything in the arguments - if (typeof this.properties.slideCallback == 'function') - { - // fire callback with original slider params - // this.properties.slideCallback.apply(null, Array.prototype.slice.call(arguments, 1)); - - // fire per-design callback - var params = { - itemIndex : itemIndex, - value:value, - finalAdjustment : finalAdjustment - }; - this.properties.slideCallback(this, this.dataList.items[itemIndex].appData, params); - } -}; - - - -/* - * ========================= - * TOGGLE BUTTONS - * When a button is selected it is automatically - * highlighted (activated) and the value is reported to the - * button select callback (if defined) - * ========================= - */ - - -/** - * Remove hit state from the toggle button - * TAG: touch-only, internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {void} - */ -List2Ctrl.prototype._buttonRemoveHit = function(itemIndex) -{ - var targetElt = this._getDOMItem(itemIndex); - if (targetElt) - { - var hitItems = targetElt.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - // Check which button is hit - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button hit - if (buttonId) - { - // save the button as _startButton - this._startButton = buttonId; - - var domItem = this._getDOMItem(itemIndex); - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle button - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable && this._startButton) - { - // we are outside the hittable area and we have started from a button -> return cancel - return 'cancel'; - } - else if (!inHittable) - { - // we are outside the hittable area -> return cancel - return null; - } - - // Check which button is selected - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button active - if (buttonId && buttonId === this._startButton) - { - this._startButton = null; - - if (this.dataList.items[itemIndex].value == buttonId) - { - // we ended on already selected button -> cancel - return 'cancel'; - } - // we ended up on the same button we started -> select that button - this._buttonActivate(itemIndex, buttonId); - } - else if (buttonId && null === this._startButton) - { - // we started off the buttons but ended up on a button -> select next button - this._startButton = null; - return null; - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startButton = null; - return 'cancel'; - } - - // Return the button id - return buttonId; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectLeft = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectRight = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current+1); -}; - -/** - * Activate toggle button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonActivate = function(itemIndex, buttonId) -{ - // Ensure that buttonId is valid and wraps in a loop - if ('style10' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 2) - buttonId = 1; - else if (buttonId < 1) - buttonId = 2; - } - else if('style11' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 3) - buttonId = 1; - else if (buttonId < 1) - buttonId = 3; - } - else if('draggable' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = 1; - } - else - { - log.debug('Unknown item style for itemIndex ' + itemIndex); - return null; - } - - if ('draggable' != this.dataList.items[itemIndex].itemStyle) - { - // Save the new value in the dataList - this.dataList.items[itemIndex].value = buttonId; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Remove any residual hit states - this._buttonRemoveHit(itemIndex); - - // Activate the button - if (domItem) - { - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // save the button as _startLockButton - this._startLockButton = buttonId; - - // remove hit - this._lockRemoveHit(itemIndex); - - // make that button hit - if (1 === buttonId) - { - this._lockShowFocus(itemIndex, 1); - domItem.querySelector('.buttonLock').classList.add('hit'); - } - else - { - this._lockShowFocus(itemIndex, 2); - domItem.querySelector('.buttonDelete').classList.add('hit'); - } - - this._hideFocus(); - - return true; - -}; - -/** - * Select lock button - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockSelect = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return null; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return null; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // set secondary multicontroller leaving highlight from where it started - if (this._startLockButton) - { - this._setSecondaryMulticontroller(true, itemIndex); - this._lockShowFocus(itemIndex, this._startLockButton); - } - - // we are outside the hittable area -> return null - return null; - } - - var action = null; - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // Make that button active - if (buttonId === this._startLockButton) - { - this._startLockButton = null; - // we ended up on the same button we started -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else if (null === this._startButton) - { - this._startLockButton = null; - // we started off the buttons but ended up on a button -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startLockButton = null; - - return null; - } - - // Return the performed action - return action; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusLeft = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusRight = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current+1); -}; - -/** - * Activate lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the button that is going to be activated - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockActivate = function(itemIndex, buttonId) -{ - var action = null; - - switch (buttonId) - { - case 1 : - if (this.dataList.items[itemIndex].locked) - { - this.dataList.items[itemIndex].locked = false; - action = 'unlock'; - } - else - { - this.dataList.items[itemIndex].locked = true; - action = 'lock'; - } - break; - case 2 : - if (!this.dataList.items[itemIndex].locked) - { - action = 'delete'; - } - break; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Update the item - if (domItem) - { - switch (action) - { - case 'lock' : - domItem.classList.add('locked'); - break; - case 'unlock' : - domItem.classList.remove('locked'); - break; - } - } - - return action; -}; - - -/** - * Show focus highlight on a lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the index of the button that will be focused - * @return {integer} - id of the focussed lock button - */ -List2Ctrl.prototype._lockShowFocus = function(itemIndex, buttonId) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - if ('clear' === buttonId) - { - if (domItem) - { - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.remove('focus'); - } - return null; - } - else - { - // validate button id - var buttonId = this.dataList.items[itemIndex].locked ? 1 : this.m.min(this.m.max(buttonId, 1), 2); - - if (domItem) - { - // add focus on the respective button - switch (buttonId) - { - case 1 : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - case 2 : - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.add('focus'); - break; - default : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - } - } - return buttonId; - } -}; - - -/** - * Get currently focused lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - id of the currently focussed lock button - */ -List2Ctrl.prototype._lockGetFocus = function(itemIndex) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - var focussedButton = null; - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (domItem.querySelector('.buttonLock').classList.contains('focus')) - focussedButton = 1; - else if (domItem.querySelector('.buttonDelete').classList.contains('focus')) - focussedButton = 2; - } - - return focussedButton; -}; - - -/* - * ========================= - * STEP ITEM - * ========================= - */ - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {MouseEvent} - raw mouse event - * @return {integer} - the new value - */ -List2Ctrl.prototype._stepAdjust = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // perform hit test - var itemDOMElement = this._getDOMItem(itemIndex); - if (!itemDOMElement) - { - return; - } - - var p = itemDOMElement.querySelector('.plus'); - var m = itemDOMElement.querySelector('.minus'); - var pLayout = { x1:p.offsetLeft, x2:p.offsetLeft + p.clientWidth }; - var mLayout = { x1:m.offsetLeft, x2:m.offsetLeft + m.clientWidth }; - - var newValue = null; - - if (relativeX >= pLayout.x1 && relativeX <= pLayout.x2) - { - // plus pressed - newValue = this._stepUp(itemIndex); - } - else if (relativeX >= mLayout.x1 && relativeX <= mLayout.x2) - { - // minus pressed - newValue = this._stepDown(itemIndex); - } - else if (relativeX < mLayout.x1) - { - newValue = 'commit'; - } - - - return newValue; -}; - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepUp = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.min(this.dataList.items[itemIndex].value + this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].max); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - -/** - * Decrease the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepDown = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.max(this.dataList.items[itemIndex].value - this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].min); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - - -/** - * ========================= - * LIST REORDERING - * ========================= - */ - -/** - * Enter into list reorder mode - * This method stores the original item style of the - * item that is being reordered and substitutes it with - * an internal 'draggable' item style. - * TAG: internal - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype._enterListReorder = function(fromInit) -{ - // keep a copy of the item before converting it to a draggable item - - var focussedIndex; - if (fromInit) - { - focussedIndex = this.properties.focussedItem; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // check for items in the dataList - if (!this.dataList || !this.dataList.items || !this.dataList.items[focussedIndex]) - { - return; - } - - // do not reorder disabled items - if (this.dataList.items[focussedIndex].disabled) - { - return; - } - - // enter into List Reordering mode - this._inListReorder = true; - - this.dataList.items[focussedIndex].itemBehavior = 'shortAndLong'; // make it accept long press (if not already) - this._reorderItem = this.dataList.items[focussedIndex]; - this._reorderItemIndex = focussedIndex; - this._reorderCurrentIndex = focussedIndex; - - // convert the item to a draggable item - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[focussedIndex] = draggableItem; - this.updateItems(focussedIndex, focussedIndex); - -}; - -/** - * Leave list reorder mode - * The item that is being reordered is restored - * to it initial style. The select callback is - * then fired to notify the interested parties of - * the change and the new position of the item. - * TAG: internal - * ========================= - * @param {Boolean} - prevent item selection when releasing the reorder - * @return {void} - */ -List2Ctrl.prototype._releaseListReorder = function(preventSelect) -{ - // exit list reordering mode - this._inListReorder = false; - - // get draggable item index - var draggableItems = this.getItemsByType('draggable'); - if (!draggableItems.length) - { - return; - } - - var draggableItemIndex = draggableItems[0]; - - // convert the draggable item back into the previous item type - this.dataList.items[draggableItemIndex] = this._reorderItem; - this.updateItems(draggableItemIndex, draggableItemIndex); - - // cast preventSelect as Boolean - var preventSelect = Boolean(preventSelect); - - // selection is allowed - if (!preventSelect) - { - // fire item select - var params = { - newIndex : draggableItemIndex, - oldIndex : this._reorderItemIndex - }; - this._itemSelect(draggableItemIndex, params); - } - - // release the copy of the reorder item - this._reorderItem = null; - this._reorderItemIndex = null; - this._reorderTouchElt = null; - -}; - - -/** - * Touch start reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._startReorder = function(e) -{ - // get target item index - var itemIndex = this._getTargetItem(e); - - // get draggable item index - if (itemIndex === this._reorderCurrentIndex) - { - this._startY = e.pageY - this._maskPositionY; - this._startX = e.pageX - this._maskPositionX; - - // do we have hit on the button? - var positiveButtonHit = this._buttonMakeHit(e); - - if (!positiveButtonHit) - { - this._itemMakeLongPress(e); - - // clone draggable item - var tmp = this._getDOMItem(itemIndex); - this._reorderTouchElt = tmp.cloneNode(true); - this.scroller.appendChild(this._reorderTouchElt); - - // convert the draggable item to a ghost item - var ghostItem = {itemStyle:'ghost', hasCaret:false}; - this.dataList.items[itemIndex] = ghostItem; - this.updateItems(itemIndex, itemIndex); - - this._hideFocus(); - - // raise _inDrag - this._inDrag = true; - } - else - { - // flag the behaviour as release intent - this._releaseReorderByTouch = true; - } - - // track event - this._trackEvent(e); - } -}; - -/** - * Touch move reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._moveReorder = function(e) -{ - if (this._reorderTouchElt) - { - // track event - this._trackEvent(e); - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // get last move - var moveDirection = this._getMoveDirection(); - - // reset any scheduled scrolling if the user intends cacnelling the scroll - if (newPos <= (this._topItem * this.properties.itemHeight) + this.properties.itemHeight && - newPos > this._topItem * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - else if (newPos >= (this._topItem + this.properties.visibleItems - 2) * this.properties.itemHeight && - newPos < (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - - // drag down - if (1 === moveDirection) - { - // have we passed the last item's top border? - if ( (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) && (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) ) - { - this._reorderGhostItemDown(); - } - else if (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) - { - // do we have a scroll down scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos >= (this._reorderCurrentIndex * this.properties.itemHeight) + this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemDown(); - } - } - // drag up - else if (-1 === moveDirection) - { - // have we passed the top item's top border? - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // do we have a scroll up scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos <= (this._reorderCurrentIndex * this.properties.itemHeight) - this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemUp(); - } - } - - } // endif (this._reorderTouchElt) -}; - -/** - * Touch end reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._endReorder = function(e) -{ - if (this._reorderTouchElt) - { - // get nearest snap position - var newSnappedIndex = Math.floor( ( (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) ) / this.properties.itemHeight ); - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = newSnappedIndex * this.properties.itemHeight; - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the scroller if in bounds - this._reorderTouchElt.style.top = newPos + 'px'; - - // convert the ghost item back to a draggable ite m - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[this._reorderCurrentIndex] = draggableItem; - this.updateItems(this._reorderCurrentIndex, this._reorderCurrentIndex); - - // remove the cloned element - this._reorderTouchElt.parentElement.removeChild(this._reorderTouchElt); - } - - this._itemRemoveLongPress(); - this._reorderTouchElt = null; - - // reset flags - this._inHorizontalDrag = null; - this._hDragItem = null; - this._inDrag = false; - this._stopSelect = false; - - // restore focus - this._showFocus(this._reorderCurrentIndex); - - // clear any scroll timeout - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - - // are we about to release reorder - if (this._releaseReorderByTouch && this._isToggle(this._reorderCurrentIndex)) - { - // remove hit state of button and release list reorder - this._buttonRemoveHit(this._reorderCurrentIndex); - this._releaseListReorder(); - this._releaseReorderByTouch = false; - } - -}; - -/** - * After the list has scrolled due to touch reorder action, - * upon animation end, the touch reorder item is brought under the - * user's finger and if the possition requires it, a new scroll - * is scheduled. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._bringReorderItem = function() -{ - if (this._trackedEvents.length && this._reorderTouchElt) - { - // get last event - var lastEvent = this._trackedEvents[this._trackedEvents.length-1]; - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (lastEvent.y - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // we are past the top item's top boundary - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemUp(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (0 == this._topItem) - { - // update blank spot - this._reorderGhostItemUp(); - } - else if (this._topItem != this.dataList.itemCount - this.properties.visibleItems && - newPos >= (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemDown(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) - { - // update blank spot - this._reorderGhostItemDown(); - } - - } -}; -/** - * Reorder the item to the index - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {void} - */ -List2Ctrl.prototype._reorderToIndex = function(itemIndex) -{ - if (!this._inListReorder || isNaN(itemIndex)) - { - log.error("list1 _reorderToIndex : Invalid arguments - inListReorder, itemIndex", this._inListReorder, itemIndex); - return; - } - - if (itemIndex != this._reorderItemIndex) - { - if (itemIndex < this._reorderItemIndex) - { - this._reorderItemUp(this._reorderItemIndex - itemIndex) - } - else - { - this._reorderItemDown(itemIndex - this._reorderItemIndex) - } - } -} - -/** - * Reorder the item down - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemDown = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(draggableItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(draggableItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; -/** - * Reorder the item up - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemUp = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(draggableItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, draggableItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; - -/** - * Reorder ghost item one position down - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemDown = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(ghostItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(ghostItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - -/** - * Reorder ghost item one position up - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemUp = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(ghostItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, ghostItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - - -/** - * ========================= - * LIST EVENTS API - * ========================= - */ - -/** - * List event - * TAG: internal - * ========================= - * @param {string} - Event name - * @param {*} - Event data - * @return {void} - */ -List2Ctrl.prototype._listEvent = function(type, data) -{ - var data = data || null; - switch (type) - { - case this._EVENTS.ITEM_SELECT : - this._dispatch(this._EVENTS.ITEM_SELECT, data); - break; - case this._EVENTS.LETTER_SELECT : - this._dispatch(this._EVENTS.LETTER_SELECT, data); - break; - case this._EVENTS.DATALIST_CHANGE : - this._dispatch(this._EVENTS.DATALIST_CHANGE, null); - break; - case this._EVENTS.SCROLL_START : - this._dispatch(this._EVENTS.SCROLL_START, data); - break; - case this._EVENTS.SCROLL_END : - this._dispatch(this._EVENTS.SCROLL_END, data); - break; - case this._EVENTS.CLEAN_UP : - this._dispatch(this._EVENTS.CLEAN_UP, data); - break; - default : - // nothing to do - break; - } -}; - -/** - * Get listeners array for an event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {array} - */ -List2Ctrl.prototype._getListeners = function(type, useCapture) -{ - var captype = (useCapture ? '1' : '0') + type; - if (!(captype in this._eventListeners)) - this._eventListeners[captype] = []; - return this._eventListeners[captype]; -}; - -/** - * Dispatch custom event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {void} - */ -List2Ctrl.prototype._dispatch = function(type, data) -{ - if (!type || '' == type) - return; - var evt = new CustomEvent( type, { detail : { data : data, bubbles: true, cancelable: true } } ); - this.dispatchEvent(evt); -}; - -/** - * Add event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.addEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 === ix) - listeners.push(listener); -}; - -/** - * Remove event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.removeEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 !== ix) - listeners.splice(ix, 1); -}; - -/** - * Displatch custom list event - * TAG: public - * ========================= - * @param {object} - event object - * @return {boolean} - */ -List2Ctrl.prototype.dispatchEvent = function(evt) -{ - var listeners = this._getListeners(evt.type, false).slice(); - for (var i= 0; i dataList.items.length) - { - for (var i=dataList.items.length; i= 0) - { - // force exit secondary multicontroller - this._inSecondaryMulticontroller = false; - - var additionalSpace = this._getAdditionalSpace(); - - this.scroller.style.height = this.dataList.itemCount * this.properties.itemHeight + additionalSpace + 'px'; - this._scrollerH = this.scroller.offsetHeight; - this._emptyScroller(); - this._scrollIndicatorReset(); - if(0 === this.dataList.itemCount) - { - this._scrollIndicatorBuild(false); - } - else - { - this._scrollIndicatorBuild(true); - } - - // set line numbers - this.setLineNumbers(); - } - -}; - -List2Ctrl.prototype.hasDataList = function() -{ - if (this.dataList == null) - { - return false; - } - - if (!this.dataList.hasOwnProperty('itemCountKnown') && !this.dataList.hasOwnProperty('itemCount') && !this.dataList.hasOwnProperty('items')) - { - return false; - } - - if (this.dataList.itemCountKnown && this.dataList.itemCount == 0) - { - return false; - } - - if (!this.dataList.itemCountKnown && this.dataList.itemCount <= 0) - { - return false; - } - - return true; -}; - -/** - * Update Items - * - * This is intended to be used whenever the bound data is changed programmatically by the app. In other words, - * it informs the control that bound data has changed … and if the range of changed items overlaps with items - * rendered into HTML objects, then the ListMenu must update those elements. There are several use cases for this: - * - * 1. For the case where the dataList is fetched asynchronously in the background after ListMenu is displayed, - * the updateItems() API will be called as new data arrives. I think this use case is described fairly completely - * in section 2.2.4 of the ListMenu SDD. Note that these updates may correspond to the user scrolling, or may simply - * occur in the background as the list is loaded into GUI while the user is still looking at the first N list items. - * Also note that the listCount can change and the ListMenu control must adapt appropriately, including handling - * reduction of the list count. - * - * 2. To allow the application to update menu text dynamically, e.g. to display the name of the connected USB - * Audio device instead of “USB”, or to change the displayed image(s). - * - * 3. To allow the application to enable/disable menu items or to set/clear the “selected” indicator. - * - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype.updateItems = function(firstItem, lastItem) -{ - log.debug("List2 updateItems() firstItem, lastItem",firstItem, lastItem); - // update _maxScrollY - this._maxScrollY = this.mask.offsetHeight - this.scroller.offsetHeight; - - var emptyDOMItem = null; - - // clear _needDataTimeoutId - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = null; - - this._prepareItems(firstItem, lastItem); - this._localizeItems(firstItem, lastItem); - - // trim dataList.items if it is larger than dataList.itemCount - if (this.dataList && - this.dataList.itemCountKnown && - this.dataList.items && - this.dataList.itemCount < this.dataList.items.length) - { - this.dataList.items = this.dataList.items.slice(0, this.dataList.itemCount); - console.assert(this.dataList.itemCount == this.dataList.items.length, 'dataList.itemCount is not equal to dataList.items.length'); - } - - // validate first item - if (this.dataList.itemCountKnown && firstItem < -1) - { - log.warn('List2: firstItem is less than -1: ' + firstItem + ' passed. Setting it to -1.'); - firstItem = -1; - } - - // validate last item - if (this.dataList.itemCountKnown && lastItem >= this.dataList.itemCount) - { - log.warn('List2: lastItem is more than or equals dataList.itemCount(' + (this.dataList.itemCount-1) + '): ' + lastItem + ' passed. Setting it to ' + (this.dataList.itemCount - 1) + '. ' + this.uiaId + ' check your variable validation!?'); - lastItem = this.dataList.itemCount - 1; - } - - - // check for invalid items (e.g. firstItem=0, lastItem=-1) -> set loading - if (firstItem > lastItem) - { - firstItem = lastItem = -1; - } - - if (firstItem == -1 && lastItem == -1) - { - // we have dataList but no list items => show loading - this._setLoading(true); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem && !this._hasFill) - { - - - // we have dataList and we have list items but we do not have fill => do initial fill - var lastFillItem = this.m.min(lastItem, this.properties.itemsBefore + this.properties.itemsAfter); - - this._fill(firstItem, lastFillItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - if (this.properties.focussedItem < this.dataList.itemCount) - { - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - else - { - this.properties.focussedItem = this.dataList.itemCount - 1; - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - /* - * Immediately scroll to a preset location and - * show focus on preset item if this is specified - * in the control's config. Focus placement needs to be done - * after the DOM is refreshed. This is done only the - * first time after a fresh setDataList() call. - * Focussed item has precedence over scroll location. - */ - if (null === this._initialScrollMode) - { - // first check if the focussed item and the scroll position are all on the same screen - // scroll to that position and show the focus according to the config - if ( (this.properties.focussedItem >= 0 || this.properties.scrollTo >= 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 1)) ) - { - log.debug('Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // set initial focus to a particular item if this is set in the config - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem >= 0) - { - log.debug('Focus is not visible and has priority'); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // scroll (no animation) to a particular item if this is set in the config - // the focus will be placed on the top item - else if (this.properties.scrollTo >= 0) - { - log.debug('Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._topItem = this._canGainFocus(this._topItem); - this._showFocus(this._topItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - } - // sync the top item with focus if not in initial mode any more - // enter in this case usualy when a new data list is set - else - { - var focussedItem = this.focussedItem; - var topInFocusRange = focussedItem >= this.topItem && focussedItem < this.topItem + this.properties.visibleItems - 1; - var prevTopInFocusRange = focussedItem >= this._prevTopItem && focussedItem < this._prevTopItem + this.properties.visibleItems - 1; - if (!topInFocusRange && !prevTopInFocusRange) - { - this.topItem = focussedItem; - } - else if (!topInFocusRange && prevTopInFocusRange) - { - this.topItem = this._prevTopItem; - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem) - { - // preserve focussed element - var lastFocussedIndex = this._getFocussedIndex(); - - // we have dataList and we have list items, and we have fill => perform update - this._updateDisplay(firstItem, lastItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - // restore focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(lastFocussedIndex, true); - } - else if (this._inSecondaryMulticontroller) - { - // treat disabling the secondary multicontroller item as interrupt -> commit value and exit - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this.dataList.items[smi].disabled) - { - this._setSecondaryMulticontroller(false, smi); - this._showFocus(smi, true); - } - else if (this.dataList.items[smi]) - { - this._setSecondaryMulticontroller(true, smi); - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else - { - log.error(this.uiaId + ' called List2 updateItems() with invalid arguments: firstItem = ' + firstItem + ', lastItem = ' + lastItem); - } - - // suppress secondary item request when the list is in reorder mode - if (this.properties.enableSecondaryItemRequest && !this._inListReorder) - { - // do we have empty DOM items? - if (null == emptyDOMItem) - { - // clear _secondaryRequestCount - this._secondaryRequestCount = 0; - } - else if (this._secondaryRequestCount <= this.properties.secondaryRequestLimit) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - // increment _secondaryRequestCount - this._secondaryRequestCount++; - } - else - { - log.warn('Lis2: control has reached the secondary request count limit. Enabling the list'); - // we have reached secondaryRequestLimit -> set loading to False - this._setLoading(false); - } - } - - // restore the focus to the last focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(this._lastItemWithFocus, true); - } - -}; - - -/** 2. LETTER INDEX API **/ - -/** - * Set letter index data on demand, filling letters in the letter index area - * and assigning jump indices to them, so that when touched or selected - * by multicontroller, the list jumps to the respective index. - * TAG: public - * ========================= - * @param {data} - letter index data object - * @return {boolean} - True if letter index binding operation is a success - */ -List2Ctrl.prototype.setLetterIndexData = function(data) -{ - // validate input - if (!(data instanceof Array)) - { - log.error('Lis2: letter index data should be a valid array'); - return false; - } - - // validate control support - if (!this.properties.hasLetterIndex) - { - log.error('Lis2: list2 does not support letter index'); - return false; - } - - // reset any previous letter index data - this.letterIndexData = []; - this.letterIndex.innerText = ''; - - var letterIndexItem; - var label; - for (var i=0, l=data.length; i= 0) - { - this._letterIndexDataSorted[this._letterIndexDataSorted.length] = { - publicIndex : this.letterIndexData.length-1, - itemIndex : data[i].itemIndex - }; - } - } - - // sort private and filtered letter index by the itemIndex in ASC order - this._letterIndexDataSorted.sort(function(a,b) { - var compRes = 0; - if (a.itemIndex < b.itemIndex) - compRes = -1; - else if (a.itemIndex > b.itemIndex) - compRes = 1; - else - compRes = 0; - return compRes; - }); - - // set letter index scroller height - var additionalSpace = Math.ceil(this.properties.letterIndexHeight / 2) - 5; // adjusting factor - this.letterIndex.style.height = i * this.properties.letterIndexHeight + additionalSpace + 'px'; - this._scrollerHIndex = this.letterIndex.offsetHeight; - - // update _maxScrollYIndex - this._maxScrollYIndex = this.letterIndexWrapper.offsetHeight - this.letterIndex.offsetHeight; - - // set initial active letter index if there are any available - if (this.hasDataList() && this._letterIndexDataSorted.length) - { - // get current focus index and first letter index - var focussedIndex = this._getFocussedIndex(); - var firstIndex = this._letterIndexDataSorted[0].itemIndex; - - if (firstIndex > 0 && focussedIndex < firstIndex) - { - this._setLetterIndexPosition(firstIndex); - } - else - { - this._setLetterIndexPosition(focussedIndex); - } - - } - else if (this._letterIndexDataSorted.length) - { - this._setLetterIndexPosition(this._letterIndexDataSorted[0].itemIndex); - } -}; - - -/** 3. VOICE API **/ - -/** - * Set left button configuration depending on current list configuration: - * title style, visible items, item count, item thickness - * TAG: public, VUI - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setLineNumbers = function() -{ - // check if we need to show numbers - if (!this.properties.numberedList) - { - return; - } - - // check if we have some items to number - if (!this.dataList.hasOwnProperty('itemCount') || this.dataList.itemCount <= 0) - { - return; - } - - - var style = ''; - var maxItemCount = 0; - - // determine max item count and style - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - maxItemCount = this.properties.thickItems ? 5 : 6; - style = this.properties.thickItems ? 'Style02' : 'Style04'; - break; - case 'tabsTitle' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style03a' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'style05' : - case 'style08' : - maxItemCount = 4; - style = this.properties.thickItems ? 'Style07' : 'Style06'; - break; - case 'style06' : - case 'style07' : - maxItemCount = 3; - style = this.properties.thickItems ? 'Style09' : 'Style08'; - break; - default : - log.warn('Lis2: unknown title style: ' + this._currentTitle.titleStyle); - return; - break; - } - break; - default : - log.warn('Lis2: unknown title configuration: ' + this.properties.titleConfiguration); - return; - break; - } - - // get actual item count - var itemCount = this.m.min(this.dataList.itemCount, maxItemCount); - - // check for common API - if (framework.common.setLineNumbers) - { - // call LeftBtnCtrl to show list numbers - return framework.common.setLineNumbers(itemCount, style); - } - -}; - -/** - * Performs select on the specified line number. When the select callback is fired, - * fromVui parameter is set to true. The function can return several possible - * statuses depending on the output of the operation. - * TAG: public, VUI - * ========================= - * @param {integer} - the line number that needs to be selected - * @return {string} - 'selected', 'outOfRange', 'disabled', 'sendAck', 'noList' - */ -List2Ctrl.prototype.selectLine = function(lineNumber) -{ - // get target item - var targetIndex = this._topItem + (lineNumber - 1); - - // decide what to return depending on what's visible - var status; - - // check if the list supports line numbers - if (!this.hasDataList()) - { - status = 'noList'; - log.debug('Lis2: selectLine() called with no list on the screen'); - } - else if (!this.dataList.vuiSupport) - { - status = 'noList'; - log.debug('Lis2: no VUI support for this list'); - } - else if (targetIndex > this.dataList.itemCount - 1 || targetIndex < 0) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (targetIndex < this._topItem || targetIndex > this._topItem + this.properties.visibleItems) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (!this.dataList.items[targetIndex].vuiSelectable) - { - status = 'notSelectable'; - log.debug('Lis2: list item is not VUI selectable'); - } - else if (this.dataList.items[targetIndex].disabled) - { - status = 'disabled'; - log.debug('Lis2: list item is disabled'); - this._itemSelect(targetIndex, {fromVui:true, vuiStatus:status}); - } - else - { - // default status is 'selected' -> if the item is not selectable, the callback will not be fired - var selectResult = this._itemSelect(targetIndex, {fromVui:true, vuiStatus:'selected'}); - if (true === selectResult) - { - // normal enabled status - status = 'selected'; - } - else if (false === selectResult) - { - // status if no select callback is attached - status = 'sendAck'; - } - else - { - // returned status from the select callback in the app - status = selectResult; - } - } - - return status; -}; - -/** - * Scrolls the list one page down. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageDown = function() -{ - var status = this._scrollDownPage(); - return status; -}; - -/** - * Scrolls the list one page up. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageUp = function() -{ - var status = this._scrollUpPage(); - return status; -}; - - -/** 4. SLIDER / TOGGLE API **/ - -/** - * Set slider to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the slider/pivot item - * @param {number} - the new value of the slider/pivot - * @return {void} - */ -List2Ctrl.prototype.setSliderValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isSlider(itemIndex)) - { - log.warn(this.uiaId + ': Lis2: only sliders/pivots can be used in the Slider API. Item style ' + item.itemStyle + ' passed'); - return; - } - - var slider = this._getSlider(itemIndex); - if (slider) - { - slider.setValue(value); - } - else - { - log.error(this.uiaId + ': Lis2: could not get slider instance for itemIndex ' + itemIndex); - } -}; - - -/** - * Set toggle to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the toggle item - * @param {number} - the new value of the toggle - * @return {void} - */ -List2Ctrl.prototype.setToggleValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.debug('Item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isToggle(itemIndex) && item.itemStyle != 'styleOnOff') - { - log.warn('Lis2: only toggle items can be used in the Toggle API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // normalize value - if (item.itemStyle == 'style10') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - else if(item.itemStyle == 'style11') - { - var value = this.m.max(this.m.min(value, 3), 1); - } - else if(item.itemStyle == 'styleOnOff') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'toggle')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'checkbox')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // cast as boolean - var value = Boolean(value); - - // set value - item.checked = value; - - // update item - this.updateItems(itemIndex, itemIndex); -}; - - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setRadio = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'radio')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setRadio = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'tick')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a tick item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the tick item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setTick = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an empty range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // filled item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get filled range - * traverse the dataList.items for filled items and returns - * an array of filled-item ranges - * TAG: public - * ========================= - * @return {array} - Array([firstFilled, lastFilled], [firstFilled, lastFilled]) - */ -List2Ctrl.prototype.getFilledRange = function() -{ - var ranges = []; - var currentRange = []; - - for (var i=0, l=this.dataList.items.length; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an filled range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // empty item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get current focus mode - * TAG: public - * ========================= - * @return {string} - 'mainList' | 'letterIndex' | 'noFocus' - */ -List2Ctrl.prototype.getFocusMode = function() -{ - var currentFocusMode = 'mainList'; - if (!this._hasFocus) - { - currentFocusMode = 'noFocus'; - } - else if (this._inLetterIndexMulticontroller) - { - currentFocusMode = 'letterIndex'; - } - - return currentFocusMode; -}; - - -/** 7. OTHER **/ - -/** - * Set loading state of the list - * TAG: public - * ========================= - * @param {boolean} - enable or disable loading state - * @return {void} - */ -List2Ctrl.prototype.setLoading = function(state) -{ - // cast as boolean - var state = Boolean(state); - this._setLoading(state); -}; - - -/** - * Public API that changes the loading configuration - * ========================= - * @param {Object} - object that will set loading item configuration - * @return {Object} - retuns the loading configuration object - */ -List2Ctrl.prototype.setLoadingConfig = function (config) -{ - for (var i in config) - { - this.properties.loadingConfig[i] = config[i]; - } - - if (null !== this.properties.loadingConfig.loadingTextId && undefined !== this.properties.loadingConfig.loadingTextId && "" !== this.properties.loadingConfig.loadingTextId) - { - this.properties.loadingConfig.loadingText = this._getLocalizedString(this.properties.loadingConfig.loadingTextId, this.properties.loadingConfig.loadingSubMap); - } - this.loading.querySelector(".loadingText").innerText = ""; - this.loading.querySelector(".loadingText").appendChild(document.createTextNode(this.properties.loadingConfig.loadingText)); - this.loading.querySelector(".loadingImage1").style.backgroundImage = 'url(' + this.properties.loadingConfig.loadingImage1 + ')'; - - return this.properties.loadingConfig; -}; - -/** - * Enter or release reorder mode - * TAG: public - * ========================= - * @param {boolean} - enter or release list reorder - * @param {boolean} - prevent item select on releasing reorder - * @return {void} - */ -List2Ctrl.prototype.setReorder = function(state, preventSelect) -{ - // cast as boolean - var state = Boolean(state); - var preventSelect = Boolean(preventSelect); - - if (state && !this._inListReorder) - { - // if user has lost the reorder item - if (null != this._reorderCurrentIndex && (this._reorderCurrentIndex < this._topItem || this._reorderCurrentIndex > this._topItem + this.properties.visibleItems-1)) - { - if (this.dataList.items[this._reorderCurrentIndex] && !this.dataList.items[this._reorderCurrentIndex].disabled) - { - // reorder item is outside screen. Bring it back in and show focus on it - this._showFocus(this._reorderCurrentIndex); - } - } - - // enter into reorder - this._enterListReorder(); - } - else if (!state && this._inListReorder) - { - // release reorder - this._releaseListReorder(preventSelect); - } -}; - -/** - * Set fixed title for the list - * TAG: public - * ========================= - * @param {object} - title properties - * @return {void} - */ -List2Ctrl.prototype.setTitle = function(titleStructure) -{ - - // validate titleStructure - if (!titleStructure || !titleStructure.hasOwnProperty('titleStyle')) - { - return; - } - - /* - * title structure: - * { - * titleStyle : 'style02', - * text1Id : null, - * text1SubMap : null, - * text1 : '', - * image1 : 'path/to/image.png' - * } - */ - - // prepare title - var titleStructure = titleStructure || {}; - titleStructure = this._prepareTitle(titleStructure); - - if (this._currentTitle) - { - // we already have a title -> update it - - // validate new title - switch (titleStructure.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - // thin - if ('style02' != this._currentTitle.titleStyle && - 'style02a' != this._currentTitle.titleStyle && - 'style03' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style05' : - case 'style08' : - // medium - if ('style05' != this._currentTitle.titleStyle && - 'style08' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style06' : - case 'style07' : - // thick - if ('style06' != this._currentTitle.titleStyle && - 'style07' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - } - } - - // empty title element - this.title.innerText = ''; - // remove old title style class - if (this._currentTitle) - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - this.title.classList.remove(this._currentTitle.titleStyle); - } - // add title style as a class - this.title.classList.add(titleStructure.titleStyle); - - // fill it - var line1, line2, image1; - - switch (titleStructure.titleStyle) - { - case 'style02' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style02a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style03' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style05' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleMedium'); - - break; - - case 'style06' : - - if (titleStructure.image1 === 'canvas') - { - // preview image is a canvas - image1 = document.createElement('canvas'); - image1.className = 'image1'; - // store canvas for public API call - this.titleCanvas = image1; - this.title.appendChild(image1); - } - else - { - // preview image is an image - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - } - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style07' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style08' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleMedium'); - - break; - - default : - log.error('Lis2: unknown title style: ' + titleStructure.titleStyle); - } - - // save the title structure - this._currentTitle = titleStructure; - -}; - - -/** 8. CONTEXT CAPTURE AND RESTORE **/ - -/** - * Context capture - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.getContextCapture = function() -{ - var obj = { - hasFocus : this._hasFocus, - topItem : this._topItem, - focussedItem : this._getFocussedIndex(), - itemCount : this.dataList ? this.dataList.itemCount : 0 - }; - - log.debug('Lis2: getContextCapture obj ', obj); - return obj; -}; - -/** - * Context restore - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.restoreContext = function(restoreData) -{ - log.debug('Lis2: restoreContext restoreData ', restoreData); - // validate input - if (!restoreData.hasOwnProperty('topItem') || !restoreData.hasOwnProperty('focussedItem')) - { - log.info('No data to restore'); - return; - } - - - // restore hasFocus flag - if (restoreData.hasFocus) - { - this._hasFocus = true; - } - - if (this.hasDataList()) - { - // scroll to previous position and show previous focus - // no checks for value conflicts are necessary. These ought to be correct. - this._scrollTo(restoreData.topItem); - - // NOTE: actual focus placement happens in controllerActive event handling - - // mark the list as data-restored preventing any subsequent auto-scrolls - this._initialScrollMode = 'restore'; - - this._manageFocus(restoreData.focussedItem); - } - else - { - log.info('List has no dataList to restore'); - } - - // overwrite control properties - this.properties.scrollTo = restoreData.topItem; - this.properties.focussedItem = restoreData.focussedItem; - this._lastItemWithFocus = restoreData.focussedItem; -}; - - -/** 9. BACKGROUND API **/ - -/** - * Set a custom background on the list control - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setListBackground = function(img, position) -{ - this.clearListBackground(); - this.listBackground = document.createElement('div'); - this.listBackground.className = 'List2CtrlCustomBackground'; - this.listBackground.style.backgroundImage = 'url('+img+')'; - - // set background position - if (position && typeof position == 'object' && position['left'] != undefined && position['top'] != undefined) - { - var left = (!isNaN(position['left'])) ? position.left + 'px' : position.left.toString(); - var top = (!isNaN(position['top'])) ? position.top + 'px' : position.top.toString(); - this.listBackground.style.backgroundPosition = left + ' ' + top; - } - - this.divElt.appendChild(this.listBackground); -}; - -/** - * Clear any custom background image - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.clearListBackground = function() -{ - if (this.listBackground) - { - this.listBackground.parentElement.removeChild(this.listBackground); - this.listBackground = null; - } -}; - - - -/** - * ========================= - * HELPERS AND UTILITIES - * ========================= - */ - - /** - * Create Tabs control - * ========================= - * @return The TabsCtrl instance. - */ -List2Ctrl.prototype._createTabsControl = function() -{ - log.debug(' Instantiating TabsCtrl'); - if (this.properties.tabsButtonConfig.tiltStartCallback) - { - log.warn("Lis2: the tabsButtonConfig.tiltStartCallback property was defined outside of the list control but should only be used by the list."); - } - this.properties.tabsButtonConfig.tiltStartCallback = this._tabsCtrlTiltStartCallback.bind(this); - return framework.instantiateControl(this.uiaId, this.divElt, "TabsCtrl", this.properties.tabsButtonConfig); -}; - -/** - * Clear the list contents when the user starts tilting to a new tab. - */ -List2Ctrl.prototype._tabsCtrlTiltStartCallback = function(controlRef, appData, params) -{ - if (this.title) - { - this.title.style.opacity = 0; - } - this.setDataList({}); - this._hideScrollIndicator(); -}; - - -/** - * Tracks touch position properties of the last two events. - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - MouseMove event - * @return {void} - */ -List2Ctrl.prototype._trackEvent = function(e) -{ - // use shallow copy - var trackedEvents = this._trackedEvents; - trackedEvents[0] = trackedEvents[1]; - trackedEvents[1] = { y: e.pageY, x: e.pageX }; -}; - -/** - * Get touch direction upon touch move - * TAG: touch-only, internal - * ========================= - * @return {integer} - 1 for 'down', -1 for 'uo' - */ -List2Ctrl.prototype._getMoveDirection = function() -{ - var trackedEvents = this._trackedEvents, - event0 = trackedEvents[0], - event1 = trackedEvents[1]; - - if (!event0) return 1; - - return (event1.y - event0.y < 0) ? -1 : 1; -}; - -/** - * Get current list position (or specific position relative to supplied item index) - * TAG: internal - * ========================= - * @param {integer} - optional, item index from which to calculate position - * @return {string} - onepage | top | bottom | bottomclose | topclose | middle - */ -List2Ctrl.prototype._getListPosition = function(itemIndex) -{ - // get item index - var itemIndex = (undefined === itemIndex) ? this._topItem : itemIndex; - - // get list position - var listPosition = null; - - // determine list position - if (this.dataList.itemCount <= this.properties.visibleItems) - listPosition = 'onepage'; - else if (0 === itemIndex) - listPosition = 'top'; // list is at the top - else if (itemIndex === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; // list is at the bottom - else if (itemIndex > this.dataList.itemCount - (2 * this.properties.visibleItems)) - listPosition = 'bottomclose'; // list is less than a screen to the bottom - else if (itemIndex < 2 * this.properties.visibleItems) - listPosition = 'topclose'; // list is less than a screen to the top - else - listPosition = 'middle'; // list is somewhere in the middle - - // return list position - return listPosition; -}; - - -/** - * Get additional space that needs to be added to the scroller - * height in order to satisfy the 'half-line' requirements. - * Correction is needed because there's a difference between - * visual style guide and actual item heights. The values are - * fixed and depend on the style. - * TAG: helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getAdditionalSpace = function() -{ - // determine additional space - var additionalSpace = 0; - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - additionalSpace = this.properties.thickItems ? 6 : 32; - break; - case 'tabsTitle' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style03' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'style05' : - case 'style08' : - additionalSpace = this.properties.thickItems ? 52 : 42; - break; - case 'style06' : - case 'style07' : - additionalSpace = this.properties.thickItems ? 60 : 32; - break; - default : - // nothing to do - break; - } - break; - default : - // nothing to do - break; - } - - - - return additionalSpace; -}; - -/** - * Get empty DOM elements - * Return the first element in the DOM that doesn't - * have data associated with it in the dataList - */ -List2Ctrl.prototype._getEmptyDOMElement = function() -{ - var emptyItem = null; - var items = []; - - // get item indeces and sort them in ascending order - for (var i=0; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var itemIndex = Math.floor(relativeY / this.properties.itemHeight); - - // if we are in the active area but below the last item -> return -1 - if (itemIndex > this.dataList.itemCount - 1) - { - return -1; - } - - // constrain itemIndex to the max possible index - itemIndex = this.m.min(itemIndex, this.dataList.itemCount - 1); - - return itemIndex; -}; - -/** - * Get DOM Element by itemIndex - * Returns a DOM element (or null) for a particular - * item after performing a search for its item index - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {HTML Element} -
  • element - */ -List2Ctrl.prototype._getDOMItem = function(itemIndex) -{ - var domItem = null; - - for (var i=0, l=this.items.length; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var letterIndex = Math.floor(relativeY / this.properties.letterIndexHeight); - - // if we are in the active area but below the last letter index item -> return -1 - if (letterIndex > this.letterIndexData.length - 1) - { - return -1; - } - - // constrain letterIndex to the max possible index - letterIndex = this.m.min(letterIndex, this.letterIndexData.length - 1); - - return letterIndex; -}; - -/** - * Get Slider instance by itemIndex - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {SliderCtrl} - slider instance - */ -List2Ctrl.prototype._getSlider = function(itemIndex) -{ - var sliderCtrl = null; - - var index; - if (utility.toType(itemIndex) === 'number') - { - index = itemIndex; - } - else - { - index = this._getFocussedIndex(); - } - - var domElt = this._getDOMItem(index); - if (domElt) - { - var poolId = domElt.getAttribute('data-poolid'); - var hashKey = 'slider_'+index+'_'+poolId; - - // check whether a slider exists - if (this._sliders.hasOwnProperty(hashKey) && this._sliders[hashKey].slider) - { - sliderCtrl = this._sliders[hashKey].slider; - } - } - - return sliderCtrl; -}; - -/** - * Checks whether the supplied itemIndex contains a slider - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains a slider - */ -List2Ctrl.prototype._isSlider = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSlider = false; - - if (!isNaN(itemIndex)) - { - isSlider = ('style12' === this.dataList.items[itemIndex].itemStyle || 'style13' === this.dataList.items[itemIndex].itemStyle || 'style28' == this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSlider = ('style12' === itemIndex || 'style13' === itemIndex|| 'style28' === itemIndex); - } - - return isSlider; -}; - -/** - * Checks whether the supplied itemIndex is a lock item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a lock item - */ -List2Ctrl.prototype._isLock = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isLock = false; - - if (!isNaN(itemIndex)) - { - isLock = ('styleLock' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isLock = ('styleLock' === itemIndex); - } - - return isLock; -}; - -/** - * Checks whether the supplied itemIndex contains toggle buttons - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains toggle buttons - */ -List2Ctrl.prototype._isToggle = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isToggle = false; - - if (!isNaN(itemIndex)) - { - isToggle = ('style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle || 'draggable' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isToggle = ('style10' === itemIndex || 'style11' === itemIndex || 'draggable' === itemIndex); - } - - return isToggle; -}; - -/** - * Checks whether the supplied itemIndex is On/Off item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is On/Off - */ -List2Ctrl.prototype._isOnOff = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isOnOff = false; - - if (!isNaN(itemIndex)) - { - isOnOff = ('styleOnOff' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isOnOff = ('styleOnOff' === itemIndex); - } - - return isOnOff; -}; - -/** - * Checks whether the supplied itemIndex is a step item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a step item - */ -List2Ctrl.prototype._isStep = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isStep = false; - - if (!isNaN(itemIndex)) - { - isStep = ('styleStep' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isStep = ('styleStep' === itemIndex); - } - - return isStep; -}; - -/** - * Checks whether the supplied itemIndex is a checkbox - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a checkbox/tick/radio item - */ -List2Ctrl.prototype._isCheckBox = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isCheckbox = false; - - if (!isNaN(itemIndex)) - { - isCheckbox = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isCheckbox = ('style03' === itemIndex || 'style03a' === itemIndex); - } - - return isCheckbox; -}; - -/** - * Checks whether the supplied itemIndex is a simple select item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is simple select item - */ -List2Ctrl.prototype._isSimpleSelectItem = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSimpleSelect = false; - - if (!isNaN(itemIndex)) - { - isSimpleSelect = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle || 'styleOnOff' === this.dataList.items[itemIndex].itemStyle || 'style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSimpleSelect = ('styleOnOff' === itemIndex || 'style10' === itemIndex || 'style11' === itemIndex); - } - - return isSimpleSelect; -}; - -/** - * Checks whether the item contains _data property - * TAG: internal, helper - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item contains _data property - */ -List2Ctrl.prototype._hasData = function(itemIndex) -{ - var containsData = false; - if (this.dataList && this.dataList.items && this.dataList.items[itemIndex]) - { - containsData = this.dataList.items[itemIndex].hasOwnProperty('_data'); - } - return containsData; -}; - -/** - * Wraps inline text element if the width exceeds certain - * max width that depends on the item style. - * TAG: internal, helper - * ========================= - * @param {HTML Li Element} - the LI element that will be searched for overflowing text - * @return {HTML Li Element} - the modified LI element - */ -List2Ctrl.prototype._wrapInlineElement = function(li) -{ - var searchClass = null; - var maxWidth = 0; - - if (li.classList.contains('style17')) - { - searchClass = 'line1'; - maxWidth = this.properties.wrapTextThreshold; - } - else - { - return li; - } - - var line1 = li.getElementsByClassName(searchClass); - if (!line1 || 0 === line1.length) - { - return li; - } - else - { - line1 = line1[0]; - } - - if (line1.clientWidth > maxWidth) - { - line1.classList.add("wrap"); - } - else - { - line1.classList.remove("wrap"); - } - - return li; -}; - -/** - * Checks if the item can be displayed, even if it has no text field. - * TAG: internal, helper - * ===================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._displayWithoutText = function(item) -{ - var returnValue = true; - for(var i =0; i < this._itemsWithNoText.length; i++) - { - if(item.itemStyle === this._itemsWithNoText[i]) - { - returnValue = false; - break; - } - } - return returnValue; -}; - -/** - * Checks if the item is a slider with full hittable area - * TAG: internal, helper - * =================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._hasRightHittableArea = function(item) -{ - var returnValue = false; - - for(var i =0; i < this._rightHittableArea.length; i++) - { - if(item.itemStyle === this._rightHittableArea[i]) - { - returnValue = true; - break; - } - } - return returnValue; -}; - - -/** - * Show bounding boxes of some elements in the list. - * This should be used for debugging purposes only - * TAG: internal, utility - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype.showBoundingBoxes = function(state) -{ - if (state) - { - this.divElt.classList.add('showBoundingBoxes'); - } - else - { - this.divElt.classList.remove('showBoundingBoxes'); - } -}; - - -/** - * Searches an array for a value - * TAG: internal, utility - * ========================= - * @param {string|number} - * @param {array} - * @return {object} - copy of the source object - */ -List2Ctrl.prototype.inArray = function(needle, haystack) -{ - if (!needle || !haystack) - { - log.warn('Lis2: 2 arguments expected'); - return; - } - - for (var i=0, l=haystack.length; i b ? a : b // return the higher - : NaN; // else return NaN (just like the Math class) - }, - abs : function(a) - { - return (!isNaN(a)) ? // if the argument is a number - a < 0 ? -a : a // return the abs - : NaN; // else return NaN (just like the Math class) - } -}; - -/** - * Finish partial activity. - * @return {void} - */ -List2Ctrl.prototype.finishPartialActivity = function() -{ - // route finish partial activity to sub controls - - // tabs ctrl - if (this.tabsCtrl) - { - // delete the assigned callback reference so that it's not stored in the App's context table - delete this.properties.tabsButtonConfig.tiltStartCallback; - this.tabsCtrl.finishPartialActivity(); - } - - // slider - if (this._activeSlider && this._activeSlider.slider) - { - this._activeSlider.slider.finishPartialActivity(); - } - - // list -> exit any items in secondary MC mode - if (this._inSecondaryMulticontroller) - { - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this._isStep(smi)) - { - this._setSecondaryMulticontroller(false); - this._triggerFocus(); - } - } -}; - - -/** - * ========================= - * GARBAGE COLLECTION - * - Clear listeners - * - Clean up subcontrols - * - Clear timeouts - * TAG: framework - * ========================= - * @return {void} - */ -List2Ctrl.prototype.cleanUp = function() -{ - // remove event callbacks - this.divElt.removeEventListener(this._USER_EVENT_START, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - - // remove animation callbacks - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - if (this.scrollIndicator) - { - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - } - if (this.letterIndex) - { - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - } - - // clean up subcontrols - if (this.tabsCtrl) - { - this.tabsCtrl.cleanUp(); - } - for (var i in this._sliders) - { - this._sliders[i]['slider'].cleanUp(); - } - - // clear timeouts - clearTimeout(this._makeHitTimeoutId); - clearTimeout(this._longPressTimeoutId); - clearTimeout(this._touchReorderTimeoutId); - clearTimeout(this._scrollIndicatorTimeoutId); - clearTimeout(this._indexSelectTimeoutId); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - clearTimeout(this._needDataTimeoutId); - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - clearTimeout(this._radioSettleTimeoutId); - clearTimeout(this._tickSettleTimeoutId); - if (this.hasDataList()) - { - for (var i=0, l=this.dataList.items.length; i 0 || this.properties.scrollTo > 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 2)) ) - { - log.debug('Lis2: Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // set initial focus to a particular item if the list is populated - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem > 0) - { - log.debug('Lis2: Focus is not visible and has priority'); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // scroll (no animation) to a particular item if the list is populated - // the focus will be placed on the top item - else if (this.properties.scrollTo > 0) - { - log.debug('Lis2: Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this._topItem); - this._initialScrollMode = 'init'; - } - - // enter list reorder if the list is reordable - if (true === this.properties.listReorder) - { - this._enterListReorder(true); - } - - } - } - else - { - this._setLoading(true); - } - - - /* SET LETTER INDEX DATA */ - if (this.properties.hasLetterIndex && this.properties.letterIndexData) - { - // bind letter index data - this.setLetterIndexData(this.properties.letterIndexData); - } - - /* SET CUSTOM LIST BACKGROUND */ - if (null != this.properties.listBackground && '' != this.properties.listBackground) - { - this.setListBackground(this.properties.listBackground); - } - -}; - - -/** - * ========================= - * LIST ITEMS - * 1. pool (_createPool) - * 2. default items configuration (_prepareItems, _prepareListItem) for every item style - * 3. items localization (_localizeItems, _getLocalizedString) - * 4. pool operations (_setText, _setImage, _getListItem, _returnListItem, _putToScroller, _emptyScroller) - * 5. dynamic list items (_updateRange, _updateDisplay, _requestMore, _fill) - * 6. set internal properties (_checkScrollable, _setTopListItem, _setLoading) - * 7. default title configuration (_prepareTitle) - * ========================= - */ - -/** 1. POOL **/ - -/** - * Create list items pool - * Add HTML elements to each item in the pool - * depending on its style - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._createPool = function() -{ - this.pool = { - empty : new Array(), // 'empty' is internal style - draggable : new Array(), // 'draggable' is internal style - ghost : new Array(), // 'ghost' is internal style - - style01 : new Array(), - style02 : new Array(), - style03 : new Array(), - style03a : new Array(), - style04 : new Array(), - style05 : new Array(), - style06 : new Array(), - style07 : new Array(), - style09 : new Array(), - style10 : new Array(), - style11 : new Array(), - style12 : new Array(), - style13 : new Array(), // deprecated - style14 : new Array(), - style17 : new Array(), - style18 : new Array(), - style19 : new Array(), - style20 : new Array(), - style21 : new Array(), - style22 : new Array(), - // TODO: style23 - same as style12 - // TODO: style24 - same as style12 - style25 : new Array(), - styleOnOff : new Array(), // not official name - styleStep : new Array(), // TODO: rename this to style26 - styleLock : new Array(), // not official name - style28 : new Array(), - style29 : new Array(), - style38 : new Array() - }; - - // the pool size (this.properties.poolsize) should be at least 3 times - // the visible items (one for above and two for below the top item) - var line1, line2, - image1, image2, - label1, label2, - button1, button2, button3, - caret; - - for (var i in this.pool) - { - for (var j=0; j no content - break; - - case 'draggable' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - button1 = document.createElement('span'); - button1.className = 'button buttonOk'; - li.appendChild(button1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - break; - - case 'ghost' : - // ghost item -> no contet - break; - - case 'style01' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style02' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style04' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style05' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style06' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style07' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style09' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style10' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - break; - - case 'style11' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - button3 = document.createElement('span'); - button3.className = 'button button3'; - buttonsWrapper.appendChild(button3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style12' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style13' : - // style13 is deprecated - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style14' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style17' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - // label is inside line1 element to allow natural text flow - label1 = document.createElement('span'); - label1.className = 'label1'; - line1.appendChild(label1); - - break; - - case 'style18' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - break; - - case 'style19' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style20' : - button1 = document.createElement('span'); - button1.className = 'button1'; - li.appendChild(button1); - - break; - - case 'style21' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style22' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style25' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'styleOnOff' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'styleStep' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - var plusSign = document.createElement('span'); - plusSign.className = 'plus'; - li.appendChild(plusSign); - - var minusSign = document.createElement('span'); - minusSign.className = 'minus'; - li.appendChild(minusSign); - - break; - - case 'styleLock' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2 buttonLock'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3 buttonDelete'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style28' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style29' : - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - break; - - case 'style38' : - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - break; - - default : - log.error('List2: unknown list item style in pool: ' + i); - break; - - } - - // add common elements - caret = document.createElement('span'); - caret.className = 'caret'; - li.appendChild(caret); - - - this.pool[i].push(li); - } - } - -}; - -/** 2. DEFAULT ITEMS CONFIGURATION **/ - -/** - * Prepare items - * Extend the whole dataList so that every item - * meet the required structure. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._prepareItems = function(firstItem, lastItem) -{ - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) || (lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - for (var i=firstItem, l=lastItem; i<=l; i++) - { - this.dataList.items[i] = this._prepareListItem(this.dataList.items[i]); - } - -}; - -/** - * Prepare list item - * A list item can be defined with minimal set of properties - * that are needed for its proper display. In fact these - * properties extend the default list item structure defined below. - * This function sets default configuration for a valid list item and merge - * it with the custom configuration passed to the item. - * TAG: internal - * ========================= - * @param {object} - the list item that will be set a default set of properties and will be returned - * @return {object} - the complete list item - */ -List2Ctrl.prototype._prepareListItem = function(item) -{ - // The itemStyle property is required - if (!item.hasOwnProperty('itemStyle')) - { - log.error('List2: list item should have itemStyle property: ' + item); - return; - } - - /* - * All types of list items extend this - * default structure by overriding the - * values and adding specific ones. The - * extended structure is then returned to be - * fed in the dataList container. - */ - var completeItem = { - appData : null, // Any kind of data that will be passed in the callbacks - text1Id : null, // String ID of the label - text1SubMap : null, // String Sub Map of the label - text1 : '', // Textual content of the label - hasCaret : true, // Show the caret icon on the right of the item - disabled : false, // Whether the list item is disabled - styleMod : '', // Style modifier, 'hint', 'bold', or ''/omitted - disabledStyleMod: "normal", // Disabled style modifier, 'normal' or 'white' - background : 'normal', // Background modifier, 'normal' or 'grey' - itemStyle : '', // String indicating the list type - itemBehavior : 'shortPressOnly', // String "hold" behavior for the item ('shortPressOnly', 'shortAndHold', or 'shortAndLong') - vuiSelectable: true, // Boolean for some items that cannot be selected by vui even when they are enabled - _data : { // Object containing any item-specific data used ONLY by the control - eventTimeout : null, - lastEvent : null, - settleTimeout : null, - lastUpdated : null, - settleValue : null, - } - }; - - // extend the default structure with default specific properties - var specificItem = {}; - switch (item.itemStyle) - { - case 'empty' : - specificItem = { hasCaret : false }; - break; - case 'draggable' : - specificItem = { image1:'', button1Id:null, button1SubMap:null, button1:''}; - break; - case 'ghost' : - specificItem = {}; - break; - case 'style01' : - specificItem = { image1:'', indented:false }; - break; - case 'style02' : - specificItem = { image1:'', image2:'' }; - break; - case 'style03' : - specificItem = { image1:'', image2:'', image3:'', checked:false, indented:false }; - break; - case 'style03a' : - specificItem = { image1: '', label1Id: null, label1SubMap: null, label1: '', checked: false, labelWidth: 'wide2', label1Align:'right', styleMod: "hint"}; - break; - case 'style04' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style05' : - specificItem = { image1:'', image2:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style06' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', labelWidth:'normal', label1Align:'right', label1Warning:false }; - break; - case 'style07' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style09' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style10' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', value:1, indeterminate:false, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style11' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', button3Id:null, button3SubMap:null, button3:'', value:1, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style12' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime }; - break; - case 'style13' : - // deprecated - issue a warning - log.warn(this.uiaId + ': List2 style13 has been deprecated. Please use style12 instead. Setting pivot=True. Check SDD for details.'); - specificItem = { min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:true }; - break; - case 'style14' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', text1Align:'left' }; - break; - case 'style17' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'' }; - break; - case 'style18' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'' }; - break; - case 'style19' : - specificItem = { image1:'' }; - break; - case 'style20' : - // nothing specific for this style - break; - case 'style21' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style22' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', indented:false }; - case 'style25' : - specificItem = { image1:'', image2:'', image3:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'styleOnOff' : - specificItem = { image1:'', value:2, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'styleStep' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2:'', min:0, max:36, increment:1, value:0, warning:false }; - break; - case 'styleLock' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', locked:false }; - break; - case 'style28' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime, indented : false }; - break; - case 'style29' : - specificItem = { label1Id:null, label1SubMap:null, label1:'',label2Id:null, label2SubMap:null, label2:'', image1:'' }; - break; - case 'style38' : - specificItem = {image1:'' ,text1Id:null, text1SubMap:null, text1:'',label1SubMap:null, label1:'',label2Id:null, label2SubMap:null, label2:'' ,image2:''}; - break; - default : - log.error('List2: unknown item style: ' + item.itemStyle); - break; - } - - // Extend default structure with the specific one - for (var i in specificItem) - { - completeItem[i] = specificItem[i]; - } - - // Extend default structure with the supplied item - for (var j in item) - { - completeItem[j] = item[j]; - } - - return completeItem; -}; - - -List2Ctrl.prototype._updateModifiedTimestamps = function(firstItem, lastItem) -{ - // update lastModified timestamp - var now = new Date().getTime(); - for (var i=firstItem; i<=lastItem; i++) - { - if (this._hasData(i)) - { - this.dataList.items[i]._data.lastUpdated = now; - } - } -}; - - -/** 3. ITEMS LOCALIZATION **/ - -/** - * Localize items - * Localize text in known list items using localization framework. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._localizeItems = function(firstItem, lastItem) -{ - log.debug('Localizing...'); - - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) ||(lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - // iterate through the dataList - for (var i=firstItem, l=lastItem; i<=l; i++) - { - switch (this.dataList.items[i].itemStyle) - { - // no elements - case 'empty' : - // do nothing - break; - - // text1, button1 - case 'draggable' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - //label1 and label2 only supports for style38 for reorderList - if(this._reorderItem.itemStyle === "style38") - { - if (this.dataList.items[i].laebl1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].laebl1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].laebl2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].laebl2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - break; - - // no elements - case 'ghost' : - // do nothing - break; - - // text1 - case 'style01' : - case 'style02' : - case 'style03' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - case 'style03a' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style04' : - case 'style05' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1, label1 - case 'style06' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style07' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, text2, label1, label2 - case 'style09' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, button1, button2 - case 'style10' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - break; - - // text1, button1, button2, button3 - case 'style11' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - if (this.dataList.items[i].button3Id) - { - var button3 = this._getLocalizedString(this.dataList.items[i].button3Id, this.dataList.items[i].button3SubMap); - this.dataList.items[i].button3 = button3; - } - break; - - // text1, labelLeft, labelRight - case 'style12' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, labelLeft, labelCenter, labelRight - case 'style13' : - // style13 is deprecated - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1 - case 'style14' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style17' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style18' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1 - case 'style19' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1 - case 'style20' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, text2, label1 - case 'style21' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style22' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style25' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1 - case 'styleOnOff' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1, label2 - case 'styleStep' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label2 = label2; - } - else - { - log.warn(this.uiaId + ' possible issue. Lis2: item ' + i + ' does not specify label2Id'); - } - break; - - // text1, text2 - case 'styleLock' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - case 'style29' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - - case 'style38' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label2 = label2; - } - break; - - } - - } -}; - -/** - * Get localization entry for a string id - * TAG: internal - * ========================= - * @return {string} - */ -List2Ctrl.prototype._getLocalizedString = function(labelId, subMap) -{ - return framework.localize.getLocStr(this.uiaId, labelId, subMap); -}; - -/** 4. POOL OPERATIONS **/ - -/** - * Set line 1 content - * This helper function clears any previous content for the supplied - * element class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - textual content to be inserted - * @param {boolean} - do not remove child html tags when inserting textual content - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setText = function(li, className, content, preserveHTML) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - if (!content) - { - content = ''; - } - li.querySelector(className).innerText = ''; - li.querySelector(className).appendChild(document.createTextNode(content)); - return li; -}; - -/** - * Set image background - * This helper function clears any previous path for the supplied - * image class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - path to the image - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setImage = function(li, className, url) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - li.querySelector(className).style.backgroundImage = ''; - if ('' != url) - { - li.querySelector(className).style.backgroundImage = 'url(' + url + ')'; - } - return li; -}; - -/** - * Set slider - * This helper function clears any previous slider in the list item - * and cleans up local references. It then creates a new slider control - * inside the list item and sets its values - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setSlider = function(li, className, sliderProperties, itemIndex) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - - // get current item poolid - var poolId = li.getAttribute('data-poolid'); - - // get previous itemIndex for this particular li - var prevItemIndex = li.getAttribute('data-ref'); - - // destruct any previous sliders for this poolid and previous index - if (prevItemIndex != 'undefined') - { - var hashKey = 'slider_'+prevItemIndex+'_'+poolId; - - // remove slider from the hash and the DOM - if (this._sliders.hasOwnProperty(hashKey)) - { - this._sliders[hashKey]['slider'].cleanUp(); - this._sliders[hashKey]['slider'].divElt.parentElement.removeChild(this._sliders[hashKey]['slider'].divElt); - } - } - - // add slider to the hash and the DOM - var sliderCont = li.querySelector(className); - if (sliderProperties && sliderCont) - { - var hashKey = 'slider_'+itemIndex+'_'+poolId; - - // instantiate slider and add it to the _sliders hash - this._sliders[hashKey] = {}; - this._sliders[hashKey]['itemIndex'] = itemIndex; - this._sliders[hashKey]['poolId'] = poolId; - this._sliders[hashKey]['slider'] = framework.instantiateControl(this.uiaId, sliderCont, 'SliderCtrl', sliderProperties); - } - return li; -}; - -/** - * Set toggle - * This helper function clears any previous toggled buttons in - * the supplied list item and sets initial toggle value - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setToggle = function(li, className, value) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - var buttons = li.querySelectorAll(className); - for (var i=0; i element wit proper elements inside - */ -List2Ctrl.prototype._getListItem = function(listItem, dataListIndex) -{ - - // get it from the pool - var li = this.pool[listItem.itemStyle].shift(); - - // remove any residual touch classes - li.classList.remove('hit'); - li.classList.remove('focus'); - li.classList.remove('longpress'); - li.classList.remove('secondaryFocus'); - - // add content to it following style definitions - switch (listItem.itemStyle) - { - case 'empty' : - // empty item -> no content - break; - - case 'draggable' : - // listItem : { text1:String, image1:String, button1:String } - this._setText(li, '.line1', listItem.text1); - if(this._reorderItem.itemStyle === "style38" ) - { - //For style 38 line1 width should be shorter as compare the other style. - li.querySelector(".line1").classList.add('shortText') - } - - //label1 and label2 only supports for style38 for reorderList - if(this._reorderItem.itemStyle === "style38" ) - { - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - } - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.buttonOk', listItem.button1); - break; - - case 'ghost' : - // list item : {} - break; - - case 'style01' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style02' : - // listItem : { text1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.image2 === 'indeterminate') - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - this._setImage(li, '.image2', listItem.image2); - } - break; - - case 'style03' : - // listItem : { text1:String, image1:String, image2:String, checked:Boolean } - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style03a' : - // listItem : { text1:String, image1:String, label1: String} - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - this._setText(li, '.label1', listItem.label1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style04' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style05' : - // listItem : { text1:String, text2:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - break; - - case 'style06' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style07' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style09' : - // listItem : { text1:String, text2:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style10' : - // listItem : { text1:String, button1:String, button2:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 2), 0) ); - if (listItem.indeterminate) - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - } - break; - - case 'style11' : - // listItem : { text1:String, button1:String, button2:String, button3:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setText(li, '.button3', listItem.button3); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 3), 0) ); - break; - - case 'style12' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style13' : - // TODO: style13 has been depricated - // listItem : { text1:String, labelLeft:String, labelCenter:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: this.properties.minChangeInterval, - settleTime: this.properties.settleTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style14' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - if ('right' == listItem.text1Align) - { - li.classList.add('text1AlignRight'); - } - else - { - li.classList.remove('text1AlignRight'); - } - - break; - - case 'style17' : - // listItem : { text1:String, label1:String, image1:String } - li.querySelector('.line1').innerText = ''; - var label1 = document.createElement('span'); - label1.className = 'label1'; - label1.appendChild(document.createTextNode(listItem.label1)); - li.querySelector('.line1').appendChild(label1); - li.querySelector('.line1').appendChild(document.createTextNode(listItem.text1)); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style18' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style19' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style20' : - // listItem : { text1:String } - this._setText(li, '.button1', listItem.text1); - break; - - case 'style21' : - // listItem : { text1:String, text2:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style22' : - // listItem : { text1:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style25' : - // listItem : { text1:String, text2:String, image1:String, image2:String, image3:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - break; - - case 'styleOnOff' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.value === 1) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - break; - - case 'styleStep' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - li.classList.remove('maxReached'); - li.classList.remove('minReached'); - if (listItem.value === listItem.max) - { - li.classList.add('maxReached'); - } - else if (listItem.value === listItem.min) - { - li.classList.add('minReached'); - } - - // configure label warning - if (listItem.warning) - li.classList.add('warning'); - else - li.classList.remove('warning'); - - break; - - case 'styleLock' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - if (listItem.locked) - { - li.classList.add('locked'); - } - else - { - li.classList.remove('locked'); - } - break; - - case 'style28' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setImage(li, '.image1', listItem.image1); - - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - - - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style29': - - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style38': - - if(listItem.text1) - { - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image2', listItem.image2); - } - else - { - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.line1', ""); - this._setText(li, '.label1', ""); - this._setText(li, '.label2', ""); - this._setImage(li, '.image2', listItem.image2); - - } - break; - } - - /* ITEM MODIFICATORS */ - // add/remove hasCaret class - if (listItem.hasCaret) - { - li.classList.add('hasCaret'); - } - else - { - li.classList.remove('hasCaret'); - } - - // add/remove disabled class - if (listItem.disabled) - { - li.classList.add('disabled'); - } - else - { - li.classList.remove('disabled'); - } - - // add/remove styleMod class (hint/bold/'') - if ('hint' == listItem.styleMod) - { - li.classList.remove('bold'); - li.classList.add('hint'); - } - else if ('bold' == listItem.styleMod) - { - li.classList.remove('hint'); - li.classList.add('bold'); - } - else if ('both' == listItem.styleMod) - { - li.classList.add('hint'); - li.classList.add('bold'); - } - else - { - li.classList.remove('hint'); - li.classList.remove('bold'); - } - - // add/remove background modifier class (normal/grey) - if ('grey' == listItem.background) - { - li.classList.remove('bgLightGrey'); - li.classList.add('bgGrey'); - } - else if('lightGrey' == listItem.background) - { - li.classList.remove('bgGrey'); - li.classList.add('bgLightGrey'); - } - else - { - li.classList.remove('bgLightGrey'); - li.classList.remove('bgGrey'); - } - - // add disabled style mod - if ('white' === listItem.disabledStyleMod) - { - li.classList.add("disabledWhite"); - } - - // return it - return li; - -}; - -/** - * Return list item to the pool - * This will result in increasing the pool contents - * with one item. The returned item will be removed from the DOM. - * However, its content will not be reset as this is done in the - * process of any subsequent pool extraction (see _getListItem() above) - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @return {void} - */ -List2Ctrl.prototype._returnListItem = function(li) -{ - // get the style - var itemStyle = li.getAttribute('data-itemStyle'); - // reset it - li.style.top = '0px'; - // remove it - li.parentNode.removeChild(li); - - // put it back to the pool - this.pool[itemStyle].push(li); -}; - -/** - * Put a list item to the scroller - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._putToScroller = function(li, index, operation) -{ - li.style.top = index * this.properties.itemHeight + 'px'; - li.setAttribute('data-ref', index); - - - if (operation == 'prepend') - { - this.items.unshift({ref:index, domElt:li}); - this.scroller.insertBefore(li, this.scroller.firstChild); - - this._wrapInlineElement(li); - } - else if (operation == 'append') - { - this.items.push({ref:index, domElt:li}); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else if (!isNaN(operation)) - { - this.items.splice(operation, 0, {ref:index, domElt:li}); - - // insertBefore breaks in Opera - use appendChild instead - // this.scroller.insertBefore(li, this.items[operation+1]); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else - { - log.error('Lis2: unknown _putToScroller() operation: ' + li + ' ' + index + ' ' + operation); - } - -}; - -/** - * Return everything into the pool and empty the scroller - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._emptyScroller = function() -{ - for (var i=0, l=this.items.length; i itemsOnScreen) - { - // return everything into the pool - var itemsLength = this.items.length; - for (var i=0; i < itemsLength; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - var dataListIndex = 0; - - if (topItem < this.dataList.items.length - Math.round(itemsOnScreen / 2) && - topItem > Math.round((itemsOnScreen / 2)) ) - { - - - // WE ARE IN THE MIDDLE - - for (var i=0; i < itemsLength; i++) - { - dataListIndex = (topItem - itemsBefore) + i; - - // we've reached the end of the dataList. No more items to add -> break - if (dataListIndex >= this.dataList.items.length) - { - break; - } - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'middle'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else - { - - if (numOfScrolledElements > 0) - { - - // PRESSED END BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = (this.dataList.items.length - itemsLength) + i; - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'down'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else if (numOfScrolledElements < 0) - { - - // PRESSED HOME BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = i; - - - // request it if it is empty - if (this.dataList.items[dataListIndex].itemStyle === 'empty' || (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex]))) - { - this._requestMore(dataListIndex, 'down'); - log.debug('Requesting items ' + dataListIndex); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - - } - - } - - } - - - } - else - { - - - - if (numOfScrolledElements > 0) - { - - /* SCROLL DOWN BOF */ - - // return to pool - var firstItemRef = this.items[0].ref; - var bottomDifference = topItem - firstItemRef; - var extraEls = bottomDifference - itemsBefore; - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Down - extraEls ' + extraEls); - - if (extraEls > 0) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - } - - // lastItemRef = this.items[this.items.length-1].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var topDifference = this.items[this.items.length-1].ref - ( topItem - 1 ); - var newEls = ( itemsAfter + 1 ) - topDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Down - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i break - log.debug('end of list'); - break; - } - - } - - } - - /* SCROLL DOWN EOF */ - - } - else if (numOfScrolledElements < 0) - { - - /* SCROLL UP BOF */ - - // return to pool - var topDifference = this.items[this.items.length-1].ref - topItem + 1; - var extraEls = topDifference - ( itemsAfter + 1 ); - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Up - extraEls ' + extraEls); - - if ( extraEls > 0 ) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.pop(); - this._returnListItem(item.domElt); - } - - } - - - // firstItemRef = this.items[0].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var bottomDifference = topItem - this.items[0].ref; - var newEls = itemsBefore - bottomDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Up - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i= 0) - { - - // if empty item is encountered, request more data - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'up'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'prepend'); - - } - else - { - // we've reached the beginning of the dataList array => break - log.debug('beginning of list'); - break; - } - - } // for - - } - else - { - log.debug('no new elements'); - } - - /* SCROLL UP EOF */ - - } - else - { - // there's no scroll => do nothing - } - - - - } // closes if (this.m.abs(numOfScrolledElements) > itemsOnScreen) - -}; - - -/** - * Redraw updated items that are currently visible - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._updateDisplay = function(firstItem, lastItem) -{ - - var firstItemRef = this.items[0].ref; - var lastItemRef = this.items[this.items.length-1].ref; - - // update only when the updated items overlap with the visible items - if ( (firstItem >= firstItemRef && firstItem <= lastItemRef) || - (firstItem <= firstItemRef && lastItem >= firstItemRef) ) - { - - var firstToUpdate = this.m.max(firstItem, firstItemRef); - var lastToUpdate = this.m.min(lastItem, lastItemRef); - var firstToUpdateIndex = firstToUpdate - firstItemRef; - var lastToUpdateIndex = (lastToUpdate - firstToUpdate) + firstToUpdateIndex; - - for (var i=firstToUpdateIndex; i<=lastToUpdateIndex; i++ ) - { - - var returnItem = this.items.splice(i,1); - var dataListIndex = returnItem[0].ref; - - // return to pool - this._returnListItem(returnItem[0].domElt); - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // recover secondary focus - if (this._inSecondaryMulticontroller && this._currentSecondaryMulticontrollerItem === dataListIndex) - { - li.classList.add('focus'); - li.classList.add('secondaryFocus'); - } - - // put it to scroller - this._putToScroller(li, dataListIndex, i); - - } - - } - - // update _isScrollable flag - this._checkScrollable(); - -}; - -/** - * Request more list items - * TAG: internal - * ========================= - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._requestMore = function(index, direction) -{ - - // do not request more if a previous request is pending - if (!this._inLoading) - { - if(this._appIsAtSpeed) - { - return; // do not do anything if the list gets this._appIsAtSpeed - } - else - { - // indicate loading is in progress - this._setLoading(true); - - if (direction == 'up') - { - // we add 1 to the requestSize to include the last element in the way up - index = this.m.max(index - this.properties.requestSize + 1, 0); - - } - else if (direction == 'middle') - { - // we request 25 items on each direction from the topItem - index = this.m.max(index, 0); - - } - - // build additional data - var additionalParams = { - topItem : this._topItem, - visibleItems : this.properties.visibleItems, - ranges : this.getEmptyRange(), - }; - - log.debug('Request items from ' + index + ' to ' + index+this.properties.requestSize + ' ' + direction); - - // call needDataCallback if it is defined. The first empty item is - if (typeof this.properties.needDataCallback == 'function') - { - this.properties.needDataCallback(index, additionalParams); - } - - // set timeout for data population - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = setTimeout(this._needDataTimeoutCallback.bind(this, index), this.properties.needDataTimeout); - } - } - -}; - -List2Ctrl.prototype._needDataTimeoutCallback = function(index) -{ - log.warn('Lis2: control has requested items from index ' + index + ' but has not receieved them yet. Enabling the list.'); - this._setLoading(false); -}; - -/** - * Initial pool operation - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._fill = function(firstItem, lastItem) -{ - - log.debug('Start pool operation'); - log.debug('POOL | ITEMS'); - - // get items from the pool - for (var i=firstItem; i<=lastItem; i++) - { - // get it from the pool - var li = this._getListItem(this.dataList.items[i], i); - - // put it to scroller - this._putToScroller(li, i, 'append'); - - log.debug(this.pool[this.dataList.items[i].itemStyle].length + ' -> ' + this.items.length); - } - - this._hasFill = true; - - // update _isScrollable flag - var scrollable = this._checkScrollable(); - - // show/hide scroll indicator - if (!scrollable || (scrollable && this.properties.hasLetterIndex)) - { - this._hideScrollIndicator(); - } - else - { - this._showScrollIndicator(); - } - - log.debug('End pool operation'); - -}; - -/** SET INTERNAL PROPERTIES **/ - -/** - * Update _isScrollable flag - * TAG: internal - * ========================= - * @return {boolean} - returns _isScrollable - */ -List2Ctrl.prototype._checkScrollable = function() -{ - if (this.dataList.items.length > this.properties.visibleItems) - { - this._isScrollable = true; - } - else - { - this._isScrollable = false; - } - - return this._isScrollable; -}; - -/** - * Update _topItem property - * TAG: internal - * ========================= - * @param {integer} - top item index - * @return {integer} - returns _topItem - */ -List2Ctrl.prototype._setTopListItem = function(pos) -{ - // pos should be number for proper topItem calculation - if (!isNaN(pos)) - { - this._prevTopItem = this._topItem; - this._topItem = -(Math.round(pos / this.properties.itemHeight)); - - // throw out of bounds exception - if (this._topItem < 0 || this._topItem > this.dataList.items.length - 1) - { - log.error('Lis2: _topItem is out of bounds'); - } - } - - if (this.properties.enableItemRequestOnScroll) - { - // check for empty items in DOM - var emptyDOMItem = this._getEmptyDOMElement(); - if (null != emptyDOMItem) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - } - } - - return this._topItem; - -}; - -/** - * Indicate loading activity in the list - * and update _inLoading property - * TAG: internal - * ========================= - * @param {boolean} - show or hide loading activity - * @return {boolean} - returns _inLoading - */ -List2Ctrl.prototype._setLoading = function(show) -{ - if (show) - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - // update start time - this._loadingData.timeStarted = new Date().getTime(); - - if (this.properties.showLoadingOverlayTimeout > 0) - { - // delayed show overlay - this._loadingData.startTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, true), this.properties.showLoadingOverlayTimeout); - } - else - { - // show overlay immediately - this._setLoadingOverlay(true); - } - } - - // update flag - this._inLoading = true; - } - else - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - if (this.properties.hideLoadingOverlayTimeout > 0) - { - // delayed hide overlay - var now = new Date().getTime(); - if (now - this._loadingData.timeStarted < this.properties.showLoadingOverlayTimeout) - { - // no overlay has been shown -> reset everything - this._setLoadingOverlay(false); - } - else if (now - this._loadingData.timeShown < this.properties.hideLoadingOverlayTimeout) - { - // the overlay has been visible less than the hideLoadingOverlayTimeout -> hide it in hideLoadingOverlayTimeout ms after it has been made visible - this._loadingData.endTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, false), this.properties.hideLoadingOverlayTimeout - (now - this._loadingData.timeShown)); - } - else - { - // the overlay has been visible long enough -> hide it immediately - this._setLoadingOverlay(false); - } - } - else - { - // hide overlay immediately - this._setLoadingOverlay(false); - } - } - - // update flag - this._inLoading = false; - } - - return this._inLoading; -}; - -List2Ctrl.prototype._setLoadingOverlay = function(show) -{ - if (show) - { - // show loading - this.mask.appendChild(this.loading); - - this._loadingData.timeShown = new Date().getTime(); - } - else - { - // hide loading - if (null != this.loading.parentElement) - { - this.loading.parentElement.removeChild(this.loading); - } - - // reset loading data - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - this._loadingData.timeStarted = 0; - this._loadingData.timeShown = 0; - this._loadingData.startTimeoutId = null; - this._loadingData.endTimeoutId = null; - } -}; - -/** 7. DEFAULT TITLE CONFIGURATION **/ - -/** - * Prepare title - * A list title can be defined with minimal set of properties - * that are needed for its proper display. This function sets - * default configuration for a valid title and merge it with the - * custom configuration passed to the title. - * TAG: internal - * ========================= - * @param {object} - the title object that will be set a default set of properties and will be returned - * @return {object} - the complete title object - */ -List2Ctrl.prototype._prepareTitle = function(titleObj) -{ - // The itemStyle property is required - if (!titleObj.hasOwnProperty('titleStyle')) - { - log.error('Lis2: title should have titleStyle property: ' + titleObj); - return; - } - - // default properties - var title = {}; - switch (titleObj.titleStyle) - { - case 'style02' : - title = { text1:'', text1Id:null, text1SubMap:null, styleMod:'' }; - break; - case 'style02a' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - case 'style03' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'' }; - break; - case 'style05' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null, image1:'' }; - break; - case 'style06' : - title = { image1:'' }; - break; - case 'style07' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null }; - break; - case 'style08' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - default : - log.error('Lis2: unknown title style: ' + titleObj.titleStyle); - break; - } - - // Extend default structure with the supplied item - for (var i in titleObj) - { - title[i] = titleObj[i]; - } - - // Perform localization - switch (title.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style08' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - break; - case 'style05' : - case 'style07' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - if (title.text2Id) - { - title.text2 = this._getLocalizedString(title.text2Id, title.text2SubMap); - } - break; - } - - return title; -}; - - -/** - * ========================= - * SCROLL INDICATOR - * - reset - * - create - * - visual update - * ========================= - */ - -/** - * Remove any scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorReset = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // remove any scroll indicator - if (this.scrollIndicatorWrapper) - { - // remove wrapper (and scroll indicator) - this.scrollIndicatorWrapper.parentElement.removeChild(this.scrollIndicatorWrapper); - - // nullify elements - this.scrollIndicatorWrapper = null; - this.scrollIndicator = null; - - // reset scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = 0; - } -}; - -/** - * Create scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorBuild = function(visible) -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator size - var indicatorSize = Math.round(this.mask.offsetHeight * (this.mask.offsetHeight / this.scroller.offsetHeight)); - - // add scroll indicator wrapper - this.scrollIndicatorWrapper = document.createElement('div'); - this.scrollIndicatorWrapper.className = 'List2CtrlScrollIndicatorWrapper'; - this.divElt.appendChild(this.scrollIndicatorWrapper); - - // add scroll indicator - this.scrollIndicator = document.createElement('div'); - this.scrollIndicator.className = 'List2CtrlScrollIndicator'; - if(!visible) - { - this.scrollIndicatorWrapper.style.visibility = 'hidden'; - } - else - { - this.scrollIndicatorWrapper.style.visibility = 'visible'; - } - this.scrollIndicator.style.height = this.m.max(indicatorSize, this.properties.scrollIndicatorMinSize) + 'px'; - this.scrollIndicator.style.top = '0px'; - this.scrollIndicatorWrapper.appendChild(this.scrollIndicator); - - // set scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = this.mask.offsetHeight - this.scrollIndicator.offsetHeight; - - if (this.properties.hasLetterIndex) - { - // hide scroll indicator when letterIndex is enabled - this._hideScrollIndicator(); - } - else - { - // fade out scroll indicator - this._fadeOutScrollIndicator(); - } -}; - -/** - * Update scroll indicator position on drag - * This is fired on _USER_EVENT_MOVE when the - * list is being dragged by touch. - * TAG: touch-only, internal - * ========================= - * @return {integer} scroll indicator position - */ -List2Ctrl.prototype._dragUpdateScrollIndicator = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator position - var indicatorPos = Math.round(this._indicatorMax * (this.scroller.offsetTop / this._maxScrollY)); - - // constrain position - indicatorPos = this.m.max(indicatorPos, this._indicatorMin); - - // set new position - this.scrollIndicator.style.top = indicatorPos + 'px'; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return indicatorPos; -}; - -/** - * Update scroll indicator position on drag - * Called on scroll animation (flick or scroll ad-hoc) - * TAG: internal - * ========================= - * @param {integer} the new position of the scroller - * @param {integer} the time for animation to the new position - * @return {integer} the new scroll indicator position - */ -List2Ctrl.prototype._updateScrollIndicator = function(pos, time) -{ - // check for time - if (time == undefined || time == null) - { - // get default time - time = this.properties.swipeAnimationDuration; - } - - // determine scroll indicator new position - var newRelativePos = pos / this._maxScrollY; - var newPos = Math.round(newRelativePos * (this._indicatorMax - this._indicatorMin)); - - // start animation - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollIndicatorAnimationEndCallback = this._scrollIndicatorAnimationEnd.bind(this); - this.scrollIndicator.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicator.style.top = newPos + 'px'; - - // clear any previously scheduled scroll indicator fade out - clearTimeout(this._scrollIndicatorTimeoutId); - this._scrollIndicatorTimeoutId = null; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return newPos; - -}; - - -List2Ctrl.prototype._fadeInScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeInDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -List2Ctrl.prototype._fadeOutScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - // clear any previously-scheduled hiding - clearTimeout(this._scrollIndicatorTimeoutId); - - // schedule hide - this._scrollIndicatorTimeoutId = setTimeout(function() { - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeOutDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 0; - this._scrollIndicatorTimeoutId = null; - }.bind(this), this.properties.scrollIndicatorFadeTimeout); -}; - -List2Ctrl.prototype._hideScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 0; -}; - -List2Ctrl.prototype._showScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -/** - * ========================= - * TOUCH EVENT HANDLERS - * - Event detection and custom event dispatching - * - Start/Move/End/Out event handling - * - Hit state control - * ========================= - */ - -/** - * Handle any touch event and dispatch appropriate - * custom event. Actual event processing is done in the - * respective handlers of the custom events. The original - * event object is attached to the custom event in its - * event property. - * ========================= - * @param {event} - any touch event - * @return {Boolean} - True if event was processed - */ -List2Ctrl.prototype._touch = function(e) -{ - var touchResult = false; - - switch(e.type) - { - case this._USER_EVENT_START : - // route to letter index first, otherwise route to list - touchResult = this._startIndex(e) || this._start(e); - /* - * Attach temporary listeners to document if we have a positive start. - * These listeners will be removed on _USER_EVENT_END - */ - if (touchResult) - { - document.addEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - } - break; - - case this._USER_EVENT_MOVE : - // route to letter index first, otherwise route to list - touchResult = this._moveIndex(e) || this._move(e); - break; - - case this._USER_EVENT_END : - /* - * Remove the document event listeners no matter of these have been - * attached or not. This will prevent any non-existent callbacks firing. - */ - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - // route to letter index first, otherwise route to list - touchResult = this._endIndex(e) || this._end(e); - break; - - case this._USER_EVENT_OUT : - this._out(e); - break; - } - - return touchResult; -}; - -/** - * Start Touch on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._start = function(e) -{ - // abort any ongoing scroll - this._abortScroll(e); - - // get mask position and dimensions - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - this._maskH = this.mask.offsetHeight; - this._maskW = this.mask.offsetWidth; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - // reset letter index multicontroller - this._focusStolen = false; - if (relativeY >= 0) - { - this._setLetterIndexMulticontroller(false, true); - - // steal focus - var canGainFocus = this._canGainFocus(e); - if (!this._hasFocus && -1 !== canGainFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - this._focusStolen = true; - } - } - - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by start reorder rather than regular start - this._startReorder(e); - return true; - } - else if(!this._inListReorder && this._appIsAtSpeed) - { - this._startReorder(e); - return true; - } - - this._startItem = this._getTargetItem(e); - this._startDOMItem = this._getDOMItem(this._startItem); - - // make hit - if (this.properties.hitTimeout > 0) - { - // after some time - this._makeHitTimeoutId = setTimeout(this._itemMakeHit.bind(this, e), this.properties.hitTimeout); - } - else - { - // immediately - this._itemMakeHit(e); - } - - // Place focus on the reported available item when focus is stolen - if (this._focusStolen) - { - this._showFocus(canGainFocus, true); - } - - // make toggles hit - this._buttonMakeHit(e); - - // make locks hit - this._lockMakeHit(e); - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return false; - } - - // check relative mouse position - if (relativeY < 0) - { - return false; - } - - // check for a valid target item - if (this._startItem == -1) - { - return false; - } - - // get current y - this._y = this.scroller.offsetTop; - this._startY = relativeY; - this._startX = relativeX; - this._startTime = new Date().getTime(); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, e), this.properties.longPressTimeout); - - // raise _inDrag - this._inDrag = true; - - // Release secondary MC mode - if (this._inSecondaryMulticontroller && null != this._currentSecondaryMulticontrollerItem && this._startItem != this._currentSecondaryMulticontrollerItem) - { - var temp = this._currentSecondaryMulticontrollerItem; - - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - - // Commit the value - if (!this._isLock(temp)) // locks do not commit the value - { - this._triggerFocus(temp); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(temp, 'clear'); - } - } - - // dispatch scroll start event - this._listEvent(this._EVENTS.SCROLL_START, {scrollPosition:this._topItem}); - - // user touched the list -> return True - return true; - -}; - -/** - * Touch move on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._move = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by move reorder rather than regular move - this._moveReorder(e); - return true; - } - - if (!this._inDrag) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._end(e); - return true; - } - - // calculate travelled distance - var deltaY = relativeY - this._startY; - var deltaX = relativeX - this._startX; - - if (this._inLongPress) - { - return false; - } - - /* - * DRAG DETECTION - * determine whether this is a horizontal or vertical drag - * and raise the horizontal flag - */ - if (null == this._inHorizontalDrag) { - - var alpha = Math.atan2(this.m.abs(deltaX), this.m.abs(deltaY)); - if (alpha < this.properties.hvThreshold) - { - // vertical - this._inHorizontalDrag = false; - } - else - { - // horizontal - this._inHorizontalDrag = true; - this._hDragItem = this._getTargetItem(e); - - // set slideStart - this._slideStart(e); - } - } - - // drag slider - if (this._inHorizontalDrag == true) - { - // we have a horizontal drag -> move sliders - this._slideMove(e); - } - // drag list if scrollable - else if (false == this._inHorizontalDrag && this._isScrollable) - { - // we have a vertical drag and the list can be scrolled - // calculate the scroller's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollY, this.m.min(this._y + deltaY, this._minScrollY)); - - // drag the scroller if in bounds - this.scroller.style.top = newPos + 'px'; - - // update scroll indicator - this._dragUpdateScrollIndicator(); - - // raise _stopClick flag and remove hit and long press - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit and prevent delayed hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); - - // remove long press and prevent long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); - } - } - // control hit state when not scrollable or when no scrolling occurs (e.g. when we are one of the list extremities) - if (!this._isScrollable || this.m.abs(deltaY) > this.properties.selectThreshold) - { - var targetTop = this._startDOMItem.offsetTop; - if (relativeY < targetTop || relativeY > targetTop + this.properties.itemHeight) - { - // remove hit - this._itemRemoveHit(e); - - // prevent select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = true; - } - } - else - { - // make hit - if (this._stopSelect && !this._isScrollable) - { - this._itemMakeHit(e); - } - - // enable select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = false; - } - } - } - - // user touched the list -> return True - return true; -}; - -/** - * Touch end on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._end = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by end reorder rather than regular end - this._endReorder(e); - return true; - } - else if(!this._inListReorder && this._appIsAtSpeed) - { - this._endReorder(e); - return true; - } - - - // remove hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); // clear hit timeout - // remove long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - this._startItem = null; - this._startDOMItem = null; - - // reset drag flag and hDrag item - this._inHorizontalDrag = null; - this._hDragItem = null; - - if (!this._inDrag) - { - // this is called without having a drag - return false; - } - - // end any drag of sliders - this._slideEnd(e); - - // set scroll nature - this._scrollNature = 'touch'; - - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTime; - if (this._focusStolen && !this._stopSelect) - { - // slight drag -> scroll to show focus on the available item when stealing focus - // decide whether to allow offscrean - var focussedIndex = this._getFocussedIndex(); - var allowOffScreen = (focussedIndex > this._topItem && focussedIndex < this._topItem + this.properties.visibleItems); - this._showFocus(focussedIndex, allowOffScreen); - this._focusStolen = false; - } - else if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startY; - - // swipte detected - this._startSwipe(deltaY, velocity); - } - else - { - // regular drag -> snap to item bounds - this._snap(this.scroller.offsetTop); - } - - // call touch select logic - this._touchSelectItem(e); - - // reset any previously set flags - this._inDrag = false; - this._stopSelect = false; - this._startTime = 0; - - // user touched the list -> return True - return true; -}; - -/** - * Touch leave on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._out = function(e) -{ - return this._end(e); -}; - - -/** - * Start Touch on letter index - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {boolean} - True if letter index is touched - */ -List2Ctrl.prototype._startIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // get mask position - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - if (relativeY < 0) - { - return false; - } - - // hit test letter index - if (relativeX <= this.letterIndexWrapper.offsetLeft) - { - return false; - } - - // steal focus - if (!this._hasFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - } - - // Enter into letter index multicontroller mode if not already - if (!this._inLetterIndexMulticontroller) - { - this._setLetterIndexMulticontroller(true); - } - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - - // make hit - this._indexMakeHit(e); - - // get start coordinates and time - this._yIndex = this.letterIndex.offsetTop; - this._startIndexY = relativeY; - this._startIndexX = relativeX; - this._startTimeIndex = new Date().getTime(); - - this._inDragIndex = true; - - return true; - -}; - - -List2Ctrl.prototype._moveIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - if (!this._inDragIndex) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._endIndex(e); - - return false; - } - - // calculate travelled distance - var deltaY = relativeY - this._startIndexY; - var deltaX = relativeX - this._startIndexX; - - // calculate the letter index's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollYIndex, this.m.min(this._yIndex + deltaY, this._minScrollYIndex)); - - // drag the letter index if in bounds - this.letterIndex.style.top = newPos + 'px'; - - // raise _stopClick flag - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit - this._indexRemoveHit(e); - } - - return true; - -}; - - -List2Ctrl.prototype._endIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // remove hit - this._indexRemoveHit(e); - - if (!this._inDragIndex) - { - return false; - } - - if (!this._stopSelect) - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // select letter index - var letterIndex = this._getTargetLetterIndex(e); - this._letterIndexSelect(letterIndex, 'Touch'); - } - else - { - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTimeIndex; - if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startIndexY; - - // swipte detected - this._startSwipeIndex(deltaY, velocity); - } - else - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // schedule letter index select if letter is enabled - var letterIndex = this._getTargetLetterIndex(e); - if (!this.letterIndexData[letterIndex].disabled) - { - this._scheduleLetterIndexSelect(letterIndex); - } - } - } - - // reset flags - this._inDragIndex = false; - this._stopSelect = false; - - return true; -}; - - - -/** - * Select item - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {void} - */ -List2Ctrl.prototype._touchSelectItem = function(e) -{ - // clear any hit timeout - clearTimeout(this._makeHitTimeoutId); - - // if we are not allowed to select (when in drag) - if (this._stopSelect) - { - this._stopSelect = false; - return; - } - - // select during loading is not allowed - if (this._inLoading) - { - return; - } - - var itemIndex; - var fireSelect = true; - var additionalModifier = null; - var params = {}; - - // determine target item - itemIndex = this._getTargetItem(e); - - // only valid list items can fire the select callback - if (itemIndex == -1) - { - return; - } - - // ensure that we end up on the same item where we started so that the select is valid - if (itemIndex != this._getFocussedIndex()) - { - return; - } - - // perform any additional touch processing for some items before issuing select callback - if (this._isToggle(itemIndex)) - { - // the target contains toggle buttons -> select toggle buttons - var toggleSelected = this._buttonSelect(e); - if ('cancel' == toggleSelected) - { - fireSelect = false; - } - else if (null != toggleSelected) - { - params = { additionalData:toggleSelected }; - additionalModifier = 'preventSimpleSelect'; - } - - } - - if (this._isSlider(itemIndex)) - { - // the target contains a slider -> disable select only if the slider is adjustable - if (this.dataList.items[itemIndex].allowAdjust) - { - fireSelect = false; - } - } - - if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && this._inSecondaryMulticontroller) - { - // if we are in secondary multicontroller and the item is a step item - var stepResult = this._stepAdjust(e); - if ('commit' === stepResult) - { - params = { finalAdjust:true, value:this.dataList.items[itemIndex].value }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - else if (null != stepResult) - { - params = { finalAdjust:false, value:stepResult }; - } - else - { - fireSelect = false; - } - } - else if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && !this._inSecondaryMulticontroller) - { - // if we are not in secondary multicontroller and the item is step item - this._setSecondaryMulticontroller(true, itemIndex); - fireSelect = false; - - // produce beep - this._beep('Short', 'Touch'); - } - - if (this._isLock(itemIndex) && this._hasSecondaryMulticontroller(itemIndex)) - { - // the target is a lock item - var lockAction = this._lockSelect(e); - if (null == lockAction) - { - fireSelect = false; - } - else - { - // prepare params - params = { additionalData:lockAction }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - } - - // prevent select on disabled items - if (this.dataList.items[itemIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Touch'); - - this._itemSelect(itemIndex, params, additionalModifier); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior) - { - this._itemHoldStop(itemIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - -}; - -/** - * Exit hit state of the currently hit item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._itemRemoveHit = function() -{ - var hitItems = this.scroller.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i= this.dataList.itemCount || this.dataList.items[itemIndex].disabled) - { - return; - } - - var returnValue = null; - - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'styleOnOff' : - // get and update current value - var currentValue = this.dataList.items[itemIndex].value; - var newValue = (1 === currentValue) ? 2 : 1; - this.dataList.items[itemIndex].value = newValue; - - // get and update DOM item - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (1 === newValue) - { - domItem.classList.add('checked'); - } - else - { - domItem.classList.remove('checked'); - } - } - returnValue = newValue; - break; - - case 'style10' : - case 'style11' : - // Note: settle timeout is registered in this._buttonActivate - this._buttonSelectRight(itemIndex); - returnValue = this.dataList.items[itemIndex].value; - break; - - case 'style03' : - case 'style03a' : - var currentValue = this.dataList.items[itemIndex].checked; - switch (this.dataList.items[itemIndex].image1) - { - case 'tick' : - if (!currentValue) - this._setTick(itemIndex, !currentValue); - break; - case 'radio' : - if (!currentValue) - this._setRadio(itemIndex, !currentValue); - break; - case 'checkbox' : - this._setCheckBox(itemIndex, !currentValue); - break; - } - returnValue = this.dataList.items[itemIndex].checked; - break; - - default : - log.warn('Lis2: No simple select behavior for item style ' + this.dataList.items[itemIndex].itemStyle); - break; - } - - return returnValue; - -}; - -/** - * Fire select callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid selectCallback - */ -List2Ctrl.prototype._itemSelect = function(itemIndex, paramsModifier, additionalModifier) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - // get paramsModifier - var paramsModifier = paramsModifier || {}; - - // get additionalModifier - var additionalModifier = additionalModifier || null; - - var appData = null; - var additionalData = null; - var params = {}; - - // event filtering - var filterEvent = false; - - if (this._isSlider(itemIndex)) - { - // the item contains a slider - additionalData = this.dataList.items[itemIndex].value; - } - - if (this._isSimpleSelectItem(itemIndex)) - { - // the item is simple select item - if ('preventSimpleSelect' != additionalModifier) - { - // process simple select behavior before firing the select callback - additionalData = this._simpleSelect(itemIndex); - } - - // apply event filter - var filterType = (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) ? 'toggle' : (this._isCheckBox(itemIndex)) ? 'check' : null; - filterEvent = this._applyEventFilter(itemIndex, filterType); - } - else if (this._isStep(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - this._setSecondaryMulticontroller(false, itemIndex); - } - else if (this._isLock(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - // restore focus and remove any secondary multicontroler - this._showFocus(this._lastItemWithFocus); - this._lockShowFocus(itemIndex, 'clear'); - this._setSecondaryMulticontroller(false, itemIndex); - } - else if (this._isStep(itemIndex)) - { - // apply event filter - var filterType = "step"; - filterEvent = this._applyEventFilter(itemIndex, filterType); - } - - // is this filtered event? - if (filterEvent) - { - return false; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - // merge params with params modifier - for (var i in paramsModifier) - { - params[i] = paramsModifier[i]; - } - - // return value - var result = false; - - // do not fire select on disabled items but instead fire select disabled - if (this.dataList.items[itemIndex].disabled) - { - // fire select disabled callback - if (typeof this.properties.selectDisabledCallback == 'function') - { - /* - * Handles touches on disabled list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectDisabledCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - } - else - { - // fire select callback - if (typeof this.properties.selectCallback == 'function') - { - /* - * Handles select on list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - - // dispatch select event - this._listEvent(this._EVENTS.ITEM_SELECT, params); - } - - if (this._hasData(itemIndex)) - { - // record this event and clear any timeouts - this.dataList.items[itemIndex]._data.lastEvent = new Date().getTime(); - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = null; - } - - return result; -}; - -/** - * Fire long press callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {event|integer} - raw touch/mouse event or directly the index of the item - * @return {boolean} - true if there's a valid longPressCallback - */ -List2Ctrl.prototype._itemLongPress = function(e) -{ - var eventCause = null; - var itemIndex = -1; - - // the parameter is an event - if (typeof e == 'object') - { - // determine target item - itemIndex = this._getTargetItem(e);var itemIndex = this._getTargetItem(e); - eventCause = 'Touch'; - } - // the parameter is an index - else if (!isNaN(e)) - { - itemIndex = e; - eventCause = 'Multicontroller'; - } - - // if the item is short-press-only -> prevent any longpress activity - if ('shortPressOnly' === this.dataList.items[itemIndex].itemBehavior) - { - return; - } - // if the item has itemBehavior other than shortAndLong and shortAndHold -> this is invalid property and prevent any longpress activity - else if ('shortAndLong' != this.dataList.items[itemIndex].itemBehavior && 'shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - log.warn('Lis2: Invalid itemBehavior property. Item behavior can be shortPressOnly / shortAndLong / shortAndHold'); - return; - } - - // make it long-pressed - this._itemMakeLongPress(e); - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // produce beep - this._beep('Long', eventCause); - - // fire long press callback - if ('shortAndLong' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.longPressCallback == 'function') - { - /* - * Handles long press on list items - * @param ctrlObj Object Reference to the list control that was long-pressed - * @param btnData Object Data that was attached to the long-pressed item - * @param params Object Object containing extra data - */ - this.properties.longPressCallback(this, appData, params); - - result = true; - } - // fire hold start callback - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.holdStartCallback == 'function') - { - /* - * Handles hold start on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStartCallback(this, appData, params); - - result = true; - } - - // raise the flag for long-press/hold-start issued callback - this._longPressIssued = true; - - // enter into list reorder on long press if the list supports it - if (this.properties.listReorder) - { - this._enterListReorder(); - this._startReorder(e); - } - - return result; -}; - - -/** - * Fire hold stop on an item. - * This function is called whenever the user ends touch - * on an item that has itemBehavior = shortAndHold - * TAG: internal, touch-only - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid holdStopCallback - */ -List2Ctrl.prototype._itemHoldStop = function(itemIndex) -{ - // validate item behavior property - if ('shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - return; - } - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // fire hold stop callback - if (typeof this.properties.holdStopCallback == 'function') - { - /* - * Handles hold stop on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStopCallback(this, appData, params); - - result = true; - } - - return result; -}; - -/** - * Perform outbound event filtering - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {boolean} - whethet to filter the event or not - */ -List2Ctrl.prototype._applyEventFilter = function(itemIndex, filterType) -{ - var filter = false; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return filter; - } - - var now = new Date().getTime(); - - switch (filterType) - { - case 'toggle' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.dataList.items[itemIndex].minChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.dataList.items[itemIndex].minChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - } - break; - - case 'check' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.properties.checkMinChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.properties.checkMinChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - } - break; - - case 'step' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - - if (this.properties.stepMinChangeInterval !== 0 && difference < this.properties.stepMinChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.properties.stepMinChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - } - break; - } - - return filter; -}; - -/** - * Timeout callback that is run if a select event - * is scheduled by the outbound filtering mechanism - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {void} - */ -List2Ctrl.prototype._filterTimeoutCallback = function(itemIndex, filterType) -{ - switch (filterType) - { - case 'toggle' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].value }, 'preventSimpleSelect'); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - break; - - case 'check' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].checked }, 'preventSimpleSelect'); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - break; - case 'step' : - this._itemSelect(itemIndex, { value : this.dataList.items[itemIndex].value }, 'preventSimpleSelect'); - break; - } -}; - -/** - * Register a settle timeout on any new user input. - * Any previous settle timeout should get cleared - * before setting a new one. The timeout state should - * be checked when public API call is made and depending - * on whether the timeout is running or not, the value - * will be cached or applied to the item. - * The settle time acts as an inbound event filtering mechanism. - * TAG: internal - * ========================= - * @param {integer} - itemIndex - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._registerSettleTimeout = function(itemIndex, itemType) -{ - log.debug('Settle scheduled'); - this._clearSettleTimeout(itemIndex, itemType); - - // schedule settle item - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._radioSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._tickSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.dataList.items[itemIndex].settleTime); - } - break; - } -}; - -/** - * Clear any settle timeouts on any user input. - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._clearSettleTimeout = function(itemIndex, itemType) -{ - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._radioSettleTimeoutId); - this._radioSettleTimeoutId = null; - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._tickSettleTimeoutId); - this._tickSettleTimeoutId = null; - } - break; - - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - } -}; - -/** - * Performs a check whether a settlie timeout - * is running for a particular item, radio group - * or tick group. - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {Boolean} - True if a settle timeout is running - */ -List2Ctrl.prototype._hasSettleTimeout = function(itemIndex, itemType) -{ - var timeoutRunning = false; - - switch (itemType) - { - case 'radio' : - if (null !== this._radioSettleTimeoutId && this._radioSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'tick' : - if (null !== this._tickSettleTimeoutId && this._tickSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'checkbox' : - case 'toggle' : - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return timeoutRunning; - } - - if (null !== this.dataList.items[itemIndex]._data.settleTimeout && this.dataList.items[itemIndex]._data.settleTimeout >= 0) - { - timeoutRunning = true; - } - break; - } - - return timeoutRunning; -}; - -/** - * Settle an item after the settle time expires. - * The cached value (if any) gets assigned as a - * real value to the item and the item is updated. - * This is the settleTimeout callback. - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item is successfully settled - */ -List2Ctrl.prototype._settleItem = function(itemIndex) -{ - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return false; - } - - // exit if the item index is out of range - if (isNaN(itemIndex) || itemIndex < 0 || itemIndex >= this.dataList.items.length) - { - return false; - } - - var item = this.dataList.items[itemIndex]; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return false; - } - - // get settle value and set it as real value, and update item - var settleValue = item._data.settleValue; - - - - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - if (null != item._data.settleValue) - { - // set real value - item.value = settleValue; - this.updateItems(itemIndex, itemIndex); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - } - else if (this._isCheckBox(itemIndex)) - { - // Note: setting the real value is done in the helpers - switch (item.image1) - { - case 'checkbox' : - if (null != item._data.settleValue) - { - // set real value - this._setCheckBox(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - break; - - case 'radio' : - if (null != item._data.settleValue) - { - // set real value - this._setRadio(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._radioSettleTimeoutId = null; - break; - - case 'tick' : - if (null != item._data.settleValue) - { - // set real value - this._setTick(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._tickSettleTimeoutId = null; - break; - } - } - else - { - // item does not support settlement - return false; - } - - log.debug('Settle item: ' + itemIndex + ', value: ' + settleValue); - - // return success - return true; - -}; - - -/** - * ========================= - * MULTICONTROLLER AND VUI - * ========================= - */ - -/** - * Main multicontroller handler - * TAG: multicontroller-only, public - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype.handleControllerEvent = function(eventID) -{ - log.debug("handleController() called, eventID: " + eventID); - - /* - * eventID - * - acceptFocusInit (sent on instantiation) - * - acceptFocusFromLeft - * - acceptFocusFromRight - * - acceptFocusFromTop - * - acceptFocusFromBottom - * - lostFocus - * - touchActive - * ... - */ - - var response; - - // ignore certain MC events when the list is in motion by touch - if (this._inDrag || (this._inScroll && 'touch' === this._scrollNature)) - { - switch (eventID) - { - case "acceptFocusInit" : - case "acceptFocusFromLeft" : - case "acceptFocusFromRight" : - case "acceptFocusFromTop" : - case "acceptFocusFromBottom" : - case "lostFocus" : - case "touchActive" : - case "controllerActive" : - // pass these events - break; - default : - // ignore everything else - return "ignored"; - break; - } - } - - if (!this._inSecondaryMulticontroller) - { - // we are in primary multicontroller mode - switch (eventID) - { - case "acceptFocusInit": - // consume event by default - response = "consumed"; - - // Input mode change to multicontroller - this._inputMode = 'controller'; - /* - * this event is received every time a template is displayed - * if we already have preset a focus item, do not set it again - */ - // Show focus animation - this._showFocusAnimation = true; - if ('restore' != this._initialScrollMode) - { - this._hasFocus = true; - var itemToGainFocus = this._canGainFocus('controllerActive'); - if (-1 !== itemToGainFocus) - { - this._showFocus(itemToGainFocus); - } - else - { - if (this.hasDataList()) - { - // we have data list and there are no enabled items -> give focus to the left - response = 'giveFocusLeft'; - } - else - { - // we probably dont't have a data list -> wait untul we get it - this._showFocus(this.properties.focussedItem); - } - } - } - else - { - this._showFocus(this.properties.focussedItem); - } - break; - - case "acceptFocusFromLeft": - // Show focus animation - this._showFocusAnimation = true; - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromRight": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromTop": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromBottom": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "lostFocus": - this._hideFocus(); - this._hideFocusLetterIndex(); - this._hasFocus = false; - response = "consumed"; - break; - - case "touchActive": - // Input mode change to touch - this._inputMode = 'touch'; - this._hideFocus(); - response = "consumed"; - break; - - case "controllerActive": - response = "consumed"; - break; - - case "cw": - // Rotate Right (CW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCW(); - break; - - case "ccw": - // Rotate Left (CCW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCCW(); - break; - - case "downStart": - // Tilt Down Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCDown(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCDown(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCDown.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll down for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollDownPage(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollDownPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll down for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "down" : - // Tilt Down Stop - - if ('downStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any downs without downStarts - response = "ignored"; - } - - break; - - case "upStart": - // Tilt Up Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCUp(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCUp(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCUp.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll up for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollUpPage(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollUpPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll up for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "up": - // Tilt Up Stop - - if ('upStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any ups without upStarts - response = "ignored"; - } - - break; - - case "leftStart": - // Tilt Left Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && this._inLetterIndexMulticontroller) - { - // Exit letter index multicontroller mode - this._setLetterIndexMulticontroller(false); - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusLeft..."); - response = "giveFocusLeft"; - } - break; - - case "left": - // Tilt Left Stop - - if ('leftStart' === this._lastControllerEvent) - { - response = "ignored"; - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any lefts without leftStarts - response = "ignored"; - } - break; - - case "rightStart": - // Tilt Right Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && !this._inLetterIndexMulticontroller) - { - // Enter into letter index multicontroller mode - this._setLetterIndexMulticontroller(true); - response = "consumed"; - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusRight..."); - response = "giveFocusRight"; - } - break; - - - case "right": - // Tilt Right Stop - - if ('rightStart' === this._lastControllerEvent) - { - response = "ignored"; - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any rights without rightStarts - response = "ignored"; - } - break; - - - case "selectStart": - // SelectStart (press down) - - if (this._inLetterIndexMulticontroller) - { - // get the focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - - // make focussed letter index hit - this._indexMakeHit(focussedLetterIndex); - } - else - { - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // make focussed index hit - this._itemMakeHit(focussedIndex); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, focussedIndex), this.properties.longPressTimeout); - } - - // always consume selectStart - response = "consumed"; - - break; - - case "select": - // Select (press down) - - if ('selectStart' === this._lastControllerEvent) - { - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // remove long press - this._itemRemoveLongPress(); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // fire letter index select - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._letterIndexSelect(currentFocussedLetterIndex, 'Multicontroller'); - } - else - { - if (this.properties.listReorder) - { - // if we are reordering lists (hence pressing down does not produce select event) - if (!this._inListReorder) - { - - // get focussed index - var focussedIndex = this._getFocussedIndex(); - - // check if focussed index is indeed eligable for list reorder - if ('shortAndLong' === this.dataList.items[focussedIndex].itemBehavior) - { - // we are about to begin list reorder - this._enterListReorder(); - } - - } - else - { - // we finish list reorder - this._releaseListReorder(); - } - - } - else - { - // if we are in normal mode - not reordering list - - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // does the element have secondary multicontroller behavior? - if (this._hasSecondaryMulticontroller(focussedIndex) && this._isSlider(focussedIndex)) - { - if (this.dataList.items[focussedIndex].allowAdjust) - { - // this item has secondary select and is adjustable slider -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this item has secondary select but is not adjustable -> trigger focus - this._triggerFocus(); - } - } - else if (this._hasSecondaryMulticontroller(focussedIndex)) - { - // this item has secondary select -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this is a regular item -> trigger focus - this._triggerFocus(); - } - - } - } - - // consume Select only after selectStart is consumed - response = "consumed"; - } - else - { - // ignore any selects without selectStarts - response = "ignored"; - } - - break; - - default: - // No action - response = "ignored"; - break; - } - - } - else - { - // we are in secondary multicontroller mode - response = this._handleControllerEventSecondary(eventID); - } - - // keep track of the last consumed event - if ('consumed' === response) - { - this._lastControllerEvent = eventID; - } - - /* - * returns - * - giveFocusLeft (control retains highlight unless it later gets lostFocus event) - * - giveFocusRight - * - giveFocusUp - * - giveFocusDown - * - consumed (always returned on select event, and if control adjusted highlight) - * - ignored (returned only if control doesn't know about focus) - */ - - log.debug("Event: " + eventID + " -> " + "Response: " + response); - - return response; - -}; - -/** - * Handle multicontroller clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - } - else - { - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller counter clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller down tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCDown = function() -{ - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - else - { - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - - -/** - * Handle multicontroller up tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCUp = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - // if we are in list reorder mode - push the draggable item up and set focus on it - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - var rfi = this._getRelativeFocussedIndex(); - } - else - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - - -/** - * handle controller event and apply it on items that are in secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype._handleControllerEventSecondary = function(eventID) -{ - // get the index - var focussedIndex = this._getFocussedIndex(); - - // handle event - switch (eventID) - { - case "up" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus up - this._showFocus('up'); - - // get relative focussed index after moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // we need to go back to the beginning in order to scroll up - if (rfi < 1) - { - this._scrollUpOne(); - } - break; - - - case "down" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus down - this._showFocus('down'); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleItems - 2; - // get relative focussed index after moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // we need to go to the end in order to scroll down - if (rfi >= bottomFocusThreshold) - { - this._scrollDownOne(); - } - break; - - case "leftStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('leftStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepDown(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "left" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('left'); - } - break; - - case "ccw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepDown(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "rightStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('rightStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepUp(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "right" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('right'); - } - - break; - - case "cw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepUp(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "select": - // leave secondary multicontroller mode and trigger focus - this._setSecondaryMulticontroller(false); - this._showFocus(this._lastItemWithFocus); - this._triggerFocus(); - break; - } - - // the secondary multicontroller events are always consumed - return "consumed"; -}; - -/** - * Set secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @param {integer} - focussed index - * @return {void} - */ -List2Ctrl.prototype._setSecondaryMulticontroller = function(state, focussedIndex) -{ - // get focussed index - if (isNaN(focussedIndex)) - { - var focussedIndex = this._getFocussedIndex(); - } - - // do not set secondary multicontroller to true if the item is disabled - if (state && this.dataList.items[focussedIndex].disabled) - { - return; - } - - if (state) - { - // flag as we are in secondary multicontroller mode - this._inSecondaryMulticontroller = true; - - // add secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.add('secondaryFocus'); - } - - /** - * Fire select callback to notify apps that we are - * entering into secondary multicontroller mode. - * In most cases apps will ignore this event. - * Transition focus to subcontrols. - */ - if (this._isSlider(focussedIndex)) - { - // the target is a slider and can be adjusted -> set currently active slider - this._activeSlider = { - itemIndex : focussedIndex, // currently active slider index - slider : this._getSlider(focussedIndex) // currently active slider instance - }; - - // transition focus - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - - // fire select callback for app notification - this._itemSelect(focussedIndex); - } - - /** - * Place focus highlight on the lock inline button - * if the target is a lock item - */ - if (this._isLock(focussedIndex)) - { - this._lockShowFocus(focussedIndex, 1); - } - - this._currentSecondaryMulticontrollerItem = focussedIndex; - } - else - { - this._inSecondaryMulticontroller = false; - - // remove secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.remove('secondaryFocus'); - } - - /** - * Transition focus from subcontrols. - */ - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // transition focus - this._activeSlider.slider.handleControllerEvent('lostFocus'); - } - - this._currentSecondaryMulticontrollerItem = null; - } - -}; - -/** - * Set letter index multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {boolean} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexMulticontroller = function(state, isTouch) -{ - if (state) - { - // hide focus from the main list and show it in the letter index - this._hideFocus(); - this._showFocusLetterIndex(this._getCurrentLetterIndex()); - this._inLetterIndexMulticontroller = true; - } - else - { - // hide focus from the letter index and show it in the main list - if (!isTouch) - { - this._showFocus(this._lastItemWithFocus); - } - this._inLetterIndexMulticontroller = false; - this._hideFocusLetterIndex(); - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - } - -}; - -/** - * Manage focus highlight - * This is the single point for managing focus when requested from outside List2. - * (focusedItem setter, restoreContext) Manages reorder and focus as required. - * TAG: internal - * ========================= - * @param {number} - item index - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._manageFocus = function(item) -{ - if (this._inListReorder && !isNaN(item)) - { - this._reorderToIndex(item); - } - return this._showFocus(item); -} - -/** - * Show focus highlight - * This is the single point for showing the - * focus highlight - * TAG: internal - * ========================= - * @param {strig | number} - direction (up|down) or item index - * @param {boolean} - simulation mode: use to perform check on where the focus will end - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._showFocus = function(item, allowOffscreen, simulationMode, abortMode) -{ - log.debug("List2: _showFocus item, allowOffscreen, simulationMode, abortMode ", item, allowOffscreen, simulationMode, abortMode); - if (!this._hasFocus) - { - return; - } - - if (this._inputMode != 'controller') - { - // do not show the focus if the input mode is other than 'controller' - return; - } - - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return; - } - - // do not show focus when in list reorder by touch - if (this._reorderTouchElt) - { - return; - } - - var abortMode = (true === abortMode); - - // do not change focussed index when we are in loading and no scrolling is allowed during that time - if (!this.properties.scrollingDuringLoading && this._inLoading && !abortMode) - { - return; - } - - var simulationMode = (true === simulationMode); - - // get the last focussed index (real and relative) - var lastFocussedIndex = this._getFocussedIndex(); - var lastRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // if we don't have previous focus, select the topmost - if (lastFocussedIndex == null) - { - lastFocussedIndex = this._topItem; - } - - // hide the focus only in real mode - if (!simulationMode) - { - this._hideFocus(); - } - - - var nextFocussedIndex = -1; - var useTransition = true; - var useRelativeIndeces = true; - - // find the next focussed element index - // NOTE: 'down' and 'up' are ued primarily when focussing with multicontroller - switch (item) - { - case 'down' : - // 'down' uses relative positioning - // the next one but not exceeding the visible items - - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.min(lastFocussedIndex+1, this.dataList.itemCount-1); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex >= this.dataList.itemCount-1) { - // we have reached the end of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the next one - nextRealFocussedIndex++; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.min(lastRelativeFocussedIndex+1, this.properties.visibleItems-1); - } - break; - - case 'up' : - // 'up' uses relative positioning - // the previous one but not lower than the first one - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.max(lastFocussedIndex-1, 0); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex <= 0) { - // we have reached the beginning of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the previous one - nextRealFocussedIndex--; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.max(lastRelativeFocussedIndex-1, 0); - } - break; - - default : - // move highlight instantly when jumping to an item - useTransition = false; - // absolute indeces use real positioning - useRelativeIndeces = false; - - if (!isNaN(item)) - { - // specific one -> make sure it is within the list bounds - nextFocussedIndex = this.m.max(this.m.min(item, this.dataList.itemCount-1), 0); - } - else - { - // the top one - nextFocussedIndex = this._topItem; - } - } - - // if we are in simulation -> return the would-be focussed index - if (simulationMode) - { - return nextFocussedIndex; - } - - // From here on, perform actual focus change - // ----------------------------------------- - var pos = 0; - if (useRelativeIndeces) - { - // convert relative nextFocussedIndex to position - pos = nextFocussedIndex * this.properties.itemHeight; - // convert nextFocussedIndex back to real one - nextFocussedIndex = this._relativeToRealIndex(nextFocussedIndex); - } - else - { - // are we allowed to focus off screen? - if (!allowOffscreen) - { - // check if focus is outside the screen and scroll the list so that it is inside - if (this._realToRelativeIndex(nextFocussedIndex) < 0) - { - // scrollt up - this._scrollTo(nextFocussedIndex, 0); - } - else if (this._realToRelativeIndex(nextFocussedIndex) > this.properties.visibleItems - 2) - { - // scroll down - this._scrollTo((nextFocussedIndex + 2) - this.properties.visibleItems, 0); - } - } - - // convert absolute nextFocussedIndex to position - pos = (nextFocussedIndex - this._topItem) * this.properties.itemHeight; - } - - - - - // find the new focussed element - var focussedElement = this._getDOMItem(nextFocussedIndex); - - - // do we have a focussed element? - if (focussedElement) - { - focussedElement.classList.add('focus'); - - // create first focus animation - if (this._showFocusAnimation) - { - this._showFocusAnimation = false; - this.firstFocusAnimationEndCallback = this._firstFocusAnimationEndCallback.bind(this); - focussedElement.addEventListener("animationend", this.firstFocusAnimationEndCallback, false); - focussedElement.classList.add('firstFocus'); - } - } - - // set letter index position - this._setLetterIndexPosition(nextFocussedIndex); - - // store focussed item - this._lastItemWithFocus = nextFocussedIndex; - - return nextFocussedIndex; -}; - -/** - * First focus animation end callback that is fired - * when the first focus animation finishes. - * It removes the firstFocus class from the event's target - * and clears any subsequent animation callbacks - * TAG: internal - * ========================= - * @param {AnimationEvent} - * @return {void} - */ -List2Ctrl.prototype._firstFocusAnimationEndCallback = function(e) -{ - e.target.classList.remove('firstFocus'); - e.target.removeEventListener("animationend", this.firstFocusAnimationEndCallback, false); - this.firstFocusAnimationEndCallback = null; -}; - -/** - * Hide focus highlight - * This is the single point for hiding the - * focus highlight - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._hideFocus = function() -{ - // Preserve focussed element - this._lastItemWithFocus = this._getFocussedIndex(); - - for (var i=0; i disable select only if the slider is adjustable - if (this.dataList.items[focussedIndex].allowAdjust) - { - fireSelect = false; - } - - // reset currently active slider - this._activeSlider = null; - } - - if (this._isStep(focussedIndex)) - { - params = { - value : this.dataList.items[focussedIndex].value, - finalAdjustment : true, - }; - } - - /** - * Trigger the currently selected button - */ - if (this._isLock(focussedIndex)) - { - var focussedButton = this._lockGetFocus(focussedIndex); - var actionResult = this._lockActivate(focussedIndex, focussedButton); - this._lockShowFocus(focussedIndex, 'clear'); - params = { additionalData : actionResult }; - } - - // prevent select on disabled items - if (this.dataList.items[focussedIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Multicontroller'); - - this._itemSelect(focussedIndex, params); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[focussedIndex].itemBehavior) - { - this._itemHoldStop(focussedIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - - } -}; - -/** - * Check whether the list can gain focus. In certain cases focus cannot be - * shown (e.g. when there are no items available) or if it can gain it - * it should be restored on the nearest available item if the one that - * previously had focus is disabled. - * TAG: internal - * ========================= - * @param {MouseEvent|Number} - optional argument. If passed a check will be performed whether the target item is disabled - * @return {integer} - the item that will have focus. If no item can have focus, return -1 - */ -List2Ctrl.prototype._canGainFocus = function(e) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return -1; - } - - var itemToGainFocus = -1; - - // check if we are touching the element - if (typeof e === 'object') - { - var targetItem = this._getTargetItem(e); - - // the item is enabled and can gain focus - if (-1 !== targetItem && !this.dataList.items[targetItem].disabled) - { - itemToGainFocus = targetItem; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(targetItem); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - else if (typeof e === 'number') - { - if (-1 !== e && !this.dataList.items[e].disabled) - { - itemToGainFocus = e; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(e); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - // check whether this is called from the controllerActive event handler - else if ('controllerActive' === e && this.properties.focussedItem > 0 && this.dataList.items[this.properties.focussedItem] && !this.dataList.items[this.properties.focussedItem].disabled) - { - itemToGainFocus = this.properties.focussedItem; - } - // check if last item with focus is disabled - else if (this.dataList.items[this._lastItemWithFocus] && !this.dataList.items[this._lastItemWithFocus].disabled) - { - itemToGainFocus = this._lastItemWithFocus; - } - else - { - // show focus on the closest available item to the last with focus - var nearestItem = this._getNearestEnabledItem(this._lastItemWithFocus); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - - // if we have tabs and no enabled items, always show focus on the first line allowing tabs navigation - if (this.tabsCtrl && -1 === itemToGainFocus) - { - itemToGainFocus = this._topItem; - } - } - - return itemToGainFocus; -}; - -/** - * Get focussed index - * TAG: internal, helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getFocussedIndex = function() -{ - var focussedIndex = this._lastItemWithFocus; - - for (var i=0; i - */ -List2Ctrl.prototype._getFocussedElement = function() -{ - var focussedElement = null; - var focussedIndex = this._getFocussedIndex(); - for (var i=0; i= this.dataList.itemCount) - { - currentItem = null; - } - else - { - while (this.dataList.items[currentItem].disabled) - { - if (currentItem >= this.dataList.itemCount-1 || currentItem <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentItem = null; - break; - } - currentItem = ('down' === direction) ? currentItem+1 : currentItem-1; - } - } - return currentItem; -}; - -/** - * Get nearest enabled item in all directions - * If there are two enabled items in both directions that are - * at equal distances from the reference item, the one below is - * returned. - * TAG: internal, helper - * ========================= - * @param {integer} - from which item to search - * @return {integer} - the next enabled item. - * If nothing is found, return Null - */ -List2Ctrl.prototype._getNearestEnabledItem = function(fromItem) -{ - var nearestEnabledItem = null; - - var nearestDown = this._getNearestEnabledItemByDirection(fromItem, 'down'); - var nearestUp = this._getNearestEnabledItemByDirection(fromItem, 'up'); - - if (null === nearestDown === nearestUp) - { - // no enabled item is found - nearestEnabledItem = null; - } - else if (null === nearestDown) - { - // nothing is found below -> return the one above - nearestEnabledItem = nearestUp; - } - else if (null === nearestUp) - { - // nothing is found above -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - var differenceDown = this.m.abs(fromItem - nearestDown); - var differenceUp = this.m.abs(fromItem - nearestUp); - if (differenceDown === differenceUp) - { - // equally spaced -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - // differently spaced -> return the closer one - nearestEnabledItem = (differenceDown < differenceUp) ? nearestDown : nearestUp; - } - } - - return nearestEnabledItem; -}; - -/** - * Get secondary select status of an item - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {boolean} - whether the item has secondary multicontroller - */ -List2Ctrl.prototype._hasSecondaryMulticontroller = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var hasSecondaryMulticontroller = false; - - var type = this.dataList.items[itemIndex].itemStyle; - for (var i=0; i return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+this.properties.visibleItems-2, 'down'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi + 2 - this.properties.visibleItems; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll up by one element - * If the element that will be placed at the top - * position is disabled, the list will be scrolled to - * the nearest available enabled item - * TAG: internal - * ========================= - * @return {integer} - new position of the scroller in px - */ -List2Ctrl.prototype._scrollUpOne = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topItem === 0) - { - // we can't scroll up any more -> return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi - 1; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.min(newPos, 0); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll down by one page (screen) - * TAG: internal - * ========================= - * @return {string} - paged | atlimit | onepage - */ -List2Ctrl.prototype._scrollDownPage = function() -{ - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = 'onepage'; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the bottom - case 'bottom' : - // place focus on the last available item - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'up'); - if (null != nei && nei >= this._topItem) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the bottom - case 'bottomclose' : - // search for enabled item in the bottom screen - var nei = this._getNearestEnabledItemByDirection(this.dataList.itemCount - 1, 'up'); - if (null != nei && nei >= this.dataList.itemCount - this.properties.visibleItems) - { - // place focus on the last available item and scroll to the bottom - this._showFocus(nei); - this._scrollTo(this.dataList.itemCount - this.properties.visibleItems); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.min(this._topItem + this.properties.visibleItems + currentRelativeFocussedIndex, this.dataList.itemCount-1); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem + this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future top item down - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'down'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atLimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll up by one page (screen) - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollUpPage = function() -{ - - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = ''; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the top - case 'top' : - // place focus on the first available item - var nei = this._getNearestEnabledItemByDirection(-1, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the top - case 'topclose' : - // search for enabled item in the top screen - var nei = this._getNearestEnabledItemByDirection(0, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - // place focus on the last available item and scroll to the top - this._showFocus(nei); - this._scrollTo(0); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.max(this._topItem - this.properties.visibleItems + currentRelativeFocussedIndex, 0); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem - this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.min(newPos, 0); // constrain it to the min scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future bottom item up - var nei = this._getNearestEnabledItemByDirection(this._topItem - this.properties.visibleItems, 'up'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atlimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll to the top - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollTop = function() -{ - this._performScroll(0); // do the scroll -}; - -/** - * Scroll to the bottom - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollBottom = function() -{ - this._performScroll(this._maxScrollY); // do the scroll -}; - -/** - * Do the actual scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._performScroll = function(pos, duration) -{ - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return; - } - - // if menu can be scrolled (it has enough list items) - if (this._isScrollable) - { - // make it snappy - var newPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(pos, duration); - } -}; - -/** - * Animate the scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateScroll = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - if (null !== this.scrollerAnimationEndCallback) - { - // remove any redundant animationEnd listeners - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scrollerAnimationEndCallback = null; - } - - // animate scroller or directly call the animation end callback if the time is 0 - this.scroller.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollerAnimationEndCallback = this._scrollerAnimationEnd.bind(this); - this.scroller.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scroller.style.top = pos + 'px'; - - this._inScroll = false; - if (time > 0) - { - this._inScroll = true; - } - - // set top item and update display - this._updateScrollIndicator(pos, time); - this._setTopListItem(pos); - this._updateRange(); -}; - -/** - * Abort any ongoing scroll and reset any flags - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._abortScroll = function(e) -{ - // aborting scroll is possible only while the list is scrolling - if (false === this._inScroll) - { - return; - } - - // get target item - var targetItem = this._getTargetItem(e); - - // check if target item is enabled - if (this.dataList.items[targetItem] && !this.dataList.items[targetItem].disabled) - { - // show focus there - this._showFocus(targetItem, true, false, true); - } - else - { - // restore focus - this._restoreFocus(); - } - - // get current snapped position - var snapPos = this._getSnapPosition(this.scroller.offsetTop); - this._animateScroll(snapPos, 0); - - // reset any touch flags - this._inDrag = false; - this._inScroll = false; - this._scrollNature = null; - this._inHorizontalDrag = null; - this._hDragItem = null; - this._stopSelect = false; - this._startTime = 0; - this._startItem = null; - this._startDOMItem = null; - this._activeSlider = null; - this._startY = 0; - this._startX = 0; -}; - - -/** 2. LIST SNAPPING **/ - -/** - * Get snap position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getSnapPosition = function(pos) -{ - return this.properties.itemHeight * (Math.round(pos / this.properties.itemHeight)); -}; - -/** - * Get snap (above) position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest above item edge - */ -List2Ctrl.prototype._getSnapPositionAbove = function(pos) -{ - return this.properties.itemHeight * (Math.floor(pos / this.properties.itemHeight)); -}; - -/** - * Scroll list to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {void} - */ -List2Ctrl.prototype._snap = function(pos) -{ - // the snap position is the same as the current - if (pos == this._y) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - return; - } - else if (pos === this._minScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex > this._topItem + this.properties.visibleItems - 1) - { - this._restoreFocus(); - } - return; - } - - var snapPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(snapPos); -}; - -/** 3. LIST SWIPING AND PHYSICS **/ - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipe = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._y, this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0, 0); - - /* ANIMATE THE SCROLLER */ - var newPos = this.m.min(this.m.max(this._y + momentumY.dist, this._maxScrollY), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.scroller.offsetTop) // only if newPos is a number and the list is worth scrolling - { - this._animateScroll(newPos, swipeDuration); - } - else - { - // set top item and bring focus on the screen - this._setTopListItem(newPos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - } -}; - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipeIndex = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._yIndex, this._maxScrollYIndex < 0 ? this._scrollerHIndex - this._maskH + this._yIndex - this._minScrollYIndex : 0, 0); - - /* ANIMATE THE LETTER INDEX SCROLLER */ - var newPos = this.m.min(this.m.max(this._yIndex + momentumY.dist, this._maxScrollYIndex), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getIndexSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.letterIndex.offsetTop) // only if newPos is a number and the letter index is worth scrolling - { - // start animation - this._animateLetterIndex(newPos, swipeDuration); - } - else - { - // set top letter index and bring focus on the screen - this._setTopLetterIndex(newPos); - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (focussedLetterIndex < this._topLetterIndex) - { - this._showFocusLetterIndex(this._topLetterIndex); - } - } -}; - -/** - * @param {integer} - dragged distance - * @param {time} - time dragged - * @param {integer} - this._y - * @param {integer} - this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0 - * @param {integer} - 0 - */ -List2Ctrl.prototype._momentum = function (dist, time, maxDistUpper, maxDistLower, size) -{ - var deceleration = this.properties.deceleration, - speed = this.m.abs(dist) / time, - newDist = (speed * speed) / (2 * deceleration), - newTime = 0, outsideDist = 0; - - // Proportinally reduce speed if we are outside of the boundaries - if (dist > 0 && newDist > maxDistUpper) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistUpper = maxDistUpper + outsideDist; - speed = speed * maxDistUpper / newDist; - newDist = maxDistUpper; - } else if (dist < 0 && newDist > maxDistLower) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistLower = maxDistLower + outsideDist; - speed = speed * maxDistLower / newDist; - newDist = maxDistLower; - } - - newDist = newDist * (dist < 0 ? -1 : 1); - newTime = speed / deceleration; - - return { dist: newDist, time: Math.round(newTime) }; -}; - - -/** - * ========================= - * LETTER INDEX - * ========================= - */ - -/** - * Letter index select - * scrolls list to letter index - * TAG: internal - * ========================= - * @param {integer} - the new position of the scroller in element index. - * @return {void} - */ -List2Ctrl.prototype._letterIndexSelect = function(letterIndex, eventCause) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // check if if letterIndex is a valid index - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - return; - } - - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - - // set scroll nature - this._scrollNature = 'letterIndex'; - - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - - // set letter index active position - this._setLetterIndexPosition(this.letterIndexData[letterIndex].itemIndex); - - // update last item with focus so that focus gets restored in the correct place - this._lastItemWithFocus = this.letterIndexData[letterIndex].itemIndex; - - // set proper event cause - var eventCause = ('Multicontroller' != eventCause && 'Touch' != eventCause) ? null : eventCause; - // produce beep - this._beep('Short', eventCause); - - // dispatch letter select event - var eventData = { - index : letterIndex, - label : this.letterIndexData[letterIndex].label, - itemIndex : this.letterIndexData[letterIndex].itemIndex, - }; - this._listEvent(this._EVENTS.LETTER_SELECT, eventData); -}; - -/** - * Schedule letter index select after some time - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - - if (!clear) - { - // if no letter index is passed, get the currently focussed one - if (undefined === letterIndex) - { - // check whether we already have focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex) - { - // if yes, schedule to that one - letterIndex = focussedLetterIndex; - } - } - - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - this._letterIndexSelect(letterIndex); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; - -/** - * Schedule background letter index select after some time. - * Background select occurs without affecting the letter index - * scroll position. This is intended to be used only programatically. - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleBackgroundLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - // check for a valid letter index item - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - log.warn('List2: a valid letter index expected. Letter index passed": ' + letterIndex); - return; - } - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - if (!clear) - { - // activate the new index - this._setCurrentLetterIndex(letterIndex); - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - // set scroll nature - this._scrollNature = 'letterIndex'; - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; -/** - * Animate the letter index - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @param {integer} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateLetterIndex = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - // animate letter index - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.letterIndexAnimationEndCallback = this._letterIndexAnimationEnd.bind(this); - this.letterIndex.addEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndex.style.top = pos + 'px'; - - // set top letter index - this._setTopLetterIndex(pos); -}; - -/** - * Set top letter index item depending on the position - * TAG: internal - * ========================= - * @param {integer} - position in px at which the letter should be - * @return {void} - */ -List2Ctrl.prototype._setTopLetterIndex = function(pos) -{ - // pos should be number for proper topLetterIndex calculation - if (!isNaN(pos)) - { - this._prevTopLetterIndex = this._topLetterIndex; - this._topLetterIndex = -(Math.round(pos / this.properties.letterIndexHeight)); - } -}; - -/** - * Get snap position of letter index - * depending on the new letter index position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getIndexSnapPosition = function(pos) -{ - return this.properties.letterIndexHeight * (Math.round(pos / this.properties.letterIndexHeight)); -}; - -/** - * Scroll letter index to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {void} - */ -List2Ctrl.prototype._snapIndex = function(pos) -{ - // the snap position is the same as the current - if (pos == this._yIndex) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollYIndex) - { - // set top item and bring focus on the screen - this._setTopLetterIndex(pos); - var focussedIndex = this._getFocussedLetterIndex(); - if (focussedIndex < this._topLetterIndex) - { - this._restoreLetterIndexFocus(); - } - return; - } - - var snapPos = this._getIndexSnapPosition(pos); - - // start animation - this._animateLetterIndex(snapPos); -}; - -/** - * Scroll to a specific index item - * TAG: internal - * ========================= - * @param {integer | string} - letter or letter index - * @return {void} - */ -List2Ctrl.prototype._scrollToIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - var targetIndex = -1; - - if (!isNaN(letter)) - { - // we are going to a letter index - targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - } - else if (typeof letter === 'string'); - { - // we are searching for the letter index of the letter - for (var i=0, l=this.letterIndexData.length; i above or below the visible range - // NOTE: if the letter is within the visible range this should not get called at all - if (-1 != targetIndex && targetIndex >= this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // look below -> find closest target index so that the focus is visible and apply target index correction - targetIndex = targetIndex - this.properties.visibleLetterIndexItems + 1; - } - else if (-1 != targetIndex && targetIndex <= this._topLetterIndex) - { - // look above -> find closest target index so that the focus is visible - // correction: the taget index is the top item whereas the item in question is the second one - targetIndex--; - } - else - { - // we don't scroll if the target is visible - return; - } - - // do the scroll - var newPos = -(targetIndex) * this.properties.letterIndexHeight; // calculate new position - newPos = this.m.max(this.m.min(newPos, this._minScrollYIndex), this._maxScrollYIndex); // constrain it to scroll bounds - this._animateLetterIndex(newPos); // start animation - - -}; - -/** - * Scroll down by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollDownOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the bottom-most position - if (this._topLetterIndex === this.letterIndexData.length - this.properties.visibleLetterIndexItems) - { - // we can't scroll down any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+this.properties.visibleLetterIndexItems-2, 'down'); - // do not scroll if no enabled letters are found - if (null != bi) - { - var newTopLetter = bi + 2 - this.properties.visibleLetterIndexItems; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.max(newPos, this._maxScrollYIndex); // constrain it to the max scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Scroll up by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollUpOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topLetterIndex === 0) - { - // we can't scroll up any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopLetter = bi - 1; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.min(newPos, this._minScrollYIndex); // constrain it to the min scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Set letter index position relative to the - * focussed item in the scroller - * TAG: internal - * ========================= - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexPosition = function(index) -{ - // check for letter index - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return false; - } - - // get focussed item - var focussedIndex; - if (!isNaN(index)) - { - focussedIndex = index; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // get the new index - var targetIndex = -1; - for (var i=this._letterIndexDataSorted.length-1; i>=0; i--) - { - if (focussedIndex >= this._letterIndexDataSorted[i].itemIndex) - { - targetIndex = this._letterIndexDataSorted[i].publicIndex; - break; - } - } - - // show focus on target index - if (targetIndex > -1) - { - this._setCurrentLetterIndex(targetIndex); - } - - // check if letter index scrolling is needed - if (targetIndex >= this._topLetterIndex && targetIndex < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - return; - } - - // scroll to target index - if (targetIndex > -1) - { - this._scrollToIndex(targetIndex); - } -}; - -/** - * Set currently active letter index - * TAG: internal - * ========================= - * @param {integer} - letter item index - * @return {integer} - the currently active letter index - */ -List2Ctrl.prototype._setCurrentLetterIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return null; - } - - var targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - - - // remove any previously active letter index - for (var i=0, l=this.letterIndexData.length; i= this.letterIndexData.length-1) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - case 'up' : - // we are searching for the previous - targetIndex = lastFocussedIndex; - while (targetIndex > 0) - { - targetIndex--; - if (-1 != this.letterIndexData[targetIndex].itemIndex) - { - break; - } - else if (targetIndex <= 0) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - default : - // we are searching for the index of the letter - for (var i=0, l=this.letterIndexData.length; i= letterIndexCount) - { - currentLetter = null; - } - else - { - while (this.letterIndexData[currentLetter].disabled) - { - if (currentLetter >= letterIndexCount-1 || currentLetter <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentLetter = null; - break; - } - currentLetter = ('down' === direction) ? currentLetter+1 : currentLetter-1; - } - } - return currentLetter; -}; - -/** - * Exit hit state of the currently hit index item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._indexRemoveHit = function() -{ - for (var i=0, l=this.letterIndexData.length; i bring back reorder item - if (this._inListReorder && this._reorderTouchElt) - { - this._bringReorderItem(); - } - - // Focus adjust after animation ends - - // get list position - var listPosition = null; - if (0 === this._topItem) - listPosition = 'top'; - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; - else - listPosition = 'middle'; - - // get scroll direction - var scrollDirection = null; - if (this._prevTopItem > this._topItem) - scrollDirection = 'up'; - else if (this._prevTopItem < this._topItem) - scrollDirection = 'down'; - else - scrollDirection = 'none'; - - // get scroll size - var scrollSize = this.m.abs(this._prevTopItem - this._topItem); - - if ('page' === this._scrollNature) - { - // do not place focus, it should have been done by the paging function - } - else if ('item' === this._scrollNature) - { - // show focus - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // check if focussed index is outside the screen and we actually have a scroll - if (scrollSize > this.properties.visibleItems-1 && !this._inLetterIndexMulticontroller) - { - // restore focus - this._restoreFocus(); - } - else if (scrollSize > 0 && !this._inLetterIndexMulticontroller) - { - // check if the focus is just slightly outside the visible range - if (this._lastItemWithFocus < this._topItem || this._lastItemWithFocus >= this._topItem + this.properties.visibleItems) - { - // restore focus - this._restoreFocus(); - } - else - { - // else the focus remains on the screen -> only set letter index position - this._setLetterIndexPosition(this._getFocussedIndex()); - } - } - else - { - // we don't have a scroll -> nothing to do here - } - } - - // lower _inScroll flag - this._inScroll = false; - - // reset scroll nature - this._scrollNature = null; - - // dispatch scroll end event - this._listEvent(this._EVENTS.SCROLL_END, {scrollPosition:this._topItem}); -}; - -/** - * Restore focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreFocus = function() -{ - // check if the top item is enabled - if (!this.dataList.items[this._topItem].disabled) - { - this._showFocus(this._topItem, false, false, true); - } - // top item is disabled, find the nearest enabled item below the top one - else - { - var neiDown = this._getNearestEnabledItem(this._topItem, 'down'); - // check if the item is on screen - if (null != neiDown && neiDown >= this._topItem && neiDown < this._topItem + this.properties.visibleItems) - { - this._showFocus(neiDown, true, false, true); - } - // there's no enabled item or it is off screen - else - { - this._showFocus(this._topItem, false, false, true); - } - } -}; - -/** - * Scroll indicator animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorAnimationEnd = function() -{ - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicatorAnimationEndCallback = null; - - // fadeOut scroll indicator - this._fadeOutScrollIndicator(); -}; - -/** - * Letter index animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._letterIndexAnimationEnd = function() -{ - // remove animation end callbacks - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndexAnimationEndCallback = null; - - // restore focus - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex && (focussedLetterIndex < this._topLetterIndex || focussedLetterIndex > this._topLetterIndex + this.properties.visibleLetterIndexItems - 1)) - { - // focus is off screen - this._restoreLetterIndexFocus(); - } - else if (null != focussedLetterIndex) - { - // schedule letter index select if letter is enabled - if (!this.letterIndexData[focussedLetterIndex].disabled) - { - this._scheduleLetterIndexSelect(focussedLetterIndex); - } - } -}; - -/** - * Restore letter index focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreLetterIndexFocus = function() -{ - // check if the top letter index is enabled - if (!this.letterIndexData[this._topLetterIndex].disabled) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule letter index select - this._scheduleLetterIndexSelect(this._topLetterIndex); - } - else - { - // look for enabled item down and up - var neiDown = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'down'); - var neiUp = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'up'); - // determine scroll direction - var scrollDirection = (this._topLetterIndex - this._prevTopLetterIndex < 0) ? 'up' : 'down'; - - // check whether we have an enabled item on screen - if (null != neiDown && neiDown >= this._topLetterIndex && neiDown < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // there is an enabled item on screen -> place the focus there - this._showFocusLetterIndex(neiDown); - // schedule letter index select - this._scheduleLetterIndexSelect(neiDown); - } - else if ('down' === scrollDirection) - { - // we are scrolling down -> look for enabled item up - if (null != neiUp) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiUp); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - else if ('up' === scrollDirection) - { - // we are scrolling up -> look for enabled item down - if (null != neiDown) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiDown); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - } -}; - - -/** - * ========================= - * SLIDERS AND TOGGLE CONTROL - * ========================= - */ - -/** - * Passes START (mousedown) event to the currently - * targeted slider instance and returns it. - * TAG: internal - * ========================= - * @param {MouseEvent} - * @param {Boolean} - * @return {SliderCtrl} - */ -List2Ctrl.prototype._slideStart = function(e, skipActiveSlider) -{ - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // check if slider can be adjusted - if (!this.dataList.items[itemIndex].allowAdjust) - { - return; - } - - // check if we are in the hittable area - if(!this._hasRightHittableArea(this.dataList.items[itemIndex])) - { - var relativeX = e.pageX - this._maskPositionX; - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight; - var leftBoundary = this.properties.sliderReferencePointRight - this.properties.sliderWidth; - } - else if(this.dataList.items[itemIndex].indented) - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)) + (this.properties.indentOffset * 2); - var leftBoundary = this.properties.sliderReferencePointLeft; - } else - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)); - var leftBoundary = this.properties.sliderReferencePointLeft; - } - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> exit - return; - } - - var sliderInstance = this._getSlider(itemIndex); - var skipActiveSlider = (true === skipActiveSlider); - if (!skipActiveSlider) - { - // set currently active slider - this._activeSlider = { - itemIndex : itemIndex, // currently active slider index - slider : sliderInstance // currently active slider instance - }; - - // transition focus to slider and hide focus on the item - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - this._hideFocus(); - - // pass the event to the SliderCtrl - this._activeSlider.slider._onDownHandler(e); - } - - return sliderInstance; -}; - -List2Ctrl.prototype._slideMove = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - return; - } - - // determine target item - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // pass the event to the SliderCtrl - this._activeSlider.slider._onMoveHandler(e); -}; - -List2Ctrl.prototype._slideEnd = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - var sliderInstance = this._slideStart(e, true); - if (sliderInstance && !this._stopSelect) - { - // pass the event to the SliderCtrl - sliderInstance._onDownHandler(e); - sliderInstance._onUpHandler(e); - } - return; - } - else - { - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - if (this._inSecondaryMulticontroller && itemIndex == this._currentSecondaryMulticontrollerItem) - { - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // pass the event to the SliderCtrl - this._activeSlider.slider._onUpHandler(e); - - // transition focus back to item and remove it from the slider - this._activeSlider.slider.handleControllerEvent('lostFocus'); - this._showFocus(this._lastItemWithFocus, true); - } - } - - // reset currently active slider - this._activeSlider = null; -}; - -List2Ctrl.prototype._slideCallback = function() -{ - // get item index from the first argument - var itemIndex = arguments[0]; - - // get value and final adjustment from fourth argument - var value = arguments[3].value; - var finalAdjustment = arguments[3].finalAdjustment; - - // update local value - this.dataList.items[itemIndex].value = value; - - // Fire slide callback passing forward anything in the arguments - if (typeof this.properties.slideCallback == 'function') - { - // fire callback with original slider params - // this.properties.slideCallback.apply(null, Array.prototype.slice.call(arguments, 1)); - - // fire per-design callback - var params = { - itemIndex : itemIndex, - value:value, - finalAdjustment : finalAdjustment - }; - this.properties.slideCallback(this, this.dataList.items[itemIndex].appData, params); - } -}; - - - -/* - * ========================= - * TOGGLE BUTTONS - * When a button is selected it is automatically - * highlighted (activated) and the value is reported to the - * button select callback (if defined) - * ========================= - */ - - -/** - * Remove hit state from the toggle button - * TAG: touch-only, internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {void} - */ -List2Ctrl.prototype._buttonRemoveHit = function(itemIndex) -{ - var targetElt = this._getDOMItem(itemIndex); - if (targetElt) - { - var hitItems = targetElt.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - // Check which button is hit - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button hit - if (buttonId) - { - // save the button as _startButton - this._startButton = buttonId; - - var domItem = this._getDOMItem(itemIndex); - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle button - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable && this._startButton) - { - // we are outside the hittable area and we have started from a button -> return cancel - return 'cancel'; - } - else if (!inHittable) - { - // we are outside the hittable area -> return cancel - return null; - } - - // Check which button is selected - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button active - if (buttonId && buttonId === this._startButton) - { - this._startButton = null; - - if (this.dataList.items[itemIndex].value == buttonId) - { - // we ended on already selected button -> cancel - return 'cancel'; - } - // we ended up on the same button we started -> select that button - this._buttonActivate(itemIndex, buttonId); - } - else if (buttonId && null === this._startButton) - { - // we started off the buttons but ended up on a button -> select next button - this._startButton = null; - return null; - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startButton = null; - return 'cancel'; - } - - // Return the button id - return buttonId; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectLeft = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectRight = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current+1); -}; - -/** - * Activate toggle button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonActivate = function(itemIndex, buttonId) -{ - // Ensure that buttonId is valid and wraps in a loop - if ('style10' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 2) - buttonId = 1; - else if (buttonId < 1) - buttonId = 2; - } - else if('style11' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 3) - buttonId = 1; - else if (buttonId < 1) - buttonId = 3; - } - else if('draggable' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = 1; - } - else - { - log.debug('Unknown item style for itemIndex ' + itemIndex); - return null; - } - - if ('draggable' != this.dataList.items[itemIndex].itemStyle) - { - // Save the new value in the dataList - this.dataList.items[itemIndex].value = buttonId; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Remove any residual hit states - this._buttonRemoveHit(itemIndex); - - // Activate the button - if (domItem) - { - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // save the button as _startLockButton - this._startLockButton = buttonId; - - // remove hit - this._lockRemoveHit(itemIndex); - - // make that button hit - if (1 === buttonId) - { - this._lockShowFocus(itemIndex, 1); - domItem.querySelector('.buttonLock').classList.add('hit'); - } - else - { - this._lockShowFocus(itemIndex, 2); - domItem.querySelector('.buttonDelete').classList.add('hit'); - } - - this._hideFocus(); - - return true; - -}; - -/** - * Select lock button - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockSelect = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return null; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return null; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // set secondary multicontroller leaving highlight from where it started - if (this._startLockButton) - { - this._setSecondaryMulticontroller(true, itemIndex); - this._lockShowFocus(itemIndex, this._startLockButton); - } - - // we are outside the hittable area -> return null - return null; - } - - var action = null; - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // Make that button active - if (buttonId === this._startLockButton) - { - this._startLockButton = null; - // we ended up on the same button we started -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else if (null === this._startButton) - { - this._startLockButton = null; - // we started off the buttons but ended up on a button -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startLockButton = null; - - return null; - } - - // Return the performed action - return action; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusLeft = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusRight = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current+1); -}; - -/** - * Activate lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the button that is going to be activated - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockActivate = function(itemIndex, buttonId) -{ - var action = null; - - switch (buttonId) - { - case 1 : - if (this.dataList.items[itemIndex].locked) - { - this.dataList.items[itemIndex].locked = false; - action = 'unlock'; - } - else - { - this.dataList.items[itemIndex].locked = true; - action = 'lock'; - } - break; - case 2 : - if (!this.dataList.items[itemIndex].locked) - { - action = 'delete'; - } - break; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Update the item - if (domItem) - { - switch (action) - { - case 'lock' : - domItem.classList.add('locked'); - break; - case 'unlock' : - domItem.classList.remove('locked'); - break; - } - } - - return action; -}; - - -/** - * Show focus highlight on a lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the index of the button that will be focused - * @return {integer} - id of the focussed lock button - */ -List2Ctrl.prototype._lockShowFocus = function(itemIndex, buttonId) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - if ('clear' === buttonId) - { - if (domItem) - { - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.remove('focus'); - } - return null; - } - else - { - // validate button id - var buttonId = this.dataList.items[itemIndex].locked ? 1 : this.m.min(this.m.max(buttonId, 1), 2); - - if (domItem) - { - // add focus on the respective button - switch (buttonId) - { - case 1 : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - case 2 : - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.add('focus'); - break; - default : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - } - } - return buttonId; - } -}; - - -/** - * Get currently focused lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - id of the currently focussed lock button - */ -List2Ctrl.prototype._lockGetFocus = function(itemIndex) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - var focussedButton = null; - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (domItem.querySelector('.buttonLock').classList.contains('focus')) - focussedButton = 1; - else if (domItem.querySelector('.buttonDelete').classList.contains('focus')) - focussedButton = 2; - } - - return focussedButton; -}; - - -/* - * ========================= - * STEP ITEM - * ========================= - */ - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {MouseEvent} - raw mouse event - * @return {integer} - the new value - */ -List2Ctrl.prototype._stepAdjust = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // perform hit test - var itemDOMElement = this._getDOMItem(itemIndex); - if (!itemDOMElement) - { - return; - } - - var p = itemDOMElement.querySelector('.plus'); - var m = itemDOMElement.querySelector('.minus'); - var pLayout = { x1:p.offsetLeft, x2:p.offsetLeft + p.clientWidth }; - var mLayout = { x1:m.offsetLeft, x2:m.offsetLeft + m.clientWidth }; - - var newValue = null; - - if (relativeX >= pLayout.x1 && relativeX <= pLayout.x2) - { - // plus pressed - newValue = this._stepUp(itemIndex); - } - else if (relativeX >= mLayout.x1 && relativeX <= mLayout.x2) - { - // minus pressed - newValue = this._stepDown(itemIndex); - } - else if (relativeX < mLayout.x1) - { - newValue = 'commit'; - } - - - return newValue; -}; - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepUp = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.min(this.dataList.items[itemIndex].value + this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].max); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - -/** - * Decrease the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepDown = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.max(this.dataList.items[itemIndex].value - this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].min); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - - -/** - * ========================= - * LIST REORDERING - * ========================= - */ - -/** - * Enter into list reorder mode - * This method stores the original item style of the - * item that is being reordered and substitutes it with - * an internal 'draggable' item style. - * TAG: internal - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype._enterListReorder = function(fromInit) -{ - // keep a copy of the item before converting it to a draggable item - - var focussedIndex; - if (fromInit) - { - focussedIndex = this.properties.focussedItem; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // check for items in the dataList - if (!this.dataList || !this.dataList.items || !this.dataList.items[focussedIndex]) - { - return; - } - - // do not reorder disabled items - if (this.dataList.items[focussedIndex].disabled) - { - return; - } - - // enter into List Reordering mode - this._inListReorder = true; - - this.dataList.items[focussedIndex].itemBehavior = 'shortAndLong'; // make it accept long press (if not already) - this._reorderItem = this.dataList.items[focussedIndex]; - this._reorderItemIndex = focussedIndex; - this._reorderCurrentIndex = focussedIndex; - - // convert the item to a draggable item - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - if(this._reorderItem.itemStyle === "style38") - { - draggableItem.label1 = (this._reorderItem.hasOwnProperty('label1')) ? this._reorderItem.label1 : ''; - draggableItem.label2 = (this._reorderItem.hasOwnProperty('label2')) ? this._reorderItem.label2 : ''; - } - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[focussedIndex] = draggableItem; - this.updateItems(focussedIndex, focussedIndex); - -}; - -/** - * Leave list reorder mode - * The item that is being reordered is restored - * to it initial style. The select callback is - * then fired to notify the interested parties of - * the change and the new position of the item. - * TAG: internal - * ========================= - * @param {Boolean} - prevent item selection when releasing the reorder - * @return {void} - */ -List2Ctrl.prototype._releaseListReorder = function(preventSelect) -{ - // exit list reordering mode - this._inListReorder = false; - this._appIsAtSpeed = false; - - // get draggable item index - var draggableItems = this.getItemsByType('draggable'); - if (!draggableItems.length) - { - return; - } - - var draggableItemIndex = draggableItems[0]; - - // convert the draggable item back into the previous item type - this.dataList.items[draggableItemIndex] = this._reorderItem; - this.updateItems(draggableItemIndex, draggableItemIndex); - - // cast preventSelect as Boolean - var preventSelect = Boolean(preventSelect); - - // selection is allowed - if (!preventSelect) - { - // fire item select - var params = { - newIndex : draggableItemIndex, - oldIndex : this._reorderItemIndex - }; - this._itemSelect(draggableItemIndex, params); - } - - // release the copy of the reorder item - this._reorderItem = null; - this._reorderItemIndex = null; - this._reorderTouchElt = null; - -}; - - -/** - * Touch start reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._startReorder = function(e) -{ - // get target item index - var itemIndex = this._getTargetItem(e); - - // get draggable item index - if (itemIndex === this._reorderCurrentIndex) - { - this._startY = e.pageY - this._maskPositionY; - this._startX = e.pageX - this._maskPositionX; - - // do we have hit on the button? - var positiveButtonHit = this._buttonMakeHit(e); - - if (!positiveButtonHit) - { - this._itemMakeLongPress(e); - - // clone draggable item - var tmp = this._getDOMItem(itemIndex); - this._reorderTouchElt = tmp.cloneNode(true); - this.scroller.appendChild(this._reorderTouchElt); - - // convert the draggable item to a ghost item - var ghostItem = {itemStyle:'ghost', hasCaret:false}; - this.dataList.items[itemIndex] = ghostItem; - this.updateItems(itemIndex, itemIndex); - - this._hideFocus(); - - // raise _inDrag - this._inDrag = true; - } - else - { - // flag the behaviour as release intent - this._releaseReorderByTouch = true; - } - - // track event - this._trackEvent(e); - } -}; - -/** - * Touch move reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._moveReorder = function(e) -{ - if (this._reorderTouchElt) - { - // track event - this._trackEvent(e); - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // get last move - var moveDirection = this._getMoveDirection(); - - // reset any scheduled scrolling if the user intends cacnelling the scroll - if (newPos <= (this._topItem * this.properties.itemHeight) + this.properties.itemHeight && - newPos > this._topItem * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - else if (newPos >= (this._topItem + this.properties.visibleItems - 2) * this.properties.itemHeight && - newPos < (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - - // drag down - if (1 === moveDirection) - { - // have we passed the last item's top border? - if ( (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) && (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) ) - { - this._reorderGhostItemDown(); - } - else if (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) - { - // do we have a scroll down scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos >= (this._reorderCurrentIndex * this.properties.itemHeight) + this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemDown(); - } - } - // drag up - else if (-1 === moveDirection) - { - // have we passed the top item's top border? - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // do we have a scroll up scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos <= (this._reorderCurrentIndex * this.properties.itemHeight) - this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemUp(); - } - } - - } // endif (this._reorderTouchElt) -}; - -/** - * Touch end reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._endReorder = function(e) -{ - if (this._reorderTouchElt) - { - // get nearest snap position - var newSnappedIndex = Math.floor( ( (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) ) / this.properties.itemHeight ); - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = newSnappedIndex * this.properties.itemHeight; - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the scroller if in bounds - this._reorderTouchElt.style.top = newPos + 'px'; - - // convert the ghost item back to a draggable item - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - if(this._reorderItem.itemStyle === "style38") - { - draggableItem.label1 = (this._reorderItem.hasOwnProperty('label1')) ? this._reorderItem.label1 : ''; - draggableItem.label2 = (this._reorderItem.hasOwnProperty('label2')) ? this._reorderItem.label2 : ''; - } - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[this._reorderCurrentIndex] = draggableItem; - this.updateItems(this._reorderCurrentIndex, this._reorderCurrentIndex); - - // remove the cloned element - this._reorderTouchElt.parentElement.removeChild(this._reorderTouchElt); - } - - this._itemRemoveLongPress(); - this._reorderTouchElt = null; - - // reset flags - this._inHorizontalDrag = null; - this._hDragItem = null; - this._inDrag = false; - this._stopSelect = false; - - // restore focus - this._showFocus(this._reorderCurrentIndex); - - // clear any scroll timeout - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - - // are we about to release reorder - if (this._releaseReorderByTouch && this._isToggle(this._reorderCurrentIndex)) - { - // remove hit state of button and release list reorder - this._buttonRemoveHit(this._reorderCurrentIndex); - this._releaseListReorder(); - this._releaseReorderByTouch = false; - } - -}; - -/** - * After the list has scrolled due to touch reorder action, - * upon animation end, the touch reorder item is brought under the - * user's finger and if the possition requires it, a new scroll - * is scheduled. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._bringReorderItem = function() -{ - if (this._trackedEvents.length && this._reorderTouchElt) - { - // get last event - var lastEvent = this._trackedEvents[this._trackedEvents.length-1]; - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (lastEvent.y - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // we are past the top item's top boundary - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemUp(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (0 == this._topItem) - { - // update blank spot - this._reorderGhostItemUp(); - } - else if (this._topItem != this.dataList.itemCount - this.properties.visibleItems && - newPos >= (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemDown(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) - { - // update blank spot - this._reorderGhostItemDown(); - } - - } -}; -/** - * Reorder the item to the index - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {void} - */ -List2Ctrl.prototype._reorderToIndex = function(itemIndex) -{ - if (!this._inListReorder || isNaN(itemIndex)) - { - log.error("list1 _reorderToIndex : Invalid arguments - inListReorder, itemIndex", this._inListReorder, itemIndex); - return; - } - - if (itemIndex != this._reorderItemIndex) - { - if (itemIndex < this._reorderItemIndex) - { - this._reorderItemUp(this._reorderItemIndex - itemIndex) - } - else - { - this._reorderItemDown(itemIndex - this._reorderItemIndex) - } - } -} - -/** - * Reorder the item down - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemDown = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(draggableItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(draggableItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; -/** - * Reorder the item up - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemUp = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(draggableItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, draggableItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; - -/** - * Reorder ghost item one position down - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemDown = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(ghostItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(ghostItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - -/** - * Reorder ghost item one position up - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemUp = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(ghostItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, ghostItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - - -/** - * ========================= - * LIST EVENTS API - * ========================= - */ - -/** - * List event - * TAG: internal - * ========================= - * @param {string} - Event name - * @param {*} - Event data - * @return {void} - */ -List2Ctrl.prototype._listEvent = function(type, data) -{ - var data = data || null; - switch (type) - { - case this._EVENTS.ITEM_SELECT : - this._dispatch(this._EVENTS.ITEM_SELECT, data); - break; - case this._EVENTS.LETTER_SELECT : - this._dispatch(this._EVENTS.LETTER_SELECT, data); - break; - case this._EVENTS.DATALIST_CHANGE : - this._dispatch(this._EVENTS.DATALIST_CHANGE, null); - break; - case this._EVENTS.SCROLL_START : - this._dispatch(this._EVENTS.SCROLL_START, data); - break; - case this._EVENTS.SCROLL_END : - this._dispatch(this._EVENTS.SCROLL_END, data); - break; - case this._EVENTS.CLEAN_UP : - this._dispatch(this._EVENTS.CLEAN_UP, data); - break; - default : - // nothing to do - break; - } -}; - -/** - * Get listeners array for an event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {array} - */ -List2Ctrl.prototype._getListeners = function(type, useCapture) -{ - var captype = (useCapture ? '1' : '0') + type; - if (!(captype in this._eventListeners)) - this._eventListeners[captype] = []; - return this._eventListeners[captype]; -}; - -/** - * Dispatch custom event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {void} - */ -List2Ctrl.prototype._dispatch = function(type, data) -{ - if (!type || '' == type) - return; - var evt = new CustomEvent( type, { detail : { data : data, bubbles: true, cancelable: true } } ); - this.dispatchEvent(evt); -}; - -/** - * Add event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.addEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 === ix) - listeners.push(listener); -}; - -/** - * Remove event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.removeEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 !== ix) - listeners.splice(ix, 1); -}; - -/** - * Displatch custom list event - * TAG: public - * ========================= - * @param {object} - event object - * @return {boolean} - */ -List2Ctrl.prototype.dispatchEvent = function(evt) -{ - var listeners = this._getListeners(evt.type, false).slice(); - for (var i= 0; i dataList.items.length) - { - for (var i=dataList.items.length; i= 0) - { - // force exit secondary multicontroller - this._inSecondaryMulticontroller = false; - - var additionalSpace = this._getAdditionalSpace(); - - this.scroller.style.height = this.dataList.itemCount * this.properties.itemHeight + additionalSpace + 'px'; - this._scrollerH = this.scroller.offsetHeight; - this._emptyScroller(); - this._scrollIndicatorReset(); - if(0 === this.dataList.itemCount) - { - this._scrollIndicatorBuild(false); - } - else - { - this._scrollIndicatorBuild(true); - } - - // set line numbers - this.setLineNumbers(); - } - -}; - -List2Ctrl.prototype.hasDataList = function() -{ - if (this.dataList == null) - { - return false; - } - - if (!this.dataList.hasOwnProperty('itemCountKnown') && !this.dataList.hasOwnProperty('itemCount') && !this.dataList.hasOwnProperty('items')) - { - return false; - } - - if (this.dataList.itemCountKnown && this.dataList.itemCount == 0) - { - return false; - } - - if (!this.dataList.itemCountKnown && this.dataList.itemCount <= 0) - { - return false; - } - - return true; -}; - -/** - * Update Items - * - * This is intended to be used whenever the bound data is changed programmatically by the app. In other words, - * it informs the control that bound data has changed … and if the range of changed items overlaps with items - * rendered into HTML objects, then the ListMenu must update those elements. There are several use cases for this: - * - * 1. For the case where the dataList is fetched asynchronously in the background after ListMenu is displayed, - * the updateItems() API will be called as new data arrives. I think this use case is described fairly completely - * in section 2.2.4 of the ListMenu SDD. Note that these updates may correspond to the user scrolling, or may simply - * occur in the background as the list is loaded into GUI while the user is still looking at the first N list items. - * Also note that the listCount can change and the ListMenu control must adapt appropriately, including handling - * reduction of the list count. - * - * 2. To allow the application to update menu text dynamically, e.g. to display the name of the connected USB - * Audio device instead of “USB”, or to change the displayed image(s). - * - * 3. To allow the application to enable/disable menu items or to set/clear the “selected” indicator. - * - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype.updateItems = function(firstItem, lastItem) -{ - log.debug("List2 updateItems() firstItem, lastItem",firstItem, lastItem); - // update _maxScrollY - this._maxScrollY = this.mask.offsetHeight - this.scroller.offsetHeight; - - var emptyDOMItem = null; - - // clear _needDataTimeoutId - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = null; - - this._prepareItems(firstItem, lastItem); - this._localizeItems(firstItem, lastItem); - - // trim dataList.items if it is larger than dataList.itemCount - if (this.dataList && - this.dataList.itemCountKnown && - this.dataList.items && - this.dataList.itemCount < this.dataList.items.length) - { - this.dataList.items = this.dataList.items.slice(0, this.dataList.itemCount); - console.assert(this.dataList.itemCount == this.dataList.items.length, 'dataList.itemCount is not equal to dataList.items.length'); - } - - // validate first item - if (this.dataList.itemCountKnown && firstItem < -1) - { - log.warn('List2: firstItem is less than -1: ' + firstItem + ' passed. Setting it to -1.'); - firstItem = -1; - } - - // validate last item - if (this.dataList.itemCountKnown && lastItem >= this.dataList.itemCount) - { - log.warn('List2: lastItem is more than or equals dataList.itemCount(' + (this.dataList.itemCount-1) + '): ' + lastItem + ' passed. Setting it to ' + (this.dataList.itemCount - 1) + '. ' + this.uiaId + ' check your variable validation!?'); - lastItem = this.dataList.itemCount - 1; - } - - - // check for invalid items (e.g. firstItem=0, lastItem=-1) -> set loading - if (firstItem > lastItem) - { - firstItem = lastItem = -1; - } - - if (firstItem == -1 && lastItem == -1) - { - // we have dataList but no list items => show loading - this._setLoading(true); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem && !this._hasFill) - { - - - // we have dataList and we have list items but we do not have fill => do initial fill - var lastFillItem = this.m.min(lastItem, this.properties.itemsBefore + this.properties.itemsAfter); - - this._fill(firstItem, lastFillItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - if (this.properties.focussedItem < this.dataList.itemCount) - { - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - else - { - this.properties.focussedItem = this.dataList.itemCount - 1; - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - /* - * Immediately scroll to a preset location and - * show focus on preset item if this is specified - * in the control's config. Focus placement needs to be done - * after the DOM is refreshed. This is done only the - * first time after a fresh setDataList() call. - * Focussed item has precedence over scroll location. - */ - if (null === this._initialScrollMode) - { - // first check if the focussed item and the scroll position are all on the same screen - // scroll to that position and show the focus according to the config - if ( (this.properties.focussedItem >= 0 || this.properties.scrollTo >= 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 1)) ) - { - log.debug('Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // set initial focus to a particular item if this is set in the config - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem >= 0) - { - log.debug('Focus is not visible and has priority'); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // scroll (no animation) to a particular item if this is set in the config - // the focus will be placed on the top item - else if (this.properties.scrollTo >= 0) - { - log.debug('Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._topItem = this._canGainFocus(this._topItem); - this._showFocus(this._topItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - } - // sync the top item with focus if not in initial mode any more - // enter in this case usualy when a new data list is set - else - { - var focussedItem = this.focussedItem; - var topInFocusRange = focussedItem >= this.topItem && focussedItem < this.topItem + this.properties.visibleItems - 1; - var prevTopInFocusRange = focussedItem >= this._prevTopItem && focussedItem < this._prevTopItem + this.properties.visibleItems - 1; - if (!topInFocusRange && !prevTopInFocusRange) - { - this.topItem = focussedItem; - } - else if (!topInFocusRange && prevTopInFocusRange) - { - this.topItem = this._prevTopItem; - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem) - { - // preserve focussed element - var lastFocussedIndex = this._getFocussedIndex(); - - // we have dataList and we have list items, and we have fill => perform update - this._updateDisplay(firstItem, lastItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - // restore focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(lastFocussedIndex, true); - } - else if (this._inSecondaryMulticontroller) - { - // treat disabling the secondary multicontroller item as interrupt -> commit value and exit - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this.dataList.items[smi].disabled) - { - this._setSecondaryMulticontroller(false, smi); - this._showFocus(smi, true); - } - else if (this.dataList.items[smi]) - { - this._setSecondaryMulticontroller(true, smi); - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else - { - log.error(this.uiaId + ' called List2 updateItems() with invalid arguments: firstItem = ' + firstItem + ', lastItem = ' + lastItem); - } - - // suppress secondary item request when the list is in reorder mode - if (this.properties.enableSecondaryItemRequest && !this._inListReorder) - { - // do we have empty DOM items? - if (null == emptyDOMItem) - { - // clear _secondaryRequestCount - this._secondaryRequestCount = 0; - } - else if (this._secondaryRequestCount <= this.properties.secondaryRequestLimit) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - // increment _secondaryRequestCount - this._secondaryRequestCount++; - } - else - { - log.warn('Lis2: control has reached the secondary request count limit. Enabling the list'); - // we have reached secondaryRequestLimit -> set loading to False - this._setLoading(false); - } - } - - // restore the focus to the last focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(this._lastItemWithFocus, true); - } - -}; - - -/** 2. LETTER INDEX API **/ - -/** - * Set letter index data on demand, filling letters in the letter index area - * and assigning jump indices to them, so that when touched or selected - * by multicontroller, the list jumps to the respective index. - * TAG: public - * ========================= - * @param {data} - letter index data object - * @return {boolean} - True if letter index binding operation is a success - */ -List2Ctrl.prototype.setLetterIndexData = function(data) -{ - // validate input - if (!(data instanceof Array)) - { - log.error('Lis2: letter index data should be a valid array'); - return false; - } - - // validate control support - if (!this.properties.hasLetterIndex) - { - log.error('Lis2: list2 does not support letter index'); - return false; - } - - // reset any previous letter index data - this.letterIndexData = []; - this.letterIndex.innerText = ''; - - var letterIndexItem; - var label; - for (var i=0, l=data.length; i= 0) - { - this._letterIndexDataSorted[this._letterIndexDataSorted.length] = { - publicIndex : this.letterIndexData.length-1, - itemIndex : data[i].itemIndex - }; - } - } - - // sort private and filtered letter index by the itemIndex in ASC order - this._letterIndexDataSorted.sort(function(a,b) { - var compRes = 0; - if (a.itemIndex < b.itemIndex) - compRes = -1; - else if (a.itemIndex > b.itemIndex) - compRes = 1; - else - compRes = 0; - return compRes; - }); - - // set letter index scroller height - var additionalSpace = Math.ceil(this.properties.letterIndexHeight / 2) - 5; // adjusting factor - this.letterIndex.style.height = i * this.properties.letterIndexHeight + additionalSpace + 'px'; - this._scrollerHIndex = this.letterIndex.offsetHeight; - - // update _maxScrollYIndex - this._maxScrollYIndex = this.letterIndexWrapper.offsetHeight - this.letterIndex.offsetHeight; - - // set initial active letter index if there are any available - if (this.hasDataList() && this._letterIndexDataSorted.length) - { - // get current focus index and first letter index - var focussedIndex = this._getFocussedIndex(); - var firstIndex = this._letterIndexDataSorted[0].itemIndex; - - if (firstIndex > 0 && focussedIndex < firstIndex) - { - this._setLetterIndexPosition(firstIndex); - } - else - { - this._setLetterIndexPosition(focussedIndex); - } - - } - else if (this._letterIndexDataSorted.length) - { - this._setLetterIndexPosition(this._letterIndexDataSorted[0].itemIndex); - } -}; - - -/** 3. VOICE API **/ - -/** - * Set left button configuration depending on current list configuration: - * title style, visible items, item count, item thickness - * TAG: public, VUI - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setLineNumbers = function() -{ - // check if we need to show numbers - if (!this.properties.numberedList) - { - return; - } - - // check if we have some items to number - if (!this.dataList.hasOwnProperty('itemCount') || this.dataList.itemCount <= 0) - { - return; - } - - - var style = ''; - var maxItemCount = 0; - - // determine max item count and style - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - maxItemCount = this.properties.thickItems ? 5 : 6; - style = this.properties.thickItems ? 'Style02' : 'Style04'; - break; - case 'tabsTitle' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style03a' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'style05' : - case 'style08' : - maxItemCount = 4; - style = this.properties.thickItems ? 'Style07' : 'Style06'; - break; - case 'style06' : - case 'style07' : - maxItemCount = 3; - style = this.properties.thickItems ? 'Style09' : 'Style08'; - break; - default : - log.warn('Lis2: unknown title style: ' + this._currentTitle.titleStyle); - return; - break; - } - break; - default : - log.warn('Lis2: unknown title configuration: ' + this.properties.titleConfiguration); - return; - break; - } - - // get actual item count - var itemCount = this.m.min(this.dataList.itemCount, maxItemCount); - - // check for common API - if (framework.common.setLineNumbers) - { - // call LeftBtnCtrl to show list numbers - return framework.common.setLineNumbers(itemCount, style); - } - -}; - -/** - * Performs select on the specified line number. When the select callback is fired, - * fromVui parameter is set to true. The function can return several possible - * statuses depending on the output of the operation. - * TAG: public, VUI - * ========================= - * @param {integer} - the line number that needs to be selected - * @return {string} - 'selected', 'outOfRange', 'disabled', 'sendAck', 'noList' - */ -List2Ctrl.prototype.selectLine = function(lineNumber) -{ - // get target item - var targetIndex = this._topItem + (lineNumber - 1); - - // decide what to return depending on what's visible - var status; - - // check if the list supports line numbers - if (!this.hasDataList()) - { - status = 'noList'; - log.debug('Lis2: selectLine() called with no list on the screen'); - } - else if (!this.dataList.vuiSupport) - { - status = 'noList'; - log.debug('Lis2: no VUI support for this list'); - } - else if (targetIndex > this.dataList.itemCount - 1 || targetIndex < 0) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (targetIndex < this._topItem || targetIndex > this._topItem + this.properties.visibleItems) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (!this.dataList.items[targetIndex].vuiSelectable) - { - status = 'notSelectable'; - log.debug('Lis2: list item is not VUI selectable'); - } - else if (this.dataList.items[targetIndex].disabled) - { - status = 'disabled'; - log.debug('Lis2: list item is disabled'); - this._itemSelect(targetIndex, {fromVui:true, vuiStatus:status}); - } - else - { - // default status is 'selected' -> if the item is not selectable, the callback will not be fired - var selectResult = this._itemSelect(targetIndex, {fromVui:true, vuiStatus:'selected'}); - if (true === selectResult) - { - // normal enabled status - status = 'selected'; - } - else if (false === selectResult) - { - // status if no select callback is attached - status = 'sendAck'; - } - else - { - // returned status from the select callback in the app - status = selectResult; - } - } - - return status; -}; - -/** - * Scrolls the list one page down. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageDown = function() -{ - var status = this._scrollDownPage(); - return status; -}; - -/** - * Scrolls the list one page up. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageUp = function() -{ - var status = this._scrollUpPage(); - return status; -}; - - -/** 4. SLIDER / TOGGLE API **/ - -/** - * Set slider to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the slider/pivot item - * @param {number} - the new value of the slider/pivot - * @return {void} - */ -List2Ctrl.prototype.setSliderValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isSlider(itemIndex)) - { - log.warn(this.uiaId + ': Lis2: only sliders/pivots can be used in the Slider API. Item style ' + item.itemStyle + ' passed'); - return; - } - - var slider = this._getSlider(itemIndex); - if (slider) - { - slider.setValue(value); - } - else - { - log.error(this.uiaId + ': Lis2: could not get slider instance for itemIndex ' + itemIndex); - } -}; - - -/** - * Set toggle to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the toggle item - * @param {number} - the new value of the toggle - * @return {void} - */ -List2Ctrl.prototype.setToggleValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.debug('Item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isToggle(itemIndex) && item.itemStyle != 'styleOnOff') - { - log.warn('Lis2: only toggle items can be used in the Toggle API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // normalize value - if (item.itemStyle == 'style10') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - else if(item.itemStyle == 'style11') - { - var value = this.m.max(this.m.min(value, 3), 1); - } - else if(item.itemStyle == 'styleOnOff') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'toggle')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'checkbox')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // cast as boolean - var value = Boolean(value); - - // set value - item.checked = value; - - // update item - this.updateItems(itemIndex, itemIndex); -}; - - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setRadio = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'radio')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setRadio = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'tick')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a tick item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the tick item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setTick = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an empty range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // filled item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get filled range - * traverse the dataList.items for filled items and returns - * an array of filled-item ranges - * TAG: public - * ========================= - * @return {array} - Array([firstFilled, lastFilled], [firstFilled, lastFilled]) - */ -List2Ctrl.prototype.getFilledRange = function() -{ - var ranges = []; - var currentRange = []; - - for (var i=0, l=this.dataList.items.length; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an filled range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // empty item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get current focus mode - * TAG: public - * ========================= - * @return {string} - 'mainList' | 'letterIndex' | 'noFocus' - */ -List2Ctrl.prototype.getFocusMode = function() -{ - var currentFocusMode = 'mainList'; - if (!this._hasFocus) - { - currentFocusMode = 'noFocus'; - } - else if (this._inLetterIndexMulticontroller) - { - currentFocusMode = 'letterIndex'; - } - - return currentFocusMode; -}; - - -/** 7. OTHER **/ - -/** - * Set loading state of the list - * TAG: public - * ========================= - * @param {boolean} - enable or disable loading state - * @return {void} - */ -List2Ctrl.prototype.setLoading = function(state) -{ - // cast as boolean - var state = Boolean(state); - this._setLoading(state); -}; - - -/** - * Public API that changes the loading configuration - * ========================= - * @param {Object} - object that will set loading item configuration - * @return {Object} - retuns the loading configuration object - */ -List2Ctrl.prototype.setLoadingConfig = function (config) -{ - for (var i in config) - { - this.properties.loadingConfig[i] = config[i]; - } - - if (null !== this.properties.loadingConfig.loadingTextId && undefined !== this.properties.loadingConfig.loadingTextId && "" !== this.properties.loadingConfig.loadingTextId) - { - this.properties.loadingConfig.loadingText = this._getLocalizedString(this.properties.loadingConfig.loadingTextId, this.properties.loadingConfig.loadingSubMap); - } - this.loading.querySelector(".loadingText").innerText = ""; - this.loading.querySelector(".loadingText").appendChild(document.createTextNode(this.properties.loadingConfig.loadingText)); - this.loading.querySelector(".loadingImage1").style.backgroundImage = 'url(' + this.properties.loadingConfig.loadingImage1 + ')'; - - return this.properties.loadingConfig; -}; - -/** - * Enter or release reorder mode - * TAG: public - * ========================= - * @param {boolean} - enter or release list reorder - * @param {boolean} - prevent item select on releasing reorder - * @return {void} - */ -List2Ctrl.prototype.setReorder = function(state, preventSelect) -{ - // cast as boolean - var state = Boolean(state); - var preventSelect = Boolean(preventSelect); - - if (state && !this._inListReorder) - { - // if user has lost the reorder item - if (null != this._reorderCurrentIndex && (this._reorderCurrentIndex < this._topItem || this._reorderCurrentIndex > this._topItem + this.properties.visibleItems-1)) - { - if (this.dataList.items[this._reorderCurrentIndex] && !this.dataList.items[this._reorderCurrentIndex].disabled) - { - // reorder item is outside screen. Bring it back in and show focus on it - this._showFocus(this._reorderCurrentIndex); - } - } - - // enter into reorder - this._enterListReorder(); - } - else if (!state && this._inListReorder) - { - // release reorder - this._releaseListReorder(preventSelect); - } -}; - -/** - * Enter or release reorder mode - * TAG: public - * ========================= - * @param {boolean} - enter or release list reorder - * @return {void} - */ -List2Ctrl.prototype.setReorderAtSpeed = function(AtSpeed) -{ - if(AtSpeed) - { - this._inListReorder = false; - this._appIsAtSpeed = AtSpeed ; - this.properties.listReorder = false; - } - else - { - this._inListReorder = true; - this._appIsAtSpeed = AtSpeed ; - this.properties.listReorder = true; - } -}; - -/** - * Set fixed title for the list - * TAG: public - * ========================= - * @param {object} - title properties - * @return {void} - */ -List2Ctrl.prototype.setTitle = function(titleStructure) -{ - - // validate titleStructure - if (!titleStructure || !titleStructure.hasOwnProperty('titleStyle')) - { - return; - } - - /* - * title structure: - * { - * titleStyle : 'style02', - * text1Id : null, - * text1SubMap : null, - * text1 : '', - * image1 : 'path/to/image.png' - * } - */ - - // prepare title - var titleStructure = titleStructure || {}; - titleStructure = this._prepareTitle(titleStructure); - - if (this._currentTitle) - { - // we already have a title -> update it - - // validate new title - switch (titleStructure.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - // thin - if ('style02' != this._currentTitle.titleStyle && - 'style02a' != this._currentTitle.titleStyle && - 'style03' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style05' : - case 'style08' : - // medium - if ('style05' != this._currentTitle.titleStyle && - 'style08' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style06' : - case 'style07' : - // thick - if ('style06' != this._currentTitle.titleStyle && - 'style07' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - } - } - - // empty title element - this.title.innerText = ''; - // remove old title style class - if (this._currentTitle) - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - this.title.classList.remove(this._currentTitle.titleStyle); - } - // add title style as a class - this.title.classList.add(titleStructure.titleStyle); - - // fill it - var line1, line2, image1; - - switch (titleStructure.titleStyle) - { - case 'style02' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style02a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style03' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style05' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleMedium'); - - break; - - case 'style06' : - - if (titleStructure.image1 === 'canvas') - { - // preview image is a canvas - image1 = document.createElement('canvas'); - image1.className = 'image1'; - // store canvas for public API call - this.titleCanvas = image1; - this.title.appendChild(image1); - } - else - { - // preview image is an image - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - } - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style07' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style08' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleMedium'); - - break; - - default : - log.error('Lis2: unknown title style: ' + titleStructure.titleStyle); - } - - // save the title structure - this._currentTitle = titleStructure; - -}; - - -/** 8. CONTEXT CAPTURE AND RESTORE **/ - -/** - * Context capture - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.getContextCapture = function() -{ - var obj = { - hasFocus : this._hasFocus, - topItem : this._topItem, - focussedItem : this._getFocussedIndex(), - itemCount : this.dataList ? this.dataList.itemCount : 0 - }; - - log.debug('Lis2: getContextCapture obj ', obj); - return obj; -}; - -/** - * Context restore - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.restoreContext = function(restoreData) -{ - log.debug('Lis2: restoreContext restoreData ', restoreData); - // validate input - if (!restoreData.hasOwnProperty('topItem') || !restoreData.hasOwnProperty('focussedItem')) - { - log.info('No data to restore'); - return; - } - - - // restore hasFocus flag - if (restoreData.hasFocus) - { - this._hasFocus = true; - } - - if (this.hasDataList()) - { - // scroll to previous position and show previous focus - // no checks for value conflicts are necessary. These ought to be correct. - this._scrollTo(restoreData.topItem); - - // NOTE: actual focus placement happens in controllerActive event handling - - // mark the list as data-restored preventing any subsequent auto-scrolls - this._initialScrollMode = 'restore'; - - this._manageFocus(restoreData.focussedItem); - } - else - { - log.info('List has no dataList to restore'); - } - - // overwrite control properties - this.properties.scrollTo = restoreData.topItem; - this.properties.focussedItem = restoreData.focussedItem; - this._lastItemWithFocus = restoreData.focussedItem; -}; - - -/** 9. BACKGROUND API **/ - -/** - * Set a custom background on the list control - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setListBackground = function(img, position) -{ - this.clearListBackground(); - this.listBackground = document.createElement('div'); - this.listBackground.className = 'List2CtrlCustomBackground'; - this.listBackground.style.backgroundImage = 'url('+img+')'; - - // set background position - if (position && typeof position == 'object' && position['left'] != undefined && position['top'] != undefined) - { - var left = (!isNaN(position['left'])) ? position.left + 'px' : position.left.toString(); - var top = (!isNaN(position['top'])) ? position.top + 'px' : position.top.toString(); - this.listBackground.style.backgroundPosition = left + ' ' + top; - } - - this.divElt.appendChild(this.listBackground); -}; - -/** - * Clear any custom background image - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.clearListBackground = function() -{ - if (this.listBackground) - { - this.listBackground.parentElement.removeChild(this.listBackground); - this.listBackground = null; - } -}; - - - -/** - * ========================= - * HELPERS AND UTILITIES - * ========================= - */ - - /** - * Create Tabs control - * ========================= - * @return The TabsCtrl instance. - */ -List2Ctrl.prototype._createTabsControl = function() -{ - log.debug(' Instantiating TabsCtrl'); - if (this.properties.tabsButtonConfig.tiltStartCallback) - { - log.warn("Lis2: the tabsButtonConfig.tiltStartCallback property was defined outside of the list control but should only be used by the list."); - } - this.properties.tabsButtonConfig.tiltStartCallback = this._tabsCtrlTiltStartCallback.bind(this); - return framework.instantiateControl(this.uiaId, this.divElt, "TabsCtrl", this.properties.tabsButtonConfig); -}; - -/** - * Clear the list contents when the user starts tilting to a new tab. - */ -List2Ctrl.prototype._tabsCtrlTiltStartCallback = function(controlRef, appData, params) -{ - if (this.title) - { - this.title.style.opacity = 0; - } - this.setDataList({}); - this._hideScrollIndicator(); -}; - - -/** - * Tracks touch position properties of the last two events. - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - MouseMove event - * @return {void} - */ -List2Ctrl.prototype._trackEvent = function(e) -{ - // use shallow copy - var trackedEvents = this._trackedEvents; - trackedEvents[0] = trackedEvents[1]; - trackedEvents[1] = { y: e.pageY, x: e.pageX }; -}; - -/** - * Get touch direction upon touch move - * TAG: touch-only, internal - * ========================= - * @return {integer} - 1 for 'down', -1 for 'uo' - */ -List2Ctrl.prototype._getMoveDirection = function() -{ - var trackedEvents = this._trackedEvents, - event0 = trackedEvents[0], - event1 = trackedEvents[1]; - - if (!event0) return 1; - - return (event1.y - event0.y < 0) ? -1 : 1; -}; - -/** - * Get current list position (or specific position relative to supplied item index) - * TAG: internal - * ========================= - * @param {integer} - optional, item index from which to calculate position - * @return {string} - onepage | top | bottom | bottomclose | topclose | middle - */ -List2Ctrl.prototype._getListPosition = function(itemIndex) -{ - // get item index - var itemIndex = (undefined === itemIndex) ? this._topItem : itemIndex; - - // get list position - var listPosition = null; - - // determine list position - if (this.dataList.itemCount <= this.properties.visibleItems) - listPosition = 'onepage'; - else if (0 === itemIndex) - listPosition = 'top'; // list is at the top - else if (itemIndex === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; // list is at the bottom - else if (itemIndex > this.dataList.itemCount - (2 * this.properties.visibleItems)) - listPosition = 'bottomclose'; // list is less than a screen to the bottom - else if (itemIndex < 2 * this.properties.visibleItems) - listPosition = 'topclose'; // list is less than a screen to the top - else - listPosition = 'middle'; // list is somewhere in the middle - - // return list position - return listPosition; -}; - - -/** - * Get additional space that needs to be added to the scroller - * height in order to satisfy the 'half-line' requirements. - * Correction is needed because there's a difference between - * visual style guide and actual item heights. The values are - * fixed and depend on the style. - * TAG: helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getAdditionalSpace = function() -{ - // determine additional space - var additionalSpace = 0; - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - additionalSpace = this.properties.thickItems ? 6 : 32; - break; - case 'tabsTitle' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style03' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'style05' : - case 'style08' : - additionalSpace = this.properties.thickItems ? 52 : 42; - break; - case 'style06' : - case 'style07' : - additionalSpace = this.properties.thickItems ? 60 : 32; - break; - default : - // nothing to do - break; - } - break; - default : - // nothing to do - break; - } - - - - return additionalSpace; -}; - -/** - * Get empty DOM elements - * Return the first element in the DOM that doesn't - * have data associated with it in the dataList - */ -List2Ctrl.prototype._getEmptyDOMElement = function() -{ - var emptyItem = null; - var items = []; - - // get item indeces and sort them in ascending order - for (var i=0; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var itemIndex = Math.floor(relativeY / this.properties.itemHeight); - - // if we are in the active area but below the last item -> return -1 - if (itemIndex > this.dataList.itemCount - 1) - { - return -1; - } - - // constrain itemIndex to the max possible index - itemIndex = this.m.min(itemIndex, this.dataList.itemCount - 1); - - return itemIndex; -}; - -/** - * Get DOM Element by itemIndex - * Returns a DOM element (or null) for a particular - * item after performing a search for its item index - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {HTML Element} -
  • element - */ -List2Ctrl.prototype._getDOMItem = function(itemIndex) -{ - var domItem = null; - - for (var i=0, l=this.items.length; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var letterIndex = Math.floor(relativeY / this.properties.letterIndexHeight); - - // if we are in the active area but below the last letter index item -> return -1 - if (letterIndex > this.letterIndexData.length - 1) - { - return -1; - } - - // constrain letterIndex to the max possible index - letterIndex = this.m.min(letterIndex, this.letterIndexData.length - 1); - - return letterIndex; -}; - -/** - * Get Slider instance by itemIndex - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {SliderCtrl} - slider instance - */ -List2Ctrl.prototype._getSlider = function(itemIndex) -{ - var sliderCtrl = null; - - var index; - if (utility.toType(itemIndex) === 'number') - { - index = itemIndex; - } - else - { - index = this._getFocussedIndex(); - } - - var domElt = this._getDOMItem(index); - if (domElt) - { - var poolId = domElt.getAttribute('data-poolid'); - var hashKey = 'slider_'+index+'_'+poolId; - - // check whether a slider exists - if (this._sliders.hasOwnProperty(hashKey) && this._sliders[hashKey].slider) - { - sliderCtrl = this._sliders[hashKey].slider; - } - } - - return sliderCtrl; -}; - -/** - * Checks whether the supplied itemIndex contains a slider - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains a slider - */ -List2Ctrl.prototype._isSlider = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSlider = false; - - if (!isNaN(itemIndex)) - { - isSlider = ('style12' === this.dataList.items[itemIndex].itemStyle || 'style13' === this.dataList.items[itemIndex].itemStyle || 'style28' == this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSlider = ('style12' === itemIndex || 'style13' === itemIndex|| 'style28' === itemIndex); - } - - return isSlider; -}; - -/** - * Checks whether the supplied itemIndex is a lock item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a lock item - */ -List2Ctrl.prototype._isLock = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isLock = false; - - if (!isNaN(itemIndex)) - { - isLock = ('styleLock' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isLock = ('styleLock' === itemIndex); - } - - return isLock; -}; - -/** - * Checks whether the supplied itemIndex contains toggle buttons - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains toggle buttons - */ -List2Ctrl.prototype._isToggle = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isToggle = false; - - if (!isNaN(itemIndex)) - { - isToggle = ('style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle || 'draggable' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isToggle = ('style10' === itemIndex || 'style11' === itemIndex || 'draggable' === itemIndex); - } - - return isToggle; -}; - -/** - * Checks whether the supplied itemIndex is On/Off item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is On/Off - */ -List2Ctrl.prototype._isOnOff = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isOnOff = false; - - if (!isNaN(itemIndex)) - { - isOnOff = ('styleOnOff' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isOnOff = ('styleOnOff' === itemIndex); - } - - return isOnOff; -}; - -/** - * Checks whether the supplied itemIndex is a step item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a step item - */ -List2Ctrl.prototype._isStep = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isStep = false; - - if (!isNaN(itemIndex)) - { - isStep = ('styleStep' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isStep = ('styleStep' === itemIndex); - } - - return isStep; -}; - -/** - * Checks whether the supplied itemIndex is a checkbox - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a checkbox/tick/radio item - */ -List2Ctrl.prototype._isCheckBox = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isCheckbox = false; - - if (!isNaN(itemIndex)) - { - isCheckbox = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isCheckbox = ('style03' === itemIndex || 'style03a' === itemIndex); - } - - return isCheckbox; -}; - -/** - * Checks whether the supplied itemIndex is a simple select item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is simple select item - */ -List2Ctrl.prototype._isSimpleSelectItem = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSimpleSelect = false; - - if (!isNaN(itemIndex)) - { - isSimpleSelect = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle || 'styleOnOff' === this.dataList.items[itemIndex].itemStyle || 'style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSimpleSelect = ('styleOnOff' === itemIndex || 'style10' === itemIndex || 'style11' === itemIndex); - } - - return isSimpleSelect; -}; - -/** - * Checks whether the item contains _data property - * TAG: internal, helper - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item contains _data property - */ -List2Ctrl.prototype._hasData = function(itemIndex) -{ - var containsData = false; - if (this.dataList && this.dataList.items && this.dataList.items[itemIndex]) - { - containsData = this.dataList.items[itemIndex].hasOwnProperty('_data'); - } - return containsData; -}; - -/** - * Wraps inline text element if the width exceeds certain - * max width that depends on the item style. - * TAG: internal, helper - * ========================= - * @param {HTML Li Element} - the LI element that will be searched for overflowing text - * @return {HTML Li Element} - the modified LI element - */ -List2Ctrl.prototype._wrapInlineElement = function(li) -{ - var searchClass = null; - var maxWidth = 0; - - if (li.classList.contains('style17')) - { - searchClass = 'line1'; - maxWidth = this.properties.wrapTextThreshold; - } - else - { - return li; - } - - var line1 = li.getElementsByClassName(searchClass); - if (!line1 || 0 === line1.length) - { - return li; - } - else - { - line1 = line1[0]; - } - - if (line1.clientWidth > maxWidth) - { - line1.classList.add("wrap"); - } - else - { - line1.classList.remove("wrap"); - } - - return li; -}; - -/** - * Checks if the item can be displayed, even if it has no text field. - * TAG: internal, helper - * ===================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._displayWithoutText = function(item) -{ - var returnValue = true; - for(var i =0; i < this._itemsWithNoText.length; i++) - { - if(item.itemStyle === this._itemsWithNoText[i]) - { - returnValue = false; - break; - } - } - return returnValue; -}; - -/** - * Checks if the item is a slider with full hittable area - * TAG: internal, helper - * =================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._hasRightHittableArea = function(item) -{ - var returnValue = false; - - for(var i =0; i < this._rightHittableArea.length; i++) - { - if(item.itemStyle === this._rightHittableArea[i]) - { - returnValue = true; - break; - } - } - return returnValue; -}; - - -/** - * Show bounding boxes of some elements in the list. - * This should be used for debugging purposes only - * TAG: internal, utility - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype.showBoundingBoxes = function(state) -{ - if (state) - { - this.divElt.classList.add('showBoundingBoxes'); - } - else - { - this.divElt.classList.remove('showBoundingBoxes'); - } -}; - - -/** - * Searches an array for a value - * TAG: internal, utility - * ========================= - * @param {string|number} - * @param {array} - * @return {object} - copy of the source object - */ -List2Ctrl.prototype.inArray = function(needle, haystack) -{ - if (!needle || !haystack) - { - log.warn('Lis2: 2 arguments expected'); - return; - } - - for (var i=0, l=haystack.length; i b ? a : b // return the higher - : NaN; // else return NaN (just like the Math class) - }, - abs : function(a) - { - return (!isNaN(a)) ? // if the argument is a number - a < 0 ? -a : a // return the abs - : NaN; // else return NaN (just like the Math class) - } -}; - -/** - * Finish partial activity. - * @return {void} - */ -List2Ctrl.prototype.finishPartialActivity = function() -{ - // route finish partial activity to sub controls - - // tabs ctrl - if (this.tabsCtrl) - { - // delete the assigned callback reference so that it's not stored in the App's context table - delete this.properties.tabsButtonConfig.tiltStartCallback; - this.tabsCtrl.finishPartialActivity(); - } - - // slider - if (this._activeSlider && this._activeSlider.slider) - { - this._activeSlider.slider.finishPartialActivity(); - } - - // list -> exit any items in secondary MC mode - if (this._inSecondaryMulticontroller) - { - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this._isStep(smi)) - { - this._setSecondaryMulticontroller(false); - this._triggerFocus(); - } - } -}; - -List2Ctrl.prototype.getStationAndRelay = function(stationName,RelayName) -{ - var stationRelay = ""; - if(stationName && RelayName) - { - stationRelay = stationName+" ("+RelayName+")"; - } - else if(stationName && ((RelayName=="")||(RelayName==null))) - { - stationRelay = stationName; - } - else{ - log.debug("Station name and relay not defined"); - } - - return stationRelay; -}; - - -/** - * ========================= - * GARBAGE COLLECTION - * - Clear listeners - * - Clean up subcontrols - * - Clear timeouts - * TAG: framework - * ========================= - * @return {void} - */ -List2Ctrl.prototype.cleanUp = function() -{ - // remove event callbacks - this.divElt.removeEventListener(this._USER_EVENT_START, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - - // remove animation callbacks - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - if (this.scrollIndicator) - { - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - } - if (this.letterIndex) - { - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - } - - // clean up subcontrols - if (this.tabsCtrl) - { - this.tabsCtrl.cleanUp(); - } - for (var i in this._sliders) - { - this._sliders[i]['slider'].cleanUp(); - } - - // clear timeouts - clearTimeout(this._makeHitTimeoutId); - clearTimeout(this._longPressTimeoutId); - clearTimeout(this._touchReorderTimeoutId); - clearTimeout(this._scrollIndicatorTimeoutId); - clearTimeout(this._indexSelectTimeoutId); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - clearTimeout(this._needDataTimeoutId); - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - clearTimeout(this._radioSettleTimeoutId); - clearTimeout(this._tickSettleTimeoutId); - if (this.hasDataList()) - { - for (var i=0, l=this.dataList.items.length; i 0 || this.properties.scrollTo > 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 2)) ) - { - log.debug('Lis2: Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // set initial focus to a particular item if the list is populated - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem > 0) - { - log.debug('Lis2: Focus is not visible and has priority'); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // scroll (no animation) to a particular item if the list is populated - // the focus will be placed on the top item - else if (this.properties.scrollTo > 0) - { - log.debug('Lis2: Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this._topItem); - this._initialScrollMode = 'init'; - } - - // enter list reorder if the list is reordable - if (true === this.properties.listReorder) - { - this._enterListReorder(true); - } - - } - } - else - { - this._setLoading(true); - } - - - /* SET LETTER INDEX DATA */ - if (this.properties.hasLetterIndex && this.properties.letterIndexData) - { - // bind letter index data - this.setLetterIndexData(this.properties.letterIndexData); - } - - /* SET CUSTOM LIST BACKGROUND */ - if (null != this.properties.listBackground && '' != this.properties.listBackground) - { - this.setListBackground(this.properties.listBackground); - } - -}; - - -/** - * ========================= - * LIST ITEMS - * 1. pool (_createPool) - * 2. default items configuration (_prepareItems, _prepareListItem) for every item style - * 3. items localization (_localizeItems, _getLocalizedString) - * 4. pool operations (_setText, _setImage, _getListItem, _returnListItem, _putToScroller, _emptyScroller) - * 5. dynamic list items (_updateRange, _updateDisplay, _requestMore, _fill) - * 6. set internal properties (_checkScrollable, _setTopListItem, _setLoading) - * 7. default title configuration (_prepareTitle) - * ========================= - */ - -/** 1. POOL **/ - -/** - * Create list items pool - * Add HTML elements to each item in the pool - * depending on its style - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._createPool = function() -{ - this.pool = { - empty : new Array(), // 'empty' is internal style - draggable : new Array(), // 'draggable' is internal style - ghost : new Array(), // 'ghost' is internal style - - style01 : new Array(), - style02 : new Array(), - style03 : new Array(), - style03a : new Array(), - style04 : new Array(), - style05 : new Array(), - style06 : new Array(), - style07 : new Array(), - style09 : new Array(), - style10 : new Array(), - style11 : new Array(), - style12 : new Array(), - style13 : new Array(), // deprecated - style14 : new Array(), - style17 : new Array(), - style18 : new Array(), - style19 : new Array(), - style20 : new Array(), - style21 : new Array(), - style22 : new Array(), - // TODO: style23 - same as style12 - // TODO: style24 - same as style12 - style25 : new Array(), - styleOnOff : new Array(), // not official name - styleStep : new Array(), // TODO: rename this to style26 - styleLock : new Array(), // not official name - style28 : new Array(), - style29 : new Array(), - style38 : new Array() - }; - - // the pool size (this.properties.poolsize) should be at least 3 times - // the visible items (one for above and two for below the top item) - var line1, line2, - image1, image2, - label1, label2, - button1, button2, button3, - caret; - - for (var i in this.pool) - { - for (var j=0; j no content - break; - - case 'draggable' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - button1 = document.createElement('span'); - button1.className = 'button buttonOk'; - li.appendChild(button1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - break; - - case 'ghost' : - // ghost item -> no contet - break; - - case 'style01' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style02' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style04' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style05' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style06' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style07' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style09' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style10' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - break; - - case 'style11' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - button3 = document.createElement('span'); - button3.className = 'button button3'; - buttonsWrapper.appendChild(button3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style12' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style13' : - // style13 is deprecated - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style14' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style17' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - // label is inside line1 element to allow natural text flow - label1 = document.createElement('span'); - label1.className = 'label1'; - line1.appendChild(label1); - - break; - - case 'style18' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - break; - - case 'style19' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style20' : - button1 = document.createElement('span'); - button1.className = 'button1'; - li.appendChild(button1); - - break; - - case 'style21' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style22' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style25' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'styleOnOff' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'styleStep' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - var plusSign = document.createElement('span'); - plusSign.className = 'plus'; - li.appendChild(plusSign); - - var minusSign = document.createElement('span'); - minusSign.className = 'minus'; - li.appendChild(minusSign); - - break; - - case 'styleLock' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2 buttonLock'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3 buttonDelete'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style28' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style29' : - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - break; - - case 'style38' : - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - break; - - default : - log.error('List2: unknown list item style in pool: ' + i); - break; - - } - - // add common elements - caret = document.createElement('span'); - caret.className = 'caret'; - li.appendChild(caret); - - - this.pool[i].push(li); - } - } - -}; - -/** 2. DEFAULT ITEMS CONFIGURATION **/ - -/** - * Prepare items - * Extend the whole dataList so that every item - * meet the required structure. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._prepareItems = function(firstItem, lastItem) -{ - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) || (lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - for (var i=firstItem, l=lastItem; i<=l; i++) - { - this.dataList.items[i] = this._prepareListItem(this.dataList.items[i]); - } - -}; - -/** - * Prepare list item - * A list item can be defined with minimal set of properties - * that are needed for its proper display. In fact these - * properties extend the default list item structure defined below. - * This function sets default configuration for a valid list item and merge - * it with the custom configuration passed to the item. - * TAG: internal - * ========================= - * @param {object} - the list item that will be set a default set of properties and will be returned - * @return {object} - the complete list item - */ -List2Ctrl.prototype._prepareListItem = function(item) -{ - // The itemStyle property is required - if (!item.hasOwnProperty('itemStyle')) - { - log.error('List2: list item should have itemStyle property: ' + item); - return; - } - - /* - * All types of list items extend this - * default structure by overriding the - * values and adding specific ones. The - * extended structure is then returned to be - * fed in the dataList container. - */ - var completeItem = { - appData : null, // Any kind of data that will be passed in the callbacks - text1Id : null, // String ID of the label - text1SubMap : null, // String Sub Map of the label - text1 : '', // Textual content of the label - hasCaret : true, // Show the caret icon on the right of the item - disabled : false, // Whether the list item is disabled - styleMod : '', // Style modifier, 'hint', 'bold', or ''/omitted - disabledStyleMod: "normal", // Disabled style modifier, 'normal' or 'white' - background : 'normal', // Background modifier, 'normal' or 'grey' - itemStyle : '', // String indicating the list type - itemBehavior : 'shortPressOnly', // String "hold" behavior for the item ('shortPressOnly', 'shortAndHold', or 'shortAndLong') - vuiSelectable: true, // Boolean for some items that cannot be selected by vui even when they are enabled - _data : { // Object containing any item-specific data used ONLY by the control - eventTimeout : null, - lastEvent : null, - settleTimeout : null, - lastUpdated : null, - settleValue : null, - } - }; - - // extend the default structure with default specific properties - var specificItem = {}; - switch (item.itemStyle) - { - case 'empty' : - specificItem = { hasCaret : false }; - break; - case 'draggable' : - specificItem = { image1:'', button1Id:null, button1SubMap:null, button1:''}; - break; - case 'ghost' : - specificItem = {}; - break; - case 'style01' : - specificItem = { image1:'', indented:false }; - break; - case 'style02' : - specificItem = { image1:'', image2:'' }; - break; - case 'style03' : - specificItem = { image1:'', image2:'', image3:'', checked:false, indented:false }; - break; - case 'style03a' : - specificItem = { image1: '', label1Id: null, label1SubMap: null, label1: '', checked: false, labelWidth: 'wide2', label1Align:'right', styleMod: "hint"}; - break; - case 'style04' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style05' : - specificItem = { image1:'', image2:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style06' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', labelWidth:'normal', label1Align:'right', label1Warning:false }; - break; - case 'style07' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style09' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style10' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', value:1, indeterminate:false, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style11' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', button3Id:null, button3SubMap:null, button3:'', value:1, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style12' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime }; - break; - case 'style13' : - // deprecated - issue a warning - log.warn(this.uiaId + ': List2 style13 has been deprecated. Please use style12 instead. Setting pivot=True. Check SDD for details.'); - specificItem = { min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:true }; - break; - case 'style14' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', text1Align:'left' }; - break; - case 'style17' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'' }; - break; - case 'style18' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'' }; - break; - case 'style19' : - specificItem = { image1:'' }; - break; - case 'style20' : - // nothing specific for this style - break; - case 'style21' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style22' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', indented:false }; - case 'style25' : - specificItem = { image1:'', image2:'', image3:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'styleOnOff' : - specificItem = { image1:'', value:2, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'styleStep' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2:'', min:0, max:36, increment:1, value:0, warning:false }; - break; - case 'styleLock' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', locked:false }; - break; - case 'style28' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime, indented : false }; - break; - case 'style29' : - specificItem = { label1Id:null, label1SubMap:null, label1:'',label2Id:null, label2SubMap:null, label2:'', image1:'' }; - break; - case 'style38' : - specificItem = {image1:'' ,text1Id:null, text1SubMap:null, text1:'',label1SubMap:null, label1:'',label2Id:null, label2SubMap:null, label2:'' ,image2:''}; - break; - default : - log.error('List2: unknown item style: ' + item.itemStyle); - break; - } - - // Extend default structure with the specific one - for (var i in specificItem) - { - completeItem[i] = specificItem[i]; - } - - // Extend default structure with the supplied item - for (var j in item) - { - completeItem[j] = item[j]; - } - - return completeItem; -}; - - -List2Ctrl.prototype._updateModifiedTimestamps = function(firstItem, lastItem) -{ - // update lastModified timestamp - var now = new Date().getTime(); - for (var i=firstItem; i<=lastItem; i++) - { - if (this._hasData(i)) - { - this.dataList.items[i]._data.lastUpdated = now; - } - } -}; - - -/** 3. ITEMS LOCALIZATION **/ - -/** - * Localize items - * Localize text in known list items using localization framework. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._localizeItems = function(firstItem, lastItem) -{ - log.debug('Localizing...'); - - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) ||(lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - // iterate through the dataList - for (var i=firstItem, l=lastItem; i<=l; i++) - { - switch (this.dataList.items[i].itemStyle) - { - // no elements - case 'empty' : - // do nothing - break; - - // text1, button1 - case 'draggable' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - //label1 and label2 only supports for style38 for reorderList - if(this._reorderItem.itemStyle === "style38") - { - if (this.dataList.items[i].laebl1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].laebl1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].laebl2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].laebl2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - break; - - // no elements - case 'ghost' : - // do nothing - break; - - // text1 - case 'style01' : - case 'style02' : - case 'style03' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - case 'style03a' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style04' : - case 'style05' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1, label1 - case 'style06' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style07' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, text2, label1, label2 - case 'style09' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, button1, button2 - case 'style10' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - break; - - // text1, button1, button2, button3 - case 'style11' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - if (this.dataList.items[i].button3Id) - { - var button3 = this._getLocalizedString(this.dataList.items[i].button3Id, this.dataList.items[i].button3SubMap); - this.dataList.items[i].button3 = button3; - } - break; - - // text1, labelLeft, labelRight - case 'style12' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, labelLeft, labelCenter, labelRight - case 'style13' : - // style13 is deprecated - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1 - case 'style14' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style17' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style18' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1 - case 'style19' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1 - case 'style20' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, text2, label1 - case 'style21' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style22' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style25' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1 - case 'styleOnOff' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1, label2 - case 'styleStep' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label2 = label2; - } - else - { - log.warn(this.uiaId + ' possible issue. Lis2: item ' + i + ' does not specify label2Id'); - } - break; - - // text1, text2 - case 'styleLock' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - case 'style29' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - - case 'style38' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label2 = label2; - } - break; - - } - - } -}; - -/** - * Get localization entry for a string id - * TAG: internal - * ========================= - * @return {string} - */ -List2Ctrl.prototype._getLocalizedString = function(labelId, subMap) -{ - return framework.localize.getLocStr(this.uiaId, labelId, subMap); -}; - -/** 4. POOL OPERATIONS **/ - -/** - * Set line 1 content - * This helper function clears any previous content for the supplied - * element class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - textual content to be inserted - * @param {boolean} - do not remove child html tags when inserting textual content - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setText = function(li, className, content, preserveHTML) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - if (!content) - { - content = ''; - } - li.querySelector(className).innerText = ''; - li.querySelector(className).appendChild(document.createTextNode(content)); - return li; -}; - -/** - * Set image background - * This helper function clears any previous path for the supplied - * image class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - path to the image - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setImage = function(li, className, url) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - li.querySelector(className).style.backgroundImage = ''; - if ('' != url) - { - li.querySelector(className).style.backgroundImage = 'url(' + url + ')'; - } - return li; -}; - -/** - * Set slider - * This helper function clears any previous slider in the list item - * and cleans up local references. It then creates a new slider control - * inside the list item and sets its values - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setSlider = function(li, className, sliderProperties, itemIndex) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - - // get current item poolid - var poolId = li.getAttribute('data-poolid'); - - // get previous itemIndex for this particular li - var prevItemIndex = li.getAttribute('data-ref'); - - // destruct any previous sliders for this poolid and previous index - if (prevItemIndex != 'undefined') - { - var hashKey = 'slider_'+prevItemIndex+'_'+poolId; - - // remove slider from the hash and the DOM - if (this._sliders.hasOwnProperty(hashKey)) - { - this._sliders[hashKey]['slider'].cleanUp(); - this._sliders[hashKey]['slider'].divElt.parentElement.removeChild(this._sliders[hashKey]['slider'].divElt); - } - } - - // add slider to the hash and the DOM - var sliderCont = li.querySelector(className); - if (sliderProperties && sliderCont) - { - var hashKey = 'slider_'+itemIndex+'_'+poolId; - - // instantiate slider and add it to the _sliders hash - this._sliders[hashKey] = {}; - this._sliders[hashKey]['itemIndex'] = itemIndex; - this._sliders[hashKey]['poolId'] = poolId; - this._sliders[hashKey]['slider'] = framework.instantiateControl(this.uiaId, sliderCont, 'SliderCtrl', sliderProperties); - } - return li; -}; - -/** - * Set toggle - * This helper function clears any previous toggled buttons in - * the supplied list item and sets initial toggle value - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setToggle = function(li, className, value) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - var buttons = li.querySelectorAll(className); - for (var i=0; i element wit proper elements inside - */ -List2Ctrl.prototype._getListItem = function(listItem, dataListIndex) -{ - - // get it from the pool - var li = this.pool[listItem.itemStyle].shift(); - - // remove any residual touch classes - li.classList.remove('hit'); - li.classList.remove('focus'); - li.classList.remove('longpress'); - li.classList.remove('secondaryFocus'); - - // add content to it following style definitions - switch (listItem.itemStyle) - { - case 'empty' : - // empty item -> no content - break; - - case 'draggable' : - // listItem : { text1:String, image1:String, button1:String } - this._setText(li, '.line1', listItem.text1); - if(this._reorderItem.itemStyle === "style38" ) - { - //For style 38 line1 width should be shorter as compare the other style. - li.querySelector(".line1").classList.add('shortText') - } - - //label1 and label2 only supports for style38 for reorderList - if(this._reorderItem.itemStyle === "style38" ) - { - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - } - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.buttonOk', listItem.button1); - break; - - case 'ghost' : - // list item : {} - break; - - case 'style01' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style02' : - // listItem : { text1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.image2 === 'indeterminate') - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - this._setImage(li, '.image2', listItem.image2); - } - break; - - case 'style03' : - // listItem : { text1:String, image1:String, image2:String, checked:Boolean } - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style03a' : - // listItem : { text1:String, image1:String, label1: String} - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - this._setText(li, '.label1', listItem.label1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style04' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style05' : - // listItem : { text1:String, text2:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - break; - - case 'style06' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style07' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style09' : - // listItem : { text1:String, text2:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style10' : - // listItem : { text1:String, button1:String, button2:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 2), 0) ); - if (listItem.indeterminate) - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - } - break; - - case 'style11' : - // listItem : { text1:String, button1:String, button2:String, button3:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setText(li, '.button3', listItem.button3); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 3), 0) ); - break; - - case 'style12' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style13' : - // TODO: style13 has been depricated - // listItem : { text1:String, labelLeft:String, labelCenter:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: this.properties.minChangeInterval, - settleTime: this.properties.settleTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style14' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - if ('right' == listItem.text1Align) - { - li.classList.add('text1AlignRight'); - } - else - { - li.classList.remove('text1AlignRight'); - } - - break; - - case 'style17' : - // listItem : { text1:String, label1:String, image1:String } - li.querySelector('.line1').innerText = ''; - var label1 = document.createElement('span'); - label1.className = 'label1'; - label1.appendChild(document.createTextNode(listItem.label1)); - li.querySelector('.line1').appendChild(label1); - li.querySelector('.line1').appendChild(document.createTextNode(listItem.text1)); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style18' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style19' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style20' : - // listItem : { text1:String } - this._setText(li, '.button1', listItem.text1); - break; - - case 'style21' : - // listItem : { text1:String, text2:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style22' : - // listItem : { text1:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style25' : - // listItem : { text1:String, text2:String, image1:String, image2:String, image3:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - break; - - case 'styleOnOff' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.value === 1) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - break; - - case 'styleStep' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - li.classList.remove('maxReached'); - li.classList.remove('minReached'); - if (listItem.value === listItem.max) - { - li.classList.add('maxReached'); - } - else if (listItem.value === listItem.min) - { - li.classList.add('minReached'); - } - - // configure label warning - if (listItem.warning) - li.classList.add('warning'); - else - li.classList.remove('warning'); - - break; - - case 'styleLock' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - if (listItem.locked) - { - li.classList.add('locked'); - } - else - { - li.classList.remove('locked'); - } - break; - - case 'style28' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setImage(li, '.image1', listItem.image1); - - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - - - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style29': - - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style38': - - if(listItem.text1) - { - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image2', listItem.image2); - } - else - { - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.line1', ""); - this._setText(li, '.label1', ""); - this._setText(li, '.label2', ""); - this._setImage(li, '.image2', listItem.image2); - - } - break; - } - - /* ITEM MODIFICATORS */ - // add/remove hasCaret class - if (listItem.hasCaret) - { - li.classList.add('hasCaret'); - } - else - { - li.classList.remove('hasCaret'); - } - - // add/remove disabled class - if (listItem.disabled) - { - li.classList.add('disabled'); - } - else - { - li.classList.remove('disabled'); - } - - // add/remove styleMod class (hint/bold/'') - if ('hint' == listItem.styleMod) - { - li.classList.remove('bold'); - li.classList.add('hint'); - } - else if ('bold' == listItem.styleMod) - { - li.classList.remove('hint'); - li.classList.add('bold'); - } - else if ('both' == listItem.styleMod) - { - li.classList.add('hint'); - li.classList.add('bold'); - } - else - { - li.classList.remove('hint'); - li.classList.remove('bold'); - } - - // add/remove background modifier class (normal/grey) - if ('grey' == listItem.background) - { - li.classList.remove('bgLightGrey'); - li.classList.add('bgGrey'); - } - else if('lightGrey' == listItem.background) - { - li.classList.remove('bgGrey'); - li.classList.add('bgLightGrey'); - } - else - { - li.classList.remove('bgLightGrey'); - li.classList.remove('bgGrey'); - } - - // add disabled style mod - if ('white' === listItem.disabledStyleMod) - { - li.classList.add("disabledWhite"); - } - - // return it - return li; - -}; - -/** - * Return list item to the pool - * This will result in increasing the pool contents - * with one item. The returned item will be removed from the DOM. - * However, its content will not be reset as this is done in the - * process of any subsequent pool extraction (see _getListItem() above) - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @return {void} - */ -List2Ctrl.prototype._returnListItem = function(li) -{ - // get the style - var itemStyle = li.getAttribute('data-itemStyle'); - // reset it - li.style.top = '0px'; - // remove it - li.parentNode.removeChild(li); - - // put it back to the pool - this.pool[itemStyle].push(li); -}; - -/** - * Put a list item to the scroller - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._putToScroller = function(li, index, operation) -{ - li.style.top = index * this.properties.itemHeight + 'px'; - li.setAttribute('data-ref', index); - - - if (operation == 'prepend') - { - this.items.unshift({ref:index, domElt:li}); - this.scroller.insertBefore(li, this.scroller.firstChild); - - this._wrapInlineElement(li); - } - else if (operation == 'append') - { - this.items.push({ref:index, domElt:li}); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else if (!isNaN(operation)) - { - this.items.splice(operation, 0, {ref:index, domElt:li}); - - // insertBefore breaks in Opera - use appendChild instead - // this.scroller.insertBefore(li, this.items[operation+1]); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else - { - log.error('Lis2: unknown _putToScroller() operation: ' + li + ' ' + index + ' ' + operation); - } - -}; - -/** - * Return everything into the pool and empty the scroller - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._emptyScroller = function() -{ - for (var i=0, l=this.items.length; i itemsOnScreen) - { - // return everything into the pool - var itemsLength = this.items.length; - for (var i=0; i < itemsLength; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - var dataListIndex = 0; - - if (topItem < this.dataList.items.length - Math.round(itemsOnScreen / 2) && - topItem > Math.round((itemsOnScreen / 2)) ) - { - - - // WE ARE IN THE MIDDLE - - for (var i=0; i < itemsLength; i++) - { - dataListIndex = (topItem - itemsBefore) + i; - - // we've reached the end of the dataList. No more items to add -> break - if (dataListIndex >= this.dataList.items.length) - { - break; - } - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'middle'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else - { - - if (numOfScrolledElements > 0) - { - - // PRESSED END BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = (this.dataList.items.length - itemsLength) + i; - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'down'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else if (numOfScrolledElements < 0) - { - - // PRESSED HOME BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = i; - - - // request it if it is empty - if (this.dataList.items[dataListIndex].itemStyle === 'empty' || (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex]))) - { - this._requestMore(dataListIndex, 'down'); - log.debug('Requesting items ' + dataListIndex); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - - } - - } - - } - - - } - else - { - - - - if (numOfScrolledElements > 0) - { - - /* SCROLL DOWN BOF */ - - // return to pool - var firstItemRef = this.items[0].ref; - var bottomDifference = topItem - firstItemRef; - var extraEls = bottomDifference - itemsBefore; - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Down - extraEls ' + extraEls); - - if (extraEls > 0) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - } - - // lastItemRef = this.items[this.items.length-1].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var topDifference = this.items[this.items.length-1].ref - ( topItem - 1 ); - var newEls = ( itemsAfter + 1 ) - topDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Down - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i break - log.debug('end of list'); - break; - } - - } - - } - - /* SCROLL DOWN EOF */ - - } - else if (numOfScrolledElements < 0) - { - - /* SCROLL UP BOF */ - - // return to pool - var topDifference = this.items[this.items.length-1].ref - topItem + 1; - var extraEls = topDifference - ( itemsAfter + 1 ); - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Up - extraEls ' + extraEls); - - if ( extraEls > 0 ) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.pop(); - this._returnListItem(item.domElt); - } - - } - - - // firstItemRef = this.items[0].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var bottomDifference = topItem - this.items[0].ref; - var newEls = itemsBefore - bottomDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Up - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i= 0) - { - - // if empty item is encountered, request more data - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'up'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'prepend'); - - } - else - { - // we've reached the beginning of the dataList array => break - log.debug('beginning of list'); - break; - } - - } // for - - } - else - { - log.debug('no new elements'); - } - - /* SCROLL UP EOF */ - - } - else - { - // there's no scroll => do nothing - } - - - - } // closes if (this.m.abs(numOfScrolledElements) > itemsOnScreen) - -}; - - -/** - * Redraw updated items that are currently visible - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._updateDisplay = function(firstItem, lastItem) -{ - - var firstItemRef = this.items[0].ref; - var lastItemRef = this.items[this.items.length-1].ref; - - // update only when the updated items overlap with the visible items - if ( (firstItem >= firstItemRef && firstItem <= lastItemRef) || - (firstItem <= firstItemRef && lastItem >= firstItemRef) ) - { - - var firstToUpdate = this.m.max(firstItem, firstItemRef); - var lastToUpdate = this.m.min(lastItem, lastItemRef); - var firstToUpdateIndex = firstToUpdate - firstItemRef; - var lastToUpdateIndex = (lastToUpdate - firstToUpdate) + firstToUpdateIndex; - - for (var i=firstToUpdateIndex; i<=lastToUpdateIndex; i++ ) - { - - var returnItem = this.items.splice(i,1); - var dataListIndex = returnItem[0].ref; - - // return to pool - this._returnListItem(returnItem[0].domElt); - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // recover secondary focus - if (this._inSecondaryMulticontroller && this._currentSecondaryMulticontrollerItem === dataListIndex) - { - li.classList.add('focus'); - li.classList.add('secondaryFocus'); - } - - // put it to scroller - this._putToScroller(li, dataListIndex, i); - - } - - } - - // update _isScrollable flag - this._checkScrollable(); - -}; - -/** - * Request more list items - * TAG: internal - * ========================= - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._requestMore = function(index, direction) -{ - - // do not request more if a previous request is pending - if (!this._inLoading) - { - if(this._appIsAtSpeed) - { - return; // do not do anything if the list gets this._appIsAtSpeed - } - else - { - // indicate loading is in progress - this._setLoading(true); - - if (direction == 'up') - { - // we add 1 to the requestSize to include the last element in the way up - index = this.m.max(index - this.properties.requestSize + 1, 0); - - } - else if (direction == 'middle') - { - // we request 25 items on each direction from the topItem - index = this.m.max(index, 0); - - } - - // build additional data - var additionalParams = { - topItem : this._topItem, - visibleItems : this.properties.visibleItems, - ranges : this.getEmptyRange(), - }; - - log.debug('Request items from ' + index + ' to ' + index+this.properties.requestSize + ' ' + direction); - - // call needDataCallback if it is defined. The first empty item is - if (typeof this.properties.needDataCallback == 'function') - { - this.properties.needDataCallback(index, additionalParams); - } - - // set timeout for data population - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = setTimeout(this._needDataTimeoutCallback.bind(this, index), this.properties.needDataTimeout); - } - } - -}; - -List2Ctrl.prototype._needDataTimeoutCallback = function(index) -{ - log.warn('Lis2: control has requested items from index ' + index + ' but has not receieved them yet. Enabling the list.'); - this._setLoading(false); -}; - -/** - * Initial pool operation - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._fill = function(firstItem, lastItem) -{ - - log.debug('Start pool operation'); - log.debug('POOL | ITEMS'); - - // get items from the pool - for (var i=firstItem; i<=lastItem; i++) - { - // get it from the pool - var li = this._getListItem(this.dataList.items[i], i); - - // put it to scroller - this._putToScroller(li, i, 'append'); - - log.debug(this.pool[this.dataList.items[i].itemStyle].length + ' -> ' + this.items.length); - } - - this._hasFill = true; - - // update _isScrollable flag - var scrollable = this._checkScrollable(); - - // show/hide scroll indicator - if (!scrollable || (scrollable && this.properties.hasLetterIndex)) - { - this._hideScrollIndicator(); - } - else - { - this._showScrollIndicator(); - } - - log.debug('End pool operation'); - -}; - -/** SET INTERNAL PROPERTIES **/ - -/** - * Update _isScrollable flag - * TAG: internal - * ========================= - * @return {boolean} - returns _isScrollable - */ -List2Ctrl.prototype._checkScrollable = function() -{ - if (this.dataList.items.length > this.properties.visibleItems) - { - this._isScrollable = true; - } - else - { - this._isScrollable = false; - } - - return this._isScrollable; -}; - -/** - * Update _topItem property - * TAG: internal - * ========================= - * @param {integer} - top item index - * @return {integer} - returns _topItem - */ -List2Ctrl.prototype._setTopListItem = function(pos) -{ - // pos should be number for proper topItem calculation - if (!isNaN(pos)) - { - this._prevTopItem = this._topItem; - this._topItem = -(Math.round(pos / this.properties.itemHeight)); - - // throw out of bounds exception - if (this._topItem < 0 || this._topItem > this.dataList.items.length - 1) - { - log.error('Lis2: _topItem is out of bounds'); - } - } - - if (this.properties.enableItemRequestOnScroll) - { - // check for empty items in DOM - var emptyDOMItem = this._getEmptyDOMElement(); - if (null != emptyDOMItem) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - } - } - - return this._topItem; - -}; - -/** - * Indicate loading activity in the list - * and update _inLoading property - * TAG: internal - * ========================= - * @param {boolean} - show or hide loading activity - * @return {boolean} - returns _inLoading - */ -List2Ctrl.prototype._setLoading = function(show) -{ - if (show) - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - // update start time - this._loadingData.timeStarted = new Date().getTime(); - - if (this.properties.showLoadingOverlayTimeout > 0) - { - // delayed show overlay - this._loadingData.startTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, true), this.properties.showLoadingOverlayTimeout); - } - else - { - // show overlay immediately - this._setLoadingOverlay(true); - } - } - - // update flag - this._inLoading = true; - } - else - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - if (this.properties.hideLoadingOverlayTimeout > 0) - { - // delayed hide overlay - var now = new Date().getTime(); - if (now - this._loadingData.timeStarted < this.properties.showLoadingOverlayTimeout) - { - // no overlay has been shown -> reset everything - this._setLoadingOverlay(false); - } - else if (now - this._loadingData.timeShown < this.properties.hideLoadingOverlayTimeout) - { - // the overlay has been visible less than the hideLoadingOverlayTimeout -> hide it in hideLoadingOverlayTimeout ms after it has been made visible - this._loadingData.endTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, false), this.properties.hideLoadingOverlayTimeout - (now - this._loadingData.timeShown)); - } - else - { - // the overlay has been visible long enough -> hide it immediately - this._setLoadingOverlay(false); - } - } - else - { - // hide overlay immediately - this._setLoadingOverlay(false); - } - } - - // update flag - this._inLoading = false; - } - - return this._inLoading; -}; - -List2Ctrl.prototype._setLoadingOverlay = function(show) -{ - if (show) - { - // show loading - this.mask.appendChild(this.loading); - - this._loadingData.timeShown = new Date().getTime(); - } - else - { - // hide loading - if (null != this.loading.parentElement) - { - this.loading.parentElement.removeChild(this.loading); - } - - // reset loading data - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - this._loadingData.timeStarted = 0; - this._loadingData.timeShown = 0; - this._loadingData.startTimeoutId = null; - this._loadingData.endTimeoutId = null; - } -}; - -/** 7. DEFAULT TITLE CONFIGURATION **/ - -/** - * Prepare title - * A list title can be defined with minimal set of properties - * that are needed for its proper display. This function sets - * default configuration for a valid title and merge it with the - * custom configuration passed to the title. - * TAG: internal - * ========================= - * @param {object} - the title object that will be set a default set of properties and will be returned - * @return {object} - the complete title object - */ -List2Ctrl.prototype._prepareTitle = function(titleObj) -{ - // The itemStyle property is required - if (!titleObj.hasOwnProperty('titleStyle')) - { - log.error('Lis2: title should have titleStyle property: ' + titleObj); - return; - } - - // default properties - var title = {}; - switch (titleObj.titleStyle) - { - case 'style02' : - title = { text1:'', text1Id:null, text1SubMap:null, styleMod:'' }; - break; - case 'style02a' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - case 'style03' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'' }; - break; - case 'style05' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null, image1:'' }; - break; - case 'style06' : - title = { image1:'' }; - break; - case 'style07' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null }; - break; - case 'style08' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - default : - log.error('Lis2: unknown title style: ' + titleObj.titleStyle); - break; - } - - // Extend default structure with the supplied item - for (var i in titleObj) - { - title[i] = titleObj[i]; - } - - // Perform localization - switch (title.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style08' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - break; - case 'style05' : - case 'style07' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - if (title.text2Id) - { - title.text2 = this._getLocalizedString(title.text2Id, title.text2SubMap); - } - break; - } - - return title; -}; - - -/** - * ========================= - * SCROLL INDICATOR - * - reset - * - create - * - visual update - * ========================= - */ - -/** - * Remove any scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorReset = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // remove any scroll indicator - if (this.scrollIndicatorWrapper) - { - // remove wrapper (and scroll indicator) - this.scrollIndicatorWrapper.parentElement.removeChild(this.scrollIndicatorWrapper); - - // nullify elements - this.scrollIndicatorWrapper = null; - this.scrollIndicator = null; - - // reset scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = 0; - } -}; - -/** - * Create scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorBuild = function(visible) -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator size - var indicatorSize = Math.round(this.mask.offsetHeight * (this.mask.offsetHeight / this.scroller.offsetHeight)); - - // add scroll indicator wrapper - this.scrollIndicatorWrapper = document.createElement('div'); - this.scrollIndicatorWrapper.className = 'List2CtrlScrollIndicatorWrapper'; - this.divElt.appendChild(this.scrollIndicatorWrapper); - - // add scroll indicator - this.scrollIndicator = document.createElement('div'); - this.scrollIndicator.className = 'List2CtrlScrollIndicator'; - if(!visible) - { - this.scrollIndicatorWrapper.style.visibility = 'hidden'; - } - else - { - this.scrollIndicatorWrapper.style.visibility = 'visible'; - } - this.scrollIndicator.style.height = this.m.max(indicatorSize, this.properties.scrollIndicatorMinSize) + 'px'; - this.scrollIndicator.style.top = '0px'; - this.scrollIndicatorWrapper.appendChild(this.scrollIndicator); - - // set scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = this.mask.offsetHeight - this.scrollIndicator.offsetHeight; - - if (this.properties.hasLetterIndex) - { - // hide scroll indicator when letterIndex is enabled - this._hideScrollIndicator(); - } - else - { - // fade out scroll indicator - this._fadeOutScrollIndicator(); - } -}; - -/** - * Update scroll indicator position on drag - * This is fired on _USER_EVENT_MOVE when the - * list is being dragged by touch. - * TAG: touch-only, internal - * ========================= - * @return {integer} scroll indicator position - */ -List2Ctrl.prototype._dragUpdateScrollIndicator = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator position - var indicatorPos = Math.round(this._indicatorMax * (this.scroller.offsetTop / this._maxScrollY)); - - // constrain position - indicatorPos = this.m.max(indicatorPos, this._indicatorMin); - - // set new position - this.scrollIndicator.style.top = indicatorPos + 'px'; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return indicatorPos; -}; - -/** - * Update scroll indicator position on drag - * Called on scroll animation (flick or scroll ad-hoc) - * TAG: internal - * ========================= - * @param {integer} the new position of the scroller - * @param {integer} the time for animation to the new position - * @return {integer} the new scroll indicator position - */ -List2Ctrl.prototype._updateScrollIndicator = function(pos, time) -{ - // check for time - if (time == undefined || time == null) - { - // get default time - time = this.properties.swipeAnimationDuration; - } - - // determine scroll indicator new position - var newRelativePos = pos / this._maxScrollY; - var newPos = Math.round(newRelativePos * (this._indicatorMax - this._indicatorMin)); - - // start animation - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollIndicatorAnimationEndCallback = this._scrollIndicatorAnimationEnd.bind(this); - this.scrollIndicator.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicator.style.top = newPos + 'px'; - - // clear any previously scheduled scroll indicator fade out - clearTimeout(this._scrollIndicatorTimeoutId); - this._scrollIndicatorTimeoutId = null; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return newPos; - -}; - - -List2Ctrl.prototype._fadeInScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeInDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -List2Ctrl.prototype._fadeOutScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - // clear any previously-scheduled hiding - clearTimeout(this._scrollIndicatorTimeoutId); - - // schedule hide - this._scrollIndicatorTimeoutId = setTimeout(function() { - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeOutDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 0; - this._scrollIndicatorTimeoutId = null; - }.bind(this), this.properties.scrollIndicatorFadeTimeout); -}; - -List2Ctrl.prototype._hideScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 0; -}; - -List2Ctrl.prototype._showScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -/** - * ========================= - * TOUCH EVENT HANDLERS - * - Event detection and custom event dispatching - * - Start/Move/End/Out event handling - * - Hit state control - * ========================= - */ - -/** - * Handle any touch event and dispatch appropriate - * custom event. Actual event processing is done in the - * respective handlers of the custom events. The original - * event object is attached to the custom event in its - * event property. - * ========================= - * @param {event} - any touch event - * @return {Boolean} - True if event was processed - */ -List2Ctrl.prototype._touch = function(e) -{ - var touchResult = false; - - switch(e.type) - { - case this._USER_EVENT_START : - // route to letter index first, otherwise route to list - touchResult = this._startIndex(e) || this._start(e); - /* - * Attach temporary listeners to document if we have a positive start. - * These listeners will be removed on _USER_EVENT_END - */ - if (touchResult) - { - document.addEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - } - break; - - case this._USER_EVENT_MOVE : - // route to letter index first, otherwise route to list - touchResult = this._moveIndex(e) || this._move(e); - break; - - case this._USER_EVENT_END : - /* - * Remove the document event listeners no matter of these have been - * attached or not. This will prevent any non-existent callbacks firing. - */ - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - // route to letter index first, otherwise route to list - touchResult = this._endIndex(e) || this._end(e); - break; - - case this._USER_EVENT_OUT : - this._out(e); - break; - } - - return touchResult; -}; - -/** - * Start Touch on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._start = function(e) -{ - // abort any ongoing scroll - this._abortScroll(e); - - // get mask position and dimensions - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - this._maskH = this.mask.offsetHeight; - this._maskW = this.mask.offsetWidth; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - // reset letter index multicontroller - this._focusStolen = false; - if (relativeY >= 0) - { - this._setLetterIndexMulticontroller(false, true); - - // steal focus - var canGainFocus = this._canGainFocus(e); - if (!this._hasFocus && -1 !== canGainFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - this._focusStolen = true; - } - } - - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by start reorder rather than regular start - this._startReorder(e); - return true; - } - else if(!this._inListReorder && this._appIsAtSpeed) - { - this._startReorder(e); - return true; - } - - this._startItem = this._getTargetItem(e); - this._startDOMItem = this._getDOMItem(this._startItem); - - // make hit - if (this.properties.hitTimeout > 0) - { - // after some time - this._makeHitTimeoutId = setTimeout(this._itemMakeHit.bind(this, e), this.properties.hitTimeout); - } - else - { - // immediately - this._itemMakeHit(e); - } - - // Place focus on the reported available item when focus is stolen - if (this._focusStolen) - { - this._showFocus(canGainFocus, true); - } - - // make toggles hit - this._buttonMakeHit(e); - - // make locks hit - this._lockMakeHit(e); - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return false; - } - - // check relative mouse position - if (relativeY < 0) - { - return false; - } - - // check for a valid target item - if (this._startItem == -1) - { - return false; - } - - // get current y - this._y = this.scroller.offsetTop; - this._startY = relativeY; - this._startX = relativeX; - this._startTime = new Date().getTime(); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, e), this.properties.longPressTimeout); - - // raise _inDrag - this._inDrag = true; - - // Release secondary MC mode - if (this._inSecondaryMulticontroller && null != this._currentSecondaryMulticontrollerItem && this._startItem != this._currentSecondaryMulticontrollerItem) - { - var temp = this._currentSecondaryMulticontrollerItem; - - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - - // Commit the value - if (!this._isLock(temp)) // locks do not commit the value - { - this._triggerFocus(temp); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(temp, 'clear'); - } - } - - // dispatch scroll start event - this._listEvent(this._EVENTS.SCROLL_START, {scrollPosition:this._topItem}); - - // user touched the list -> return True - return true; - -}; - -/** - * Touch move on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._move = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by move reorder rather than regular move - this._moveReorder(e); - return true; - } - - if (!this._inDrag) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._end(e); - return true; - } - - // calculate travelled distance - var deltaY = relativeY - this._startY; - var deltaX = relativeX - this._startX; - - if (this._inLongPress) - { - return false; - } - - /* - * DRAG DETECTION - * determine whether this is a horizontal or vertical drag - * and raise the horizontal flag - */ - if (null == this._inHorizontalDrag) { - - var alpha = Math.atan2(this.m.abs(deltaX), this.m.abs(deltaY)); - if (alpha < this.properties.hvThreshold) - { - // vertical - this._inHorizontalDrag = false; - } - else - { - // horizontal - this._inHorizontalDrag = true; - this._hDragItem = this._getTargetItem(e); - - // set slideStart - this._slideStart(e); - } - } - - // drag slider - if (this._inHorizontalDrag == true) - { - // we have a horizontal drag -> move sliders - this._slideMove(e); - } - // drag list if scrollable - else if (false == this._inHorizontalDrag && this._isScrollable) - { - // we have a vertical drag and the list can be scrolled - // calculate the scroller's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollY, this.m.min(this._y + deltaY, this._minScrollY)); - - // drag the scroller if in bounds - this.scroller.style.top = newPos + 'px'; - - // update scroll indicator - this._dragUpdateScrollIndicator(); - - // raise _stopClick flag and remove hit and long press - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit and prevent delayed hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); - - // remove long press and prevent long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); - } - } - // control hit state when not scrollable or when no scrolling occurs (e.g. when we are one of the list extremities) - if (!this._isScrollable || this.m.abs(deltaY) > this.properties.selectThreshold) - { - var targetTop = this._startDOMItem.offsetTop; - if (relativeY < targetTop || relativeY > targetTop + this.properties.itemHeight) - { - // remove hit - this._itemRemoveHit(e); - - // prevent select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = true; - } - } - else - { - // make hit - if (this._stopSelect && !this._isScrollable) - { - this._itemMakeHit(e); - } - - // enable select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = false; - } - } - } - - // user touched the list -> return True - return true; -}; - -/** - * Touch end on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._end = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by end reorder rather than regular end - this._endReorder(e); - return true; - } - else if(!this._inListReorder && this._appIsAtSpeed) - { - this._endReorder(e); - return true; - } - - - // remove hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); // clear hit timeout - // remove long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - this._startItem = null; - this._startDOMItem = null; - - // reset drag flag and hDrag item - this._inHorizontalDrag = null; - this._hDragItem = null; - - if (!this._inDrag) - { - // this is called without having a drag - return false; - } - - // end any drag of sliders - this._slideEnd(e); - - // set scroll nature - this._scrollNature = 'touch'; - - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTime; - if (this._focusStolen && !this._stopSelect) - { - // slight drag -> scroll to show focus on the available item when stealing focus - // decide whether to allow offscrean - var focussedIndex = this._getFocussedIndex(); - var allowOffScreen = (focussedIndex > this._topItem && focussedIndex < this._topItem + this.properties.visibleItems); - this._showFocus(focussedIndex, allowOffScreen); - this._focusStolen = false; - } - else if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startY; - - // swipte detected - this._startSwipe(deltaY, velocity); - } - else - { - // regular drag -> snap to item bounds - this._snap(this.scroller.offsetTop); - } - - // call touch select logic - this._touchSelectItem(e); - - // reset any previously set flags - this._inDrag = false; - this._stopSelect = false; - this._startTime = 0; - - // user touched the list -> return True - return true; -}; - -/** - * Touch leave on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._out = function(e) -{ - return this._end(e); -}; - - -/** - * Start Touch on letter index - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {boolean} - True if letter index is touched - */ -List2Ctrl.prototype._startIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // get mask position - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - if (relativeY < 0) - { - return false; - } - - // hit test letter index - if (relativeX <= this.letterIndexWrapper.offsetLeft) - { - return false; - } - - // steal focus - if (!this._hasFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - } - - // Enter into letter index multicontroller mode if not already - if (!this._inLetterIndexMulticontroller) - { - this._setLetterIndexMulticontroller(true); - } - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - - // make hit - this._indexMakeHit(e); - - // get start coordinates and time - this._yIndex = this.letterIndex.offsetTop; - this._startIndexY = relativeY; - this._startIndexX = relativeX; - this._startTimeIndex = new Date().getTime(); - - this._inDragIndex = true; - - return true; - -}; - - -List2Ctrl.prototype._moveIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - if (!this._inDragIndex) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._endIndex(e); - - return false; - } - - // calculate travelled distance - var deltaY = relativeY - this._startIndexY; - var deltaX = relativeX - this._startIndexX; - - // calculate the letter index's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollYIndex, this.m.min(this._yIndex + deltaY, this._minScrollYIndex)); - - // drag the letter index if in bounds - this.letterIndex.style.top = newPos + 'px'; - - // raise _stopClick flag - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit - this._indexRemoveHit(e); - } - - return true; - -}; - - -List2Ctrl.prototype._endIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // remove hit - this._indexRemoveHit(e); - - if (!this._inDragIndex) - { - return false; - } - - if (!this._stopSelect) - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // select letter index - var letterIndex = this._getTargetLetterIndex(e); - this._letterIndexSelect(letterIndex, 'Touch'); - } - else - { - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTimeIndex; - if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startIndexY; - - // swipte detected - this._startSwipeIndex(deltaY, velocity); - } - else - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // schedule letter index select if letter is enabled - var letterIndex = this._getTargetLetterIndex(e); - if (!this.letterIndexData[letterIndex].disabled) - { - this._scheduleLetterIndexSelect(letterIndex); - } - } - } - - // reset flags - this._inDragIndex = false; - this._stopSelect = false; - - return true; -}; - - - -/** - * Select item - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {void} - */ -List2Ctrl.prototype._touchSelectItem = function(e) -{ - // clear any hit timeout - clearTimeout(this._makeHitTimeoutId); - - // if we are not allowed to select (when in drag) - if (this._stopSelect) - { - this._stopSelect = false; - return; - } - - // select during loading is not allowed - if (this._inLoading) - { - return; - } - - var itemIndex; - var fireSelect = true; - var additionalModifier = null; - var params = {}; - - // determine target item - itemIndex = this._getTargetItem(e); - - // only valid list items can fire the select callback - if (itemIndex == -1) - { - return; - } - - // ensure that we end up on the same item where we started so that the select is valid - if (itemIndex != this._getFocussedIndex()) - { - return; - } - - // perform any additional touch processing for some items before issuing select callback - if (this._isToggle(itemIndex)) - { - // the target contains toggle buttons -> select toggle buttons - var toggleSelected = this._buttonSelect(e); - if ('cancel' == toggleSelected) - { - fireSelect = false; - } - else if (null != toggleSelected) - { - params = { additionalData:toggleSelected }; - additionalModifier = 'preventSimpleSelect'; - } - - } - - if (this._isSlider(itemIndex)) - { - // the target contains a slider -> disable select only if the slider is adjustable - if (this.dataList.items[itemIndex].allowAdjust) - { - fireSelect = false; - } - } - - if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && this._inSecondaryMulticontroller) - { - // if we are in secondary multicontroller and the item is a step item - var stepResult = this._stepAdjust(e); - if ('commit' === stepResult) - { - params = { finalAdjust:true, value:this.dataList.items[itemIndex].value }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - else if (null != stepResult) - { - params = { finalAdjust:false, value:stepResult }; - } - else - { - fireSelect = false; - } - } - else if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && !this._inSecondaryMulticontroller) - { - // if we are not in secondary multicontroller and the item is step item - this._setSecondaryMulticontroller(true, itemIndex); - fireSelect = false; - - // produce beep - this._beep('Short', 'Touch'); - } - - if (this._isLock(itemIndex) && this._hasSecondaryMulticontroller(itemIndex)) - { - // the target is a lock item - var lockAction = this._lockSelect(e); - if (null == lockAction) - { - fireSelect = false; - } - else - { - // prepare params - params = { additionalData:lockAction }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - } - - // prevent select on disabled items - if (this.dataList.items[itemIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Touch'); - - this._itemSelect(itemIndex, params, additionalModifier); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior) - { - this._itemHoldStop(itemIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - -}; - -/** - * Exit hit state of the currently hit item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._itemRemoveHit = function() -{ - var hitItems = this.scroller.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i= this.dataList.itemCount || this.dataList.items[itemIndex].disabled) - { - return; - } - - var returnValue = null; - - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'styleOnOff' : - // get and update current value - var currentValue = this.dataList.items[itemIndex].value; - var newValue = (1 === currentValue) ? 2 : 1; - this.dataList.items[itemIndex].value = newValue; - - // get and update DOM item - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (1 === newValue) - { - domItem.classList.add('checked'); - } - else - { - domItem.classList.remove('checked'); - } - } - returnValue = newValue; - break; - - case 'style10' : - case 'style11' : - // Note: settle timeout is registered in this._buttonActivate - this._buttonSelectRight(itemIndex); - returnValue = this.dataList.items[itemIndex].value; - break; - - case 'style03' : - case 'style03a' : - var currentValue = this.dataList.items[itemIndex].checked; - switch (this.dataList.items[itemIndex].image1) - { - case 'tick' : - if (!currentValue) - this._setTick(itemIndex, !currentValue); - break; - case 'radio' : - if (!currentValue) - this._setRadio(itemIndex, !currentValue); - break; - case 'checkbox' : - this._setCheckBox(itemIndex, !currentValue); - break; - } - returnValue = this.dataList.items[itemIndex].checked; - break; - - default : - log.warn('Lis2: No simple select behavior for item style ' + this.dataList.items[itemIndex].itemStyle); - break; - } - - return returnValue; - -}; - -/** - * Fire select callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid selectCallback - */ -List2Ctrl.prototype._itemSelect = function(itemIndex, paramsModifier, additionalModifier) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - // get paramsModifier - var paramsModifier = paramsModifier || {}; - - // get additionalModifier - var additionalModifier = additionalModifier || null; - - var appData = null; - var additionalData = null; - var params = {}; - - // event filtering - var filterEvent = false; - - if (this._isSlider(itemIndex)) - { - // the item contains a slider - additionalData = this.dataList.items[itemIndex].value; - } - - if (this._isSimpleSelectItem(itemIndex)) - { - // the item is simple select item - if ('preventSimpleSelect' != additionalModifier) - { - // process simple select behavior before firing the select callback - additionalData = this._simpleSelect(itemIndex); - } - - // apply event filter - var filterType = (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) ? 'toggle' : (this._isCheckBox(itemIndex)) ? 'check' : null; - filterEvent = this._applyEventFilter(itemIndex, filterType); - } - else if (this._isStep(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - this._setSecondaryMulticontroller(false, itemIndex); - } - else if (this._isLock(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - // restore focus and remove any secondary multicontroler - this._showFocus(this._lastItemWithFocus); - this._lockShowFocus(itemIndex, 'clear'); - this._setSecondaryMulticontroller(false, itemIndex); - } - else if (this._isStep(itemIndex)) - { - // apply event filter - var filterType = "step"; - filterEvent = this._applyEventFilter(itemIndex, filterType); - } - - // is this filtered event? - if (filterEvent) - { - return false; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - // merge params with params modifier - for (var i in paramsModifier) - { - params[i] = paramsModifier[i]; - } - - // return value - var result = false; - - // do not fire select on disabled items but instead fire select disabled - if (this.dataList.items[itemIndex].disabled) - { - // fire select disabled callback - if (typeof this.properties.selectDisabledCallback == 'function') - { - /* - * Handles touches on disabled list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectDisabledCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - } - else - { - // fire select callback - if (typeof this.properties.selectCallback == 'function') - { - /* - * Handles select on list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - - // dispatch select event - this._listEvent(this._EVENTS.ITEM_SELECT, params); - } - - if (this._hasData(itemIndex)) - { - // record this event and clear any timeouts - this.dataList.items[itemIndex]._data.lastEvent = new Date().getTime(); - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = null; - } - - return result; -}; - -/** - * Fire long press callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {event|integer} - raw touch/mouse event or directly the index of the item - * @return {boolean} - true if there's a valid longPressCallback - */ -List2Ctrl.prototype._itemLongPress = function(e) -{ - var eventCause = null; - var itemIndex = -1; - - // the parameter is an event - if (typeof e == 'object') - { - // determine target item - itemIndex = this._getTargetItem(e);var itemIndex = this._getTargetItem(e); - eventCause = 'Touch'; - } - // the parameter is an index - else if (!isNaN(e)) - { - itemIndex = e; - eventCause = 'Multicontroller'; - } - - // if the item is short-press-only -> prevent any longpress activity - if ('shortPressOnly' === this.dataList.items[itemIndex].itemBehavior) - { - return; - } - // if the item has itemBehavior other than shortAndLong and shortAndHold -> this is invalid property and prevent any longpress activity - else if ('shortAndLong' != this.dataList.items[itemIndex].itemBehavior && 'shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - log.warn('Lis2: Invalid itemBehavior property. Item behavior can be shortPressOnly / shortAndLong / shortAndHold'); - return; - } - - // make it long-pressed - this._itemMakeLongPress(e); - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // produce beep - this._beep('Long', eventCause); - - // fire long press callback - if ('shortAndLong' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.longPressCallback == 'function') - { - /* - * Handles long press on list items - * @param ctrlObj Object Reference to the list control that was long-pressed - * @param btnData Object Data that was attached to the long-pressed item - * @param params Object Object containing extra data - */ - this.properties.longPressCallback(this, appData, params); - - result = true; - } - // fire hold start callback - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.holdStartCallback == 'function') - { - /* - * Handles hold start on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStartCallback(this, appData, params); - - result = true; - } - - // raise the flag for long-press/hold-start issued callback - this._longPressIssued = true; - - // enter into list reorder on long press if the list supports it - if (this.properties.listReorder) - { - this._enterListReorder(); - this._startReorder(e); - } - - return result; -}; - - -/** - * Fire hold stop on an item. - * This function is called whenever the user ends touch - * on an item that has itemBehavior = shortAndHold - * TAG: internal, touch-only - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid holdStopCallback - */ -List2Ctrl.prototype._itemHoldStop = function(itemIndex) -{ - // validate item behavior property - if ('shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - return; - } - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // fire hold stop callback - if (typeof this.properties.holdStopCallback == 'function') - { - /* - * Handles hold stop on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStopCallback(this, appData, params); - - result = true; - } - - return result; -}; - -/** - * Perform outbound event filtering - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {boolean} - whethet to filter the event or not - */ -List2Ctrl.prototype._applyEventFilter = function(itemIndex, filterType) -{ - var filter = false; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return filter; - } - - var now = new Date().getTime(); - - switch (filterType) - { - case 'toggle' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.dataList.items[itemIndex].minChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.dataList.items[itemIndex].minChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - } - break; - - case 'check' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.properties.checkMinChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.properties.checkMinChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - } - break; - - case 'step' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - - if (this.properties.stepMinChangeInterval !== 0 && difference < this.properties.stepMinChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.properties.stepMinChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - } - break; - } - - return filter; -}; - -/** - * Timeout callback that is run if a select event - * is scheduled by the outbound filtering mechanism - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {void} - */ -List2Ctrl.prototype._filterTimeoutCallback = function(itemIndex, filterType) -{ - switch (filterType) - { - case 'toggle' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].value }, 'preventSimpleSelect'); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - break; - - case 'check' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].checked }, 'preventSimpleSelect'); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - break; - case 'step' : - this._itemSelect(itemIndex, { value : this.dataList.items[itemIndex].value }, 'preventSimpleSelect'); - break; - } -}; - -/** - * Register a settle timeout on any new user input. - * Any previous settle timeout should get cleared - * before setting a new one. The timeout state should - * be checked when public API call is made and depending - * on whether the timeout is running or not, the value - * will be cached or applied to the item. - * The settle time acts as an inbound event filtering mechanism. - * TAG: internal - * ========================= - * @param {integer} - itemIndex - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._registerSettleTimeout = function(itemIndex, itemType) -{ - log.debug('Settle scheduled'); - this._clearSettleTimeout(itemIndex, itemType); - - // schedule settle item - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._radioSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._tickSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.dataList.items[itemIndex].settleTime); - } - break; - } -}; - -/** - * Clear any settle timeouts on any user input. - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._clearSettleTimeout = function(itemIndex, itemType) -{ - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._radioSettleTimeoutId); - this._radioSettleTimeoutId = null; - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._tickSettleTimeoutId); - this._tickSettleTimeoutId = null; - } - break; - - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - } -}; - -/** - * Performs a check whether a settlie timeout - * is running for a particular item, radio group - * or tick group. - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {Boolean} - True if a settle timeout is running - */ -List2Ctrl.prototype._hasSettleTimeout = function(itemIndex, itemType) -{ - var timeoutRunning = false; - - switch (itemType) - { - case 'radio' : - if (null !== this._radioSettleTimeoutId && this._radioSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'tick' : - if (null !== this._tickSettleTimeoutId && this._tickSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'checkbox' : - case 'toggle' : - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return timeoutRunning; - } - - if (null !== this.dataList.items[itemIndex]._data.settleTimeout && this.dataList.items[itemIndex]._data.settleTimeout >= 0) - { - timeoutRunning = true; - } - break; - } - - return timeoutRunning; -}; - -/** - * Settle an item after the settle time expires. - * The cached value (if any) gets assigned as a - * real value to the item and the item is updated. - * This is the settleTimeout callback. - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item is successfully settled - */ -List2Ctrl.prototype._settleItem = function(itemIndex) -{ - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return false; - } - - // exit if the item index is out of range - if (isNaN(itemIndex) || itemIndex < 0 || itemIndex >= this.dataList.items.length) - { - return false; - } - - var item = this.dataList.items[itemIndex]; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return false; - } - - // get settle value and set it as real value, and update item - var settleValue = item._data.settleValue; - - - - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - if (null != item._data.settleValue) - { - // set real value - item.value = settleValue; - this.updateItems(itemIndex, itemIndex); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - } - else if (this._isCheckBox(itemIndex)) - { - // Note: setting the real value is done in the helpers - switch (item.image1) - { - case 'checkbox' : - if (null != item._data.settleValue) - { - // set real value - this._setCheckBox(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - break; - - case 'radio' : - if (null != item._data.settleValue) - { - // set real value - this._setRadio(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._radioSettleTimeoutId = null; - break; - - case 'tick' : - if (null != item._data.settleValue) - { - // set real value - this._setTick(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._tickSettleTimeoutId = null; - break; - } - } - else - { - // item does not support settlement - return false; - } - - log.debug('Settle item: ' + itemIndex + ', value: ' + settleValue); - - // return success - return true; - -}; - - -/** - * ========================= - * MULTICONTROLLER AND VUI - * ========================= - */ - -/** - * Main multicontroller handler - * TAG: multicontroller-only, public - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype.handleControllerEvent = function(eventID) -{ - log.debug("handleController() called, eventID: " + eventID); - - /* - * eventID - * - acceptFocusInit (sent on instantiation) - * - acceptFocusFromLeft - * - acceptFocusFromRight - * - acceptFocusFromTop - * - acceptFocusFromBottom - * - lostFocus - * - touchActive - * ... - */ - - var response; - - // ignore certain MC events when the list is in motion by touch - if (this._inDrag || (this._inScroll && 'touch' === this._scrollNature)) - { - switch (eventID) - { - case "acceptFocusInit" : - case "acceptFocusFromLeft" : - case "acceptFocusFromRight" : - case "acceptFocusFromTop" : - case "acceptFocusFromBottom" : - case "lostFocus" : - case "touchActive" : - case "controllerActive" : - // pass these events - break; - default : - // ignore everything else - return "ignored"; - break; - } - } - - if (!this._inSecondaryMulticontroller) - { - // we are in primary multicontroller mode - switch (eventID) - { - case "acceptFocusInit": - // consume event by default - response = "consumed"; - - // Input mode change to multicontroller - this._inputMode = 'controller'; - /* - * this event is received every time a template is displayed - * if we already have preset a focus item, do not set it again - */ - // Show focus animation - this._showFocusAnimation = true; - if ('restore' != this._initialScrollMode) - { - this._hasFocus = true; - var itemToGainFocus = this._canGainFocus('controllerActive'); - if (-1 !== itemToGainFocus) - { - this._showFocus(itemToGainFocus); - } - else - { - if (this.hasDataList()) - { - // we have data list and there are no enabled items -> give focus to the left - response = 'giveFocusLeft'; - } - else - { - // we probably dont't have a data list -> wait untul we get it - this._showFocus(this.properties.focussedItem); - } - } - } - else - { - this._showFocus(this.properties.focussedItem); - } - break; - - case "acceptFocusFromLeft": - // Show focus animation - this._showFocusAnimation = true; - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromRight": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromTop": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromBottom": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "lostFocus": - this._hideFocus(); - this._hideFocusLetterIndex(); - this._hasFocus = false; - response = "consumed"; - break; - - case "touchActive": - // Input mode change to touch - this._inputMode = 'touch'; - this._hideFocus(); - response = "consumed"; - break; - - case "controllerActive": - response = "consumed"; - break; - - case "cw": - // Rotate Right (CW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCW(); - break; - - case "ccw": - // Rotate Left (CCW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCCW(); - break; - - case "downStart": - // Tilt Down Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCDown(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCDown(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCDown.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll down for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollDownPage(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollDownPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll down for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "down" : - // Tilt Down Stop - - if ('downStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any downs without downStarts - response = "ignored"; - } - - break; - - case "upStart": - // Tilt Up Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCUp(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCUp(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCUp.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll up for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollUpPage(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollUpPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll up for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "up": - // Tilt Up Stop - - if ('upStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any ups without upStarts - response = "ignored"; - } - - break; - - case "leftStart": - // Tilt Left Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && this._inLetterIndexMulticontroller) - { - // Exit letter index multicontroller mode - this._setLetterIndexMulticontroller(false); - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusLeft..."); - response = "giveFocusLeft"; - } - break; - - case "left": - // Tilt Left Stop - - if ('leftStart' === this._lastControllerEvent) - { - response = "ignored"; - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any lefts without leftStarts - response = "ignored"; - } - break; - - case "rightStart": - // Tilt Right Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && !this._inLetterIndexMulticontroller) - { - // Enter into letter index multicontroller mode - this._setLetterIndexMulticontroller(true); - response = "consumed"; - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusRight..."); - response = "giveFocusRight"; - } - break; - - - case "right": - // Tilt Right Stop - - if ('rightStart' === this._lastControllerEvent) - { - response = "ignored"; - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any rights without rightStarts - response = "ignored"; - } - break; - - - case "selectStart": - // SelectStart (press down) - - if (this._inLetterIndexMulticontroller) - { - // get the focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - - // make focussed letter index hit - this._indexMakeHit(focussedLetterIndex); - } - else - { - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // make focussed index hit - this._itemMakeHit(focussedIndex); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, focussedIndex), this.properties.longPressTimeout); - } - - // always consume selectStart - response = "consumed"; - - break; - - case "select": - // Select (press down) - - if ('selectStart' === this._lastControllerEvent) - { - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // remove long press - this._itemRemoveLongPress(); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // fire letter index select - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._letterIndexSelect(currentFocussedLetterIndex, 'Multicontroller'); - } - else - { - if (this.properties.listReorder) - { - // if we are reordering lists (hence pressing down does not produce select event) - if (!this._inListReorder) - { - - // get focussed index - var focussedIndex = this._getFocussedIndex(); - - // check if focussed index is indeed eligable for list reorder - if ('shortAndLong' === this.dataList.items[focussedIndex].itemBehavior) - { - // we are about to begin list reorder - this._enterListReorder(); - } - - } - else - { - // we finish list reorder - this._releaseListReorder(); - } - - } - else - { - // if we are in normal mode - not reordering list - - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // does the element have secondary multicontroller behavior? - if (this._hasSecondaryMulticontroller(focussedIndex) && this._isSlider(focussedIndex)) - { - if (this.dataList.items[focussedIndex].allowAdjust) - { - // this item has secondary select and is adjustable slider -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this item has secondary select but is not adjustable -> trigger focus - this._triggerFocus(); - } - } - else if (this._hasSecondaryMulticontroller(focussedIndex)) - { - // this item has secondary select -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this is a regular item -> trigger focus - this._triggerFocus(); - } - - } - } - - // consume Select only after selectStart is consumed - response = "consumed"; - } - else - { - // ignore any selects without selectStarts - response = "ignored"; - } - - break; - - default: - // No action - response = "ignored"; - break; - } - - } - else - { - // we are in secondary multicontroller mode - response = this._handleControllerEventSecondary(eventID); - } - - // keep track of the last consumed event - if ('consumed' === response) - { - this._lastControllerEvent = eventID; - } - - /* - * returns - * - giveFocusLeft (control retains highlight unless it later gets lostFocus event) - * - giveFocusRight - * - giveFocusUp - * - giveFocusDown - * - consumed (always returned on select event, and if control adjusted highlight) - * - ignored (returned only if control doesn't know about focus) - */ - - log.debug("Event: " + eventID + " -> " + "Response: " + response); - - return response; - -}; - -/** - * Handle multicontroller clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - } - else - { - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller counter clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller down tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCDown = function() -{ - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - else - { - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - - -/** - * Handle multicontroller up tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCUp = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - // if we are in list reorder mode - push the draggable item up and set focus on it - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - var rfi = this._getRelativeFocussedIndex(); - } - else - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - - -/** - * handle controller event and apply it on items that are in secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype._handleControllerEventSecondary = function(eventID) -{ - // get the index - var focussedIndex = this._getFocussedIndex(); - - // handle event - switch (eventID) - { - case "up" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus up - this._showFocus('up'); - - // get relative focussed index after moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // we need to go back to the beginning in order to scroll up - if (rfi < 1) - { - this._scrollUpOne(); - } - break; - - - case "down" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus down - this._showFocus('down'); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleItems - 2; - // get relative focussed index after moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // we need to go to the end in order to scroll down - if (rfi >= bottomFocusThreshold) - { - this._scrollDownOne(); - } - break; - - case "leftStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('leftStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepDown(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "left" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('left'); - } - break; - - case "ccw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var itemDOMElement = this._getDOMItem(focussedIndex); - if(!itemDOMElement.classList.contains('minReached')) - { - var newValue = this._stepDown(focussedIndex); - - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "rightStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('rightStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepUp(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "right" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('right'); - } - - break; - - case "cw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var itemDOMElement = this._getDOMItem(focussedIndex); - if(!itemDOMElement.classList.contains('maxReached')) - { - var newValue = this._stepUp(focussedIndex); - - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "select": - // leave secondary multicontroller mode and trigger focus - this._setSecondaryMulticontroller(false); - this._showFocus(this._lastItemWithFocus); - this._triggerFocus(); - break; - } - - // the secondary multicontroller events are always consumed - return "consumed"; -}; - -/** - * Set secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @param {integer} - focussed index - * @return {void} - */ -List2Ctrl.prototype._setSecondaryMulticontroller = function(state, focussedIndex) -{ - // get focussed index - if (isNaN(focussedIndex)) - { - var focussedIndex = this._getFocussedIndex(); - } - - // do not set secondary multicontroller to true if the item is disabled - if (state && this.dataList.items[focussedIndex].disabled) - { - return; - } - - if (state) - { - // flag as we are in secondary multicontroller mode - this._inSecondaryMulticontroller = true; - - // add secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.add('secondaryFocus'); - } - - /** - * Fire select callback to notify apps that we are - * entering into secondary multicontroller mode. - * In most cases apps will ignore this event. - * Transition focus to subcontrols. - */ - if (this._isSlider(focussedIndex)) - { - // the target is a slider and can be adjusted -> set currently active slider - this._activeSlider = { - itemIndex : focussedIndex, // currently active slider index - slider : this._getSlider(focussedIndex) // currently active slider instance - }; - - // transition focus - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - - // fire select callback for app notification - this._itemSelect(focussedIndex); - } - - /** - * Place focus highlight on the lock inline button - * if the target is a lock item - */ - if (this._isLock(focussedIndex)) - { - this._lockShowFocus(focussedIndex, 1); - } - - this._currentSecondaryMulticontrollerItem = focussedIndex; - } - else - { - this._inSecondaryMulticontroller = false; - - // remove secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.remove('secondaryFocus'); - } - - /** - * Transition focus from subcontrols. - */ - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // transition focus - this._activeSlider.slider.handleControllerEvent('lostFocus'); - } - - this._currentSecondaryMulticontrollerItem = null; - } - -}; - -/** - * Set letter index multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {boolean} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexMulticontroller = function(state, isTouch) -{ - if (state) - { - // hide focus from the main list and show it in the letter index - this._hideFocus(); - this._showFocusLetterIndex(this._getCurrentLetterIndex()); - this._inLetterIndexMulticontroller = true; - } - else - { - // hide focus from the letter index and show it in the main list - if (!isTouch) - { - this._showFocus(this._lastItemWithFocus); - } - this._inLetterIndexMulticontroller = false; - this._hideFocusLetterIndex(); - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - } - -}; - -/** - * Manage focus highlight - * This is the single point for managing focus when requested from outside List2. - * (focusedItem setter, restoreContext) Manages reorder and focus as required. - * TAG: internal - * ========================= - * @param {number} - item index - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._manageFocus = function(item) -{ - if (this._inListReorder && !isNaN(item)) - { - this._reorderToIndex(item); - } - return this._showFocus(item); -} - -/** - * Show focus highlight - * This is the single point for showing the - * focus highlight - * TAG: internal - * ========================= - * @param {strig | number} - direction (up|down) or item index - * @param {boolean} - simulation mode: use to perform check on where the focus will end - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._showFocus = function(item, allowOffscreen, simulationMode, abortMode) -{ - log.debug("List2: _showFocus item, allowOffscreen, simulationMode, abortMode ", item, allowOffscreen, simulationMode, abortMode); - if (!this._hasFocus) - { - return; - } - - if (this._inputMode != 'controller') - { - // do not show the focus if the input mode is other than 'controller' - return; - } - - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return; - } - - // do not show focus when in list reorder by touch - if (this._reorderTouchElt) - { - return; - } - - var abortMode = (true === abortMode); - - // do not change focussed index when we are in loading and no scrolling is allowed during that time - if (!this.properties.scrollingDuringLoading && this._inLoading && !abortMode) - { - return; - } - - var simulationMode = (true === simulationMode); - - // get the last focussed index (real and relative) - var lastFocussedIndex = this._getFocussedIndex(); - var lastRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // if we don't have previous focus, select the topmost - if (lastFocussedIndex == null) - { - lastFocussedIndex = this._topItem; - } - - // hide the focus only in real mode - if (!simulationMode) - { - this._hideFocus(); - } - - - var nextFocussedIndex = -1; - var useTransition = true; - var useRelativeIndeces = true; - - // find the next focussed element index - // NOTE: 'down' and 'up' are ued primarily when focussing with multicontroller - switch (item) - { - case 'down' : - // 'down' uses relative positioning - // the next one but not exceeding the visible items - - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.min(lastFocussedIndex+1, this.dataList.itemCount-1); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex >= this.dataList.itemCount-1) { - // we have reached the end of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the next one - nextRealFocussedIndex++; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.min(lastRelativeFocussedIndex+1, this.properties.visibleItems-1); - } - break; - - case 'up' : - // 'up' uses relative positioning - // the previous one but not lower than the first one - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.max(lastFocussedIndex-1, 0); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex <= 0) { - // we have reached the beginning of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the previous one - nextRealFocussedIndex--; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.max(lastRelativeFocussedIndex-1, 0); - } - break; - - default : - // move highlight instantly when jumping to an item - useTransition = false; - // absolute indeces use real positioning - useRelativeIndeces = false; - - if (!isNaN(item)) - { - // specific one -> make sure it is within the list bounds - nextFocussedIndex = this.m.max(this.m.min(item, this.dataList.itemCount-1), 0); - } - else - { - // the top one - nextFocussedIndex = this._topItem; - } - } - - // if we are in simulation -> return the would-be focussed index - if (simulationMode) - { - return nextFocussedIndex; - } - - // From here on, perform actual focus change - // ----------------------------------------- - var pos = 0; - if (useRelativeIndeces) - { - // convert relative nextFocussedIndex to position - pos = nextFocussedIndex * this.properties.itemHeight; - // convert nextFocussedIndex back to real one - nextFocussedIndex = this._relativeToRealIndex(nextFocussedIndex); - } - else - { - // are we allowed to focus off screen? - if (!allowOffscreen) - { - // check if focus is outside the screen and scroll the list so that it is inside - if (this._realToRelativeIndex(nextFocussedIndex) < 0) - { - // scrollt up - this._scrollTo(nextFocussedIndex, 0); - } - else if (this._realToRelativeIndex(nextFocussedIndex) > this.properties.visibleItems - 2) - { - // scroll down - this._scrollTo((nextFocussedIndex + 2) - this.properties.visibleItems, 0); - } - } - - // convert absolute nextFocussedIndex to position - pos = (nextFocussedIndex - this._topItem) * this.properties.itemHeight; - } - - - - - // find the new focussed element - var focussedElement = this._getDOMItem(nextFocussedIndex); - - - // do we have a focussed element? - if (focussedElement) - { - focussedElement.classList.add('focus'); - - // create first focus animation - if (this._showFocusAnimation) - { - this._showFocusAnimation = false; - this.firstFocusAnimationEndCallback = this._firstFocusAnimationEndCallback.bind(this); - focussedElement.addEventListener("animationend", this.firstFocusAnimationEndCallback, false); - focussedElement.classList.add('firstFocus'); - } - } - - // set letter index position - this._setLetterIndexPosition(nextFocussedIndex); - - // store focussed item - this._lastItemWithFocus = nextFocussedIndex; - - return nextFocussedIndex; -}; - -/** - * First focus animation end callback that is fired - * when the first focus animation finishes. - * It removes the firstFocus class from the event's target - * and clears any subsequent animation callbacks - * TAG: internal - * ========================= - * @param {AnimationEvent} - * @return {void} - */ -List2Ctrl.prototype._firstFocusAnimationEndCallback = function(e) -{ - e.target.classList.remove('firstFocus'); - e.target.removeEventListener("animationend", this.firstFocusAnimationEndCallback, false); - this.firstFocusAnimationEndCallback = null; -}; - -/** - * Hide focus highlight - * This is the single point for hiding the - * focus highlight - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._hideFocus = function() -{ - // Preserve focussed element - this._lastItemWithFocus = this._getFocussedIndex(); - - for (var i=0; i disable select only if the slider is adjustable - if (this.dataList.items[focussedIndex].allowAdjust) - { - fireSelect = false; - } - - // reset currently active slider - this._activeSlider = null; - } - - if (this._isStep(focussedIndex)) - { - params = { - value : this.dataList.items[focussedIndex].value, - finalAdjustment : true, - }; - } - - /** - * Trigger the currently selected button - */ - if (this._isLock(focussedIndex)) - { - var focussedButton = this._lockGetFocus(focussedIndex); - var actionResult = this._lockActivate(focussedIndex, focussedButton); - this._lockShowFocus(focussedIndex, 'clear'); - params = { additionalData : actionResult }; - } - - // prevent select on disabled items - if (this.dataList.items[focussedIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Multicontroller'); - - this._itemSelect(focussedIndex, params); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[focussedIndex].itemBehavior) - { - this._itemHoldStop(focussedIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - - } -}; - -/** - * Check whether the list can gain focus. In certain cases focus cannot be - * shown (e.g. when there are no items available) or if it can gain it - * it should be restored on the nearest available item if the one that - * previously had focus is disabled. - * TAG: internal - * ========================= - * @param {MouseEvent|Number} - optional argument. If passed a check will be performed whether the target item is disabled - * @return {integer} - the item that will have focus. If no item can have focus, return -1 - */ -List2Ctrl.prototype._canGainFocus = function(e) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return -1; - } - - var itemToGainFocus = -1; - - // check if we are touching the element - if (typeof e === 'object') - { - var targetItem = this._getTargetItem(e); - - // the item is enabled and can gain focus - if (-1 !== targetItem && !this.dataList.items[targetItem].disabled) - { - itemToGainFocus = targetItem; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(targetItem); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - else if (typeof e === 'number') - { - if (-1 !== e && !this.dataList.items[e].disabled) - { - itemToGainFocus = e; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(e); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - // check whether this is called from the controllerActive event handler - else if ('controllerActive' === e && this.properties.focussedItem > 0 && this.dataList.items[this.properties.focussedItem] && !this.dataList.items[this.properties.focussedItem].disabled) - { - itemToGainFocus = this.properties.focussedItem; - } - // check if last item with focus is disabled - else if (this.dataList.items[this._lastItemWithFocus] && !this.dataList.items[this._lastItemWithFocus].disabled) - { - itemToGainFocus = this._lastItemWithFocus; - } - else - { - // show focus on the closest available item to the last with focus - var nearestItem = this._getNearestEnabledItem(this._lastItemWithFocus); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - - // if we have tabs and no enabled items, always show focus on the first line allowing tabs navigation - if (this.tabsCtrl && -1 === itemToGainFocus) - { - itemToGainFocus = this._topItem; - } - } - - return itemToGainFocus; -}; - -/** - * Get focussed index - * TAG: internal, helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getFocussedIndex = function() -{ - var focussedIndex = this._lastItemWithFocus; - - for (var i=0; i - */ -List2Ctrl.prototype._getFocussedElement = function() -{ - var focussedElement = null; - var focussedIndex = this._getFocussedIndex(); - for (var i=0; i= this.dataList.itemCount) - { - currentItem = null; - } - else - { - while (this.dataList.items[currentItem].disabled) - { - if (currentItem >= this.dataList.itemCount-1 || currentItem <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentItem = null; - break; - } - currentItem = ('down' === direction) ? currentItem+1 : currentItem-1; - } - } - return currentItem; -}; - -/** - * Get nearest enabled item in all directions - * If there are two enabled items in both directions that are - * at equal distances from the reference item, the one below is - * returned. - * TAG: internal, helper - * ========================= - * @param {integer} - from which item to search - * @return {integer} - the next enabled item. - * If nothing is found, return Null - */ -List2Ctrl.prototype._getNearestEnabledItem = function(fromItem) -{ - var nearestEnabledItem = null; - - var nearestDown = this._getNearestEnabledItemByDirection(fromItem, 'down'); - var nearestUp = this._getNearestEnabledItemByDirection(fromItem, 'up'); - - if (null === nearestDown === nearestUp) - { - // no enabled item is found - nearestEnabledItem = null; - } - else if (null === nearestDown) - { - // nothing is found below -> return the one above - nearestEnabledItem = nearestUp; - } - else if (null === nearestUp) - { - // nothing is found above -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - var differenceDown = this.m.abs(fromItem - nearestDown); - var differenceUp = this.m.abs(fromItem - nearestUp); - if (differenceDown === differenceUp) - { - // equally spaced -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - // differently spaced -> return the closer one - nearestEnabledItem = (differenceDown < differenceUp) ? nearestDown : nearestUp; - } - } - - return nearestEnabledItem; -}; - -/** - * Get secondary select status of an item - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {boolean} - whether the item has secondary multicontroller - */ -List2Ctrl.prototype._hasSecondaryMulticontroller = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var hasSecondaryMulticontroller = false; - - var type = this.dataList.items[itemIndex].itemStyle; - for (var i=0; i return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+this.properties.visibleItems-2, 'down'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi + 2 - this.properties.visibleItems; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll up by one element - * If the element that will be placed at the top - * position is disabled, the list will be scrolled to - * the nearest available enabled item - * TAG: internal - * ========================= - * @return {integer} - new position of the scroller in px - */ -List2Ctrl.prototype._scrollUpOne = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topItem === 0) - { - // we can't scroll up any more -> return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi - 1; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.min(newPos, 0); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll down by one page (screen) - * TAG: internal - * ========================= - * @return {string} - paged | atlimit | onepage - */ -List2Ctrl.prototype._scrollDownPage = function() -{ - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = 'onepage'; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the bottom - case 'bottom' : - // place focus on the last available item - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'up'); - if (null != nei && nei >= this._topItem) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the bottom - case 'bottomclose' : - // search for enabled item in the bottom screen - var nei = this._getNearestEnabledItemByDirection(this.dataList.itemCount - 1, 'up'); - if (null != nei && nei >= this.dataList.itemCount - this.properties.visibleItems) - { - // place focus on the last available item and scroll to the bottom - this._showFocus(nei); - this._scrollTo(this.dataList.itemCount - this.properties.visibleItems); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.min(this._topItem + this.properties.visibleItems + currentRelativeFocussedIndex, this.dataList.itemCount-1); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem + this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future top item down - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'down'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atLimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll up by one page (screen) - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollUpPage = function() -{ - - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = ''; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the top - case 'top' : - // place focus on the first available item - var nei = this._getNearestEnabledItemByDirection(-1, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the top - case 'topclose' : - // search for enabled item in the top screen - var nei = this._getNearestEnabledItemByDirection(0, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - // place focus on the last available item and scroll to the top - this._showFocus(nei); - this._scrollTo(0); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.max(this._topItem - this.properties.visibleItems + currentRelativeFocussedIndex, 0); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem - this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.min(newPos, 0); // constrain it to the min scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future bottom item up - var nei = this._getNearestEnabledItemByDirection(this._topItem - this.properties.visibleItems, 'up'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atlimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll to the top - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollTop = function() -{ - this._performScroll(0); // do the scroll -}; - -/** - * Scroll to the bottom - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollBottom = function() -{ - this._performScroll(this._maxScrollY); // do the scroll -}; - -/** - * Do the actual scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._performScroll = function(pos, duration) -{ - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return; - } - - // if menu can be scrolled (it has enough list items) - if (this._isScrollable) - { - // make it snappy - var newPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(pos, duration); - } -}; - -/** - * Animate the scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateScroll = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - if (null !== this.scrollerAnimationEndCallback) - { - // remove any redundant animationEnd listeners - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scrollerAnimationEndCallback = null; - } - - // animate scroller or directly call the animation end callback if the time is 0 - this.scroller.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollerAnimationEndCallback = this._scrollerAnimationEnd.bind(this); - this.scroller.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scroller.style.top = pos + 'px'; - - this._inScroll = false; - if (time > 0) - { - this._inScroll = true; - } - - // set top item and update display - this._updateScrollIndicator(pos, time); - this._setTopListItem(pos); - this._updateRange(); -}; - -/** - * Abort any ongoing scroll and reset any flags - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._abortScroll = function(e) -{ - // aborting scroll is possible only while the list is scrolling - if (false === this._inScroll) - { - return; - } - - // get target item - var targetItem = this._getTargetItem(e); - - // check if target item is enabled - if (this.dataList.items[targetItem] && !this.dataList.items[targetItem].disabled) - { - // show focus there - this._showFocus(targetItem, true, false, true); - } - else - { - // restore focus - this._restoreFocus(); - } - - // get current snapped position - var snapPos = this._getSnapPosition(this.scroller.offsetTop); - this._animateScroll(snapPos, 0); - - // reset any touch flags - this._inDrag = false; - this._inScroll = false; - this._scrollNature = null; - this._inHorizontalDrag = null; - this._hDragItem = null; - this._stopSelect = false; - this._startTime = 0; - this._startItem = null; - this._startDOMItem = null; - this._activeSlider = null; - this._startY = 0; - this._startX = 0; -}; - - -/** 2. LIST SNAPPING **/ - -/** - * Get snap position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getSnapPosition = function(pos) -{ - return this.properties.itemHeight * (Math.round(pos / this.properties.itemHeight)); -}; - -/** - * Get snap (above) position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest above item edge - */ -List2Ctrl.prototype._getSnapPositionAbove = function(pos) -{ - return this.properties.itemHeight * (Math.floor(pos / this.properties.itemHeight)); -}; - -/** - * Scroll list to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {void} - */ -List2Ctrl.prototype._snap = function(pos) -{ - // the snap position is the same as the current - if (pos == this._y) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - return; - } - else if (pos === this._minScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex > this._topItem + this.properties.visibleItems - 1) - { - this._restoreFocus(); - } - return; - } - - var snapPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(snapPos); -}; - -/** 3. LIST SWIPING AND PHYSICS **/ - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipe = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._y, this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0, 0); - - /* ANIMATE THE SCROLLER */ - var newPos = this.m.min(this.m.max(this._y + momentumY.dist, this._maxScrollY), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.scroller.offsetTop) // only if newPos is a number and the list is worth scrolling - { - this._animateScroll(newPos, swipeDuration); - } - else - { - // set top item and bring focus on the screen - this._setTopListItem(newPos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - } -}; - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipeIndex = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._yIndex, this._maxScrollYIndex < 0 ? this._scrollerHIndex - this._maskH + this._yIndex - this._minScrollYIndex : 0, 0); - - /* ANIMATE THE LETTER INDEX SCROLLER */ - var newPos = this.m.min(this.m.max(this._yIndex + momentumY.dist, this._maxScrollYIndex), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getIndexSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.letterIndex.offsetTop) // only if newPos is a number and the letter index is worth scrolling - { - // start animation - this._animateLetterIndex(newPos, swipeDuration); - } - else - { - // set top letter index and bring focus on the screen - this._setTopLetterIndex(newPos); - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (focussedLetterIndex < this._topLetterIndex) - { - this._showFocusLetterIndex(this._topLetterIndex); - } - } -}; - -/** - * @param {integer} - dragged distance - * @param {time} - time dragged - * @param {integer} - this._y - * @param {integer} - this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0 - * @param {integer} - 0 - */ -List2Ctrl.prototype._momentum = function (dist, time, maxDistUpper, maxDistLower, size) -{ - var deceleration = this.properties.deceleration, - speed = this.m.abs(dist) / time, - newDist = (speed * speed) / (2 * deceleration), - newTime = 0, outsideDist = 0; - - // Proportinally reduce speed if we are outside of the boundaries - if (dist > 0 && newDist > maxDistUpper) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistUpper = maxDistUpper + outsideDist; - speed = speed * maxDistUpper / newDist; - newDist = maxDistUpper; - } else if (dist < 0 && newDist > maxDistLower) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistLower = maxDistLower + outsideDist; - speed = speed * maxDistLower / newDist; - newDist = maxDistLower; - } - - newDist = newDist * (dist < 0 ? -1 : 1); - newTime = speed / deceleration; - - return { dist: newDist, time: Math.round(newTime) }; -}; - - -/** - * ========================= - * LETTER INDEX - * ========================= - */ - -/** - * Letter index select - * scrolls list to letter index - * TAG: internal - * ========================= - * @param {integer} - the new position of the scroller in element index. - * @return {void} - */ -List2Ctrl.prototype._letterIndexSelect = function(letterIndex, eventCause) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // check if if letterIndex is a valid index - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - return; - } - - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - - // set scroll nature - this._scrollNature = 'letterIndex'; - - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - - // set letter index active position - this._setLetterIndexPosition(this.letterIndexData[letterIndex].itemIndex); - - // update last item with focus so that focus gets restored in the correct place - this._lastItemWithFocus = this.letterIndexData[letterIndex].itemIndex; - - // set proper event cause - var eventCause = ('Multicontroller' != eventCause && 'Touch' != eventCause) ? null : eventCause; - // produce beep - this._beep('Short', eventCause); - - // dispatch letter select event - var eventData = { - index : letterIndex, - label : this.letterIndexData[letterIndex].label, - itemIndex : this.letterIndexData[letterIndex].itemIndex, - }; - this._listEvent(this._EVENTS.LETTER_SELECT, eventData); -}; - -/** - * Schedule letter index select after some time - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - - if (!clear) - { - // if no letter index is passed, get the currently focussed one - if (undefined === letterIndex) - { - // check whether we already have focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex) - { - // if yes, schedule to that one - letterIndex = focussedLetterIndex; - } - } - - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - this._letterIndexSelect(letterIndex); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; - -/** - * Schedule background letter index select after some time. - * Background select occurs without affecting the letter index - * scroll position. This is intended to be used only programatically. - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleBackgroundLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - // check for a valid letter index item - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - log.warn('List2: a valid letter index expected. Letter index passed": ' + letterIndex); - return; - } - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - if (!clear) - { - // activate the new index - this._setCurrentLetterIndex(letterIndex); - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - // set scroll nature - this._scrollNature = 'letterIndex'; - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; -/** - * Animate the letter index - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @param {integer} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateLetterIndex = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - // animate letter index - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.letterIndexAnimationEndCallback = this._letterIndexAnimationEnd.bind(this); - this.letterIndex.addEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndex.style.top = pos + 'px'; - - // set top letter index - this._setTopLetterIndex(pos); -}; - -/** - * Set top letter index item depending on the position - * TAG: internal - * ========================= - * @param {integer} - position in px at which the letter should be - * @return {void} - */ -List2Ctrl.prototype._setTopLetterIndex = function(pos) -{ - // pos should be number for proper topLetterIndex calculation - if (!isNaN(pos)) - { - this._prevTopLetterIndex = this._topLetterIndex; - this._topLetterIndex = -(Math.round(pos / this.properties.letterIndexHeight)); - } -}; - -/** - * Get snap position of letter index - * depending on the new letter index position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getIndexSnapPosition = function(pos) -{ - return this.properties.letterIndexHeight * (Math.round(pos / this.properties.letterIndexHeight)); -}; - -/** - * Scroll letter index to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {void} - */ -List2Ctrl.prototype._snapIndex = function(pos) -{ - // the snap position is the same as the current - if (pos == this._yIndex) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollYIndex) - { - // set top item and bring focus on the screen - this._setTopLetterIndex(pos); - var focussedIndex = this._getFocussedLetterIndex(); - if (focussedIndex < this._topLetterIndex) - { - this._restoreLetterIndexFocus(); - } - return; - } - - var snapPos = this._getIndexSnapPosition(pos); - - // start animation - this._animateLetterIndex(snapPos); -}; - -/** - * Scroll to a specific index item - * TAG: internal - * ========================= - * @param {integer | string} - letter or letter index - * @return {void} - */ -List2Ctrl.prototype._scrollToIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - var targetIndex = -1; - - if (!isNaN(letter)) - { - // we are going to a letter index - targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - } - else if (typeof letter === 'string'); - { - // we are searching for the letter index of the letter - for (var i=0, l=this.letterIndexData.length; i above or below the visible range - // NOTE: if the letter is within the visible range this should not get called at all - if (-1 != targetIndex && targetIndex >= this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // look below -> find closest target index so that the focus is visible and apply target index correction - targetIndex = targetIndex - this.properties.visibleLetterIndexItems + 1; - } - else if (-1 != targetIndex && targetIndex <= this._topLetterIndex) - { - // look above -> find closest target index so that the focus is visible - // correction: the taget index is the top item whereas the item in question is the second one - targetIndex--; - } - else - { - // we don't scroll if the target is visible - return; - } - - // do the scroll - var newPos = -(targetIndex) * this.properties.letterIndexHeight; // calculate new position - newPos = this.m.max(this.m.min(newPos, this._minScrollYIndex), this._maxScrollYIndex); // constrain it to scroll bounds - this._animateLetterIndex(newPos); // start animation - - -}; - -/** - * Scroll down by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollDownOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the bottom-most position - if (this._topLetterIndex === this.letterIndexData.length - this.properties.visibleLetterIndexItems) - { - // we can't scroll down any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+this.properties.visibleLetterIndexItems-2, 'down'); - // do not scroll if no enabled letters are found - if (null != bi) - { - var newTopLetter = bi + 2 - this.properties.visibleLetterIndexItems; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.max(newPos, this._maxScrollYIndex); // constrain it to the max scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Scroll up by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollUpOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topLetterIndex === 0) - { - // we can't scroll up any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopLetter = bi - 1; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.min(newPos, this._minScrollYIndex); // constrain it to the min scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Set letter index position relative to the - * focussed item in the scroller - * TAG: internal - * ========================= - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexPosition = function(index) -{ - // check for letter index - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return false; - } - - // get focussed item - var focussedIndex; - if (!isNaN(index)) - { - focussedIndex = index; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // get the new index - var targetIndex = -1; - for (var i=this._letterIndexDataSorted.length-1; i>=0; i--) - { - if (focussedIndex >= this._letterIndexDataSorted[i].itemIndex) - { - targetIndex = this._letterIndexDataSorted[i].publicIndex; - break; - } - } - - // show focus on target index - if (targetIndex > -1) - { - this._setCurrentLetterIndex(targetIndex); - } - - // check if letter index scrolling is needed - if (targetIndex >= this._topLetterIndex && targetIndex < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - return; - } - - // scroll to target index - if (targetIndex > -1) - { - this._scrollToIndex(targetIndex); - } -}; - -/** - * Set currently active letter index - * TAG: internal - * ========================= - * @param {integer} - letter item index - * @return {integer} - the currently active letter index - */ -List2Ctrl.prototype._setCurrentLetterIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return null; - } - - var targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - - - // remove any previously active letter index - for (var i=0, l=this.letterIndexData.length; i= this.letterIndexData.length-1) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - case 'up' : - // we are searching for the previous - targetIndex = lastFocussedIndex; - while (targetIndex > 0) - { - targetIndex--; - if (-1 != this.letterIndexData[targetIndex].itemIndex) - { - break; - } - else if (targetIndex <= 0) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - default : - // we are searching for the index of the letter - for (var i=0, l=this.letterIndexData.length; i= letterIndexCount) - { - currentLetter = null; - } - else - { - while (this.letterIndexData[currentLetter].disabled) - { - if (currentLetter >= letterIndexCount-1 || currentLetter <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentLetter = null; - break; - } - currentLetter = ('down' === direction) ? currentLetter+1 : currentLetter-1; - } - } - return currentLetter; -}; - -/** - * Exit hit state of the currently hit index item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._indexRemoveHit = function() -{ - for (var i=0, l=this.letterIndexData.length; i bring back reorder item - if (this._inListReorder && this._reorderTouchElt) - { - this._bringReorderItem(); - } - - // Focus adjust after animation ends - - // get list position - var listPosition = null; - if (0 === this._topItem) - listPosition = 'top'; - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; - else - listPosition = 'middle'; - - // get scroll direction - var scrollDirection = null; - if (this._prevTopItem > this._topItem) - scrollDirection = 'up'; - else if (this._prevTopItem < this._topItem) - scrollDirection = 'down'; - else - scrollDirection = 'none'; - - // get scroll size - var scrollSize = this.m.abs(this._prevTopItem - this._topItem); - - if ('page' === this._scrollNature) - { - // do not place focus, it should have been done by the paging function - } - else if ('item' === this._scrollNature) - { - // show focus - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // check if focussed index is outside the screen and we actually have a scroll - if (scrollSize > this.properties.visibleItems-1 && !this._inLetterIndexMulticontroller) - { - // restore focus - this._restoreFocus(); - } - else if (scrollSize > 0 && !this._inLetterIndexMulticontroller) - { - // check if the focus is just slightly outside the visible range - if (this._lastItemWithFocus < this._topItem || this._lastItemWithFocus >= this._topItem + this.properties.visibleItems) - { - // restore focus - this._restoreFocus(); - } - else - { - // else the focus remains on the screen -> only set letter index position - this._setLetterIndexPosition(this._getFocussedIndex()); - } - } - else - { - // we don't have a scroll -> nothing to do here - } - } - - // lower _inScroll flag - this._inScroll = false; - - // reset scroll nature - this._scrollNature = null; - - // dispatch scroll end event - this._listEvent(this._EVENTS.SCROLL_END, {scrollPosition:this._topItem}); -}; - -/** - * Restore focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreFocus = function() -{ - // check if the top item is enabled - if (!this.dataList.items[this._topItem].disabled) - { - this._showFocus(this._topItem, false, false, true); - } - // top item is disabled, find the nearest enabled item below the top one - else - { - var neiDown = this._getNearestEnabledItem(this._topItem, 'down'); - // check if the item is on screen - if (null != neiDown && neiDown >= this._topItem && neiDown < this._topItem + this.properties.visibleItems) - { - this._showFocus(neiDown, true, false, true); - } - // there's no enabled item or it is off screen - else - { - this._showFocus(this._topItem, false, false, true); - } - } -}; - -/** - * Scroll indicator animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorAnimationEnd = function() -{ - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicatorAnimationEndCallback = null; - - // fadeOut scroll indicator - this._fadeOutScrollIndicator(); -}; - -/** - * Letter index animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._letterIndexAnimationEnd = function() -{ - // remove animation end callbacks - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndexAnimationEndCallback = null; - - // restore focus - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex && (focussedLetterIndex < this._topLetterIndex || focussedLetterIndex > this._topLetterIndex + this.properties.visibleLetterIndexItems - 1)) - { - // focus is off screen - this._restoreLetterIndexFocus(); - } - else if (null != focussedLetterIndex) - { - // schedule letter index select if letter is enabled - if (!this.letterIndexData[focussedLetterIndex].disabled) - { - this._scheduleLetterIndexSelect(focussedLetterIndex); - } - } -}; - -/** - * Restore letter index focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreLetterIndexFocus = function() -{ - // check if the top letter index is enabled - if (!this.letterIndexData[this._topLetterIndex].disabled) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule letter index select - this._scheduleLetterIndexSelect(this._topLetterIndex); - } - else - { - // look for enabled item down and up - var neiDown = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'down'); - var neiUp = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'up'); - // determine scroll direction - var scrollDirection = (this._topLetterIndex - this._prevTopLetterIndex < 0) ? 'up' : 'down'; - - // check whether we have an enabled item on screen - if (null != neiDown && neiDown >= this._topLetterIndex && neiDown < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // there is an enabled item on screen -> place the focus there - this._showFocusLetterIndex(neiDown); - // schedule letter index select - this._scheduleLetterIndexSelect(neiDown); - } - else if ('down' === scrollDirection) - { - // we are scrolling down -> look for enabled item up - if (null != neiUp) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiUp); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - else if ('up' === scrollDirection) - { - // we are scrolling up -> look for enabled item down - if (null != neiDown) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiDown); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - } -}; - - -/** - * ========================= - * SLIDERS AND TOGGLE CONTROL - * ========================= - */ - -/** - * Passes START (mousedown) event to the currently - * targeted slider instance and returns it. - * TAG: internal - * ========================= - * @param {MouseEvent} - * @param {Boolean} - * @return {SliderCtrl} - */ -List2Ctrl.prototype._slideStart = function(e, skipActiveSlider) -{ - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // check if slider can be adjusted - if (!this.dataList.items[itemIndex].allowAdjust) - { - return; - } - - // check if we are in the hittable area - if(!this._hasRightHittableArea(this.dataList.items[itemIndex])) - { - var relativeX = e.pageX - this._maskPositionX; - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight; - var leftBoundary = this.properties.sliderReferencePointRight - this.properties.sliderWidth; - } - else if(this.dataList.items[itemIndex].indented) - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)) + (this.properties.indentOffset * 2); - var leftBoundary = this.properties.sliderReferencePointLeft; - } else - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)); - var leftBoundary = this.properties.sliderReferencePointLeft; - } - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> exit - return; - } - - var sliderInstance = this._getSlider(itemIndex); - var skipActiveSlider = (true === skipActiveSlider); - if (!skipActiveSlider) - { - // set currently active slider - this._activeSlider = { - itemIndex : itemIndex, // currently active slider index - slider : sliderInstance // currently active slider instance - }; - - // transition focus to slider and hide focus on the item - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - this._hideFocus(); - - // pass the event to the SliderCtrl - this._activeSlider.slider._onDownHandler(e); - } - - return sliderInstance; -}; - -List2Ctrl.prototype._slideMove = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - return; - } - - // determine target item - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // pass the event to the SliderCtrl - this._activeSlider.slider._onMoveHandler(e); -}; - -List2Ctrl.prototype._slideEnd = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - var sliderInstance = this._slideStart(e, true); - if (sliderInstance && !this._stopSelect) - { - // pass the event to the SliderCtrl - sliderInstance._onDownHandler(e); - sliderInstance._onUpHandler(e); - } - return; - } - else - { - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - if (this._inSecondaryMulticontroller && itemIndex == this._currentSecondaryMulticontrollerItem) - { - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // pass the event to the SliderCtrl - this._activeSlider.slider._onUpHandler(e); - - // transition focus back to item and remove it from the slider - this._activeSlider.slider.handleControllerEvent('lostFocus'); - this._showFocus(this._lastItemWithFocus, true); - } - } - - // reset currently active slider - this._activeSlider = null; -}; - -List2Ctrl.prototype._slideCallback = function() -{ - // get item index from the first argument - var itemIndex = arguments[0]; - - // get value and final adjustment from fourth argument - var value = arguments[3].value; - var finalAdjustment = arguments[3].finalAdjustment; - - // update local value - this.dataList.items[itemIndex].value = value; - - // Fire slide callback passing forward anything in the arguments - if (typeof this.properties.slideCallback == 'function') - { - // fire callback with original slider params - // this.properties.slideCallback.apply(null, Array.prototype.slice.call(arguments, 1)); - - // fire per-design callback - var params = { - itemIndex : itemIndex, - value:value, - finalAdjustment : finalAdjustment - }; - this.properties.slideCallback(this, this.dataList.items[itemIndex].appData, params); - } -}; - - - -/* - * ========================= - * TOGGLE BUTTONS - * When a button is selected it is automatically - * highlighted (activated) and the value is reported to the - * button select callback (if defined) - * ========================= - */ - - -/** - * Remove hit state from the toggle button - * TAG: touch-only, internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {void} - */ -List2Ctrl.prototype._buttonRemoveHit = function(itemIndex) -{ - var targetElt = this._getDOMItem(itemIndex); - if (targetElt) - { - var hitItems = targetElt.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - // Check which button is hit - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button hit - if (buttonId) - { - // save the button as _startButton - this._startButton = buttonId; - - var domItem = this._getDOMItem(itemIndex); - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle button - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable && this._startButton) - { - // we are outside the hittable area and we have started from a button -> return cancel - return 'cancel'; - } - else if (!inHittable) - { - // we are outside the hittable area -> return cancel - return null; - } - - // Check which button is selected - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button active - if (buttonId && buttonId === this._startButton) - { - this._startButton = null; - - if (this.dataList.items[itemIndex].value == buttonId) - { - // we ended on already selected button -> cancel - return 'cancel'; - } - // we ended up on the same button we started -> select that button - this._buttonActivate(itemIndex, buttonId); - } - else if (buttonId && null === this._startButton) - { - // we started off the buttons but ended up on a button -> select next button - this._startButton = null; - return null; - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startButton = null; - return 'cancel'; - } - - // Return the button id - return buttonId; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectLeft = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectRight = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current+1); -}; - -/** - * Activate toggle button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonActivate = function(itemIndex, buttonId) -{ - // Ensure that buttonId is valid and wraps in a loop - if ('style10' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 2) - buttonId = 1; - else if (buttonId < 1) - buttonId = 2; - } - else if('style11' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 3) - buttonId = 1; - else if (buttonId < 1) - buttonId = 3; - } - else if('draggable' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = 1; - } - else - { - log.debug('Unknown item style for itemIndex ' + itemIndex); - return null; - } - - if ('draggable' != this.dataList.items[itemIndex].itemStyle) - { - // Save the new value in the dataList - this.dataList.items[itemIndex].value = buttonId; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Remove any residual hit states - this._buttonRemoveHit(itemIndex); - - // Activate the button - if (domItem) - { - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // save the button as _startLockButton - this._startLockButton = buttonId; - - // remove hit - this._lockRemoveHit(itemIndex); - - // make that button hit - if (1 === buttonId) - { - this._lockShowFocus(itemIndex, 1); - domItem.querySelector('.buttonLock').classList.add('hit'); - } - else - { - this._lockShowFocus(itemIndex, 2); - domItem.querySelector('.buttonDelete').classList.add('hit'); - } - - this._hideFocus(); - - return true; - -}; - -/** - * Select lock button - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockSelect = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return null; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return null; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // set secondary multicontroller leaving highlight from where it started - if (this._startLockButton) - { - this._setSecondaryMulticontroller(true, itemIndex); - this._lockShowFocus(itemIndex, this._startLockButton); - } - - // we are outside the hittable area -> return null - return null; - } - - var action = null; - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // Make that button active - if (buttonId === this._startLockButton) - { - this._startLockButton = null; - // we ended up on the same button we started -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else if (null === this._startButton) - { - this._startLockButton = null; - // we started off the buttons but ended up on a button -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startLockButton = null; - - return null; - } - - // Return the performed action - return action; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusLeft = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusRight = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current+1); -}; - -/** - * Activate lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the button that is going to be activated - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockActivate = function(itemIndex, buttonId) -{ - var action = null; - - switch (buttonId) - { - case 1 : - if (this.dataList.items[itemIndex].locked) - { - this.dataList.items[itemIndex].locked = false; - action = 'unlock'; - } - else - { - this.dataList.items[itemIndex].locked = true; - action = 'lock'; - } - break; - case 2 : - if (!this.dataList.items[itemIndex].locked) - { - action = 'delete'; - } - break; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Update the item - if (domItem) - { - switch (action) - { - case 'lock' : - domItem.classList.add('locked'); - break; - case 'unlock' : - domItem.classList.remove('locked'); - break; - } - } - - return action; -}; - - -/** - * Show focus highlight on a lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the index of the button that will be focused - * @return {integer} - id of the focussed lock button - */ -List2Ctrl.prototype._lockShowFocus = function(itemIndex, buttonId) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - if ('clear' === buttonId) - { - if (domItem) - { - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.remove('focus'); - } - return null; - } - else - { - // validate button id - var buttonId = this.dataList.items[itemIndex].locked ? 1 : this.m.min(this.m.max(buttonId, 1), 2); - - if (domItem) - { - // add focus on the respective button - switch (buttonId) - { - case 1 : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - case 2 : - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.add('focus'); - break; - default : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - } - } - return buttonId; - } -}; - - -/** - * Get currently focused lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - id of the currently focussed lock button - */ -List2Ctrl.prototype._lockGetFocus = function(itemIndex) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - var focussedButton = null; - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (domItem.querySelector('.buttonLock').classList.contains('focus')) - focussedButton = 1; - else if (domItem.querySelector('.buttonDelete').classList.contains('focus')) - focussedButton = 2; - } - - return focussedButton; -}; - - -/* - * ========================= - * STEP ITEM - * ========================= - */ - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {MouseEvent} - raw mouse event - * @return {integer} - the new value - */ -List2Ctrl.prototype._stepAdjust = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // perform hit test - var itemDOMElement = this._getDOMItem(itemIndex); - if (!itemDOMElement) - { - return; - } - - var p = itemDOMElement.querySelector('.plus'); - var m = itemDOMElement.querySelector('.minus'); - var pLayout = { x1:p.offsetLeft, x2:p.offsetLeft + p.clientWidth }; - var mLayout = { x1:m.offsetLeft, x2:m.offsetLeft + m.clientWidth }; - - var newValue = null; - - if (relativeX >= pLayout.x1 && relativeX <= pLayout.x2) - { - // plus pressed - if(!itemDOMElement.classList.contains('maxReached')) - { - newValue = this._stepUp(itemIndex); - } - } - else if (relativeX >= mLayout.x1 && relativeX <= mLayout.x2) - { - // minus pressed - if(!itemDOMElement.classList.contains('minReached')) - { - newValue = this._stepDown(itemIndex); - } - } - else if (relativeX < mLayout.x1) - { - newValue = 'commit'; - } - - - return newValue; -}; - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepUp = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.min(this.dataList.items[itemIndex].value + this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].max); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - -/** - * Decrease the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepDown = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.max(this.dataList.items[itemIndex].value - this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].min); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - - -/** - * ========================= - * LIST REORDERING - * ========================= - */ - -/** - * Enter into list reorder mode - * This method stores the original item style of the - * item that is being reordered and substitutes it with - * an internal 'draggable' item style. - * TAG: internal - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype._enterListReorder = function(fromInit) -{ - // keep a copy of the item before converting it to a draggable item - - var focussedIndex; - if (fromInit) - { - focussedIndex = this.properties.focussedItem; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // check for items in the dataList - if (!this.dataList || !this.dataList.items || !this.dataList.items[focussedIndex]) - { - return; - } - - // do not reorder disabled items - if (this.dataList.items[focussedIndex].disabled) - { - return; - } - - // enter into List Reordering mode - this._inListReorder = true; - - this.dataList.items[focussedIndex].itemBehavior = 'shortAndLong'; // make it accept long press (if not already) - this._reorderItem = this.dataList.items[focussedIndex]; - this._reorderItemIndex = focussedIndex; - this._reorderCurrentIndex = focussedIndex; - - // convert the item to a draggable item - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - if(this._reorderItem.itemStyle === "style38") - { - draggableItem.label1 = (this._reorderItem.hasOwnProperty('label1')) ? this._reorderItem.label1 : ''; - draggableItem.label2 = (this._reorderItem.hasOwnProperty('label2')) ? this._reorderItem.label2 : ''; - } - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[focussedIndex] = draggableItem; - this.updateItems(focussedIndex, focussedIndex); - -}; - -/** - * Leave list reorder mode - * The item that is being reordered is restored - * to it initial style. The select callback is - * then fired to notify the interested parties of - * the change and the new position of the item. - * TAG: internal - * ========================= - * @param {Boolean} - prevent item selection when releasing the reorder - * @return {void} - */ -List2Ctrl.prototype._releaseListReorder = function(preventSelect) -{ - // exit list reordering mode - this._inListReorder = false; - this._appIsAtSpeed = false; - - // get draggable item index - var draggableItems = this.getItemsByType('draggable'); - if (!draggableItems.length) - { - return; - } - - var draggableItemIndex = draggableItems[0]; - - // convert the draggable item back into the previous item type - this.dataList.items[draggableItemIndex] = this._reorderItem; - this.updateItems(draggableItemIndex, draggableItemIndex); - - // cast preventSelect as Boolean - var preventSelect = Boolean(preventSelect); - - // selection is allowed - if (!preventSelect) - { - // fire item select - var params = { - newIndex : draggableItemIndex, - oldIndex : this._reorderItemIndex - }; - this._itemSelect(draggableItemIndex, params); - } - - // release the copy of the reorder item - this._reorderItem = null; - this._reorderItemIndex = null; - this._reorderTouchElt = null; - -}; - - -/** - * Touch start reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._startReorder = function(e) -{ - // get target item index - var itemIndex = this._getTargetItem(e); - - // get draggable item index - if (itemIndex === this._reorderCurrentIndex) - { - this._startY = e.pageY - this._maskPositionY; - this._startX = e.pageX - this._maskPositionX; - - // do we have hit on the button? - var positiveButtonHit = this._buttonMakeHit(e); - - if (!positiveButtonHit) - { - this._itemMakeLongPress(e); - - // clone draggable item - var tmp = this._getDOMItem(itemIndex); - this._reorderTouchElt = tmp.cloneNode(true); - this.scroller.appendChild(this._reorderTouchElt); - - // convert the draggable item to a ghost item - var ghostItem = {itemStyle:'ghost', hasCaret:false}; - this.dataList.items[itemIndex] = ghostItem; - this.updateItems(itemIndex, itemIndex); - - this._hideFocus(); - - // raise _inDrag - this._inDrag = true; - } - else - { - // flag the behaviour as release intent - this._releaseReorderByTouch = true; - } - - // track event - this._trackEvent(e); - } -}; - -/** - * Touch move reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._moveReorder = function(e) -{ - if (this._reorderTouchElt) - { - // track event - this._trackEvent(e); - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // get last move - var moveDirection = this._getMoveDirection(); - - // reset any scheduled scrolling if the user intends cacnelling the scroll - if (newPos <= (this._topItem * this.properties.itemHeight) + this.properties.itemHeight && - newPos > this._topItem * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - else if (newPos >= (this._topItem + this.properties.visibleItems - 2) * this.properties.itemHeight && - newPos < (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - - // drag down - if (1 === moveDirection) - { - // have we passed the last item's top border? - if ( (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) && (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) ) - { - this._reorderGhostItemDown(); - } - else if (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) - { - // do we have a scroll down scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos >= (this._reorderCurrentIndex * this.properties.itemHeight) + this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemDown(); - } - } - // drag up - else if (-1 === moveDirection) - { - // have we passed the top item's top border? - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // do we have a scroll up scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos <= (this._reorderCurrentIndex * this.properties.itemHeight) - this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemUp(); - } - } - - } // endif (this._reorderTouchElt) -}; - -/** - * Touch end reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._endReorder = function(e) -{ - if (this._reorderTouchElt) - { - // get nearest snap position - var newSnappedIndex = Math.floor( ( (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) ) / this.properties.itemHeight ); - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = newSnappedIndex * this.properties.itemHeight; - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the scroller if in bounds - this._reorderTouchElt.style.top = newPos + 'px'; - - // convert the ghost item back to a draggable item - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - if(this._reorderItem.itemStyle === "style38") - { - draggableItem.label1 = (this._reorderItem.hasOwnProperty('label1')) ? this._reorderItem.label1 : ''; - draggableItem.label2 = (this._reorderItem.hasOwnProperty('label2')) ? this._reorderItem.label2 : ''; - } - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[this._reorderCurrentIndex] = draggableItem; - this.updateItems(this._reorderCurrentIndex, this._reorderCurrentIndex); - - // remove the cloned element - this._reorderTouchElt.parentElement.removeChild(this._reorderTouchElt); - } - - this._itemRemoveLongPress(); - this._reorderTouchElt = null; - - // reset flags - this._inHorizontalDrag = null; - this._hDragItem = null; - this._inDrag = false; - this._stopSelect = false; - - // restore focus - this._showFocus(this._reorderCurrentIndex); - - // clear any scroll timeout - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - - // are we about to release reorder - if (this._releaseReorderByTouch && this._isToggle(this._reorderCurrentIndex)) - { - // remove hit state of button and release list reorder - this._buttonRemoveHit(this._reorderCurrentIndex); - this._releaseListReorder(); - this._releaseReorderByTouch = false; - } - -}; - -/** - * After the list has scrolled due to touch reorder action, - * upon animation end, the touch reorder item is brought under the - * user's finger and if the possition requires it, a new scroll - * is scheduled. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._bringReorderItem = function() -{ - if (this._trackedEvents.length && this._reorderTouchElt) - { - // get last event - var lastEvent = this._trackedEvents[this._trackedEvents.length-1]; - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (lastEvent.y - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // we are past the top item's top boundary - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemUp(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (0 == this._topItem) - { - // update blank spot - this._reorderGhostItemUp(); - } - else if (this._topItem != this.dataList.itemCount - this.properties.visibleItems && - newPos >= (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemDown(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) - { - // update blank spot - this._reorderGhostItemDown(); - } - - } -}; -/** - * Reorder the item to the index - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {void} - */ -List2Ctrl.prototype._reorderToIndex = function(itemIndex) -{ - if (!this._inListReorder || isNaN(itemIndex)) - { - log.error("list1 _reorderToIndex : Invalid arguments - inListReorder, itemIndex", this._inListReorder, itemIndex); - return; - } - - if (itemIndex != this._reorderItemIndex) - { - if (itemIndex < this._reorderItemIndex) - { - this._reorderItemUp(this._reorderItemIndex - itemIndex) - } - else - { - this._reorderItemDown(itemIndex - this._reorderItemIndex) - } - } -} - -/** - * Reorder the item down - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemDown = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(draggableItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(draggableItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; -/** - * Reorder the item up - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemUp = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(draggableItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, draggableItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; - -/** - * Reorder ghost item one position down - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemDown = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(ghostItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(ghostItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - -/** - * Reorder ghost item one position up - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemUp = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(ghostItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, ghostItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - - -/** - * ========================= - * LIST EVENTS API - * ========================= - */ - -/** - * List event - * TAG: internal - * ========================= - * @param {string} - Event name - * @param {*} - Event data - * @return {void} - */ -List2Ctrl.prototype._listEvent = function(type, data) -{ - var data = data || null; - switch (type) - { - case this._EVENTS.ITEM_SELECT : - this._dispatch(this._EVENTS.ITEM_SELECT, data); - break; - case this._EVENTS.LETTER_SELECT : - this._dispatch(this._EVENTS.LETTER_SELECT, data); - break; - case this._EVENTS.DATALIST_CHANGE : - this._dispatch(this._EVENTS.DATALIST_CHANGE, null); - break; - case this._EVENTS.SCROLL_START : - this._dispatch(this._EVENTS.SCROLL_START, data); - break; - case this._EVENTS.SCROLL_END : - this._dispatch(this._EVENTS.SCROLL_END, data); - break; - case this._EVENTS.CLEAN_UP : - this._dispatch(this._EVENTS.CLEAN_UP, data); - break; - default : - // nothing to do - break; - } -}; - -/** - * Get listeners array for an event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {array} - */ -List2Ctrl.prototype._getListeners = function(type, useCapture) -{ - var captype = (useCapture ? '1' : '0') + type; - if (!(captype in this._eventListeners)) - this._eventListeners[captype] = []; - return this._eventListeners[captype]; -}; - -/** - * Dispatch custom event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {void} - */ -List2Ctrl.prototype._dispatch = function(type, data) -{ - if (!type || '' == type) - return; - var evt = new CustomEvent( type, { detail : { data : data, bubbles: true, cancelable: true } } ); - this.dispatchEvent(evt); -}; - -/** - * Add event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.addEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 === ix) - listeners.push(listener); -}; - -/** - * Remove event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.removeEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 !== ix) - listeners.splice(ix, 1); -}; - -/** - * Displatch custom list event - * TAG: public - * ========================= - * @param {object} - event object - * @return {boolean} - */ -List2Ctrl.prototype.dispatchEvent = function(evt) -{ - var listeners = this._getListeners(evt.type, false).slice(); - for (var i= 0; i dataList.items.length) - { - for (var i=dataList.items.length; i= 0) - { - // force exit secondary multicontroller - this._inSecondaryMulticontroller = false; - - var additionalSpace = this._getAdditionalSpace(); - - this.scroller.style.height = this.dataList.itemCount * this.properties.itemHeight + additionalSpace + 'px'; - this._scrollerH = this.scroller.offsetHeight; - this._emptyScroller(); - this._scrollIndicatorReset(); - if(0 === this.dataList.itemCount) - { - this._scrollIndicatorBuild(false); - } - else - { - this._scrollIndicatorBuild(true); - } - - // set line numbers - this.setLineNumbers(); - } - -}; - -List2Ctrl.prototype.hasDataList = function() -{ - if (this.dataList == null) - { - return false; - } - - if (!this.dataList.hasOwnProperty('itemCountKnown') && !this.dataList.hasOwnProperty('itemCount') && !this.dataList.hasOwnProperty('items')) - { - return false; - } - - if (this.dataList.itemCountKnown && this.dataList.itemCount == 0) - { - return false; - } - - if (!this.dataList.itemCountKnown && this.dataList.itemCount <= 0) - { - return false; - } - - return true; -}; - -/** - * Update Items - * - * This is intended to be used whenever the bound data is changed programmatically by the app. In other words, - * it informs the control that bound data has changed … and if the range of changed items overlaps with items - * rendered into HTML objects, then the ListMenu must update those elements. There are several use cases for this: - * - * 1. For the case where the dataList is fetched asynchronously in the background after ListMenu is displayed, - * the updateItems() API will be called as new data arrives. I think this use case is described fairly completely - * in section 2.2.4 of the ListMenu SDD. Note that these updates may correspond to the user scrolling, or may simply - * occur in the background as the list is loaded into GUI while the user is still looking at the first N list items. - * Also note that the listCount can change and the ListMenu control must adapt appropriately, including handling - * reduction of the list count. - * - * 2. To allow the application to update menu text dynamically, e.g. to display the name of the connected USB - * Audio device instead of “USB”, or to change the displayed image(s). - * - * 3. To allow the application to enable/disable menu items or to set/clear the “selected” indicator. - * - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype.updateItems = function(firstItem, lastItem) -{ - log.debug("List2 updateItems() firstItem, lastItem",firstItem, lastItem); - // update _maxScrollY - this._maxScrollY = this.mask.offsetHeight - this.scroller.offsetHeight; - - var emptyDOMItem = null; - - // clear _needDataTimeoutId - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = null; - - this._prepareItems(firstItem, lastItem); - this._localizeItems(firstItem, lastItem); - - // trim dataList.items if it is larger than dataList.itemCount - if (this.dataList && - this.dataList.itemCountKnown && - this.dataList.items && - this.dataList.itemCount < this.dataList.items.length) - { - this.dataList.items = this.dataList.items.slice(0, this.dataList.itemCount); - console.assert(this.dataList.itemCount == this.dataList.items.length, 'dataList.itemCount is not equal to dataList.items.length'); - } - - // validate first item - if (this.dataList.itemCountKnown && firstItem < -1) - { - log.warn('List2: firstItem is less than -1: ' + firstItem + ' passed. Setting it to -1.'); - firstItem = -1; - } - - // validate last item - if (this.dataList.itemCountKnown && lastItem >= this.dataList.itemCount) - { - log.warn('List2: lastItem is more than or equals dataList.itemCount(' + (this.dataList.itemCount-1) + '): ' + lastItem + ' passed. Setting it to ' + (this.dataList.itemCount - 1) + '. ' + this.uiaId + ' check your variable validation!?'); - lastItem = this.dataList.itemCount - 1; - } - - - // check for invalid items (e.g. firstItem=0, lastItem=-1) -> set loading - if (firstItem > lastItem) - { - firstItem = lastItem = -1; - } - - if (firstItem == -1 && lastItem == -1) - { - // we have dataList but no list items => show loading - this._setLoading(true); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem && !this._hasFill) - { - - - // we have dataList and we have list items but we do not have fill => do initial fill - var lastFillItem = this.m.min(lastItem, this.properties.itemsBefore + this.properties.itemsAfter); - - this._fill(firstItem, lastFillItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - if (this.properties.focussedItem < this.dataList.itemCount) - { - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - else - { - this.properties.focussedItem = this.dataList.itemCount - 1; - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - /* - * Immediately scroll to a preset location and - * show focus on preset item if this is specified - * in the control's config. Focus placement needs to be done - * after the DOM is refreshed. This is done only the - * first time after a fresh setDataList() call. - * Focussed item has precedence over scroll location. - */ - if (null === this._initialScrollMode) - { - // first check if the focussed item and the scroll position are all on the same screen - // scroll to that position and show the focus according to the config - if ( (this.properties.focussedItem >= 0 || this.properties.scrollTo >= 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 1)) ) - { - log.debug('Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // set initial focus to a particular item if this is set in the config - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem >= 0) - { - log.debug('Focus is not visible and has priority'); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // scroll (no animation) to a particular item if this is set in the config - // the focus will be placed on the top item - else if (this.properties.scrollTo >= 0) - { - log.debug('Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._topItem = this._canGainFocus(this._topItem); - this._showFocus(this._topItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - } - // sync the top item with focus if not in initial mode any more - // enter in this case usualy when a new data list is set - else - { - var focussedItem = this.focussedItem; - var topInFocusRange = focussedItem >= this.topItem && focussedItem < this.topItem + this.properties.visibleItems - 1; - var prevTopInFocusRange = focussedItem >= this._prevTopItem && focussedItem < this._prevTopItem + this.properties.visibleItems - 1; - if (!topInFocusRange && !prevTopInFocusRange) - { - this.topItem = focussedItem; - } - else if (!topInFocusRange && prevTopInFocusRange) - { - this.topItem = this._prevTopItem; - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem) - { - // preserve focussed element - var lastFocussedIndex = this._getFocussedIndex(); - - // we have dataList and we have list items, and we have fill => perform update - this._updateDisplay(firstItem, lastItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - // restore focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(lastFocussedIndex, true); - } - else if (this._inSecondaryMulticontroller) - { - // treat disabling the secondary multicontroller item as interrupt -> commit value and exit - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this.dataList.items[smi].disabled) - { - this._setSecondaryMulticontroller(false, smi); - this._showFocus(smi, true); - } - else if (this.dataList.items[smi]) - { - this._setSecondaryMulticontroller(true, smi); - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else - { - log.error(this.uiaId + ' called List2 updateItems() with invalid arguments: firstItem = ' + firstItem + ', lastItem = ' + lastItem); - } - - // suppress secondary item request when the list is in reorder mode - if (this.properties.enableSecondaryItemRequest && !this._inListReorder) - { - // do we have empty DOM items? - if (null == emptyDOMItem) - { - // clear _secondaryRequestCount - this._secondaryRequestCount = 0; - } - else if (this._secondaryRequestCount <= this.properties.secondaryRequestLimit) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - // increment _secondaryRequestCount - this._secondaryRequestCount++; - } - else - { - log.warn('Lis2: control has reached the secondary request count limit. Enabling the list'); - // we have reached secondaryRequestLimit -> set loading to False - this._setLoading(false); - } - } - - // restore the focus to the last focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(this._lastItemWithFocus, true); - } - -}; - - -/** 2. LETTER INDEX API **/ - -/** - * Set letter index data on demand, filling letters in the letter index area - * and assigning jump indices to them, so that when touched or selected - * by multicontroller, the list jumps to the respective index. - * TAG: public - * ========================= - * @param {data} - letter index data object - * @return {boolean} - True if letter index binding operation is a success - */ -List2Ctrl.prototype.setLetterIndexData = function(data) -{ - // validate input - if (!(data instanceof Array)) - { - log.error('Lis2: letter index data should be a valid array'); - return false; - } - - // validate control support - if (!this.properties.hasLetterIndex) - { - log.error('Lis2: list2 does not support letter index'); - return false; - } - - // reset any previous letter index data - this.letterIndexData = []; - this.letterIndex.innerText = ''; - - var letterIndexItem; - var label; - for (var i=0, l=data.length; i= 0) - { - this._letterIndexDataSorted[this._letterIndexDataSorted.length] = { - publicIndex : this.letterIndexData.length-1, - itemIndex : data[i].itemIndex - }; - } - } - - // sort private and filtered letter index by the itemIndex in ASC order - this._letterIndexDataSorted.sort(function(a,b) { - var compRes = 0; - if (a.itemIndex < b.itemIndex) - compRes = -1; - else if (a.itemIndex > b.itemIndex) - compRes = 1; - else - compRes = 0; - return compRes; - }); - - // set letter index scroller height - var additionalSpace = Math.ceil(this.properties.letterIndexHeight / 2) - 5; // adjusting factor - this.letterIndex.style.height = i * this.properties.letterIndexHeight + additionalSpace + 'px'; - this._scrollerHIndex = this.letterIndex.offsetHeight; - - // update _maxScrollYIndex - this._maxScrollYIndex = this.letterIndexWrapper.offsetHeight - this.letterIndex.offsetHeight; - - // set initial active letter index if there are any available - if (this.hasDataList() && this._letterIndexDataSorted.length) - { - // get current focus index and first letter index - var focussedIndex = this._getFocussedIndex(); - var firstIndex = this._letterIndexDataSorted[0].itemIndex; - - if (firstIndex > 0 && focussedIndex < firstIndex) - { - this._setLetterIndexPosition(firstIndex); - } - else - { - this._setLetterIndexPosition(focussedIndex); - } - - } - else if (this._letterIndexDataSorted.length) - { - this._setLetterIndexPosition(this._letterIndexDataSorted[0].itemIndex); - } -}; - - -/** 3. VOICE API **/ - -/** - * Set left button configuration depending on current list configuration: - * title style, visible items, item count, item thickness - * TAG: public, VUI - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setLineNumbers = function() -{ - // check if we need to show numbers - if (!this.properties.numberedList) - { - return; - } - - // check if we have some items to number - if (!this.dataList.hasOwnProperty('itemCount') || this.dataList.itemCount <= 0) - { - return; - } - - - var style = ''; - var maxItemCount = 0; - - // determine max item count and style - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - maxItemCount = this.properties.thickItems ? 5 : 6; - style = this.properties.thickItems ? 'Style02' : 'Style04'; - break; - case 'tabsTitle' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style03a' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'style05' : - case 'style08' : - maxItemCount = 4; - style = this.properties.thickItems ? 'Style07' : 'Style06'; - break; - case 'style06' : - case 'style07' : - maxItemCount = 3; - style = this.properties.thickItems ? 'Style09' : 'Style08'; - break; - default : - log.warn('Lis2: unknown title style: ' + this._currentTitle.titleStyle); - return; - break; - } - break; - default : - log.warn('Lis2: unknown title configuration: ' + this.properties.titleConfiguration); - return; - break; - } - - // get actual item count - var itemCount = this.m.min(this.dataList.itemCount, maxItemCount); - - // check for common API - if (framework.common.setLineNumbers) - { - // call LeftBtnCtrl to show list numbers - return framework.common.setLineNumbers(itemCount, style); - } - -}; - -/** - * Performs select on the specified line number. When the select callback is fired, - * fromVui parameter is set to true. The function can return several possible - * statuses depending on the output of the operation. - * TAG: public, VUI - * ========================= - * @param {integer} - the line number that needs to be selected - * @return {string} - 'selected', 'outOfRange', 'disabled', 'sendAck', 'noList' - */ -List2Ctrl.prototype.selectLine = function(lineNumber) -{ - // get target item - var targetIndex = this._topItem + (lineNumber - 1); - - // decide what to return depending on what's visible - var status; - - // check if the list supports line numbers - if (!this.hasDataList()) - { - status = 'noList'; - log.debug('Lis2: selectLine() called with no list on the screen'); - } - else if (!this.dataList.vuiSupport) - { - status = 'noList'; - log.debug('Lis2: no VUI support for this list'); - } - else if (targetIndex > this.dataList.itemCount - 1 || targetIndex < 0) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (targetIndex < this._topItem || targetIndex > this._topItem + this.properties.visibleItems) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (!this.dataList.items[targetIndex].vuiSelectable) - { - status = 'notSelectable'; - log.debug('Lis2: list item is not VUI selectable'); - } - else if (this.dataList.items[targetIndex].disabled) - { - status = 'disabled'; - log.debug('Lis2: list item is disabled'); - this._itemSelect(targetIndex, {fromVui:true, vuiStatus:status}); - } - else - { - // default status is 'selected' -> if the item is not selectable, the callback will not be fired - var selectResult = this._itemSelect(targetIndex, {fromVui:true, vuiStatus:'selected'}); - if (true === selectResult) - { - // normal enabled status - status = 'selected'; - } - else if (false === selectResult) - { - // status if no select callback is attached - status = 'sendAck'; - } - else - { - // returned status from the select callback in the app - status = selectResult; - } - } - - return status; -}; - -/** - * Scrolls the list one page down. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageDown = function() -{ - var status = this._scrollDownPage(); - return status; -}; - -/** - * Scrolls the list one page up. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageUp = function() -{ - var status = this._scrollUpPage(); - return status; -}; - - -/** 4. SLIDER / TOGGLE API **/ - -/** - * Set slider to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the slider/pivot item - * @param {number} - the new value of the slider/pivot - * @return {void} - */ -List2Ctrl.prototype.setSliderValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isSlider(itemIndex)) - { - log.warn(this.uiaId + ': Lis2: only sliders/pivots can be used in the Slider API. Item style ' + item.itemStyle + ' passed'); - return; - } - - var slider = this._getSlider(itemIndex); - if (slider) - { - slider.setValue(value); - } - else - { - log.error(this.uiaId + ': Lis2: could not get slider instance for itemIndex ' + itemIndex); - } -}; - - -/** - * Set toggle to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the toggle item - * @param {number} - the new value of the toggle - * @return {void} - */ -List2Ctrl.prototype.setToggleValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.debug('Item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isToggle(itemIndex) && item.itemStyle != 'styleOnOff') - { - log.warn('Lis2: only toggle items can be used in the Toggle API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // normalize value - if (item.itemStyle == 'style10') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - else if(item.itemStyle == 'style11') - { - var value = this.m.max(this.m.min(value, 3), 1); - } - else if(item.itemStyle == 'styleOnOff') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'toggle')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'checkbox')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // cast as boolean - var value = Boolean(value); - - // set value - item.checked = value; - - // update item - this.updateItems(itemIndex, itemIndex); -}; - - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setRadio = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'radio')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setRadio = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'tick')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a tick item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the tick item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setTick = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an empty range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // filled item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get filled range - * traverse the dataList.items for filled items and returns - * an array of filled-item ranges - * TAG: public - * ========================= - * @return {array} - Array([firstFilled, lastFilled], [firstFilled, lastFilled]) - */ -List2Ctrl.prototype.getFilledRange = function() -{ - var ranges = []; - var currentRange = []; - - for (var i=0, l=this.dataList.items.length; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an filled range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // empty item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get current focus mode - * TAG: public - * ========================= - * @return {string} - 'mainList' | 'letterIndex' | 'noFocus' - */ -List2Ctrl.prototype.getFocusMode = function() -{ - var currentFocusMode = 'mainList'; - if (!this._hasFocus) - { - currentFocusMode = 'noFocus'; - } - else if (this._inLetterIndexMulticontroller) - { - currentFocusMode = 'letterIndex'; - } - - return currentFocusMode; -}; - - -/** 7. OTHER **/ - -/** - * Set loading state of the list - * TAG: public - * ========================= - * @param {boolean} - enable or disable loading state - * @return {void} - */ -List2Ctrl.prototype.setLoading = function(state) -{ - // cast as boolean - var state = Boolean(state); - this._setLoading(state); -}; - - -/** - * Public API that changes the loading configuration - * ========================= - * @param {Object} - object that will set loading item configuration - * @return {Object} - retuns the loading configuration object - */ -List2Ctrl.prototype.setLoadingConfig = function (config) -{ - for (var i in config) - { - this.properties.loadingConfig[i] = config[i]; - } - - if (null !== this.properties.loadingConfig.loadingTextId && undefined !== this.properties.loadingConfig.loadingTextId && "" !== this.properties.loadingConfig.loadingTextId) - { - this.properties.loadingConfig.loadingText = this._getLocalizedString(this.properties.loadingConfig.loadingTextId, this.properties.loadingConfig.loadingSubMap); - } - this.loading.querySelector(".loadingText").innerText = ""; - this.loading.querySelector(".loadingText").appendChild(document.createTextNode(this.properties.loadingConfig.loadingText)); - this.loading.querySelector(".loadingImage1").style.backgroundImage = 'url(' + this.properties.loadingConfig.loadingImage1 + ')'; - - return this.properties.loadingConfig; -}; - -/** - * Enter or release reorder mode - * TAG: public - * ========================= - * @param {boolean} - enter or release list reorder - * @param {boolean} - prevent item select on releasing reorder - * @return {void} - */ -List2Ctrl.prototype.setReorder = function(state, preventSelect) -{ - // cast as boolean - var state = Boolean(state); - var preventSelect = Boolean(preventSelect); - - if (state && !this._inListReorder) - { - // if user has lost the reorder item - if (null != this._reorderCurrentIndex && (this._reorderCurrentIndex < this._topItem || this._reorderCurrentIndex > this._topItem + this.properties.visibleItems-1)) - { - if (this.dataList.items[this._reorderCurrentIndex] && !this.dataList.items[this._reorderCurrentIndex].disabled) - { - // reorder item is outside screen. Bring it back in and show focus on it - this._showFocus(this._reorderCurrentIndex); - } - } - - // enter into reorder - this._enterListReorder(); - } - else if (!state && this._inListReorder) - { - // release reorder - this._releaseListReorder(preventSelect); - } -}; - -/** - * Enter or release reorder mode - * TAG: public - * ========================= - * @param {boolean} - enter or release list reorder - * @return {void} - */ -List2Ctrl.prototype.setReorderAtSpeed = function(AtSpeed) -{ - if(AtSpeed) - { - this._inListReorder = false; - this._appIsAtSpeed = AtSpeed ; - this.properties.listReorder = false; - } - else - { - this._inListReorder = true; - this._appIsAtSpeed = AtSpeed ; - this.properties.listReorder = true; - } -}; - -/** - * Set fixed title for the list - * TAG: public - * ========================= - * @param {object} - title properties - * @return {void} - */ -List2Ctrl.prototype.setTitle = function(titleStructure) -{ - - // validate titleStructure - if (!titleStructure || !titleStructure.hasOwnProperty('titleStyle')) - { - return; - } - - /* - * title structure: - * { - * titleStyle : 'style02', - * text1Id : null, - * text1SubMap : null, - * text1 : '', - * image1 : 'path/to/image.png' - * } - */ - - // prepare title - var titleStructure = titleStructure || {}; - titleStructure = this._prepareTitle(titleStructure); - - if (this._currentTitle) - { - // we already have a title -> update it - - // validate new title - switch (titleStructure.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - // thin - if ('style02' != this._currentTitle.titleStyle && - 'style02a' != this._currentTitle.titleStyle && - 'style03' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style05' : - case 'style08' : - // medium - if ('style05' != this._currentTitle.titleStyle && - 'style08' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style06' : - case 'style07' : - // thick - if ('style06' != this._currentTitle.titleStyle && - 'style07' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - } - } - - // empty title element - this.title.innerText = ''; - // remove old title style class - if (this._currentTitle) - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - this.title.classList.remove(this._currentTitle.titleStyle); - } - // add title style as a class - this.title.classList.add(titleStructure.titleStyle); - - // fill it - var line1, line2, image1; - - switch (titleStructure.titleStyle) - { - case 'style02' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style02a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style03' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style05' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleMedium'); - - break; - - case 'style06' : - - if (titleStructure.image1 === 'canvas') - { - // preview image is a canvas - image1 = document.createElement('canvas'); - image1.className = 'image1'; - // store canvas for public API call - this.titleCanvas = image1; - this.title.appendChild(image1); - } - else - { - // preview image is an image - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - } - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style07' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style08' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleMedium'); - - break; - - default : - log.error('Lis2: unknown title style: ' + titleStructure.titleStyle); - } - - // save the title structure - this._currentTitle = titleStructure; - -}; - - -/** 8. CONTEXT CAPTURE AND RESTORE **/ - -/** - * Context capture - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.getContextCapture = function() -{ - var obj = { - hasFocus : this._hasFocus, - topItem : this._topItem, - focussedItem : this._getFocussedIndex(), - itemCount : this.dataList ? this.dataList.itemCount : 0 - }; - - log.debug('Lis2: getContextCapture obj ', obj); - return obj; -}; - -/** - * Context restore - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.restoreContext = function(restoreData) -{ - log.debug('Lis2: restoreContext restoreData ', restoreData); - // validate input - if (!restoreData.hasOwnProperty('topItem') || !restoreData.hasOwnProperty('focussedItem')) - { - log.info('No data to restore'); - return; - } - - - // restore hasFocus flag - if (restoreData.hasFocus) - { - this._hasFocus = true; - } - - if (this.hasDataList()) - { - // scroll to previous position and show previous focus - // no checks for value conflicts are necessary. These ought to be correct. - this._scrollTo(restoreData.topItem); - - // NOTE: actual focus placement happens in controllerActive event handling - - // mark the list as data-restored preventing any subsequent auto-scrolls - this._initialScrollMode = 'restore'; - - this._manageFocus(restoreData.focussedItem); - } - else - { - log.info('List has no dataList to restore'); - } - - // overwrite control properties - this.properties.scrollTo = restoreData.topItem; - this.properties.focussedItem = restoreData.focussedItem; - this._lastItemWithFocus = restoreData.focussedItem; -}; - - -/** 9. BACKGROUND API **/ - -/** - * Set a custom background on the list control - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setListBackground = function(img, position) -{ - this.clearListBackground(); - this.listBackground = document.createElement('div'); - this.listBackground.className = 'List2CtrlCustomBackground'; - this.listBackground.style.backgroundImage = 'url('+img+')'; - - // set background position - if (position && typeof position == 'object' && position['left'] != undefined && position['top'] != undefined) - { - var left = (!isNaN(position['left'])) ? position.left + 'px' : position.left.toString(); - var top = (!isNaN(position['top'])) ? position.top + 'px' : position.top.toString(); - this.listBackground.style.backgroundPosition = left + ' ' + top; - } - - this.divElt.appendChild(this.listBackground); -}; - -/** - * Clear any custom background image - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.clearListBackground = function() -{ - if (this.listBackground) - { - this.listBackground.parentElement.removeChild(this.listBackground); - this.listBackground = null; - } -}; - - - -/** - * ========================= - * HELPERS AND UTILITIES - * ========================= - */ - - /** - * Create Tabs control - * ========================= - * @return The TabsCtrl instance. - */ -List2Ctrl.prototype._createTabsControl = function() -{ - log.debug(' Instantiating TabsCtrl'); - if (this.properties.tabsButtonConfig.tiltStartCallback) - { - log.warn("Lis2: the tabsButtonConfig.tiltStartCallback property was defined outside of the list control but should only be used by the list."); - } - this.properties.tabsButtonConfig.tiltStartCallback = this._tabsCtrlTiltStartCallback.bind(this); - return framework.instantiateControl(this.uiaId, this.divElt, "TabsCtrl", this.properties.tabsButtonConfig); -}; - -/** - * Clear the list contents when the user starts tilting to a new tab. - */ -List2Ctrl.prototype._tabsCtrlTiltStartCallback = function(controlRef, appData, params) -{ - if (this.title) - { - this.title.style.opacity = 0; - } - this.setDataList({}); - this._hideScrollIndicator(); -}; - - -/** - * Tracks touch position properties of the last two events. - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - MouseMove event - * @return {void} - */ -List2Ctrl.prototype._trackEvent = function(e) -{ - // use shallow copy - var trackedEvents = this._trackedEvents; - trackedEvents[0] = trackedEvents[1]; - trackedEvents[1] = { y: e.pageY, x: e.pageX }; -}; - -/** - * Get touch direction upon touch move - * TAG: touch-only, internal - * ========================= - * @return {integer} - 1 for 'down', -1 for 'uo' - */ -List2Ctrl.prototype._getMoveDirection = function() -{ - var trackedEvents = this._trackedEvents, - event0 = trackedEvents[0], - event1 = trackedEvents[1]; - - if (!event0) return 1; - - return (event1.y - event0.y < 0) ? -1 : 1; -}; - -/** - * Get current list position (or specific position relative to supplied item index) - * TAG: internal - * ========================= - * @param {integer} - optional, item index from which to calculate position - * @return {string} - onepage | top | bottom | bottomclose | topclose | middle - */ -List2Ctrl.prototype._getListPosition = function(itemIndex) -{ - // get item index - var itemIndex = (undefined === itemIndex) ? this._topItem : itemIndex; - - // get list position - var listPosition = null; - - // determine list position - if (this.dataList.itemCount <= this.properties.visibleItems) - listPosition = 'onepage'; - else if (0 === itemIndex) - listPosition = 'top'; // list is at the top - else if (itemIndex === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; // list is at the bottom - else if (itemIndex > this.dataList.itemCount - (2 * this.properties.visibleItems)) - listPosition = 'bottomclose'; // list is less than a screen to the bottom - else if (itemIndex < 2 * this.properties.visibleItems) - listPosition = 'topclose'; // list is less than a screen to the top - else - listPosition = 'middle'; // list is somewhere in the middle - - // return list position - return listPosition; -}; - - -/** - * Get additional space that needs to be added to the scroller - * height in order to satisfy the 'half-line' requirements. - * Correction is needed because there's a difference between - * visual style guide and actual item heights. The values are - * fixed and depend on the style. - * TAG: helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getAdditionalSpace = function() -{ - // determine additional space - var additionalSpace = 0; - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - additionalSpace = this.properties.thickItems ? 6 : 32; - break; - case 'tabsTitle' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style03' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'style05' : - case 'style08' : - additionalSpace = this.properties.thickItems ? 52 : 42; - break; - case 'style06' : - case 'style07' : - additionalSpace = this.properties.thickItems ? 60 : 32; - break; - default : - // nothing to do - break; - } - break; - default : - // nothing to do - break; - } - - - - return additionalSpace; -}; - -/** - * Get empty DOM elements - * Return the first element in the DOM that doesn't - * have data associated with it in the dataList - */ -List2Ctrl.prototype._getEmptyDOMElement = function() -{ - var emptyItem = null; - var items = []; - - // get item indeces and sort them in ascending order - for (var i=0; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var itemIndex = Math.floor(relativeY / this.properties.itemHeight); - - // if we are in the active area but below the last item -> return -1 - if (itemIndex > this.dataList.itemCount - 1) - { - return -1; - } - - // constrain itemIndex to the max possible index - itemIndex = this.m.min(itemIndex, this.dataList.itemCount - 1); - - return itemIndex; -}; - -/** - * Get DOM Element by itemIndex - * Returns a DOM element (or null) for a particular - * item after performing a search for its item index - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {HTML Element} -
  • element - */ -List2Ctrl.prototype._getDOMItem = function(itemIndex) -{ - var domItem = null; - - for (var i=0, l=this.items.length; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var letterIndex = Math.floor(relativeY / this.properties.letterIndexHeight); - - // if we are in the active area but below the last letter index item -> return -1 - if (letterIndex > this.letterIndexData.length - 1) - { - return -1; - } - - // constrain letterIndex to the max possible index - letterIndex = this.m.min(letterIndex, this.letterIndexData.length - 1); - - return letterIndex; -}; - -/** - * Get Slider instance by itemIndex - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {SliderCtrl} - slider instance - */ -List2Ctrl.prototype._getSlider = function(itemIndex) -{ - var sliderCtrl = null; - - var index; - if (utility.toType(itemIndex) === 'number') - { - index = itemIndex; - } - else - { - index = this._getFocussedIndex(); - } - - var domElt = this._getDOMItem(index); - if (domElt) - { - var poolId = domElt.getAttribute('data-poolid'); - var hashKey = 'slider_'+index+'_'+poolId; - - // check whether a slider exists - if (this._sliders.hasOwnProperty(hashKey) && this._sliders[hashKey].slider) - { - sliderCtrl = this._sliders[hashKey].slider; - } - } - - return sliderCtrl; -}; - -/** - * Checks whether the supplied itemIndex contains a slider - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains a slider - */ -List2Ctrl.prototype._isSlider = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSlider = false; - - if (!isNaN(itemIndex)) - { - isSlider = ('style12' === this.dataList.items[itemIndex].itemStyle || 'style13' === this.dataList.items[itemIndex].itemStyle || 'style28' == this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSlider = ('style12' === itemIndex || 'style13' === itemIndex|| 'style28' === itemIndex); - } - - return isSlider; -}; - -/** - * Checks whether the supplied itemIndex is a lock item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a lock item - */ -List2Ctrl.prototype._isLock = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isLock = false; - - if (!isNaN(itemIndex)) - { - isLock = ('styleLock' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isLock = ('styleLock' === itemIndex); - } - - return isLock; -}; - -/** - * Checks whether the supplied itemIndex contains toggle buttons - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains toggle buttons - */ -List2Ctrl.prototype._isToggle = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isToggle = false; - - if (!isNaN(itemIndex)) - { - isToggle = ('style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle || 'draggable' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isToggle = ('style10' === itemIndex || 'style11' === itemIndex || 'draggable' === itemIndex); - } - - return isToggle; -}; - -/** - * Checks whether the supplied itemIndex is On/Off item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is On/Off - */ -List2Ctrl.prototype._isOnOff = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isOnOff = false; - - if (!isNaN(itemIndex)) - { - isOnOff = ('styleOnOff' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isOnOff = ('styleOnOff' === itemIndex); - } - - return isOnOff; -}; - -/** - * Checks whether the supplied itemIndex is a step item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a step item - */ -List2Ctrl.prototype._isStep = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isStep = false; - - if (!isNaN(itemIndex)) - { - isStep = ('styleStep' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isStep = ('styleStep' === itemIndex); - } - - return isStep; -}; - -/** - * Checks whether the supplied itemIndex is a checkbox - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a checkbox/tick/radio item - */ -List2Ctrl.prototype._isCheckBox = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isCheckbox = false; - - if (!isNaN(itemIndex)) - { - isCheckbox = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isCheckbox = ('style03' === itemIndex || 'style03a' === itemIndex); - } - - return isCheckbox; -}; - -/** - * Checks whether the supplied itemIndex is a simple select item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is simple select item - */ -List2Ctrl.prototype._isSimpleSelectItem = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSimpleSelect = false; - - if (!isNaN(itemIndex)) - { - isSimpleSelect = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle || 'styleOnOff' === this.dataList.items[itemIndex].itemStyle || 'style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSimpleSelect = ('styleOnOff' === itemIndex || 'style10' === itemIndex || 'style11' === itemIndex); - } - - return isSimpleSelect; -}; - -/** - * Checks whether the item contains _data property - * TAG: internal, helper - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item contains _data property - */ -List2Ctrl.prototype._hasData = function(itemIndex) -{ - var containsData = false; - if (this.dataList && this.dataList.items && this.dataList.items[itemIndex]) - { - containsData = this.dataList.items[itemIndex].hasOwnProperty('_data'); - } - return containsData; -}; - -/** - * Wraps inline text element if the width exceeds certain - * max width that depends on the item style. - * TAG: internal, helper - * ========================= - * @param {HTML Li Element} - the LI element that will be searched for overflowing text - * @return {HTML Li Element} - the modified LI element - */ -List2Ctrl.prototype._wrapInlineElement = function(li) -{ - var searchClass = null; - var maxWidth = 0; - - if (li.classList.contains('style17')) - { - searchClass = 'line1'; - maxWidth = this.properties.wrapTextThreshold; - } - else - { - return li; - } - - var line1 = li.getElementsByClassName(searchClass); - if (!line1 || 0 === line1.length) - { - return li; - } - else - { - line1 = line1[0]; - } - - if (line1.clientWidth > maxWidth) - { - line1.classList.add("wrap"); - } - else - { - line1.classList.remove("wrap"); - } - - return li; -}; - -/** - * Checks if the item can be displayed, even if it has no text field. - * TAG: internal, helper - * ===================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._displayWithoutText = function(item) -{ - var returnValue = true; - for(var i =0; i < this._itemsWithNoText.length; i++) - { - if(item.itemStyle === this._itemsWithNoText[i]) - { - returnValue = false; - break; - } - } - return returnValue; -}; - -/** - * Checks if the item is a slider with full hittable area - * TAG: internal, helper - * =================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._hasRightHittableArea = function(item) -{ - var returnValue = false; - - for(var i =0; i < this._rightHittableArea.length; i++) - { - if(item.itemStyle === this._rightHittableArea[i]) - { - returnValue = true; - break; - } - } - return returnValue; -}; - - -/** - * Show bounding boxes of some elements in the list. - * This should be used for debugging purposes only - * TAG: internal, utility - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype.showBoundingBoxes = function(state) -{ - if (state) - { - this.divElt.classList.add('showBoundingBoxes'); - } - else - { - this.divElt.classList.remove('showBoundingBoxes'); - } -}; - - -/** - * Searches an array for a value - * TAG: internal, utility - * ========================= - * @param {string|number} - * @param {array} - * @return {object} - copy of the source object - */ -List2Ctrl.prototype.inArray = function(needle, haystack) -{ - if (!needle || !haystack) - { - log.warn('Lis2: 2 arguments expected'); - return; - } - - for (var i=0, l=haystack.length; i b ? a : b // return the higher - : NaN; // else return NaN (just like the Math class) - }, - abs : function(a) - { - return (!isNaN(a)) ? // if the argument is a number - a < 0 ? -a : a // return the abs - : NaN; // else return NaN (just like the Math class) - } -}; - -/** - * Finish partial activity. - * @return {void} - */ -List2Ctrl.prototype.finishPartialActivity = function() -{ - // route finish partial activity to sub controls - - // tabs ctrl - if (this.tabsCtrl) - { - // delete the assigned callback reference so that it's not stored in the App's context table - delete this.properties.tabsButtonConfig.tiltStartCallback; - this.tabsCtrl.finishPartialActivity(); - } - - // slider - if (this._activeSlider && this._activeSlider.slider) - { - this._activeSlider.slider.finishPartialActivity(); - } - - // list -> exit any items in secondary MC mode - if (this._inSecondaryMulticontroller) - { - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this._isStep(smi)) - { - this._setSecondaryMulticontroller(false); - this._triggerFocus(); - } - } -}; - -List2Ctrl.prototype.getStationAndRelay = function(stationName,RelayName) -{ - var stationRelay = ""; - if(stationName && RelayName) - { - stationRelay = stationName+" ("+RelayName+")"; - } - else if(stationName && ((RelayName=="")||(RelayName==null))) - { - stationRelay = stationName; - } - else{ - log.debug("Station name and relay not defined"); - } - - return stationRelay; -}; - - -/** - * ========================= - * GARBAGE COLLECTION - * - Clear listeners - * - Clean up subcontrols - * - Clear timeouts - * TAG: framework - * ========================= - * @return {void} - */ -List2Ctrl.prototype.cleanUp = function() -{ - // remove event callbacks - this.divElt.removeEventListener(this._USER_EVENT_START, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - - // remove animation callbacks - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - if (this.scrollIndicator) - { - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - } - if (this.letterIndex) - { - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - } - - // clean up subcontrols - if (this.tabsCtrl) - { - this.tabsCtrl.cleanUp(); - } - for (var i in this._sliders) - { - this._sliders[i]['slider'].cleanUp(); - } - - // clear timeouts - clearTimeout(this._makeHitTimeoutId); - clearTimeout(this._longPressTimeoutId); - clearTimeout(this._touchReorderTimeoutId); - clearTimeout(this._scrollIndicatorTimeoutId); - clearTimeout(this._indexSelectTimeoutId); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - clearTimeout(this._needDataTimeoutId); - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - clearTimeout(this._radioSettleTimeoutId); - clearTimeout(this._tickSettleTimeoutId); - if (this.hasDataList()) - { - for (var i=0, l=this.dataList.items.length; i 0 || this.properties.scrollTo > 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 2)) ) - { - log.debug('Lis2: Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // set initial focus to a particular item if the list is populated - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem > 0) - { - log.debug('Lis2: Focus is not visible and has priority'); - this._showFocus(this.properties.focussedItem); - this._initialScrollMode = 'init'; - } - // scroll (no animation) to a particular item if the list is populated - // the focus will be placed on the top item - else if (this.properties.scrollTo > 0) - { - log.debug('Lis2: Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - this._showFocus(this._topItem); - this._initialScrollMode = 'init'; - } - - // enter list reorder if the list is reordable - if (true === this.properties.listReorder) - { - this._enterListReorder(true); - } - - } - } - else - { - this._setLoading(true); - } - - - /* SET LETTER INDEX DATA */ - if (this.properties.hasLetterIndex && this.properties.letterIndexData) - { - // bind letter index data - this.setLetterIndexData(this.properties.letterIndexData); - } - - /* SET CUSTOM LIST BACKGROUND */ - if (null != this.properties.listBackground && '' != this.properties.listBackground) - { - this.setListBackground(this.properties.listBackground); - } - -}; - - -/** - * ========================= - * LIST ITEMS - * 1. pool (_createPool) - * 2. default items configuration (_prepareItems, _prepareListItem) for every item style - * 3. items localization (_localizeItems, _getLocalizedString) - * 4. pool operations (_setText, _setImage, _getListItem, _returnListItem, _putToScroller, _emptyScroller) - * 5. dynamic list items (_updateRange, _updateDisplay, _requestMore, _fill) - * 6. set internal properties (_checkScrollable, _setTopListItem, _setLoading) - * 7. default title configuration (_prepareTitle) - * ========================= - */ - -/** 1. POOL **/ - -/** - * Create list items pool - * Add HTML elements to each item in the pool - * depending on its style - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._createPool = function() -{ - this.pool = { - empty : new Array(), // 'empty' is internal style - draggable : new Array(), // 'draggable' is internal style - ghost : new Array(), // 'ghost' is internal style - - style01 : new Array(), - style02 : new Array(), - style03 : new Array(), - style03a : new Array(), - style04 : new Array(), - style05 : new Array(), - style06 : new Array(), - style07 : new Array(), - style09 : new Array(), - style10 : new Array(), - style11 : new Array(), - style12 : new Array(), - style13 : new Array(), // deprecated - style14 : new Array(), - style17 : new Array(), - style18 : new Array(), - style19 : new Array(), - style20 : new Array(), - style21 : new Array(), - style22 : new Array(), - // TODO: style23 - same as style12 - // TODO: style24 - same as style12 - style25 : new Array(), - styleOnOff : new Array(), // not official name - styleStep : new Array(), // TODO: rename this to style26 - styleLock : new Array(), // not official name - style28 : new Array(), - - }; - - // the pool size (this.properties.poolsize) should be at least 3 times - // the visible items (one for above and two for below the top item) - var line1, line2, - image1, image2, - label1, label2, - button1, button2, button3, - caret; - - for (var i in this.pool) - { - for (var j=0; j no content - break; - - case 'draggable' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - button1 = document.createElement('span'); - button1.className = 'button buttonOk'; - li.appendChild(button1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'ghost' : - // ghost item -> no contet - break; - - case 'style01' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style02' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style03a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style04' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style05' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style06' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style07' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style09' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style10' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - break; - - case 'style11' : - var buttonsWrapper = document.createElement('div'); - buttonsWrapper.className = 'buttonsWrapper'; - li.appendChild(buttonsWrapper); - - button1 = document.createElement('span'); - button1.className = 'button button1'; - buttonsWrapper.appendChild(button1); - - button2 = document.createElement('span'); - button2.className = 'button button2'; - buttonsWrapper.appendChild(button2); - - button3 = document.createElement('span'); - button3.className = 'button button3'; - buttonsWrapper.appendChild(button3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style12' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style13' : - // style13 is deprecated - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - break; - - case 'style14' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style17' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - // label is inside line1 element to allow natural text flow - label1 = document.createElement('span'); - label1.className = 'label1'; - line1.appendChild(label1); - - break; - - case 'style18' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - label1 = document.createElement('span'); - label1.className = 'label1'; - subcontainer.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - break; - - case 'style19' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - - line1 = document.createElement('span'); - line1.className = 'line1'; - subcontainer.appendChild(line1); - - break; - - case 'style20' : - button1 = document.createElement('span'); - button1.className = 'button1'; - li.appendChild(button1); - - break; - - case 'style21' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'style22' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'style25' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - - case 'styleOnOff' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2'; - li.appendChild(image2); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - break; - - case 'styleStep' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - label1 = document.createElement('span'); - label1.className = 'label1'; - li.appendChild(label1); - - label2 = document.createElement('span'); - label2.className = 'label2'; - li.appendChild(label2); - - var plusSign = document.createElement('span'); - plusSign.className = 'plus'; - li.appendChild(plusSign); - - var minusSign = document.createElement('span'); - minusSign.className = 'minus'; - li.appendChild(minusSign); - - break; - - case 'styleLock' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - image2 = document.createElement('span'); - image2.className = 'image2 buttonLock'; - li.appendChild(image2); - - image3 = document.createElement('span'); - image3.className = 'image3 buttonDelete'; - li.appendChild(image3); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - li.appendChild(line2); - - break; - case 'style28' : - image1 = document.createElement('span'); - image1.className = 'image1'; - li.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - li.appendChild(line1); - - var subcontainer = document.createElement('div'); - subcontainer.className = 'subcontainer'; - li.appendChild(subcontainer); - break; - - default : - log.error('List2: unknown list item style in pool: ' + i); - break; - - } - - // add common elements - caret = document.createElement('span'); - caret.className = 'caret'; - li.appendChild(caret); - - - this.pool[i].push(li); - } - } - -}; - -/** 2. DEFAULT ITEMS CONFIGURATION **/ - -/** - * Prepare items - * Extend the whole dataList so that every item - * meet the required structure. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._prepareItems = function(firstItem, lastItem) -{ - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) || (lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - for (var i=firstItem, l=lastItem; i<=l; i++) - { - this.dataList.items[i] = this._prepareListItem(this.dataList.items[i]); - } - -}; - -/** - * Prepare list item - * A list item can be defined with minimal set of properties - * that are needed for its proper display. In fact these - * properties extend the default list item structure defined below. - * This function sets default configuration for a valid list item and merge - * it with the custom configuration passed to the item. - * TAG: internal - * ========================= - * @param {object} - the list item that will be set a default set of properties and will be returned - * @return {object} - the complete list item - */ -List2Ctrl.prototype._prepareListItem = function(item) -{ - // The itemStyle property is required - if (!item.hasOwnProperty('itemStyle')) - { - log.error('List2: list item should have itemStyle property: ' + item); - return; - } - - /* - * All types of list items extend this - * default structure by overriding the - * values and adding specific ones. The - * extended structure is then returned to be - * fed in the dataList container. - */ - var completeItem = { - appData : null, // Any kind of data that will be passed in the callbacks - text1Id : null, // String ID of the label - text1SubMap : null, // String Sub Map of the label - text1 : '', // Textual content of the label - hasCaret : true, // Show the caret icon on the right of the item - disabled : false, // Whether the list item is disabled - styleMod : '', // Style modifier, 'hint', 'bold', or ''/omitted - disabledStyleMod: "normal", // Disabled style modifier, 'normal' or 'white' - background : 'normal', // Background modifier, 'normal' or 'grey' - itemStyle : '', // String indicating the list type - itemBehavior : 'shortPressOnly', // String "hold" behavior for the item ('shortPressOnly', 'shortAndHold', or 'shortAndLong') - vuiSelectable: true, // Boolean for some items that cannot be selected by vui even when they are enabled - _data : { // Object containing any item-specific data used ONLY by the control - eventTimeout : null, - lastEvent : null, - settleTimeout : null, - lastUpdated : null, - settleValue : null, - } - }; - - // extend the default structure with default specific properties - var specificItem = {}; - switch (item.itemStyle) - { - case 'empty' : - specificItem = { hasCaret : false }; - break; - case 'draggable' : - specificItem = { image1:'', button1Id:null, button1SubMap:null, button1:'' }; - break; - case 'ghost' : - specificItem = {}; - break; - case 'style01' : - specificItem = { image1:'', indented:false }; - break; - case 'style02' : - specificItem = { image1:'', image2:'' }; - break; - case 'style03' : - specificItem = { image1:'', image2:'', image3:'', checked:false, indented:false }; - break; - case 'style03a' : - specificItem = { image1: '', label1Id: null, label1SubMap: null, label1: '', checked: false, labelWidth: 'wide2', label1Align:'right', styleMod: "hint"}; - break; - case 'style04' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style05' : - specificItem = { image1:'', image2:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style06' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', labelWidth:'normal', label1Align:'right', label1Warning:false }; - break; - case 'style07' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style09' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'', labelWidth:'normal', label1Align:'right', label1Warning:false, label2Align:'right', label2Warning:false }; - break; - case 'style10' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', value:1, indeterminate:false, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style11' : - specificItem = { button1Id:null, button1SubMap:null, button1:'', button2Id:null, button2SubMap:null, button2:'', button3Id:null, button3SubMap:null, button3:'', value:1, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'style12' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime }; - break; - case 'style13' : - // deprecated - issue a warning - log.warn(this.uiaId + ': List2 style13 has been deprecated. Please use style12 instead. Setting pivot=True. Check SDD for details.'); - specificItem = { min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:true }; - break; - case 'style14' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', text1Align:'left' }; - break; - case 'style17' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'' }; - break; - case 'style18' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2SubMap:null, label2:'' }; - break; - case 'style19' : - specificItem = { image1:'' }; - break; - case 'style20' : - // nothing specific for this style - break; - case 'style21' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'style22' : - specificItem = { image1:'', image2:'', label1Id:null, label1SubMap:null, label1:'', indented:false }; - case 'style25' : - specificItem = { image1:'', image2:'', image3:'', text2Id:null, text2SubMap:null, text2:'' }; - break; - case 'styleOnOff' : - specificItem = { image1:'', value:2, minChangeInterval : this.properties.toggleMinChangeInterval, settleTime : this.properties.toggleSettleTime }; - break; - case 'styleStep' : - specificItem = { image1:'', label1Id:null, label1SubMap:null, label1:'', label2Id:null, label2:'', min:0, max:36, increment:1, value:0, warning:false }; - break; - case 'styleLock' : - specificItem = { image1:'', text2Id:null, text2SubMap:null, text2:'', locked:false }; - break; - case 'style28' : - specificItem = { image1:'', min:0, max:1, increment:0.1, value:1, allowAdjust:true, showTickMarks:false, tickMarkObject:null, showLabels:false, labelObject:null, showPlusMinus:false, pivot:false, minChangeInterval:this.properties.minChangeInterval, settleTime:this.properties.settleTime, rotationIdleDetectTime:this.properties.rotationIdleDetectTime, indented : false }; - break; - default : - log.error('List2: unknown item style: ' + item.itemStyle); - break; - } - - // Extend default structure with the specific one - for (var i in specificItem) - { - completeItem[i] = specificItem[i]; - } - - // Extend default structure with the supplied item - for (var j in item) - { - completeItem[j] = item[j]; - } - - return completeItem; -}; - - -List2Ctrl.prototype._updateModifiedTimestamps = function(firstItem, lastItem) -{ - // update lastModified timestamp - var now = new Date().getTime(); - for (var i=firstItem; i<=lastItem; i++) - { - if (this._hasData(i)) - { - this.dataList.items[i]._data.lastUpdated = now; - } - } -}; - - -/** 3. ITEMS LOCALIZATION **/ - -/** - * Localize items - * Localize text in known list items using localization framework. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._localizeItems = function(firstItem, lastItem) -{ - log.debug('Localizing...'); - - if ((firstItem == null) || (firstItem < 0)) - { - firstItem = 0; - } - - if ((lastItem == null) ||(lastItem >= this.dataList.items.length)) - { - lastItem = this.dataList.items.length - 1; - } - - // iterate through the dataList - for (var i=firstItem, l=lastItem; i<=l; i++) - { - switch (this.dataList.items[i].itemStyle) - { - // no elements - case 'empty' : - // do nothing - break; - - // text1, button1 - case 'draggable' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - break; - - // no elements - case 'ghost' : - // do nothing - break; - - // text1 - case 'style01' : - case 'style02' : - case 'style03' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - case 'style03a' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style04' : - case 'style05' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1, label1 - case 'style06' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style07' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, text2, label1, label2 - case 'style09' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1, button1, button2 - case 'style10' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - break; - - // text1, button1, button2, button3 - case 'style11' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].button1Id) - { - var button1 = this._getLocalizedString(this.dataList.items[i].button1Id, this.dataList.items[i].button1SubMap); - this.dataList.items[i].button1 = button1; - } - if (this.dataList.items[i].button2Id) - { - var button2 = this._getLocalizedString(this.dataList.items[i].button2Id, this.dataList.items[i].button2SubMap); - this.dataList.items[i].button2 = button2; - } - if (this.dataList.items[i].button3Id) - { - var button3 = this._getLocalizedString(this.dataList.items[i].button3Id, this.dataList.items[i].button3SubMap); - this.dataList.items[i].button3 = button3; - } - break; - - // text1, labelLeft, labelRight - case 'style12' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, labelLeft, labelCenter, labelRight - case 'style13' : - // style13 is deprecated - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1 - case 'style14' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style17' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1, label2 - case 'style18' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, this.dataList.items[i].label2SubMap); - this.dataList.items[i].label2 = label2; - } - break; - - // text1 - case 'style19' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1 - case 'style20' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, text2, label1 - case 'style21' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, label1 - case 'style22' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - break; - - // text1, text2 - case 'style25' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - // text1 - case 'styleOnOff' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - break; - - // text1, label1, label2 - case 'styleStep' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].label1Id) - { - var label1 = this._getLocalizedString(this.dataList.items[i].label1Id, this.dataList.items[i].label1SubMap); - this.dataList.items[i].label1 = label1; - } - if (this.dataList.items[i].label2Id) - { - var label2 = this._getLocalizedString(this.dataList.items[i].label2Id, {value:this.dataList.items[i].value}); - this.dataList.items[i].label2 = label2; - } - else - { - log.warn(this.uiaId + ' possible issue. Lis2: item ' + i + ' does not specify label2Id'); - } - break; - - // text1, text2 - case 'styleLock' : - if (this.dataList.items[i].text1Id) - { - var text1 = this._getLocalizedString(this.dataList.items[i].text1Id, this.dataList.items[i].text1SubMap); - this.dataList.items[i].text1 = text1; - } - if (this.dataList.items[i].text2Id) - { - var text2 = this._getLocalizedString(this.dataList.items[i].text2Id, this.dataList.items[i].text2SubMap); - this.dataList.items[i].text2 = text2; - } - break; - - } - - } -}; - -/** - * Get localization entry for a string id - * TAG: internal - * ========================= - * @return {string} - */ -List2Ctrl.prototype._getLocalizedString = function(labelId, subMap) -{ - return framework.localize.getLocStr(this.uiaId, labelId, subMap); -}; - -/** 4. POOL OPERATIONS **/ - -/** - * Set line 1 content - * This helper function clears any previous content for the supplied - * element class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - textual content to be inserted - * @param {boolean} - do not remove child html tags when inserting textual content - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setText = function(li, className, content, preserveHTML) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - if (!content) - { - content = ''; - } - li.querySelector(className).innerText = ''; - li.querySelector(className).appendChild(document.createTextNode(content)); - return li; -}; - -/** - * Set image background - * This helper function clears any previous path for the supplied - * image class and sets new one. Then the list item is returned. - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {string} - path to the image - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setImage = function(li, className, url) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - li.querySelector(className).style.backgroundImage = ''; - if ('' != url) - { - li.querySelector(className).style.backgroundImage = 'url(' + url + ')'; - } - return li; -}; - -/** - * Set slider - * This helper function clears any previous slider in the list item - * and cleans up local references. It then creates a new slider control - * inside the list item and sets its values - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setSlider = function(li, className, sliderProperties, itemIndex) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - - // get current item poolid - var poolId = li.getAttribute('data-poolid'); - - // get previous itemIndex for this particular li - var prevItemIndex = li.getAttribute('data-ref'); - - // destruct any previous sliders for this poolid and previous index - if (prevItemIndex != 'undefined') - { - var hashKey = 'slider_'+prevItemIndex+'_'+poolId; - - // remove slider from the hash and the DOM - if (this._sliders.hasOwnProperty(hashKey)) - { - this._sliders[hashKey]['slider'].cleanUp(); - this._sliders[hashKey]['slider'].divElt.parentElement.removeChild(this._sliders[hashKey]['slider'].divElt); - } - } - - // add slider to the hash and the DOM - var sliderCont = li.querySelector(className); - if (sliderProperties && sliderCont) - { - var hashKey = 'slider_'+itemIndex+'_'+poolId; - - // instantiate slider and add it to the _sliders hash - this._sliders[hashKey] = {}; - this._sliders[hashKey]['itemIndex'] = itemIndex; - this._sliders[hashKey]['poolId'] = poolId; - this._sliders[hashKey]['slider'] = framework.instantiateControl(this.uiaId, sliderCont, 'SliderCtrl', sliderProperties); - } - return li; -}; - -/** - * Set toggle - * This helper function clears any previous toggled buttons in - * the supplied list item and sets initial toggle value - * TAG: internal - * ========================= - * @param {HTML element} -
  • element as taken from the pool - * @param {string} - className of the taget element - * @param {object} - slider configuration - * @return {HTML element} -
  • element with the new content - */ -List2Ctrl.prototype._setToggle = function(li, className, value) -{ - if (!li) - { - log.error('Lis2: HTML LI element should be passed'); - return; - } - if (!className) - { - log.error('Lis2: className should be passed'); - return; - } - var buttons = li.querySelectorAll(className); - for (var i=0; i element wit proper elements inside - */ -List2Ctrl.prototype._getListItem = function(listItem, dataListIndex) -{ - - // get it from the pool - var li = this.pool[listItem.itemStyle].shift(); - - // remove any residual touch classes - li.classList.remove('hit'); - li.classList.remove('focus'); - li.classList.remove('longpress'); - li.classList.remove('secondaryFocus'); - - // add content to it following style definitions - switch (listItem.itemStyle) - { - case 'empty' : - // empty item -> no content - break; - - case 'draggable' : - // listItem : { text1:String, image1:String, button1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - this._setText(li, '.buttonOk', listItem.button1); - break; - - case 'ghost' : - // list item : {} - break; - - case 'style01' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style02' : - // listItem : { text1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.image2 === 'indeterminate') - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - this._setImage(li, '.image2', listItem.image2); - } - break; - - case 'style03' : - // listItem : { text1:String, image1:String, image2:String, checked:Boolean } - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style03a' : - // listItem : { text1:String, image1:String, label1: String} - this._setText(li, '.line1', listItem.text1); - if (listItem.image1 === 'checkbox') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('checkbox'); - } - else if (listItem.image1 === 'radio') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('radio'); - } - else if (listItem.image1 === 'tick') - { - li.classList.remove('radio'); - li.classList.remove('checkbox'); - li.classList.remove('tick'); - li.classList.add('tick'); - } - else - { - li.classList.remove('checkbox'); - li.classList.remove('radio'); - li.classList.remove('tick'); - this._setImage(li, '.image1', listItem.image1); - } - - if (listItem.checked) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - - this._setText(li, '.label1', listItem.label1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style04' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style05' : - // listItem : { text1:String, text2:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - break; - - case 'style06' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style07' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style09' : - // listItem : { text1:String, text2:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - - // configure label width - li.classList.remove('wideLabel'); - li.classList.remove('wideLabel2'); - switch (listItem.labelWidth) - { - case 'wide' : li.classList.add('wideLabel'); break; - case 'wide2' : li.classList.add('wideLabel2'); break; - } - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - li.classList.remove('label2Right'); - li.classList.remove('label2Left'); - li.classList.remove('label2Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - switch (listItem.label2Align) - { - case 'right' : li.classList.add('label2Right'); break; - case 'left' : li.classList.add('label2Left'); break; - case 'center' : li.classList.add('label2Center'); break; - default : li.classList.add('label2Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - if (listItem.label2Warning) - li.classList.add('label2Warning'); - else - li.classList.remove('label2Warning'); - - break; - - case 'style10' : - // listItem : { text1:String, button1:String, button2:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 2), 0) ); - if (listItem.indeterminate) - { - li.classList.add('indeterminate'); - } - else - { - li.classList.remove('indeterminate'); - } - break; - - case 'style11' : - // listItem : { text1:String, button1:String, button2:String, button3:String, value:Integer } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.button1', listItem.button1); - this._setText(li, '.button2', listItem.button2); - this._setText(li, '.button3', listItem.button3); - this._setToggle(li, '.button', this.m.max(this.m.min(listItem.value, 3), 0) ); - break; - - case 'style12' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style13' : - // TODO: style13 has been depricated - // listItem : { text1:String, labelLeft:String, labelCenter:String, labelRight:String } - this._setText(li, '.line1', listItem.text1); - - // extend tickmark object - if (listItem.tickMarkObject) - { - listItem.tickMarkObject.tickMarkStyle = "List2CtrlSliderTickMark"; - listItem.tickMarkObject.centerMarkTopStyle = "List2CtrlCenterMarkTop"; - listItem.tickMarkObject.centerMarkBottomStyle = "List2CtrlCenterMarkBottom"; - listItem.tickMarkObject.numberStyle = "List2CtrlTickNumber"; - } - - // extend label object - if (listItem.labelObject) - { - listItem.labelObject.leftLabelStyle = "List2CtrlSliderLeftLabel"; - listItem.labelObject.rightLabelStyle = "List2CtrlSliderRightLabel"; - listItem.labelObject.centerLabelStyle = "List2CtrlSliderCenterLabel"; - } - - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: this.properties.minChangeInterval, - settleTime: this.properties.settleTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - - case 'style14' : - // listItem : { text1:String, label1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - - if ('right' == listItem.text1Align) - { - li.classList.add('text1AlignRight'); - } - else - { - li.classList.remove('text1AlignRight'); - } - - break; - - case 'style17' : - // listItem : { text1:String, label1:String, image1:String } - li.querySelector('.line1').innerText = ''; - var label1 = document.createElement('span'); - label1.className = 'label1'; - label1.appendChild(document.createTextNode(listItem.label1)); - li.querySelector('.line1').appendChild(label1); - li.querySelector('.line1').appendChild(document.createTextNode(listItem.text1)); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style18' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style19' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - break; - - case 'style20' : - // listItem : { text1:String } - this._setText(li, '.button1', listItem.text1); - break; - - case 'style21' : - // listItem : { text1:String, text2:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - break; - - case 'style22' : - // listItem : { text1:String, label1:String, image1:String, image2:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - - // configure label alignment - li.classList.remove('label1Right'); - li.classList.remove('label1Left'); - li.classList.remove('label1Center'); - switch (listItem.label1Align) - { - case 'right' : li.classList.add('label1Right'); break; - case 'left' : li.classList.add('label1Left'); break; - case 'center' : li.classList.add('label1Center'); break; - default : li.classList.add('label1Right'); break; - } - - // configure label warning - if (listItem.label1Warning) - li.classList.add('label1Warning'); - else - li.classList.remove('label1Warning'); - - // configure text indentation - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - - break; - - case 'style25' : - // listItem : { text1:String, text2:String, image1:String, image2:String, image3:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - this._setImage(li, '.image2', listItem.image2); - this._setImage(li, '.image3', listItem.image3); - break; - - case 'styleOnOff' : - // listItem : { text1:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setImage(li, '.image1', listItem.image1); - if (listItem.value === 1) - { - li.classList.add('checked'); - } - else - { - li.classList.remove('checked'); - } - break; - - case 'styleStep' : - // listItem : { text1:String, label1:String, label2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.label1', listItem.label1); - this._setText(li, '.label2', listItem.label2); - this._setImage(li, '.image1', listItem.image1); - li.classList.remove('maxReached'); - li.classList.remove('minReached'); - if (listItem.value === listItem.max) - { - li.classList.add('maxReached'); - } - else if (listItem.value === listItem.min) - { - li.classList.add('minReached'); - } - - // configure label warning - if (listItem.warning) - li.classList.add('warning'); - else - li.classList.remove('warning'); - - break; - - case 'styleLock' : - // listItem : { text1:String, text2:String, image1:String } - this._setText(li, '.line1', listItem.text1); - this._setText(li, '.line2', listItem.text2); - this._setImage(li, '.image1', listItem.image1); - if (listItem.locked) - { - li.classList.add('locked'); - } - else - { - li.classList.remove('locked'); - } - break; - - case 'style28' : - // listItem : { text1:String, image1:String, labelLeft:String, labelRight:String } - this._setImage(li, '.image1', listItem.image1); - - if (listItem.indented) - li.classList.add('indented'); - else - li.classList.remove('indented'); - // instantiate SliderCtrl in the subcontainer - // TODO: how about a pool of sliders? -> need slider API for setting properties - var sliderProperties = { - style: listItem.allowAdjust ? listItem.pivot ? 'pivot' : 'slider' : 'progress', - slideCallback: this._slideCallback.bind(this, dataListIndex), - minChangeInterval: listItem.minChangeInterval, - settleTime: listItem.settleTime, - rotationIdleDetectTime: listItem.rotationIdleDetectTime, - min: listItem.min, - max: listItem.max, - increment: listItem.increment, - value: listItem.value, - - // tickmarks, labels and +/- - showTickMarks: listItem.showTickMarks, - tickMarkObject: listItem.tickMarkObject, - showLabels: listItem.showLabels, - labelObject: listItem.labelObject, - showPlusMinus: listItem.showPlusMinus, - plusMinusObject: listItem.showPlusMinus ? { plusSignStyle : "List2CtrlSliderPlus", minusSignStyle : "List2CtrlSliderMinus" } : null, // default +/- object - - appData: listItem.appData, - wrapperClass: "List2CtrlSliderCtrl", // (CSS Class) CSS Class passed in to define the appearance of the slider wrapper - fillClass: "List2CtrlSliderCtrlFill", // (CSS Class) CSS Class passed in to define the appearance of the fill - handleClass: "List2CtrlSliderCtrlHandle", // (CSS Class) CSS Class passed in to define the appearance of the handle - focusedWrapperClass: "List2CtrlSliderCtrlFocusedWrapper", // (CSS Class) Optional CSS Class to define the appearance of the slider wrapper when the slider has MC focus - focusedFillClass: "List2CtrlSliderCtrlFocusedFill", // (CSS Class) Optional CSS Class to define the appearance of the fill when the slider has MC focus - focusedHandleClass: "List2CtrlSliderCtrlFocusedHandle", // (CSS Class) Optional CSS Class to define the appearance of the handle when the slider has MC focus - - width: this.properties.sliderWidth, - handleWidth: this.properties.sliderHandleWidth, - }; - - - this._setSlider(li, '.subcontainer', sliderProperties, dataListIndex); - - if (listItem.allowAdjust) - { - li.classList.add('adjustable'); - li.classList.remove('notAdjustable'); - } - else - { - li.classList.remove('adjustable'); - li.classList.add('notAdjustable'); - } - - break; - } - - /* ITEM MODIFICATORS */ - // add/remove hasCaret class - if (listItem.hasCaret) - { - li.classList.add('hasCaret'); - } - else - { - li.classList.remove('hasCaret'); - } - - // add/remove disabled class - if (listItem.disabled) - { - li.classList.add('disabled'); - } - else - { - li.classList.remove('disabled'); - } - - // add/remove styleMod class (hint/bold/'') - if ('hint' == listItem.styleMod) - { - li.classList.remove('bold'); - li.classList.add('hint'); - } - else if ('bold' == listItem.styleMod) - { - li.classList.remove('hint'); - li.classList.add('bold'); - } - else if ('both' == listItem.styleMod) - { - li.classList.add('hint'); - li.classList.add('bold'); - } - else - { - li.classList.remove('hint'); - li.classList.remove('bold'); - } - - // add/remove background modifier class (normal/grey) - if ('grey' == listItem.background) - { - li.classList.remove('bgLightGrey'); - li.classList.add('bgGrey'); - } - else if('lightGrey' == listItem.background) - { - li.classList.remove('bgGrey'); - li.classList.add('bgLightGrey'); - } - else - { - li.classList.remove('bgLightGrey'); - li.classList.remove('bgGrey'); - } - - // add disabled style mod - if ('white' === listItem.disabledStyleMod) - { - li.classList.add("disabledWhite"); - } - - // return it - return li; - -}; - -/** - * Return list item to the pool - * This will result in increasing the pool contents - * with one item. The returned item will be removed from the DOM. - * However, its content will not be reset as this is done in the - * process of any subsequent pool extraction (see _getListItem() above) - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @return {void} - */ -List2Ctrl.prototype._returnListItem = function(li) -{ - // get the style - var itemStyle = li.getAttribute('data-itemStyle'); - // reset it - li.style.top = '0px'; - // remove it - li.parentNode.removeChild(li); - - // put it back to the pool - this.pool[itemStyle].push(li); -}; - -/** - * Put a list item to the scroller - * TAG: internal - * ========================= - * @param {HTML element} -
  • element from the DOM - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._putToScroller = function(li, index, operation) -{ - li.style.top = index * this.properties.itemHeight + 'px'; - li.setAttribute('data-ref', index); - - - if (operation == 'prepend') - { - this.items.unshift({ref:index, domElt:li}); - this.scroller.insertBefore(li, this.scroller.firstChild); - - this._wrapInlineElement(li); - } - else if (operation == 'append') - { - this.items.push({ref:index, domElt:li}); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else if (!isNaN(operation)) - { - this.items.splice(operation, 0, {ref:index, domElt:li}); - - // insertBefore breaks in Opera - use appendChild instead - // this.scroller.insertBefore(li, this.items[operation+1]); - this.scroller.appendChild(li); - - this._wrapInlineElement(li); - } - else - { - log.error('Lis2: unknown _putToScroller() operation: ' + li + ' ' + index + ' ' + operation); - } - -}; - -/** - * Return everything into the pool and empty the scroller - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._emptyScroller = function() -{ - for (var i=0, l=this.items.length; i itemsOnScreen) - { - // return everything into the pool - var itemsLength = this.items.length; - for (var i=0; i < itemsLength; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - var dataListIndex = 0; - - if (topItem < this.dataList.items.length - Math.round(itemsOnScreen / 2) && - topItem > Math.round((itemsOnScreen / 2)) ) - { - - - // WE ARE IN THE MIDDLE - - for (var i=0; i < itemsLength; i++) - { - dataListIndex = (topItem - itemsBefore) + i; - - // we've reached the end of the dataList. No more items to add -> break - if (dataListIndex >= this.dataList.items.length) - { - break; - } - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'middle'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else - { - - if (numOfScrolledElements > 0) - { - - // PRESSED END BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = (this.dataList.items.length - itemsLength) + i; - - // request it if it is empty - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'down'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - } - - } - else if (numOfScrolledElements < 0) - { - - // PRESSED HOME BUTTON - - for (var i=0; i < itemsLength; i++) - { - - dataListIndex = i; - - - // request it if it is empty - if (this.dataList.items[dataListIndex].itemStyle === 'empty' || (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex]))) - { - this._requestMore(dataListIndex, 'down'); - log.debug('Requesting items ' + dataListIndex); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'append'); - - } - - } - - } - - - } - else - { - - - - if (numOfScrolledElements > 0) - { - - /* SCROLL DOWN BOF */ - - // return to pool - var firstItemRef = this.items[0].ref; - var bottomDifference = topItem - firstItemRef; - var extraEls = bottomDifference - itemsBefore; - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Down - extraEls ' + extraEls); - - if (extraEls > 0) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.shift(); - this._returnListItem(item.domElt); - } - - } - - // lastItemRef = this.items[this.items.length-1].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var topDifference = this.items[this.items.length-1].ref - ( topItem - 1 ); - var newEls = ( itemsAfter + 1 ) - topDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Down - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i break - log.debug('end of list'); - break; - } - - } - - } - - /* SCROLL DOWN EOF */ - - } - else if (numOfScrolledElements < 0) - { - - /* SCROLL UP BOF */ - - // return to pool - var topDifference = this.items[this.items.length-1].ref - topItem + 1; - var extraEls = topDifference - ( itemsAfter + 1 ); - - // extraEls cannot be more than the poolsize - NOTE: this breaks the items array - // extraEls = this.m.min(extraEls, this.properties.poolsize-1); - // extraEls cannot be more than the items array - NOTE: introduced not to break the items array - extraEls = this.m.min(extraEls, this.items.length-1); - - log.debug(' Scroll Up - extraEls ' + extraEls); - - if ( extraEls > 0 ) - { - - for (var i=0; i < extraEls; i++) - { - var item = this.items.pop(); - this._returnListItem(item.domElt); - } - - } - - - // firstItemRef = this.items[0].ref; - // Note: this is not defined as a separate variable because the - // this.items array is being modified in the below cycle - - // get from pool - var bottomDifference = topItem - this.items[0].ref; - var newEls = itemsBefore - bottomDifference; - - // newEls cannot be more than the poolsize - newEls = this.m.min(newEls, this.properties.poolsize-1); - - log.debug(' Scroll Up - newEls ' + newEls); - - if (newEls > 0) - { - - for (var i=0; i= 0) - { - - // if empty item is encountered, request more data - if (this.dataList.items[dataListIndex].text1 == '' && this._displayWithoutText(this.dataList.items[dataListIndex])) - { - this._requestMore(dataListIndex, 'up'); - } - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // put it to scroller - this._putToScroller(li, dataListIndex, 'prepend'); - - } - else - { - // we've reached the beginning of the dataList array => break - log.debug('beginning of list'); - break; - } - - } // for - - } - else - { - log.debug('no new elements'); - } - - /* SCROLL UP EOF */ - - } - else - { - // there's no scroll => do nothing - } - - - - } // closes if (this.m.abs(numOfScrolledElements) > itemsOnScreen) - -}; - - -/** - * Redraw updated items that are currently visible - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._updateDisplay = function(firstItem, lastItem) -{ - - var firstItemRef = this.items[0].ref; - var lastItemRef = this.items[this.items.length-1].ref; - - // update only when the updated items overlap with the visible items - if ( (firstItem >= firstItemRef && firstItem <= lastItemRef) || - (firstItem <= firstItemRef && lastItem >= firstItemRef) ) - { - - var firstToUpdate = this.m.max(firstItem, firstItemRef); - var lastToUpdate = this.m.min(lastItem, lastItemRef); - var firstToUpdateIndex = firstToUpdate - firstItemRef; - var lastToUpdateIndex = (lastToUpdate - firstToUpdate) + firstToUpdateIndex; - - for (var i=firstToUpdateIndex; i<=lastToUpdateIndex; i++ ) - { - - var returnItem = this.items.splice(i,1); - var dataListIndex = returnItem[0].ref; - - // return to pool - this._returnListItem(returnItem[0].domElt); - - // get it from pool - var li = this._getListItem(this.dataList.items[dataListIndex], dataListIndex); - - // recover secondary focus - if (this._inSecondaryMulticontroller && this._currentSecondaryMulticontrollerItem === dataListIndex) - { - li.classList.add('focus'); - li.classList.add('secondaryFocus'); - } - - // put it to scroller - this._putToScroller(li, dataListIndex, i); - - } - - } - - // update _isScrollable flag - this._checkScrollable(); - -}; - -/** - * Request more list items - * TAG: internal - * ========================= - * @param {integer} - * @param {string} - * @return {void} - */ -List2Ctrl.prototype._requestMore = function(index, direction) -{ - - // do not request more if a previous request is pending - if (!this._inLoading) - { - // indicate loading is in progress - this._setLoading(true); - - if (direction == 'up') - { - // we add 1 to the requestSize to include the last element in the way up - index = this.m.max(index - this.properties.requestSize + 1, 0); - - } - else if (direction == 'middle') - { - // we request 25 items on each direction from the topItem - index = this.m.max(index, 0); - - } - - // build additional data - var additionalParams = { - topItem : this._topItem, - visibleItems : this.properties.visibleItems, - ranges : this.getEmptyRange(), - }; - - log.debug('Request items from ' + index + ' to ' + index+this.properties.requestSize + ' ' + direction); - - // call needDataCallback if it is defined. The first empty item is - if (typeof this.properties.needDataCallback == 'function') - { - this.properties.needDataCallback(index, additionalParams); - } - - // set timeout for data population - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = setTimeout(this._needDataTimeoutCallback.bind(this, index), this.properties.needDataTimeout); - } - -}; - -List2Ctrl.prototype._needDataTimeoutCallback = function(index) -{ - log.warn('Lis2: control has requested items from index ' + index + ' but has not receieved them yet. Enabling the list.'); - this._setLoading(false); -}; - -/** - * Initial pool operation - * TAG: internal - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._fill = function(firstItem, lastItem) -{ - - log.debug('Start pool operation'); - log.debug('POOL | ITEMS'); - - // get items from the pool - for (var i=firstItem; i<=lastItem; i++) - { - // get it from the pool - var li = this._getListItem(this.dataList.items[i], i); - - // put it to scroller - this._putToScroller(li, i, 'append'); - - log.debug(this.pool[this.dataList.items[i].itemStyle].length + ' -> ' + this.items.length); - } - - this._hasFill = true; - - // update _isScrollable flag - var scrollable = this._checkScrollable(); - - // show/hide scroll indicator - if (!scrollable || (scrollable && this.properties.hasLetterIndex)) - { - this._hideScrollIndicator(); - } - else - { - this._showScrollIndicator(); - } - - log.debug('End pool operation'); - -}; - -/** SET INTERNAL PROPERTIES **/ - -/** - * Update _isScrollable flag - * TAG: internal - * ========================= - * @return {boolean} - returns _isScrollable - */ -List2Ctrl.prototype._checkScrollable = function() -{ - if (this.dataList.items.length > this.properties.visibleItems) - { - this._isScrollable = true; - } - else - { - this._isScrollable = false; - } - - return this._isScrollable; -}; - -/** - * Update _topItem property - * TAG: internal - * ========================= - * @param {integer} - top item index - * @return {integer} - returns _topItem - */ -List2Ctrl.prototype._setTopListItem = function(pos) -{ - // pos should be number for proper topItem calculation - if (!isNaN(pos)) - { - this._prevTopItem = this._topItem; - this._topItem = -(Math.round(pos / this.properties.itemHeight)); - - // throw out of bounds exception - if (this._topItem < 0 || this._topItem > this.dataList.items.length - 1) - { - log.error('Lis2: _topItem is out of bounds'); - } - } - - if (this.properties.enableItemRequestOnScroll) - { - // check for empty items in DOM - var emptyDOMItem = this._getEmptyDOMElement(); - if (null != emptyDOMItem) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - } - } - - return this._topItem; - -}; - -/** - * Indicate loading activity in the list - * and update _inLoading property - * TAG: internal - * ========================= - * @param {boolean} - show or hide loading activity - * @return {boolean} - returns _inLoading - */ -List2Ctrl.prototype._setLoading = function(show) -{ - if (show) - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - // update start time - this._loadingData.timeStarted = new Date().getTime(); - - if (this.properties.showLoadingOverlayTimeout > 0) - { - // delayed show overlay - this._loadingData.startTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, true), this.properties.showLoadingOverlayTimeout); - } - else - { - // show overlay immediately - this._setLoadingOverlay(true); - } - } - - // update flag - this._inLoading = true; - } - else - { - // check whether loading overlay is enabled - if (this.properties.loadingOverlayEnabled) - { - if (this.properties.hideLoadingOverlayTimeout > 0) - { - // delayed hide overlay - var now = new Date().getTime(); - if (now - this._loadingData.timeStarted < this.properties.showLoadingOverlayTimeout) - { - // no overlay has been shown -> reset everything - this._setLoadingOverlay(false); - } - else if (now - this._loadingData.timeShown < this.properties.hideLoadingOverlayTimeout) - { - // the overlay has been visible less than the hideLoadingOverlayTimeout -> hide it in hideLoadingOverlayTimeout ms after it has been made visible - this._loadingData.endTimeoutId = setTimeout(this._setLoadingOverlay.bind(this, false), this.properties.hideLoadingOverlayTimeout - (now - this._loadingData.timeShown)); - } - else - { - // the overlay has been visible long enough -> hide it immediately - this._setLoadingOverlay(false); - } - } - else - { - // hide overlay immediately - this._setLoadingOverlay(false); - } - } - - // update flag - this._inLoading = false; - } - - return this._inLoading; -}; - -List2Ctrl.prototype._setLoadingOverlay = function(show) -{ - if (show) - { - // show loading - this.mask.appendChild(this.loading); - - this._loadingData.timeShown = new Date().getTime(); - } - else - { - // hide loading - if (null != this.loading.parentElement) - { - this.loading.parentElement.removeChild(this.loading); - } - - // reset loading data - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - this._loadingData.timeStarted = 0; - this._loadingData.timeShown = 0; - this._loadingData.startTimeoutId = null; - this._loadingData.endTimeoutId = null; - } -}; - -/** 7. DEFAULT TITLE CONFIGURATION **/ - -/** - * Prepare title - * A list title can be defined with minimal set of properties - * that are needed for its proper display. This function sets - * default configuration for a valid title and merge it with the - * custom configuration passed to the title. - * TAG: internal - * ========================= - * @param {object} - the title object that will be set a default set of properties and will be returned - * @return {object} - the complete title object - */ -List2Ctrl.prototype._prepareTitle = function(titleObj) -{ - // The itemStyle property is required - if (!titleObj.hasOwnProperty('titleStyle')) - { - log.error('Lis2: title should have titleStyle property: ' + titleObj); - return; - } - - // default properties - var title = {}; - switch (titleObj.titleStyle) - { - case 'style02' : - title = { text1:'', text1Id:null, text1SubMap:null, styleMod:'' }; - break; - case 'style02a' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - case 'style03' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'' }; - break; - case 'style05' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null, image1:'' }; - break; - case 'style06' : - title = { image1:'' }; - break; - case 'style07' : - title = { text1:'', text1Id:null, text1SubMap:null, text2:'', text2Id:null, text2SubMap:null }; - break; - case 'style08' : - title = { text1:'', text1Id:null, text1SubMap:null, image1:'', styleMod:'' }; - break; - default : - log.error('Lis2: unknown title style: ' + titleObj.titleStyle); - break; - } - - // Extend default structure with the supplied item - for (var i in titleObj) - { - title[i] = titleObj[i]; - } - - // Perform localization - switch (title.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style08' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - break; - case 'style05' : - case 'style07' : - if (title.text1Id) - { - title.text1 = this._getLocalizedString(title.text1Id, title.text1SubMap); - } - if (title.text2Id) - { - title.text2 = this._getLocalizedString(title.text2Id, title.text2SubMap); - } - break; - } - - return title; -}; - - -/** - * ========================= - * SCROLL INDICATOR - * - reset - * - create - * - visual update - * ========================= - */ - -/** - * Remove any scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorReset = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // remove any scroll indicator - if (this.scrollIndicatorWrapper) - { - // remove wrapper (and scroll indicator) - this.scrollIndicatorWrapper.parentElement.removeChild(this.scrollIndicatorWrapper); - - // nullify elements - this.scrollIndicatorWrapper = null; - this.scrollIndicator = null; - - // reset scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = 0; - } -}; - -/** - * Create scroll indicator - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorBuild = function(visible) -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator size - var indicatorSize = Math.round(this.mask.offsetHeight * (this.mask.offsetHeight / this.scroller.offsetHeight)); - - // add scroll indicator wrapper - this.scrollIndicatorWrapper = document.createElement('div'); - this.scrollIndicatorWrapper.className = 'List2CtrlScrollIndicatorWrapper'; - this.divElt.appendChild(this.scrollIndicatorWrapper); - - // add scroll indicator - this.scrollIndicator = document.createElement('div'); - this.scrollIndicator.className = 'List2CtrlScrollIndicator'; - if(!visible) - { - this.scrollIndicatorWrapper.style.visibility = 'hidden'; - } - else - { - this.scrollIndicatorWrapper.style.visibility = 'visible'; - } - this.scrollIndicator.style.height = this.m.max(indicatorSize, this.properties.scrollIndicatorMinSize) + 'px'; - this.scrollIndicator.style.top = '0px'; - this.scrollIndicatorWrapper.appendChild(this.scrollIndicator); - - // set scroll indicator boundaries - this._indicatorMin = 0; - this._indicatorMax = this.mask.offsetHeight - this.scrollIndicator.offsetHeight; - - if (this.properties.hasLetterIndex) - { - // hide scroll indicator when letterIndex is enabled - this._hideScrollIndicator(); - } - else - { - // fade out scroll indicator - this._fadeOutScrollIndicator(); - } -}; - -/** - * Update scroll indicator position on drag - * This is fired on _USER_EVENT_MOVE when the - * list is being dragged by touch. - * TAG: touch-only, internal - * ========================= - * @return {integer} scroll indicator position - */ -List2Ctrl.prototype._dragUpdateScrollIndicator = function() -{ - // check for scroll indicator configuration - if (!this.properties.showScrollIndicator) - { - return; - } - - // determine scroll indicator position - var indicatorPos = Math.round(this._indicatorMax * (this.scroller.offsetTop / this._maxScrollY)); - - // constrain position - indicatorPos = this.m.max(indicatorPos, this._indicatorMin); - - // set new position - this.scrollIndicator.style.top = indicatorPos + 'px'; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return indicatorPos; -}; - -/** - * Update scroll indicator position on drag - * Called on scroll animation (flick or scroll ad-hoc) - * TAG: internal - * ========================= - * @param {integer} the new position of the scroller - * @param {integer} the time for animation to the new position - * @return {integer} the new scroll indicator position - */ -List2Ctrl.prototype._updateScrollIndicator = function(pos, time) -{ - // check for time - if (time == undefined || time == null) - { - // get default time - time = this.properties.swipeAnimationDuration; - } - - // determine scroll indicator new position - var newRelativePos = pos / this._maxScrollY; - var newPos = Math.round(newRelativePos * (this._indicatorMax - this._indicatorMin)); - - // start animation - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollIndicatorAnimationEndCallback = this._scrollIndicatorAnimationEnd.bind(this); - this.scrollIndicator.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicator.style.top = newPos + 'px'; - - // clear any previously scheduled scroll indicator fade out - clearTimeout(this._scrollIndicatorTimeoutId); - this._scrollIndicatorTimeoutId = null; - - // fade in scroll indicator - this._fadeInScrollIndicator(); - - return newPos; - -}; - - -List2Ctrl.prototype._fadeInScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeInDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -List2Ctrl.prototype._fadeOutScrollIndicator = function() -{ - // check whether scroll indicator needs to fade - if (this.properties.scrollIndicatorFadeTimeout <= 0) - { - return; - } - - // clear any previously-scheduled hiding - clearTimeout(this._scrollIndicatorTimeoutId); - - // schedule hide - this._scrollIndicatorTimeoutId = setTimeout(function() { - this.scrollIndicatorWrapper.style[this._VENDOR + 'TransitionDuration'] = this.properties.scrollIndicatorFadeOutDuration + 'ms'; - this.scrollIndicatorWrapper.style.opacity = 0; - this._scrollIndicatorTimeoutId = null; - }.bind(this), this.properties.scrollIndicatorFadeTimeout); -}; - -List2Ctrl.prototype._hideScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 0; -}; - -List2Ctrl.prototype._showScrollIndicator = function() -{ - this.scrollIndicatorWrapper.style.opacity = 1; -}; - -/** - * ========================= - * TOUCH EVENT HANDLERS - * - Event detection and custom event dispatching - * - Start/Move/End/Out event handling - * - Hit state control - * ========================= - */ - -/** - * Handle any touch event and dispatch appropriate - * custom event. Actual event processing is done in the - * respective handlers of the custom events. The original - * event object is attached to the custom event in its - * event property. - * ========================= - * @param {event} - any touch event - * @return {Boolean} - True if event was processed - */ -List2Ctrl.prototype._touch = function(e) -{ - var touchResult = false; - - switch(e.type) - { - case this._USER_EVENT_START : - // route to letter index first, otherwise route to list - touchResult = this._startIndex(e) || this._start(e); - /* - * Attach temporary listeners to document if we have a positive start. - * These listeners will be removed on _USER_EVENT_END - */ - if (touchResult) - { - document.addEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.addEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - } - break; - - case this._USER_EVENT_MOVE : - // route to letter index first, otherwise route to list - touchResult = this._moveIndex(e) || this._move(e); - break; - - case this._USER_EVENT_END : - /* - * Remove the document event listeners no matter of these have been - * attached or not. This will prevent any non-existent callbacks firing. - */ - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - // route to letter index first, otherwise route to list - touchResult = this._endIndex(e) || this._end(e); - break; - - case this._USER_EVENT_OUT : - this._out(e); - break; - } - - return touchResult; -}; - -/** - * Start Touch on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._start = function(e) -{ - // abort any ongoing scroll - this._abortScroll(e); - - // get mask position and dimensions - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - this._maskH = this.mask.offsetHeight; - this._maskW = this.mask.offsetWidth; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - // reset letter index multicontroller - this._focusStolen = false; - if (relativeY >= 0) - { - this._setLetterIndexMulticontroller(false, true); - - // steal focus - var canGainFocus = this._canGainFocus(e); - if (!this._hasFocus && -1 !== canGainFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - this._focusStolen = true; - } - } - - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by start reorder rather than regular start - this._startReorder(e); - return true; - } - - this._startItem = this._getTargetItem(e); - this._startDOMItem = this._getDOMItem(this._startItem); - - // make hit - if (this.properties.hitTimeout > 0) - { - // after some time - this._makeHitTimeoutId = setTimeout(this._itemMakeHit.bind(this, e), this.properties.hitTimeout); - } - else - { - // immediately - this._itemMakeHit(e); - } - - // Place focus on the reported available item when focus is stolen - if (this._focusStolen) - { - this._showFocus(canGainFocus, true); - } - - // make toggles hit - this._buttonMakeHit(e); - - // make locks hit - this._lockMakeHit(e); - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return false; - } - - // check relative mouse position - if (relativeY < 0) - { - return false; - } - - // check for a valid target item - if (this._startItem == -1) - { - return false; - } - - // get current y - this._y = this.scroller.offsetTop; - this._startY = relativeY; - this._startX = relativeX; - this._startTime = new Date().getTime(); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, e), this.properties.longPressTimeout); - - // raise _inDrag - this._inDrag = true; - - // Release secondary MC mode - if (this._inSecondaryMulticontroller && null != this._currentSecondaryMulticontrollerItem && this._startItem != this._currentSecondaryMulticontrollerItem) - { - var temp = this._currentSecondaryMulticontrollerItem; - - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - - // Commit the value - if (!this._isLock(temp)) // locks do not commit the value - { - this._triggerFocus(temp); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(temp, 'clear'); - } - } - - // dispatch scroll start event - this._listEvent(this._EVENTS.SCROLL_START, {scrollPosition:this._topItem}); - - // user touched the list -> return True - return true; - -}; - -/** - * Touch move on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._move = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by move reorder rather than regular move - this._moveReorder(e); - return true; - } - - if (!this._inDrag) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._end(e); - return true; - } - - // calculate travelled distance - var deltaY = relativeY - this._startY; - var deltaX = relativeX - this._startX; - - if (this._inLongPress) - { - return false; - } - - /* - * DRAG DETECTION - * determine whether this is a horizontal or vertical drag - * and raise the horizontal flag - */ - if (null == this._inHorizontalDrag) { - - var alpha = Math.atan2(this.m.abs(deltaX), this.m.abs(deltaY)); - if (alpha < this.properties.hvThreshold) - { - // vertical - this._inHorizontalDrag = false; - } - else - { - // horizontal - this._inHorizontalDrag = true; - this._hDragItem = this._getTargetItem(e); - - // set slideStart - this._slideStart(e); - } - } - - // drag slider - if (this._inHorizontalDrag == true) - { - // we have a horizontal drag -> move sliders - this._slideMove(e); - } - // drag list if scrollable - else if (false == this._inHorizontalDrag && this._isScrollable) - { - // we have a vertical drag and the list can be scrolled - // calculate the scroller's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollY, this.m.min(this._y + deltaY, this._minScrollY)); - - // drag the scroller if in bounds - this.scroller.style.top = newPos + 'px'; - - // update scroll indicator - this._dragUpdateScrollIndicator(); - - // raise _stopClick flag and remove hit and long press - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit and prevent delayed hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); - - // remove long press and prevent long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); - } - } - // control hit state when not scrollable or when no scrolling occurs (e.g. when we are one of the list extremities) - if (!this._isScrollable || this.m.abs(deltaY) > this.properties.selectThreshold) - { - var targetTop = this._startDOMItem.offsetTop; - if (relativeY < targetTop || relativeY > targetTop + this.properties.itemHeight) - { - // remove hit - this._itemRemoveHit(e); - - // prevent select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = true; - } - } - else - { - // make hit - if (this._stopSelect && !this._isScrollable) - { - this._itemMakeHit(e); - } - - // enable select only on non-scrollable lists - // the scrollable lists are handled in the above case - if (!this._isScrollable) - { - this._stopSelect = false; - } - } - } - - // user touched the list -> return True - return true; -}; - -/** - * Touch end on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._end = function(e) -{ - // handle list reorder cases first - if (this._inListReorder) - { - // route event to be handled by end reorder rather than regular end - this._endReorder(e); - return true; - } - - - // remove hit - this._itemRemoveHit(e); - clearTimeout(this._makeHitTimeoutId); // clear hit timeout - // remove long press - this._itemRemoveLongPress(e); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - this._startItem = null; - this._startDOMItem = null; - - // reset drag flag and hDrag item - this._inHorizontalDrag = null; - this._hDragItem = null; - - if (!this._inDrag) - { - // this is called without having a drag - return false; - } - - // end any drag of sliders - this._slideEnd(e); - - // set scroll nature - this._scrollNature = 'touch'; - - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTime; - if (this._focusStolen && !this._stopSelect) - { - // slight drag -> scroll to show focus on the available item when stealing focus - // decide whether to allow offscrean - var focussedIndex = this._getFocussedIndex(); - var allowOffScreen = (focussedIndex > this._topItem && focussedIndex < this._topItem + this.properties.visibleItems); - this._showFocus(focussedIndex, allowOffScreen); - this._focusStolen = false; - } - else if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startY; - - // swipte detected - this._startSwipe(deltaY, velocity); - } - else - { - // regular drag -> snap to item bounds - this._snap(this.scroller.offsetTop); - } - - // call touch select logic - this._touchSelectItem(e); - - // reset any previously set flags - this._inDrag = false; - this._stopSelect = false; - this._startTime = 0; - - // user touched the list -> return True - return true; -}; - -/** - * Touch leave on list - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {Boolean} - True if list is touched - */ -List2Ctrl.prototype._out = function(e) -{ - return this._end(e); -}; - - -/** - * Start Touch on letter index - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {boolean} - True if letter index is touched - */ -List2Ctrl.prototype._startIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // get mask position - this._maskPositionY = this.getPosition(this.mask)[1]; - this._maskPositionX = this.getPosition(this.mask)[0]; - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - if (relativeY < 0) - { - return false; - } - - // hit test letter index - if (relativeX <= this.letterIndexWrapper.offsetLeft) - { - return false; - } - - // steal focus - if (!this._hasFocus) - { - framework.common.stealFocus(); - this._hasFocus = true; - } - - // Enter into letter index multicontroller mode if not already - if (!this._inLetterIndexMulticontroller) - { - this._setLetterIndexMulticontroller(true); - } - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - - // make hit - this._indexMakeHit(e); - - // get start coordinates and time - this._yIndex = this.letterIndex.offsetTop; - this._startIndexY = relativeY; - this._startIndexX = relativeX; - this._startTimeIndex = new Date().getTime(); - - this._inDragIndex = true; - - return true; - -}; - - -List2Ctrl.prototype._moveIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - if (!this._inDragIndex) - { - return false; - } - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return false; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get relative mouse position - var relativeY = e.pageY - this._maskPositionY; - var relativeX = e.pageX - this._maskPositionX; - - if (relativeY < -this._maskPositionY) - { - // we are out of bounds - this._endIndex(e); - - return false; - } - - // calculate travelled distance - var deltaY = relativeY - this._startIndexY; - var deltaX = relativeX - this._startIndexX; - - // calculate the letter index's new position and constrain it into bounds - var newPos = this.m.max(this._maxScrollYIndex, this.m.min(this._yIndex + deltaY, this._minScrollYIndex)); - - // drag the letter index if in bounds - this.letterIndex.style.top = newPos + 'px'; - - // raise _stopClick flag - if (this.m.abs(deltaY) > this.properties.selectThreshold) - { - this._stopSelect = true; - - // remove hit - this._indexRemoveHit(e); - } - - return true; - -}; - - -List2Ctrl.prototype._endIndex = function(e) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - // remove hit - this._indexRemoveHit(e); - - if (!this._inDragIndex) - { - return false; - } - - if (!this._stopSelect) - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // select letter index - var letterIndex = this._getTargetLetterIndex(e); - this._letterIndexSelect(letterIndex, 'Touch'); - } - else - { - // detect swipe motion - var endTime = e.timeStamp || new Date().getTime(); - var velocity = endTime - this._startTimeIndex; - if (velocity < this.properties.swipeThreshold && velocity > 0) - { - // get relative mouse position and calculate travelled distance - var relativeY = e.pageY - this._maskPositionY; - var deltaY = relativeY - this._startIndexY; - - // swipte detected - this._startSwipeIndex(deltaY, velocity); - } - else - { - // snap position - this._snapIndex(this.letterIndex.offsetTop); - - // schedule letter index select if letter is enabled - var letterIndex = this._getTargetLetterIndex(e); - if (!this.letterIndexData[letterIndex].disabled) - { - this._scheduleLetterIndexSelect(letterIndex); - } - } - } - - // reset flags - this._inDragIndex = false; - this._stopSelect = false; - - return true; -}; - - - -/** - * Select item - * TAG: touch-only, internal - * ========================= - * @param {event} - raw touch/mouse event - * @return {void} - */ -List2Ctrl.prototype._touchSelectItem = function(e) -{ - // clear any hit timeout - clearTimeout(this._makeHitTimeoutId); - - // if we are not allowed to select (when in drag) - if (this._stopSelect) - { - this._stopSelect = false; - return; - } - - // select during loading is not allowed - if (this._inLoading) - { - return; - } - - var itemIndex; - var fireSelect = true; - var additionalModifier = null; - var params = {}; - - // determine target item - itemIndex = this._getTargetItem(e); - - // only valid list items can fire the select callback - if (itemIndex == -1) - { - return; - } - - // ensure that we end up on the same item where we started so that the select is valid - if (itemIndex != this._getFocussedIndex()) - { - return; - } - - // perform any additional touch processing for some items before issuing select callback - if (this._isToggle(itemIndex)) - { - // the target contains toggle buttons -> select toggle buttons - var toggleSelected = this._buttonSelect(e); - if ('cancel' == toggleSelected) - { - fireSelect = false; - } - else if (null != toggleSelected) - { - params = { additionalData:toggleSelected }; - additionalModifier = 'preventSimpleSelect'; - } - - } - - if (this._isSlider(itemIndex)) - { - // the target contains a slider -> disable select only if the slider is adjustable - if (this.dataList.items[itemIndex].allowAdjust) - { - fireSelect = false; - } - } - - if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && this._inSecondaryMulticontroller) - { - // if we are in secondary multicontroller and the item is a step item - var stepResult = this._stepAdjust(e); - if ('commit' === stepResult) - { - params = { finalAdjust:true, value:this.dataList.items[itemIndex].value }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - else if (null != stepResult) - { - params = { finalAdjust:false, value:stepResult }; - } - else - { - fireSelect = false; - } - } - else if (this._isStep(itemIndex) && this._hasSecondaryMulticontroller(itemIndex) && !this._inSecondaryMulticontroller) - { - // if we are not in secondary multicontroller and the item is step item - this._setSecondaryMulticontroller(true, itemIndex); - fireSelect = false; - - // produce beep - this._beep('Short', 'Touch'); - } - - if (this._isLock(itemIndex) && this._hasSecondaryMulticontroller(itemIndex)) - { - // the target is a lock item - var lockAction = this._lockSelect(e); - if (null == lockAction) - { - fireSelect = false; - } - else - { - // prepare params - params = { additionalData:lockAction }; - additionalModifier = 'exitSecondaryMulticontroller'; - } - } - - // prevent select on disabled items - if (this.dataList.items[itemIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Touch'); - - this._itemSelect(itemIndex, params, additionalModifier); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior) - { - this._itemHoldStop(itemIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - -}; - -/** - * Exit hit state of the currently hit item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._itemRemoveHit = function() -{ - var hitItems = this.scroller.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i= this.dataList.itemCount || this.dataList.items[itemIndex].disabled) - { - return; - } - - var returnValue = null; - - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'styleOnOff' : - // get and update current value - var currentValue = this.dataList.items[itemIndex].value; - var newValue = (1 === currentValue) ? 2 : 1; - this.dataList.items[itemIndex].value = newValue; - - // get and update DOM item - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (1 === newValue) - { - domItem.classList.add('checked'); - } - else - { - domItem.classList.remove('checked'); - } - } - returnValue = newValue; - break; - - case 'style10' : - case 'style11' : - // Note: settle timeout is registered in this._buttonActivate - this._buttonSelectRight(itemIndex); - returnValue = this.dataList.items[itemIndex].value; - break; - - case 'style03' : - case 'style03a' : - var currentValue = this.dataList.items[itemIndex].checked; - switch (this.dataList.items[itemIndex].image1) - { - case 'tick' : - if (!currentValue) - this._setTick(itemIndex, !currentValue); - break; - case 'radio' : - if (!currentValue) - this._setRadio(itemIndex, !currentValue); - break; - case 'checkbox' : - this._setCheckBox(itemIndex, !currentValue); - break; - } - returnValue = this.dataList.items[itemIndex].checked; - break; - - default : - log.warn('Lis2: No simple select behavior for item style ' + this.dataList.items[itemIndex].itemStyle); - break; - } - - return returnValue; - -}; - -/** - * Fire select callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid selectCallback - */ -List2Ctrl.prototype._itemSelect = function(itemIndex, paramsModifier, additionalModifier) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - // get paramsModifier - var paramsModifier = paramsModifier || {}; - - // get additionalModifier - var additionalModifier = additionalModifier || null; - - var appData = null; - var additionalData = null; - var params = {}; - - // event filtering - var filterEvent = false; - - if (this._isSlider(itemIndex)) - { - // the item contains a slider - additionalData = this.dataList.items[itemIndex].value; - } - - if (this._isSimpleSelectItem(itemIndex)) - { - // the item is simple select item - if ('preventSimpleSelect' != additionalModifier) - { - // process simple select behavior before firing the select callback - additionalData = this._simpleSelect(itemIndex); - } - - // apply event filter - var filterType = (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) ? 'toggle' : (this._isCheckBox(itemIndex)) ? 'check' : null; - filterEvent = this._applyEventFilter(itemIndex, filterType); - } - else if (this._isStep(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - this._setSecondaryMulticontroller(false, itemIndex); - } - else if (this._isLock(itemIndex) && 'exitSecondaryMulticontroller' === additionalModifier) - { - // restore focus and remove any secondary multicontroler - this._showFocus(this._lastItemWithFocus); - this._lockShowFocus(itemIndex, 'clear'); - this._setSecondaryMulticontroller(false, itemIndex); - } - - // is this filtered event? - if (filterEvent) - { - return false; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - // merge params with params modifier - for (var i in paramsModifier) - { - params[i] = paramsModifier[i]; - } - - // return value - var result = false; - - // do not fire select on disabled items but instead fire select disabled - if (this.dataList.items[itemIndex].disabled) - { - // fire select disabled callback - if (typeof this.properties.selectDisabledCallback == 'function') - { - /* - * Handles touches on disabled list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectDisabledCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - } - else - { - // fire select callback - if (typeof this.properties.selectCallback == 'function') - { - /* - * Handles select on list items - * @param ctrlObj Object Reference to the list control that was selected - * @param btnData Object Data that was attached to the selected item - * @param params Object Object containing extra data - */ - result = this.properties.selectCallback(this, appData, params); - - // set result to true if nothing is returned from the select callback - if (undefined == result) - { - result = true; - } - } - - // dispatch select event - this._listEvent(this._EVENTS.ITEM_SELECT, params); - } - - if (this._hasData(itemIndex)) - { - // record this event and clear any timeouts - this.dataList.items[itemIndex]._data.lastEvent = new Date().getTime(); - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = null; - } - - return result; -}; - -/** - * Fire long press callback on an item. - * This function is called whenever a select event - * occurs. It is a single call point for all selects - * and should be invoked whether select event is intended. - * TAG: internal - * ========================= - * @param {event|integer} - raw touch/mouse event or directly the index of the item - * @return {boolean} - true if there's a valid longPressCallback - */ -List2Ctrl.prototype._itemLongPress = function(e) -{ - var eventCause = null; - var itemIndex = -1; - - // the parameter is an event - if (typeof e == 'object') - { - // determine target item - itemIndex = this._getTargetItem(e);var itemIndex = this._getTargetItem(e); - eventCause = 'Touch'; - } - // the parameter is an index - else if (!isNaN(e)) - { - itemIndex = e; - eventCause = 'Multicontroller'; - } - - // if the item is short-press-only -> prevent any longpress activity - if ('shortPressOnly' === this.dataList.items[itemIndex].itemBehavior) - { - return; - } - // if the item has itemBehavior other than shortAndLong and shortAndHold -> this is invalid property and prevent any longpress activity - else if ('shortAndLong' != this.dataList.items[itemIndex].itemBehavior && 'shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - log.warn('Lis2: Invalid itemBehavior property. Item behavior can be shortPressOnly / shortAndLong / shortAndHold'); - return; - } - - // make it long-pressed - this._itemMakeLongPress(e); - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // produce beep - this._beep('Long', eventCause); - - // fire long press callback - if ('shortAndLong' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.longPressCallback == 'function') - { - /* - * Handles long press on list items - * @param ctrlObj Object Reference to the list control that was long-pressed - * @param btnData Object Data that was attached to the long-pressed item - * @param params Object Object containing extra data - */ - this.properties.longPressCallback(this, appData, params); - - result = true; - } - // fire hold start callback - else if ('shortAndHold' === this.dataList.items[itemIndex].itemBehavior && typeof this.properties.holdStartCallback == 'function') - { - /* - * Handles hold start on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStartCallback(this, appData, params); - - result = true; - } - - // raise the flag for long-press/hold-start issued callback - this._longPressIssued = true; - - // enter into list reorder on long press if the list supports it - if (this.properties.listReorder) - { - this._enterListReorder(); - this._startReorder(e); - } - - return result; -}; - - -/** - * Fire hold stop on an item. - * This function is called whenever the user ends touch - * on an item that has itemBehavior = shortAndHold - * TAG: internal, touch-only - * ========================= - * @param {integet} - item index - * @return {boolean} - true if there's a valid holdStopCallback - */ -List2Ctrl.prototype._itemHoldStop = function(itemIndex) -{ - // validate item behavior property - if ('shortAndHold' != this.dataList.items[itemIndex].itemBehavior) - { - return; - } - - var appData = null; - var additionalData = null; - var params = {}; - - if (this._isSlider(itemIndex)) - { - // the target has a slider - additionalData = this.dataList.items[itemIndex].value; - } - - // get the data - appData = this.dataList.items[itemIndex].appData; - - // prepare params - params = { - itemIndex : itemIndex, - additionalData : additionalData, - fromVui : false - }; - - // return value - var result = false; - - // fire hold stop callback - if (typeof this.properties.holdStopCallback == 'function') - { - /* - * Handles hold stop on list items - * @param ctrlObj Object Reference to the list control that was long-held - * @param btnData Object Data that was attached to the long-held item - * @param params Object Object containing extra data - */ - this.properties.holdStopCallback(this, appData, params); - - result = true; - } - - return result; -}; - -/** - * Perform outbound event filtering - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {boolean} - whethet to filter the event or not - */ -List2Ctrl.prototype._applyEventFilter = function(itemIndex, filterType) -{ - var filter = false; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return filter; - } - - var now = new Date().getTime(); - - switch (filterType) - { - case 'toggle' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.dataList.items[itemIndex].minChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.dataList.items[itemIndex].minChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - } - break; - - case 'check' : - var difference = now - this.dataList.items[itemIndex]._data.lastEvent; - if (difference < this.properties.checkMinChangeInterval) - { - // too soon -> filter the immediate event and send it later - log.debug('Event filtered'); - filter = true; - - // schedule callback - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - this.dataList.items[itemIndex]._data.eventTimeout = setTimeout(this._filterTimeoutCallback.bind(this, itemIndex, filterType), this.properties.checkMinChangeInterval - difference); - } - else - { - // timing is ok -> pass the event and clear any scheduled selects - clearTimeout(this.dataList.items[itemIndex]._data.eventTimeout); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - } - break; - } - - return filter; -}; - -/** - * Timeout callback that is run if a select event - * is scheduled by the outbound filtering mechanism - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - filter type - * @return {void} - */ -List2Ctrl.prototype._filterTimeoutCallback = function(itemIndex, filterType) -{ - switch (filterType) - { - case 'toggle' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].value }, 'preventSimpleSelect'); - - // register settle timeout - this._registerSettleTimeout(itemIndex, 'toggle'); - break; - - case 'check' : - this._itemSelect(itemIndex, { additionalData : this.dataList.items[itemIndex].checked }, 'preventSimpleSelect'); - - // register settle timeout - if ('radio' === this.dataList.items[itemIndex].image1 || - 'tick' === this.dataList.items[itemIndex].image1 || - 'checkbox' === this.dataList.items[itemIndex].image1) - { - var itemType = this.dataList.items[itemIndex].image1; - this._registerSettleTimeout(itemIndex, itemType); - } - break; - } -}; - -/** - * Register a settle timeout on any new user input. - * Any previous settle timeout should get cleared - * before setting a new one. The timeout state should - * be checked when public API call is made and depending - * on whether the timeout is running or not, the value - * will be cached or applied to the item. - * The settle time acts as an inbound event filtering mechanism. - * TAG: internal - * ========================= - * @param {integer} - itemIndex - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._registerSettleTimeout = function(itemIndex, itemType) -{ - log.debug('Settle scheduled'); - this._clearSettleTimeout(itemIndex, itemType); - - // schedule settle item - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._radioSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - this._tickSettleTimeoutId = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.properties.checkSettleTime); - } - break; - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - this.dataList.items[itemIndex]._data.settleTimeout = setTimeout(this._settleItem.bind(this, itemIndex), this.dataList.items[itemIndex].settleTime); - } - break; - } -}; - -/** - * Clear any settle timeouts on any user input. - * TAG: internal - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {void} - */ -List2Ctrl.prototype._clearSettleTimeout = function(itemIndex, itemType) -{ - switch (itemType) - { - case 'radio' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._radioSettleTimeoutId); - this._radioSettleTimeoutId = null; - } - case 'tick' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - clearTimeout(this._tickSettleTimeoutId); - this._tickSettleTimeoutId = null; - } - break; - - case 'checkbox' : - if (this._isCheckBox(itemIndex) && itemType === this.dataList.items[itemIndex].image1) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - - case 'toggle' : - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - clearTimeout(this.dataList.items[itemIndex]._data.settleTimeout); - this.dataList.items[itemIndex]._data.settleTimeout = null; - } - break; - } -}; - -/** - * Performs a check whether a settlie timeout - * is running for a particular item, radio group - * or tick group. - * ========================= - * @param {integer} - item index - * @param {string} - item type - tick | radio | checkbox | toggle - * @return {Boolean} - True if a settle timeout is running - */ -List2Ctrl.prototype._hasSettleTimeout = function(itemIndex, itemType) -{ - var timeoutRunning = false; - - switch (itemType) - { - case 'radio' : - if (null !== this._radioSettleTimeoutId && this._radioSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'tick' : - if (null !== this._tickSettleTimeoutId && this._tickSettleTimeoutId >= 0) - { - timeoutRunning = true; - } - break; - - case 'checkbox' : - case 'toggle' : - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return timeoutRunning; - } - - if (null !== this.dataList.items[itemIndex]._data.settleTimeout && this.dataList.items[itemIndex]._data.settleTimeout >= 0) - { - timeoutRunning = true; - } - break; - } - - return timeoutRunning; -}; - -/** - * Settle an item after the settle time expires. - * The cached value (if any) gets assigned as a - * real value to the item and the item is updated. - * This is the settleTimeout callback. - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item is successfully settled - */ -List2Ctrl.prototype._settleItem = function(itemIndex) -{ - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return false; - } - - // exit if the item index is out of range - if (isNaN(itemIndex) || itemIndex < 0 || itemIndex >= this.dataList.items.length) - { - return false; - } - - var item = this.dataList.items[itemIndex]; - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return false; - } - - // get settle value and set it as real value, and update item - var settleValue = item._data.settleValue; - - - - if (this._isToggle(itemIndex) || this._isOnOff(itemIndex)) - { - if (null != item._data.settleValue) - { - // set real value - item.value = settleValue; - this.updateItems(itemIndex, itemIndex); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - } - else if (this._isCheckBox(itemIndex)) - { - // Note: setting the real value is done in the helpers - switch (item.image1) - { - case 'checkbox' : - if (null != item._data.settleValue) - { - // set real value - this._setCheckBox(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - item._data.settleTimeout = null; - break; - - case 'radio' : - if (null != item._data.settleValue) - { - // set real value - this._setRadio(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._radioSettleTimeoutId = null; - break; - - case 'tick' : - if (null != item._data.settleValue) - { - // set real value - this._setTick(itemIndex, settleValue); - - // release settle value - item._data.settleValue = null; - } - // reset timeout - this._tickSettleTimeoutId = null; - break; - } - } - else - { - // item does not support settlement - return false; - } - - log.debug('Settle item: ' + itemIndex + ', value: ' + settleValue); - - // return success - return true; - -}; - - -/** - * ========================= - * MULTICONTROLLER AND VUI - * ========================= - */ - -/** - * Main multicontroller handler - * TAG: multicontroller-only, public - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype.handleControllerEvent = function(eventID) -{ - log.debug("handleController() called, eventID: " + eventID); - - /* - * eventID - * - acceptFocusInit (sent on instantiation) - * - acceptFocusFromLeft - * - acceptFocusFromRight - * - acceptFocusFromTop - * - acceptFocusFromBottom - * - lostFocus - * - touchActive - * ... - */ - - var response; - - // ignore certain MC events when the list is in motion by touch - if (this._inDrag || (this._inScroll && 'touch' === this._scrollNature)) - { - switch (eventID) - { - case "acceptFocusInit" : - case "acceptFocusFromLeft" : - case "acceptFocusFromRight" : - case "acceptFocusFromTop" : - case "acceptFocusFromBottom" : - case "lostFocus" : - case "touchActive" : - case "controllerActive" : - // pass these events - break; - default : - // ignore everything else - return "ignored"; - break; - } - } - - if (!this._inSecondaryMulticontroller) - { - // we are in primary multicontroller mode - switch (eventID) - { - case "acceptFocusInit": - // consume event by default - response = "consumed"; - - // Input mode change to multicontroller - this._inputMode = 'controller'; - /* - * this event is received every time a template is displayed - * if we already have preset a focus item, do not set it again - */ - // Show focus animation - this._showFocusAnimation = true; - if ('restore' != this._initialScrollMode) - { - this._hasFocus = true; - var itemToGainFocus = this._canGainFocus('controllerActive'); - if (-1 !== itemToGainFocus) - { - this._showFocus(itemToGainFocus); - } - else - { - if (this.hasDataList()) - { - // we have data list and there are no enabled items -> give focus to the left - response = 'giveFocusLeft'; - } - else - { - // we probably dont't have a data list -> wait untul we get it - this._showFocus(this.properties.focussedItem); - } - } - } - else - { - this._showFocus(this.properties.focussedItem); - } - break; - - case "acceptFocusFromLeft": - // Show focus animation - this._showFocusAnimation = true; - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromRight": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromTop": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "acceptFocusFromBottom": - // Restore focussed element - var itemToGainFocus = this._canGainFocus(); - if (-1 !== itemToGainFocus) - { - this._hasFocus = true; - this._showFocus(itemToGainFocus); - response = "consumed"; - } - else - { - response = "ignored"; - } - break; - - case "lostFocus": - this._hideFocus(); - this._hideFocusLetterIndex(); - this._hasFocus = false; - response = "consumed"; - break; - - case "touchActive": - // Input mode change to touch - this._inputMode = 'touch'; - this._hideFocus(); - response = "consumed"; - break; - - case "controllerActive": - response = "consumed"; - break; - - case "cw": - // Rotate Right (CW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCW(); - break; - - case "ccw": - // Rotate Left (CCW) - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCCCW(); - break; - - case "downStart": - // Tilt Down Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCDown(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCDown(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCDown.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll down for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollDownPage(); // do the first scroll down - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollDownPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll down for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "down" : - // Tilt Down Stop - - if ('downStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any downs without downStarts - response = "ignored"; - } - - break; - - case "upStart": - // Tilt Up Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // handle event in dedicated handler - response = this._handleMCUp(); - - // schedule autoscroll behavior only if not in list reorder - if (!this._inListReorder) - { - clearTimeout(this._tiltHoldTimeoutId); // clear any redundant timeouts - this._tiltHoldTimeoutId = null; - log.debug('Schedule autoscroll tier 1'); - this._tiltHoldTimeoutId = setTimeout(function() { // schedule first autoscroll tier - this._beep('Long', 'Multicontroller'); // produce beep - log.debug('Start autoscroll tier 1'); - this._handleMCUp(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals - this._tiltHoldIntervalId = null; - log.debug('Schedule autoscroll tier 2'); - this._tiltHoldIntervalId = setInterval(this._handleMCUp.bind(this), this.properties.autoscrollTier1Interval); // schedule auto scroll up for first tier - if (!this._inLetterIndexMulticontroller) - { - this._tiltHoldTimeoutId = setTimeout(function() { // schedule second autoscroll tier only if not in letter index multicontroller - log.debug('Start autoscroll tier 2'); - this._scrollUpPage(); // do the first scroll up - clearInterval(this._tiltHoldIntervalId); // clear any redundand intervals from the first tier - this._tiltHoldIntervalId = null; - this._tiltHoldIntervalId = setInterval(this._scrollUpPage.bind(this), this.properties.autoscrollTier2Interval); // schedule auto scroll up for second tier - }.bind(this), this.properties.autoscrollTier2Timeout); - } - }.bind(this), this.properties.autoscrollTier1Timeout); - } - - break; - - case "up": - // Tilt Up Stop - - if ('upStart' === this._lastControllerEvent) - { - log.debug('Clear any scheduled autoscrolls'); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - this._tiltHoldTimeoutId = null; - this._tiltHoldIntervalId = null; - - // schedule letter index select - if (this._inLetterIndexMulticontroller) - { - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - } - - response = "consumed"; - } - else - { - // ignore any ups without upStarts - response = "ignored"; - } - - break; - - case "leftStart": - // Tilt Left Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && this._inLetterIndexMulticontroller) - { - // Exit letter index multicontroller mode - this._setLetterIndexMulticontroller(false); - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusLeft..."); - response = "giveFocusLeft"; - } - break; - - case "left": - // Tilt Left Stop - - if ('leftStart' === this._lastControllerEvent) - { - response = "ignored"; - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any lefts without leftStarts - response = "ignored"; - } - break; - - case "rightStart": - // Tilt Right Start - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - else if (this.letterIndexData.length && !this._inLetterIndexMulticontroller) - { - // Enter into letter index multicontroller mode - this._setLetterIndexMulticontroller(true); - response = "consumed"; - } - else - { - // Return - log.debug("No TabsCtrl. Return giveFocusRight..."); - response = "giveFocusRight"; - } - break; - - - case "right": - // Tilt Right Stop - - if ('rightStart' === this._lastControllerEvent) - { - response = "ignored"; - if (this.tabsCtrl) - { - // Pass bump to TabsCtrl - response = this.tabsCtrl.handleControllerEvent(eventID); - } - } - else - { - // ignore any rights without rightStarts - response = "ignored"; - } - break; - - - case "selectStart": - // SelectStart (press down) - - if (this._inLetterIndexMulticontroller) - { - // get the focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - - // make focussed letter index hit - this._indexMakeHit(focussedLetterIndex); - } - else - { - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // make focussed index hit - this._itemMakeHit(focussedIndex); - - // start longpress countdown - this._longPressTimeoutId = setTimeout(this._itemLongPress.bind(this, focussedIndex), this.properties.longPressTimeout); - } - - // always consume selectStart - response = "consumed"; - - break; - - case "select": - // Select (press down) - - if ('selectStart' === this._lastControllerEvent) - { - - // remove any hit state - this._itemRemoveHit(); - this._indexRemoveHit(); - - // remove long press - this._itemRemoveLongPress(); - clearTimeout(this._longPressTimeoutId); // clear longpress timeout - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // fire letter index select - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - this._letterIndexSelect(currentFocussedLetterIndex, 'Multicontroller'); - } - else - { - if (this.properties.listReorder) - { - // if we are reordering lists (hence pressing down does not produce select event) - if (!this._inListReorder) - { - - // get focussed index - var focussedIndex = this._getFocussedIndex(); - - // check if focussed index is indeed eligable for list reorder - if ('shortAndLong' === this.dataList.items[focussedIndex].itemBehavior) - { - // we are about to begin list reorder - this._enterListReorder(); - } - - } - else - { - // we finish list reorder - this._releaseListReorder(); - } - - } - else - { - // if we are in normal mode - not reordering list - - // get the focussed index - var focussedIndex = this._getFocussedIndex(); - - // does the element have secondary multicontroller behavior? - if (this._hasSecondaryMulticontroller(focussedIndex) && this._isSlider(focussedIndex)) - { - if (this.dataList.items[focussedIndex].allowAdjust) - { - // this item has secondary select and is adjustable slider -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this item has secondary select but is not adjustable -> trigger focus - this._triggerFocus(); - } - } - else if (this._hasSecondaryMulticontroller(focussedIndex)) - { - // this item has secondary select -> enter into secondary multicontroller mode - this._setSecondaryMulticontroller(true); - } - else - { - // this is a regular item -> trigger focus - this._triggerFocus(); - } - - } - } - - // consume Select only after selectStart is consumed - response = "consumed"; - } - else - { - // ignore any selects without selectStarts - response = "ignored"; - } - - break; - - default: - // No action - response = "ignored"; - break; - } - - } - else - { - // we are in secondary multicontroller mode - response = this._handleControllerEventSecondary(eventID); - } - - // keep track of the last consumed event - if ('consumed' === response) - { - this._lastControllerEvent = eventID; - } - - /* - * returns - * - giveFocusLeft (control retains highlight unless it later gets lostFocus event) - * - giveFocusRight - * - giveFocusUp - * - giveFocusDown - * - consumed (always returned on select event, and if control adjusted highlight) - * - ignored (returned only if control doesn't know about focus) - */ - - log.debug("Event: " + eventID + " -> " + "Response: " + response); - - return response; - -}; - -/** - * Handle multicontroller clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - } - else - { - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller counter clockwise rotation event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCCCW = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // we need to go back to the beginning in order to scroll up - var currentFocussedLetterIndex = this._getFocussedLetterIndex(); - - // schedule letter index select - this._scheduleLetterIndexSelect(currentFocussedLetterIndex); - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - - // if we are in list reorder mode - push the draggable item down and set focus on it - if (this._inListReorder) - { - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - // we are not in list reorder mode -> do regular focus scroll - else - { - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - -/** - * Handle multicontroller down tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCDown = function() -{ - - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // define threshold that will serve as a scroll trigger - var bottomFocusThreshold = this.properties.visibleLetterIndexItems - 2; - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocusLetterIndex('down'); - } - else if (this._topLetterIndex === this.letterIndexData.length - this.properties.vivisibleLetterIndexItemssibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - this._reorderItemDown(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - - var rfi = this._getRelativeFocussedIndex(); - } - else - { - var bottomFocusThreshold = this.properties.visibleItems - 2; - - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi <= bottomFocusThreshold) - { - // we are free to move the focus down - this._showFocus('down'); - } - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - { - // we are at the end -> move the focus to the last item - this._showFocus('down'); - } - else if (rfi > bottomFocusThreshold) - { - // the focus is past the bottom focus threshold -> do not move it any more - // this._showFocus('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - // attempt scroll if the focus has passed the threshold - if (rfi > bottomFocusThreshold) - { - this._scrollDownOne(); - } - - } - - return 'consumed'; -}; - - -/** - * Handle multicontroller up tilt event - * TAG: multicontroller-only, internal - * ========================= - * @return {string} - event consumed status - */ -List2Ctrl.prototype._handleMCUp = function() -{ - // are we in letter index multicontroller mode? - if (this._inLetterIndexMulticontroller) - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedLetterIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus down - this._showFocusLetterIndex('up'); - } - else if (this._topLetterIndex === 0) - { - // we are at the end -> move the focus to the last item - this._showFocusLetterIndex('up'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedLetterIndex(); - - // attempt scroll if the focus has passed the threshold - if (rfi < 1) - { - this._scrollUpOneIndex(); - } - - } - else - { - if (this._inListReorder) - { - // if we are in list reorder mode - push the draggable item up and set focus on it - this._reorderItemUp(); - - // set focus - this._showFocus(this._reorderCurrentIndex); - var rfi = this._getRelativeFocussedIndex(); - } - else - { - // get relative focussed index before moving the focus - var rfi = this._getRelativeFocussedIndex(); - - // attempt focus move - if (rfi >= 1) - { - // we are free to move the focus up - this._showFocus('up'); - } - else if (this._topItem === 0) - { - // we are at the beginning -> move the focus to the first item - this._showFocus('up'); - } - else if (rfi === 0) - { - // the focus is on the top item -> do not move it any more - // this._showFocus('down'); - } - - // get relative focussed index after moving the focus - rfi = this._getRelativeFocussedIndex(); - } - - // attempt scroll if the focus is at the first item - if (rfi < 1) - { - this._scrollUpOne(); - } - - } - - return 'consumed'; -}; - - -/** - * handle controller event and apply it on items that are in secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @return {string} - event consumed - */ -List2Ctrl.prototype._handleControllerEventSecondary = function(eventID) -{ - // get the index - var focussedIndex = this._getFocussedIndex(); - - // handle event - switch (eventID) - { - case "up" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus up - this._showFocus('up'); - - // we need to go back to the beginning in order to scroll up - if (focussedIndex < this._topItem) - { - this._scrollUpOne(); - } - break; - - - case "down" : - // leave secondary multicontroller mode - this._setSecondaryMulticontroller(false); - if (!this._isLock(focussedIndex)) - { - // trigger focus only on non-lock items - this._triggerFocus(); - } - else - { - // remove focus from lock buttons - this._lockShowFocus(focussedIndex, 'clear'); - } - - // move the focus down - this._showFocus('down'); - - // we need to go to the end in order to scroll down - if (focussedIndex >= this._topItem + this.properties.visibleItems) - { - this._scrollDownOne(); - } - break; - - case "leftStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('leftStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepDown(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "left" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('left'); - } - break; - - case "ccw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepDown(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusLeft(focussedIndex); - } - - break; - - case "rightStart" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass event to slider - this._activeSlider.slider.handleControllerEvent('rightStart'); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepUp(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "right" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent('right'); - } - - break; - - case "cw" : - - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // pass the event down to the slider - this._activeSlider.slider.handleControllerEvent(eventID); - } - else if (this._isStep(focussedIndex)) - { - // change the value and fire selectCallback informing the app of the change - var newValue = this._stepUp(focussedIndex); - // do not fire select if value is the same - if (null != newValue) - { - this._itemSelect(focussedIndex, {value:newValue, finalAdjustment:false}); - } - } - else if (this._isLock(focussedIndex)) - { - // move the focus - this._lockMoveFocusRight(focussedIndex); - } - - break; - - case "select": - // leave secondary multicontroller mode and trigger focus - this._setSecondaryMulticontroller(false); - this._showFocus(this._lastItemWithFocus); - this._triggerFocus(); - break; - } - - // the secondary multicontroller events are always consumed - return "consumed"; -}; - -/** - * Set secondary multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {string} - multicontroller event - * @param {integer} - focussed index - * @return {void} - */ -List2Ctrl.prototype._setSecondaryMulticontroller = function(state, focussedIndex) -{ - // get focussed index - if (isNaN(focussedIndex)) - { - var focussedIndex = this._getFocussedIndex(); - } - - // do not set secondary multicontroller to true if the item is disabled - if (state && this.dataList.items[focussedIndex].disabled) - { - return; - } - - if (state) - { - // flag as we are in secondary multicontroller mode - this._inSecondaryMulticontroller = true; - - // add secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.add('secondaryFocus'); - } - - /** - * Fire select callback to notify apps that we are - * entering into secondary multicontroller mode. - * In most cases apps will ignore this event. - * Transition focus to subcontrols. - */ - if (this._isSlider(focussedIndex)) - { - // the target is a slider and can be adjusted -> set currently active slider - this._activeSlider = { - itemIndex : focussedIndex, // currently active slider index - slider : this._getSlider(focussedIndex) // currently active slider instance - }; - - // transition focus - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - - // fire select callback for app notification - this._itemSelect(focussedIndex); - } - - /** - * Place focus highlight on the lock inline button - * if the target is a lock item - */ - if (this._isLock(focussedIndex)) - { - this._lockShowFocus(focussedIndex, 1); - } - - this._currentSecondaryMulticontrollerItem = focussedIndex; - } - else - { - this._inSecondaryMulticontroller = false; - - // remove secondary focus class - var domItem = this._getDOMItem(focussedIndex); - if (domItem) - { - domItem.classList.remove('secondaryFocus'); - } - - /** - * Transition focus from subcontrols. - */ - if (this._isSlider(focussedIndex) && this._activeSlider) - { - // transition focus - this._activeSlider.slider.handleControllerEvent('lostFocus'); - } - - this._currentSecondaryMulticontrollerItem = null; - } - -}; - -/** - * Set letter index multicontroller mode - * TAG: multicontroller-only, internal - * ========================= - * @param {boolean} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexMulticontroller = function(state, isTouch) -{ - if (state) - { - // hide focus from the main list and show it in the letter index - this._hideFocus(); - this._showFocusLetterIndex(this._getCurrentLetterIndex()); - this._inLetterIndexMulticontroller = true; - } - else - { - // hide focus from the letter index and show it in the main list - if (!isTouch) - { - this._showFocus(this._lastItemWithFocus); - } - this._inLetterIndexMulticontroller = false; - this._hideFocusLetterIndex(); - - // clear any scheduled letter index select - this._scheduleLetterIndexSelect(null, true); - } - -}; - -/** - * Manage focus highlight - * This is the single point for managing focus when requested from outside List2. - * (focusedItem setter, restoreContext) Manages reorder and focus as required. - * TAG: internal - * ========================= - * @param {number} - item index - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._manageFocus = function(item) -{ - if (this._inListReorder && !isNaN(item)) - { - this._reorderToIndex(item); - } - return this._showFocus(item); -} - -/** - * Show focus highlight - * This is the single point for showing the - * focus highlight - * TAG: internal - * ========================= - * @param {strig | number} - direction (up|down) or item index - * @param {boolean} - simulation mode: use to perform check on where the focus will end - * @return {integer} - the new focussed index - */ -List2Ctrl.prototype._showFocus = function(item, allowOffscreen, simulationMode, abortMode) -{ - log.debug("List2: _showFocus item, allowOffscreen, simulationMode, abortMode ", item, allowOffscreen, simulationMode, abortMode); - if (!this._hasFocus) - { - return; - } - - if (this._inputMode != 'controller') - { - // do not show the focus if the input mode is other than 'controller' - return; - } - - // exit if we don't have any items (nothing to show the focus) - if (!this.hasDataList()) - { - return; - } - - // do not show focus when in list reorder by touch - if (this._reorderTouchElt) - { - return; - } - - var abortMode = (true === abortMode); - - // do not change focussed index when we are in loading and no scrolling is allowed during that time - if (!this.properties.scrollingDuringLoading && this._inLoading && !abortMode) - { - return; - } - - var simulationMode = (true === simulationMode); - - // get the last focussed index (real and relative) - var lastFocussedIndex = this._getFocussedIndex(); - var lastRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // if we don't have previous focus, select the topmost - if (lastFocussedIndex == null) - { - lastFocussedIndex = this._topItem; - } - - // hide the focus only in real mode - if (!simulationMode) - { - this._hideFocus(); - } - - - var nextFocussedIndex = -1; - var useTransition = true; - var useRelativeIndeces = true; - - // find the next focussed element index - // NOTE: 'down' and 'up' are ued primarily when focussing with multicontroller - switch (item) - { - case 'down' : - // 'down' uses relative positioning - // the next one but not exceeding the visible items - - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.min(lastFocussedIndex+1, this.dataList.itemCount-1); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex >= this.dataList.itemCount-1) { - // we have reached the end of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the next one - nextRealFocussedIndex++; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.min(lastRelativeFocussedIndex+1, this.properties.visibleItems-1); - } - break; - - case 'up' : - // 'up' uses relative positioning - // the previous one but not lower than the first one - if (!simulationMode) - { - var nextRealFocussedIndex = this.m.max(lastFocussedIndex-1, 0); - while(this.dataList.items[nextRealFocussedIndex].disabled) - { - if (nextRealFocussedIndex <= 0) { - // we have reached the beginning of the list and nothing is found -> exit with current index - nextRealFocussedIndex = lastFocussedIndex; - break; - } - // hmmm, not enabled -> try the previous one - nextRealFocussedIndex--; - } - // convert it to relative index - nextFocussedIndex = this._realToRelativeIndex(nextRealFocussedIndex); - } - else - { - nextFocussedIndex = this.m.max(lastRelativeFocussedIndex-1, 0); - } - break; - - default : - // move highlight instantly when jumping to an item - useTransition = false; - // absolute indeces use real positioning - useRelativeIndeces = false; - - if (!isNaN(item)) - { - // specific one -> make sure it is within the list bounds - nextFocussedIndex = this.m.max(this.m.min(item, this.dataList.itemCount-1), 0); - } - else - { - // the top one - nextFocussedIndex = this._topItem; - } - } - - // if we are in simulation -> return the would-be focussed index - if (simulationMode) - { - return nextFocussedIndex; - } - - // From here on, perform actual focus change - // ----------------------------------------- - var pos = 0; - if (useRelativeIndeces) - { - // convert relative nextFocussedIndex to position - pos = nextFocussedIndex * this.properties.itemHeight; - // convert nextFocussedIndex back to real one - nextFocussedIndex = this._relativeToRealIndex(nextFocussedIndex); - } - else - { - // are we allowed to focus off screen? - if (!allowOffscreen) - { - // check if focus is outside the screen and scroll the list so that it is inside - if (this._realToRelativeIndex(nextFocussedIndex) < 0) - { - // scrollt up - this._scrollTo(nextFocussedIndex, 0); - } - else if (this._realToRelativeIndex(nextFocussedIndex) > this.properties.visibleItems - 2) - { - // scroll down - this._scrollTo((nextFocussedIndex + 2) - this.properties.visibleItems, 0); - } - } - - // convert absolute nextFocussedIndex to position - pos = (nextFocussedIndex - this._topItem) * this.properties.itemHeight; - } - - - - - // find the new focussed element - var focussedElement = this._getDOMItem(nextFocussedIndex); - - - // do we have a focussed element? - if (focussedElement) - { - focussedElement.classList.add('focus'); - - // create first focus animation - if (this._showFocusAnimation) - { - this._showFocusAnimation = false; - this.firstFocusAnimationEndCallback = this._firstFocusAnimationEndCallback.bind(this); - focussedElement.addEventListener("animationend", this.firstFocusAnimationEndCallback, false); - focussedElement.classList.add('firstFocus'); - } - } - - // set letter index position - this._setLetterIndexPosition(nextFocussedIndex); - - // store focussed item - this._lastItemWithFocus = nextFocussedIndex; - - return nextFocussedIndex; -}; - -/** - * First focus animation end callback that is fired - * when the first focus animation finishes. - * It removes the firstFocus class from the event's target - * and clears any subsequent animation callbacks - * TAG: internal - * ========================= - * @param {AnimationEvent} - * @return {void} - */ -List2Ctrl.prototype._firstFocusAnimationEndCallback = function(e) -{ - e.target.classList.remove('firstFocus'); - e.target.removeEventListener("animationend", this.firstFocusAnimationEndCallback, false); - this.firstFocusAnimationEndCallback = null; -}; - -/** - * Hide focus highlight - * This is the single point for hiding the - * focus highlight - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._hideFocus = function() -{ - // Preserve focussed element - this._lastItemWithFocus = this._getFocussedIndex(); - - for (var i=0; i disable select only if the slider is adjustable - if (this.dataList.items[focussedIndex].allowAdjust) - { - fireSelect = false; - } - - // reset currently active slider - this._activeSlider = null; - } - - if (this._isStep(focussedIndex)) - { - params = { - value : this.dataList.items[focussedIndex].value, - finalAdjustment : true, - }; - } - - /** - * Trigger the currently selected button - */ - if (this._isLock(focussedIndex)) - { - var focussedButton = this._lockGetFocus(focussedIndex); - var actionResult = this._lockActivate(focussedIndex, focussedButton); - this._lockShowFocus(focussedIndex, 'clear'); - params = { additionalData : actionResult }; - } - - // prevent select on disabled items - if (this.dataList.items[focussedIndex].disabled) - { - fireSelect = false; - } - - // everything looks ok -> call internal _itemSelect() method if the item permits it - if (fireSelect) - { - // fire select only if no long press / hold start has been issued - if (!this._longPressIssued) - { - // produce beep - this._beep('Short', 'Multicontroller'); - - this._itemSelect(focussedIndex, params); - } - // otherwise fire holdStop Callback on shortAndHold items - else if ('shortAndHold' === this.dataList.items[focussedIndex].itemBehavior) - { - this._itemHoldStop(focussedIndex); - } - } - - // lower long-press/hold-start flag - this._longPressIssued = false; - - } -}; - -/** - * Check whether the list can gain focus. In certain cases focus cannot be - * shown (e.g. when there are no items available) or if it can gain it - * it should be restored on the nearest available item if the one that - * previously had focus is disabled. - * TAG: internal - * ========================= - * @param {MouseEvent|Number} - optional argument. If passed a check will be performed whether the target item is disabled - * @return {integer} - the item that will have focus. If no item can have focus, return -1 - */ -List2Ctrl.prototype._canGainFocus = function(e) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return -1; - } - - var itemToGainFocus = -1; - - // check if we are touching the element - if (typeof e === 'object') - { - var targetItem = this._getTargetItem(e); - - // the item is enabled and can gain focus - if (-1 !== targetItem && !this.dataList.items[targetItem].disabled) - { - itemToGainFocus = targetItem; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(targetItem); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - else if (typeof e === 'number') - { - if (-1 !== e && !this.dataList.items[e].disabled) - { - itemToGainFocus = e; - } - // the item is disabled -> find the closest enabled to it - else - { - var nearestItem = this._getNearestEnabledItem(e); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - } - } - // check whether this is called from the controllerActive event handler - else if ('controllerActive' === e && this.properties.focussedItem > 0 && this.dataList.items[this.properties.focussedItem] && !this.dataList.items[this.properties.focussedItem].disabled) - { - itemToGainFocus = this.properties.focussedItem; - } - // check if last item with focus is disabled - else if (this.dataList.items[this._lastItemWithFocus] && !this.dataList.items[this._lastItemWithFocus].disabled) - { - itemToGainFocus = this._lastItemWithFocus; - } - else - { - // show focus on the closest available item to the last with focus - var nearestItem = this._getNearestEnabledItem(this._lastItemWithFocus); - itemToGainFocus = (null != nearestItem) ? nearestItem : -1; - - // if we have tabs and no enabled items, always show focus on the first line allowing tabs navigation - if (this.tabsCtrl && -1 === itemToGainFocus) - { - itemToGainFocus = this._topItem; - } - } - - return itemToGainFocus; -}; - -/** - * Get focussed index - * TAG: internal, helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getFocussedIndex = function() -{ - var focussedIndex = this._lastItemWithFocus; - - for (var i=0; i - */ -List2Ctrl.prototype._getFocussedElement = function() -{ - var focussedElement = null; - var focussedIndex = this._getFocussedIndex(); - for (var i=0; i= this.dataList.itemCount) - { - currentItem = null; - } - else - { - while (this.dataList.items[currentItem].disabled) - { - if (currentItem >= this.dataList.itemCount-1 || currentItem <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentItem = null; - break; - } - currentItem = ('down' === direction) ? currentItem+1 : currentItem-1; - } - } - return currentItem; -}; - -/** - * Get nearest enabled item in all directions - * If there are two enabled items in both directions that are - * at equal distances from the reference item, the one below is - * returned. - * TAG: internal, helper - * ========================= - * @param {integer} - from which item to search - * @return {integer} - the next enabled item. - * If nothing is found, return Null - */ -List2Ctrl.prototype._getNearestEnabledItem = function(fromItem) -{ - var nearestEnabledItem = null; - - var nearestDown = this._getNearestEnabledItemByDirection(fromItem, 'down'); - var nearestUp = this._getNearestEnabledItemByDirection(fromItem, 'up'); - - if (null === nearestDown === nearestUp) - { - // no enabled item is found - nearestEnabledItem = null; - } - else if (null === nearestDown) - { - // nothing is found below -> return the one above - nearestEnabledItem = nearestUp; - } - else if (null === nearestUp) - { - // nothing is found above -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - var differenceDown = this.m.abs(fromItem - nearestDown); - var differenceUp = this.m.abs(fromItem - nearestUp); - if (differenceDown === differenceUp) - { - // equally spaced -> return the one below - nearestEnabledItem = nearestDown; - } - else - { - // differently spaced -> return the closer one - nearestEnabledItem = (differenceDown < differenceUp) ? nearestDown : nearestUp; - } - } - - return nearestEnabledItem; -}; - -/** - * Get secondary select status of an item - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {boolean} - whether the item has secondary multicontroller - */ -List2Ctrl.prototype._hasSecondaryMulticontroller = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var hasSecondaryMulticontroller = false; - - var type = this.dataList.items[itemIndex].itemStyle; - for (var i=0; i return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+this.properties.visibleItems-2, 'down'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi + 2 - this.properties.visibleItems; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll up by one element - * If the element that will be placed at the top - * position is disabled, the list will be scrolled to - * the nearest available enabled item - * TAG: internal - * ========================= - * @return {integer} - new position of the scroller in px - */ -List2Ctrl.prototype._scrollUpOne = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topItem === 0) - { - // we can't scroll up any more -> return current position - newPos = this.scroller.offsetTop; - } - else - { - var bi = this._getNearestEnabledItemByDirection(this._topItem+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopItem = bi - 1; - newPos = -newTopItem * this.properties.itemHeight; - newPos = this.m.min(newPos, 0); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - } - else - { - newPos = this.scroller.offsetTop; - } - } - - // set scroll nature - this._scrollNature = 'item'; - - // return the new position - return newPos; -}; - -/** - * Scroll down by one page (screen) - * TAG: internal - * ========================= - * @return {string} - paged | atlimit | onepage - */ -List2Ctrl.prototype._scrollDownPage = function() -{ - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = 'onepage'; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the bottom - case 'bottom' : - // place focus on the last available item - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'up'); - if (null != nei && nei >= this._topItem) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the bottom - case 'bottomclose' : - // search for enabled item in the bottom screen - var nei = this._getNearestEnabledItemByDirection(this.dataList.itemCount - 1, 'up'); - if (null != nei && nei >= this.dataList.itemCount - this.properties.visibleItems) - { - // place focus on the last available item and scroll to the bottom - this._showFocus(nei); - this._scrollTo(this.dataList.itemCount - this.properties.visibleItems); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.min(this._topItem + this.properties.visibleItems + currentRelativeFocussedIndex, this.dataList.itemCount-1); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem + this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.max(newPos, this._maxScrollY); // constrain it to the max scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future top item down - var nei = this._getNearestEnabledItemByDirection(this._topItem + this.properties.visibleItems, 'down'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atLimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll up by one page (screen) - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollUpPage = function() -{ - - // get list position - var listPosition = this._getListPosition(); - - // set return status - var returnStatus = ''; - - // determine behavior by the list position - switch (listPosition) - { - // we have only one page - case 'onepage' : - returnStatus = 'onePage'; - break; - - // we are ate the top - case 'top' : - // place focus on the first available item - var nei = this._getNearestEnabledItemByDirection(-1, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - this._showFocus(nei); - } - - // set return status - returnStatus = 'atLimit'; - break; - - // we are close to the top - case 'topclose' : - // search for enabled item in the top screen - var nei = this._getNearestEnabledItemByDirection(0, 'down'); - if (null != nei && nei <= this.properties.visibleItems-1) - { - // place focus on the last available item and scroll to the top - this._showFocus(nei); - this._scrollTo(0); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // set return status - returnStatus = 'atLimit'; - } - break; - - // we are somewhere else - default : - // get current relative focussed index - var currentRelativeFocussedIndex = this._getRelativeFocussedIndex(); - - // get future absolute focussed index - var futureAbsoluteFocussedIndex = this.m.max(this._topItem - this.properties.visibleItems + currentRelativeFocussedIndex, 0); - - // check whether the future absolute focussed index is enabled - if (!this.dataList.items[futureAbsoluteFocussedIndex].disabled) - { - // item is enabled -> we can page down - var newPos = -(this._topItem - this.properties.visibleItems) * this.properties.itemHeight; // calculate new position - newPos = this.m.min(newPos, 0); // constrain it to the min scroll - this._performScroll(newPos); // do the scroll - - // place the focus on the future absolute focussed index - this._showFocus(futureAbsoluteFocussedIndex); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // item is disabled -> search for nearest enabled item from the future bottom item up - var nei = this._getNearestEnabledItemByDirection(this._topItem - this.properties.visibleItems, 'up'); - if (null != nei) - { - // we have found such item -> scroll down so it is in the same relative position - this._scrollTo(nei - currentRelativeFocussedIndex); - - // place the focus on the enabled item - this._showFocus(nei); - - // set scroll nature - this._scrollNature = 'page'; - - // set return status - returnStatus = 'paged'; - } - else - { - // no more enabled items -> set return status and do nothing - returnStatus = 'atlimit'; - } - } - break; - - } - - return returnStatus; -}; - -/** - * Scroll to the top - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollTop = function() -{ - this._performScroll(0); // do the scroll -}; - -/** - * Scroll to the bottom - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollBottom = function() -{ - this._performScroll(this._maxScrollY); // do the scroll -}; - -/** - * Do the actual scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._performScroll = function(pos, duration) -{ - - // if scrolling during loading is not allowed - if (!this.properties.scrollingDuringLoading && this._inLoading) - { - return; - } - - // if menu can be scrolled (it has enough list items) - if (this._isScrollable) - { - // make it snappy - var newPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(pos, duration); - } -}; - -/** - * Animate the scroll - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @param {duration} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateScroll = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - if (null !== this.scrollerAnimationEndCallback) - { - // remove any redundant animationEnd listeners - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scrollerAnimationEndCallback = null; - } - - // animate scroller or directly call the animation end callback if the time is 0 - this.scroller.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.scrollerAnimationEndCallback = this._scrollerAnimationEnd.bind(this); - this.scroller.addEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - this.scroller.style.top = pos + 'px'; - - this._inScroll = false; - if (time > 0) - { - this._inScroll = true; - } - - // set top item and update display - this._updateScrollIndicator(pos, time); - this._setTopListItem(pos); - this._updateRange(); -}; - -/** - * Abort any ongoing scroll and reset any flags - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._abortScroll = function(e) -{ - // aborting scroll is possible only while the list is scrolling - if (false === this._inScroll) - { - return; - } - - // get target item - var targetItem = this._getTargetItem(e); - - // check if target item is enabled - if (this.dataList.items[targetItem] && !this.dataList.items[targetItem].disabled) - { - // show focus there - this._showFocus(targetItem, true, false, true); - } - else - { - // restore focus - this._restoreFocus(); - } - - // get current snapped position - var snapPos = this._getSnapPosition(this.scroller.offsetTop); - this._animateScroll(snapPos, 0); - - // reset any touch flags - this._inDrag = false; - this._inScroll = false; - this._scrollNature = null; - this._inHorizontalDrag = null; - this._hDragItem = null; - this._stopSelect = false; - this._startTime = 0; - this._startItem = null; - this._startDOMItem = null; - this._activeSlider = null; - this._startY = 0; - this._startX = 0; -}; - - -/** 2. LIST SNAPPING **/ - -/** - * Get snap position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getSnapPosition = function(pos) -{ - return this.properties.itemHeight * (Math.round(pos / this.properties.itemHeight)); -}; - -/** - * Get snap (above) position depending on the new scroller position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {integer} - position snapped to the nearest above item edge - */ -List2Ctrl.prototype._getSnapPositionAbove = function(pos) -{ - return this.properties.itemHeight * (Math.floor(pos / this.properties.itemHeight)); -}; - -/** - * Scroll list to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the scroller in px. - * @return {void} - */ -List2Ctrl.prototype._snap = function(pos) -{ - // the snap position is the same as the current - if (pos == this._y) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - return; - } - else if (pos === this._minScrollY) - { - // set top item and bring focus on the screen - this._setTopListItem(pos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex > this._topItem + this.properties.visibleItems - 1) - { - this._restoreFocus(); - } - return; - } - - var snapPos = this._getSnapPosition(pos); - - // start animation - this._animateScroll(snapPos); -}; - -/** 3. LIST SWIPING AND PHYSICS **/ - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipe = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._y, this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0, 0); - - /* ANIMATE THE SCROLLER */ - var newPos = this.m.min(this.m.max(this._y + momentumY.dist, this._maxScrollY), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.scroller.offsetTop) // only if newPos is a number and the list is worth scrolling - { - this._animateScroll(newPos, swipeDuration); - } - else - { - // set top item and bring focus on the screen - this._setTopListItem(newPos); - var focussedIndex = this._getFocussedIndex(); - if (focussedIndex < this._topItem) - { - this._restoreFocus(); - } - } -}; - -/** - * Perform swipe based on physics definition - * TAG: touch-only, internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._startSwipeIndex = function(distance, time) -{ - // physics calculations - var momentumY = this._momentum(distance, time, -this._yIndex, this._maxScrollYIndex < 0 ? this._scrollerHIndex - this._maskH + this._yIndex - this._minScrollYIndex : 0, 0); - - /* ANIMATE THE LETTER INDEX SCROLLER */ - var newPos = this.m.min(this.m.max(this._yIndex + momentumY.dist, this._maxScrollYIndex), 0); - var swipeDuration = momentumY.time; - - // make it snappy - newPos = this._getIndexSnapPosition(newPos); - - // start animation - if (!isNaN(newPos) && newPos !== this.letterIndex.offsetTop) // only if newPos is a number and the letter index is worth scrolling - { - // start animation - this._animateLetterIndex(newPos, swipeDuration); - } - else - { - // set top letter index and bring focus on the screen - this._setTopLetterIndex(newPos); - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (focussedLetterIndex < this._topLetterIndex) - { - this._showFocusLetterIndex(this._topLetterIndex); - } - } -}; - -/** - * @param {integer} - dragged distance - * @param {time} - time dragged - * @param {integer} - this._y - * @param {integer} - this._maxScrollY < 0 ? this._scrollerH - this._maskH + this._y - this._minScrollY : 0 - * @param {integer} - 0 - */ -List2Ctrl.prototype._momentum = function (dist, time, maxDistUpper, maxDistLower, size) -{ - var deceleration = this.properties.deceleration, - speed = this.m.abs(dist) / time, - newDist = (speed * speed) / (2 * deceleration), - newTime = 0, outsideDist = 0; - - // Proportinally reduce speed if we are outside of the boundaries - if (dist > 0 && newDist > maxDistUpper) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistUpper = maxDistUpper + outsideDist; - speed = speed * maxDistUpper / newDist; - newDist = maxDistUpper; - } else if (dist < 0 && newDist > maxDistLower) { - outsideDist = size / (6 / (newDist / speed * deceleration)); - maxDistLower = maxDistLower + outsideDist; - speed = speed * maxDistLower / newDist; - newDist = maxDistLower; - } - - newDist = newDist * (dist < 0 ? -1 : 1); - newTime = speed / deceleration; - - return { dist: newDist, time: Math.round(newTime) }; -}; - - -/** - * ========================= - * LETTER INDEX - * ========================= - */ - -/** - * Letter index select - * scrolls list to letter index - * TAG: internal - * ========================= - * @param {integer} - the new position of the scroller in element index. - * @return {void} - */ -List2Ctrl.prototype._letterIndexSelect = function(letterIndex, eventCause) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // check if if letterIndex is a valid index - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - return; - } - - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - - // set scroll nature - this._scrollNature = 'letterIndex'; - - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - - // set letter index active position - this._setLetterIndexPosition(this.letterIndexData[letterIndex].itemIndex); - - // update last item with focus so that focus gets restored in the correct place - this._lastItemWithFocus = this.letterIndexData[letterIndex].itemIndex; - - // set proper event cause - var eventCause = ('Multicontroller' != eventCause && 'Touch' != eventCause) ? null : eventCause; - // produce beep - this._beep('Short', eventCause); - - // dispatch letter select event - var eventData = { - index : letterIndex, - label : this.letterIndexData[letterIndex].label, - itemIndex : this.letterIndexData[letterIndex].itemIndex, - }; - this._listEvent(this._EVENTS.LETTER_SELECT, eventData); -}; - -/** - * Schedule letter index select after some time - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - - if (!clear) - { - // if no letter index is passed, get the currently focussed one - if (undefined === letterIndex) - { - // check whether we already have focussed letter index - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex) - { - // if yes, schedule to that one - letterIndex = focussedLetterIndex; - } - } - - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - this._letterIndexSelect(letterIndex); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; - -/** - * Schedule background letter index select after some time. - * Background select occurs without affecting the letter index - * scroll position. This is intended to be used only programatically. - * TAG: internal - * ========================= - * @param {integer} - the letter index - * @param {boolean} - clear any timeouts without scheduling a new one - * @return {void} - */ -List2Ctrl.prototype._scheduleBackgroundLetterIndexSelect = function(letterIndex, clear) -{ - // check for letter index and letter index data - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return; - } - // check for a valid letter index item - if (letterIndex < 0 || letterIndex >= this.letterIndexData.length) - { - log.warn('List2: a valid letter index expected. Letter index passed": ' + letterIndex); - return; - } - // check for disabled letter index (no valid item index) - if (this.letterIndexData[letterIndex].disabled) - { - return; - } - // clear previous timeout - clearTimeout(this._indexSelectTimeoutId); - this._indexSelectTimeoutId = null; - if (!clear) - { - // activate the new index - this._setCurrentLetterIndex(letterIndex); - // set scroll timeout - this._indexSelectTimeoutId = setTimeout(function() { - // set scroll nature - this._scrollNature = 'letterIndex'; - // all seems fine -> scroll - this._scrollTo(this.letterIndexData[letterIndex].itemIndex - 1); - }.bind(this), this.properties.letterIndexSelectTimeout); - } -}; -/** - * Animate the letter index - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @param {integer} - duration of the scrolling animation - * @return {void} - */ -List2Ctrl.prototype._animateLetterIndex = function(pos, time) -{ - if (time == undefined || time == null) - { - time = this.properties.swipeAnimationDuration; - } - - // animate letter index - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = time + 'ms'; - this.letterIndexAnimationEndCallback = this._letterIndexAnimationEnd.bind(this); - this.letterIndex.addEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndex.style.top = pos + 'px'; - - // set top letter index - this._setTopLetterIndex(pos); -}; - -/** - * Set top letter index item depending on the position - * TAG: internal - * ========================= - * @param {integer} - position in px at which the letter should be - * @return {void} - */ -List2Ctrl.prototype._setTopLetterIndex = function(pos) -{ - // pos should be number for proper topLetterIndex calculation - if (!isNaN(pos)) - { - this._prevTopLetterIndex = this._topLetterIndex; - this._topLetterIndex = -(Math.round(pos / this.properties.letterIndexHeight)); - } -}; - -/** - * Get snap position of letter index - * depending on the new letter index position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {integer} - position snapped to the nearest item edge - */ -List2Ctrl.prototype._getIndexSnapPosition = function(pos) -{ - return this.properties.letterIndexHeight * (Math.round(pos / this.properties.letterIndexHeight)); -}; - -/** - * Scroll letter index to an even snap position - * TAG: internal - * ========================= - * @param {integer} - new position of the letter index in px. - * @return {void} - */ -List2Ctrl.prototype._snapIndex = function(pos) -{ - // the snap position is the same as the current - if (pos == this._yIndex) - { - return; - } - - // the user has reached the end of the list and there will be no animation - if (pos == this._maxScrollYIndex) - { - // set top item and bring focus on the screen - this._setTopLetterIndex(pos); - var focussedIndex = this._getFocussedLetterIndex(); - if (focussedIndex < this._topLetterIndex) - { - this._restoreLetterIndexFocus(); - } - return; - } - - var snapPos = this._getIndexSnapPosition(pos); - - // start animation - this._animateLetterIndex(snapPos); -}; - -/** - * Scroll to a specific index item - * TAG: internal - * ========================= - * @param {integer | string} - letter or letter index - * @return {void} - */ -List2Ctrl.prototype._scrollToIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return false; - } - - var targetIndex = -1; - - if (!isNaN(letter)) - { - // we are going to a letter index - targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - } - else if (typeof letter === 'string'); - { - // we are searching for the letter index of the letter - for (var i=0, l=this.letterIndexData.length; i above or below the visible range - // NOTE: if the letter is within the visible range this should not get called at all - if (-1 != targetIndex && targetIndex >= this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // look below -> find closest target index so that the focus is visible and apply target index correction - targetIndex = targetIndex - this.properties.visibleLetterIndexItems + 1; - } - else if (-1 != targetIndex && targetIndex <= this._topLetterIndex) - { - // look above -> find closest target index so that the focus is visible - // correction: the taget index is the top item whereas the item in question is the second one - targetIndex--; - } - else - { - // we don't scroll if the target is visible - return; - } - - // do the scroll - var newPos = -(targetIndex) * this.properties.letterIndexHeight; // calculate new position - newPos = this.m.max(this.m.min(newPos, this._minScrollYIndex), this._maxScrollYIndex); // constrain it to scroll bounds - this._animateLetterIndex(newPos); // start animation - - -}; - -/** - * Scroll down by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollDownOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the bottom-most position - if (this._topLetterIndex === this.letterIndexData.length - this.properties.visibleLetterIndexItems) - { - // we can't scroll down any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+this.properties.visibleLetterIndexItems-2, 'down'); - // do not scroll if no enabled letters are found - if (null != bi) - { - var newTopLetter = bi + 2 - this.properties.visibleLetterIndexItems; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.max(newPos, this._maxScrollYIndex); // constrain it to the max scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Scroll up by one or more index elements - * TAG: internal - * ========================= - * @return {integer} - new position of the letter index in px - */ -List2Ctrl.prototype._scrollUpOneIndex = function() -{ - var newPos = 0; - - // check whether we are in the top-most position - if (this._topLetterIndex === 0) - { - // we can't scroll up any more -> return current position - newPos = this.letterIndex.offsetTop; - } - else - { - var bi = this._getNearestEnabledLetterByDirection(this._topLetterIndex+1, 'up'); - // do not scroll if no enabled items are found - if (null != bi) - { - var newTopLetter = bi - 1; - newPos = -newTopLetter * this.properties.letterIndexHeight; - newPos = this.m.min(newPos, this._minScrollYIndex); // constrain it to the min scroll - this._animateLetterIndex(newPos); // do the scroll - } - else - { - newPos = this.letterIndex.offsetTop; - } - } - - // return the new position - return newPos; -}; - -/** - * Set letter index position relative to the - * focussed item in the scroller - * TAG: internal - * ========================= - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype._setLetterIndexPosition = function(index) -{ - // check for letter index - if (!this.properties.hasLetterIndex || !this.letterIndexData.length) - { - return false; - } - - // get focussed item - var focussedIndex; - if (!isNaN(index)) - { - focussedIndex = index; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // get the new index - var targetIndex = -1; - for (var i=this._letterIndexDataSorted.length-1; i>=0; i--) - { - if (focussedIndex >= this._letterIndexDataSorted[i].itemIndex) - { - targetIndex = this._letterIndexDataSorted[i].publicIndex; - break; - } - } - - // show focus on target index - if (targetIndex > -1) - { - this._setCurrentLetterIndex(targetIndex); - } - - // check if letter index scrolling is needed - if (targetIndex >= this._topLetterIndex && targetIndex < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - return; - } - - // scroll to target index - if (targetIndex > -1) - { - this._scrollToIndex(targetIndex); - } -}; - -/** - * Set currently active letter index - * TAG: internal - * ========================= - * @param {integer} - letter item index - * @return {integer} - the currently active letter index - */ -List2Ctrl.prototype._setCurrentLetterIndex = function(letter) -{ - // check for letter index - if (!this.properties.hasLetterIndex) - { - return null; - } - - var targetIndex = this.m.max(this.m.min(letter, this.letterIndexData.length-1), 0); // constrain the index - - - // remove any previously active letter index - for (var i=0, l=this.letterIndexData.length; i= this.letterIndexData.length-1) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - case 'up' : - // we are searching for the previous - targetIndex = lastFocussedIndex; - while (targetIndex > 0) - { - targetIndex--; - if (-1 != this.letterIndexData[targetIndex].itemIndex) - { - break; - } - else if (targetIndex <= 0) - { - // nothing is found, return the old one - targetIndex = lastFocussedIndex; - break; - } - } - break; - - default : - // we are searching for the index of the letter - for (var i=0, l=this.letterIndexData.length; i= letterIndexCount) - { - currentLetter = null; - } - else - { - while (this.letterIndexData[currentLetter].disabled) - { - if (currentLetter >= letterIndexCount-1 || currentLetter <= 0) - { - // this is the end/beginning of the array -> nothing is found so return Null - currentLetter = null; - break; - } - currentLetter = ('down' === direction) ? currentLetter+1 : currentLetter-1; - } - } - return currentLetter; -}; - -/** - * Exit hit state of the currently hit index item - * ========================= - * @return {void} - */ -List2Ctrl.prototype._indexRemoveHit = function() -{ - for (var i=0, l=this.letterIndexData.length; i bring back reorder item - if (this._inListReorder && this._reorderTouchElt) - { - this._bringReorderItem(); - } - - // Focus adjust after animation ends - - // get list position - var listPosition = null; - if (0 === this._topItem) - listPosition = 'top'; - else if (this._topItem === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; - else - listPosition = 'middle'; - - // get scroll direction - var scrollDirection = null; - if (this._prevTopItem > this._topItem) - scrollDirection = 'up'; - else if (this._prevTopItem < this._topItem) - scrollDirection = 'down'; - else - scrollDirection = 'none'; - - // get scroll size - var scrollSize = this.m.abs(this._prevTopItem - this._topItem); - - if ('page' === this._scrollNature) - { - // do not place focus, it should have been done by the paging function - } - else if ('item' === this._scrollNature) - { - // show focus - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // check if focussed index is outside the screen and we actually have a scroll - if (scrollSize > this.properties.visibleItems-1 && !this._inLetterIndexMulticontroller) - { - // restore focus - this._restoreFocus(); - } - else if (scrollSize > 0 && !this._inLetterIndexMulticontroller) - { - // check if the focus is just slightly outside the visible range - if (this._lastItemWithFocus < this._topItem || this._lastItemWithFocus >= this._topItem + this.properties.visibleItems) - { - // restore focus - this._restoreFocus(); - } - else - { - // else the focus remains on the screen -> only set letter index position - this._setLetterIndexPosition(this._getFocussedIndex()); - } - } - else - { - // we don't have a scroll -> nothing to do here - } - } - - // lower _inScroll flag - this._inScroll = false; - - // reset scroll nature - this._scrollNature = null; - - // dispatch scroll end event - this._listEvent(this._EVENTS.SCROLL_END, {scrollPosition:this._topItem}); -}; - -/** - * Restore focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreFocus = function() -{ - // check if the top item is enabled - if (!this.dataList.items[this._topItem].disabled) - { - this._showFocus(this._topItem, false, false, true); - } - // top item is disabled, find the nearest enabled item below the top one - else - { - var neiDown = this._getNearestEnabledItem(this._topItem, 'down'); - // check if the item is on screen - if (null != neiDown && neiDown >= this._topItem && neiDown < this._topItem + this.properties.visibleItems) - { - this._showFocus(neiDown, true, false, true); - } - // there's no enabled item or it is off screen - else - { - this._showFocus(this._topItem, false, false, true); - } - } -}; - -/** - * Scroll indicator animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._scrollIndicatorAnimationEnd = function() -{ - this.scrollIndicator.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - this.scrollIndicatorAnimationEndCallback = null; - - // fadeOut scroll indicator - this._fadeOutScrollIndicator(); -}; - -/** - * Letter index animation end callback - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._letterIndexAnimationEnd = function() -{ - // remove animation end callbacks - this.letterIndex.style[this._VENDOR + 'TransitionDuration'] = '0ms'; - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - this.letterIndexAnimationEndCallback = null; - - // restore focus - var focussedLetterIndex = this._getFocussedLetterIndex(); - if (null != focussedLetterIndex && (focussedLetterIndex < this._topLetterIndex || focussedLetterIndex > this._topLetterIndex + this.properties.visibleLetterIndexItems - 1)) - { - // focus is off screen - this._restoreLetterIndexFocus(); - } - else if (null != focussedLetterIndex) - { - // schedule letter index select if letter is enabled - if (!this.letterIndexData[focussedLetterIndex].disabled) - { - this._scheduleLetterIndexSelect(focussedLetterIndex); - } - } -}; - -/** - * Restore letter index focus after it has been left off screen. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._restoreLetterIndexFocus = function() -{ - // check if the top letter index is enabled - if (!this.letterIndexData[this._topLetterIndex].disabled) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule letter index select - this._scheduleLetterIndexSelect(this._topLetterIndex); - } - else - { - // look for enabled item down and up - var neiDown = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'down'); - var neiUp = this._getNearestEnabledLetterByDirection(this._topLetterIndex, 'up'); - // determine scroll direction - var scrollDirection = (this._topLetterIndex - this._prevTopLetterIndex < 0) ? 'up' : 'down'; - - // check whether we have an enabled item on screen - if (null != neiDown && neiDown >= this._topLetterIndex && neiDown < this._topLetterIndex + this.properties.visibleLetterIndexItems) - { - // there is an enabled item on screen -> place the focus there - this._showFocusLetterIndex(neiDown); - // schedule letter index select - this._scheduleLetterIndexSelect(neiDown); - } - else if ('down' === scrollDirection) - { - // we are scrolling down -> look for enabled item up - if (null != neiUp) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiUp); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - else if ('up' === scrollDirection) - { - // we are scrolling up -> look for enabled item down - if (null != neiDown) - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - // schedule background letter index select - this._scheduleBackgroundLetterIndexSelect(neiDown); - } - else - { - // show focus on the top letter - this._showFocusLetterIndex(this._topLetterIndex); - } - } - } -}; - - -/** - * ========================= - * SLIDERS AND TOGGLE CONTROL - * ========================= - */ - -/** - * Passes START (mousedown) event to the currently - * targeted slider instance and returns it. - * TAG: internal - * ========================= - * @param {MouseEvent} - * @param {Boolean} - * @return {SliderCtrl} - */ -List2Ctrl.prototype._slideStart = function(e, skipActiveSlider) -{ - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // check if slider can be adjusted - if (!this.dataList.items[itemIndex].allowAdjust) - { - return; - } - - // check if we are in the hittable area - if(!this._hasRightHittableArea(this.dataList.items[itemIndex])) - { - var relativeX = e.pageX - this._maskPositionX; - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight; - var leftBoundary = this.properties.sliderReferencePointRight - this.properties.sliderWidth; - } - else if(this.dataList.items[itemIndex].indented) - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)) + (this.properties.indentOffset * 2); - var leftBoundary = this.properties.sliderReferencePointLeft; - } else - { - var relativeX = e.pageX - (Math.ceil(this._maskPositionX / 1.5)); - var inHittable = false; - var rightBoundary = this.properties.sliderReferencePointRight - (Math.ceil(this.properties.sliderWidth / 1.5)); - var leftBoundary = this.properties.sliderReferencePointLeft; - } - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> exit - return; - } - - var sliderInstance = this._getSlider(itemIndex); - var skipActiveSlider = (true === skipActiveSlider); - if (!skipActiveSlider) - { - // set currently active slider - this._activeSlider = { - itemIndex : itemIndex, // currently active slider index - slider : sliderInstance // currently active slider instance - }; - - // transition focus to slider and hide focus on the item - this._activeSlider.slider.handleControllerEvent('acceptFocusFromTop'); - this._hideFocus(); - - // pass the event to the SliderCtrl - this._activeSlider.slider._onDownHandler(e); - } - - return sliderInstance; -}; - -List2Ctrl.prototype._slideMove = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - return; - } - - // determine target item - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - // pass the event to the SliderCtrl - this._activeSlider.slider._onMoveHandler(e); -}; - -List2Ctrl.prototype._slideEnd = function(e) -{ - // determine if we have an active slider - if (!this._activeSlider) - { - var sliderInstance = this._slideStart(e, true); - if (sliderInstance && !this._stopSelect) - { - // pass the event to the SliderCtrl - sliderInstance._onDownHandler(e); - sliderInstance._onUpHandler(e); - } - return; - } - else - { - var itemIndex = this._activeSlider.itemIndex; - - // do not slide disabled items - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // determine if sliding is reasonable for the target item (i.e. the item is 'slidable') - if (!this._isSlider(itemIndex)) - { - // this is not a slider -> exit - return; - } - - if (this._inSecondaryMulticontroller && itemIndex == this._currentSecondaryMulticontrollerItem) - { - // if we are in secondary multicontroller mode, touching outside the item will exit it - this._setSecondaryMulticontroller(false, this._currentSecondaryMulticontrollerItem); - this._showFocus(this._lastItemWithFocus, true); - } - else - { - // pass the event to the SliderCtrl - this._activeSlider.slider._onUpHandler(e); - - // transition focus back to item and remove it from the slider - this._activeSlider.slider.handleControllerEvent('lostFocus'); - this._showFocus(this._lastItemWithFocus, true); - } - } - - // reset currently active slider - this._activeSlider = null; -}; - -List2Ctrl.prototype._slideCallback = function() -{ - // get item index from the first argument - var itemIndex = arguments[0]; - - // get value and final adjustment from fourth argument - var value = arguments[3].value; - var finalAdjustment = arguments[3].finalAdjustment; - - // update local value - this.dataList.items[itemIndex].value = value; - - // Fire slide callback passing forward anything in the arguments - if (typeof this.properties.slideCallback == 'function') - { - // fire callback with original slider params - // this.properties.slideCallback.apply(null, Array.prototype.slice.call(arguments, 1)); - - // fire per-design callback - var params = { - itemIndex : itemIndex, - value:value, - finalAdjustment : finalAdjustment - }; - this.properties.slideCallback(this, this.dataList.items[itemIndex].appData, params); - } -}; - - - -/* - * ========================= - * TOGGLE BUTTONS - * When a button is selected it is automatically - * highlighted (activated) and the value is reported to the - * button select callback (if defined) - * ========================= - */ - - -/** - * Remove hit state from the toggle button - * TAG: touch-only, internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {void} - */ -List2Ctrl.prototype._buttonRemoveHit = function(itemIndex) -{ - var targetElt = this._getDOMItem(itemIndex); - if (targetElt) - { - var hitItems = targetElt.querySelectorAll('.hit'); - - if (hitItems.length) - { - for (var i=0, l=hitItems.length; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - // Check which button is hit - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button hit - if (buttonId) - { - // save the button as _startButton - this._startButton = buttonId; - - var domItem = this._getDOMItem(itemIndex); - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // Check if we are in the hittable area - var inHittable = false; - var rightBoundary = this.properties.toggleReferencePointRight; - var leftBoundary = 0; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : // 2 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (2 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'style11' : // 3 toggle buttons - leftBoundary = this.properties.toggleReferencePointRight - (3 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - - case 'draggable' : // 1 toggle button - leftBoundary = this.properties.toggleReferencePointRight - (1 * this.properties.toggleButtonWidth); - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - break; - } - - if (!inHittable && this._startButton) - { - // we are outside the hittable area and we have started from a button -> return cancel - return 'cancel'; - } - else if (!inHittable) - { - // we are outside the hittable area -> return cancel - return null; - } - - // Check which button is selected - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - var buttonId = null; - switch (this.dataList.items[itemIndex].itemStyle) - { - case 'style10' : - buttonId = clickedZone < 0.5 ? 1 : 2; - break; - case 'style11' : - buttonId = clickedZone < 0.33 ? 1 : - clickedZone < 0.66 ? 2 : - 3; - break; - case 'draggable' : - buttonId = 1; - break; - } - - // Make that button active - if (buttonId && buttonId === this._startButton) - { - this._startButton = null; - - if (this.dataList.items[itemIndex].value == buttonId) - { - // we ended on already selected button -> cancel - return 'cancel'; - } - // we ended up on the same button we started -> select that button - this._buttonActivate(itemIndex, buttonId); - } - else if (buttonId && null === this._startButton) - { - // we started off the buttons but ended up on a button -> select next button - this._startButton = null; - return null; - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startButton = null; - return 'cancel'; - } - - // Return the button id - return buttonId; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectLeft = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonSelectRight = function(itemIndex) -{ - // get current active button - var current = this.dataList.items[itemIndex].value; - - // set new active button - return this._buttonActivate(itemIndex, current+1); -}; - -/** - * Activate toggle button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._buttonActivate = function(itemIndex, buttonId) -{ - // Ensure that buttonId is valid and wraps in a loop - if ('style10' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 2) - buttonId = 1; - else if (buttonId < 1) - buttonId = 2; - } - else if('style11' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = (!isNaN(buttonId)) ? buttonId : 1; - if (buttonId > 3) - buttonId = 1; - else if (buttonId < 1) - buttonId = 3; - } - else if('draggable' === this.dataList.items[itemIndex].itemStyle) - { - var buttonId = 1; - } - else - { - log.debug('Unknown item style for itemIndex ' + itemIndex); - return null; - } - - if ('draggable' != this.dataList.items[itemIndex].itemStyle) - { - // Save the new value in the dataList - this.dataList.items[itemIndex].value = buttonId; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Remove any residual hit states - this._buttonRemoveHit(itemIndex); - - // Activate the button - if (domItem) - { - var buttons = domItem.querySelectorAll('.button'); - for (var i=0; i do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // we are outside the hittable area -> return false - return false; - } - - // when user hits one of the buttons, the item does not gain hit highlight - this._itemRemoveHit(); - - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // save the button as _startLockButton - this._startLockButton = buttonId; - - // remove hit - this._lockRemoveHit(itemIndex); - - // make that button hit - if (1 === buttonId) - { - this._lockShowFocus(itemIndex, 1); - domItem.querySelector('.buttonLock').classList.add('hit'); - } - else - { - this._lockShowFocus(itemIndex, 2); - domItem.querySelector('.buttonDelete').classList.add('hit'); - } - - this._hideFocus(); - - return true; - -}; - -/** - * Select lock button - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockSelect = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return null; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return null; - } - - // Check if we are in the hittable area - var inHittable = false; - var domItem = this._getDOMItem(itemIndex); - var lockButton = domItem.querySelector('.buttonLock'); - var deleteButton = domItem.querySelector('.buttonDelete'); - var leftBoundary = lockButton.offsetLeft; - var rightBoundary; - if (this.dataList.items[itemIndex].locked) - { - // the delete button is disabled - rightBoundary = lockButton.offsetLeft + lockButton.clientWidth; - } - else - { - // the delete button is enabled - rightBoundary = deleteButton.offsetLeft + deleteButton.clientWidth; - } - - // hit test - if (relativeX >= leftBoundary && relativeX <= rightBoundary) - { - inHittable = true; - } - - if (!inHittable) - { - // set secondary multicontroller leaving highlight from where it started - if (this._startLockButton) - { - this._setSecondaryMulticontroller(true, itemIndex); - this._lockShowFocus(itemIndex, this._startLockButton); - } - - // we are outside the hittable area -> return null - return null; - } - - var action = null; - var buttonId = 1; - // Check which button is hit is the item is not locked - if (!this.dataList.items[itemIndex].locked) - { - var clickedZone = (relativeX - leftBoundary) / (rightBoundary - leftBoundary); - buttonId = clickedZone < 0.5 ? 1 : 2; - } - - // Make that button active - if (buttonId === this._startLockButton) - { - this._startLockButton = null; - // we ended up on the same button we started -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else if (null === this._startButton) - { - this._startLockButton = null; - // we started off the buttons but ended up on a button -> select that button - action = this._lockActivate(itemIndex, buttonId); - } - else - { - // we started from one of the buttons but ended out of them -> cancel - this._startLockButton = null; - - return null; - } - - // Return the performed action - return action; - -}; - -/** - * Select the nearest left toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusLeft = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current-1); -}; - -/** - * Select the nearest right toggle button to the currently active one - * TAG: internal - * ========================= - * @param {integer} - index of the currently focussed item - * @return {integer} - selected button id (1,2,3) - */ -List2Ctrl.prototype._lockMoveFocusRight = function(itemIndex) -{ - // get current focussed lock button - var current = this._lockGetFocus(itemIndex); - - // set the new focussed lock button - return this._lockShowFocus(itemIndex, current+1); -}; - -/** - * Activate lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the button that is going to be activated - * @return {string} - performed action (lock, unlock, delete) - */ -List2Ctrl.prototype._lockActivate = function(itemIndex, buttonId) -{ - var action = null; - - switch (buttonId) - { - case 1 : - if (this.dataList.items[itemIndex].locked) - { - this.dataList.items[itemIndex].locked = false; - action = 'unlock'; - } - else - { - this.dataList.items[itemIndex].locked = true; - action = 'lock'; - } - break; - case 2 : - if (!this.dataList.items[itemIndex].locked) - { - action = 'delete'; - } - break; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - // Update the item - if (domItem) - { - switch (action) - { - case 'lock' : - domItem.classList.add('locked'); - break; - case 'unlock' : - domItem.classList.remove('locked'); - break; - } - } - - return action; -}; - - -/** - * Show focus highlight on a lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @param {integer} - the index of the button that will be focused - * @return {integer} - id of the focussed lock button - */ -List2Ctrl.prototype._lockShowFocus = function(itemIndex, buttonId) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - - if ('clear' === buttonId) - { - if (domItem) - { - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.remove('focus'); - } - return null; - } - else - { - // validate button id - var buttonId = this.dataList.items[itemIndex].locked ? 1 : this.m.min(this.m.max(buttonId, 1), 2); - - if (domItem) - { - // add focus on the respective button - switch (buttonId) - { - case 1 : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - case 2 : - domItem.querySelector('.buttonLock').classList.remove('focus'); - domItem.querySelector('.buttonDelete').classList.add('focus'); - break; - default : - domItem.querySelector('.buttonDelete').classList.remove('focus'); - domItem.querySelector('.buttonLock').classList.add('focus'); - break; - } - } - return buttonId; - } -}; - - -/** - * Get currently focused lock button - * TAG: internal - * ========================= - * @param {integer} - index of the currently hit or focussed item - * @return {integer} - id of the currently focussed lock button - */ -List2Ctrl.prototype._lockGetFocus = function(itemIndex) -{ - // check if this is a lock item - if (!this._isLock(itemIndex)) - { - return false; - } - - // if the item is disabled -> do not make hit - if (this.dataList.items[itemIndex].disabled) - { - return false; - } - - var focussedButton = null; - - // Get the DOM element - var domItem = this._getDOMItem(itemIndex); - if (domItem) - { - if (domItem.querySelector('.buttonLock').classList.contains('focus')) - focussedButton = 1; - else if (domItem.querySelector('.buttonDelete').classList.contains('focus')) - focussedButton = 2; - } - - return focussedButton; -}; - - -/* - * ========================= - * STEP ITEM - * ========================= - */ - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {MouseEvent} - raw mouse event - * @return {integer} - the new value - */ -List2Ctrl.prototype._stepAdjust = function(e) -{ - // get relative mouse position - var relativeX = e.pageX - this._maskPositionX; - - // determine target item - var itemIndex = this._getTargetItem(e); - - // only valid list items are allowed - if (itemIndex == -1) - { - return; - } - - // if the item is disabled -> do not make active - if (this.dataList.items[itemIndex].disabled) - { - return; - } - - // perform hit test - var itemDOMElement = this._getDOMItem(itemIndex); - if (!itemDOMElement) - { - return; - } - - var p = itemDOMElement.querySelector('.plus'); - var m = itemDOMElement.querySelector('.minus'); - var pLayout = { x1:p.offsetLeft, x2:p.offsetLeft + p.clientWidth }; - var mLayout = { x1:m.offsetLeft, x2:m.offsetLeft + m.clientWidth }; - - var newValue = null; - - if (relativeX >= pLayout.x1 && relativeX <= pLayout.x2) - { - // plus pressed - newValue = this._stepUp(itemIndex); - } - else if (relativeX >= mLayout.x1 && relativeX <= mLayout.x2) - { - // minus pressed - newValue = this._stepDown(itemIndex); - } - else if (relativeX < mLayout.x1) - { - newValue = 'commit'; - } - - - return newValue; -}; - -/** - * Increase the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepUp = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.min(this.dataList.items[itemIndex].value + this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].max); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - -/** - * Decrease the value by one step - * TAG: internal - * ========================= - * @param {integer} - index of the step item - * @return {integer|null} - the new value - */ -List2Ctrl.prototype._stepDown = function(itemIndex) -{ - if (!this._isStep(itemIndex)) - { - return; - } - - var oldValue = this.dataList.items[itemIndex].value; - var newValue = this.m.max(this.dataList.items[itemIndex].value - this.dataList.items[itemIndex].increment, this.dataList.items[itemIndex].min); - - if (newValue != oldValue) - { - // value changed -> store it and update item - this.dataList.items[itemIndex].value = newValue; - this.updateItems(itemIndex, itemIndex); - } - else - { - // value is the same -> return null - newValue = null; - } - - return newValue; -}; - - -/** - * ========================= - * LIST REORDERING - * ========================= - */ - -/** - * Enter into list reorder mode - * This method stores the original item style of the - * item that is being reordered and substitutes it with - * an internal 'draggable' item style. - * TAG: internal - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype._enterListReorder = function(fromInit) -{ - // keep a copy of the item before converting it to a draggable item - - var focussedIndex; - if (fromInit) - { - focussedIndex = this.properties.focussedItem; - } - else - { - focussedIndex = this._getFocussedIndex(); - } - - // check for items in the dataList - if (!this.dataList || !this.dataList.items || !this.dataList.items[focussedIndex]) - { - return; - } - - // do not reorder disabled items - if (this.dataList.items[focussedIndex].disabled) - { - return; - } - - // enter into List Reordering mode - this._inListReorder = true; - - this.dataList.items[focussedIndex].itemBehavior = 'shortAndLong'; // make it accept long press (if not already) - this._reorderItem = this.dataList.items[focussedIndex]; - this._reorderItemIndex = focussedIndex; - this._reorderCurrentIndex = focussedIndex; - - // convert the item to a draggable item - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[focussedIndex] = draggableItem; - this.updateItems(focussedIndex, focussedIndex); - -}; - -/** - * Leave list reorder mode - * The item that is being reordered is restored - * to it initial style. The select callback is - * then fired to notify the interested parties of - * the change and the new position of the item. - * TAG: internal - * ========================= - * @param {Boolean} - prevent item selection when releasing the reorder - * @return {void} - */ -List2Ctrl.prototype._releaseListReorder = function(preventSelect) -{ - // exit list reordering mode - this._inListReorder = false; - - // get draggable item index - var draggableItems = this.getItemsByType('draggable'); - if (!draggableItems.length) - { - return; - } - - var draggableItemIndex = draggableItems[0]; - - // convert the draggable item back into the previous item type - this.dataList.items[draggableItemIndex] = this._reorderItem; - this.updateItems(draggableItemIndex, draggableItemIndex); - - // cast preventSelect as Boolean - var preventSelect = Boolean(preventSelect); - - // selection is allowed - if (!preventSelect) - { - // fire item select - var params = { - newIndex : draggableItemIndex, - oldIndex : this._reorderItemIndex - }; - this._itemSelect(draggableItemIndex, params); - } - - // release the copy of the reorder item - this._reorderItem = null; - this._reorderItemIndex = null; - this._reorderTouchElt = null; - -}; - - -/** - * Touch start reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._startReorder = function(e) -{ - // get target item index - var itemIndex = this._getTargetItem(e); - - // get draggable item index - if (itemIndex === this._reorderCurrentIndex) - { - this._startY = e.pageY - this._maskPositionY; - this._startX = e.pageX - this._maskPositionX; - - // do we have hit on the button? - var positiveButtonHit = this._buttonMakeHit(e); - - if (!positiveButtonHit) - { - this._itemMakeLongPress(e); - - // clone draggable item - var tmp = this._getDOMItem(itemIndex); - this._reorderTouchElt = tmp.cloneNode(true); - this.scroller.appendChild(this._reorderTouchElt); - - // convert the draggable item to a ghost item - var ghostItem = {itemStyle:'ghost', hasCaret:false}; - this.dataList.items[itemIndex] = ghostItem; - this.updateItems(itemIndex, itemIndex); - - this._hideFocus(); - - // raise _inDrag - this._inDrag = true; - } - else - { - // flag the behaviour as release intent - this._releaseReorderByTouch = true; - } - - // track event - this._trackEvent(e); - } -}; - -/** - * Touch move reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._moveReorder = function(e) -{ - if (this._reorderTouchElt) - { - // track event - this._trackEvent(e); - - // perform event filtering - if (this.properties.eventFilterThreshold > 0) - { - // skip event - if (e.timeStamp-this._lastEventTime <= this.properties.eventFilterThreshold) - { - return; - } - - // record time - this._lastEventTime = e.timeStamp; - } - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // get last move - var moveDirection = this._getMoveDirection(); - - // reset any scheduled scrolling if the user intends cacnelling the scroll - if (newPos <= (this._topItem * this.properties.itemHeight) + this.properties.itemHeight && - newPos > this._topItem * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - else if (newPos >= (this._topItem + this.properties.visibleItems - 2) * this.properties.itemHeight && - newPos < (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - } - - // drag down - if (1 === moveDirection) - { - // have we passed the last item's top border? - if ( (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) && (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) ) - { - this._reorderGhostItemDown(); - } - else if (newPos >= ((this._topItem + this.properties.visibleItems) * this.properties.itemHeight) - this.properties.itemHeight) - { - // do we have a scroll down scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos >= (this._reorderCurrentIndex * this.properties.itemHeight) + this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemDown(); - } - } - // drag up - else if (-1 === moveDirection) - { - // have we passed the top item's top border? - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // do we have a scroll up scheduled? -> if not, schedule one - if (null === this._touchReorderTimeoutId) - { - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - } - else if (newPos <= (this._reorderCurrentIndex * this.properties.itemHeight) - this.properties.itemHeight) - { - if (null != this._touchReorderTimeoutId) - { - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - } - this._reorderGhostItemUp(); - } - } - - } // endif (this._reorderTouchElt) -}; - -/** - * Touch end reorder item - * TAG: internal, touch-only - * ========================= - * @param {MouseEvent} - * @return {void} - */ -List2Ctrl.prototype._endReorder = function(e) -{ - if (this._reorderTouchElt) - { - // get nearest snap position - var newSnappedIndex = Math.floor( ( (e.pageY - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) ) / this.properties.itemHeight ); - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = newSnappedIndex * this.properties.itemHeight; - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the scroller if in bounds - this._reorderTouchElt.style.top = newPos + 'px'; - - // convert the ghost item back to a draggable ite m - var draggableItem = {}; - draggableItem.itemStyle = 'draggable'; - draggableItem.text1 = this._reorderItem.text1; - draggableItem.image1 = (this._reorderItem.hasOwnProperty('image1')) ? this._reorderItem.image1 : ''; - draggableItem.button1 = this._getLocalizedString('common.Ok'); - draggableItem.hasCaret = false; - this.dataList.items[this._reorderCurrentIndex] = draggableItem; - this.updateItems(this._reorderCurrentIndex, this._reorderCurrentIndex); - - // remove the cloned element - this._reorderTouchElt.parentElement.removeChild(this._reorderTouchElt); - } - - this._itemRemoveLongPress(); - this._reorderTouchElt = null; - - // reset flags - this._inHorizontalDrag = null; - this._hDragItem = null; - this._inDrag = false; - this._stopSelect = false; - - // restore focus - this._showFocus(this._reorderCurrentIndex); - - // clear any scroll timeout - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = null; - - // are we about to release reorder - if (this._releaseReorderByTouch && this._isToggle(this._reorderCurrentIndex)) - { - // remove hit state of button and release list reorder - this._buttonRemoveHit(this._reorderCurrentIndex); - this._releaseListReorder(); - this._releaseReorderByTouch = false; - } - -}; - -/** - * After the list has scrolled due to touch reorder action, - * upon animation end, the touch reorder item is brought under the - * user's finger and if the possition requires it, a new scroll - * is scheduled. - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._bringReorderItem = function() -{ - if (this._trackedEvents.length && this._reorderTouchElt) - { - // get last event - var lastEvent = this._trackedEvents[this._trackedEvents.length-1]; - - // get mouse position relative to scroller corrected with the reorder touch element position - var newPos = (lastEvent.y - this._maskPositionY) + this.m.abs(this.scroller.offsetTop) - (this.properties.itemHeight / 2); - - // constrain the new position - newPos = this.m.max(0, newPos); - - // drag the item - this._reorderTouchElt.style.top = newPos + 'px'; - - // we are past the top item's top boundary - if (0 != this._topItem && newPos <= this._topItem * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemUp(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollUpOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (0 == this._topItem) - { - // update blank spot - this._reorderGhostItemUp(); - } - else if (this._topItem != this.dataList.itemCount - this.properties.visibleItems && - newPos >= (this._topItem + this.properties.visibleItems - 1) * this.properties.itemHeight) - { - // update blank spot - this._reorderGhostItemDown(); - - // reschedule list scroll - clearTimeout(this._touchReorderTimeoutId); - this._touchReorderTimeoutId = setTimeout(this._scrollDownOne.bind(this), this.properties.listReorderScrollTimeout); - } - else if (this._topItem >= this.dataList.itemCount - this.properties.visibleItems) - { - // update blank spot - this._reorderGhostItemDown(); - } - - } -}; -/** - * Reorder the item to the index - * TAG: internal - * ========================= - * @param {integer} - item index - * @return {void} - */ -List2Ctrl.prototype._reorderToIndex = function(itemIndex) -{ - if (!this._inListReorder || isNaN(itemIndex)) - { - log.error("list1 _reorderToIndex : Invalid arguments - inListReorder, itemIndex", this._inListReorder, itemIndex); - return; - } - - if (itemIndex != this._reorderItemIndex) - { - if (itemIndex < this._reorderItemIndex) - { - this._reorderItemUp(this._reorderItemIndex - itemIndex) - } - else - { - this._reorderItemDown(itemIndex - this._reorderItemIndex) - } - } -} - -/** - * Reorder the item down - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemDown = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(draggableItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(draggableItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; -/** - * Reorder the item up - * TAG: internal - * ========================= - * @param {integer} -number of items - * @return {void} - */ -List2Ctrl.prototype._reorderItemUp = function(reorderCount) -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - //prevent list scrolling while we're loading - if (this._inLoading) - { - return; - } - - if (!reorderCount) - { - reorderCount = 1; - } - - for (var count = 1; count <= reorderCount; count++) - { - // get draggable item index - var draggableItemIndex = this.getItemsByType('draggable')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(draggableItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[draggableItemIndex]; - this.dataList.items[draggableItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, draggableItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - } - -}; - -/** - * Reorder ghost item one position down - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemDown = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.min(ghostItemIndex + 1, this.dataList.itemCount - 1); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(ghostItemIndex, targetItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - -/** - * Reorder ghost item one position up - * TAG: internal - * ========================= - * @return {void} - */ -List2Ctrl.prototype._reorderGhostItemUp = function() -{ - // ensure that we are in list reorder mode - if (!this._inListReorder) - { - return; - } - - // get draggable item index - var ghostItemIndex = this.getItemsByType('ghost')[0]; - - // get new index not exceeding the list count - var targetItemIndex = this.m.max(ghostItemIndex - 1, 0); - - // reorder the dataList.items array - var tempCopy = this.dataList.items[targetItemIndex]; - this.dataList.items[targetItemIndex] = this.dataList.items[ghostItemIndex]; - this.dataList.items[ghostItemIndex] = tempCopy; - - // update display - this.updateItems(targetItemIndex, ghostItemIndex); - - // store current temporary index - this._reorderCurrentIndex = targetItemIndex; - - this._hideFocus(); -}; - - -/** - * ========================= - * LIST EVENTS API - * ========================= - */ - -/** - * List event - * TAG: internal - * ========================= - * @param {string} - Event name - * @param {*} - Event data - * @return {void} - */ -List2Ctrl.prototype._listEvent = function(type, data) -{ - var data = data || null; - switch (type) - { - case this._EVENTS.ITEM_SELECT : - this._dispatch(this._EVENTS.ITEM_SELECT, data); - break; - case this._EVENTS.LETTER_SELECT : - this._dispatch(this._EVENTS.LETTER_SELECT, data); - break; - case this._EVENTS.DATALIST_CHANGE : - this._dispatch(this._EVENTS.DATALIST_CHANGE, null); - break; - case this._EVENTS.SCROLL_START : - this._dispatch(this._EVENTS.SCROLL_START, data); - break; - case this._EVENTS.SCROLL_END : - this._dispatch(this._EVENTS.SCROLL_END, data); - break; - case this._EVENTS.CLEAN_UP : - this._dispatch(this._EVENTS.CLEAN_UP, data); - break; - default : - // nothing to do - break; - } -}; - -/** - * Get listeners array for an event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {array} - */ -List2Ctrl.prototype._getListeners = function(type, useCapture) -{ - var captype = (useCapture ? '1' : '0') + type; - if (!(captype in this._eventListeners)) - this._eventListeners[captype] = []; - return this._eventListeners[captype]; -}; - -/** - * Dispatch custom event - * TAG: internal - * ========================= - * @param {string} - Event name - * @return {void} - */ -List2Ctrl.prototype._dispatch = function(type, data) -{ - if (!type || '' == type) - return; - var evt = new CustomEvent( type, { detail : { data : data, bubbles: true, cancelable: true } } ); - this.dispatchEvent(evt); -}; - -/** - * Add event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.addEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 === ix) - listeners.push(listener); -}; - -/** - * Remove event listener to custom list event - * TAG: public - * ========================= - * @param {string} - event name - * @param {function} - event listener - * @param {boolean} - use capture - * @return {void} - */ -List2Ctrl.prototype.removeEventListener = function(type, listener, useCapture) -{ - var listeners = this._getListeners(type, useCapture); - var ix = listeners.indexOf(listener); - if (-1 !== ix) - listeners.splice(ix, 1); -}; - -/** - * Displatch custom list event - * TAG: public - * ========================= - * @param {object} - event object - * @return {boolean} - */ -List2Ctrl.prototype.dispatchEvent = function(evt) -{ - var listeners = this._getListeners(evt.type, false).slice(); - for (var i= 0; i dataList.items.length) - { - for (var i=dataList.items.length; i= 0) - { - // force exit secondary multicontroller - this._inSecondaryMulticontroller = false; - - var additionalSpace = this._getAdditionalSpace(); - - this.scroller.style.height = this.dataList.itemCount * this.properties.itemHeight + additionalSpace + 'px'; - this._scrollerH = this.scroller.offsetHeight; - this._emptyScroller(); - this._scrollIndicatorReset(); - if(0 === this.dataList.itemCount) - { - this._scrollIndicatorBuild(false); - } - else - { - this._scrollIndicatorBuild(true); - } - - // set line numbers - this.setLineNumbers(); - } - -}; - -List2Ctrl.prototype.hasDataList = function() -{ - if (this.dataList == null) - { - return false; - } - - if (!this.dataList.hasOwnProperty('itemCountKnown') && !this.dataList.hasOwnProperty('itemCount') && !this.dataList.hasOwnProperty('items')) - { - return false; - } - - if (this.dataList.itemCountKnown && this.dataList.itemCount == 0) - { - return false; - } - - if (!this.dataList.itemCountKnown && this.dataList.itemCount <= 0) - { - return false; - } - - return true; -}; - -/** - * Update Items - * - * This is intended to be used whenever the bound data is changed programmatically by the app. In other words, - * it informs the control that bound data has changed … and if the range of changed items overlaps with items - * rendered into HTML objects, then the ListMenu must update those elements. There are several use cases for this: - * - * 1. For the case where the dataList is fetched asynchronously in the background after ListMenu is displayed, - * the updateItems() API will be called as new data arrives. I think this use case is described fairly completely - * in section 2.2.4 of the ListMenu SDD. Note that these updates may correspond to the user scrolling, or may simply - * occur in the background as the list is loaded into GUI while the user is still looking at the first N list items. - * Also note that the listCount can change and the ListMenu control must adapt appropriately, including handling - * reduction of the list count. - * - * 2. To allow the application to update menu text dynamically, e.g. to display the name of the connected USB - * Audio device instead of “USB”, or to change the displayed image(s). - * - * 3. To allow the application to enable/disable menu items or to set/clear the “selected” indicator. - * - * ========================= - * @param {integer} - * @param {integer} - * @return {void} - */ -List2Ctrl.prototype.updateItems = function(firstItem, lastItem) -{ - log.debug("List2 updateItems() firstItem, lastItem",firstItem, lastItem); - // update _maxScrollY - this._maxScrollY = this.mask.offsetHeight - this.scroller.offsetHeight; - - var emptyDOMItem = null; - - // clear _needDataTimeoutId - clearTimeout(this._needDataTimeoutId); - this._needDataTimeoutId = null; - - this._prepareItems(firstItem, lastItem); - this._localizeItems(firstItem, lastItem); - - // trim dataList.items if it is larger than dataList.itemCount - if (this.dataList && - this.dataList.itemCountKnown && - this.dataList.items && - this.dataList.itemCount < this.dataList.items.length) - { - this.dataList.items = this.dataList.items.slice(0, this.dataList.itemCount); - console.assert(this.dataList.itemCount == this.dataList.items.length, 'dataList.itemCount is not equal to dataList.items.length'); - } - - // validate first item - if (this.dataList.itemCountKnown && firstItem < -1) - { - log.warn('List2: firstItem is less than -1: ' + firstItem + ' passed. Setting it to -1.'); - firstItem = -1; - } - - // validate last item - if (this.dataList.itemCountKnown && lastItem >= this.dataList.itemCount) - { - log.warn('List2: lastItem is more than or equals dataList.itemCount(' + (this.dataList.itemCount-1) + '): ' + lastItem + ' passed. Setting it to ' + (this.dataList.itemCount - 1) + '. ' + this.uiaId + ' check your variable validation!?'); - lastItem = this.dataList.itemCount - 1; - } - - - // check for invalid items (e.g. firstItem=0, lastItem=-1) -> set loading - if (firstItem > lastItem) - { - firstItem = lastItem = -1; - } - - if (firstItem == -1 && lastItem == -1) - { - // we have dataList but no list items => show loading - this._setLoading(true); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem && !this._hasFill) - { - - - // we have dataList and we have list items but we do not have fill => do initial fill - var lastFillItem = this.m.min(lastItem, this.properties.itemsBefore + this.properties.itemsAfter); - - this._fill(firstItem, lastFillItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - if (this.properties.focussedItem < this.dataList.itemCount) - { - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - else - { - this.properties.focussedItem = this.dataList.itemCount - 1; - this.properties.focussedItem = this._canGainFocus(this.properties.focussedItem); - } - /* - * Immediately scroll to a preset location and - * show focus on preset item if this is specified - * in the control's config. Focus placement needs to be done - * after the DOM is refreshed. This is done only the - * first time after a fresh setDataList() call. - * Focussed item has precedence over scroll location. - */ - if (null === this._initialScrollMode) - { - // first check if the focussed item and the scroll position are all on the same screen - // scroll to that position and show the focus according to the config - if ( (this.properties.focussedItem >= 0 || this.properties.scrollTo >= 0) && - (this.m.abs(this.properties.focussedItem - this.properties.scrollTo) <= (this.properties.visibleItems - 1)) ) - { - log.debug('Focus is visible on screen'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // set initial focus to a particular item if this is set in the config - // the list will be scrolled so that this item is visible - else if (this.properties.focussedItem >= 0) - { - log.debug('Focus is not visible and has priority'); - setTimeout(function() { - this._showFocus(this.properties.focussedItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - // scroll (no animation) to a particular item if this is set in the config - // the focus will be placed on the top item - else if (this.properties.scrollTo >= 0) - { - log.debug('Focus is 0 and scrollTo has priority'); - this._scrollTo(this.properties.scrollTo, 0); - setTimeout(function() { - this._topItem = this._canGainFocus(this._topItem); - this._showFocus(this._topItem); - }.bind(this), 0); - this._initialScrollMode = 'config'; - } - } - // sync the top item with focus if not in initial mode any more - // enter in this case usualy when a new data list is set - else - { - var focussedItem = this.focussedItem; - var topInFocusRange = focussedItem >= this.topItem && focussedItem < this.topItem + this.properties.visibleItems - 1; - var prevTopInFocusRange = focussedItem >= this._prevTopItem && focussedItem < this._prevTopItem + this.properties.visibleItems - 1; - if (!topInFocusRange && !prevTopInFocusRange) - { - this.topItem = focussedItem; - } - else if (!topInFocusRange && prevTopInFocusRange) - { - this.topItem = this._prevTopItem; - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else if (firstItem >= 0 && lastItem >= 0 && lastItem >= firstItem) - { - // preserve focussed element - var lastFocussedIndex = this._getFocussedIndex(); - - // we have dataList and we have list items, and we have fill => perform update - this._updateDisplay(firstItem, lastItem); - this._setLoading(false); - - // update modified timestamps - this._updateModifiedTimestamps(firstItem, lastItem); - - // restore focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(lastFocussedIndex, true); - } - else if (this._inSecondaryMulticontroller) - { - // treat disabling the secondary multicontroller item as interrupt -> commit value and exit - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this.dataList.items[smi].disabled) - { - this._setSecondaryMulticontroller(false, smi); - this._showFocus(smi, true); - } - else if (this.dataList.items[smi]) - { - this._setSecondaryMulticontroller(true, smi); - } - } - - // check for empty items in DOM - emptyDOMItem = this._getEmptyDOMElement(); - - } - else - { - log.error(this.uiaId + ' called List2 updateItems() with invalid arguments: firstItem = ' + firstItem + ', lastItem = ' + lastItem); - } - - // suppress secondary item request when the list is in reorder mode - if (this.properties.enableSecondaryItemRequest && !this._inListReorder) - { - // do we have empty DOM items? - if (null == emptyDOMItem) - { - // clear _secondaryRequestCount - this._secondaryRequestCount = 0; - } - else if (this._secondaryRequestCount <= this.properties.secondaryRequestLimit) - { - // fire needDataCallback() if an empty item is found in the DOM - this._requestMore(emptyDOMItem); - // increment _secondaryRequestCount - this._secondaryRequestCount++; - } - else - { - log.warn('Lis2: control has reached the secondary request count limit. Enabling the list'); - // we have reached secondaryRequestLimit -> set loading to False - this._setLoading(false); - } - } - - // restore the focus to the last focussed element - if (!this._inLetterIndexMulticontroller && !this._inSecondaryMulticontroller) - { - this._showFocus(this._lastItemWithFocus, true); - } - -}; - - -/** 2. LETTER INDEX API **/ - -/** - * Set letter index data on demand, filling letters in the letter index area - * and assigning jump indices to them, so that when touched or selected - * by multicontroller, the list jumps to the respective index. - * TAG: public - * ========================= - * @param {data} - letter index data object - * @return {boolean} - True if letter index binding operation is a success - */ -List2Ctrl.prototype.setLetterIndexData = function(data) -{ - // validate input - if (!(data instanceof Array)) - { - log.error('Lis2: letter index data should be a valid array'); - return false; - } - - // validate control support - if (!this.properties.hasLetterIndex) - { - log.error('Lis2: list2 does not support letter index'); - return false; - } - - // reset any previous letter index data - this.letterIndexData = []; - this.letterIndex.innerText = ''; - - var letterIndexItem; - var label; - for (var i=0, l=data.length; i= 0) - { - this._letterIndexDataSorted[this._letterIndexDataSorted.length] = { - publicIndex : this.letterIndexData.length-1, - itemIndex : data[i].itemIndex - }; - } - } - - // sort private and filtered letter index by the itemIndex in ASC order - this._letterIndexDataSorted.sort(function(a,b) { - var compRes = 0; - if (a.itemIndex < b.itemIndex) - compRes = -1; - else if (a.itemIndex > b.itemIndex) - compRes = 1; - else - compRes = 0; - return compRes; - }); - - // set letter index scroller height - var additionalSpace = Math.ceil(this.properties.letterIndexHeight / 2) - 5; // adjusting factor - this.letterIndex.style.height = i * this.properties.letterIndexHeight + additionalSpace + 'px'; - this._scrollerHIndex = this.letterIndex.offsetHeight; - - // update _maxScrollYIndex - this._maxScrollYIndex = this.letterIndexWrapper.offsetHeight - this.letterIndex.offsetHeight; - - // set initial active letter index if there are any available - if (this.hasDataList() && this._letterIndexDataSorted.length) - { - // get current focus index and first letter index - var focussedIndex = this._getFocussedIndex(); - var firstIndex = this._letterIndexDataSorted[0].itemIndex; - - if (firstIndex > 0 && focussedIndex < firstIndex) - { - this._setLetterIndexPosition(firstIndex); - } - else - { - this._setLetterIndexPosition(focussedIndex); - } - - } - else if (this._letterIndexDataSorted.length) - { - this._setLetterIndexPosition(this._letterIndexDataSorted[0].itemIndex); - } -}; - - -/** 3. VOICE API **/ - -/** - * Set left button configuration depending on current list configuration: - * title style, visible items, item count, item thickness - * TAG: public, VUI - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setLineNumbers = function() -{ - // check if we need to show numbers - if (!this.properties.numberedList) - { - return; - } - - // check if we have some items to number - if (!this.dataList.hasOwnProperty('itemCount') || this.dataList.itemCount <= 0) - { - return; - } - - - var style = ''; - var maxItemCount = 0; - - // determine max item count and style - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - maxItemCount = this.properties.thickItems ? 5 : 6; - style = this.properties.thickItems ? 'Style02' : 'Style04'; - break; - case 'tabsTitle' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - case 'style03a' : - maxItemCount = this.properties.thickItems ? 4 : 5; - style = this.properties.thickItems ? 'Style01' : 'Style03'; - break; - case 'style05' : - case 'style08' : - maxItemCount = 4; - style = this.properties.thickItems ? 'Style07' : 'Style06'; - break; - case 'style06' : - case 'style07' : - maxItemCount = 3; - style = this.properties.thickItems ? 'Style09' : 'Style08'; - break; - default : - log.warn('Lis2: unknown title style: ' + this._currentTitle.titleStyle); - return; - break; - } - break; - default : - log.warn('Lis2: unknown title configuration: ' + this.properties.titleConfiguration); - return; - break; - } - - // get actual item count - var itemCount = this.m.min(this.dataList.itemCount, maxItemCount); - - // check for common API - if (framework.common.setLineNumbers) - { - // call LeftBtnCtrl to show list numbers - return framework.common.setLineNumbers(itemCount, style); - } - -}; - -/** - * Performs select on the specified line number. When the select callback is fired, - * fromVui parameter is set to true. The function can return several possible - * statuses depending on the output of the operation. - * TAG: public, VUI - * ========================= - * @param {integer} - the line number that needs to be selected - * @return {string} - 'selected', 'outOfRange', 'disabled', 'sendAck', 'noList' - */ -List2Ctrl.prototype.selectLine = function(lineNumber) -{ - // get target item - var targetIndex = this._topItem + (lineNumber - 1); - - // decide what to return depending on what's visible - var status; - - // check if the list supports line numbers - if (!this.hasDataList()) - { - status = 'noList'; - log.debug('Lis2: selectLine() called with no list on the screen'); - } - else if (!this.dataList.vuiSupport) - { - status = 'noList'; - log.debug('Lis2: no VUI support for this list'); - } - else if (targetIndex > this.dataList.itemCount - 1 || targetIndex < 0) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (targetIndex < this._topItem || targetIndex > this._topItem + this.properties.visibleItems) - { - status = 'outOfRange'; - log.debug('Lis2: line number out of range'); - } - else if (!this.dataList.items[targetIndex].vuiSelectable) - { - status = 'notSelectable'; - log.debug('Lis2: list item is not VUI selectable'); - } - else if (this.dataList.items[targetIndex].disabled) - { - status = 'disabled'; - log.debug('Lis2: list item is disabled'); - this._itemSelect(targetIndex, {fromVui:true, vuiStatus:status}); - } - else - { - // default status is 'selected' -> if the item is not selectable, the callback will not be fired - var selectResult = this._itemSelect(targetIndex, {fromVui:true, vuiStatus:'selected'}); - if (true === selectResult) - { - // normal enabled status - status = 'selected'; - } - else if (false === selectResult) - { - // status if no select callback is attached - status = 'sendAck'; - } - else - { - // returned status from the select callback in the app - status = selectResult; - } - } - - return status; -}; - -/** - * Scrolls the list one page down. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageDown = function() -{ - var status = this._scrollDownPage(); - return status; -}; - -/** - * Scrolls the list one page up. A page is the number of visible items on the screen. - * Depending on the output of the function, several return values are possible. - * TAG: public, VUI - * ========================= - * @return {string} - 'paged', 'atLimit', 'onePage' - */ -List2Ctrl.prototype.pageUp = function() -{ - var status = this._scrollUpPage(); - return status; -}; - - -/** 4. SLIDER / TOGGLE API **/ - -/** - * Set slider to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the slider/pivot item - * @param {number} - the new value of the slider/pivot - * @return {void} - */ -List2Ctrl.prototype.setSliderValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isSlider(itemIndex)) - { - log.warn(this.uiaId + ': Lis2: only sliders/pivots can be used in the Slider API. Item style ' + item.itemStyle + ' passed'); - return; - } - - var slider = this._getSlider(itemIndex); - if (slider) - { - slider.setValue(value); - } - else - { - log.error(this.uiaId + ': Lis2: could not get slider instance for itemIndex ' + itemIndex); - } -}; - - -/** - * Set toggle to a specific value - * TAG: public - * ========================= - * @param {integer} - the index of the toggle item - * @param {number} - the new value of the toggle - * @return {void} - */ -List2Ctrl.prototype.setToggleValue = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.debug('Item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isToggle(itemIndex) && item.itemStyle != 'styleOnOff') - { - log.warn('Lis2: only toggle items can be used in the Toggle API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // normalize value - if (item.itemStyle == 'style10') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - else if(item.itemStyle == 'style11') - { - var value = this.m.max(this.m.min(value, 3), 1); - } - else if(item.itemStyle == 'styleOnOff') - { - var value = this.m.max(this.m.min(value, 2), 1); - } - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'toggle')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'checkbox')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - - -/** - * Set checked state for a checkbox item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the checkbox item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setCheckBox = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // cast as boolean - var value = Boolean(value); - - // set value - item.checked = value; - - // update item - this.updateItems(itemIndex, itemIndex); -}; - - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: public - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype.setRadio = function(itemIndex, value) -{ - // validate index - if (itemIndex < 0 || itemIndex >= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'radio')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a radio item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the radio item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setRadio = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i= this.dataList.itemCount) - { - log.warn('Lis2: item index out of bounds'); - return; - } - - // get item - var item = this.dataList.items[itemIndex]; - - // validate item - if (!this._isCheckBox(itemIndex)) - { - log.warn('Lis2: only checkbox or radio items can be used in the CheckBox API'); - return; - } - - // exit if we don't have _data property - if (!this._hasData(itemIndex)) - { - return; - } - - // cast as boolean - var value = Boolean(value); - - // cache value - item._data.settleValue = value; - - // perform inbound event filtering - if (!this._hasSettleTimeout(itemIndex, 'tick')) - { - // settle item immediately - this._settleItem(itemIndex); - } -}; - -/** - * Set checked state for a tick item (style03 and style03a) - * TAG: private - * ========================= - * @param {integer} - the index of the tick item - * @param {boolean} - TRUE for checked - * @return {void} - */ -List2Ctrl.prototype._setTick = function(itemIndex, value) -{ - // cast as boolean - var value = Boolean(value); - - // remove checked state of all radio items - for (var i=0; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an empty range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // filled item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get filled range - * traverse the dataList.items for filled items and returns - * an array of filled-item ranges - * TAG: public - * ========================= - * @return {array} - Array([firstFilled, lastFilled], [firstFilled, lastFilled]) - */ -List2Ctrl.prototype.getFilledRange = function() -{ - var ranges = []; - var currentRange = []; - - for (var i=0, l=this.dataList.items.length; i start the range if not already started - if (currentRange.length == 0) - { - // set first index to the range start - currentRange[0] = i; - } - - // if this is the last iteration and we are still in an filled range -> close currentRange - if (i == l-1 && currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - else - { - // empty item encountered -> end the range if started - if (currentRange.length == 1) - { - // set second index to the range end - currentRange[1] = i-1; - - // push currentRange to the ranges - ranges[ranges.length] = [currentRange[0], currentRange[1]]; - - // reset current range - currentRange.length = 0; - } - } - } - - return (ranges.length) ? ranges : null; -}; - -/** - * Get current focus mode - * TAG: public - * ========================= - * @return {string} - 'mainList' | 'letterIndex' | 'noFocus' - */ -List2Ctrl.prototype.getFocusMode = function() -{ - var currentFocusMode = 'mainList'; - if (!this._hasFocus) - { - currentFocusMode = 'noFocus'; - } - else if (this._inLetterIndexMulticontroller) - { - currentFocusMode = 'letterIndex'; - } - - return currentFocusMode; -}; - - -/** 7. OTHER **/ - -/** - * Set loading state of the list - * TAG: public - * ========================= - * @param {boolean} - enable or disable loading state - * @return {void} - */ -List2Ctrl.prototype.setLoading = function(state) -{ - // cast as boolean - var state = Boolean(state); - this._setLoading(state); -}; - - -/** - * Public API that changes the loading configuration - * ========================= - * @param {Object} - object that will set loading item configuration - * @return {Object} - retuns the loading configuration object - */ -List2Ctrl.prototype.setLoadingConfig = function (config) -{ - for (var i in config) - { - this.properties.loadingConfig[i] = config[i]; - } - - if (null !== this.properties.loadingConfig.loadingTextId && undefined !== this.properties.loadingConfig.loadingTextId && "" !== this.properties.loadingConfig.loadingTextId) - { - this.properties.loadingConfig.loadingText = this._getLocalizedString(this.properties.loadingConfig.loadingTextId, this.properties.loadingConfig.loadingSubMap); - } - this.loading.querySelector(".loadingText").innerText = ""; - this.loading.querySelector(".loadingText").appendChild(document.createTextNode(this.properties.loadingConfig.loadingText)); - this.loading.querySelector(".loadingImage1").style.backgroundImage = 'url(' + this.properties.loadingConfig.loadingImage1 + ')'; - - return this.properties.loadingConfig; -}; - -/** - * Enter or release reorder mode - * TAG: public - * ========================= - * @param {boolean} - enter or release list reorder - * @param {boolean} - prevent item select on releasing reorder - * @return {void} - */ -List2Ctrl.prototype.setReorder = function(state, preventSelect) -{ - // cast as boolean - var state = Boolean(state); - var preventSelect = Boolean(preventSelect); - - if (state && !this._inListReorder) - { - // if user has lost the reorder item - if (null != this._reorderCurrentIndex && (this._reorderCurrentIndex < this._topItem || this._reorderCurrentIndex > this._topItem + this.properties.visibleItems-1)) - { - if (this.dataList.items[this._reorderCurrentIndex] && !this.dataList.items[this._reorderCurrentIndex].disabled) - { - // reorder item is outside screen. Bring it back in and show focus on it - this._showFocus(this._reorderCurrentIndex); - } - } - - // enter into reorder - this._enterListReorder(); - } - else if (!state && this._inListReorder) - { - // release reorder - this._releaseListReorder(preventSelect); - } -}; - -/** - * Set fixed title for the list - * TAG: public - * ========================= - * @param {object} - title properties - * @return {void} - */ -List2Ctrl.prototype.setTitle = function(titleStructure) -{ - - // validate titleStructure - if (!titleStructure || !titleStructure.hasOwnProperty('titleStyle')) - { - return; - } - - /* - * title structure: - * { - * titleStyle : 'style02', - * text1Id : null, - * text1SubMap : null, - * text1 : '', - * image1 : 'path/to/image.png' - * } - */ - - // prepare title - var titleStructure = titleStructure || {}; - titleStructure = this._prepareTitle(titleStructure); - - if (this._currentTitle) - { - // we already have a title -> update it - - // validate new title - switch (titleStructure.titleStyle) - { - case 'style02' : - case 'style02a' : - case 'style03' : - // thin - if ('style02' != this._currentTitle.titleStyle && - 'style02a' != this._currentTitle.titleStyle && - 'style03' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style05' : - case 'style08' : - // medium - if ('style05' != this._currentTitle.titleStyle && - 'style08' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - - case 'style06' : - case 'style07' : - // thick - if ('style06' != this._currentTitle.titleStyle && - 'style07' != this._currentTitle.titleStyle) - { - log.warn('Lis2: changing title style with a different height is not possible'); - return; - } - break; - } - } - - // empty title element - this.title.innerText = ''; - // remove old title style class - if (this._currentTitle) - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - this.title.classList.remove(this._currentTitle.titleStyle); - } - // add title style as a class - this.title.classList.add(titleStructure.titleStyle); - - // fill it - var line1, line2, image1; - - switch (titleStructure.titleStyle) - { - case 'style02' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style02a' : - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style03' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleNormal'); - - break; - - case 'style05' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - this.divElt.classList.add('listTitleMedium'); - - break; - - case 'style06' : - - if (titleStructure.image1 === 'canvas') - { - // preview image is a canvas - image1 = document.createElement('canvas'); - image1.className = 'image1'; - // store canvas for public API call - this.titleCanvas = image1; - this.title.appendChild(image1); - } - else - { - // preview image is an image - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - } - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style07' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - line2 = document.createElement('span'); - line2.className = 'line2'; - line2.appendChild(document.createTextNode(titleStructure.text2)); - this.title.appendChild(line2); - - this.divElt.classList.add('listTitleThick'); - - break; - - case 'style08' : - line1 = document.createElement('span'); - line1.className = 'line1'; - line1.appendChild(document.createTextNode(titleStructure.text1)); - this.title.appendChild(line1); - - image1 = document.createElement('span'); - image1.className = 'image1'; - image1.style.backgroundImage = 'url(' + titleStructure.image1 + ')'; - this.title.appendChild(image1); - - // add/remove styleMod class (warning/bold/both/'') - if ('warning' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - } - else if ('bold' == titleStructure.styleMod) - { - this.title.classList.add('bold'); - } - else if ('both' == titleStructure.styleMod) - { - this.title.classList.add('warning'); - this.title.classList.add('bold'); - } - else - { - this.title.classList.remove('warning'); - this.title.classList.remove('bold'); - } - - this.divElt.classList.add('listTitleMedium'); - - break; - - default : - log.error('Lis2: unknown title style: ' + titleStructure.titleStyle); - } - - // save the title structure - this._currentTitle = titleStructure; - -}; - - -/** 8. CONTEXT CAPTURE AND RESTORE **/ - -/** - * Context capture - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.getContextCapture = function() -{ - var obj = { - hasFocus : this._hasFocus, - topItem : this._topItem, - focussedItem : this._getFocussedIndex(), - itemCount : this.dataList ? this.dataList.itemCount : 0 - }; - - log.debug('Lis2: getContextCapture obj ', obj); - return obj; -}; - -/** - * Context restore - * TAG: framework, public - * ========================= - * @return {object} - capture data - */ -List2Ctrl.prototype.restoreContext = function(restoreData) -{ - log.debug('Lis2: restoreContext restoreData ', restoreData); - // validate input - if (!restoreData.hasOwnProperty('topItem') || !restoreData.hasOwnProperty('focussedItem')) - { - log.info('No data to restore'); - return; - } - - - // restore hasFocus flag - if (restoreData.hasFocus) - { - this._hasFocus = true; - } - - if (this.hasDataList()) - { - // scroll to previous position and show previous focus - // no checks for value conflicts are necessary. These ought to be correct. - this._scrollTo(restoreData.topItem); - - // NOTE: actual focus placement happens in controllerActive event handling - - // mark the list as data-restored preventing any subsequent auto-scrolls - this._initialScrollMode = 'restore'; - - this._manageFocus(restoreData.focussedItem); - } - else - { - log.info('List has no dataList to restore'); - } - - // overwrite control properties - this.properties.scrollTo = restoreData.topItem; - this.properties.focussedItem = restoreData.focussedItem; - this._lastItemWithFocus = restoreData.focussedItem; -}; - - -/** 9. BACKGROUND API **/ - -/** - * Set a custom background on the list control - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.setListBackground = function(img, position) -{ - this.clearListBackground(); - this.listBackground = document.createElement('div'); - this.listBackground.className = 'List2CtrlCustomBackground'; - this.listBackground.style.backgroundImage = 'url('+img+')'; - - // set background position - if (position && typeof position == 'object' && position['left'] != undefined && position['top'] != undefined) - { - var left = (!isNaN(position['left'])) ? position.left + 'px' : position.left.toString(); - var top = (!isNaN(position['top'])) ? position.top + 'px' : position.top.toString(); - this.listBackground.style.backgroundPosition = left + ' ' + top; - } - - this.divElt.appendChild(this.listBackground); -}; - -/** - * Clear any custom background image - * TAG: public - * ========================= - * @return {void} - */ -List2Ctrl.prototype.clearListBackground = function() -{ - if (this.listBackground) - { - this.listBackground.parentElement.removeChild(this.listBackground); - this.listBackground = null; - } -}; - - - -/** - * ========================= - * HELPERS AND UTILITIES - * ========================= - */ - - /** - * Create Tabs control - * ========================= - * @return The TabsCtrl instance. - */ -List2Ctrl.prototype._createTabsControl = function() -{ - log.debug(' Instantiating TabsCtrl'); - if (this.properties.tabsButtonConfig.tiltStartCallback) - { - log.warn("Lis2: the tabsButtonConfig.tiltStartCallback property was defined outside of the list control but should only be used by the list."); - } - this.properties.tabsButtonConfig.tiltStartCallback = this._tabsCtrlTiltStartCallback.bind(this); - return framework.instantiateControl(this.uiaId, this.divElt, "TabsCtrl", this.properties.tabsButtonConfig); -}; - -/** - * Clear the list contents when the user starts tilting to a new tab. - */ -List2Ctrl.prototype._tabsCtrlTiltStartCallback = function(controlRef, appData, params) -{ - if (this.title) - { - this.title.style.opacity = 0; - } - this.setDataList({}); - this._hideScrollIndicator(); -}; - - -/** - * Tracks touch position properties of the last two events. - * TAG: touch-only, internal - * ========================= - * @param {MouseEvent} - MouseMove event - * @return {void} - */ -List2Ctrl.prototype._trackEvent = function(e) -{ - // use shallow copy - var trackedEvents = this._trackedEvents; - trackedEvents[0] = trackedEvents[1]; - trackedEvents[1] = { y: e.pageY, x: e.pageX }; -}; - -/** - * Get touch direction upon touch move - * TAG: touch-only, internal - * ========================= - * @return {integer} - 1 for 'down', -1 for 'uo' - */ -List2Ctrl.prototype._getMoveDirection = function() -{ - var trackedEvents = this._trackedEvents, - event0 = trackedEvents[0], - event1 = trackedEvents[1]; - - if (!event0) return 1; - - return (event1.y - event0.y < 0) ? -1 : 1; -}; - -/** - * Get current list position (or specific position relative to supplied item index) - * TAG: internal - * ========================= - * @param {integer} - optional, item index from which to calculate position - * @return {string} - onepage | top | bottom | bottomclose | topclose | middle - */ -List2Ctrl.prototype._getListPosition = function(itemIndex) -{ - // get item index - var itemIndex = (undefined === itemIndex) ? this._topItem : itemIndex; - - // get list position - var listPosition = null; - - // determine list position - if (this.dataList.itemCount <= this.properties.visibleItems) - listPosition = 'onepage'; - else if (0 === itemIndex) - listPosition = 'top'; // list is at the top - else if (itemIndex === this.dataList.itemCount - this.properties.visibleItems) - listPosition = 'bottom'; // list is at the bottom - else if (itemIndex > this.dataList.itemCount - (2 * this.properties.visibleItems)) - listPosition = 'bottomclose'; // list is less than a screen to the bottom - else if (itemIndex < 2 * this.properties.visibleItems) - listPosition = 'topclose'; // list is less than a screen to the top - else - listPosition = 'middle'; // list is somewhere in the middle - - // return list position - return listPosition; -}; - - -/** - * Get additional space that needs to be added to the scroller - * height in order to satisfy the 'half-line' requirements. - * Correction is needed because there's a difference between - * visual style guide and actual item heights. The values are - * fixed and depend on the style. - * TAG: helper - * ========================= - * @return {integer} - */ -List2Ctrl.prototype._getAdditionalSpace = function() -{ - // determine additional space - var additionalSpace = 0; - switch (this.properties.titleConfiguration) - { - case 'noTitle' : - additionalSpace = this.properties.thickItems ? 6 : 32; - break; - case 'tabsTitle' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'listTitle' : - switch (this._currentTitle.titleStyle) - { - case 'style02' : - case 'style03' : - additionalSpace = this.properties.thickItems ? 19 : 27; - break; - case 'style05' : - case 'style08' : - additionalSpace = this.properties.thickItems ? 52 : 42; - break; - case 'style06' : - case 'style07' : - additionalSpace = this.properties.thickItems ? 60 : 32; - break; - default : - // nothing to do - break; - } - break; - default : - // nothing to do - break; - } - - - - return additionalSpace; -}; - -/** - * Get empty DOM elements - * Return the first element in the DOM that doesn't - * have data associated with it in the dataList - */ -List2Ctrl.prototype._getEmptyDOMElement = function() -{ - var emptyItem = null; - var items = []; - - // get item indeces and sort them in ascending order - for (var i=0; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var itemIndex = Math.floor(relativeY / this.properties.itemHeight); - - // if we are in the active area but below the last item -> return -1 - if (itemIndex > this.dataList.itemCount - 1) - { - return -1; - } - - // constrain itemIndex to the max possible index - itemIndex = this.m.min(itemIndex, this.dataList.itemCount - 1); - - return itemIndex; -}; - -/** - * Get DOM Element by itemIndex - * Returns a DOM element (or null) for a particular - * item after performing a search for its item index - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {HTML Element} -
  • element - */ -List2Ctrl.prototype._getDOMItem = function(itemIndex) -{ - var domItem = null; - - for (var i=0, l=this.items.length; i return -1 - if (relativeY < 0 || e.pageY - this._maskPositionY < 0) - { - return -1; - } - - var letterIndex = Math.floor(relativeY / this.properties.letterIndexHeight); - - // if we are in the active area but below the last letter index item -> return -1 - if (letterIndex > this.letterIndexData.length - 1) - { - return -1; - } - - // constrain letterIndex to the max possible index - letterIndex = this.m.min(letterIndex, this.letterIndexData.length - 1); - - return letterIndex; -}; - -/** - * Get Slider instance by itemIndex - * TAG: internal, helper - * ========================= - * @param {integer} - index of the list item - * @return {SliderCtrl} - slider instance - */ -List2Ctrl.prototype._getSlider = function(itemIndex) -{ - var sliderCtrl = null; - - var index; - if (utility.toType(itemIndex) === 'number') - { - index = itemIndex; - } - else - { - index = this._getFocussedIndex(); - } - - var domElt = this._getDOMItem(index); - if (domElt) - { - var poolId = domElt.getAttribute('data-poolid'); - var hashKey = 'slider_'+index+'_'+poolId; - - // check whether a slider exists - if (this._sliders.hasOwnProperty(hashKey) && this._sliders[hashKey].slider) - { - sliderCtrl = this._sliders[hashKey].slider; - } - } - - return sliderCtrl; -}; - -/** - * Checks whether the supplied itemIndex contains a slider - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains a slider - */ -List2Ctrl.prototype._isSlider = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSlider = false; - - if (!isNaN(itemIndex)) - { - isSlider = ('style12' === this.dataList.items[itemIndex].itemStyle || 'style13' === this.dataList.items[itemIndex].itemStyle || 'style28' == this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSlider = ('style12' === itemIndex || 'style13' === itemIndex|| 'style28' === itemIndex); - } - - return isSlider; -}; - -/** - * Checks whether the supplied itemIndex is a lock item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a lock item - */ -List2Ctrl.prototype._isLock = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isLock = false; - - if (!isNaN(itemIndex)) - { - isLock = ('styleLock' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isLock = ('styleLock' === itemIndex); - } - - return isLock; -}; - -/** - * Checks whether the supplied itemIndex contains toggle buttons - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item contains toggle buttons - */ -List2Ctrl.prototype._isToggle = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isToggle = false; - - if (!isNaN(itemIndex)) - { - isToggle = ('style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle || 'draggable' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isToggle = ('style10' === itemIndex || 'style11' === itemIndex || 'draggable' === itemIndex); - } - - return isToggle; -}; - -/** - * Checks whether the supplied itemIndex is On/Off item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is On/Off - */ -List2Ctrl.prototype._isOnOff = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isOnOff = false; - - if (!isNaN(itemIndex)) - { - isOnOff = ('styleOnOff' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isOnOff = ('styleOnOff' === itemIndex); - } - - return isOnOff; -}; - -/** - * Checks whether the supplied itemIndex is a step item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a step item - */ -List2Ctrl.prototype._isStep = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isStep = false; - - if (!isNaN(itemIndex)) - { - isStep = ('styleStep' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isStep = ('styleStep' === itemIndex); - } - - return isStep; -}; - -/** - * Checks whether the supplied itemIndex is a checkbox - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is a checkbox/tick/radio item - */ -List2Ctrl.prototype._isCheckBox = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isCheckbox = false; - - if (!isNaN(itemIndex)) - { - isCheckbox = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isCheckbox = ('style03' === itemIndex || 'style03a' === itemIndex); - } - - return isCheckbox; -}; - -/** - * Checks whether the supplied itemIndex is a simple select item - * TAG: internal, helper - * ========================= - * @param {integer|string} - index of the list item | item style - * @return {boolean} - true if the item is simple select item - */ -List2Ctrl.prototype._isSimpleSelectItem = function(itemIndex) -{ - // exit if we don't have any items - if (!this.hasDataList()) - { - return false; - } - - var isSimpleSelect = false; - - if (!isNaN(itemIndex)) - { - isSimpleSelect = ('style03' === this.dataList.items[itemIndex].itemStyle || 'style03a' === this.dataList.items[itemIndex].itemStyle || 'styleOnOff' === this.dataList.items[itemIndex].itemStyle || 'style10' === this.dataList.items[itemIndex].itemStyle || 'style11' === this.dataList.items[itemIndex].itemStyle); - } - else if (typeof itemIndex === 'string') - { - isSimpleSelect = ('styleOnOff' === itemIndex || 'style10' === itemIndex || 'style11' === itemIndex); - } - - return isSimpleSelect; -}; - -/** - * Checks whether the item contains _data property - * TAG: internal, helper - * ========================= - * @param {integer} - item index - * @return {Boolean} - True if the item contains _data property - */ -List2Ctrl.prototype._hasData = function(itemIndex) -{ - var containsData = false; - if (this.dataList && this.dataList.items && this.dataList.items[itemIndex]) - { - containsData = this.dataList.items[itemIndex].hasOwnProperty('_data'); - } - return containsData; -}; - -/** - * Wraps inline text element if the width exceeds certain - * max width that depends on the item style. - * TAG: internal, helper - * ========================= - * @param {HTML Li Element} - the LI element that will be searched for overflowing text - * @return {HTML Li Element} - the modified LI element - */ -List2Ctrl.prototype._wrapInlineElement = function(li) -{ - var searchClass = null; - var maxWidth = 0; - - if (li.classList.contains('style17')) - { - searchClass = 'line1'; - maxWidth = this.properties.wrapTextThreshold; - } - else - { - return li; - } - - var line1 = li.getElementsByClassName(searchClass); - if (!line1 || 0 === line1.length) - { - return li; - } - else - { - line1 = line1[0]; - } - - if (line1.clientWidth > maxWidth) - { - line1.classList.add("wrap"); - } - else - { - line1.classList.remove("wrap"); - } - - return li; -}; - -/** - * Checks if the item can be displayed, even if it has no text field. - * TAG: internal, helper - * ===================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._displayWithoutText = function(item) -{ - var returnValue = true; - for(var i =0; i < this._itemsWithNoText.length; i++) - { - if(item.itemStyle === this._itemsWithNoText[i]) - { - returnValue = false; - break; - } - } - return returnValue; -}; - -/** - * Checks if the item is a slider with full hittable area - * TAG: internal, helper - * =================================================== - * @param {Object} - * @return {Boolean} - */ -List2Ctrl.prototype._hasRightHittableArea = function(item) -{ - var returnValue = false; - - for(var i =0; i < this._rightHittableArea.length; i++) - { - if(item.itemStyle === this._rightHittableArea[i]) - { - returnValue = true; - break; - } - } - return returnValue; -}; - - -/** - * Show bounding boxes of some elements in the list. - * This should be used for debugging purposes only - * TAG: internal, utility - * ========================= - * @param {Boolean} - * @return {void} - */ -List2Ctrl.prototype.showBoundingBoxes = function(state) -{ - if (state) - { - this.divElt.classList.add('showBoundingBoxes'); - } - else - { - this.divElt.classList.remove('showBoundingBoxes'); - } -}; - - -/** - * Searches an array for a value - * TAG: internal, utility - * ========================= - * @param {string|number} - * @param {array} - * @return {object} - copy of the source object - */ -List2Ctrl.prototype.inArray = function(needle, haystack) -{ - if (!needle || !haystack) - { - log.warn('Lis2: 2 arguments expected'); - return; - } - - for (var i=0, l=haystack.length; i b ? a : b // return the higher - : NaN; // else return NaN (just like the Math class) - }, - abs : function(a) - { - return (!isNaN(a)) ? // if the argument is a number - a < 0 ? -a : a // return the abs - : NaN; // else return NaN (just like the Math class) - } -}; - -/** - * Finish partial activity. - * @return {void} - */ -List2Ctrl.prototype.finishPartialActivity = function() -{ - // route finish partial activity to sub controls - - // tabs ctrl - if (this.tabsCtrl) - { - // delete the assigned callback reference so that it's not stored in the App's context table - delete this.properties.tabsButtonConfig.tiltStartCallback; - this.tabsCtrl.finishPartialActivity(); - } - - // slider - if (this._activeSlider && this._activeSlider.slider) - { - this._activeSlider.slider.finishPartialActivity(); - } - - // list -> exit any items in secondary MC mode - if (this._inSecondaryMulticontroller) - { - var smi = this._currentSecondaryMulticontrollerItem; - if (this.dataList.items[smi] && this._isStep(smi)) - { - this._setSecondaryMulticontroller(false); - this._triggerFocus(); - } - } -}; - - -/** - * ========================= - * GARBAGE COLLECTION - * - Clear listeners - * - Clean up subcontrols - * - Clear timeouts - * TAG: framework - * ========================= - * @return {void} - */ -List2Ctrl.prototype.cleanUp = function() -{ - // remove event callbacks - this.divElt.removeEventListener(this._USER_EVENT_START, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_MOVE, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_END, this.touchHandler, false); - document.removeEventListener(this._USER_EVENT_OUT, this.touchHandler, false); - - // remove animation callbacks - this.scroller.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollerAnimationEndCallback, false); - if (this.scrollIndicator) - { - this.scrollIndicator.removeEventListener(this._VENDOR + 'TransitionEnd', this.scrollIndicatorAnimationEndCallback, false); - } - if (this.letterIndex) - { - this.letterIndex.removeEventListener(this._VENDOR + 'TransitionEnd', this.letterIndexAnimationEndCallback, false); - } - - // clean up subcontrols - if (this.tabsCtrl) - { - this.tabsCtrl.cleanUp(); - } - for (var i in this._sliders) - { - this._sliders[i]['slider'].cleanUp(); - } - - // clear timeouts - clearTimeout(this._makeHitTimeoutId); - clearTimeout(this._longPressTimeoutId); - clearTimeout(this._touchReorderTimeoutId); - clearTimeout(this._scrollIndicatorTimeoutId); - clearTimeout(this._indexSelectTimeoutId); - clearTimeout(this._tiltHoldTimeoutId); - clearInterval(this._tiltHoldIntervalId); - clearTimeout(this._needDataTimeoutId); - clearTimeout(this._loadingData.startTimeoutId); - clearTimeout(this._loadingData.endTimeoutId); - clearTimeout(this._radioSettleTimeoutId); - clearTimeout(this._tickSettleTimeoutId); - if (this.hasDataList()) - { - for (var i=0, l=this.dataList.items.length; i 4) - { - index = 4; - } - - if (index !== this._getFocus()) - { - this._setFocus(index); - this._setHighlight(index); - } -} - -// Start a timer while the user holds tilt. -MainMenuCtrl.prototype._startTiltHoldTimer = function() -{ - this._cancelFastTilt(); - - // Only start the fast tilt hold timer if fast-tilting would have any effect from the current focus position. - if ((this._fastTiltDirection === -1 && this._getFocus() > 0) || - (this._fastTiltDirection === 1 && this._getFocus() < 4)) - { - this._tiltHoldTimerId = setTimeout(this._startFastTiltInterval.bind(this), this.properties.tiltHoldTime); - } -} - -// Invoked when the user holds tilt long enough to start fast tilting. -MainMenuCtrl.prototype._startFastTiltInterval = function() -{ - framework.common.beep("Long", "Multicontroller"); - this._tiltHoldTimerId = null; - this._fastTiltStep(); - this._fastTiltStepIntervalId = setInterval(this._fastTiltStep.bind(this), this.properties.tiltStepTime); -} - -// Cancels all fast-tilt or tilt-hold timers. -MainMenuCtrl.prototype._cancelFastTilt = function() -{ - clearTimeout(this._tiltHoldTimerId); - clearInterval(this._fastTiltStepIntervalId); - - this._tiltHoldTimerId = null; - this._fastTiltStepIntervalId = null; -} - -// Periodic interval invoked during fast tilting. -MainMenuCtrl.prototype._fastTiltStep = function() -{ - this._offsetFocus(this._fastTiltDirection); -} - -// Handle multicontroller events. -MainMenuCtrl.prototype.handleControllerEvent = function(eventId) -{ - var response = null; - switch(eventId) - { - case "lostFocus": - if (framework.isCurrentTemplateDialog()) - { - this._setHighlight(-1); - } - response = "consumed"; - break; - - case "acceptFocusInit": - this._setHighlight(this._getFocus()); - response = "consumed"; - break; - - case "ccw": - if (this._allowInput) - { - this._offsetFocus(-1); - response = "consumed"; - } - break; - - case "cw": - if (this._allowInput) - { - this._offsetFocus(1); - response = "consumed"; - } - break; - - case "leftStart": - if (this._allowInput) - { - this._lastControllerStartEvent = eventId; - this._fastTiltDirection = -1; - this._offsetFocus(this._fastTiltDirection); - this._startTiltHoldTimer(); - response = "consumed"; - } - break; - - case "left": - if (this._allowInput && this._lastControllerStartEvent === "leftStart") - { - this._cancelFastTilt(); - response = "consumed"; - } - this._lastControllerStartEvent = ""; - break; - - case "rightStart": - if (this._allowInput) - { - this._lastControllerStartEvent = eventId; - this._fastTiltDirection = 1; - this._offsetFocus(this._fastTiltDirection); - this._startTiltHoldTimer(); - response = "consumed"; - } - break; - - case "right": - if (this._allowInput && this._lastControllerStartEvent === "rightStart") - { - this._cancelFastTilt(); - response = "consumed"; - } - this._lastControllerStartEvent = ""; - break; - - case "selectStart": - if (this._allowInput) - { - this._lastControllerStartEvent = eventId; - this._setHighlight(this._getFocus()); - } - break; - - case "select": - if (this._allowInput && this._lastControllerStartEvent === "selectStart") - { - this._invokeSelectCallback(this._getFocus()); - response = "consumed"; - } - this._lastControllerStartEvent = ""; - break; - } - - return response; -} - -MainMenuCtrl.prototype.startTransitionFrom = function() -{ - if (this._hasInvokedSelectCallback) - { - var index = this._getFocus(); - switch (index) - { - case 0: // fallthrough - case 4: - this._coins[index].div.classList.add("MainMenuCtrlCoinAExplode"); - this._coins[index].highlight.classList.add("MainMenuCtrlHighlightExplode"); - break; - - case 1: // fallthrough - case 2: // fallthrough - case 3: - this._coins[index].div.classList.add("MainMenuCtrlCoinBExplode"); - this._coins[index].highlight.classList.add("MainMenuCtrlHighlightExplode"); - break; - - default: - break; - } - } -} - -MainMenuCtrl.prototype.endTransitionTo = function() -{ - this._iconNameDiv.classList.add("Visible"); -} - -MainMenuCtrl.prototype.getContextCapture = function() -{ - var capture = {}; - capture.focusedIcon = this._getFocus(); - log.debug("MainMenuCtrl.prototype.getContextCapture " + capture.focusedIcon); - return capture; -} - -MainMenuCtrl.prototype.restoreContext = function(capture) -{ - if (capture && typeof capture.focusedIcon === "number") - { - this._setFocus(capture.focusedIcon); - log.debug("MainMenuCtrl.prototype.restoreContext " + capture.focusedIcon); - } -} - -MainMenuCtrl.prototype.finishPartialActivity = function() -{ - this._cancelFastTilt(); - - // Null out the selectCallback to prevent any inadvertant callbacks while/after this template is destroyed. - this.properties.selectCallback = null; -} - -MainMenuCtrl.prototype.cleanUp = function() -{ - // delete obj reference - delete this.properties; - - document.body.removeEventListener("mousemove", this._mouseMoveCallback); - document.body.removeEventListener("mousedown", this._mouseDownCallback); - document.body.removeEventListener("mouseup", this._mouseUpCallback); - - for (var i = 0; i < this._coins.length; i++) - { - this._coins[i].div.removeEventListener('OTransitionEnd', this._coins[i].setHighlightEndBinder); - } - - if (this._allowInputTimerId) - { - clearTimeout(this._allowInputTimerId); - this._allowInputTimerId = null; - } - - this._cancelFastTilt(); -} - -framework.registerCtrlLoaded("MainMenuCtrl"); diff --git a/app/files/tweaks/config_org/message_replies/jci/settings/configurations/blm_msg-system.xml b/app/files/tweaks/config_org/message_replies/jci/settings/configurations/blm_msg-system.xml deleted file mode 100644 index 0c38774..0000000 --- a/app/files/tweaks/config_org/message_replies/jci/settings/configurations/blm_msg-system.xml +++ /dev/null @@ -1,1235 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.56.00.230A-EU b/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.56.00.230A-EU deleted file mode 100644 index 1855624..0000000 --- a/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.56.00.230A-EU +++ /dev/null @@ -1,2364 +0,0 @@ -/* - Copyright 2012 by Johnson Controls - __________________________________________________________________________ - - Filename: Common.js - __________________________________________________________________________ - - Project: JCI-IHU - Language: EN - Author: awoodhc - Date: 08.27.2012 - __________________________________________________________________________ - - Description: IHU GUI Common - - Revisions: - v0.1 (27-Aug-2012) Create Common to handle all "system-wide" logic - v0.2 (27-Aug-2012) Added basic logic for "global" controls, multicontroller events, transitions, ctrl clicks, basic BG logic - v0.3 (28-Aug-2012) Added logic for alerts - v0.4 (11-Oct-2012) Added logic to hide Home Button while on Home Screen - v0.5 (04-Nov-2012) Added API to display App Name in Status Bar - Added Diag Entry logic - v0.6 (08-Nov-2012) Added API for Setting the Left Button Style. - v0.7 (19-Nov-2012) Changed Alert event to conform with MMUI standards. Added API to set the Status Bar Clock with value from MMUI. - v0.8 (26-Nov-2012) Fixed Diagnostics Entry. Common now counts a sequence to make sure the sequence is complete before resetting. - v0.9 (03-Dec-2012) Added message table for handling MMUI common messages and handling for LanguageChangeStatus msg - v1.0 (05-Dec-2012) Added API to set state of status bar icons - v1.1 (21-Jan-2012) Added new SBN and Wink logic - __________________________________________________________________________ - - */ - -log.addSrcFile("Common.js", "common"); -//log.setLogLevel("common", "debug"); - -function Common() -{ - log.debug("constructor called..."); - - //-- public variables - this.moduleName = "common"; // (String) Name of this module (used in place of uiaId when instantiating controls) - this.statusBar = null; // (Object) Status Bar Control Object - this.leftBtn = null; // (Object) Left Button Control Object - - this.cmnCtrlsDisabled = false; // (Boolean) Whether to Status Bar/Left Button are disabled due to a dialog - - - //-- private variables - - this._cachedTime = 0; // (Number) Stores the time value sent from MMUI via GUI_SYSSETTINGS - this._cachedTemplate = null; // (Object) template currently active in the DOM. Framework updates this. - this._menuUpReceiverApp = null; // (String) cached uiaId sent from MMUI when during a transition caused by a Menu Up action - this._canShowSbns = false; // (Boolean) true if Common can display SBNs over the cached template - - this._bgDiv1 = null; // (HTMLElement) the background div - this._bgDiv2 = null; // (HTMLElement) used to transition between 2 backgrounds - this._rightChrome = null; // (HTMLElement) the div used to display the right-hand chrome - this._customBgSet = false; // (Boolean) true if there is a custom bg set by the current template - this._defaultBgPath = "common/images/background.png"; // (String) the css path to the default bg image - this._currentBgPath = this._defaultBgPath; // (String) the css path to the current bg image - - this._wink = null; // (Object) The active Wink Control Object (null if none displayed) - this._winkTimeout = guiConfig.winkTimeout; // (Number) milliseconds a Wink will stay on screen - - this._muteWink = null; // (Object) The Entertainment Mute Wink Control Object (null if none displayed) - - this._cachedVuiState = null; // (String) Last VUI state sent from MMUI. - this._vuiHelpDialog = null; // (Object) The active VUI Help Dialog Control (null if none displayed) - this._lineNumberData = null; // (Object) Contains data passed from a List pertaining to the VUI line numbers - - this._diagEntrySequence = 0; // (Number) 1 if the Diagnostics entry button sequence has begun. 2 if it has completed. - this._clockHomeButtonLongPressIntervalId = null; - - this._atSpeed = false; // (Boolean) true if AtSpeed event is received from MMUI - this._isMuted = false; // (Boolean) true if entertainment audio is currently muted - - this._contextCategory = new ContextCategory(); // (Object) Contains a lookup table to determine a context's category. - - //-- Status Bar Auto-Hide Variables - // MPP 09/16/2013 SW00107357 - this._displaySbUmpByActivity = false; // (Boolean) Master switch for auto-hide status bar/UMP feature - this._displaySbUmpActivityTypes = "both"; // (String) "both" for both touch & MC input to count as activity, "touch" for touch-only input - this._inactivityTimer = null; // (Object) The timer used to measure (in)activity for auto-hiding the status bar & UMP - this._onInactivityBinder = this._onInactivity.bind(this); // (Callback) Bind the timer callback once to save memory - this._activityDetected = false; // (Boolean) Flag raised on touch/MC input; lowered when inactivity timer expires - this._sbRequestedState = "none"; // (String) External request to show/hide status bar - this._sbDelay_ms = -1; // (Integer) # of milliseconds before status bar animation starts (external request) - this._sbDuration_ms = -1; // (Integer) # of milliseconds status bar animation should take (external request) - this._defaultSbDelay_ms = 0; // (Integer) Default delay timing for status bar animation - this._defaultSbDuration_ms = 500; // (Integer) Default duration timing for status bar animation - this._defaultHelpPrompt = "SpeechNotAllowed_Help"; // (string) help promp name which requires default help screen - - //-- Status Bar Notification Variables - /* - * See _setKnownSbn() function for _knownSbns variable properties - */ - this._knownSbns = new Object(); // (Object) key'd to SbnId, value is SbnObject with information necessary to display Sbn - this._sbnIsDisplayed = false; // (Boolean) Flag indicating whether an SBN is displayed (true) or not (false). - this._displayedSbn = null; // (Object) Refernce to the currently displayed Sbn Control. - this._displayedSbnId = null; // (String) SbnId of the currently displayed Sbn. null if none is displayed - this._displayedSbnTimerId = 0; // (Number) Timer ID used for timed Sbns. - this._sbnQueue = new Array(); // (Array) Queue of all current Sbns by Id. 0 is next in line to be dispalyed. - - // Default SBN values used where value is not specified in UI Spec. - var dfltDuration = 2000; // (Number) default number of milliseconds - var dfltQueue = 0; // (Number) default number of milliseconds - - // NOTE: State-based SBNs do not expire, but Timed SBNs should be queueTime 0 so that they do not re-appear (exception: driverId) - - this._SBN_TYPES = { // (Object) contains list of Sbn Priorities by type, defined in System UI Spec - - //replaced old sbn types with new letter based sbn types(As per SCR SW00155262) - "typeA": {"priority": 1, "timedDuration": 2000, "queueTime": 0}, // 1 is highest priority - "typeB": {"priority": 2, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "typeL": {"priority": 3, "timedDuration": 5000, "queueTime": 60000}, - "typeC": {"priority": 4, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "typeD": {"priority": 5, "timedDuration": 5000, "queueTime": 0}, - "typeE": {"priority": 6, "timedDuration": 5000, "queueTime": 0}, - "typeF": {"priority": 7, "timedDuration": 5000, "queueTime": 0}, - "typeG": {"priority": 8, "timedDuration": 5000, "queueTime": 0}, - "typeI": {"priority": 9, "timedDuration": 5000, "queueTime": 0}, - "typeJ": {"priority": 10, "timedDuration": 5000, "queueTime": 0}, - "typeK": {"priority": 11, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "unknown": {"priority": 100, "timedDuration": dfltDuration, "queueTime": dfltQueue} - }; - - this._SBN_MAPPING_TABLE = { // contains mapping of old sbn types with new letter based sbn types(As per SCR SW00155262) - "volumeStatus" : "typeA", - "vrStatus" : "typeB", - "driverId" : "typeL", - "navigationNear" : "typeC", - "deviceConnected" : "typeD", - "entertainmentInfo" : "typeE", - "errorNotification" : "typeF", - "btConnecting" : "typeG", - "deviceRemoved" : "typeI", - "navigationFar" : "typeJ", - "systemFailure": "typeK", - "unknown": "unknown" - }; - - // Any SBN type in the blacklist will be blocked if it is requested. This is a centralized fix for evolving requirements. - this._SBN_TYPE_BLACKLIST = [ - "typeK" - ]; - - //@formatter:off - this._messageTable = { - "LanguageChangeStatus" : this._LanguageChangeStatusMsgHandler.bind(this), - "Global.AtSpeed" : this._AtSpeedMsgHandler.bind(this), - "Global.NoSpeed" : this._NoSpeedMsgHandler.bind(this), - "Global.PageUp" : this._PageUpDownMsgHandler.bind(this), - "Global.PageDown" : this._PageUpDownMsgHandler.bind(this), - "vuiState" : this._vuiStateMsgHandler.bind(this), - "vuiMicLevel" : this._vuiStateMsgHandler.bind(this), - "Global.SelectLineNumber" : this._SelectLineNumMsgHandler.bind(this), - "Global.StartHelp" : this._ShowVuiHelpHandler.bind(this), - "Global.HideHelp" : this._HideVuiHelpHandler.bind(this), - "Global.StatusUpdateVolumeOnOff" : this._HandleStatusUpdateVolume.bind(this), - "Global.MenuUpReceived" : this._MenuUpReceived.bind(this) - - }; // end of this._messageTable - //@formatter:on - - - //-- DOM logic - // Add the background image to the body - this._bgDiv1 = document.createElement('div'); - this._rightChrome = document.createElement('div'); - - this._bgDiv1.id = "CommonBgImg1"; - this._bgDiv1.className = "CommonBgImg"; - - this._rightChrome.id = "CommonRightChrome1"; - this._rightChrome.className = "CommonRightChrome"; - this._rightChrome.style.visibility = "hidden"; - - document.body.appendChild(this._bgDiv1); - document.body.appendChild(this._rightChrome); - - // Add controls to the DOM - this.addControls(); -}; - -/* (internal - called by framework) - * Instantiates the LeftBtnControl and StatusBarCtrl (usually only happens when the language is changed) - */ -Common.prototype.addControls = function() -{ - log.debug("addControls called."); - - // Status Bar - if (this.statusBar)//never add more than one instance of these controls - { - log.debug("status bar exists"); - // MPP 08/29/2013 SW00127573 - // Refresh status bar, rather than re-instantiating it, when languages change - //framework.destroyControl(this.statusBar); - //this.statusBar = null; - this.statusBar._refresh(); - } - else - { - log.debug("instantiating status bar"); - // create the status bar - var statusProp = { - "selectCallback" : this._statusBarClicked.bind(this), - "longPressCallback" : this._statusBarLongPress.bind(this) - }; - - this.statusBar = framework.instantiateControl(this.moduleName, document.body, "StatusBarCtrl", statusProp); - } - - // Left Button - if (this.leftBtn) - { - //never add more than one instance of these controls - //framework.destroyControl(this.leftBtn); - //this.leftBtn = null; - } - else - { - // create the left button - var lftBtnProp = {"selectCallback" : this._leftBtnSelected.bind(this)}; - - this.leftBtn = framework.instantiateControl(this.moduleName, document.body, "LeftBtnCtrl", lftBtnProp); - - this._checkTemplateProperties(); - } -}; - -/* (internal - called by framework) - * Destroys the LeftButtonControl and StatusBarCtrl (usually only happens when the language is changed) - */ -Common.prototype.removeControls = function() -{ - if (this.statusBar) - { - framework.destroyControl(this.statusBar); - this.statusBar = null; - } - - if (this.leftBtn) - { - framework.destroyControl(this.leftBtn); - this.leftBtn = null; - } - -}; - -/* - * Checks templates properties for global controls. Called when a language change occurs - */ -Common.prototype._checkTemplateProperties = function() -{ - log.debug("_checkTemplateProperties called."); - var template = this._cachedTemplate; - //we should be able to use the cached template here, because when changing languages, we don't change context - - var data; - if (template) - { - data = this._calcTransitionData(template); - } - else - { - //defaults - log.debug(" No template could be found. Using default values."); - data = new Object(); - data.leftButtonVisible = false; - data.statusBarVisible = true; - } - - log.debug(" Left Btn Visible: " + data.leftButtonVisible + ", Status Bar Visible: " + data.statusBarVisible); - - - if (data.leftButtonVisible) - { - this.leftBtn.divElt.style.visibility = 'visible'; - } - else - { - this.leftBtn.divElt.style.visibility = 'hidden'; - } - - if (data.statusBarVisible) - { - this.statusBar.divElt.style.visibility = 'visible'; - } - else - { - this.statusBar.divElt.style.visibility = 'hidden'; - } - -}; - -/* (internal) - * Called by framework when a context change occurs and data is needed. - * @param template (object) The template that will be transitioned to. - */ -Common.prototype.getCommonTransitionData = function(template) -{ - if (template == null) - { - log.error("getCommonTransitionData called with null template."); - return; - } - - // Terminate any activity timer that may be running so we don't see the - // previous template's status bar or UMP sliding during the transition - this._cleanUpInactivityTimer(); - - this._updateMuteWinkOnTransition(this._cachedTemplate, template); - - this._closeVuiHelpOnTransition(template); - - // tell left button or the previous template to lose focus before the transition starts - this.handleControllerEvent('lostFocus'); - - // cache template: - this._cachedTemplate = template; - - // Hide VUI Numbers - this.leftBtn.hideLineNumbers(); - - // Update _canShowSbns variable and hide active SBN if necessary - this._updateCanShowSbns(); - - var data = this._calcTransitionData(template); - return data; -}; - -/* (private) - * Returns an object with common transition data for the upcoming transition - * @param template (object) The template that will be transitioned to. - * @return (object) Object containing common transition data - */ -Common.prototype._calcTransitionData = function(template) -{ - if (template.properties.customBgImage) - { - if (template.properties.customBgImage != this._currentBgPath) - { - this._bgDiv2 = document.createElement('div'); - this._bgDiv2.id = "CommonBgImg2"; - this._bgDiv2.className = "CommonBgImg"; - this._bgDiv2.style.backgroundImage = "url(" + template.properties.customBgImage + ")"; - this._currentBgPath = template.properties.customBgImage; - document.body.insertBefore(this._bgDiv2, this._bgDiv1); - this._customBgSet = true; - } - } - else if (this._customBgSet == true) // don't transition to default bg on a dialog - { - this._bgDiv2 = document.createElement('div'); - this._bgDiv2.id = "CommonBgImg2"; - this._bgDiv2.className = "CommonBgImg"; - this._bgDiv2.style.backgroundImage = "url(" + this._defaultBgPath + ")"; - this._currentBgPath = this._defaultBgPath; - document.body.insertBefore(this._bgDiv2, this._bgDiv1); - this._customBgSet = false; - } - - // Check for menu up - var menuUpUsed = false; - if (this._menuUpReceiverApp) - { - if (this._menuUpReceiverApp === this._cachedTemplate.contextInfo.uiaId) - { - menuUpUsed = true; - } - this._menuUpReceiverApp = null; - } - - //@formatter:off - var commonTransitionData = { - // references to system control objects - "statusBar" : this.statusBar, - "leftButton" : this.leftBtn, - // booleans - "statusBarVisible" : template.properties.statusBarVisible, - "leftButtonVisible" : template.properties.leftButtonVisible, - "menuUpUsed": menuUpUsed, - // bg data - "customBgImage" : template.properties.customBgImage, - "bgDiv1" : this._bgDiv1, - "bgDiv2" : this._bgDiv2, - // other - "rightChrome" : this._rightChrome, - "rightChromeVisible": (template.properties.rightChromeVisible === true) ? true : false - }; - - if (template.properties.isDialog) - { - // Preserve left button visibility from the previous context when going to a dialog context. - commonTransitionData.leftButtonVisible = this.leftBtn.divElt.style.visibility === "visible"; - commonTransitionData.rightChromeVisible = this._rightChrome.style.visibility === "visible"; - } - - //@formatter:on - return commonTransitionData; -}; - -/* (internal) - * Callback for when the controls transition completes. Currently only used for custom backgrounds - * @param transitionData (object) the data that was used during the transition - */ -Common.prototype.commonControlsUpdateComplete = function(transitionData) -{ - if (transitionData.bgDiv2) - { - // bgDiv2 transitioned in, so we need to remove bgDiv1 - utility.removeHTMLElement(transitionData.bgDiv1.id); - - this._bgDiv1 = this._bgDiv2; - this._bgDiv1.id = "CommonBgImg1"; - this._bgDiv2 = null; - } - - if (framework.getCurrentApp() == "syssettings" && framework.getCurrCtxtId() == "DisplayTab") - { - this.statusBar.enableClockBtn(true); - } - else - { - this.statusBar.enableClockBtn(false); - this._diagEntrySequence = 0; // reset the sequence on context change - } - - // Retrieve the types of input that will count as user activity, and then - // turn on activity monitoring for this context/template (if needed) - this._displaySbUmpActivityTypes = "both"; - if (this._cachedTemplate.properties.displaySbUmpActivityTypes === "both" || - this._cachedTemplate.properties.displaySbUmpActivityTypes === "touch") { - this._displaySbUmpActivityTypes = this._cachedTemplate.properties.displaySbUmpActivityTypes; - } - - this._setDisplaySbUmpByActivityEnabled(this._cachedTemplate.properties.displaySbUmpByActivity == true); - - // show SBN if needed - if (this._canShowSbns) - { - // If there's NO SBN displayed - if (!this._displayedSbnId) - { - // ENTRY POINT #2 - // If a new SBN gets displayed, _displaySbnFromQueue will return the ID - var newSbnId = this._displaySbnFromQueue(); - - if (newSbnId) - { - // Tell Status Bar about the SBN - this._sbnIsDisplayed = true; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - - if (this._cachedTemplate.properties.statusBarVisible) - { - // Snap the status bar visible (only if this template is set to display a status bar) - this.statusBar.transitionVisible(0, 0, "slide", true); - } - - // Notify MMUI to turn on display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 1}}); - } - - } - } - - this.handleControllerEvent('acceptFocusInit'); - -}; - -/* (internal - Called by Controls) - * Sends a "lostFocus" Multicontroller event to the currently focused Control so that the - * Control calling stealFocus() can gain focus. - * After calling this API, the calling Control -must- gain focus automatically. - */ -Common.prototype.stealFocus = function() -{ - var response = null; - - if (this.leftBtn.btnInstance.hasFocus) - { - response = this.leftBtn.handleControllerEvent("lostFocus"); - } - else if (this._cachedTemplate && this._cachedTemplate.handleControllerEvent) - { - response = this._cachedTemplate.handleControllerEvent("lostFocus"); - } - else - { - log.warn("Cannot steal focus. Common's cached template is either null or does not have handleControllerEvent."); - } - - return response; -}; - -/* (internal - Called by framework) - * Handles multicontroller events, specifically the left event for the leftBtn - * @param eventID (string) any of the “Internal event name” values in IHU_GUI_MulticontrollerSimulation.docx (e.g. 'cw', - * 'ccw', 'select') - * @return true if common 'consumed' the tui event. false otherwise. - */ -Common.prototype.handleControllerEvent = function(eventId, firstEvent) -{ - if (eventId == "goBack") // Note: "goBack" event sent from Multicontroller.js indicates the TUI back key has been pressed - { - framework.sendEventToMmui("common", "Global.GoBack"); - } - - // The first event is thrown away, but "controllerActive" is still passed to the template/control to change its highlight - // Thus, "ccw" will come in with firstEvent true, but "controllerActive" will also come in separately with firstEvent false - if (firstEvent) - { - log.debug(" firstEvent detected. Ignoring."); - return; - } - - // Test whether one of Common/Global controls has multicontroller focus and react accordingly - - if (this._cachedTemplate && this._cachedTemplate.handleControllerEvent) - { - // always pass along controller active and touch active - if (eventId != "touchActive" && eventId != "controllerActive") - { - if (this.leftBtn.btnInstance.hasFocus) - { - var response = this.leftBtn.handleControllerEvent(eventId); - if (response == "giveFocusRight") - { - var response = this._cachedTemplate.handleControllerEvent("acceptFocusFromLeft"); - if (response == "consumed") - { - this.leftBtn.handleControllerEvent("lostFocus"); - } - } - } - else - { - var response = this._cachedTemplate.handleControllerEvent(eventId); - if (response == "giveFocusLeft" && this._cachedTemplate.properties.leftButtonVisible) - { - this.leftBtn.handleControllerEvent("acceptFocusFromRight"); - this._cachedTemplate.handleControllerEvent("lostFocus"); - } - } - } - else - { - // always pass along controller active and touch active - if (this.leftBtn) // left button check to prevent race conditions during language change - { - this.leftBtn.handleControllerEvent(eventId); - } - // _cachedTemplate is checked above - this._cachedTemplate.handleControllerEvent(eventId); - - } - - } - else - { - log.warn("Common's cached template is either null or does not have handleControllerEvent."); - } -}; - -/* (internal - Called by framework) - * Handles alert messages from framework, sent by MMUI. - */ -Common.prototype.handleAlert = function(uiaId, alertId, params) -{ - log.debug("handleAlert called."); - - // MMUI should never send two alerts at once. This is a backup check. - if (this._wink) - { - return; - } - - var app = framework.getAppInstance(uiaId); - var properties = null; - - if (app && app.getWinkProperties) // check for App method - { - properties = app.getWinkProperties(alertId, params); - } - - // NOTE: Even though we can't show the Wink, I still call into the GUI App (above) in case they have logic that needs to be done - if (!this._canShowSbns) - { - // We're in a context that can't show Winks. Immediately Ack - framework.websockets.sendAlertCompleteMsg(uiaId, alertId); - return; - } - - if (!properties) // if no properties are set, use the default paragraph style - { - // legacy wink. Use paragraph style. - log.info("No properties returned by app: " + uiaId + ". Using default Wink style."); - properties = { - "style": "style03", - "text1Id": alertId - }; - } - - // no matter what, common should set these properties - properties.winkTimeout = this._winkTimeout; - properties.alertId = alertId; - properties.completeCallback = this._alertComplete.bind(this); - - this._wink = framework.instantiateControl(uiaId, document.body, 'WinkCtrl', properties); - -}; - -/* Called by framework when a data message is sent from Mmui. - * This will pass the message information into any function the app has set in this._messageTable - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype.handleDataMessage = function(msg) -{ - log.debug("GUI COMMON" + " handleDataMessage called for", msg.msgId); - - if (this._messageTable && this._messageTable[msg.msgId]) - { - this._messageTable[msg.msgId](msg); - } - else - { - log.warn("GUI COMMON" + " No message handler for", msg.msgId); - } -}; - - -/* - * Handler for LanguageChangeStatus message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._LanguageChangeStatusMsgHandler = function(msg) -{ - if (msg && msg.params && msg.params.payload && msg.params.payload.languageID) - { - var langCode = framework.localize.getLangInGuiFormat(msg.params.payload.languageID); - } - - if (msg && msg.params && msg.params.payload && msg.params.payload.status) - { - var status = msg.params.payload.status; - } - - var bStatus = false; - - if (status == "Success") - { - bStatus = true; - } - else - { - bStatus = false; - } - - // Call unload dictionaries - framework.localize.unloadDictionaries(langCode,bStatus); -}; - -/* - * Handler for AtSpeed message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._AtSpeedMsgHandler = function(msg) -{ - log.info("Common.prototype._AtSpeedMsgHandler called",msg); - this._atSpeed = true; - framework.sendMsgToFocusedApp(msg); -}; - -/* - * Handler for NoSpeed message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._NoSpeedMsgHandler = function(msg) -{ - log.info("Common.prototype._NoSpeedMsgHandler called",msg); - this._atSpeed = false; - framework.sendMsgToFocusedApp(msg); -}; - -/* - * Handler for PageUp & PageDown messages - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._PageUpDownMsgHandler = function(msg) -{ - log.debug("Common.prototype._PageUpDownMsgHandler called", msg); - - // Assume no list exists - var result = "NoList"; - var eventName = null; - var apiName = null; - - // Determine the result event name, based on the incoming message - // (independent of anything to do with a list) - switch (msg.msgId) - { - case "Global.PageUp": - eventName = "Global.PageUpResult"; - apiName = "pageUp"; - break; - case "Global.PageDown": - eventName = "Global.PageDownResult"; - apiName = "pageDown"; - break; - default: - log.error("_PageUpDownMsgHandler called with non-pagination event!"); - break; - } - - // If we have a list and an API on it to call, ... - if (this._cachedTemplate && this._cachedTemplate.templateName === "List2Tmplt" && this._cachedTemplate.list2Ctrl && apiName) - { - // ... call that API! - response = this._cachedTemplate.list2Ctrl[apiName](); - result = response.charAt(0).toUpperCase() + response.slice(1); // make sure first letter is uppercase - } - - // Compose result & send to MMUI - if (eventName) - { - var params = { - "payload": { - "pageStatus": result - } - }; - - framework.sendEventToMmui("common", eventName, params); - } -}; - -/* - * Handler for VUI Mic messages - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._vuiStateMsgHandler = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - if (msg.msgId == "vuiState") - { - var showLineNumbers = false; - this._cachedVuiState = msg.params.payload.state; - // End the current SBN in case we need to change styles - this.endStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - switch(this._cachedVuiState) - { - case "Not Ready": // intentional fall-through - case "Idle": - case "Playing Out of Session Alert": - // Do nothing. SBN is automatically ended - break; - case "Playing Prompt": - // Show "Wait for Tone" SBN - var properties = { - "sbnStyle": "Style02", - "imagePath1": "IcnSbnMicClosed.png", - "text1Id": "common.SbnWaitForTone" - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - showLineNumbers = true; - break; - case "Listening": - // Show sound meter SBN starting at 0 - var properties = { - "sbnStyle": "Style04", - "imagePath1": "IcnSbnMicOpen.png", - "meter": {"meterType": "audio02", "min": 0, "max": 4000, "currentValue": 0} - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - showLineNumbers = true; - break; - case "Processing": // Intentional fallthrough. Show SBN with icon only - case "Playing Terminating Prompt": - // Show SBN with icon only - var properties = { - "sbnStyle": "Style02", - "imagePath1": "IcnSbnMicClosed.png", - "text1": null - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - break; - default: - log.warn("Unknown VUI State was sent to GUI: " + this._cachedVuiState); - break; - } - - this._showHideLineNumbers(showLineNumbers); - } - else if (msg.msgId == "vuiMicLevel") - { - var micLevel = parseInt(msg.params.payload.micLevel); - // clamp the micLevel value. SBN meter does not support negative numbers - micLevel += 3000; - // Adjust very low mic values to show 1-2 bars - if (micLevel < -2100) - { - micLevel = 50; - } - else if (micLevel < 100) - { - micLevel = 100; - } - - if (this._cachedVuiState == "Listening") - { - // Update state-based SBN with current mic level - var properties = { - "sbnStyle": "Style04", - "imagePath1": "IcnSbnMicOpen.png", - "meter": {"meterType": "audio02", "min": 0, "max": 4000, "currentValue": micLevel} - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - } - } - } -}; - -/* - * Handler for SelectLineNumber message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._SelectLineNumMsgHandler = function(msg) -{ - log.debug("Common.prototype._SelectLineNumMsgHandler called", msg); - - if (msg && msg.params && msg.params.payload) - { - var number = msg.params.payload.lineNumber; - } - else - { - return; - } - - var result = "NoList"; // status to send back to MMUI (default to NoList) - - // Is the current template a list? - if (this._cachedTemplate && this._cachedTemplate.templateName == "List2Tmplt") - { - // Does the list have data and support VUI? - if (this._cachedTemplate.list2Ctrl.dataList && this._cachedTemplate.list2Ctrl.dataList.vuiSupport == true) - { - log.info("Sending Line Number to List: " + number); - // List will return a result - var response = this._cachedTemplate.list2Ctrl.selectLine(number); - - if (response == "selected") - { - return; // No event from Common if "selected" is response - } - - result = response.charAt(0).toUpperCase() + response.slice(1); // first letter uppercase - } - } - - log.info("SelectLineResult is ", number, result); - var params = { - "payload" : { - "lineNumber": number, - "lineStatus": result - } - }; - framework.sendEventToMmui("common", "Global.SelectLineResult", params); -}; - -/* - * Handler for Global.StartHelp message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._ShowVuiHelpHandler = function(msg) -{ - log.debug("Common.prototype._ShowVuiHelpHandler called", msg); - - // Hide any currently displayed VUI Help - this._HideVuiHelpHandler(msg); - - // Validate that this help overlay request is for the currently displayed context. - if (framework.getCurrentApp() === msg.params.payload.currentUiaId && - framework.getCurrCtxtId() === msg.params.payload.currentContextId) - { - // Try to load a VUI Help configuration and display it if found - var targetUiaId = msg.params.payload.uiaId; - var helpPromptName = msg.params.payload.helpPromptName; - var dialogProperties = this._getVuiHelpDialogConfiguration(targetUiaId, helpPromptName); - if (dialogProperties) - { - this._vuiHelpDialog = framework.instantiateControl(dialogProperties.uiaId, document.body, 'Dialog3Ctrl', dialogProperties.dialogConf); - this._vuiHelpDialog.divElt.classList.add("Dialog3Ctrl_Style19_NoTemplateInstance"); - - // Add properties to the control to record the uiaId and contextId. See also _closeVuiHelpOnTransition(). - this._vuiHelpDialog._uiaId = msg.params.payload.currentUiaId; - this._vuiHelpDialog._contextId = msg.params.payload.currentContextId; - } - } - else - { - log.warn("Ignoring Global.StartHelp message because GUI is in context '" - + framework.getCurrentApp() - + " " - + framework.getCurrCtxtId() - + "' but the message is for a different context: " - + JSON.stringify(msg)); - } -}; - -/* - * Handler for Global.HideHelp message - * @tparam Object msg (optional) The parsed message object sent from Mmui - */ -Common.prototype._HideVuiHelpHandler = function(msg) -{ - log.debug("Common.prototype._HideVuiHelpHandler called"); - - if (this._vuiHelpDialog) - { - framework.destroyControl(this._vuiHelpDialog); - this._vuiHelpDialog = null; - } -}; - -/* - * Close Vui Help at the start of a transition to a new template if that template represents a different context. - */ -Common.prototype._closeVuiHelpOnTransition = function(template) -{ - if (this._vuiHelpDialog - && template - && template.contextInfo.uiaId != this._vuiHelpDialog._uiaId - && template.contextInfo.ctxtId != this._vuiHelpDialog._contextId) - { - this._HideVuiHelpHandler(null); - } -}; - -/* - * Returns a configuration object for a VUI help dialog3 control prompt from an app's dictionary. - * Returns null if no prompt text is found in the dictionary. - * @tparam String uiaId The application requesting the VUI help. - * @tparam String helpPromptName The name of the help prompt to look for in the dictionary. - */ -Common.prototype._getVuiHelpDialogConfiguration = function(uiaId, helpPromptName) -{ - var config = { - dialogConf: { - contentStyle: "style19", - titleStyle : "titleStyle03" - }, - uiaId: uiaId - }; - var found = false; - - // When help prompt name which requires default default help screen is received show system/Home help screen - if (this._defaultHelpPrompt === helpPromptName) - { - helpPromptName = "HomeScreen_Help"; - uiaId = "system"; - config.uiaId = uiaId; - } - - // Dictionary strings for a VUI help prompt have specific computable stringIds. - for (var i = 1; i <= 5; ++i) - { - var leftStringId = "VrHelp_" + helpPromptName + "_Left" + i; - if (framework.localize.testLocStr(uiaId, leftStringId)) - { - config.dialogConf["text" + i.toString() + "Id"] = leftStringId; - found = true; - } - - var rightStringId = "VrHelp_" + helpPromptName + "_Right" + i; - if (framework.localize.testLocStr(uiaId, rightStringId)) - { - config.dialogConf["text" + (i + 5).toString() + "Id"] = rightStringId; - } - } - - if (found) - { - var titleId = "VrHelp_" + helpPromptName + "_Title"; - if (framework.localize.testLocStr(uiaId, titleId)) - { - config.dialogConf.titleId = titleId; - } - else - { - // No title found in dictionary -- use default title - config.dialogConf.titleId = "common.VuiHelpDefaultTitle"; - } - } - - return (found) ? config : null; -}; - -/* - * Function called by apps to determine if vehicle is at speed - * @return Boolean true if vehicle is at speed - */ -Common.prototype.getAtSpeedValue = function() -{ - return this._atSpeed; -}; - -/* - * Tells the status bar to show/hide the Home button - * @param show Boolean true if the home button should be displayed. false if it should be hidden. - */ -Common.prototype.showSbHomeButton = function(show) -{ - this.statusBar.showHomeBtn(show); -}; - -/* - * (internal) Called by framework. Sets the App name text/image in the status bar - * @param label String Literal text name or image path to display in the status bar - */ -Common.prototype.setSbName = function(label) -{ - // setAppName() will differentiate between text & imagery - this.statusBar.setAppName(label); -}; - -/* - * (internal) Called by framework. Sets the translated App name text in the status bar - * @param uiaId String UiaId of the App the string should be translated for - * @param labelId String StringID to be translated - * @param subMap Object Optional subMap to be placed in the text - */ -Common.prototype.setSbNameId = function(uiaId, labelId, subMap) -{ - this.statusBar.setAppNameId(uiaId, labelId, subMap); -}; - -/* - * (internal) Called by framework. Sets the icon between the Home Button and the App Name in the status bar - * @param path String Path from index.html to icon. Pass null to remove current icon - */ -Common.prototype.setSbDomainIcon = function(path) -{ - this.statusBar.setDomainIcon(path); -}; - -/* - * Updates the state of a Status Bar Icon - * @param name String Base Icon name ("Batt", "PhoneSignal", "Roaming", "Traffic", "WifiSignal", "Music", "Bluetooth", "Message") - * @param visible Boolean True if the icon should be shown. False if it should be hidden - * @param state String (Optional) String corrsponding to the state of the icon ("00", "01", "02", "03", "04", "05") - */ -Common.prototype.setSbIcon = function(name, visible, state) -{ - this.statusBar.setIcon(name, visible, state); -}; - -/* - * Utility API for enabling/disabling auto-hide behavior for status bar & UMP - * @param isEnabled Boolean Auto-hides the status bar and UMP by internal inactivity timer (when true) - */ -Common.prototype._setDisplaySbUmpByActivityEnabled = function(isEnabled) -{ - this._displaySbUmpByActivity = isEnabled; - - if (this._displaySbUmpByActivity) { - // remove any existing non-transparent div - if (this._nonTransparentDiv) - { - utility.removeHTMLElement(this._nonTransparentDiv); - this._nonTransparentDiv = null; - } - - // create a non-transparent div so that opera receives touch events - this._nonTransparentDiv = document.createElement('div'); - this._nonTransparentDiv.className = "CommonNonTransparentDiv"; - document.body.insertBefore(this._nonTransparentDiv, document.body.firstChild); - - // Detect activity to kick everything off - this.activityDetected(true, null); - } - else - { - // Remove the non-transparent div - utility.removeHTMLElement(this._nonTransparentDiv); - this._nonTransparentDiv = null; - - // Shut down any timer we may have running - this._cleanUpInactivityTimer(); - - // Set the activity flag to "true" to force status bar & UMP visibility - this._activityDetected = true; - this._updateSbUmpVisibility(); - - // Reset the activity detected flag - this._activityDetected = false; - } - - // Ignore any prior external show/hide requests - this._sbRequestedState = "none"; -}; - -/* - * Public API for external applications (e.g. TV) to request that the status bar be shown - * @param delay_ms Integer The number of milliseconds to wait before starting the status bar animation - * @param duration_ms Integer The number of milliseconds the status bar animation should take to complete - * @param receipt_cb Function The function to call to signal receipt of the request - */ -Common.prototype.requestStatusBarShown = function(delay_ms, duration_ms, receipt_cb) -{ - log.debug("requestStatusBarShown(" + delay_ms + ", " + duration_ms + ")"); - - // Cache requested status bar timings - if ((utility.toType(delay_ms) == "number") && - (delay_ms >= 0)) { - // Store custom delay timing - this._sbDelay_ms = delay_ms; - } - else { - // Store default delay timing - this._sbDelay_ms = this._defaultSbDelay_ms; - } - if ((utility.toType(duration_ms) == "number") && - (duration_ms >= 0)) { - // Store custom duration timing - this._sbDuration_ms = duration_ms; - } - else { - // Store default duration timing - this._sbDuration_ms = this._defaultSbDuration_ms; - } - - // Remember the external request - this._sbRequestedState = "shown"; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - - // If a receipt callback was provided, ... - if (utility.toType(receipt_cb) === "function") { - // Call it to signal receipt of the request - receipt_cb(); - } -}; - -/* - * Public API for external applications (e.g. TV) to request that the status bar be hidden - * @param delay_ms Integer The number of milliseconds to wait before starting the status bar animation - * @param duration_ms Integer The number of milliseconds the status bar animation should take to complete - * @param receipt_cb Function The function to call to signal receipt of the request - */ -Common.prototype.requestStatusBarHidden = function(delay_ms, duration_ms, receipt_cb) -{ - log.debug("requestStatusBarHidden(" + delay_ms + ", " + duration_ms + ")"); - - // Cache requested status bar timings - if ((utility.toType(delay_ms) === "number") && - (delay_ms >= 0)) { - // Store custom delay timing - this._sbDelay_ms = delay_ms; - } - else { - // Store default delay timing - this._sbDelay_ms = this._defaultSbDelay_ms; - } - if ((utility.toType(duration_ms) === "number") && - (duration_ms >= 0)) { - // Store custom duration timing - this._sbDuration_ms = duration_ms; - } - else { - // Store default duration timing - this._sbDuration_ms = this._defaultSbDuration_ms; - } - - // Remember the external request - this._sbRequestedState = "hidden"; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - - // If a receipt callback was provided, ... - if (utility.toType(receipt_cb) == "function") { - // Call it to signal receipt of the request - receipt_cb(); - } -}; - -/* - * Public hook for notification (from Multicontroller.js) about user activity (touch/keyboard/multicontroller input) - * @param isActive (Boolean) Flag indicating if activity is detected (true) or not (false) - * @param evt (Object) The Opera event that generated the activity - * @param tuiEvent (String) If this is a multicontroller action, the corresponding eventId will be passed - */ -Common.prototype.activityDetected = function(isActive, evt, tuiEvent) -{ - // If we're using local timing ... - if (this._displaySbUmpByActivity) - { - // Get the current position & height of the status bar - // (so we can detect if we've selected it or not) - var det = this.statusBar.divElt.offsetTop; - var deh = this.statusBar.divElt.offsetHeight; - - var legalEvent = false; // will be set to true if this event can trigger activity given the configuration - - // If we have no event, or we have a legal event and the status bar itself wasn't selected, ... - if (evt == null) - { - // null event is used for special case private calls within Common.js - legalEvent = true; - } - else if (evt.type == "mouseup" || evt.type == "mousedown") - { - // mouse events can trigger on "touch" or "both", but only if they are not on the Status Bar - if (this._displaySbUmpActivityTypes == "both" || this._displaySbUmpActivityTypes == "touch") - { - if (evt.pageX <= 800) - { - if (evt.pageY >= (det + deh)) - { - legalEvent = true; - } - else if (evt.type == "mouseup") - { - // mouse up occurred in the status bar. Very specific case to account for touch-and-drag - legalEvent = true; - } - } - } - - } - else if (evt.type == "keydown" || evt.type == "keyup" || evt.type == "mousewheel") - { - // Multicontroller event can only trigger if the activity type is "both" - if (this._displaySbUmpActivityTypes == "both") - { - legalEvent = true; - } - } - - if (legalEvent) - { - log.debug("activityDetected()", isActive, evt); - - // Check if the activity state has changed - var stateChanged = (this._activityDetected != isActive); - - // Update the internal activity state - this._activityDetected = isActive; - - // (Re)start the timer to measure inactivity - if (this._activityDetected) { - // a press down via touch or MC should not trigger the Inactivity timeout - var triggerTimer = true; - if (evt != null) - { - if (evt.type == "mousedown") - { - triggerTimer = false; - } - else if (evt.type == "keydown") - { - // Exception: rotations should still trigger the Inactivity timeout - if (tuiEvent != "cw" && tuiEvent != "ccw") - { - triggerTimer = false; - } - } - } - - if (triggerTimer == false) - { - // just clean up the timer - this._cleanUpInactivityTimer(); - } - else - { - this._startInactivityTimer(); - } - } - - // If the activity state changed, ... - if (stateChanged) { - // ... update the controls' visibility - this._updateSbUmpVisibility(); - } - } - } -}; - -Common.prototype._startInactivityTimer = function() -{ - // Clean up any existing inactivity timer - this._cleanUpInactivityTimer(); - - if (this._displaySbUmpByActivity) { - // (Re)start inactivity timer for a 3-second wait - this._inactivityTimer = setTimeout(this._onInactivityBinder, 3000); - } -}; - -Common.prototype._onInactivity = function() -{ - // Clear the timer that got us here - this._cleanUpInactivityTimer(); - - if (this._displaySbUmpByActivity) { - // Local inactivity timer has expired -- lower the flag - this._activityDetected = false; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - } -}; - -Common.prototype._cleanUpInactivityTimer = function() -{ - if (this._inactivityTimer != null) { - // Clean up any existing inactivity timer - clearTimeout(this._inactivityTimer); - this._inactivityTimer = null; - } -}; - -Common.prototype._updateSbUmpVisibility = function() -{ - if (this._displaySbUmpByActivity || this._sbRequestedState != "none") - { - log.debug("_updateSbUmpVisibility()"); - log.debug("this._sbRequestedState = " + this._sbRequestedState); - log.debug("this._activityDetected = " + this._activityDetected); - log.debug("this._sbnIsDisplayed = " + this._sbnIsDisplayed); - - // Default values for status bar animation timing - var delay_ms = this._defaultSbDelay_ms; - var duration_ms = this._defaultSbDuration_ms; - - // Are the conditions right for showing the status bar? - if ((this._cachedTemplate.properties.statusBarVisible) && ((this._sbRequestedState === "shown") || this._activityDetected || this._sbnIsDisplayed)) { - // Yes -- show it - if (this._sbRequestedState === "shown") { - // Use custom timings from external request - delay_ms = this._sbDelay_ms; - duration_ms = this._sbDuration_ms; - } - - // Show the status bar - this.statusBar.transitionVisible(delay_ms, duration_ms, "slide", true); - } - else if ((this._sbRequestedState == "hidden" || !this._activityDetected) && !this._sbnIsDisplayed) { - // No -- hide it - if (this._sbRequestedState == "hidden") { - // Use custom timings from external request - delay_ms = this._sbDelay_ms; - duration_ms = this._sbDuration_ms; - } - - // Hide the status bar - this.statusBar.transitionVisible(delay_ms, duration_ms, "slide", false); - } - - if (this._activityDetected) { - // Call template's "showing started" callback, if available - if (utility.toType(this._cachedTemplate["onActivityShowing"]) == "function") { - this._cachedTemplate.onActivityShowing(delay_ms, duration_ms); - } - } - else { - // Call template's "hiding started" callback, if available - if (utility.toType(this._cachedTemplate["onActivityHiding"]) == "function") { - this._cachedTemplate.onActivityHiding(delay_ms, duration_ms); - } - } - - // Reset the externally-requested timings to default -- if the status bar was actually shown/hidden - // on this call, the timings were already used. Otherwise, the status bar couldn't be changed (e.g. - // an SBN was displayed), so the timings need to be reset for the next pass. - this._sbDelay_ms = this._defaultSbDelay_ms; - this._sbDuration_ms = this._defaultSbDuration_ms; - } -}; - -/* - * Adds a timed Sbn with the given properties to the Status Bar queue - */ -Common.prototype.startTimedSbn = function(uiaId, sbnId, type, properties) -{ - log.debug("Timed SBN requested by " + uiaId + " with id: " + sbnId); - - var uniqueId = uiaId + sbnId; - this._requestNewSbn(uiaId, uniqueId, type, properties, true); -}; - -/* - * Removes a timed Sbn with the given properties to the Status Bar queue - */ -Common.prototype.cancelTimedSbn = function(uiaId, sbnId, type) -{ - var uniqueId = uiaId + sbnId; - - if (utility.toType(sbnId) != 'string' || !this._knownSbns[uniqueId]) - { - log.debug("Cannot cancel unknown sbnId: " + sbnId + " for App: " + uiaId); - return; - } - - // set the expiration to the current time. this will remove the SBN when it comes up in queue, but - // will not remove it if it is already being displayed - this._knownSbns[uniqueId].expiration = new Date().getTime(); -}; - -/* - * Adds a state-based Sbn with the given properties to the Status Bar queue - */ -Common.prototype.showStateSbn = function(uiaId, sbnId, type, properties) -{ - log.debug("State-based SBN requested by " + uiaId + " with id: " + sbnId); - - var uniqueId = uiaId + sbnId; - this._requestNewSbn(uiaId, uniqueId, type, properties, false); -}; - -/* - * Removes a state-based Sbn with the given properties to the Status Bar queue - */ -Common.prototype.endStateSbn = function(uiaId, sbnId, type) -{ - var uniqueId = uiaId + sbnId; - - if (utility.toType(sbnId) != 'string' || !this._knownSbns[uniqueId]) - { - log.debug("Cannot end unknown sbnId: " + sbnId + " for App: " + uiaId); - return; - } - - log.debug("Ending State SBN: " + sbnId + " for App: " + uiaId); - - // If it is currently being displayed, remove it - if (uniqueId == this._displayedSbnId) - { - this._removeDisplayedSbn(); - } - else if (this._sbnQueue.indexOf(uniqueId) != -1) - { - // if in queue, remove from queue - this._sbnQueue.splice(this._sbnQueue.indexOf(uniqueId), 1); - } - - // if none displayed, display first in queue - if (!this._displayedSbnId) - { - this._displaySbnFromQueue(); - } -}; - -/* - * Sets how many numbers are shown in the LeftButton chrome. Called by List any time - * the visible line count changes - * @param count Number Integer indicating how many line numbers should be shown. - * @param style String Left Button VUI Number style (see Left Button SDD for information) - */ -Common.prototype.setLineNumbers = function(count, style) -{ - if (utility.toType(count) != 'number' || utility.toType(style) != 'string') - { - log.warn("Type error: setLineNumbers must be called with count as integer and style as string"); - return; - } - - this._lineNumberData = {"count": count, "style": style}; - - var showLineNumbers = false; - switch(this._cachedVuiState) - { - case "Not Ready": - break; - case "Idle": - break; - case "Playing Out of Session Alert": - break; - case "Playing Prompt": - // Show "Wait for Tone" SBN - showLineNumbers = true; - break; - case "Listening": - // Show sound meter SBN starting at 0 - showLineNumbers = true; - break; - case "Processing": - // Show SBN with no text or meter - break; - case "Playing Terminating Prompt": - // Show SBN with no text or meter - break; - default: - break; - } - - this._showHideLineNumbers(showLineNumbers); -}; - -/* - * Show or hide the line numbers. - * @param showLineNumbers (Boolean) Show line numbers if the current template supports line numbers. - */ -Common.prototype._showHideLineNumbers = function(showLineNumbers) -{ - if (showLineNumbers == true && this._lineNumberData != null) - { - // validate that this is a List and the List is configured to show line numbers - if (this._cachedTemplate && this._cachedTemplate.templateName == "List2Tmplt") - { - if ((this._cachedTemplate.list2Ctrl.dataList) && - (this._cachedTemplate.list2Ctrl.dataList.vuiSupport == true) && - (this._cachedTemplate.list2Ctrl.properties.numberedList == true) && - (this._cachedTemplate.list2Ctrl.dataList.hasOwnProperty('itemCount') && this._cachedTemplate.list2Ctrl.dataList.itemCount > 0)) - { - this.leftBtn.showLineNumbers(this._lineNumberData.count, this._lineNumberData.style); - } - - } - } - else - { - this.leftBtn.hideLineNumbers(); - } -}; - -/* - * Update this._canShowSbns based on a the cached template. - */ -Common.prototype._updateCanShowSbns = function() -{ - if (this._cachedTemplate.contextInfo.uiaId == "system" && this._cachedTemplate.contextInfo.ctxtId == "DisplayOff") - { - // A special case where the context does not have a status bar but we still need to show SBNs. - this._canShowSbns = true; - } - else if (this._cachedTemplate.properties.statusBarVisible == false) - { - // Do not display SBNs if there is no status bar - this._canShowSbns = false; - } - else if (this._cachedTemplate.contextInfo.uiaId == "ecoenergy" && - (this._cachedTemplate.contextInfo.ctxtId == "EndingFuelConsumption" || this._cachedTemplate.contextInfo.ctxtId == "EndingEffectiveness")) - { - this._canShowSbns = false; - } - else - { - this._canShowSbns = true; - } - - log.debug("Can show SBNs?", this._canShowSbns); - - if (this._canShowSbns == false) - { - // Remove and requeue any displayed SBN - if (this._displayedSbnId) - { - var temp = this._removeDisplayedSbn(); - this._addSbnToQueue(temp, "top"); - } - - // Also remove any displayed Wink - this._removeWinkHelper(); - } -}; - -/* - * helper function to check whether given sbn type is valid - * @param type String type of the SBN - */ -Common.prototype._isValidSbnType = function(type) -{ - var isValidSbnType = false; - if (this._SBN_TYPES[type] != null) - { - isValidSbnType = true; - } - return isValidSbnType; -}; - -/* - * helper function to check whether given sbn type is old one - * @param type String old type of the SBN - */ -Common.prototype._isValidConversionType = function(type) -{ - var isValidConversionType = false; - if (this._SBN_MAPPING_TABLE[type] != null) - { - isValidConversionType = true; - } - return isValidConversionType; -}; - -/* - * helper function to convert old sbn type into valid type - * @param type String old type of the SBN - */ -Common.prototype._convertToValidSbnType = function(type) -{ - var validType; - if (this._isValidConversionType(type)) - { - validType = this._SBN_MAPPING_TABLE[type]; - } - else - { - validType = "unknown"; - log.error("SBN type " + type + " is not valid. Using " + validType + " as a default. See System Specs for possible sbn types"); - } - return validType; -}; - -/* - * Helper function to reduce duplicate logic - */ -Common.prototype._requestNewSbn = function(uiaId, sbnId, type, properties, isTimed) -{ - if (utility.toType(sbnId) != 'string') - { - log.error("Given sbnId was not of valid type 'string'. Please give valid sbnId."); - return; - } - - if (utility.toType(type) != 'string') - { - log.error("Given SBN type must be a string from the table in GUI Common. See Common SDD for possible types."); - } - - if (false == this._isValidSbnType(type)) - { - type = this._convertToValidSbnType(type); - } - - //blacklist will now contain new letter based sbn type, so this check is moved after the type conversion - if (this._SBN_TYPE_BLACKLIST.indexOf(type) != -1) - { - log.debug("Request for blacklisted SBN type:", type, "has been blocked"); - return; - } - - // if already in queue or displayed, update sbn - if (sbnId == this._displayedSbnId) - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - this._displayedSbn.setSbnConfig(properties); // Call API to do live update on Control - - if (isTimed) - { - // extend the timer - clearTimeout(this._displayedSbnTimerId); - this._displayedSbnTimerId = setTimeout(this._sbnFinished.bind(this), this._knownSbns[sbnId].duration); - } - } - else if (this._sbnQueue.indexOf(sbnId) != -1) - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - } - else // if !in queue and !displayed, it's new and we need to check it for priority - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - - // If there's an SBN currently displayed... - if (this._displayedSbnId) - { - // Get priority level of this sbnId - var priority = this._knownSbns[sbnId].priority; - var queueTime = this._SBN_TYPES[type] != null ? this._SBN_TYPES[type].queueTime : this._SBN_TYPES.unknown.queueTime; - var replaceDisplayed = false; - - if (queueTime > 0) - { - // these SBNs DO queue and therefore SBNs of the same priority level should NOT clobber each other - if (priority < this._knownSbns[this._displayedSbnId].priority) // lower # is higher priority - { - replaceDisplayed = true; - } - } - else - { - // these SBNs do NOT queue and therefore SBNs of the same priority level should clobber each other - if (priority <= this._knownSbns[this._displayedSbnId].priority) // lower # is higher priority - { - replaceDisplayed = true; - } - } - - if (replaceDisplayed == true) - { - // call to this._removeDisplayedSbn() will set this._displayedSbnId to null and return displayed Id - var temp = this._removeDisplayedSbn(); - - this._displaySbn(sbnId); // the new one has higher priority and should be displayed - - this._addSbnToQueue(temp, "top"); // old SBN has been replaced and should be added to the queue (top if same priority level) - } - else - { - // new sbnId has lower priority and gets queued - this._addSbnToQueue(sbnId, "bottom"); - } - - } - else // display the new SBN. Some SBNs never go in the queue - { - if (!this._canShowSbns) - { - this._addSbnToQueue(sbnId, "bottom"); - } - else - { - // Tell Status Bar about the SBN - this._sbnIsDisplayed = true; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - - if (this._cachedTemplate.properties.statusBarVisible) - { - // Snap the status bar visible (only if this template is set to display a status bar) - this.statusBar.transitionVisible(0, 0, "slide", true); - } - - // ENTRY POINT #1 - // immediately display this SBN without adding it to the queue - this._displaySbn(sbnId); - - // Notify MMUI to turn on display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 1}}); - } - } - } - - if (this._canShowSbns && !this._displayedSbnId) - { - this._displaySbnFromQueue(); // The new SBN should be the first in queue (if something was displayed) - } -}; - -/* - * Helper function to add Sbns to the queue - * @param sbnId String Unique ID of the SBN to add to the queue - * @param queueOrder String Identifies where to place an SBN in case they are the same priority level ("top" or "bottom") - */ -Common.prototype._addSbnToQueue = function(sbnId, queueOrder) -{ - if (sbnId == null) - { - log.error("_addSbnToQueue: Cannot add null sbnId to queue."); - return; - } - if (!this._knownSbns[sbnId]) - { - log.error("Attempt to add Sbn to queue failed: Could not identify Sbn", sbnId, "in knownSbns variable."); - return; - } - - var currTime = new Date().getTime(); - // state-based SBNs do not expire. An SBN that is Timed and expired does not need to be added to the queue. It would just be removed later anyway. - if (this._knownSbns[sbnId].isTimed && currTime >= this._knownSbns[sbnId].expiration) - { - log.debug("SBN", sbnId, "has expired. No reason to add it to queue"); - return; - } - - // Get priority level of this sbnId - var priority = this._knownSbns[sbnId].priority; - - // Use queuePos so we don't modify the array while looping through it. - var queuePos = this._sbnQueue.length; // default to Array.length so that splice will add it to the end of the Array. - - // Add to queue in appropriate spot - for (var i = 0; i < this._sbnQueue.length; i++) - { - if (queueOrder == "top") - { - if (priority <= this._knownSbns[this._sbnQueue[i]].priority) // lower # is higher priority - { - // insert into queue - queuePos = i; - break; // cut in line and we're done - } - } - else - { - if (priority < this._knownSbns[this._sbnQueue[i]].priority) // lower # is higher priority - { - // insert into queue - queuePos = i; - break; // cut in line and we're done - } - } - - } - - this._sbnQueue.splice(queuePos, 0, sbnId); // at queuePos, remove 0, add sbnId - -}; - -/* - * Helper function that creates or updates an Sbn Object to add to/update the knownSbns variable. - */ -Common.prototype._setKnownSbn = function(uiaId, sbnId, type, properties, isTimed) -{ - var expiration = new Date(); - var priority = 0; - var duration = 0; - - // if type is known, use its properties - if (!this._SBN_TYPES[type]) - { - log.warn("Priority level of Sbn type: " + type + " is unknown. Setting priority to lowest level."); - type = "unknown"; - } - - expiration.setTime(expiration.getTime() + this._SBN_TYPES[type].queueTime); - priority = this._SBN_TYPES[type].priority; - duration = this._SBN_TYPES[type].timedDuration; - - this._knownSbns[sbnId] = { - "uiaId" : uiaId, - "type": type, - "priority": priority, - "isTimed": isTimed, - "duration": duration, // duration is only used for timed Sbns - "expiration": expiration.getTime(), // Set an expiration time stamp for each Sbn - "properties": properties - }; -}; - -/* - * Immediately displays the SBN with the given sbnId - */ -Common.prototype._displaySbn = function(sbnId) -{ - if (!this._knownSbns[sbnId]) - { - log.error("Cannot display requested SBN: " + sbnId + ". SBN cannot be found in knownSbns variable."); - return; - } - - if (!this._canShowSbns) - { - // safety check. We should never get here. - log.debug("Cannot show new SBNs in this context."); - return; - } - - log.info("Displaying new sbn: " + sbnId); - this._displayedSbnId = sbnId; - this._displayedSbn = framework.instantiateControl(this._knownSbns[sbnId].uiaId, document.body, "SbnCtrl", this._knownSbns[sbnId].properties); - if (this._knownSbns[sbnId].isTimed) - { - this._displayedSbnTimerId = setTimeout(this._sbnFinished.bind(this), this._knownSbns[sbnId].duration); - } -}; - -/* - * Immediately destroys and removes the currently displayed SBN - * @return String Returns the sbnId of the SBN that was removed - */ -Common.prototype._removeDisplayedSbn = function() -{ - log.info("Removing currently displayed SBN: " + this._displayedSbnId); - clearTimeout(this._displayedSbnTimerId); - framework.destroyControl(this._displayedSbn); - - var removedId = this._displayedSbnId; - this._displayedSbn = null; - this._displayedSbnId = null; - - return removedId; -}; - -/* - * Chooses the first active SBN off the queue and displays it. - * @return String The ID of the new SBN that gets displayed. null of no SBN is displayed. - */ -Common.prototype._displaySbnFromQueue = function() -{ - var newSbnToDisplay = null; - if (!this._canShowSbns) - { - // safety check. We should never get here. - log.debug("Cannot show queued SBNs in this context."); - return newSbnToDisplay; - } - - if (this._sbnQueue.length == 0) - { - // nothing to display: EXIT POINT #1 - this._sbnIsDisplayed = false; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - this._updateSbUmpVisibility(); - - // Notify MMUI to turn off display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 0}}); - return newSbnToDisplay; - } - - var sbnId = null; - var flaggedForRemoval = new Array(); - - // check expiration - var currTime = new Date().getTime(); - - for (var i = 0; i < this._sbnQueue.length; i++) - { - sbnId = this._sbnQueue[i]; - - // state-based SBNs do not expire. An SBN in the queue that is state-based or -not- expired should be displayed immediately - if (this._knownSbns[sbnId].isTimed && currTime >= this._knownSbns[sbnId].expiration) - { - flaggedForRemoval.push(sbnId); - } - else - { - this._displaySbn(sbnId); - newSbnToDisplay = sbnId; - flaggedForRemoval.push(sbnId); - break; - } - } - - // splice any expired SBNs from the queue - for (var j = 0; j < flaggedForRemoval.length; j++) - { - this._sbnQueue.splice(this._sbnQueue.indexOf(flaggedForRemoval[j]), 1); // remove from queue - - if (flaggedForRemoval[j] != this._displayedSbnId) - { - delete this._knownSbns[flaggedForRemoval[j]]; // delete from known Sbns - } - } - - flaggedForRemoval = null; - - if (this._sbnQueue.length == 0 && !this._displayedSbnId) - { - // no more SBNs to display: EXIT POINT #2 - this._sbnIsDisplayed = false; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - this._updateSbUmpVisibility(); - - // Notify MMUI to turn off display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 0}}); - } - - return newSbnToDisplay; -}; - -/* - * Callback for when a timed SBN completes - */ -Common.prototype._sbnFinished = function() -{ - this._removeDisplayedSbn(); - this._displaySbnFromQueue(); -}; - -/* - * (internal) Called by framework. Sets the style of the left button to - * either "goBack" or "menuUp" - */ -Common.prototype.setLeftBtnStyle = function(style) -{ - this.leftBtn.setStyle(style); -}; - -/* - * Updates the clock to display the value given. Value should be given in Unix format - * @param milliseconds Number the current time in number of milliseconds in a date string since midnight of January 1, 1970 - */ -Common.prototype.updateSbClock = function(milliseconds) -{ - var type = utility.toType(milliseconds); - if (type != 'number' && type != 'date') - { - log.warn("Common.updateSbClock can only accept an argument of type Number or Date"); - return; - } - - this._cachedTime = milliseconds; - this.statusBar.updateClock(milliseconds); - - // Update the clock in the OffScreen control if it that is the current template - if (this._cachedTemplate && this._cachedTemplate.templateName == "OffScreenTmplt" && this._cachedTemplate.updateClock) - { - this._cachedTemplate.updateClock(); - } -}; - -Common.prototype.getCurrentTime = function() -{ - var type = utility.toType(this._cachedTime); - var time = 0; - - if (type == 'number') - { - time = this._cachedTime; - } - else if (type == 'date') - { - time = this._cachedTime.getTime(); - } - - return time; -}; - -/* - * Removes the wink from the screen. This is called after the wink times out - * @param ctrlObj Object Reference to the Wink Control Object. - * @param appData Object App data stored by Common - * @param params Object Additional params passed by WinkCtrl - */ -Common.prototype._alertComplete = function(ctrlObj, appData, params) -{ - log.debug("Wink complete: " + ctrlObj.properties.alertId); - - this._removeWinkHelper(); -}; - -Common.prototype._removeWinkHelper = function() -{ - if (this._wink) - { - log.info("wink is", this._wink); - framework.websockets.sendAlertCompleteMsg(this._wink.uiaId, this._wink.properties.alertId); - - framework.destroyControl(this._wink); - this._wink = null; - } -}; - -/* - * Callback for when the Status Bar is clicked - * @param ctrlObj (Object) Reference to the button control object in status bar that was clicked - * @param appData (Object) Data passed in by the app when the control was instantiated - * @param params (Object) Optional params passed by the control object - */ -Common.prototype._statusBarClicked = function(ctrlObj, appData, params) -{ - log.debug("status bar clicked", ctrlObj, appData, params); - if (params.statusBtn == "home") - { - if (this._diagEntrySequence != 2 ) // 2 here indicates the sequence was completed - { - framework.sendEventToMmui("common", "Global.IntentHome"); - } - } - -}; - -/* - * Callback for when the Status Bar is long pressed - * @param ctrlObj (Object) Reference to the button control object in status bar that was clicked - * @param appData (Object) Data passed in by the app when the control was instantiated - * @param params (Object) Optional params passed by the control object - */ -Common.prototype._statusBarLongPress = function(ctrlObj, appData, params) -{ - if (params.statusBtn == "clock") - { - log.info("Clock Long Press Detected."); - this._diagEntrySequence = 1; - // clear exisiting timeout if any - clearTimeout(this._clockHomeButtonLongPressIntervalId); - //time interval between clock button long press and home button long press should be less than 9 secs - this._clockHomeButtonLongPressIntervalId = setTimeout(this._statusBarLongPressTimerHandler.bind(this),9000); - } - else if (params.statusBtn == "home" && this._diagEntrySequence == 1 && this._clockHomeButtonLongPressIntervalId) - { - log.info("Entering Diagnostics App"); - this._diagEntrySequence = 2; - framework.sendEventToMmui("syssettings", "SelectDiagnostics"); - } - -}; - -Common.prototype._statusBarLongPressTimerHandler = function() -{ - this._clockHomeButtonLongPressIntervalId = null; - this._diagEntrySequence = 0; -}; - -/* - * Callback for when the left button is pressed. - * @param controlObj (object) Reference to the LeftBtn that was pressed - */ -Common.prototype._leftBtnSelected = function(controlObj, appData, params) -{ - this._leftBtnSelectEvent(params.style); -}; - -/* - * Helper function to reduce duplicate logic. Called when the left button is selected either - * via touch or multicontroller -OR- when the TUI Left Hard Key is pressed. - * @param style String Style of the left button (determines which event to send to MMUI) - */ -Common.prototype._leftBtnSelectEvent = function(style) -{ - if (this.cmnCtrlsDisabled) - { - return; - } - - // Send an appropriate event based on the current style of the left button - switch (style) - { - case "goLeft": // legacy behavior TODO: remove when all Apps have updated - framework.sendEventToMmui("common", "Global.GoLeft"); - break; - case "goBack": // go back to the previous screen - framework.sendEventToMmui("common", "Global.GoBack"); - break; - case "menuUp": // go up one menu level - framework.sendEventToMmui("common", "Global.MenuUp"); - break; - default: - log.warn("There is no defined event for left button style: " + style); - break; - } -}; - -Common.prototype.getContextCapture = function() -{ - return { - leftBtnHasFocus : this.leftBtn.divElt.style.visibility === 'visible' && this.leftBtn.btnInstance.hasFocus - }; -}; - -Common.prototype.restoreContext = function(restoreData) -{ - if (restoreData.commonContextCapture && restoreData.commonContextCapture.leftBtnHasFocus) - { - restoreData.skipRestore = true; - } -}; - -/* - * Cause an audible beep to be played. - * @param pressType (String) Indicates a short press or a long press. Valid values are “Short” and “Long”. - * @param eventCause (String) Indicates the user interaction that caused the beep. Valid values are “Touch”, “Multicontroller”, and “Hardkey”. - */ -Common.prototype.beep = function(pressType, eventCause) -{ - var validPressTypes = [ "Short", "Long" ]; - if (utility.toType(pressType) !== "string" || validPressTypes.indexOf(pressType) === -1) - { - log.warn("Invalid pressType parameter passed to common.beep(). Valid values are 'Short' or 'Long'."); - return; - } - - var validEventCauses = [ "Touch", "Multicontroller", "Hardkey" ]; - if (utility.toType(eventCause) !== "string" || validEventCauses.indexOf(eventCause) === -1) - { - log.warn("Invalid eventCause parameter passed to common.beep(). Valid values are 'Touch' or 'Multicontroller' or 'Hardkey'"); - return; - } - - if (pressType == "Short" && eventCause == "Multicontroller") - { - // do not send this - return; - } - - var args = { - "payload" : { - "pressType" : pressType, - "eventCause" : eventCause - } - }; - - log.info("Sending PlayAudioBeep", pressType, eventCause); - framework.sendEventToMmui("audiosettings", "PlayAudioBeep", args); -}; - -/* - * Mute message handler - */ -Common.prototype._HandleStatusUpdateVolume = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - var isMuted = msg.params.payload.volumeOnOffStatus === "VolumeOff"; - if (isMuted !== this._isMuted) - { - this._isMuted = isMuted; - this._isMutedChanged(); - } - } -}; - -/* - * Called when the value of _isMuted changes - */ -Common.prototype._isMutedChanged = function() -{ - var action = this._getMuteOverlayAction(); - switch (action) - { - case "wink": - this._showMuteWink(3000); - break; - - case "persistentWink": - this._showMuteWink(null); - break; - - case "sbn": - this._showMuteSbn(); - break; - - default: - this._hideMuteWink(); - this._hideMuteSbn(); - break; - - } -}; - -Common.prototype._showMuteSbn = function() -{ - var properties = { - sbnStyle: "Style02", - }; - - if (this._isMuted) - { - properties.imagePath1 = "IcnSbnMuteOn.png"; - properties.text1Id = "common.muteOn"; - } - else - { - properties.imagePath1 = "IcnSbnMuteOff.png"; - properties.text1Id = "common.muteOff"; - } - - this.startTimedSbn("common", "TimedSbn_StatusUpdateVolumeOnOff", "typeA", properties); -}; - -Common.prototype._hideMuteSbn = function() -{ - this.cancelTimedSbn("common", "TimedSbn_StatusUpdateVolumeOnOff", "typeA"); -}; - -Common.prototype._showMuteWink = function(winkTimeout) -{ - var properties = { - "style": "style05", - "image1": "common/images/icons/IcnWinkUnMute.png", - "winkTimeout": winkTimeout, - "alertId": "", - "completeCallback": this._muteWinkComplete.bind(this) - }; - - if (this._isMuted) - { - properties.image1 = "common/images/icons/IcnWinkMute.png"; - } - - var newWink = framework.instantiateControl("common", document.body, "WinkCtrl", properties); - - // If there's a Wink currently displayed (e.g. persistentWink), get rid of it - this._hideMuteWink(); - this._muteWink = newWink; -}; - -Common.prototype._hideMuteWink = function() -{ - if (this._muteWink) - { - framework.destroyControl(this._muteWink); - this._muteWink = null; - } -}; - -Common.prototype._muteWinkComplete = function() -{ - this._hideMuteWink(); -}; - -/* - * Returns one of: "persistentWink", "wink", "sbn" - */ -Common.prototype._getMuteOverlayAction = function() -{ - if (this._cachedTemplate && this._cachedTemplate.templateName === "NowPlaying4Tmplt") - { - if (this._isMuted) - { - return "persistentWink"; - } - else - { - return "wink"; - } - } - else - { - var uiaId = framework.getCurrentApp(); - var ctxtId = framework.getCurrCtxtId(); - if (this.getContextCategory(uiaId, ctxtId) === "Entertainment") - { - return "wink"; - } - } - return "sbn"; -}; - -Common.prototype._updateMuteWinkOnTransition = function(prevTepmlate, currTemplate) -{ - if (this._isMuted && currTemplate && currTemplate.templateName === "NowPlaying4Tmplt") - { - this._showMuteWink(null); - } - else - { - this._hideMuteWink(); - } -}; - -/* - * Process Global.MenuUpReceived messages. - */ -Common.prototype._MenuUpReceived = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - this._menuUpReceiverApp = msg.params.payload.receiverApp; - } -}; - -/* - * Utility function to get the context category (domain) for a given application/context - * @param uiaId Application ID - * @param ctxtId Context ID - * @returns Domain string value (e.g. "Applications", "Communication", "Entertainment") - */ -Common.prototype.getContextCategory = function(uiaId, ctxtId) -{ - return this._contextCategory.getContextCategory(uiaId, ctxtId); -}; - -/* - * Utility function to get the status bar icon for a given context category (domain) - * @param domain Domain string value (e.g. "Applications", "Communication", "Entertainment") - * @returns Icon image file name - */ -Common.prototype.getContextCategorySbIcon = function(domain) -{ - return this._contextCategory.getContextCategorySbIcon(domain); -}; - -framework.registerCommonLoaded(["common/controls/StatusBar", - "common/controls/LeftBtn", - "common/controls/Wink", - "common/controls/Button", - "common/controls/Dialog3", - "common/controls/Sbn"], true); diff --git a/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.56.00.511A-EU b/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.56.00.511A-EU deleted file mode 100644 index ce34b1f..0000000 --- a/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.56.00.511A-EU +++ /dev/null @@ -1,2378 +0,0 @@ -/* - Copyright 2012 by Johnson Controls - __________________________________________________________________________ - - Filename: Common.js - __________________________________________________________________________ - - Project: JCI-IHU - Language: EN - Author: awoodhc - Date: 08.27.2012 - __________________________________________________________________________ - - Description: IHU GUI Common - - Revisions: - v0.1 (27-Aug-2012) Create Common to handle all "system-wide" logic - v0.2 (27-Aug-2012) Added basic logic for "global" controls, multicontroller events, transitions, ctrl clicks, basic BG logic - v0.3 (28-Aug-2012) Added logic for alerts - v0.4 (11-Oct-2012) Added logic to hide Home Button while on Home Screen - v0.5 (04-Nov-2012) Added API to display App Name in Status Bar - Added Diag Entry logic - v0.6 (08-Nov-2012) Added API for Setting the Left Button Style. - v0.7 (19-Nov-2012) Changed Alert event to conform with MMUI standards. Added API to set the Status Bar Clock with value from MMUI. - v0.8 (26-Nov-2012) Fixed Diagnostics Entry. Common now counts a sequence to make sure the sequence is complete before resetting. - v0.9 (03-Dec-2012) Added message table for handling MMUI common messages and handling for LanguageChangeStatus msg - v1.0 (05-Dec-2012) Added API to set state of status bar icons - v1.1 (21-Jan-2012) Added new SBN and Wink logic - __________________________________________________________________________ - - */ - -log.addSrcFile("Common.js", "common"); -//log.setLogLevel("common", "debug"); - -function Common() -{ - log.debug("constructor called..."); - - //-- public variables - this.moduleName = "common"; // (String) Name of this module (used in place of uiaId when instantiating controls) - this.statusBar = null; // (Object) Status Bar Control Object - this.leftBtn = null; // (Object) Left Button Control Object - - this.cmnCtrlsDisabled = false; // (Boolean) Whether to Status Bar/Left Button are disabled due to a dialog - - - //-- private variables - - this._cachedTime = 0; // (Number) Stores the time value sent from MMUI via GUI_SYSSETTINGS - this._cachedTemplate = null; // (Object) template currently active in the DOM. Framework updates this. - this._menuUpReceiverApp = null; // (String) cached uiaId sent from MMUI when during a transition caused by a Menu Up action - this._canShowSbns = false; // (Boolean) true if Common can display SBNs over the cached template - - this._bgDiv1 = null; // (HTMLElement) the background div - this._bgDiv2 = null; // (HTMLElement) used to transition between 2 backgrounds - this._rightChrome = null; // (HTMLElement) the div used to display the right-hand chrome - this._customBgSet = false; // (Boolean) true if there is a custom bg set by the current template - this._defaultBgPath = "common/images/background.png"; // (String) the css path to the default bg image - this._currentBgPath = this._defaultBgPath; // (String) the css path to the current bg image - - this._wink = null; // (Object) The active Wink Control Object (null if none displayed) - this._winkTimeout = guiConfig.winkTimeout; // (Number) milliseconds a Wink will stay on screen - - this._muteWink = null; // (Object) The Entertainment Mute Wink Control Object (null if none displayed) - - this._cachedVuiState = null; // (String) Last VUI state sent from MMUI. - this._vuiHelpDialog = null; // (Object) The active VUI Help Dialog Control (null if none displayed) - this._lineNumberData = null; // (Object) Contains data passed from a List pertaining to the VUI line numbers - - this._diagEntrySequence = 0; // (Number) 1 if the Diagnostics entry button sequence has begun. 2 if it has completed. - this._clockHomeButtonLongPressIntervalId = null; - - this._atSpeed = false; // (Boolean) true if AtSpeed event is received from MMUI - this._isMuted = false; // (Boolean) true if entertainment audio is currently muted - - this._contextCategory = new ContextCategory(); // (Object) Contains a lookup table to determine a context's category. - - //-- Status Bar Auto-Hide Variables - // MPP 09/16/2013 SW00107357 - this._displaySbUmpByActivity = false; // (Boolean) Master switch for auto-hide status bar/UMP feature - this._displaySbUmpActivityTypes = "both"; // (String) "both" for both touch & MC input to count as activity, "touch" for touch-only input - this._inactivityTimer = null; // (Object) The timer used to measure (in)activity for auto-hiding the status bar & UMP - this._onInactivityBinder = this._onInactivity.bind(this); // (Callback) Bind the timer callback once to save memory - this._activityDetected = false; // (Boolean) Flag raised on touch/MC input; lowered when inactivity timer expires - this._sbRequestedState = "none"; // (String) External request to show/hide status bar - this._sbDelay_ms = -1; // (Integer) # of milliseconds before status bar animation starts (external request) - this._sbDuration_ms = -1; // (Integer) # of milliseconds status bar animation should take (external request) - this._defaultSbDelay_ms = 0; // (Integer) Default delay timing for status bar animation - this._defaultSbDuration_ms = 500; // (Integer) Default duration timing for status bar animation - this._defaultHelpPrompt = "SpeechNotAllowed_Help"; // (string) help promp name which requires default help screen - - //-- Status Bar Notification Variables - /* - * See _setKnownSbn() function for _knownSbns variable properties - */ - this._knownSbns = new Object(); // (Object) key'd to SbnId, value is SbnObject with information necessary to display Sbn - this._sbnIsDisplayed = false; // (Boolean) Flag indicating whether an SBN is displayed (true) or not (false). - this._displayedSbn = null; // (Object) Refernce to the currently displayed Sbn Control. - this._displayedSbnId = null; // (String) SbnId of the currently displayed Sbn. null if none is displayed - this._displayedSbnTimerId = 0; // (Number) Timer ID used for timed Sbns. - this._sbnQueue = new Array(); // (Array) Queue of all current Sbns by Id. 0 is next in line to be dispalyed. - - // Default SBN values used where value is not specified in UI Spec. - var dfltDuration = 2000; // (Number) default number of milliseconds - var dfltQueue = 0; // (Number) default number of milliseconds - - // NOTE: State-based SBNs do not expire, but Timed SBNs should be queueTime 0 so that they do not re-appear (exception: driverId) - - this._SBN_TYPES = { // (Object) contains list of Sbn Priorities by type, defined in System UI Spec - - //replaced old sbn types with new letter based sbn types(As per SCR SW00155262) - "typeA": {"priority": 1, "timedDuration": 2000, "queueTime": 0}, // 1 is highest priority - "typeB": {"priority": 2, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "typeL": {"priority": 3, "timedDuration": 5000, "queueTime": 60000}, - "typeC": {"priority": 4, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "typeD": {"priority": 5, "timedDuration": 5000, "queueTime": 0}, - "typeE": {"priority": 6, "timedDuration": 5000, "queueTime": 0}, - "typeF": {"priority": 7, "timedDuration": 5000, "queueTime": 0}, - "typeG": {"priority": 8, "timedDuration": 5000, "queueTime": 0}, - "typeI": {"priority": 9, "timedDuration": 5000, "queueTime": 0}, - "typeJ": {"priority": 10, "timedDuration": 5000, "queueTime": 0}, - "typeK": {"priority": 11, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "unknown": {"priority": 100, "timedDuration": dfltDuration, "queueTime": dfltQueue} - }; - - this._SBN_MAPPING_TABLE = { // contains mapping of old sbn types with new letter based sbn types(As per SCR SW00155262) - "volumeStatus" : "typeA", - "vrStatus" : "typeB", - "driverId" : "typeL", - "navigationNear" : "typeC", - "deviceConnected" : "typeD", - "entertainmentInfo" : "typeE", - "errorNotification" : "typeF", - "btConnecting" : "typeG", - "deviceRemoved" : "typeI", - "navigationFar" : "typeJ", - "systemFailure": "typeK", - "unknown": "unknown" - }; - - // Any SBN type in the blacklist will be blocked if it is requested. This is a centralized fix for evolving requirements. - this._SBN_TYPE_BLACKLIST = [ - "typeK" - ]; - - //@formatter:off - this._messageTable = { - "LanguageChangeStatus" : this._LanguageChangeStatusMsgHandler.bind(this), - "Global.AtSpeed" : this._AtSpeedMsgHandler.bind(this), - "Global.NoSpeed" : this._NoSpeedMsgHandler.bind(this), - "Global.PageUp" : this._PageUpDownMsgHandler.bind(this), - "Global.PageDown" : this._PageUpDownMsgHandler.bind(this), - "vuiState" : this._vuiStateMsgHandler.bind(this), - "vuiMicLevel" : this._vuiStateMsgHandler.bind(this), - "Global.SelectLineNumber" : this._SelectLineNumMsgHandler.bind(this), - "Global.StartHelp" : this._ShowVuiHelpHandler.bind(this), - "Global.HideHelp" : this._HideVuiHelpHandler.bind(this), - "Global.StatusUpdateVolumeOnOff" : this._HandleStatusUpdateVolume.bind(this), - "Global.MenuUpReceived" : this._MenuUpReceived.bind(this) - - }; // end of this._messageTable - //@formatter:on - - - //-- DOM logic - // Add the background image to the body - this._bgDiv1 = document.createElement('div'); - this._rightChrome = document.createElement('div'); - - this._bgDiv1.id = "CommonBgImg1"; - this._bgDiv1.className = "CommonBgImg"; - - this._rightChrome.id = "CommonRightChrome1"; - this._rightChrome.className = "CommonRightChrome"; - this._rightChrome.style.visibility = "hidden"; - - document.body.appendChild(this._bgDiv1); - document.body.appendChild(this._rightChrome); - - // Add controls to the DOM - this.addControls(); -}; - -/* (internal - called by framework) - * Instantiates the LeftBtnControl and StatusBarCtrl (usually only happens when the language is changed) - */ -Common.prototype.addControls = function() -{ - log.debug("addControls called."); - - // Status Bar - if (this.statusBar)//never add more than one instance of these controls - { - log.debug("status bar exists"); - // MPP 08/29/2013 SW00127573 - // Refresh status bar, rather than re-instantiating it, when languages change - //framework.destroyControl(this.statusBar); - //this.statusBar = null; - this.statusBar._refresh(); - } - else - { - log.debug("instantiating status bar"); - // create the status bar - var statusProp = { - "selectCallback" : this._statusBarClicked.bind(this), - "longPressCallback" : this._statusBarLongPress.bind(this) - }; - - this.statusBar = framework.instantiateControl(this.moduleName, document.body, "StatusBarCtrl", statusProp); - } - - // Left Button - if (this.leftBtn) - { - //never add more than one instance of these controls - //framework.destroyControl(this.leftBtn); - //this.leftBtn = null; - } - else - { - // create the left button - var lftBtnProp = {"selectCallback" : this._leftBtnSelected.bind(this)}; - - this.leftBtn = framework.instantiateControl(this.moduleName, document.body, "LeftBtnCtrl", lftBtnProp); - - this._checkTemplateProperties(); - } -}; - -/* (internal - called by framework) - * Destroys the LeftButtonControl and StatusBarCtrl (usually only happens when the language is changed) - */ -Common.prototype.removeControls = function() -{ - if (this.statusBar) - { - framework.destroyControl(this.statusBar); - this.statusBar = null; - } - - if (this.leftBtn) - { - framework.destroyControl(this.leftBtn); - this.leftBtn = null; - } - -}; - -/* - * Checks templates properties for global controls. Called when a language change occurs - */ -Common.prototype._checkTemplateProperties = function() -{ - log.debug("_checkTemplateProperties called."); - var template = this._cachedTemplate; - //we should be able to use the cached template here, because when changing languages, we don't change context - - var data; - if (template) - { - data = this._calcTransitionData(template); - } - else - { - //defaults - log.debug(" No template could be found. Using default values."); - data = new Object(); - data.leftButtonVisible = false; - data.statusBarVisible = true; - } - - log.debug(" Left Btn Visible: " + data.leftButtonVisible + ", Status Bar Visible: " + data.statusBarVisible); - - - if (data.leftButtonVisible) - { - this.leftBtn.divElt.style.visibility = 'visible'; - } - else - { - this.leftBtn.divElt.style.visibility = 'hidden'; - } - - if (data.statusBarVisible) - { - this.statusBar.divElt.style.visibility = 'visible'; - } - else - { - this.statusBar.divElt.style.visibility = 'hidden'; - } - -}; - -/* (internal) - * Called by framework when a context change occurs and data is needed. - * @param template (object) The template that will be transitioned to. - */ -Common.prototype.getCommonTransitionData = function(template) -{ - if (template == null) - { - log.error("getCommonTransitionData called with null template."); - return; - } - - // Terminate any activity timer that may be running so we don't see the - // previous template's status bar or UMP sliding during the transition - this._cleanUpInactivityTimer(); - - this._updateMuteWinkOnTransition(this._cachedTemplate, template); - - this._closeVuiHelpOnTransition(template); - - // tell left button or the previous template to lose focus before the transition starts - this.handleControllerEvent('lostFocus'); - - // cache template: - this._cachedTemplate = template; - - // Hide VUI Numbers - this.leftBtn.hideLineNumbers(); - - // Update _canShowSbns variable and hide active SBN if necessary - this._updateCanShowSbns(); - - var data = this._calcTransitionData(template); - return data; -}; - -/* (private) - * Returns an object with common transition data for the upcoming transition - * @param template (object) The template that will be transitioned to. - * @return (object) Object containing common transition data - */ -Common.prototype._calcTransitionData = function(template) -{ - if (template.properties.customBgImage) - { - if (template.properties.customBgImage != this._currentBgPath) - { - this._bgDiv2 = document.createElement('div'); - this._bgDiv2.id = "CommonBgImg2"; - this._bgDiv2.className = "CommonBgImg"; - this._bgDiv2.style.backgroundImage = "url(" + template.properties.customBgImage + ")"; - this._currentBgPath = template.properties.customBgImage; - document.body.insertBefore(this._bgDiv2, this._bgDiv1); - this._customBgSet = true; - } - } - else if (this._customBgSet == true) // don't transition to default bg on a dialog - { - this._bgDiv2 = document.createElement('div'); - this._bgDiv2.id = "CommonBgImg2"; - this._bgDiv2.className = "CommonBgImg"; - this._bgDiv2.style.backgroundImage = "url(" + this._defaultBgPath + ")"; - this._currentBgPath = this._defaultBgPath; - document.body.insertBefore(this._bgDiv2, this._bgDiv1); - this._customBgSet = false; - } - - // Check for menu up - var menuUpUsed = false; - if (this._menuUpReceiverApp) - { - if (this._menuUpReceiverApp === this._cachedTemplate.contextInfo.uiaId) - { - menuUpUsed = true; - } - this._menuUpReceiverApp = null; - } - - //@formatter:off - var commonTransitionData = { - // references to system control objects - "statusBar" : this.statusBar, - "leftButton" : this.leftBtn, - // booleans - "statusBarVisible" : template.properties.statusBarVisible, - "leftButtonVisible" : template.properties.leftButtonVisible, - "menuUpUsed": menuUpUsed, - // bg data - "customBgImage" : template.properties.customBgImage, - "bgDiv1" : this._bgDiv1, - "bgDiv2" : this._bgDiv2, - // other - "rightChrome" : this._rightChrome, - "rightChromeVisible": (template.properties.rightChromeVisible === true) ? true : false - }; - - if (template.properties.isDialog) - { - // Preserve left button visibility from the previous context when going to a dialog context. - commonTransitionData.leftButtonVisible = this.leftBtn.divElt.style.visibility === "visible"; - commonTransitionData.rightChromeVisible = this._rightChrome.style.visibility === "visible"; - } - - //@formatter:on - return commonTransitionData; -}; - -/* (internal) - * Callback for when the controls transition completes. Currently only used for custom backgrounds - * @param transitionData (object) the data that was used during the transition - */ -Common.prototype.commonControlsUpdateComplete = function(transitionData) -{ - if (transitionData.bgDiv2) - { - // bgDiv2 transitioned in, so we need to remove bgDiv1 - utility.removeHTMLElement(transitionData.bgDiv1.id); - - this._bgDiv1 = this._bgDiv2; - this._bgDiv1.id = "CommonBgImg1"; - this._bgDiv2 = null; - } - - if (framework.getCurrentApp() == "syssettings" && framework.getCurrCtxtId() == "DisplayTab") - { - this.statusBar.enableClockBtn(true); - } - else - { - this.statusBar.enableClockBtn(false); - this._diagEntrySequence = 0; // reset the sequence on context change - } - - // Retrieve the types of input that will count as user activity, and then - // turn on activity monitoring for this context/template (if needed) - this._displaySbUmpActivityTypes = "both"; - if (this._cachedTemplate.properties.displaySbUmpActivityTypes === "both" || - this._cachedTemplate.properties.displaySbUmpActivityTypes === "touch") { - this._displaySbUmpActivityTypes = this._cachedTemplate.properties.displaySbUmpActivityTypes; - } - - this._setDisplaySbUmpByActivityEnabled(this._cachedTemplate.properties.displaySbUmpByActivity == true); - - // show SBN if needed - if (this._canShowSbns) - { - // If there's NO SBN displayed - if (!this._displayedSbnId) - { - // ENTRY POINT #2 - // If a new SBN gets displayed, _displaySbnFromQueue will return the ID - var newSbnId = this._displaySbnFromQueue(); - - if (newSbnId) - { - // Tell Status Bar about the SBN - this._sbnIsDisplayed = true; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - - if (this._cachedTemplate.properties.statusBarVisible) - { - // Snap the status bar visible (only if this template is set to display a status bar) - this.statusBar.transitionVisible(0, 0, "slide", true); - } - - // Notify MMUI to turn on display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 1}}); - } - - } - } - - this.handleControllerEvent('acceptFocusInit'); - -}; - -/* (internal - Called by Controls) - * Sends a "lostFocus" Multicontroller event to the currently focused Control so that the - * Control calling stealFocus() can gain focus. - * After calling this API, the calling Control -must- gain focus automatically. - */ -Common.prototype.stealFocus = function() -{ - var response = null; - - if (this.leftBtn.btnInstance.hasFocus) - { - response = this.leftBtn.handleControllerEvent("lostFocus"); - } - else if (this._cachedTemplate && this._cachedTemplate.handleControllerEvent) - { - response = this._cachedTemplate.handleControllerEvent("lostFocus"); - } - else - { - log.warn("Cannot steal focus. Common's cached template is either null or does not have handleControllerEvent."); - } - - return response; -}; - -/* (internal - Called by framework) - * Handles multicontroller events, specifically the left event for the leftBtn - * @param eventID (string) any of the “Internal event name” values in IHU_GUI_MulticontrollerSimulation.docx (e.g. 'cw', - * 'ccw', 'select') - * @return true if common 'consumed' the tui event. false otherwise. - */ -Common.prototype.handleControllerEvent = function(eventId, firstEvent) -{ - if (eventId == "goBack") // Note: "goBack" event sent from Multicontroller.js indicates the TUI back key has been pressed - { - framework.sendEventToMmui("common", "Global.GoBack"); - } - - // The first event is thrown away, but "controllerActive" is still passed to the template/control to change its highlight - // Thus, "ccw" will come in with firstEvent true, but "controllerActive" will also come in separately with firstEvent false - if (firstEvent) - { - log.debug(" firstEvent detected. Ignoring."); - return; - } - - // Test whether one of Common/Global controls has multicontroller focus and react accordingly - - if (this._cachedTemplate && this._cachedTemplate.handleControllerEvent) - { - // always pass along controller active and touch active - if (eventId != "touchActive" && eventId != "controllerActive") - { - if (this.leftBtn.btnInstance.hasFocus) - { - var response = this.leftBtn.handleControllerEvent(eventId); - if (response == "giveFocusRight") - { - var response = this._cachedTemplate.handleControllerEvent("acceptFocusFromLeft"); - if (response == "consumed") - { - this.leftBtn.handleControllerEvent("lostFocus"); - } - } - } - else - { - var response = this._cachedTemplate.handleControllerEvent(eventId); - if (response == "giveFocusLeft" && this._cachedTemplate.properties.leftButtonVisible) - { - this.leftBtn.handleControllerEvent("acceptFocusFromRight"); - this._cachedTemplate.handleControllerEvent("lostFocus"); - } - } - } - else - { - // always pass along controller active and touch active - if (this.leftBtn) // left button check to prevent race conditions during language change - { - this.leftBtn.handleControllerEvent(eventId); - } - // _cachedTemplate is checked above - this._cachedTemplate.handleControllerEvent(eventId); - - } - - } - else - { - log.warn("Common's cached template is either null or does not have handleControllerEvent."); - } -}; - -/* (internal - Called by framework) - * Handles alert messages from framework, sent by MMUI. - */ -Common.prototype.handleAlert = function(uiaId, alertId, params) -{ - log.debug("handleAlert called."); - - // MMUI should never send two alerts at once. This is a backup check. - if (this._wink) - { - return; - } - - var app = framework.getAppInstance(uiaId); - var properties = null; - - if (app && app.getWinkProperties) // check for App method - { - properties = app.getWinkProperties(alertId, params); - } - - // NOTE: Even though we can't show the Wink, I still call into the GUI App (above) in case they have logic that needs to be done - if (!this._canShowSbns) - { - // We're in a context that can't show Winks. Immediately Ack - framework.websockets.sendAlertCompleteMsg(uiaId, alertId); - return; - } - - if (!properties) // if no properties are set, use the default paragraph style - { - // legacy wink. Use paragraph style. - log.info("No properties returned by app: " + uiaId + ". Using default Wink style."); - properties = { - "style": "style03", - "text1Id": alertId - }; - } - - // no matter what, common should set these properties - properties.winkTimeout = this._winkTimeout; - properties.alertId = alertId; - properties.completeCallback = this._alertComplete.bind(this); - - this._wink = framework.instantiateControl(uiaId, document.body, 'WinkCtrl', properties); - -}; - -/* Called by framework when a data message is sent from Mmui. - * This will pass the message information into any function the app has set in this._messageTable - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype.handleDataMessage = function(msg) -{ - log.debug("GUI COMMON" + " handleDataMessage called for", msg.msgId); - - if (this._messageTable && this._messageTable[msg.msgId]) - { - this._messageTable[msg.msgId](msg); - } - else - { - log.warn("GUI COMMON" + " No message handler for", msg.msgId); - } -}; - - -/* - * Handler for LanguageChangeStatus message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._LanguageChangeStatusMsgHandler = function(msg) -{ - if (msg && msg.params && msg.params.payload && msg.params.payload.languageID) - { - var langCode = framework.localize.getLangInGuiFormat(msg.params.payload.languageID); - } - - if (msg && msg.params && msg.params.payload && msg.params.payload.status) - { - var status = msg.params.payload.status; - } - - var bStatus = false; - - if (status == "Success") - { - bStatus = true; - } - else - { - bStatus = false; - } - - // Call unload dictionaries - framework.localize.unloadDictionaries(langCode,bStatus); -}; - -/* - * Handler for AtSpeed message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._AtSpeedMsgHandler = function(msg) -{ - log.info("Common.prototype._AtSpeedMsgHandler called",msg); - this._atSpeed = true; - framework.sendMsgToFocusedApp(msg); -}; - -/* - * Handler for NoSpeed message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._NoSpeedMsgHandler = function(msg) -{ - log.info("Common.prototype._NoSpeedMsgHandler called",msg); - this._atSpeed = false; - framework.sendMsgToFocusedApp(msg); -}; - -/* - * Handler for PageUp & PageDown messages - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._PageUpDownMsgHandler = function(msg) -{ - log.debug("Common.prototype._PageUpDownMsgHandler called", msg); - - // Assume no list exists - var result = "NoList"; - var eventName = null; - var apiName = null; - - // Determine the result event name, based on the incoming message - // (independent of anything to do with a list) - switch (msg.msgId) - { - case "Global.PageUp": - eventName = "Global.PageUpResult"; - apiName = "pageUp"; - break; - case "Global.PageDown": - eventName = "Global.PageDownResult"; - apiName = "pageDown"; - break; - default: - log.error("_PageUpDownMsgHandler called with non-pagination event!"); - break; - } - - // If we have a list and an API on it to call, ... - if (this._cachedTemplate && this._cachedTemplate.templateName === "List2Tmplt" && this._cachedTemplate.list2Ctrl && apiName) - { - // ... call that API! - response = this._cachedTemplate.list2Ctrl[apiName](); - result = response.charAt(0).toUpperCase() + response.slice(1); // make sure first letter is uppercase - } - - // Compose result & send to MMUI - if (eventName) - { - var params = { - "payload": { - "pageStatus": result - } - }; - - framework.sendEventToMmui("common", eventName, params); - } -}; - -/* - * Handler for VUI Mic messages - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._vuiStateMsgHandler = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - if (msg.msgId == "vuiState") - { - var showLineNumbers = false; - this._cachedVuiState = msg.params.payload.state; - // End the current SBN in case we need to change styles - this.endStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - switch(this._cachedVuiState) - { - case "Not Ready": // intentional fall-through - case "Idle": - case "Playing Out of Session Alert": - // Do nothing. SBN is automatically ended - break; - case "Playing Prompt": - // Show "Wait for Tone" SBN - var properties = { - "sbnStyle": "Style02", - "imagePath1": "IcnSbnMicClosed.png", - "text1Id": "common.SbnWaitForTone" - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - showLineNumbers = true; - break; - case "Listening": - // Show sound meter SBN starting at 0 - var properties = { - "sbnStyle": "Style04", - "imagePath1": "IcnSbnMicOpen.png", - "meter": {"meterType": "audio02", "min": 0, "max": 4000, "currentValue": 0} - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - showLineNumbers = true; - break; - case "Processing": // Intentional fallthrough. Show SBN with icon only - case "Playing Terminating Prompt": - // Show SBN with icon only - var properties = { - "sbnStyle": "Style02", - "imagePath1": "IcnSbnMicClosed.png", - "text1": null - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - break; - default: - log.warn("Unknown VUI State was sent to GUI: " + this._cachedVuiState); - break; - } - - this._showHideLineNumbers(showLineNumbers); - } - else if (msg.msgId == "vuiMicLevel") - { - var micLevel = parseInt(msg.params.payload.micLevel); - // clamp the micLevel value. SBN meter does not support negative numbers - micLevel += 3000; - // Adjust very low mic values to show 1-2 bars - if (micLevel < -2100) - { - micLevel = 50; - } - else if (micLevel < 100) - { - micLevel = 100; - } - - if (this._cachedVuiState == "Listening") - { - // Update state-based SBN with current mic level - var properties = { - "sbnStyle": "Style04", - "imagePath1": "IcnSbnMicOpen.png", - "meter": {"meterType": "audio02", "min": 0, "max": 4000, "currentValue": micLevel} - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - } - } - } -}; - -/* - * Handler for SelectLineNumber message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._SelectLineNumMsgHandler = function(msg) -{ - log.debug("Common.prototype._SelectLineNumMsgHandler called", msg); - - if (msg && msg.params && msg.params.payload) - { - var number = msg.params.payload.lineNumber; - } - else - { - return; - } - - var result = "NoList"; // status to send back to MMUI (default to NoList) - - // Is the current template a list? - if (this._cachedTemplate && this._cachedTemplate.templateName == "List2Tmplt") - { - // Does the list have data and support VUI? - if (this._cachedTemplate.list2Ctrl.dataList && this._cachedTemplate.list2Ctrl.dataList.vuiSupport == true) - { - log.info("Sending Line Number to List: " + number); - // List will return a result - var response = this._cachedTemplate.list2Ctrl.selectLine(number); - - if (response == "selected") - { - return; // No event from Common if "selected" is response - } - - result = response.charAt(0).toUpperCase() + response.slice(1); // first letter uppercase - } - } - - log.info("SelectLineResult is ", number, result); - var params = { - "payload" : { - "lineNumber": number, - "lineStatus": result - } - }; - framework.sendEventToMmui("common", "Global.SelectLineResult", params); -}; - -/* - * Handler for Global.StartHelp message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._ShowVuiHelpHandler = function(msg) -{ - log.debug("Common.prototype._ShowVuiHelpHandler called", msg); - - // Hide any currently displayed VUI Help - this._HideVuiHelpHandler(msg); - - // Validate that this help overlay request is for the currently displayed context. - if (framework.getCurrentApp() === msg.params.payload.currentUiaId && - framework.getCurrCtxtId() === msg.params.payload.currentContextId) - { - // Try to load a VUI Help configuration and display it if found - var targetUiaId = msg.params.payload.uiaId; - var helpPromptName = msg.params.payload.helpPromptName; - var dialogProperties = this._getVuiHelpDialogConfiguration(targetUiaId, helpPromptName); - if (dialogProperties) - { - this._vuiHelpDialog = framework.instantiateControl(dialogProperties.uiaId, document.body, 'Dialog3Ctrl', dialogProperties.dialogConf); - this._vuiHelpDialog.divElt.classList.add("Dialog3Ctrl_Style19_NoTemplateInstance"); - - // Add properties to the control to record the uiaId and contextId. See also _closeVuiHelpOnTransition(). - this._vuiHelpDialog._uiaId = msg.params.payload.currentUiaId; - this._vuiHelpDialog._contextId = msg.params.payload.currentContextId; - } - } - else - { - log.warn("Ignoring Global.StartHelp message because GUI is in context '" - + framework.getCurrentApp() - + " " - + framework.getCurrCtxtId() - + "' but the message is for a different context: " - + JSON.stringify(msg)); - } -}; - -/* - * Handler for Global.HideHelp message - * @tparam Object msg (optional) The parsed message object sent from Mmui - */ -Common.prototype._HideVuiHelpHandler = function(msg) -{ - log.debug("Common.prototype._HideVuiHelpHandler called"); - - if (this._vuiHelpDialog) - { - framework.destroyControl(this._vuiHelpDialog); - this._vuiHelpDialog = null; - } -}; - -/* - * Close Vui Help at the start of a transition to a new template if that template represents a different context. - */ -Common.prototype._closeVuiHelpOnTransition = function(template) -{ - if (this._vuiHelpDialog - && template - && template.contextInfo.uiaId != this._vuiHelpDialog._uiaId - && template.contextInfo.ctxtId != this._vuiHelpDialog._contextId) - { - this._HideVuiHelpHandler(null); - } -}; - -/* - * Returns a configuration object for a VUI help dialog3 control prompt from an app's dictionary. - * Returns null if no prompt text is found in the dictionary. - * @tparam String uiaId The application requesting the VUI help. - * @tparam String helpPromptName The name of the help prompt to look for in the dictionary. - */ -Common.prototype._getVuiHelpDialogConfiguration = function(uiaId, helpPromptName) -{ - var config = { - dialogConf: { - contentStyle: "style19", - titleStyle : "titleStyle03" - }, - uiaId: uiaId - }; - var found = false; - - // When help prompt name which requires default default help screen is received show system/Home help screen - if (this._defaultHelpPrompt === helpPromptName) - { - helpPromptName = "HomeScreen_Help"; - uiaId = "system"; - config.uiaId = uiaId; - } - // __VrHelpPositionTable__ flag for the current app - var vrHelpPosTable = framework.localize.testVrHelpPosTableExistence(uiaId, helpPromptName); - var leftStringId = null; - var rightStringId = null; - - // Dictionary strings for a VUI help prompt have specific computable stringIds. - for (var i = 1; i <= 5; ++i) - { - if (vrHelpPosTable) - { - // new approach - leftStringId = framework.localize.getVrHelpStringId(uiaId, helpPromptName,"Left", i); - rightStringId = framework.localize.getVrHelpStringId(uiaId, helpPromptName,"Right", i); - } - else - { - // old approach TODO: to be removed when all the VR apps supports the new VrHelpPositionTable. - leftStringId = "VrHelp_" + helpPromptName + "_Left" + i; - rightStringId = "VrHelp_" + helpPromptName + "_Right" + i; - } - - if (leftStringId && framework.localize.testLocStr(uiaId, leftStringId)) - { - config.dialogConf["text" + i.toString() + "Id"] = leftStringId; - found = true; - } - if (rightStringId && framework.localize.testLocStr(uiaId, rightStringId)) - { - config.dialogConf["text" + (i + 5).toString() + "Id"] = rightStringId; - } - } - - if (found) - { - var titleId = "VrHelp_" + helpPromptName + "_Title"; - if (framework.localize.testLocStr(uiaId, titleId)) - { - config.dialogConf.titleId = titleId; - } - else - { - // No title found in dictionary -- use default title - config.dialogConf.titleId = "common.VuiHelpDefaultTitle"; - } - } - - return (found) ? config : null; -}; - -/* - * Function called by apps to determine if vehicle is at speed - * @return Boolean true if vehicle is at speed - */ -Common.prototype.getAtSpeedValue = function() -{ - return this._atSpeed; -}; - -/* - * Tells the status bar to show/hide the Home button - * @param show Boolean true if the home button should be displayed. false if it should be hidden. - */ -Common.prototype.showSbHomeButton = function(show) -{ - this.statusBar.showHomeBtn(show); -}; - -/* - * (internal) Called by framework. Sets the App name text/image in the status bar - * @param label String Literal text name or image path to display in the status bar - */ -Common.prototype.setSbName = function(label) -{ - // setAppName() will differentiate between text & imagery - this.statusBar.setAppName(label); -}; - -/* - * (internal) Called by framework. Sets the translated App name text in the status bar - * @param uiaId String UiaId of the App the string should be translated for - * @param labelId String StringID to be translated - * @param subMap Object Optional subMap to be placed in the text - */ -Common.prototype.setSbNameId = function(uiaId, labelId, subMap) -{ - this.statusBar.setAppNameId(uiaId, labelId, subMap); -}; - -/* - * (internal) Called by framework. Sets the icon between the Home Button and the App Name in the status bar - * @param path String Path from index.html to icon. Pass null to remove current icon - */ -Common.prototype.setSbDomainIcon = function(path) -{ - this.statusBar.setDomainIcon(path); -}; - -/* - * Updates the state of a Status Bar Icon - * @param name String Base Icon name ("Batt", "PhoneSignal", "Roaming", "Traffic", "WifiSignal", "Music", "Bluetooth", "Message") - * @param visible Boolean True if the icon should be shown. False if it should be hidden - * @param state String (Optional) String corrsponding to the state of the icon ("00", "01", "02", "03", "04", "05") - */ -Common.prototype.setSbIcon = function(name, visible, state) -{ - this.statusBar.setIcon(name, visible, state); -}; - -/* - * Utility API for enabling/disabling auto-hide behavior for status bar & UMP - * @param isEnabled Boolean Auto-hides the status bar and UMP by internal inactivity timer (when true) - */ -Common.prototype._setDisplaySbUmpByActivityEnabled = function(isEnabled) -{ - this._displaySbUmpByActivity = isEnabled; - - if (this._displaySbUmpByActivity) { - // remove any existing non-transparent div - if (this._nonTransparentDiv) - { - utility.removeHTMLElement(this._nonTransparentDiv); - this._nonTransparentDiv = null; - } - - // create a non-transparent div so that opera receives touch events - this._nonTransparentDiv = document.createElement('div'); - this._nonTransparentDiv.className = "CommonNonTransparentDiv"; - document.body.insertBefore(this._nonTransparentDiv, document.body.firstChild); - - // Detect activity to kick everything off - this.activityDetected(true, null); - } - else - { - // Remove the non-transparent div - utility.removeHTMLElement(this._nonTransparentDiv); - this._nonTransparentDiv = null; - - // Shut down any timer we may have running - this._cleanUpInactivityTimer(); - - // Set the activity flag to "true" to force status bar & UMP visibility - this._activityDetected = true; - this._updateSbUmpVisibility(); - - // Reset the activity detected flag - this._activityDetected = false; - } - - // Ignore any prior external show/hide requests - this._sbRequestedState = "none"; -}; - -/* - * Public API for external applications (e.g. TV) to request that the status bar be shown - * @param delay_ms Integer The number of milliseconds to wait before starting the status bar animation - * @param duration_ms Integer The number of milliseconds the status bar animation should take to complete - * @param receipt_cb Function The function to call to signal receipt of the request - */ -Common.prototype.requestStatusBarShown = function(delay_ms, duration_ms, receipt_cb) -{ - log.debug("requestStatusBarShown(" + delay_ms + ", " + duration_ms + ")"); - - // Cache requested status bar timings - if ((utility.toType(delay_ms) == "number") && - (delay_ms >= 0)) { - // Store custom delay timing - this._sbDelay_ms = delay_ms; - } - else { - // Store default delay timing - this._sbDelay_ms = this._defaultSbDelay_ms; - } - if ((utility.toType(duration_ms) == "number") && - (duration_ms >= 0)) { - // Store custom duration timing - this._sbDuration_ms = duration_ms; - } - else { - // Store default duration timing - this._sbDuration_ms = this._defaultSbDuration_ms; - } - - // Remember the external request - this._sbRequestedState = "shown"; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - - // If a receipt callback was provided, ... - if (utility.toType(receipt_cb) === "function") { - // Call it to signal receipt of the request - receipt_cb(); - } -}; - -/* - * Public API for external applications (e.g. TV) to request that the status bar be hidden - * @param delay_ms Integer The number of milliseconds to wait before starting the status bar animation - * @param duration_ms Integer The number of milliseconds the status bar animation should take to complete - * @param receipt_cb Function The function to call to signal receipt of the request - */ -Common.prototype.requestStatusBarHidden = function(delay_ms, duration_ms, receipt_cb) -{ - log.debug("requestStatusBarHidden(" + delay_ms + ", " + duration_ms + ")"); - - // Cache requested status bar timings - if ((utility.toType(delay_ms) === "number") && - (delay_ms >= 0)) { - // Store custom delay timing - this._sbDelay_ms = delay_ms; - } - else { - // Store default delay timing - this._sbDelay_ms = this._defaultSbDelay_ms; - } - if ((utility.toType(duration_ms) === "number") && - (duration_ms >= 0)) { - // Store custom duration timing - this._sbDuration_ms = duration_ms; - } - else { - // Store default duration timing - this._sbDuration_ms = this._defaultSbDuration_ms; - } - - // Remember the external request - this._sbRequestedState = "hidden"; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - - // If a receipt callback was provided, ... - if (utility.toType(receipt_cb) == "function") { - // Call it to signal receipt of the request - receipt_cb(); - } -}; - -/* - * Public hook for notification (from Multicontroller.js) about user activity (touch/keyboard/multicontroller input) - * @param isActive (Boolean) Flag indicating if activity is detected (true) or not (false) - * @param evt (Object) The Opera event that generated the activity - * @param tuiEvent (String) If this is a multicontroller action, the corresponding eventId will be passed - */ -Common.prototype.activityDetected = function(isActive, evt, tuiEvent) -{ - // If we're using local timing ... - if (this._displaySbUmpByActivity) - { - // Get the current position & height of the status bar - // (so we can detect if we've selected it or not) - var det = this.statusBar.divElt.offsetTop; - var deh = this.statusBar.divElt.offsetHeight; - - var legalEvent = false; // will be set to true if this event can trigger activity given the configuration - - // If we have no event, or we have a legal event and the status bar itself wasn't selected, ... - if (evt == null) - { - // null event is used for special case private calls within Common.js - legalEvent = true; - } - else if (evt.type == "mouseup" || evt.type == "mousedown") - { - // mouse events can trigger on "touch" or "both", but only if they are not on the Status Bar - if (this._displaySbUmpActivityTypes == "both" || this._displaySbUmpActivityTypes == "touch") - { - if (evt.pageX <= 800) - { - if (evt.pageY >= (det + deh)) - { - legalEvent = true; - } - else if (evt.type == "mouseup") - { - // mouse up occurred in the status bar. Very specific case to account for touch-and-drag - legalEvent = true; - } - } - } - - } - else if (evt.type == "keydown" || evt.type == "keyup" || evt.type == "mousewheel") - { - // Multicontroller event can only trigger if the activity type is "both" - if (this._displaySbUmpActivityTypes == "both") - { - legalEvent = true; - } - } - - if (legalEvent) - { - log.debug("activityDetected()", isActive, evt); - - // Check if the activity state has changed - var stateChanged = (this._activityDetected != isActive); - - // Update the internal activity state - this._activityDetected = isActive; - - // (Re)start the timer to measure inactivity - if (this._activityDetected) { - // a press down via touch or MC should not trigger the Inactivity timeout - var triggerTimer = true; - if (evt != null) - { - if (evt.type == "mousedown") - { - triggerTimer = false; - } - else if (evt.type == "keydown") - { - // Exception: rotations should still trigger the Inactivity timeout - if (tuiEvent != "cw" && tuiEvent != "ccw") - { - triggerTimer = false; - } - } - } - - if (triggerTimer == false) - { - // just clean up the timer - this._cleanUpInactivityTimer(); - } - else - { - this._startInactivityTimer(); - } - } - - // If the activity state changed, ... - if (stateChanged) { - // ... update the controls' visibility - this._updateSbUmpVisibility(); - } - } - } -}; - -Common.prototype._startInactivityTimer = function() -{ - // Clean up any existing inactivity timer - this._cleanUpInactivityTimer(); - - if (this._displaySbUmpByActivity) { - // (Re)start inactivity timer for a 3-second wait - this._inactivityTimer = setTimeout(this._onInactivityBinder, 3000); - } -}; - -Common.prototype._onInactivity = function() -{ - // Clear the timer that got us here - this._cleanUpInactivityTimer(); - - if (this._displaySbUmpByActivity) { - // Local inactivity timer has expired -- lower the flag - this._activityDetected = false; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - } -}; - -Common.prototype._cleanUpInactivityTimer = function() -{ - if (this._inactivityTimer != null) { - // Clean up any existing inactivity timer - clearTimeout(this._inactivityTimer); - this._inactivityTimer = null; - } -}; - -Common.prototype._updateSbUmpVisibility = function() -{ - if (this._displaySbUmpByActivity || this._sbRequestedState != "none") - { - log.debug("_updateSbUmpVisibility()"); - log.debug("this._sbRequestedState = " + this._sbRequestedState); - log.debug("this._activityDetected = " + this._activityDetected); - log.debug("this._sbnIsDisplayed = " + this._sbnIsDisplayed); - - // Default values for status bar animation timing - var delay_ms = this._defaultSbDelay_ms; - var duration_ms = this._defaultSbDuration_ms; - - // Are the conditions right for showing the status bar? - if ((this._cachedTemplate.properties.statusBarVisible) && ((this._sbRequestedState === "shown") || this._activityDetected || this._sbnIsDisplayed)) { - // Yes -- show it - if (this._sbRequestedState === "shown") { - // Use custom timings from external request - delay_ms = this._sbDelay_ms; - duration_ms = this._sbDuration_ms; - } - - // Show the status bar - this.statusBar.transitionVisible(delay_ms, duration_ms, "slide", true); - } - else if ((this._sbRequestedState == "hidden" || !this._activityDetected) && !this._sbnIsDisplayed) { - // No -- hide it - if (this._sbRequestedState == "hidden") { - // Use custom timings from external request - delay_ms = this._sbDelay_ms; - duration_ms = this._sbDuration_ms; - } - - // Hide the status bar - this.statusBar.transitionVisible(delay_ms, duration_ms, "slide", false); - } - - if (this._activityDetected) { - // Call template's "showing started" callback, if available - if (utility.toType(this._cachedTemplate["onActivityShowing"]) == "function") { - this._cachedTemplate.onActivityShowing(delay_ms, duration_ms); - } - } - else { - // Call template's "hiding started" callback, if available - if (utility.toType(this._cachedTemplate["onActivityHiding"]) == "function") { - this._cachedTemplate.onActivityHiding(delay_ms, duration_ms); - } - } - - // Reset the externally-requested timings to default -- if the status bar was actually shown/hidden - // on this call, the timings were already used. Otherwise, the status bar couldn't be changed (e.g. - // an SBN was displayed), so the timings need to be reset for the next pass. - this._sbDelay_ms = this._defaultSbDelay_ms; - this._sbDuration_ms = this._defaultSbDuration_ms; - } -}; - -/* - * Adds a timed Sbn with the given properties to the Status Bar queue - */ -Common.prototype.startTimedSbn = function(uiaId, sbnId, type, properties) -{ - log.debug("Timed SBN requested by " + uiaId + " with id: " + sbnId); - - var uniqueId = uiaId + sbnId; - this._requestNewSbn(uiaId, uniqueId, type, properties, true); -}; - -/* - * Removes a timed Sbn with the given properties to the Status Bar queue - */ -Common.prototype.cancelTimedSbn = function(uiaId, sbnId, type) -{ - var uniqueId = uiaId + sbnId; - - if (utility.toType(sbnId) != 'string' || !this._knownSbns[uniqueId]) - { - log.debug("Cannot cancel unknown sbnId: " + sbnId + " for App: " + uiaId); - return; - } - - // set the expiration to the current time. this will remove the SBN when it comes up in queue, but - // will not remove it if it is already being displayed - this._knownSbns[uniqueId].expiration = new Date().getTime(); -}; - -/* - * Adds a state-based Sbn with the given properties to the Status Bar queue - */ -Common.prototype.showStateSbn = function(uiaId, sbnId, type, properties) -{ - log.debug("State-based SBN requested by " + uiaId + " with id: " + sbnId); - - var uniqueId = uiaId + sbnId; - this._requestNewSbn(uiaId, uniqueId, type, properties, false); -}; - -/* - * Removes a state-based Sbn with the given properties to the Status Bar queue - */ -Common.prototype.endStateSbn = function(uiaId, sbnId, type) -{ - var uniqueId = uiaId + sbnId; - - if (utility.toType(sbnId) != 'string' || !this._knownSbns[uniqueId]) - { - log.debug("Cannot end unknown sbnId: " + sbnId + " for App: " + uiaId); - return; - } - - log.debug("Ending State SBN: " + sbnId + " for App: " + uiaId); - - // If it is currently being displayed, remove it - if (uniqueId == this._displayedSbnId) - { - this._removeDisplayedSbn(); - } - else if (this._sbnQueue.indexOf(uniqueId) != -1) - { - // if in queue, remove from queue - this._sbnQueue.splice(this._sbnQueue.indexOf(uniqueId), 1); - } - - // if none displayed, display first in queue - if (!this._displayedSbnId) - { - this._displaySbnFromQueue(); - } -}; - -/* - * Sets how many numbers are shown in the LeftButton chrome. Called by List any time - * the visible line count changes - * @param count Number Integer indicating how many line numbers should be shown. - * @param style String Left Button VUI Number style (see Left Button SDD for information) - */ -Common.prototype.setLineNumbers = function(count, style) -{ - if (utility.toType(count) != 'number' || utility.toType(style) != 'string') - { - log.warn("Type error: setLineNumbers must be called with count as integer and style as string"); - return; - } - - this._lineNumberData = {"count": count, "style": style}; - - var showLineNumbers = false; - switch(this._cachedVuiState) - { - case "Not Ready": - break; - case "Idle": - break; - case "Playing Out of Session Alert": - break; - case "Playing Prompt": - // Show "Wait for Tone" SBN - showLineNumbers = true; - break; - case "Listening": - // Show sound meter SBN starting at 0 - showLineNumbers = true; - break; - case "Processing": - // Show SBN with no text or meter - break; - case "Playing Terminating Prompt": - // Show SBN with no text or meter - break; - default: - break; - } - - this._showHideLineNumbers(showLineNumbers); -}; - -/* - * Show or hide the line numbers. - * @param showLineNumbers (Boolean) Show line numbers if the current template supports line numbers. - */ -Common.prototype._showHideLineNumbers = function(showLineNumbers) -{ - if (showLineNumbers == true && this._lineNumberData != null) - { - // validate that this is a List and the List is configured to show line numbers - if (this._cachedTemplate && this._cachedTemplate.templateName == "List2Tmplt") - { - if ((this._cachedTemplate.list2Ctrl.dataList) && - (this._cachedTemplate.list2Ctrl.dataList.vuiSupport == true) && - (this._cachedTemplate.list2Ctrl.properties.numberedList == true) && - (this._cachedTemplate.list2Ctrl.dataList.hasOwnProperty('itemCount') && this._cachedTemplate.list2Ctrl.dataList.itemCount > 0)) - { - this.leftBtn.showLineNumbers(this._lineNumberData.count, this._lineNumberData.style); - } - - } - } - else - { - this.leftBtn.hideLineNumbers(); - } -}; - -/* - * Update this._canShowSbns based on a the cached template. - */ -Common.prototype._updateCanShowSbns = function() -{ - if (this._cachedTemplate.contextInfo.uiaId == "system" && this._cachedTemplate.contextInfo.ctxtId == "DisplayOff") - { - // A special case where the context does not have a status bar but we still need to show SBNs. - this._canShowSbns = true; - } - else if (this._cachedTemplate.properties.statusBarVisible == false) - { - // Do not display SBNs if there is no status bar - this._canShowSbns = false; - } - else if (this._cachedTemplate.contextInfo.uiaId == "ecoenergy" && - (this._cachedTemplate.contextInfo.ctxtId == "EndingFuelConsumption" || this._cachedTemplate.contextInfo.ctxtId == "EndingEffectiveness")) - { - this._canShowSbns = false; - } - else - { - this._canShowSbns = true; - } - - log.debug("Can show SBNs?", this._canShowSbns); - - if (this._canShowSbns == false) - { - // Remove and requeue any displayed SBN - if (this._displayedSbnId) - { - var temp = this._removeDisplayedSbn(); - this._addSbnToQueue(temp, "top"); - } - - // Also remove any displayed Wink - this._removeWinkHelper(); - } -}; - -/* - * helper function to check whether given sbn type is valid - * @param type String type of the SBN - */ -Common.prototype._isValidSbnType = function(type) -{ - var isValidSbnType = false; - if (this._SBN_TYPES[type] != null) - { - isValidSbnType = true; - } - return isValidSbnType; -}; - -/* - * helper function to check whether given sbn type is old one - * @param type String old type of the SBN - */ -Common.prototype._isValidConversionType = function(type) -{ - var isValidConversionType = false; - if (this._SBN_MAPPING_TABLE[type] != null) - { - isValidConversionType = true; - } - return isValidConversionType; -}; - -/* - * helper function to convert old sbn type into valid type - * @param type String old type of the SBN - */ -Common.prototype._convertToValidSbnType = function(type) -{ - var validType; - if (this._isValidConversionType(type)) - { - validType = this._SBN_MAPPING_TABLE[type]; - } - else - { - validType = "unknown"; - log.error("SBN type " + type + " is not valid. Using " + validType + " as a default. See System Specs for possible sbn types"); - } - return validType; -}; - -/* - * Helper function to reduce duplicate logic - */ -Common.prototype._requestNewSbn = function(uiaId, sbnId, type, properties, isTimed) -{ - if (utility.toType(sbnId) != 'string') - { - log.error("Given sbnId was not of valid type 'string'. Please give valid sbnId."); - return; - } - - if (utility.toType(type) != 'string') - { - log.error("Given SBN type must be a string from the table in GUI Common. See Common SDD for possible types."); - } - - if (false == this._isValidSbnType(type)) - { - type = this._convertToValidSbnType(type); - } - - //blacklist will now contain new letter based sbn type, so this check is moved after the type conversion - if (this._SBN_TYPE_BLACKLIST.indexOf(type) != -1) - { - log.debug("Request for blacklisted SBN type:", type, "has been blocked"); - return; - } - - // if already in queue or displayed, update sbn - if (sbnId == this._displayedSbnId) - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - this._displayedSbn.setSbnConfig(properties); // Call API to do live update on Control - - if (isTimed) - { - // extend the timer - clearTimeout(this._displayedSbnTimerId); - this._displayedSbnTimerId = setTimeout(this._sbnFinished.bind(this), this._knownSbns[sbnId].duration); - } - } - else if (this._sbnQueue.indexOf(sbnId) != -1) - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - } - else // if !in queue and !displayed, it's new and we need to check it for priority - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - - // If there's an SBN currently displayed... - if (this._displayedSbnId) - { - // Get priority level of this sbnId - var priority = this._knownSbns[sbnId].priority; - var queueTime = this._SBN_TYPES[type] != null ? this._SBN_TYPES[type].queueTime : this._SBN_TYPES.unknown.queueTime; - var replaceDisplayed = false; - - if (queueTime > 0) - { - // these SBNs DO queue and therefore SBNs of the same priority level should NOT clobber each other - if (priority < this._knownSbns[this._displayedSbnId].priority) // lower # is higher priority - { - replaceDisplayed = true; - } - } - else - { - // these SBNs do NOT queue and therefore SBNs of the same priority level should clobber each other - if (priority <= this._knownSbns[this._displayedSbnId].priority) // lower # is higher priority - { - replaceDisplayed = true; - } - } - - if (replaceDisplayed == true) - { - // call to this._removeDisplayedSbn() will set this._displayedSbnId to null and return displayed Id - var temp = this._removeDisplayedSbn(); - - this._displaySbn(sbnId); // the new one has higher priority and should be displayed - - this._addSbnToQueue(temp, "top"); // old SBN has been replaced and should be added to the queue (top if same priority level) - } - else - { - // new sbnId has lower priority and gets queued - this._addSbnToQueue(sbnId, "bottom"); - } - - } - else // display the new SBN. Some SBNs never go in the queue - { - if (!this._canShowSbns) - { - this._addSbnToQueue(sbnId, "bottom"); - } - else - { - // Tell Status Bar about the SBN - this._sbnIsDisplayed = true; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - - if (this._cachedTemplate.properties.statusBarVisible) - { - // Snap the status bar visible (only if this template is set to display a status bar) - this.statusBar.transitionVisible(0, 0, "slide", true); - } - - // ENTRY POINT #1 - // immediately display this SBN without adding it to the queue - this._displaySbn(sbnId); - - // Notify MMUI to turn on display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 1}}); - } - } - } - - if (this._canShowSbns && !this._displayedSbnId) - { - this._displaySbnFromQueue(); // The new SBN should be the first in queue (if something was displayed) - } -}; - -/* - * Helper function to add Sbns to the queue - * @param sbnId String Unique ID of the SBN to add to the queue - * @param queueOrder String Identifies where to place an SBN in case they are the same priority level ("top" or "bottom") - */ -Common.prototype._addSbnToQueue = function(sbnId, queueOrder) -{ - if (sbnId == null) - { - log.error("_addSbnToQueue: Cannot add null sbnId to queue."); - return; - } - if (!this._knownSbns[sbnId]) - { - log.error("Attempt to add Sbn to queue failed: Could not identify Sbn", sbnId, "in knownSbns variable."); - return; - } - - var currTime = new Date().getTime(); - // state-based SBNs do not expire. An SBN that is Timed and expired does not need to be added to the queue. It would just be removed later anyway. - if (this._knownSbns[sbnId].isTimed && currTime >= this._knownSbns[sbnId].expiration) - { - log.debug("SBN", sbnId, "has expired. No reason to add it to queue"); - return; - } - - // Get priority level of this sbnId - var priority = this._knownSbns[sbnId].priority; - - // Use queuePos so we don't modify the array while looping through it. - var queuePos = this._sbnQueue.length; // default to Array.length so that splice will add it to the end of the Array. - - // Add to queue in appropriate spot - for (var i = 0; i < this._sbnQueue.length; i++) - { - if (queueOrder == "top") - { - if (priority <= this._knownSbns[this._sbnQueue[i]].priority) // lower # is higher priority - { - // insert into queue - queuePos = i; - break; // cut in line and we're done - } - } - else - { - if (priority < this._knownSbns[this._sbnQueue[i]].priority) // lower # is higher priority - { - // insert into queue - queuePos = i; - break; // cut in line and we're done - } - } - - } - - this._sbnQueue.splice(queuePos, 0, sbnId); // at queuePos, remove 0, add sbnId - -}; - -/* - * Helper function that creates or updates an Sbn Object to add to/update the knownSbns variable. - */ -Common.prototype._setKnownSbn = function(uiaId, sbnId, type, properties, isTimed) -{ - var expiration = new Date(); - var priority = 0; - var duration = 0; - - // if type is known, use its properties - if (!this._SBN_TYPES[type]) - { - log.warn("Priority level of Sbn type: " + type + " is unknown. Setting priority to lowest level."); - type = "unknown"; - } - - expiration.setTime(expiration.getTime() + this._SBN_TYPES[type].queueTime); - priority = this._SBN_TYPES[type].priority; - duration = this._SBN_TYPES[type].timedDuration; - - this._knownSbns[sbnId] = { - "uiaId" : uiaId, - "type": type, - "priority": priority, - "isTimed": isTimed, - "duration": duration, // duration is only used for timed Sbns - "expiration": expiration.getTime(), // Set an expiration time stamp for each Sbn - "properties": properties - }; -}; - -/* - * Immediately displays the SBN with the given sbnId - */ -Common.prototype._displaySbn = function(sbnId) -{ - if (!this._knownSbns[sbnId]) - { - log.error("Cannot display requested SBN: " + sbnId + ". SBN cannot be found in knownSbns variable."); - return; - } - - if (!this._canShowSbns) - { - // safety check. We should never get here. - log.debug("Cannot show new SBNs in this context."); - return; - } - - log.info("Displaying new sbn: " + sbnId); - this._displayedSbnId = sbnId; - this._displayedSbn = framework.instantiateControl(this._knownSbns[sbnId].uiaId, document.body, "SbnCtrl", this._knownSbns[sbnId].properties); - if (this._knownSbns[sbnId].isTimed) - { - this._displayedSbnTimerId = setTimeout(this._sbnFinished.bind(this), this._knownSbns[sbnId].duration); - } -}; - -/* - * Immediately destroys and removes the currently displayed SBN - * @return String Returns the sbnId of the SBN that was removed - */ -Common.prototype._removeDisplayedSbn = function() -{ - log.info("Removing currently displayed SBN: " + this._displayedSbnId); - clearTimeout(this._displayedSbnTimerId); - framework.destroyControl(this._displayedSbn); - - var removedId = this._displayedSbnId; - this._displayedSbn = null; - this._displayedSbnId = null; - - return removedId; -}; - -/* - * Chooses the first active SBN off the queue and displays it. - * @return String The ID of the new SBN that gets displayed. null of no SBN is displayed. - */ -Common.prototype._displaySbnFromQueue = function() -{ - var newSbnToDisplay = null; - if (!this._canShowSbns) - { - // safety check. We should never get here. - log.debug("Cannot show queued SBNs in this context."); - return newSbnToDisplay; - } - - if (this._sbnQueue.length == 0) - { - // nothing to display: EXIT POINT #1 - this._sbnIsDisplayed = false; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - this._updateSbUmpVisibility(); - - // Notify MMUI to turn off display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 0}}); - return newSbnToDisplay; - } - - var sbnId = null; - var flaggedForRemoval = new Array(); - - // check expiration - var currTime = new Date().getTime(); - - for (var i = 0; i < this._sbnQueue.length; i++) - { - sbnId = this._sbnQueue[i]; - - // state-based SBNs do not expire. An SBN in the queue that is state-based or -not- expired should be displayed immediately - if (this._knownSbns[sbnId].isTimed && currTime >= this._knownSbns[sbnId].expiration) - { - flaggedForRemoval.push(sbnId); - } - else - { - this._displaySbn(sbnId); - newSbnToDisplay = sbnId; - flaggedForRemoval.push(sbnId); - break; - } - } - - // splice any expired SBNs from the queue - for (var j = 0; j < flaggedForRemoval.length; j++) - { - this._sbnQueue.splice(this._sbnQueue.indexOf(flaggedForRemoval[j]), 1); // remove from queue - - if (flaggedForRemoval[j] != this._displayedSbnId) - { - delete this._knownSbns[flaggedForRemoval[j]]; // delete from known Sbns - } - } - - flaggedForRemoval = null; - - if (this._sbnQueue.length == 0 && !this._displayedSbnId) - { - // no more SBNs to display: EXIT POINT #2 - this._sbnIsDisplayed = false; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - this._updateSbUmpVisibility(); - - // Notify MMUI to turn off display if needed. - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": 0}}); - } - - return newSbnToDisplay; -}; - -/* - * Callback for when a timed SBN completes - */ -Common.prototype._sbnFinished = function() -{ - this._removeDisplayedSbn(); - this._displaySbnFromQueue(); -}; - -/* - * (internal) Called by framework. Sets the style of the left button to - * either "goBack" or "menuUp" - */ -Common.prototype.setLeftBtnStyle = function(style) -{ - this.leftBtn.setStyle(style); -}; - -/* - * Updates the clock to display the value given. Value should be given in Unix format - * @param milliseconds Number the current time in number of milliseconds in a date string since midnight of January 1, 1970 - */ -Common.prototype.updateSbClock = function(milliseconds) -{ - var type = utility.toType(milliseconds); - if (type != 'number' && type != 'date') - { - log.warn("Common.updateSbClock can only accept an argument of type Number or Date"); - return; - } - - this._cachedTime = milliseconds; - this.statusBar.updateClock(milliseconds); - - // Update the clock in the OffScreen control if it that is the current template - if (this._cachedTemplate && this._cachedTemplate.templateName == "OffScreenTmplt" && this._cachedTemplate.updateClock) - { - this._cachedTemplate.updateClock(); - } -}; - -Common.prototype.getCurrentTime = function() -{ - var type = utility.toType(this._cachedTime); - var time = 0; - - if (type == 'number') - { - time = this._cachedTime; - } - else if (type == 'date') - { - time = this._cachedTime.getTime(); - } - - return time; -}; - -/* - * Removes the wink from the screen. This is called after the wink times out - * @param ctrlObj Object Reference to the Wink Control Object. - * @param appData Object App data stored by Common - * @param params Object Additional params passed by WinkCtrl - */ -Common.prototype._alertComplete = function(ctrlObj, appData, params) -{ - log.debug("Wink complete: " + ctrlObj.properties.alertId); - - this._removeWinkHelper(); -}; - -Common.prototype._removeWinkHelper = function() -{ - if (this._wink) - { - log.info("wink is", this._wink); - framework.websockets.sendAlertCompleteMsg(this._wink.uiaId, this._wink.properties.alertId); - - framework.destroyControl(this._wink); - this._wink = null; - } -}; - -/* - * Callback for when the Status Bar is clicked - * @param ctrlObj (Object) Reference to the button control object in status bar that was clicked - * @param appData (Object) Data passed in by the app when the control was instantiated - * @param params (Object) Optional params passed by the control object - */ -Common.prototype._statusBarClicked = function(ctrlObj, appData, params) -{ - log.debug("status bar clicked", ctrlObj, appData, params); - if (params.statusBtn == "home") - { - if (this._diagEntrySequence != 2 ) // 2 here indicates the sequence was completed - { - framework.sendEventToMmui("common", "Global.IntentHome"); - } - } - -}; - -/* - * Callback for when the Status Bar is long pressed - * @param ctrlObj (Object) Reference to the button control object in status bar that was clicked - * @param appData (Object) Data passed in by the app when the control was instantiated - * @param params (Object) Optional params passed by the control object - */ -Common.prototype._statusBarLongPress = function(ctrlObj, appData, params) -{ - if (params.statusBtn == "clock") - { - log.info("Clock Long Press Detected."); - this._diagEntrySequence = 1; - // clear exisiting timeout if any - clearTimeout(this._clockHomeButtonLongPressIntervalId); - //time interval between clock button long press and home button long press should be less than 9 secs - this._clockHomeButtonLongPressIntervalId = setTimeout(this._statusBarLongPressTimerHandler.bind(this),9000); - } - else if (params.statusBtn == "home" && this._diagEntrySequence == 1 && this._clockHomeButtonLongPressIntervalId) - { - log.info("Entering Diagnostics App"); - this._diagEntrySequence = 2; - framework.sendEventToMmui("syssettings", "SelectDiagnostics"); - } - -}; - -Common.prototype._statusBarLongPressTimerHandler = function() -{ - this._clockHomeButtonLongPressIntervalId = null; - this._diagEntrySequence = 0; -}; - -/* - * Callback for when the left button is pressed. - * @param controlObj (object) Reference to the LeftBtn that was pressed - */ -Common.prototype._leftBtnSelected = function(controlObj, appData, params) -{ - this._leftBtnSelectEvent(params.style); -}; - -/* - * Helper function to reduce duplicate logic. Called when the left button is selected either - * via touch or multicontroller -OR- when the TUI Left Hard Key is pressed. - * @param style String Style of the left button (determines which event to send to MMUI) - */ -Common.prototype._leftBtnSelectEvent = function(style) -{ - if (this.cmnCtrlsDisabled) - { - return; - } - - // Send an appropriate event based on the current style of the left button - switch (style) - { - case "goLeft": // legacy behavior TODO: remove when all Apps have updated - framework.sendEventToMmui("common", "Global.GoLeft"); - break; - case "goBack": // go back to the previous screen - framework.sendEventToMmui("common", "Global.GoBack"); - break; - case "menuUp": // go up one menu level - framework.sendEventToMmui("common", "Global.MenuUp"); - break; - default: - log.warn("There is no defined event for left button style: " + style); - break; - } -}; - -Common.prototype.getContextCapture = function() -{ - return { - leftBtnHasFocus : this.leftBtn.divElt.style.visibility === 'visible' && this.leftBtn.btnInstance.hasFocus - }; -}; - -Common.prototype.restoreContext = function(restoreData) -{ - if (restoreData.commonContextCapture && restoreData.commonContextCapture.leftBtnHasFocus) - { - restoreData.skipRestore = true; - } -}; - -/* - * Cause an audible beep to be played. - * @param pressType (String) Indicates a short press or a long press. Valid values are “Short” and “Long”. - * @param eventCause (String) Indicates the user interaction that caused the beep. Valid values are “Touch”, “Multicontroller”, and “Hardkey”. - */ -Common.prototype.beep = function(pressType, eventCause) -{ - var validPressTypes = [ "Short", "Long" ]; - if (utility.toType(pressType) !== "string" || validPressTypes.indexOf(pressType) === -1) - { - log.warn("Invalid pressType parameter passed to common.beep(). Valid values are 'Short' or 'Long'."); - return; - } - - var validEventCauses = [ "Touch", "Multicontroller", "Hardkey" ]; - if (utility.toType(eventCause) !== "string" || validEventCauses.indexOf(eventCause) === -1) - { - log.warn("Invalid eventCause parameter passed to common.beep(). Valid values are 'Touch' or 'Multicontroller' or 'Hardkey'"); - return; - } - - if (pressType == "Short" && eventCause == "Multicontroller") - { - // do not send this - return; - } - - var args = { - "payload" : { - "pressType" : pressType, - "eventCause" : eventCause - } - }; - - log.info("Sending PlayAudioBeep", pressType, eventCause); - framework.sendEventToMmui("audiosettings", "PlayAudioBeep", args); -}; - -/* - * Mute message handler - */ -Common.prototype._HandleStatusUpdateVolume = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - var isMuted = msg.params.payload.volumeOnOffStatus === "VolumeOff"; - if (isMuted !== this._isMuted) - { - this._isMuted = isMuted; - this._isMutedChanged(); - } - } -}; - -/* - * Called when the value of _isMuted changes - */ -Common.prototype._isMutedChanged = function() -{ - var action = this._getMuteOverlayAction(); - switch (action) - { - case "wink": - this._showMuteWink(3000); - break; - - case "persistentWink": - this._showMuteWink(null); - break; - - case "sbn": - this._showMuteSbn(); - break; - - default: - this._hideMuteWink(); - this._hideMuteSbn(); - break; - - } -}; - -Common.prototype._showMuteSbn = function() -{ - var properties = { - sbnStyle: "Style02", - }; - - if (this._isMuted) - { - properties.imagePath1 = "IcnSbnMuteOn.png"; - properties.text1Id = "common.muteOn"; - } - else - { - properties.imagePath1 = "IcnSbnMuteOff.png"; - properties.text1Id = "common.muteOff"; - } - - this.startTimedSbn("common", "TimedSbn_StatusUpdateVolumeOnOff", "typeA", properties); -}; - -Common.prototype._hideMuteSbn = function() -{ - this.cancelTimedSbn("common", "TimedSbn_StatusUpdateVolumeOnOff", "typeA"); -}; - -Common.prototype._showMuteWink = function(winkTimeout) -{ - var properties = { - "style": "style05", - "image1": "common/images/icons/IcnWinkUnMute.png", - "winkTimeout": winkTimeout, - "alertId": "", - "completeCallback": this._muteWinkComplete.bind(this) - }; - - if (this._isMuted) - { - properties.image1 = "common/images/icons/IcnWinkMute.png"; - } - - var newWink = framework.instantiateControl("common", document.body, "WinkCtrl", properties); - - // If there's a Wink currently displayed (e.g. persistentWink), get rid of it - this._hideMuteWink(); - this._muteWink = newWink; -}; - -Common.prototype._hideMuteWink = function() -{ - if (this._muteWink) - { - framework.destroyControl(this._muteWink); - this._muteWink = null; - } -}; - -Common.prototype._muteWinkComplete = function() -{ - this._hideMuteWink(); -}; - -/* - * Returns one of: "persistentWink", "wink", "sbn" - */ -Common.prototype._getMuteOverlayAction = function() -{ - if (this._cachedTemplate && this._cachedTemplate.templateName === "NowPlaying4Tmplt") - { - if (this._isMuted) - { - return "persistentWink"; - } - else - { - return "wink"; - } - } - else - { - var uiaId = framework.getCurrentApp(); - var ctxtId = framework.getCurrCtxtId(); - if (this.getContextCategory(uiaId, ctxtId) === "Entertainment") - { - return "wink"; - } - } - return "sbn"; -}; - -Common.prototype._updateMuteWinkOnTransition = function(prevTepmlate, currTemplate) -{ - if (this._isMuted && currTemplate && currTemplate.templateName === "NowPlaying4Tmplt") - { - this._showMuteWink(null); - } - else - { - this._hideMuteWink(); - } -}; - -/* - * Process Global.MenuUpReceived messages. - */ -Common.prototype._MenuUpReceived = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - this._menuUpReceiverApp = msg.params.payload.receiverApp; - } -}; - -/* - * Utility function to get the context category (domain) for a given application/context - * @param uiaId Application ID - * @param ctxtId Context ID - * @returns Domain string value (e.g. "Applications", "Communication", "Entertainment") - */ -Common.prototype.getContextCategory = function(uiaId, ctxtId) -{ - return this._contextCategory.getContextCategory(uiaId, ctxtId); -}; - -/* - * Utility function to get the status bar icon for a given context category (domain) - * @param domain Domain string value (e.g. "Applications", "Communication", "Entertainment") - * @returns Icon image file name - */ -Common.prototype.getContextCategorySbIcon = function(domain) -{ - return this._contextCategory.getContextCategorySbIcon(domain); -}; - -framework.registerCommonLoaded(["common/controls/StatusBar", - "common/controls/LeftBtn", - "common/controls/Wink", - "common/controls/Button", - "common/controls/Dialog3", - "common/controls/Sbn"], true); diff --git a/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.58.00.250A-NA b/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.58.00.250A-NA deleted file mode 100644 index f627867..0000000 --- a/app/files/tweaks/config_org/pause-on-mute/jci/gui/common/js/Common.js.58.00.250A-NA +++ /dev/null @@ -1,2631 +0,0 @@ -/* - Copyright 2012 by Johnson Controls - __________________________________________________________________________ - - Filename: Common.js - __________________________________________________________________________ - - Project: JCI-IHU - Language: EN - Author: awoodhc - Date: 08.27.2012 - __________________________________________________________________________ - - Description: IHU GUI Common - - Revisions: - v0.1 (27-Aug-2012) Create Common to handle all "system-wide" logic - v0.2 (27-Aug-2012) Added basic logic for "global" controls, multicontroller events, transitions, ctrl clicks, basic BG logic - v0.3 (28-Aug-2012) Added logic for alerts - v0.4 (11-Oct-2012) Added logic to hide Home Button while on Home Screen - v0.5 (04-Nov-2012) Added API to display App Name in Status Bar - Added Diag Entry logic - v0.6 (08-Nov-2012) Added API for Setting the Left Button Style. - v0.7 (19-Nov-2012) Changed Alert event to conform with MMUI standards. Added API to set the Status Bar Clock with value from MMUI. - v0.8 (26-Nov-2012) Fixed Diagnostics Entry. Common now counts a sequence to make sure the sequence is complete before resetting. - v0.9 (03-Dec-2012) Added message table for handling MMUI common messages and handling for LanguageChangeStatus msg - v1.0 (05-Dec-2012) Added API to set state of status bar icons - v1.1 (21-Jan-2012) Added new SBN and Wink logic - __________________________________________________________________________ - - */ - -log.addSrcFile("Common.js", "common"); -//log.setLogLevel("common", "debug"); - -function Common() -{ - log.debug("constructor called..."); - - //-- public variables - this.moduleName = "common"; // (String) Name of this module (used in place of uiaId when instantiating controls) - this.statusBar = null; // (Object) Status Bar Control Object - this.leftBtn = null; // (Object) Left Button Control Object - - this.cmnCtrlsDisabled = false; // (Boolean) Whether to Status Bar/Left Button are disabled due to a dialog - - - //-- private variables - - this._cachedTime = 0; // (Number) Stores the time value sent from MMUI via GUI_SYSSETTINGS - this._cachedTemplate = null; // (Object) template currently active in the DOM. Framework updates this. - this._menuUpReceiverApp = null; // (String) cached uiaId sent from MMUI when during a transition caused by a Menu Up action - this._canShowSbns = false; // (Boolean) true if Common can display SBNs over the cached template - - this._bgDiv1 = null; // (HTMLElement) the background div - this._bgDiv2 = null; // (HTMLElement) used to transition between 2 backgrounds - this._rightChrome = null; // (HTMLElement) the div used to display the right-hand chrome - this._customBgSet = false; // (Boolean) true if there is a custom bg set by the current template - this._defaultBgPath = "common/images/background.png"; // (String) the css path to the default bg image - this._currentBgPath = this._defaultBgPath; // (String) the css path to the current bg image - - this._wink = null; // (Object) The active Wink Control Object (null if none displayed) - this._winkTimeout = guiConfig.winkTimeout; // (Number) milliseconds a Wink will stay on screen - - this._muteWink = null; // (Object) The Entertainment Mute Wink Control Object (null if none displayed) - - this._cachedVuiState = null; // (String) Last VUI state sent from MMUI. - this._vuiHelpDialog = null; // (Object) The active VUI Help Dialog Control (null if none displayed) - this._vuiExamplesDialog = null; // (Object) The active VUI Examples Dialog Control (null if none displayed) - this._lineNumberData = null; // (Object) Contains data passed from a List pertaining to the VUI line numbers - - this._diagEntrySequence = 0; // (Number) 1 if the Diagnostics entry button sequence has begun. 2 if it has completed. - this._clockHomeButtonLongPressIntervalId = null; - - this._atSpeed = false; // (Boolean) true if AtSpeed event is received from MMUI - this._isMuted = false; // (Boolean) true if entertainment audio is currently muted - - this._contextCategory = new ContextCategory(); // (Object) Contains a lookup table to determine a context's category. - - //-- Status Bar Auto-Hide Variables - // MPP 09/16/2013 SW00107357 - this._displaySbUmpByActivity = false; // (Boolean) Master switch for auto-hide status bar/UMP feature - this._displaySbUmpActivityTypes = "both"; // (String) "both" for both touch & MC input to count as activity, "touch" for touch-only input - this._inactivityTimer = null; // (Object) The timer used to measure (in)activity for auto-hiding the status bar & UMP - this._onInactivityBinder = this._onInactivity.bind(this); // (Callback) Bind the timer callback once to save memory - this._activityDetected = false; // (Boolean) Flag raised on touch/MC input; lowered when inactivity timer expires - this._sbRequestedState = "none"; // (String) External request to show/hide status bar - this._sbDelay_ms = -1; // (Integer) # of milliseconds before status bar animation starts (external request) - this._sbDuration_ms = -1; // (Integer) # of milliseconds status bar animation should take (external request) - this._defaultSbDelay_ms = 0; // (Integer) Default delay timing for status bar animation - this._defaultSbDuration_ms = 500; // (Integer) Default duration timing for status bar animation - this._defaultHelpPrompt = "SpeechNotAllowed_Help"; // (string) help promp name which requires default help screen - - //-- Status Bar Notification Variables - /* - * See _setKnownSbn() function for _knownSbns variable properties - */ - this._knownSbns = new Object(); // (Object) key'd to SbnId, value is SbnObject with information necessary to display Sbn - this._sbnIsDisplayed = false; // (Boolean) Flag indicating whether an SBN is displayed (true) or not (false). - this._displayedSbn = null; // (Object) Refernce to the currently displayed Sbn Control. - this._displayedSbnId = null; // (String) SbnId of the currently displayed Sbn. null if none is displayed - this._displayedSbnTimerId = 0; // (Number) Timer ID used for timed Sbns. - this._sbnQueue = new Array(); // (Array) Queue of all current Sbns by Id. 0 is next in line to be dispalyed. - this._lastDisplayStateSent = 0; // (Number) saves last display off notification state - - // Default SBN values used where value is not specified in UI Spec. - var dfltDuration = 2000; // (Number) default number of milliseconds - var dfltQueue = 0; // (Number) default number of milliseconds - - // NOTE: State-based SBNs do not expire, but Timed SBNs should be queueTime 0 so that they do not re-appear (exception: driverId) - - this._SBN_TYPES = { // (Object) contains list of Sbn Priorities by type, defined in System UI Spec - - //replaced old sbn types with new letter based sbn types(As per SCR SW00155262) - "typeA": {"priority": 1, "timedDuration": 2000, "queueTime": 0}, // 1 is highest priority - "typeB": {"priority": 2, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "typeL": {"priority": 3, "timedDuration": 5000, "queueTime": 60000}, - "typeC": {"priority": 4, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "typeD": {"priority": 5, "timedDuration": 5000, "queueTime": 0}, - "typeE": {"priority": 6, "timedDuration": 5000, "queueTime": 0}, - "typeF": {"priority": 7, "timedDuration": 5000, "queueTime": 0}, - "typeG": {"priority": 8, "timedDuration": 5000, "queueTime": 0}, - "typeI": {"priority": 9, "timedDuration": 5000, "queueTime": 0}, - "typeJ": {"priority": 10, "timedDuration": 5000, "queueTime": 0}, - "typeK": {"priority": 11, "timedDuration": dfltDuration, "queueTime": dfltQueue}, - "unknown": {"priority": 100, "timedDuration": dfltDuration, "queueTime": dfltQueue} - }; - - this._SBN_MAPPING_TABLE = { // contains mapping of old sbn types with new letter based sbn types(As per SCR SW00155262) - "volumeStatus" : "typeA", - "vrStatus" : "typeB", - "driverId" : "typeL", - "navigationNear" : "typeC", - "deviceConnected" : "typeD", - "entertainmentInfo" : "typeE", - "errorNotification" : "typeF", - "btConnecting" : "typeG", - "deviceRemoved" : "typeI", - "navigationFar" : "typeJ", - "systemFailure": "typeK", - "unknown": "unknown" - }; - - // Any SBN type in the blacklist will be blocked if it is requested. This is a centralized fix for evolving requirements. - this._SBN_TYPE_BLACKLIST = [ - "typeK" - ]; - - //@formatter:off - this._messageTable = { - "LanguageChangeStatus" : this._LanguageChangeStatusMsgHandler.bind(this), - "Global.AtSpeed" : this._AtSpeedMsgHandler.bind(this), - "Global.NoSpeed" : this._NoSpeedMsgHandler.bind(this), - "Global.PageUp" : this._PageUpDownMsgHandler.bind(this), - "Global.PageDown" : this._PageUpDownMsgHandler.bind(this), - "vuiState" : this._vuiStateMsgHandler.bind(this), - "vuiMicLevel" : this._vuiStateMsgHandler.bind(this), - "Global.SelectLineNumber" : this._SelectLineNumMsgHandler.bind(this), - "Global.StartHelp" : this._ShowVuiHelpHandler.bind(this), - "Global.HideHelp" : this._HideVuiHelpHandler.bind(this), - "Global.StartExamples" : this._ShowVuiExamplesHandler.bind(this), - "Global.HideExamples" : this._HideVuiExamplesHandler.bind(this), - "Global.StatusUpdateVolumeOnOff" : this._HandleStatusUpdateVolume.bind(this), - "Global.MenuUpReceived" : this._MenuUpReceived.bind(this) - - }; // end of this._messageTable - //@formatter:on - - - //-- DOM logic - // Add the background image to the body - this._bgDiv1 = document.createElement('div'); - this._rightChrome = document.createElement('div'); - - this._bgDiv1.id = "CommonBgImg1"; - this._bgDiv1.className = "CommonBgImg"; - - this._rightChrome.id = "CommonRightChrome1"; - this._rightChrome.className = "CommonRightChrome"; - this._rightChrome.style.visibility = "hidden"; - - document.body.appendChild(this._bgDiv1); - document.body.appendChild(this._rightChrome); - - // Add controls to the DOM - this.addControls(); - - this._remoteUiBtns = new Object(); -}; - -/* (internal - called by framework) - * Instantiates the LeftBtnControl and StatusBarCtrl (usually only happens when the language is changed) - */ -Common.prototype.addControls = function() -{ - log.debug("addControls called."); - - // Status Bar - if (this.statusBar)//never add more than one instance of these controls - { - log.debug("status bar exists"); - // MPP 08/29/2013 SW00127573 - // Refresh status bar, rather than re-instantiating it, when languages change - //framework.destroyControl(this.statusBar); - //this.statusBar = null; - this.statusBar._refresh(); - } - else - { - log.debug("instantiating status bar"); - // create the status bar - var statusProp = { - "selectCallback" : this._statusBarClicked.bind(this), - "longPressCallback" : this._statusBarLongPress.bind(this), - "onFocusCallback" : this._statusBarFocused.bind(this), - }; - - this.statusBar = framework.instantiateControl(this.moduleName, document.body, "StatusBarCtrl", statusProp); - } - - // Left Button - if (this.leftBtn) - { - //never add more than one instance of these controls - //framework.destroyControl(this.leftBtn); - //this.leftBtn = null; - } - else - { - // create the left button - var lftBtnProp = {"selectCallback" : this._leftBtnSelected.bind(this)}; - - this.leftBtn = framework.instantiateControl(this.moduleName, document.body, "LeftBtnCtrl", lftBtnProp); - - this._checkTemplateProperties(); - } -}; - -/* (internal - called by framework) - * Destroys the LeftButtonControl and StatusBarCtrl (usually only happens when the language is changed) - */ -Common.prototype.removeControls = function() -{ - if (this.statusBar) - { - framework.destroyControl(this.statusBar); - this.statusBar = null; - } - - if (this.leftBtn) - { - framework.destroyControl(this.leftBtn); - this.leftBtn = null; - } - -}; - -/* - * Checks templates properties for global controls. Called when a language change occurs - */ -Common.prototype._checkTemplateProperties = function() -{ - log.debug("_checkTemplateProperties called."); - var template = this._cachedTemplate; - //we should be able to use the cached template here, because when changing languages, we don't change context - - var data; - if (template) - { - data = this._calcTransitionData(template); - } - else - { - //defaults - log.debug(" No template could be found. Using default values."); - data = new Object(); - data.leftButtonVisible = false; - data.statusBarVisible = true; - } - - log.debug(" Left Btn Visible: " + data.leftButtonVisible + ", Status Bar Visible: " + data.statusBarVisible); - - - if (data.leftButtonVisible) - { - this.leftBtn.divElt.style.visibility = 'visible'; - } - else - { - this.leftBtn.divElt.style.visibility = 'hidden'; - } - - if (data.statusBarVisible) - { - this.statusBar.divElt.style.visibility = 'visible'; - } - else - { - this.statusBar.divElt.style.visibility = 'hidden'; - } - -}; - -/* (internal) - * Called by framework when a context change occurs and data is needed. - * @param template (object) The template that will be transitioned to. - */ -Common.prototype.getCommonTransitionData = function(template) -{ - if (template == null) - { - log.error("getCommonTransitionData called with null template."); - return; - } - - // Terminate any activity timer that may be running so we don't see the - // previous template's status bar or UMP sliding during the transition - this._cleanUpInactivityTimer(); - - this._updateMuteWinkOnTransition(this._cachedTemplate, template); - - this._closeVuiHelpOnTransition(template); - this._closeVuiExamplesOnTransition(template); - - // tell left button or the previous template to lose focus before the transition starts - this.handleControllerEvent('lostFocus'); - - // cache template: - this._cachedTemplate = template; - - // Hide VUI Numbers - this.leftBtn.hideLineNumbers(); - - // Update _canShowSbns variable and hide active SBN if necessary - this._updateCanShowSbns(); - - var data = this._calcTransitionData(template); - - - if ((this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId])&& (this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId].ctxtList.indexOf(this._cachedTemplate.contextInfo.ctxtId) != -1)) - { - this.statusBar.showRemoteUiButton(this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId]); - } - else - { - this.statusBar.hideRemoteUiButton(); - } - - return data; -}; - -/* (private) - * Returns an object with common transition data for the upcoming transition - * @param template (object) The template that will be transitioned to. - * @return (object) Object containing common transition data - */ -Common.prototype._calcTransitionData = function(template) -{ - if (template.properties.customBgImage) - { - if (template.properties.customBgImage != this._currentBgPath) - { - this._bgDiv2 = document.createElement('div'); - this._bgDiv2.id = "CommonBgImg2"; - this._bgDiv2.className = "CommonBgImg"; - this._bgDiv2.style.backgroundImage = "url(" + template.properties.customBgImage + ")"; - this._currentBgPath = template.properties.customBgImage; - document.body.insertBefore(this._bgDiv2, this._bgDiv1); - this._customBgSet = true; - } - } - else if (this._customBgSet == true) // don't transition to default bg on a dialog - { - this._bgDiv2 = document.createElement('div'); - this._bgDiv2.id = "CommonBgImg2"; - this._bgDiv2.className = "CommonBgImg"; - this._bgDiv2.style.backgroundImage = "url(" + this._defaultBgPath + ")"; - this._currentBgPath = this._defaultBgPath; - document.body.insertBefore(this._bgDiv2, this._bgDiv1); - this._customBgSet = false; - } - - // Check for menu up - var menuUpUsed = false; - if (this._menuUpReceiverApp) - { - if (this._menuUpReceiverApp === this._cachedTemplate.contextInfo.uiaId) - { - menuUpUsed = true; - } - this._menuUpReceiverApp = null; - } - - //@formatter:off - var commonTransitionData = { - // references to system control objects - "statusBar" : this.statusBar, - "leftButton" : this.leftBtn, - // booleans - "statusBarVisible" : template.properties.statusBarVisible, - "leftButtonVisible" : template.properties.leftButtonVisible, - "menuUpUsed": menuUpUsed, - // bg data - "customBgImage" : template.properties.customBgImage, - "bgDiv1" : this._bgDiv1, - "bgDiv2" : this._bgDiv2, - // other - "rightChrome" : this._rightChrome, - "rightChromeVisible": (template.properties.rightChromeVisible === true) ? true : false - }; - - if (template.properties.isDialog) - { - // Preserve left button visibility from the previous context when going to a dialog context. - commonTransitionData.leftButtonVisible = this.leftBtn.divElt.style.visibility === "visible"; - commonTransitionData.rightChromeVisible = this._rightChrome.style.visibility === "visible"; - } - - //@formatter:on - return commonTransitionData; -}; - -/* (internal) - * Callback for when the controls transition completes. Currently only used for custom backgrounds - * @param transitionData (object) the data that was used during the transition - */ -Common.prototype.commonControlsUpdateComplete = function(transitionData) -{ - if (transitionData.bgDiv2) - { - // bgDiv2 transitioned in, so we need to remove bgDiv1 - utility.removeHTMLElement(transitionData.bgDiv1.id); - - this._bgDiv1 = this._bgDiv2; - this._bgDiv1.id = "CommonBgImg1"; - this._bgDiv2 = null; - } - - if (framework.getCurrentApp() == "syssettings" && framework.getCurrCtxtId() == "DisplayTab") - { - this.statusBar.enableClockBtn(true); - } - else - { - this.statusBar.enableClockBtn(false); - this._diagEntrySequence = 0; // reset the sequence on context change - } - - // Retrieve the types of input that will count as user activity, and then - // turn on activity monitoring for this context/template (if needed) - this._displaySbUmpActivityTypes = "both"; - if (this._cachedTemplate.properties.displaySbUmpActivityTypes === "both" || - this._cachedTemplate.properties.displaySbUmpActivityTypes === "touch") { - this._displaySbUmpActivityTypes = this._cachedTemplate.properties.displaySbUmpActivityTypes; - } - - this._setDisplaySbUmpByActivityEnabled(this._cachedTemplate.properties.displaySbUmpByActivity == true); - - // show SBN if needed - if (this._canShowSbns) - { - // If there's NO SBN displayed - if (!this._displayedSbnId) - { - // ENTRY POINT #2 - // If a new SBN gets displayed, _displaySbnFromQueue will return the ID - var newSbnId = this._displaySbnFromQueue(); - - if (newSbnId) - { - // Tell Status Bar about the SBN - this._sbnIsDisplayed = true; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - - if (this._cachedTemplate.properties.statusBarVisible) - { - // Snap the status bar visible (only if this template is set to display a status bar) - this.statusBar.transitionVisible(0, 0, "slide", true); - } - - // Notify MMUI to turn on display if needed. - this._sendDisplayOffNotification(1); - } - - } - } - - this.handleControllerEvent('acceptFocusInit'); - -}; - -/* (internal - Called by Controls) - * Sends a "lostFocus" Multicontroller event to the currently focused Control so that the - * Control calling stealFocus() can gain focus. - * After calling this API, the calling Control -must- gain focus automatically. - */ -Common.prototype.stealFocus = function() -{ - var response = null; - if (this.statusBar.remoteUiBtn) // the events will be passed only when the carPlay button exists - { - if (this.statusBar.remoteUiBtn.hasFocus) - { - response = this.statusBar.handleControllerEvent("lostFocus"); - } - } - if (this.leftBtn.btnInstance.hasFocus) - { - response = this.leftBtn.handleControllerEvent("lostFocus"); - } - else if (this._cachedTemplate && this._cachedTemplate.handleControllerEvent) - { - response = this._cachedTemplate.handleControllerEvent("lostFocus"); - } - else - { - log.warn("Cannot steal focus. Common's cached template is either null or does not have handleControllerEvent."); - } -}; - -/* (internal - Called by framework) - * Handles multicontroller events, specifically the left event for the leftBtn - * @param eventID (string) any of the “Internal event name” values in IHU_GUI_MulticontrollerSimulation.docx (e.g. 'cw', - * 'ccw', 'select') - * @return true if common 'consumed' the tui event. false otherwise. - */ -Common.prototype.handleControllerEvent = function(eventId, firstEvent) -{ - if (eventId == "goBack") // Note: "goBack" event sent from Multicontroller.js indicates the TUI back key has been pressed - { - framework.sendEventToMmui("common", "Global.GoBack"); - } - - // The first event is thrown away, but "controllerActive" is still passed to the template/control to change its highlight - // Thus, "ccw" will come in with firstEvent true, but "controllerActive" will also come in separately with firstEvent false - if (firstEvent) - { - log.debug(" firstEvent detected. Ignoring."); - return; - } - - // Test whether one of Common/Global controls has multicontroller focus and react accordingly - - if (this._cachedTemplate && this._cachedTemplate.handleControllerEvent) - { - // always pass along controller active and touch active - if (eventId != "touchActive" && eventId != "controllerActive") - { - if (this.leftBtn.btnInstance.hasFocus) - { - var response = this.leftBtn.handleControllerEvent(eventId); - if (response == "giveFocusRight") - { - var response = this._cachedTemplate.handleControllerEvent("acceptFocusFromLeft"); - if (response == "consumed") - { - this.leftBtn.handleControllerEvent("lostFocus"); - } - } - } - else if (this.statusBar.remoteUiBtn && this.statusBar.remoteUiBtn.hasFocus) - { - // route events to Status Bar - var response = this.statusBar.handleControllerEvent(eventId); - if (response == "giveFocusDown") - { - var response = this._cachedTemplate.handleControllerEvent("acceptFocusFromTop"); - if (response == "consumed") - { - this.statusBar.handleControllerEvent("lostFocus"); - } - } - } - else - { - var response = this._cachedTemplate.handleControllerEvent(eventId); - if (response == "giveFocusLeft" && this._cachedTemplate.properties.leftButtonVisible) - { - this.leftBtn.handleControllerEvent("acceptFocusFromRight"); - this._cachedTemplate.handleControllerEvent("lostFocus"); - } - else if (response == "giveFocusUp" && this.statusBar.remoteUiBtn) - { - this.statusBar.remoteUiBtn.handleControllerEvent("acceptFocusFromBottom"); - this._cachedTemplate.handleControllerEvent("lostFocus"); - } - } - } - else - { - // always pass along controller active and touch active - if (this.leftBtn) // left button check to prevent race conditions during language change - { - this.leftBtn.handleControllerEvent(eventId); - } - if (this.statusBar) - { - this.statusBar.handleControllerEvent(eventId); - } - // _cachedTemplate is checked above - this._cachedTemplate.handleControllerEvent(eventId); - - } - - } - else - { - log.warn("Common's cached template is either null or does not have handleControllerEvent."); - } -}; - -/* (internal - Called by framework) - * Handles alert messages from framework, sent by MMUI. - */ -Common.prototype.handleAlert = function(uiaId, alertId, params) -{ - log.debug("handleAlert called."); - - // MMUI should never send two alerts at once. This is a backup check. - if (this._wink) - { - return; - } - - var app = framework.getAppInstance(uiaId); - var properties = null; - - if (app && app.getWinkProperties) // check for App method - { - properties = app.getWinkProperties(alertId, params); - } - - // NOTE: Even though we can't show the Wink, I still call into the GUI App (above) in case they have logic that needs to be done - if (!this._canShowSbns) - { - // We're in a context that can't show Winks. Immediately Ack - framework.websockets.sendAlertCompleteMsg(uiaId, alertId); - return; - } - - if (!properties) // if no properties are set, use the default paragraph style - { - // legacy wink. Use paragraph style. - log.info("No properties returned by app: " + uiaId + ". Using default Wink style."); - properties = { - "style": "style03", - "text1Id": alertId - }; - } - - // no matter what, common should set these properties - properties.winkTimeout = this._winkTimeout; - properties.alertId = alertId; - properties.completeCallback = this._alertComplete.bind(this); - - this._wink = framework.instantiateControl(uiaId, document.body, 'WinkCtrl', properties); - -}; - -/* Called by framework when a data message is sent from Mmui. - * This will pass the message information into any function the app has set in this._messageTable - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype.handleDataMessage = function(msg) -{ - log.debug("GUI COMMON" + " handleDataMessage called for", msg.msgId); - - if (this._messageTable && this._messageTable[msg.msgId]) - { - this._messageTable[msg.msgId](msg); - } - else - { - log.warn("GUI COMMON" + " No message handler for", msg.msgId); - } -}; - - -/* - * Handler for LanguageChangeStatus message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._LanguageChangeStatusMsgHandler = function(msg) -{ - if (msg && msg.params && msg.params.payload && msg.params.payload.languageID) - { - var langCode = framework.localize.getLangInGuiFormat(msg.params.payload.languageID); - } - - if (msg && msg.params && msg.params.payload && msg.params.payload.status) - { - var status = msg.params.payload.status; - } - - var bStatus = false; - - if (status == "Success") - { - bStatus = true; - } - else - { - bStatus = false; - } - - // Call unload dictionaries - framework.localize.unloadDictionaries(langCode,bStatus); -}; - -/* - * Handler for AtSpeed message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._AtSpeedMsgHandler = function(msg) -{ - log.info("Common.prototype._AtSpeedMsgHandler called",msg); - this._atSpeed = true; - framework.sendMsgToFocusedApp(msg); -}; - -/* - * Handler for NoSpeed message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._NoSpeedMsgHandler = function(msg) -{ - log.info("Common.prototype._NoSpeedMsgHandler called",msg); - this._atSpeed = false; - framework.sendMsgToFocusedApp(msg); -}; - -/* - * Handler for PageUp & PageDown messages - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._PageUpDownMsgHandler = function(msg) -{ - log.debug("Common.prototype._PageUpDownMsgHandler called", msg); - - // Assume no list exists - var result = "NoList"; - var eventName = null; - var apiName = null; - - // Determine the result event name, based on the incoming message - // (independent of anything to do with a list) - switch (msg.msgId) - { - case "Global.PageUp": - eventName = "Global.PageUpResult"; - apiName = "pageUp"; - break; - case "Global.PageDown": - eventName = "Global.PageDownResult"; - apiName = "pageDown"; - break; - default: - log.error("_PageUpDownMsgHandler called with non-pagination event!"); - break; - } - - // If we have a list and an API on it to call, ... - if (this._cachedTemplate && this._cachedTemplate.templateName === "List2Tmplt" && this._cachedTemplate.list2Ctrl && apiName) - { - // ... call that API! - response = this._cachedTemplate.list2Ctrl[apiName](); - result = response.charAt(0).toUpperCase() + response.slice(1); // make sure first letter is uppercase - } - - // Compose result & send to MMUI - if (eventName) - { - var params = { - "payload": { - "pageStatus": result - } - }; - - framework.sendEventToMmui("common", eventName, params); - } -}; - -/* - * Handler for VUI Mic messages - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._vuiStateMsgHandler = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - if (msg.msgId == "vuiState") - { - var showLineNumbers = false; - this._cachedVuiState = msg.params.payload.state; - // End the current SBN in case we need to change styles - this.endStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - switch(this._cachedVuiState) - { - case "Not Ready": // intentional fall-through - case "Idle": - case "Playing Out of Session Alert": - // Do nothing. SBN is automatically ended - break; - case "Playing Prompt": - // Show "Wait for Tone" SBN - var properties = { - "sbnStyle": "Style02", - "imagePath1": "IcnSbnMicClosed.png", - "text1Id": "common.SbnWaitForTone" - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - showLineNumbers = true; - break; - case "Listening": - // Show sound meter SBN starting at 0 - var properties = { - "sbnStyle": "Style04", - "imagePath1": "IcnSbnMicOpen.png", - "meter": {"meterType": "audio02", "min": 0, "max": 4000, "currentValue": 0} - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - showLineNumbers = true; - break; - case "Processing": // Intentional fallthrough. Show SBN with icon only - case "Playing Terminating Prompt": - // Show SBN with icon only - var properties = { - "sbnStyle": "Style02", - "imagePath1": "IcnSbnMicClosed.png", - "text1": null - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - break; - default: - log.warn("Unknown VUI State was sent to GUI: " + this._cachedVuiState); - break; - } - - this._showHideLineNumbers(showLineNumbers); - } - else if (msg.msgId == "vuiMicLevel") - { - var micLevel = parseInt(msg.params.payload.micLevel); - // clamp the micLevel value. SBN meter does not support negative numbers - micLevel += 3000; - // Adjust very low mic values to show 1-2 bars - if (micLevel < -2100) - { - micLevel = 50; - } - else if (micLevel < 100) - { - micLevel = 100; - } - - if (this._cachedVuiState == "Listening") - { - // Update state-based SBN with current mic level - var properties = { - "sbnStyle": "Style04", - "imagePath1": "IcnSbnMicOpen.png", - "meter": {"meterType": "audio02", "min": 0, "max": 4000, "currentValue": micLevel} - }; - this.showStateSbn(this.moduleName, "StateSbn_vuiState", "typeB", properties); - } - } - } -}; - -/* - * Handler for SelectLineNumber message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._SelectLineNumMsgHandler = function(msg) -{ - log.debug("Common.prototype._SelectLineNumMsgHandler called", msg); - - if (msg && msg.params && msg.params.payload) - { - var number = msg.params.payload.lineNumber; - } - else - { - return; - } - - var result = "NoList"; // status to send back to MMUI (default to NoList) - - // Is the current template a list? - if (this._cachedTemplate && this._cachedTemplate.templateName == "List2Tmplt") - { - // Does the list have data and support VUI? - if (this._cachedTemplate.list2Ctrl.dataList && this._cachedTemplate.list2Ctrl.dataList.vuiSupport == true) - { - log.info("Sending Line Number to List: " + number); - // List will return a result - var response = this._cachedTemplate.list2Ctrl.selectLine(number); - - if (response == "selected") - { - return; // No event from Common if "selected" is response - } - - result = response.charAt(0).toUpperCase() + response.slice(1); // first letter uppercase - } - } - - log.info("SelectLineResult is ", number, result); - var params = { - "payload" : { - "lineNumber": number, - "lineStatus": result - } - }; - framework.sendEventToMmui("common", "Global.SelectLineResult", params); -}; - -/* - * Handler for Global.StartHelp message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._ShowVuiHelpHandler = function(msg) -{ - log.debug("Common.prototype._ShowVuiHelpHandler called", msg); - // If examples prompt is there when help is called, then removes examples prompt first (functions check for the validity of prompt internally) - this._HideVuiExamplesHandler(null); - - // Hide any currently displayed VUI Help - this._HideVuiHelpHandler(null); - - // Validate that this help overlay request is for the currently displayed context. - if (framework.getCurrentApp() === msg.params.payload.currentUiaId && - framework.getCurrCtxtId() === msg.params.payload.currentContextId) - { - // Try to load a VUI Help configuration and display it if found - var targetUiaId = msg.params.payload.uiaId; - var helpPromptName = msg.params.payload.helpPromptName; - var dialogProperties = this._getVuiHelpDialogConfiguration(targetUiaId, helpPromptName); - if (dialogProperties) - { - this._vuiHelpDialog = framework.instantiateControl(dialogProperties.uiaId, document.body, 'Dialog3Ctrl', dialogProperties.dialogConf); - this._vuiHelpDialog.divElt.classList.add("Dialog3Ctrl_Style19_NoTemplateInstance"); - - // Add properties to the control to record the uiaId and contextId. See also _closeVuiHelpOnTransition(). - this._vuiHelpDialog._uiaId = msg.params.payload.currentUiaId; - this._vuiHelpDialog._contextId = msg.params.payload.currentContextId; - } - } - else - { - log.warn("Ignoring Global.StartHelp message because GUI is in context '" - + framework.getCurrentApp() - + " " - + framework.getCurrCtxtId() - + "' but the message is for a different context: " - + JSON.stringify(msg)); - } -}; - -/* - * Handler for Global.HideHelp message - * @tparam Object msg (optional) The parsed message object sent from Mmui - */ -Common.prototype._HideVuiHelpHandler = function(msg) -{ - log.debug("Common.prototype._HideVuiHelpHandler called"); - - if (this._vuiHelpDialog) - { - framework.destroyControl(this._vuiHelpDialog); - this._vuiHelpDialog = null; - } -}; - -/* - * Close Vui Help at the start of a transition to a new template if that template represents a different context. - */ -Common.prototype._closeVuiHelpOnTransition = function(template) -{ - if (this._vuiHelpDialog - && template - && template.contextInfo.uiaId != this._vuiHelpDialog._uiaId - && template.contextInfo.ctxtId != this._vuiHelpDialog._contextId) - { - this._HideVuiHelpHandler(null); - } -}; - -/* - * Returns a configuration object for a VUI help dialog3 control prompt from an app's dictionary. - * Returns null if no prompt text is found in the dictionary. - * @tparam String uiaId The application requesting the VUI help. - * @tparam String helpPromptName The name of the help prompt to look for in the dictionary. - */ -Common.prototype._getVuiHelpDialogConfiguration = function(uiaId, helpPromptName) -{ - var config = { - dialogConf: { - contentStyle: "style19", - titleStyle : "titleStyle03" - }, - uiaId: uiaId - }; - var found = false; - - // When help prompt name which requires default default help screen is received show system/Home help screen - if (this._defaultHelpPrompt === helpPromptName) - { - helpPromptName = "HomeScreen_Help"; - uiaId = "system"; - config.uiaId = uiaId; - } - // __VrHelpPositionTable__ flag for the current app - var vrHelpPosTable = framework.localize.testVrHelpPosTableExistence(uiaId, helpPromptName); - var leftStringId = null; - var rightStringId = null; - - // Dictionary strings for a VUI help prompt have specific computable stringIds. - for (var i = 1; i <= 5; ++i) - { - if (vrHelpPosTable) - { - // new approach - leftStringId = framework.localize.getVrHelpStringId(uiaId, helpPromptName,"Left", i); - rightStringId = framework.localize.getVrHelpStringId(uiaId, helpPromptName,"Right", i); - } - else - { - // old approach TODO: to be removed when all the VR apps supports the new VrHelpPositionTable. - leftStringId = "VrHelp_" + helpPromptName + "_Left" + i; - rightStringId = "VrHelp_" + helpPromptName + "_Right" + i; - } - - if (leftStringId && framework.localize.testLocStr(uiaId, leftStringId)) - { - config.dialogConf["text" + i.toString() + "Id"] = leftStringId; - found = true; - } - if (rightStringId && framework.localize.testLocStr(uiaId, rightStringId)) - { - config.dialogConf["text" + (i + 5).toString() + "Id"] = rightStringId; - } - } - - if (found) - { - var titleId = "VrHelp_" + helpPromptName + "_Title"; - if (framework.localize.testLocStr(uiaId, titleId)) - { - config.dialogConf.titleId = titleId; - } - else - { - // No title found in dictionary -- use default title - config.dialogConf.titleId = "common.VuiHelpDefaultTitle"; - } - } - - return (found) ? config : null; -}; - -/* - * Handler for Global.StartExamples message - * @tparam Object msg The parsed message object sent from Mmui - */ -Common.prototype._ShowVuiExamplesHandler = function(msg) -{ - log.debug("Common.prototype._ShowVuiExamplesHandler called", msg); - - // TODO: check requirements and confirm. - // If help prompt is there when examples is called, then removes help prompt first (functions check for the validity of prompt internally) - this._HideVuiHelpHandler(null); - - // Hide any currently displayed VUI Examples - this._HideVuiExamplesHandler(null); - - // Validate that this help overlay request is for the currently displayed context. - if (framework.getCurrentApp() === msg.params.payload.currentUiaId && - framework.getCurrCtxtId() === msg.params.payload.currentContextId) - { - // Try to load a VUI examples configuration and display it if found - var targetUiaId = msg.params.payload.currentUiaId; - var examplesId = msg.params.payload.examplesId; - var dialogProperties = this._getVuiExamplesDialogConfiguration(targetUiaId, examplesId); - if (dialogProperties) - { - this._vuiExamplesDialog = framework.instantiateControl(dialogProperties.uiaId, document.body, 'Dialog3Ctrl', dialogProperties.dialogConf); - this._vuiExamplesDialog.divElt.classList.add("Dialog3Ctrl_Style19_NoTemplateInstance"); - - // Add properties to the control to record the uiaId and contextId. See also _closeVuiExamplesOnTransition(). - this._vuiExamplesDialog._uiaId = msg.params.payload.currentUiaId; - this._vuiExamplesDialog._contextId = msg.params.payload.currentContextId; - } - } - else - { - log.warn("Ignoring Global.StartExample message because GUI is in context '" - + framework.getCurrentApp() - + " " - + framework.getCurrCtxtId() - + "' but the message is for a different context: " - + JSON.stringify(msg)); - } -}; - -/* - * Handler for Global.HideExamples message - * @tparam Object msg (optional) The parsed message object sent from Mmui - */ -Common.prototype._HideVuiExamplesHandler = function(msg) -{ - log.debug("Common.prototype._HideVuiExamplesHandler called"); - - if (this._vuiExamplesDialog) - { - framework.destroyControl(this._vuiExamplesDialog); - this._vuiExamplesDialog = null; - } -}; - -/* - * Close Vui example at the start of a transition to a new template if that template represents a different context. - */ -Common.prototype._closeVuiExamplesOnTransition = function(template) -{ - if (this._vuiExamplesDialog - && template - && template.contextInfo.uiaId != this._vuiExamplesDialog._uiaId - && template.contextInfo.ctxtId != this._vuiExamplesDialog._contextId) - { - this._HideVuiExamplesHandler(null); - } -}; - -/* - * Returns a configuration object for a VUI examples dialog3 control prompt from an app's dictionary. - * Returns null if no prompt text is found in the dictionary. - * @tparam String uiaId The application requesting the VUI Examples. - * @tparam Number examplesId Id of the example prompt to look for in the dictionary. - */ -Common.prototype._getVuiExamplesDialogConfiguration = function(uiaId, examplesId) -{ - var config = { - dialogConf: { - contentStyle: "style26", - titleStyle : "titleStyle03" - }, - uiaId: uiaId - }; - // TODO: check if we have any requirement for defualt example screen - // if so add default configuration same as helpPrompt - if(examplesId < 1 || examplesId > 23) - { - log.error("ExamplesId " + examplesId + " is not supported. Support range is 1-23."); - } - else - { - if (guiResources.VR_EXAMPLES["examplesId"+ examplesId]) - { - // get textIds - for (var num = 1; num <= 5; ++num) - { - var StringId = guiResources.VR_EXAMPLES["examplesId"+examplesId]["textId"+num]; - if(StringId) - { - var localizedString = framework.localize.getLocStr("common", StringId, null); - config.dialogConf["text" + num.toString() + "Id"] = localizedString; - } - else - { - config.dialogConf["text" + num.toString() + "Id"] = ""; - } - } - - // get title - var titleId = guiResources.VR_EXAMPLES["examplesId"+ examplesId].titleText; - if (titleId) - { - var localizedTitle = framework.localize.getLocStr("common", titleId, null); - config.dialogConf.titleId = localizedTitle; - } - else - { - config.dialogConf.titleId = ""; - } - - } - else - { - log.error("ExamplesId does not exist in guiResources.VR_EXAMPLES table"); - } - } - return config ; -}; - - -/* - * Function called by apps to determine if vehicle is at speed - * @return Boolean true if vehicle is at speed - */ -Common.prototype.getAtSpeedValue = function() -{ - return this._atSpeed; -}; - -/* - * Tells the status bar to show/hide the Home button - * @param show Boolean true if the home button should be displayed. false if it should be hidden. - */ -Common.prototype.showSbHomeButton = function(show) -{ - this.statusBar.showHomeBtn(show); -}; - -/* - * (internal) Called by framework. Sets the App name text/image in the status bar - * @param label String Literal text name or image path to display in the status bar - */ -Common.prototype.setSbName = function(label) -{ - // setAppName() will differentiate between text & imagery - this.statusBar.setAppName(label); -}; - -/* - * (internal) Called by framework. Sets the translated App name text in the status bar - * @param uiaId String UiaId of the App the string should be translated for - * @param labelId String StringID to be translated - * @param subMap Object Optional subMap to be placed in the text - */ -Common.prototype.setSbNameId = function(uiaId, labelId, subMap) -{ - this.statusBar.setAppNameId(uiaId, labelId, subMap); -}; - -/* - * (internal) Called by framework. Sets the icon between the Home Button and the App Name in the status bar - * @param path String Path from index.html to icon. Pass null to remove current icon - */ -Common.prototype.setSbDomainIcon = function(path) -{ - this.statusBar.setDomainIcon(path); -}; - -/* - * Updates the state of a Status Bar Icon - * @param name String Base Icon name ("Batt", "PhoneSignal", "Roaming", "Traffic", "WifiSignal", "Music", "Bluetooth", "Message") - * @param visible Boolean True if the icon should be shown. False if it should be hidden - * @param state String (Optional) String corrsponding to the state of the icon ("00", "01", "02", "03", "04", "05") - */ -Common.prototype.setSbIcon = function(name, visible, state) -{ - this.statusBar.setIcon(name, visible, state); -}; - -/* - * Utility API for enabling/disabling auto-hide behavior for status bar & UMP - * @param isEnabled Boolean Auto-hides the status bar and UMP by internal inactivity timer (when true) - */ -Common.prototype._setDisplaySbUmpByActivityEnabled = function(isEnabled) -{ - this._displaySbUmpByActivity = isEnabled; - - if (this._displaySbUmpByActivity) { - // remove any existing non-transparent div - if (this._nonTransparentDiv) - { - utility.removeHTMLElement(this._nonTransparentDiv); - this._nonTransparentDiv = null; - } - - // create a non-transparent div so that opera receives touch events - this._nonTransparentDiv = document.createElement('div'); - this._nonTransparentDiv.className = "CommonNonTransparentDiv"; - document.body.insertBefore(this._nonTransparentDiv, document.body.firstChild); - - // Detect activity to kick everything off - this.activityDetected(true, null); - } - else - { - // Remove the non-transparent div - utility.removeHTMLElement(this._nonTransparentDiv); - this._nonTransparentDiv = null; - - // Shut down any timer we may have running - this._cleanUpInactivityTimer(); - - // Set the activity flag to "true" to force status bar & UMP visibility - this._activityDetected = true; - this._updateSbUmpVisibility(); - - // Reset the activity detected flag - this._activityDetected = false; - } - - // Ignore any prior external show/hide requests - this._sbRequestedState = "none"; -}; - -/* - * Public API for external applications (e.g. TV) to request that the status bar be shown - * @param delay_ms Integer The number of milliseconds to wait before starting the status bar animation - * @param duration_ms Integer The number of milliseconds the status bar animation should take to complete - * @param receipt_cb Function The function to call to signal receipt of the request - */ -Common.prototype.requestStatusBarShown = function(delay_ms, duration_ms, receipt_cb) -{ - log.debug("requestStatusBarShown(" + delay_ms + ", " + duration_ms + ")"); - - // Cache requested status bar timings - if ((utility.toType(delay_ms) == "number") && - (delay_ms >= 0)) { - // Store custom delay timing - this._sbDelay_ms = delay_ms; - } - else { - // Store default delay timing - this._sbDelay_ms = this._defaultSbDelay_ms; - } - if ((utility.toType(duration_ms) == "number") && - (duration_ms >= 0)) { - // Store custom duration timing - this._sbDuration_ms = duration_ms; - } - else { - // Store default duration timing - this._sbDuration_ms = this._defaultSbDuration_ms; - } - - // Remember the external request - this._sbRequestedState = "shown"; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - - // If a receipt callback was provided, ... - if (utility.toType(receipt_cb) === "function") { - // Call it to signal receipt of the request - receipt_cb(); - } -}; - -/* - * Public API for external applications (e.g. TV) to request that the status bar be hidden - * @param delay_ms Integer The number of milliseconds to wait before starting the status bar animation - * @param duration_ms Integer The number of milliseconds the status bar animation should take to complete - * @param receipt_cb Function The function to call to signal receipt of the request - */ -Common.prototype.requestStatusBarHidden = function(delay_ms, duration_ms, receipt_cb) -{ - log.debug("requestStatusBarHidden(" + delay_ms + ", " + duration_ms + ")"); - - // Cache requested status bar timings - if ((utility.toType(delay_ms) === "number") && - (delay_ms >= 0)) { - // Store custom delay timing - this._sbDelay_ms = delay_ms; - } - else { - // Store default delay timing - this._sbDelay_ms = this._defaultSbDelay_ms; - } - if ((utility.toType(duration_ms) === "number") && - (duration_ms >= 0)) { - // Store custom duration timing - this._sbDuration_ms = duration_ms; - } - else { - // Store default duration timing - this._sbDuration_ms = this._defaultSbDuration_ms; - } - - // Remember the external request - this._sbRequestedState = "hidden"; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - - // If a receipt callback was provided, ... - if (utility.toType(receipt_cb) == "function") { - // Call it to signal receipt of the request - receipt_cb(); - } -}; - -/* - * Public hook for notification (from Multicontroller.js) about user activity (touch/keyboard/multicontroller input) - * @param isActive (Boolean) Flag indicating if activity is detected (true) or not (false) - * @param evt (Object) The Opera event that generated the activity - * @param tuiEvent (String) If this is a multicontroller action, the corresponding eventId will be passed - */ -Common.prototype.activityDetected = function(isActive, evt, tuiEvent) -{ - // If we're using local timing ... - if (this._displaySbUmpByActivity) - { - // Get the current position & height of the status bar - // (so we can detect if we've selected it or not) - var det = this.statusBar.divElt.offsetTop; - var deh = this.statusBar.divElt.offsetHeight; - - var legalEvent = false; // will be set to true if this event can trigger activity given the configuration - - // If we have no event, or we have a legal event and the status bar itself wasn't selected, ... - if (evt == null) - { - // null event is used for special case private calls within Common.js - legalEvent = true; - } - else if (evt.type == "mouseup" || evt.type == "mousedown") - { - // mouse events can trigger on "touch" or "both", but only if they are not on the Status Bar - if (this._displaySbUmpActivityTypes == "both" || this._displaySbUmpActivityTypes == "touch") - { - if (evt.pageX <= 800) - { - if (evt.pageY >= (det + deh)) - { - legalEvent = true; - } - else if (evt.type == "mouseup") - { - // mouse up occurred in the status bar. Very specific case to account for touch-and-drag - legalEvent = true; - } - } - } - - } - else if (evt.type == "keydown" || evt.type == "keyup" || evt.type == "mousewheel") - { - // Multicontroller event can only trigger if the activity type is "both" - if (this._displaySbUmpActivityTypes == "both") - { - legalEvent = true; - } - } - - if (legalEvent) - { - log.debug("activityDetected()", isActive, evt); - - // Check if the activity state has changed - var stateChanged = (this._activityDetected != isActive); - - // Update the internal activity state - this._activityDetected = isActive; - - // (Re)start the timer to measure inactivity - if (this._activityDetected) { - // a press down via touch or MC should not trigger the Inactivity timeout - var triggerTimer = true; - if (evt != null) - { - if (evt.type == "mousedown") - { - triggerTimer = false; - } - else if (evt.type == "keydown") - { - // Exception: rotations should still trigger the Inactivity timeout - if (tuiEvent != "cw" && tuiEvent != "ccw") - { - triggerTimer = false; - } - } - } - - if (triggerTimer == false) - { - // just clean up the timer - this._cleanUpInactivityTimer(); - } - else - { - this._startInactivityTimer(); - } - } - - // If the activity state changed, ... - if (stateChanged) { - // ... update the controls' visibility - this._updateSbUmpVisibility(); - } - } - } -}; - -Common.prototype._startInactivityTimer = function() -{ - // Clean up any existing inactivity timer - this._cleanUpInactivityTimer(); - - if (this._displaySbUmpByActivity) { - // (Re)start inactivity timer for a 3-second wait - this._inactivityTimer = setTimeout(this._onInactivityBinder, 3000); - } -}; - -Common.prototype._onInactivity = function() -{ - // Clear the timer that got us here - this._cleanUpInactivityTimer(); - - if (this._displaySbUmpByActivity) { - // Local inactivity timer has expired -- lower the flag - this._activityDetected = false; - - // Update the controls' visibility - this._updateSbUmpVisibility(); - } -}; - -Common.prototype._cleanUpInactivityTimer = function() -{ - if (this._inactivityTimer != null) { - // Clean up any existing inactivity timer - clearTimeout(this._inactivityTimer); - this._inactivityTimer = null; - } -}; - -Common.prototype._updateSbUmpVisibility = function() -{ - if (this._displaySbUmpByActivity || this._sbRequestedState != "none") - { - log.debug("_updateSbUmpVisibility()"); - log.debug("this._sbRequestedState = " + this._sbRequestedState); - log.debug("this._activityDetected = " + this._activityDetected); - log.debug("this._sbnIsDisplayed = " + this._sbnIsDisplayed); - - // Default values for status bar animation timing - var delay_ms = this._defaultSbDelay_ms; - var duration_ms = this._defaultSbDuration_ms; - - // Are the conditions right for showing the status bar? - if ((this._cachedTemplate.properties.statusBarVisible) && ((this._sbRequestedState === "shown") || this._activityDetected || this._sbnIsDisplayed)) { - // Yes -- show it - if (this._sbRequestedState === "shown") { - // Use custom timings from external request - delay_ms = this._sbDelay_ms; - duration_ms = this._sbDuration_ms; - } - - // Show the status bar - this.statusBar.transitionVisible(delay_ms, duration_ms, "slide", true); - } - else if ((this._sbRequestedState == "hidden" || !this._activityDetected) && !this._sbnIsDisplayed) { - // No -- hide it - if (this._sbRequestedState == "hidden") { - // Use custom timings from external request - delay_ms = this._sbDelay_ms; - duration_ms = this._sbDuration_ms; - } - - // Hide the status bar - this.statusBar.transitionVisible(delay_ms, duration_ms, "slide", false); - } - - if (this._activityDetected) { - // Call template's "showing started" callback, if available - if (utility.toType(this._cachedTemplate["onActivityShowing"]) == "function") { - this._cachedTemplate.onActivityShowing(delay_ms, duration_ms); - } - } - else { - // Call template's "hiding started" callback, if available - if (utility.toType(this._cachedTemplate["onActivityHiding"]) == "function") { - this._cachedTemplate.onActivityHiding(delay_ms, duration_ms); - } - } - - // Reset the externally-requested timings to default -- if the status bar was actually shown/hidden - // on this call, the timings were already used. Otherwise, the status bar couldn't be changed (e.g. - // an SBN was displayed), so the timings need to be reset for the next pass. - this._sbDelay_ms = this._defaultSbDelay_ms; - this._sbDuration_ms = this._defaultSbDuration_ms; - } -}; - -/* - * Adds a timed Sbn with the given properties to the Status Bar queue - */ -Common.prototype.startTimedSbn = function(uiaId, sbnId, type, properties) -{ - log.debug("Timed SBN requested by " + uiaId + " with id: " + sbnId); - - var uniqueId = uiaId + sbnId; - this._requestNewSbn(uiaId, uniqueId, type, properties, true); -}; - -/* - * Removes a timed Sbn with the given properties to the Status Bar queue - */ -Common.prototype.cancelTimedSbn = function(uiaId, sbnId, type) -{ - var uniqueId = uiaId + sbnId; - - if (utility.toType(sbnId) != 'string' || !this._knownSbns[uniqueId]) - { - log.debug("Cannot cancel unknown sbnId: " + sbnId + " for App: " + uiaId); - return; - } - - // set the expiration to the current time. this will remove the SBN when it comes up in queue, but - // will not remove it if it is already being displayed - this._knownSbns[uniqueId].expiration = new Date().getTime(); -}; - -/* - * Adds a state-based Sbn with the given properties to the Status Bar queue - */ -Common.prototype.showStateSbn = function(uiaId, sbnId, type, properties) -{ - log.debug("State-based SBN requested by " + uiaId + " with id: " + sbnId); - - var uniqueId = uiaId + sbnId; - this._requestNewSbn(uiaId, uniqueId, type, properties, false); -}; - -/* - * Removes a state-based Sbn with the given properties to the Status Bar queue - */ -Common.prototype.endStateSbn = function(uiaId, sbnId, type) -{ - var uniqueId = uiaId + sbnId; - - if (utility.toType(sbnId) != 'string' || !this._knownSbns[uniqueId]) - { - log.debug("Cannot end unknown sbnId: " + sbnId + " for App: " + uiaId); - return; - } - - log.debug("Ending State SBN: " + sbnId + " for App: " + uiaId); - - // If it is currently being displayed, remove it - if (uniqueId == this._displayedSbnId) - { - this._removeDisplayedSbn(); - } - else if (this._sbnQueue.indexOf(uniqueId) != -1) - { - // if in queue, remove from queue - this._sbnQueue.splice(this._sbnQueue.indexOf(uniqueId), 1); - } - - // if none displayed, display first in queue - if (!this._displayedSbnId) - { - this._displaySbnFromQueue(); - } -}; - -/* - * Sets how many numbers are shown in the LeftButton chrome. Called by List any time - * the visible line count changes - * @param count Number Integer indicating how many line numbers should be shown. - * @param style String Left Button VUI Number style (see Left Button SDD for information) - */ -Common.prototype.setLineNumbers = function(count, style) -{ - if (utility.toType(count) != 'number' || utility.toType(style) != 'string') - { - log.warn("Type error: setLineNumbers must be called with count as integer and style as string"); - return; - } - - this._lineNumberData = {"count": count, "style": style}; - - var showLineNumbers = false; - switch(this._cachedVuiState) - { - case "Not Ready": - break; - case "Idle": - break; - case "Playing Out of Session Alert": - break; - case "Playing Prompt": - // Show "Wait for Tone" SBN - showLineNumbers = true; - break; - case "Listening": - // Show sound meter SBN starting at 0 - showLineNumbers = true; - break; - case "Processing": - // Show SBN with no text or meter - break; - case "Playing Terminating Prompt": - // Show SBN with no text or meter - break; - default: - break; - } - - this._showHideLineNumbers(showLineNumbers); -}; - -/* - * Show or hide the line numbers. - * @param showLineNumbers (Boolean) Show line numbers if the current template supports line numbers. - */ -Common.prototype._showHideLineNumbers = function(showLineNumbers) -{ - if (showLineNumbers == true && this._lineNumberData != null) - { - // validate that this is a List and the List is configured to show line numbers - if (this._cachedTemplate && this._cachedTemplate.templateName == "List2Tmplt") - { - if ((this._cachedTemplate.list2Ctrl.dataList) && - (this._cachedTemplate.list2Ctrl.dataList.vuiSupport == true) && - (this._cachedTemplate.list2Ctrl.properties.numberedList == true) && - (this._cachedTemplate.list2Ctrl.dataList.hasOwnProperty('itemCount') && this._cachedTemplate.list2Ctrl.dataList.itemCount > 0)) - { - this.leftBtn.showLineNumbers(this._lineNumberData.count, this._lineNumberData.style); - } - - } - } - else - { - this.leftBtn.hideLineNumbers(); - } -}; - -/* - * Update this._canShowSbns based on a the cached template. - */ -Common.prototype._updateCanShowSbns = function() -{ - if (this._cachedTemplate.contextInfo.uiaId == "system" && this._cachedTemplate.contextInfo.ctxtId == "DisplayOff") - { - // A special case where the context does not have a status bar but we still need to show SBNs. - this._canShowSbns = true; - } - else if (this._cachedTemplate.properties.statusBarVisible == false) - { - // Do not display SBNs if there is no status bar - this._canShowSbns = false; - } - else if (this._cachedTemplate.contextInfo.uiaId == "ecoenergy" && - (this._cachedTemplate.contextInfo.ctxtId == "EndingFuelConsumption" || this._cachedTemplate.contextInfo.ctxtId == "EndingEffectiveness")) - { - this._canShowSbns = false; - } - else - { - this._canShowSbns = true; - } - - log.debug("Can show SBNs?", this._canShowSbns); - - if (this._canShowSbns == false) - { - // Remove and requeue any displayed SBN - if (this._displayedSbnId) - { - var temp = this._removeDisplayedSbn(); - this._addSbnToQueue(temp, "top"); - } - - // Also remove any displayed Wink - this._removeWinkHelper(); - } -}; - -/* - * helper function to check whether given sbn type is valid - * @param type String type of the SBN - */ -Common.prototype._isValidSbnType = function(type) -{ - var isValidSbnType = false; - if (this._SBN_TYPES[type] != null) - { - isValidSbnType = true; - } - return isValidSbnType; -}; - -/* - * helper function to check whether given sbn type is old one - * @param type String old type of the SBN - */ -Common.prototype._isValidConversionType = function(type) -{ - var isValidConversionType = false; - if (this._SBN_MAPPING_TABLE[type] != null) - { - isValidConversionType = true; - } - return isValidConversionType; -}; - -/* - * helper function to convert old sbn type into valid type - * @param type String old type of the SBN - */ -Common.prototype._convertToValidSbnType = function(type) -{ - var validType; - if (this._isValidConversionType(type)) - { - validType = this._SBN_MAPPING_TABLE[type]; - } - else - { - validType = "unknown"; - log.error("SBN type " + type + " is not valid. Using " + validType + " as a default. See System Specs for possible sbn types"); - } - return validType; -}; - -/* - * Helper function to reduce duplicate logic - */ -Common.prototype._requestNewSbn = function(uiaId, sbnId, type, properties, isTimed) -{ - if (utility.toType(sbnId) != 'string') - { - log.error("Given sbnId was not of valid type 'string'. Please give valid sbnId."); - return; - } - - if (utility.toType(type) != 'string') - { - log.error("Given SBN type must be a string from the table in GUI Common. See Common SDD for possible types."); - } - - if (false == this._isValidSbnType(type)) - { - type = this._convertToValidSbnType(type); - } - - //blacklist will now contain new letter based sbn type, so this check is moved after the type conversion - if (this._SBN_TYPE_BLACKLIST.indexOf(type) != -1) - { - log.debug("Request for blacklisted SBN type:", type, "has been blocked"); - return; - } - - // if already in queue or displayed, update sbn - if (sbnId == this._displayedSbnId) - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - this._displayedSbn.setSbnConfig(properties); // Call API to do live update on Control - - if (isTimed) - { - // extend the timer - clearTimeout(this._displayedSbnTimerId); - this._displayedSbnTimerId = setTimeout(this._sbnFinished.bind(this), this._knownSbns[sbnId].duration); - } - } - else if (this._sbnQueue.indexOf(sbnId) != -1) - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - } - else // if !in queue and !displayed, it's new and we need to check it for priority - { - this._setKnownSbn(uiaId, sbnId, type, properties, isTimed); - - // If there's an SBN currently displayed... - if (this._displayedSbnId) - { - // Get priority level of this sbnId - var priority = this._knownSbns[sbnId].priority; - var queueTime = this._SBN_TYPES[type] != null ? this._SBN_TYPES[type].queueTime : this._SBN_TYPES.unknown.queueTime; - var replaceDisplayed = false; - - if (queueTime > 0) - { - // these SBNs DO queue and therefore SBNs of the same priority level should NOT clobber each other - if (priority < this._knownSbns[this._displayedSbnId].priority) // lower # is higher priority - { - replaceDisplayed = true; - } - } - else - { - // these SBNs do NOT queue and therefore SBNs of the same priority level should clobber each other - if (priority <= this._knownSbns[this._displayedSbnId].priority) // lower # is higher priority - { - replaceDisplayed = true; - } - } - - if (replaceDisplayed == true) - { - // call to this._removeDisplayedSbn() will set this._displayedSbnId to null and return displayed Id - var temp = this._removeDisplayedSbn(); - - this._displaySbn(sbnId); // the new one has higher priority and should be displayed - - this._addSbnToQueue(temp, "top"); // old SBN has been replaced and should be added to the queue (top if same priority level) - } - else - { - // new sbnId has lower priority and gets queued - this._addSbnToQueue(sbnId, "bottom"); - } - - } - else // display the new SBN. Some SBNs never go in the queue - { - if (!this._canShowSbns) - { - this._addSbnToQueue(sbnId, "bottom"); - } - else - { - // Tell Status Bar about the SBN - this._sbnIsDisplayed = true; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - - if (this._cachedTemplate.properties.statusBarVisible) - { - // Snap the status bar visible (only if this template is set to display a status bar) - this.statusBar.transitionVisible(0, 0, "slide", true); - } - - // ENTRY POINT #1 - // immediately display this SBN without adding it to the queue - this._displaySbn(sbnId); - - // Notify MMUI to turn on display if needed. - this._sendDisplayOffNotification(1); - } - } - } - - if (this._canShowSbns && !this._displayedSbnId) - { - this._displaySbnFromQueue(); // The new SBN should be the first in queue (if something was displayed) - } -}; - -/* - * Helper function to add Sbns to the queue - * @param sbnId String Unique ID of the SBN to add to the queue - * @param queueOrder String Identifies where to place an SBN in case they are the same priority level ("top" or "bottom") - */ -Common.prototype._addSbnToQueue = function(sbnId, queueOrder) -{ - if (sbnId == null) - { - log.error("_addSbnToQueue: Cannot add null sbnId to queue."); - return; - } - if (!this._knownSbns[sbnId]) - { - log.error("Attempt to add Sbn to queue failed: Could not identify Sbn", sbnId, "in knownSbns variable."); - return; - } - - var currTime = new Date().getTime(); - // state-based SBNs do not expire. An SBN that is Timed and expired does not need to be added to the queue. It would just be removed later anyway. - if (this._knownSbns[sbnId].isTimed && currTime >= this._knownSbns[sbnId].expiration) - { - log.debug("SBN", sbnId, "has expired. No reason to add it to queue"); - return; - } - - // Get priority level of this sbnId - var priority = this._knownSbns[sbnId].priority; - - // Use queuePos so we don't modify the array while looping through it. - var queuePos = this._sbnQueue.length; // default to Array.length so that splice will add it to the end of the Array. - - // Add to queue in appropriate spot - for (var i = 0; i < this._sbnQueue.length; i++) - { - if (queueOrder == "top") - { - if (priority <= this._knownSbns[this._sbnQueue[i]].priority) // lower # is higher priority - { - // insert into queue - queuePos = i; - break; // cut in line and we're done - } - } - else - { - if (priority < this._knownSbns[this._sbnQueue[i]].priority) // lower # is higher priority - { - // insert into queue - queuePos = i; - break; // cut in line and we're done - } - } - - } - - this._sbnQueue.splice(queuePos, 0, sbnId); // at queuePos, remove 0, add sbnId - -}; - -/* - * Helper function that creates or updates an Sbn Object to add to/update the knownSbns variable. - */ -Common.prototype._setKnownSbn = function(uiaId, sbnId, type, properties, isTimed) -{ - var expiration = new Date(); - var priority = 0; - var duration = 0; - - // if type is known, use its properties - if (!this._SBN_TYPES[type]) - { - log.warn("Priority level of Sbn type: " + type + " is unknown. Setting priority to lowest level."); - type = "unknown"; - } - - expiration.setTime(expiration.getTime() + this._SBN_TYPES[type].queueTime); - priority = this._SBN_TYPES[type].priority; - duration = this._SBN_TYPES[type].timedDuration; - - this._knownSbns[sbnId] = { - "uiaId" : uiaId, - "type": type, - "priority": priority, - "isTimed": isTimed, - "duration": duration, // duration is only used for timed Sbns - "expiration": expiration.getTime(), // Set an expiration time stamp for each Sbn - "properties": properties - }; -}; - -/* - * Immediately displays the SBN with the given sbnId - */ -Common.prototype._displaySbn = function(sbnId) -{ - if (!this._knownSbns[sbnId]) - { - log.error("Cannot display requested SBN: " + sbnId + ". SBN cannot be found in knownSbns variable."); - return; - } - - if (!this._canShowSbns) - { - // safety check. We should never get here. - log.debug("Cannot show new SBNs in this context."); - return; - } - - log.info("Displaying new sbn: " + sbnId); - this._displayedSbnId = sbnId; - this._displayedSbn = framework.instantiateControl(this._knownSbns[sbnId].uiaId, document.body, "SbnCtrl", this._knownSbns[sbnId].properties); - if (this._knownSbns[sbnId].isTimed) - { - this._displayedSbnTimerId = setTimeout(this._sbnFinished.bind(this), this._knownSbns[sbnId].duration); - } -}; - -/* - * Immediately destroys and removes the currently displayed SBN - * @return String Returns the sbnId of the SBN that was removed - */ -Common.prototype._removeDisplayedSbn = function() -{ - log.info("Removing currently displayed SBN: " + this._displayedSbnId); - clearTimeout(this._displayedSbnTimerId); - framework.destroyControl(this._displayedSbn); - - var removedId = this._displayedSbnId; - this._displayedSbn = null; - this._displayedSbnId = null; - - return removedId; -}; - -/* - * Chooses the first active SBN off the queue and displays it. - * @return String The ID of the new SBN that gets displayed. null of no SBN is displayed. - */ -Common.prototype._displaySbnFromQueue = function() -{ - var newSbnToDisplay = null; - if (!this._canShowSbns) - { - // safety check. We should never get here. - log.debug("Cannot show queued SBNs in this context."); - return newSbnToDisplay; - } - - if (this._sbnQueue.length == 0) - { - // nothing to display: EXIT POINT #1 - this._sbnIsDisplayed = false; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - this._updateSbUmpVisibility(); - // Notify MMUI to turn off display if needed. - this._sendDisplayOffNotification(0); - return newSbnToDisplay; - } - - var sbnId = null; - var flaggedForRemoval = new Array(); - - // check expiration - var currTime = new Date().getTime(); - - for (var i = 0; i < this._sbnQueue.length; i++) - { - sbnId = this._sbnQueue[i]; - - // state-based SBNs do not expire. An SBN in the queue that is state-based or -not- expired should be displayed immediately - if (this._knownSbns[sbnId].isTimed && currTime >= this._knownSbns[sbnId].expiration) - { - flaggedForRemoval.push(sbnId); - } - else - { - this._displaySbn(sbnId); - newSbnToDisplay = sbnId; - flaggedForRemoval.push(sbnId); - break; - } - } - - // splice any expired SBNs from the queue - for (var j = 0; j < flaggedForRemoval.length; j++) - { - this._sbnQueue.splice(this._sbnQueue.indexOf(flaggedForRemoval[j]), 1); // remove from queue - - if (flaggedForRemoval[j] != this._displayedSbnId) - { - delete this._knownSbns[flaggedForRemoval[j]]; // delete from known Sbns - } - } - - flaggedForRemoval = null; - - if (this._sbnQueue.length == 0 && !this._displayedSbnId) - { - // no more SBNs to display: EXIT POINT #2 - this._sbnIsDisplayed = false; - this.statusBar.setSbnDisplayed(this._sbnIsDisplayed); - this._updateSbUmpVisibility(); - - // Notify MMUI to turn off display if needed. - this._sendDisplayOffNotification(0); - } - - return newSbnToDisplay; -}; - -/* - * Callback for when a timed SBN completes - */ -Common.prototype._sbnFinished = function() -{ - this._removeDisplayedSbn(); - this._displaySbnFromQueue(); -}; - -/* - * (internal) Called by framework. Sets the style of the left button to - * either "goBack" or "menuUp" - */ -Common.prototype.setLeftBtnStyle = function(style) -{ - this.leftBtn.setStyle(style); -}; - -/* - * Updates the clock to display the value given. Value should be given in Unix format - * @param milliseconds Number the current time in number of milliseconds in a date string since midnight of January 1, 1970 - */ -Common.prototype.updateSbClock = function(milliseconds) -{ - var type = utility.toType(milliseconds); - if (type != 'number' && type != 'date') - { - log.warn("Common.updateSbClock can only accept an argument of type Number or Date"); - return; - } - - this._cachedTime = milliseconds; - this.statusBar.updateClock(milliseconds); - - // Update the clock in the OffScreen control if it that is the current template - if (this._cachedTemplate && this._cachedTemplate.templateName == "OffScreenTmplt" && this._cachedTemplate.updateClock) - { - this._cachedTemplate.updateClock(); - } -}; - -Common.prototype.getCurrentTime = function() -{ - var type = utility.toType(this._cachedTime); - var time = 0; - - if (type == 'number') - { - time = this._cachedTime; - } - else if (type == 'date') - { - time = this._cachedTime.getTime(); - } - - return time; -}; - -/* - * Removes the wink from the screen. This is called after the wink times out - * @param ctrlObj Object Reference to the Wink Control Object. - * @param appData Object App data stored by Common - * @param params Object Additional params passed by WinkCtrl - */ -Common.prototype._alertComplete = function(ctrlObj, appData, params) -{ - log.debug("Wink complete: " + ctrlObj.properties.alertId); - - this._removeWinkHelper(); -}; - -Common.prototype._removeWinkHelper = function() -{ - if (this._wink) - { - log.info("wink is", this._wink); - framework.websockets.sendAlertCompleteMsg(this._wink.uiaId, this._wink.properties.alertId); - - framework.destroyControl(this._wink); - this._wink = null; - } -}; - -/* - * Callback for when the Status Bar is clicked - * @param ctrlObj (Object) Reference to the button control object in status bar that was clicked - * @param appData (Object) Data passed in by the app when the control was instantiated - * @param params (Object) Optional params passed by the control object - */ -Common.prototype._statusBarClicked = function(ctrlObj, appData, params) -{ - log.debug("status bar clicked", ctrlObj, appData, params); - if (params && params.statusBtn == "home") - { - if (this._diagEntrySequence != 2 ) // 2 here indicates the sequence was completed - { - framework.sendEventToMmui("common", "Global.IntentHome"); - } - } - else if (params && params.statusBtn == "carPlay") - { - if (typeof this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId].selectCallback == 'function') - { - this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId].selectCallback(ctrlObj, appData, params); - } - } - -}; - -/* - * Callback for when the Status Bar is focused - * @param ctrlObj (Object) Reference to the button control object in status bar that was clicked - * @param appData (Object) Data passed in by the app when the control was instantiated - * @param params (Object) Optional params passed by the control object - */ -Common.prototype._statusBarFocused = function(ctrlObj, appData, params) -{ - log.debug("status bar focused", ctrlObj, appData, params); - // being used and called only for carplay for now - if (params && params.statusBtn == "carPlay") - { - if (typeof this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId].onFocusCallback == 'function') - { - this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId].onFocusCallback(ctrlObj, appData, params); - } - } - -}; - -/* - * Callback for when the Status Bar is long pressed - * @param ctrlObj (Object) Reference to the button control object in status bar that was clicked - * @param appData (Object) Data passed in by the app when the control was instantiated - * @param params (Object) Optional params passed by the control object - */ -Common.prototype._statusBarLongPress = function(ctrlObj, appData, params) -{ - if (params.statusBtn == "clock") - { - log.info("Clock Long Press Detected."); - this._diagEntrySequence = 1; - // clear exisiting timeout if any - clearTimeout(this._clockHomeButtonLongPressIntervalId); - //time interval between clock button long press and home button long press should be less than 9 secs - this._clockHomeButtonLongPressIntervalId = setTimeout(this._statusBarLongPressTimerHandler.bind(this),9000); - } - else if (params.statusBtn == "home" && this._diagEntrySequence == 1 && this._clockHomeButtonLongPressIntervalId) - { - log.info("Entering Diagnostics App"); - this._diagEntrySequence = 2; - framework.sendEventToMmui("syssettings", "SelectDiagnostics"); - } - -}; - -Common.prototype._statusBarLongPressTimerHandler = function() -{ - this._clockHomeButtonLongPressIntervalId = null; - this._diagEntrySequence = 0; -}; - -/* - * Callback for when the left button is pressed. - * @param controlObj (object) Reference to the LeftBtn that was pressed - */ -Common.prototype._leftBtnSelected = function(controlObj, appData, params) -{ - this._leftBtnSelectEvent(params.style); -}; - -/* - * Helper function to reduce duplicate logic. Called when the left button is selected either - * via touch or multicontroller -OR- when the TUI Left Hard Key is pressed. - * @param style String Style of the left button (determines which event to send to MMUI) - */ -Common.prototype._leftBtnSelectEvent = function(style) -{ - if (this.cmnCtrlsDisabled) - { - return; - } - - // Send an appropriate event based on the current style of the left button - switch (style) - { - case "goLeft": // legacy behavior TODO: remove when all Apps have updated - framework.sendEventToMmui("common", "Global.GoLeft"); - break; - case "goBack": // go back to the previous screen - framework.sendEventToMmui("common", "Global.GoBack"); - break; - case "menuUp": // go up one menu level - framework.sendEventToMmui("common", "Global.MenuUp"); - break; - default: - log.warn("There is no defined event for left button style: " + style); - break; - } -}; - -Common.prototype.getContextCapture = function() -{ - return { - leftBtnHasFocus : this.leftBtn.divElt.style.visibility === 'visible' && this.leftBtn.btnInstance.hasFocus, - statusBarHasFocus: this.statusBar.remoteUiBtn && this.statusBar.remoteUiBtn.hasFocus - }; -}; - -Common.prototype.restoreContext = function(restoreData) -{ - if (restoreData.commonContextCapture && restoreData.commonContextCapture.leftBtnHasFocus) - { - restoreData.skipRestore = true; - } - else if (restoreData.commonContextCapture && restoreData.commonContextCapture.statusBarHasFocus) - { - if (this.statusBar.remoteUiBtn) - { - this.statusBar.remoteUiBtn.handleControllerEvent('acceptFocusInit'); - } - } -}; - -/* - * Cause an audible beep to be played. - * @param pressType (String) Indicates a short press or a long press. Valid values are “Short” and “Long”. - * @param eventCause (String) Indicates the user interaction that caused the beep. Valid values are “Touch”, “Multicontroller”, and “Hardkey”. - */ -Common.prototype.beep = function(pressType, eventCause) -{ - var validPressTypes = [ "Short", "Long" ]; - if (utility.toType(pressType) !== "string" || validPressTypes.indexOf(pressType) === -1) - { - log.warn("Invalid pressType parameter passed to common.beep(). Valid values are 'Short' or 'Long'."); - return; - } - - var validEventCauses = [ "Touch", "Multicontroller", "Hardkey" ]; - if (utility.toType(eventCause) !== "string" || validEventCauses.indexOf(eventCause) === -1) - { - log.warn("Invalid eventCause parameter passed to common.beep(). Valid values are 'Touch' or 'Multicontroller' or 'Hardkey'"); - return; - } - - if (pressType == "Short" && eventCause == "Multicontroller") - { - // do not send this - return; - } - - var args = { - "payload" : { - "pressType" : pressType, - "eventCause" : eventCause - } - }; - - log.info("Sending PlayAudioBeep", pressType, eventCause); - framework.sendEventToMmui("audiosettings", "PlayAudioBeep", args); -}; - -/* - * Mute message handler - */ -Common.prototype._HandleStatusUpdateVolume = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - var isMuted = msg.params.payload.volumeOnOffStatus === "VolumeOff"; - if (isMuted !== this._isMuted) - { - this._isMuted = isMuted; - this._isMutedChanged(); - } - } -}; - -/* - * Called when the value of _isMuted changes - */ -Common.prototype._isMutedChanged = function() -{ - var action = this._getMuteOverlayAction(); - switch (action) - { - case "wink": - this._showMuteWink(3000); - break; - - case "persistentWink": - this._showMuteWink(null); - break; - - case "sbn": - this._showMuteSbn(); - break; - - default: - this._hideMuteWink(); - this._hideMuteSbn(); - break; - - } -}; - -Common.prototype._showMuteSbn = function() -{ - var properties = { - sbnStyle: "Style02", - }; - - if (this._isMuted) - { - properties.imagePath1 = "IcnSbnMuteOn.png"; - properties.text1Id = "common.muteOn"; - } - else - { - properties.imagePath1 = "IcnSbnMuteOff.png"; - properties.text1Id = "common.muteOff"; - } - - this.startTimedSbn("common", "TimedSbn_StatusUpdateVolumeOnOff", "typeA", properties); -}; - -Common.prototype._hideMuteSbn = function() -{ - this.cancelTimedSbn("common", "TimedSbn_StatusUpdateVolumeOnOff", "typeA"); -}; - -Common.prototype._showMuteWink = function(winkTimeout) -{ - var properties = { - "style": "style05", - "image1": "common/images/icons/IcnWinkUnMute.png", - "winkTimeout": winkTimeout, - "alertId": "", - "completeCallback": this._muteWinkComplete.bind(this) - }; - - if (this._isMuted) - { - properties.image1 = "common/images/icons/IcnWinkMute.png"; - } - - var newWink = framework.instantiateControl("common", document.body, "WinkCtrl", properties); - - // If there's a Wink currently displayed (e.g. persistentWink), get rid of it - this._hideMuteWink(); - this._muteWink = newWink; -}; - -Common.prototype._hideMuteWink = function() -{ - if (this._muteWink) - { - framework.destroyControl(this._muteWink); - this._muteWink = null; - } -}; - -Common.prototype._muteWinkComplete = function() -{ - this._hideMuteWink(); -}; - -/* - * Returns one of: "persistentWink", "wink", "sbn" - */ -Common.prototype._getMuteOverlayAction = function() -{ - if (this._cachedTemplate && this._cachedTemplate.templateName === "NowPlaying4Tmplt") - { - if (this._isMuted) - { - return "persistentWink"; - } - else - { - return "wink"; - } - } - else - { - var uiaId = framework.getCurrentApp(); - var ctxtId = framework.getCurrCtxtId(); - if (this.getContextCategory(uiaId, ctxtId) === "Entertainment") - { - return "wink"; - } - } - return "sbn"; -}; -/*Called when carPlay is enabled */ -Common.prototype.setRemoteUiButton = function(uiaId,enabled,config) -{ - if(enabled) - { - if (this._cachedTemplate) - { - this._remoteUiBtns[uiaId] = config ; - if ((this._remoteUiBtns[this._cachedTemplate.contextInfo.uiaId])&& (this._remoteUiBtns[uiaId].ctxtList.indexOf(this._cachedTemplate.contextInfo.ctxtId) != -1)) - { - this.statusBar.showRemoteUiButton(this._remoteUiBtns[uiaId]); - } - else - { - log.info("not on home screen so not showing the carPlay icon"); - } - } - } - else - { - this._remoteUiBtns[uiaId] = null ; - this.statusBar.hideRemoteUiButton(); - } -}; - -Common.prototype._updateMuteWinkOnTransition = function(prevTepmlate, currTemplate) -{ - if (this._isMuted && currTemplate && currTemplate.templateName === "NowPlaying4Tmplt") - { - this._showMuteWink(null); - } - else - { - this._hideMuteWink(); - } -}; - -/* - * Sends display off notification event to MMUI - * @param sendDisplayOn (Number) 1 or 0 indicating if display should be on or off respectively. - */ -Common.prototype._sendDisplayOffNotification = function(sendDisplayOn) -{ - if (sendDisplayOn != this._lastDisplayStateSent) - { - framework.sendEventToMmui("system", "DisplayOffNotificationEvent", {"payload": {"notificationActive": sendDisplayOn}}); - this._lastDisplayStateSent = sendDisplayOn; - } -}; - -/* - * Process Global.MenuUpReceived messages. - */ -Common.prototype._MenuUpReceived = function(msg) -{ - if (msg && msg.params && msg.params.payload) - { - this._menuUpReceiverApp = msg.params.payload.receiverApp; - } -}; - -/* - * Utility function to get the context category (domain) for a given application/context - * @param uiaId Application ID - * @param ctxtId Context ID - * @returns Domain string value (e.g. "Applications", "Communication", "Entertainment") - */ -Common.prototype.getContextCategory = function(uiaId, ctxtId) -{ - return this._contextCategory.getContextCategory(uiaId, ctxtId); -}; - -/* - * Utility function to get the status bar icon for a given context category (domain) - * @param domain Domain string value (e.g. "Applications", "Communication", "Entertainment") - * @returns Icon image file name - */ -Common.prototype.getContextCategorySbIcon = function(domain) -{ - return this._contextCategory.getContextCategorySbIcon(domain); -}; - -framework.registerCommonLoaded(["common/controls/StatusBar", - "common/controls/LeftBtn", - "common/controls/Wink", - "common/controls/Button", - "common/controls/Dialog3", - "common/controls/Sbn"], true); diff --git a/app/files/tweaks/config_org/safety-warning-reverse-camera/jci/nativegui/images/desktop.ini b/app/files/tweaks/config_org/safety-warning-reverse-camera/jci/nativegui/images/desktop.ini deleted file mode 100644 index f33e592..0000000 --- a/app/files/tweaks/config_org/safety-warning-reverse-camera/jci/nativegui/images/desktop.ini +++ /dev/null @@ -1,2 +0,0 @@ -[LocalizedFileNames] -SafetyText_UK_Ukrainian.png=@SafetyText_UK_Ukrainian.png,0 diff --git a/app/files/tweaks/config_org/speedometer/stage_wifi.sh b/app/files/tweaks/config_org/speedometer/stage_wifi.sh deleted file mode 100644 index 13f4793..0000000 --- a/app/files/tweaks/config_org/speedometer/stage_wifi.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh - diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_1_sm.png deleted file mode 100644 index 23e168c..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_2_sm.png deleted file mode 100644 index fe22290..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_3_sm.png deleted file mode 100644 index 6128fee..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_4_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_4_sm.png deleted file mode 100644 index a5aaf5a..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackCtr_4_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_1_sm.png deleted file mode 100644 index eb9d074..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_2_sm.png deleted file mode 100644 index e576b5e..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_3_sm.png deleted file mode 100644 index 35e0961..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackLt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_1_sm.png deleted file mode 100644 index 8e62511..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_2_sm.png deleted file mode 100644 index 9b04eb0..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_3_sm.png deleted file mode 100644 index 3d274e1..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/BackRt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Background_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Background_sm.png deleted file mode 100644 index 35b970d..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Background_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Car_Ds_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Car_Ds_sm.png deleted file mode 100644 index 701abf1..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Car_Ds_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Car_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Car_sm.png deleted file mode 100644 index 45321f8..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/Car_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_1_sm.png deleted file mode 100644 index f8953a6..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_2_sm.png deleted file mode 100644 index 41b4ed9..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_3_sm.png deleted file mode 100644 index 626152c..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_4_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_4_sm.png deleted file mode 100644 index aa3c2ae..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontCtr_4_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_1_sm.png deleted file mode 100644 index bdfe905..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_2_sm.png deleted file mode 100644 index c6daaa0..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_3_sm.png deleted file mode 100644 index b47f532..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontLt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_1_sm.png deleted file mode 100644 index f287e78..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_2_sm.png deleted file mode 100644 index 5938e8b..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_3_sm.png deleted file mode 100644 index aa9a91c..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/HorizontalSensors/FrontRt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_1_sm.png deleted file mode 100644 index 4658a4a..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_2_sm.png deleted file mode 100644 index 43607ea..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_3_sm.png deleted file mode 100644 index 8d1c63f..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_4_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_4_sm.png deleted file mode 100644 index bf6e53c..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackCtr_4_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_1_sm.png deleted file mode 100644 index 73a85bb..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_2_sm.png deleted file mode 100644 index 160435a..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_3_sm.png deleted file mode 100644 index ae79630..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackLt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_1_sm.png deleted file mode 100644 index 573773b..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_2_sm.png deleted file mode 100644 index 6bc4d22..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_3_sm.png deleted file mode 100644 index 86754b8..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/BackRt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Background_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Background_sm.png deleted file mode 100644 index 6cdd71f..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Background_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Car_Ds_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Car_Ds_sm.png deleted file mode 100644 index bd13acc..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Car_Ds_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Car_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Car_sm.png deleted file mode 100644 index 4398ed7..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/Car_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_1_sm.png deleted file mode 100644 index 44ba2a5..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_2_sm.png deleted file mode 100644 index 134e1e4..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_3_sm.png deleted file mode 100644 index 5dec172..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_4_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_4_sm.png deleted file mode 100644 index 5c542eb..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontCtr_4_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_1_sm.png deleted file mode 100644 index 8d3aaf7..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_2_sm.png deleted file mode 100644 index 2b69054..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_3_sm.png deleted file mode 100644 index 3625a4f..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontLt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_1_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_1_sm.png deleted file mode 100644 index 95e8f28..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_1_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_2_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_2_sm.png deleted file mode 100644 index 6ee2280..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_2_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_3_sm.png b/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_3_sm.png deleted file mode 100644 index 85ea1ff..0000000 Binary files a/app/files/tweaks/config_org/transparent-parking-sensor/jci/nativegui/images/VerticalSensors/FrontRt_3_sm.png and /dev/null differ diff --git a/app/files/tweaks/config_org/v70/profile.org b/app/files/tweaks/config_org/v70/profile.org new file mode 100644 index 0000000..6533560 --- /dev/null +++ b/app/files/tweaks/config_org/v70/profile.org @@ -0,0 +1,24 @@ +alias ll='ls -l' +alias la='ll -a' + +export PATH='/sbin:/usr/sbin:/bin:/usr/bin:/jci/bin/:/resources/dev/bin:/resources/dev/sbin:/data_persist/dev/bin:/data_persist/dev/sbin:/resources/dev/usr/bin' + +#export DBus environment variables for the session +. dbus envset jci + +export V4LCAPTURE_DBUS_ADDRESS=$JCI_HMI_BUS + +# required for Wayland +export XDG_RUNTIME_DIR=/tmp +export WAYLAND_IVI_SURFACE_ID=2 #to set Browser's ID equal to UIA_System_ID (this has to be done before starting SM) + +# required for Wayland +OPERA_ROOT="/jci/opera" +export FREETYPE_FONT_SET=YES +export OPERA_DIR="${OPERA_ROOT}/opera_dir" +export OPERA_HOME="${OPERA_ROOT}/opera_home/" +export OPERA_FONTS="/jci/fonts/CHN" +export LD_LIBRARY_PATH="/jci/lib:${OPERA_ROOT}/3rdpartylibs/freetype:/usr/lib/imx-mm/audio-codec:/usr/lib/imx-mm/parser:/data_persist/dev/lib:${LD_LIBRARY_PATH}" + +# required for valgrind +export VALGRIND_LIB=/tmp/mnt/resources/dev/usr/lib/valgrind diff --git a/app/index.html b/app/index.html index 0c66ad9..2b61664 100644 --- a/app/index.html +++ b/app/index.html @@ -60,7 +60,7 @@
  • -
  • +
  • Update Available... Downloading Please Wait
  • + @@ -134,6 +136,7 @@ +
    +
    For instructions on how to generate tweak files:

    If you you hit an error
    or a hang up you can:

    Or you can:

    Love this app? Donating is a great way to show some love!:


    ", + "msg": "

    Help:

    \n
    For instructions on how to generate tweak files:

    If you encounter an error
    or a hang up you can:

    Or you can:

    Love this app? Donating is a great way to show some love!:


    ", "t2": "", "msg2": "" }], @@ -111,7 +111,7 @@ "msg": "This sidebar will list all the tweaks currently selected. Here will appear extra options and you can also click any item in this list for help information." }, { "id": 3, - "msg": "Additional actions such as backup jci folder & enable wifi for North American versions." + "msg": "Additional actions such as backup jci folder & enable WiFi for North American versions." }, { "id": 4, "msg": "These options can be restored to original state by selecting their default options." @@ -123,7 +123,7 @@ "msg": "When all your tweaks have been selected, click this button to compile and go!" }, { "id": 7, - "msg": "Copy the entire contents of the \"_copy_to_usb\" folder onto a blank, FAT32 format USB Flash Drive. Plug the drive into the car's usb port, the installer will start automatically after a few minutes. Remove any other USB devices but The NAV SD card should remain plugged into the car. Turning off bluetooth and wifi help as well. After the installation is complete the system will reboot, then you can remove the USB drive and your changes will be applied." + "msg": "Copy the entire contents of the \"_copy_to_usb\" folder onto a blank, FAT32 format USB Flash Drive. Plug the drive into the car's USB port, the installer will start automatically after a few minutes. Remove any other USB devices but The NAV SD card should remain plugged into the car. Turning off bluetooth and WiFi help as well. After the installation is complete the system will reboot, then you can remove the USB drive and your changes will be applied." }, { "id": 8, "msg": "For more information visit MazdaTweaks.com!" @@ -198,9 +198,9 @@ "mainOps": { "wifi": { "id": 0, - "label": "Enable WIFI", + "label": "Enable WiFi", "safetylvl": "safe", - "toolTip": "
    WIFI
    Enables WIFI for North America and Japan Regions" + "toolTip": "
    WiFi
    Enables WiFi for North America and Japan Regions" }, "backup": { "id": 1, @@ -249,7 +249,7 @@ "testlabel": "Test Backups", "skipconfirm": "Skip Confirmation", "safetylvl": "safe", - "toolTip": "
    Build \"run.sh\"

    Install tweaks using autorun. Changes the filename of \"tweaks.sh\" to \"run.sh\"
    NOTE: To use this you must have autorun script installed for this to work.

    Retrieve CMU Data

    Dump diagnostic files from the CMU to the USB Drive. Cleans out error files and core dumps from the system.

    Skip Confirmation

    Allows for the installation to run without prompting for confirmation to begin the install. Mainly this is used for recovering when the touchscreen is not responding.

    Copy Backups:

    Copy original backups of modified system files, for safe keeping.

    Test Backups:

    Some tweaks have before and after copies of the files modified during the installation. If you like that kind of thing they will be copied to your-usb/bakups/test/.

    Copy Backups:

    Copy original backups of modified system files, for safe keeping.

    Apps to Resources:

    Install app files to the \"resources\" partition instead of the Root Filesystem.

    " + "toolTip": "
    Build \"run.sh\"

    Install tweaks using autorun. Changes the filename of \"tweaks.sh\" to \"run.sh\"
    NOTE: To use this you must have autorun script installed for this to work.

    Retrieve CMU Data

    Dump diagnostic files from the CMU to the USB Drive. Cleans out error files and core dumps from the system.

    Skip Confirmation

    Allows for the installation to run without prompting for confirmation to begin the install. Mainly this is used for recovering when the touchscreen is not responding.

    Copy Backups:

    Copy original backups of modified system files, for safe keeping.

    Test Backups:

    Some tweaks have before and after copies of the files modified during the installation. If you like that kind of thing they will be copied to your-USB/bakups/test/.

    Apps to Resources:

    Install app files to the \"resources\" partition instead of the Root Filesystem.

    " }, "mainmenu": { "id": 8, diff --git a/app/lang/english.min.json b/app/lang/english.min.json deleted file mode 100644 index 07267f4..0000000 --- a/app/lang/english.min.json +++ /dev/null @@ -1 +0,0 @@ -{"languages":{"en":{"id":1,"lang":"English"},"de":{"id":2,"lang":"German"},"fr":{"id":3,"lang":"French"},"sp":{"id":4,"lang":"Spanish"},"pl":{"id":5,"lang":"Polish"},"trk":{"id":7,"lang":"Turkish"},"slv":{"id":8,"lang":"Slovak"},"hu":{"id":9,"lang":"Hungarian"}},"helpMsgs":[{"id":0,"title":"Introduction","msg":"An Installer and uninstaller for 40+ 'Tweaks' For the Mazda MZD Infotainment System \n Mazda 2 (DJ), Mazda 3 (BM), Mazda 6 (GJ), Mazda CX-3 (DK), Mazda CX-5 (KE), Mazda MX-5 Roadster (ND) and new 2017 Mazda CX-9 (TC)
    Fiat Spider, Toyota ScionA
    What Is MZD-AIO-TI?
    My good friend Siutsch copied files from many different tweaks for his infotainment system and thought, it would be helpful if you could choose what tweaks you wanted to install or uninstall. He went on to develop a CMD based program to accomplish this and it worked well but had reached certain limitations and lacked that modern app feel. I contacted Siutsch and proposed we make the next AIO desktop app style starting with the same tweaks from AIO v1.5.x that we all know and love. I went on to develop MZD-AIO-TI. \n\n##### I personallty tested all the tweaks in my 2016 Mazda3 FW:55.00.753A-NA\n\nCurrently this app is in a BETA TEST phase in its final stages of development. I ask for 2 things from anyone who participates in testing this app before its official release: \n\n1. Give some feedback and report any bugs or major issues. \n\n2. Be cautious and mindful to what you are doing to your system while installing or unistalling tweaks. I can offer no warranty but I did include every safety precaution I know about.\n\n###### **So please, be mindful when preforming tweak installs.** \n\nThis app will automatically update.","t2":"","msg2":""},{"id":1,"title":"Tweaking","msg":"

    All changes happen at your own risk!

    \n Please understand that you can damage or brick your infotainment system running these tweaks! \n Anyone who is unsure should leave it alone, ask someone with experience to help or ask in the forum.
    I am not responsible for damages that may incur from the use.
    Having said that, MZD-AIO-TI was built with Safety in mind so there are 3 compatibility levels: \n\n - All - Compatible with all known firmware versions \n - Under58 - Only compatible with firmware versions less then 58 (ie. 55 & 56). If the compatibility is more specific than that it will be noted. \n - Development - These are tweaks that are still under development, or do not work yet. Android Auto is getting bumped up to yellow very soon, maybe even green.","t2":"Compatible Firmware Versions:","msg2":"###### 55.00.650A/753A/760A / 56.00.521A-NA(NA N) \n\n###### 56.00.100A/230A/240B/511A/512A/513C/514A-ADR(4A N) \n\n###### 56.00.100A/230A/511A/512A/513A/513B/513C-EU \n\n###### 56.00.401A/403A-JP | 56.00.100A-CHN \n\n###### 58.00.250A-NA(NA N) / 58.00.251A-ADR(4A N) \n\n59.00.326A/330A/342A/442A/443C-ADR(4A N) \n\n###### 59.00.330A/441A/443A-NA \n\n###### 59.00.330A/331A/443C/447A/449A-EU \n\n###### Only use with FirmWare Versions >= v55. DO NOT USE with V30/31/33 OR YOU WILL BRICK YOUR SYSTEM IT WILL FOREVER STAY LOOPING THE MAZDA BOOT LOGO! \n\nTo Be Safe, For now AIO-TI Will Automatically Abort The Installation If No Compadible Firmware Version Is Found. \n\nTo overide this you have to be comfortable editing tweaks.sh directly, find the code that preforms the firmware check and disable or ad your version to the list of Compatible firmwares. **Do This At Your Own Risk!**"},{"id":2,"title":"Reverting","msg":"**Almost all the tweaks** can be uninstalled to revert to the system default state.
    Default Background:

    \n\n - AIO creates backups of all the files that it modifies and uses those backups when reverting. AIO also contains an original version of each file just in case any of the backup files are missing. In future versions I plan to include an option to copy and store your own system's backup files into AIO as a failsafe to ensure compatability for future CMD versions.\n - In general, for all Compatible CMD versions it is safe to run uninstalls of tweaks that have not been installed BUT keep in mind that AIO will overwrite the files involved with the included failsafe backups because it will not find any available backups in the system. So try to avoid running uninstallers for tweaks that you have not installed.","t2":"What Parts Of The System Are Not Reverted By AIO?","msg2":"

    MZD-AIO-TI modifies some files in the system that cannot be reverted back using this app.

    \n\nThese first 3 files honestly should never be reverted because a mistake in one of these files will result in a unrecoverable bootloop. They are only modified to disable the system from triggering a reboot on error and consequently creating a bootloop, so reverting them would put your system at a high risk. **Only the first time** the installer runs on your system they are backed up and modified.\n\n**DO NOT MODIFY ANY OF THESE FILES YOURSELF, YOU WILL BREAK YOUR SYSTEM IF YOU DO**\n\n- /jci/sm/sm.conf (Also modified by the Android Auto Tweak)\n- /jci/opera/opera_home/opera.ini \n- /jci/opera/opera_dir/userjs/fps.js\n\n##### These 2 tweaks have no uninstall because the system should have had these enabled by default.\n\n- Wifi (NA Region)\n- SSH_Bringback"},{"id":3,"title":"Troubleshooting","msg":"Here are some common errors with ways to avoid them. \n#### If you keep hitting errors and/or hang ups:\n - The most common issue is a file system access error: resource busy or locked. This occurs when a file or directory cannot be modified becasue it is open or being used by another program. While compiling, close all folders and documents especially files that are actively being used by MZD-AIO-TI (*ex: '_copy_to_usb'*)\n - Try selecting fewer tweaks at a time, picking too many increases the chaces for an unexpected error. I have tested running every single tweak at once many times, if you are consistantly hitting an error please report the bug. \n - If the installer does not start in the car try reformatting your USB drive as FAT32 and make sure all other USB devices are disconnected. It helps to turn bluetooth off too. NAV SD card should be left in.","t2":"If you are having Video Player Issues","msg2":" Try:\n\n- Place your videos in a folder named 'Movies'! \n\n- Use H264 video codec and MPEG-4 AAC audio codec in video files\n\n- Unplug all other USB drives, especially one, with many MP3s on it \n\n- Copy only one mp3 on your video USB drive \n\n- Copy only a few videos on your stick (you don't have to delete, rename to *._mp4 is OK too, so that they will not found anymore) \n\n- Reboot your system and try to play a video right after that \n\n- Close the player and start again \n\n- If that doesn't work, then change the audio input.\n\n- Sometimes the first video selected lags or fails to start but pressing 'next' will sometimes start the next video.\n\n- Videos can be: MP4, AVI, FLV, WMV"},{"id":4,"title":"Contributing","msg":"Though I did build this user interface, the more valuable aspects of this project are the tweak files. Communities like Mazda3Revolution Forum out there and many developers laid down the groundwork from which this app is built and will continue to play an important role in future developments.\n\nIf you want to contributes a tweak, make sure you test your tweak thouroughly.

    If you are an expert in javascript or AngularJS then feel free to fix up my code (its a little bit messy... sorry) or implement more of the ui 'The Angular Way'

    This Project Is Copyleft Under The GPLv3.0 License

    Github Repo","t2":"Issues","msg2":"- FW Versions 59.xx.xxx apps do not show up in the app menu (Speedometer and Video Player) also have an issue with the date to statusbar mod (rejects on installation for effecgted FW versions.) \n- If there is not enough space free on the USB drive, you will hang up while copying to USB drive. This may happen if you are copying the swapfile on a drive that is almost full. I plan to fix this in a future version and have an error message pop up. \n- If you installed the 'No Background Behind Buttons' tweak and are going to install a color scheme, it will restore the background behind buttons. Prevent this by selecting both tweaks in the same installation.\n- The Google Translator will try to translate certain parts of the code resulting in unexpected effects. Try to use it to make a translated file with the translator to include in the next version so everything will still work when others use the language."},{"id":5,"title":"Tips & Tricks","msg":"I will include some tips that go above and beyond this app.
    Here are instructions how to run the CMU OS on yor computer.","t2":"Technical Talk","msg2":"This app is built with Electron and AngularJS"},{"id":6,"title":"Help & Settings","msg":"

    Help:

    \n
    For instructions on how to generate tweak files:

    If you you hit an error
    or a hang up you can:

    Or you can:

    Love this app? Donating is a great way to show some love!:


    ","t2":"","msg2":""}],"FAQs":{"title":"FAQ","msg":"Frequently Asked Questions: ","q1":"Is AIO compatible with my FW version?","a1":"All compatible FW versions are listed in the 'Tweaking > Compatible Firmware Versions' section to the left in this help panel. MZD-AIO-TI will read out your FW version at beginning of installation and show if it’s not compatible (or not yet tested) and you will abort the installation at this point, for Safety.","q2":"How long does it take till the installation starts?","a2":"Tipically installation will start whithin 30 seconds to 2 minutes but it can take up to 10 minutes to begin.","q3":"If something goes wrong, how can I help you to help me?","a3":"During installation/uninstallation, a log file is created (AIO log.txt & MZD-AIO-TI info.txt) and some additional files will be copied on the USB drive. Please make a ZIP file of them (complete root of USB drive) and send that to me or upload it somewhere (e.g. google drive or so) and send me the link. Or you can download this tweak that will copy some files from your MZD system to the USB drive and send those.","q4":"Do I have to uninstall a tweak with AIO 1.x before installing it again?","a4":"No, You can install every tweak with AIO, you never have to uninstall before. MZD-AIO-TI 2.x use the same tweaks AIO 1.x and compatability was taken into consideration.","q5":"How long does the installation/uninstallation take?","a5":"Up to 10 minutes if every tweak has been selected (especially custom colors and speedcam-patch). Preforming a backup of your JCI folder can also take up to 10 minutes by itself so with everything up to 20 minutes.","q6":"What if I want to revert my system but I forgot the tweaks I've installed?","a6":"Uninstalling tweaks is safe in general, if the uninstaller dosn't find a backup, it will copy the original files from USB drive over your original files of your MZD system BUT: YOU SHOULD NOT DO THIS FOR NEW AND UNKNOWN FW VERSIONS! See: 'Reverting' section of this help panel.","q7":"I want to change the order of the audio sources?","a7":"Edit: /jci/gui/apps/system/js/systemApp.js on lines 624 - 637

    * Be careful, the last line must not end with a comma, or you run in to boot loop! *
    I am working on modifying the tweak to give the option to make your own order without manually modifying any files.","q8":"Can I install AIO from an SD card?","a8":"No. SD card slot in the car is ONLY for satnav maps. You need to use USB port in the car, so either USB stick or USB-SD card reader with your card in it.","q9":"How do I a reboot the MZD system? ","a9":"Press NAV+MUTE for 10 seconds.","q10":"Can you write this or that tweak for us?","a10":"I have improved on many of the existing tweaks and tweaks.sh as a whole but I do have a job and Developing the GUI for this app is a pretty hefty task. That being said, I do have ideas for future tweaks and I will take suggestions but no promises. You can contact me with the contact form on the bottom right of the app."},"tourMsgs":[{"id":0,"msg":"

    Welcome to MZD-AIO-TI!


    Mazda All In One Tweaks Installer

    An Installer And Uninstaller for 40+ 'Tweaks' For the Mazda MZD Infotainment System."},{"id":1,"msg":"These are the main Tweaks. You can choose to install or uninstall for each."},{"id":2,"msg":"This sidebar will list all the tweaks currently selected. Here will appear extra options and you can also click any item in this list for help information."},{"id":3,"msg":"Additional actions such as backup jci folder & enable wifi for North American versions."},{"id":4,"msg":"These options can be restored to original state by selecting their default options."},{"id":5,"msg":"The menus have more help topics and links to resources and documentation."},{"id":6,"msg":"When all your tweaks have been selected, click this button to compile and go!"},{"id":7,"msg":"Copy the entire contents of the \"_copy_to_usb\" folder onto a blank, FAT32 format USB Flash Drive. Plug the drive into the car's usb port, the installer will start automatically after a few minutes. Remove any other USB devices but The NAV SD card should remain plugged into the car. Turning off bluetooth and wifi help as well. After the installation is complete the system will reboot, then you can remove the USB drive and your changes will be applied."},{"id":8,"msg":"For more information visit MazdaTweaks.com!"}],"popupMsgs":[{"id":0,"msg":"Compiling... Please Wait..."},{"id":1,"msg":"Location of Tweak Files"},{"id":2,"msg":"(For best results, erase USB drive prior to copying)"},{"id":3,"msg":"Copy to USB Drive"},{"id":4,"msg":"Not Yet"},{"id":5,"msg":"Open USB Drive"},{"id":6,"msg":"USB drives Found"},{"id":7,"msg":"Do you want to copy files to USB drive"},{"id":8,"msg":"Choose a USB drive to copy files onto"},{"id":9,"msg":"No available USB drives found. Copy the entire contents of"},{"id":10,"msg":"onto a blank, FAT32 formatted USB flash drive"},{"id":11,"msg":"Copying to USB Drive"},{"id":12,"msg":"Please Wait"},{"id":13,"msg":"Unzipping Swapfile To"},{"id":14,"msg":"This takes a few minutes... be patient."},{"id":15,"msg":"Swapfile size is 1 GB."},{"id":16,"msg":"While you wait, here is some information"},{"id":17,"msg":"Start Over"},{"id":18,"msg":"View AIO Compile Log"},{"id":19,"msg":"Exit"},{"id":20,"msg":"Success!"},{"id":21,"msg":"Delete _copy_to_usb Folder After Copying"}],"mainOps":{"wifi":{"id":0,"label":"Enable WIFI","safetylvl":"safe","toolTip":"
    WIFI
    Enables WIFI for North America Region"},"backup":{"id":1,"label":"Backup JCI Folder","safetylvl":"safe","toolTip":"
    Backup JCI
    Do backup of JCI folder before installing tweaks."},"background":{"id":2,"label":"Background Image","safetylvl":"safe","toolTip":"
    Background
    Change your Infotainment background to your own custom image. Supported image formats are: jpg, jpeg, and png (any size). Note: If single img is chosen, the image will be resized to 800px x 480px BUT NOT CROPPED and converted .png format. To change the background image back to original, choose 'Default Background.","img":"cic.jpg"},"colors":{"id":3,"label":"Custom Infotainment Colors","safetylvl":"safe","toolTip":"
    Custom Color Schemes:
    Changes your Infotainment color scheme from Red (default) to one the following colors:
    • Blue
    • Green
    • Orange
    • Pink
    • Purple
    • Silver
    • Yellow
    • Smooth Red
    Themes: Themes only replace the main menu coins. When installed over a color scheme, the custom colors will remain with the theme. Included Themes:
    • carOS
    • Storm Troopers
    • Poker
    • Mazda Logos
    • Floating Logo
    • X-Men

    PROTIP: Delete all the images that you do not want to change. It can be as little as deleting one folder or as much as deleting every image except one. ","toolTip2":"
    The Custom Theme Option:
    Use any theme designed for the MZD Infotainment System or easily apply your own Custom Made Theme.
  • To use any theme: download and unzip the theme
  • Import the config/jci/ folder from the theme into AIO.

  • NOTE: Using This Method Will Copy Only .png Files For Themes
    Using Your Own Custom Made Theme:
  • If no theme is chosen: a folder will be generated here: _copy_to_usb/config/color-schemes/theme/jci/
  • After compiling tweaks, copy your files into the generated jci folder in the same directory location of the images you want to replace.
    WARNING: WHEN USING THIS METHOD EVERYTHING IN THE JCI FOLDER WILL BE COPIED ONTO YOUR SYSTEM IN THE SAME LOCATION. USE RESPONSIBLY.
    ","img":"carOS.png"},"sshbringback":{"id":4,"label":"Install SSH_bringback","safetylvl":"safe","toolTip":"
    SSH_bringback
    **No removing possible!** With FW 56.00.511 Mazda has removed SSH access. With SSH_bringback this will be reinstalled. This tweak will still only be installed if FW 56.00.511 is recognized, if it's 56.00.230, nothing happens."},"sdcid":{"id":5,"label":"SD CID","safetylvl":"safe","toolTip":"
    SD CID
    Gets the CID from the Nav SD card if available."},"backgroundrotator":{"id":6,"label":"Background Rotator","btntxt":"Join Images","button":"Click To Join Images For Your Background To Rotate Through","safetylvl":"safe","toolTip":"
    Background Rotator Tweak.
    Cycles through 10 Backgrounds over 10 minutes (600 seconds - 60 seconds per background). Note: After installing this tweak, you can change your joined background multiple times without installing again. To Revert back to a single background uninstall this tweak."},"retain":{"id":7,"label":"Copy Backups","testlabel":"Test Backups","safetylvl":"safe","toolTip":"
    Copy Backups:

    Copy original backups of modified system files, for safe keeping.

    Test Backups:

    Some tweaks have before and after copys of the files modified during the instalation. If you like that kind of thing they will copied to your-usb/bakups/test/.

    "},"mainmenu":{"id":8,"label":"Main Menu Tweaks","safetylvl":"safe","toolTip":"
    Main Menu Tweaks

    • Alternative Main Menu Layouts
      • 'Star Points' Layout

      • 'Inverted' Layout

    • 3D Main Menu Label
    • Hide Main Menu Ellipse
    • Smaller Main Menu 'Coins'
    ","img":"Alt-layouts.jpg"},"uistyle":{"id":9,"label":"Text Colors","safetylvl":"safe","toolTip":"

    User Interface Text Style Tweaks

    Customize Your User Interface Style and Text Colors:
    • Song Title
    • Artist & Album
    • Radio Station
    • List Item & Disabled List Item
    • Text Shadow
    "},"offscreenbg":{"id":10,"label":"Off Screen Background","btntxt":"Off Screen Default","safetylvl":"safe","toolTip":"
    Off Screen Background.
    Background Image when \"Turn Display Off and Show Clock\" is chosen in the Settings menu. Also shown during system shutdown."}},"menu":{"save":{"menuId":"0","label":"Save","toolTip":"Save Current Configuration."},"load":{"menuId":"1","label":"Load","toolTip":"Load Last Saved Configuration"},"tour":{"menuId":"2","label":"Tour","toolTip":"Take a Tour of MZD-AIO-TI"},"lastcompilelog":{"menuId":"3","label":"Last Compile Log","toolTip":"MZD_LOG"},"installall":{"menuId":"4","label":"Install All","toolTip":"Install All Except: Android Auto and Castscreen."},"uninstallall":{"menuId":"5","label":"Uninstall All","toolTip":"Uninstall All Tweaks."},"resetoptions":{"menuId":"6","label":"Reset Options","toolTip":"Reset Checked Options."},"reloadapp":{"menuId":"17","label":"Reload App","toolTip":"Reload the app."},"copytousb":{"menuId":"8","label":"_copy_to_usb","toolTip":"Open _copy_to_usb Folder"},"help":{"menuId":"9","label":"Help","toolTip":"Click tweak name for help."},"install":{"menuId":"10","label":"Install"},"uninstall":{"menuId":"11","label":"Uninstall"},"languages":{"menuId":"12","label":"Languages"},"close":{"menuId":"13","label":"Close"},"clickforhelp":{"menuId":"14","label":"Click For Help"},"tweakstoinstall":{"menuId":"15","label":"Tweaks To Install"},"file":{"menuId":"18","label":"File"},"window":{"menuId":"19","label":"Window"},"download":{"menuId":"20","label":"Download"},"fullscreen":{"menuId":"20","label":"Fullscreen"},"translator":{"menuId":"21","label":"Translator"},"dlcolors":{"menuId":"22","label":"Download Color Scheme Files"},"dlspeedcam":{"menuId":"22","label":"Download Speedcam Patch Files"},"helppanel":{"menuId":"23","label":"Help Panel"},"changelog":{"menuId":"24","label":"Changelog"},"start":{"menuId":"16","label":"Start Compilation","toolTip":"

    Ready?

    Start The Compilation!"},"centerwindow":{"menuId":"17","label":"Center Window","toolTip":"Reset Window Size and Position"}},"imgOps":[{"id":0,"label":"Join multiple images for your infotainment background"},{"id":1,"label":"Select up to 50, 480px X 800px Images (Each Image will be resized to 480x800). Background Rotator Will Show Each Background For X Seconds (Max 300 Seconds = 5 Minutes per img)."},{"id":2,"label":"Drag images to change order."},{"id":3,"label":"images selected"},{"id":4,"label":"You need to choose some images to join (Each will be resized to height: 480px, width: 800px) or "},{"id":5,"label":"Use Your Own Joined Image (No Resize)"},{"id":6,"label":"This image wil replace your infotainment background."},{"id":7,"label":"Save Image As"},{"id":8,"label":"Make Another"},{"id":9,"label":"Right-click > Save Image saves a copy of background.png to your downloads folder."},{"id":10,"label":"Minutes"},{"id":11,"label":"Select Images"},{"id":12,"label":"Images"}],"translatorWindow":[{"label":"Language Translator"},{"label":"Reset to Default"},{"label":"Enter Language Name (file will save as"},{"label":"in your 'documents' folder"},{"label":"Email translated files to"},{"label":"Pull Request"},{"label":"loading"},{"label":"Saved in 'Documents'"},{"label":"Show In Explorer"},{"label":"Load File"},{"label":"This section was designed for easily translating this app into many languages."},{"label":"Choose a translation file to edit"},{"label":"Enter name of the translated language"},{"label":"BACK"},{"label":"Save (To Documents)."},{"label":"Auto-Save"}],"colors":{"red":{"id":0,"label":"Red (Default)"},"blue":{"id":1,"label":"Blue"},"green":{"id":2,"label":"Green"},"silver":{"id":3,"label":"Silver"},"pink":{"id":4,"label":"Pink"},"purple":{"id":5,"label":"Purple"},"orange":{"id":6,"label":"Orange"},"yellow":{"id":7,"label":"Yellow"},"smoothred":{"id":9,"label":"Smooth Red"},"caros":{"id":8,"label":"CarOS"},"stormtroopers":{"id":10,"label":"Storm Troopers"},"poker":{"id":11,"label":"Poker"},"mazdalogos":{"id":12,"label":"Mazda Logos"},"floating":{"id":13,"label":"Floating Logo"},"xmen":{"id":14,"label":"X-Men"},"custom":{"id":15,"label":"Custom Theme"}},"statusbar":{"main":{"id":0,"label":"Remove Statusbar Background"},"opacity":{"id":1,"label":"Statusbar Opacity"},"app":{"id":2,"label":"App Title"},"clock":{"id":3,"label":"Clock"},"notif":{"id":4,"label":"Status Notifications"},"d2sbinst":{"id":5,"label":"Date To Statusbar Mod"},"d2sbuninst":{"id":6,"label":"Remove Date To Statusbar Mod"}},"uistyle":{"body":{"id":0,"label":"Body Text (Audio Artist & Album)"},"listitem":{"id":1,"label":"List Item"},"listitemdisabled":{"id":2,"label":"Disabled List Item"},"title":{"id":3,"label":"Song Title"},"radio":{"id":4,"label":"Radio Station"},"main3d":{"id":5,"label":"3D Main Menu Text"},"ellipse":{"id":6,"label":"Remove Ellipse"},"altlayout":{"id":7,"label":"'Star Points' Layout"},"shadow":{"id":8,"label":"Text Shadow"},"altulayout":{"id":9,"label":"'Inverted' Layout"},"minicoins":{"id":10,"label":"Smaller 'Coins'"}},"speedcamOps":[{"id":0,"label":"Europe With Mobile Cameras"},{"id":1,"label":"Europe Without Mobile Cameras"},{"id":2,"label":"Germany With Mobile Cameras"},{"id":3,"label":"Germany Without Mobile Cameras"},{"id":4,"label":"Turkey"},{"id":5,"label":"Use Your Own speedcam.txt file"}],"disclaimOps":[{"id":0,"label":"Remove Completely"},{"id":1,"label":"Reduce Time To 0.5 seconds"}],"fuelOps":[{"id":0,"label":"Km/L"},{"id":1,"label":"MPG"}],"d2sbOps":[{"id":0,"label":"V1.0"},{"id":1,"label":"v3.3 (Date Localized)"},{"id":2,"label":"V3.3 (dd.mm.)"},{"id":3,"label":"V3.3 (mm/dd)"}],"speedoOps":{"lang":{"en":{"id":0,"label":"English"},"de":{"id":1,"label":"German"},"sp":{"id":2,"label":"Spanish"},"pl":{"id":3,"label":"Polish"},"sl":{"id":4,"label":"Slovak"},"tk":{"id":5,"label":"Turkish"},"fr":{"id":6,"label":"French"},"it":{"id":7,"label":"Italian"}},"xph":{"mph":{"id":10,"label":"MPH"},"kmh":{"id":11,"label":"KM/H"}},"sml":{"gps":{"id":20,"label":"GPS Values"},"car":{"id":21,"label":"Car Values"},"none":{"id":22,"label":"Do Not Activate"}},"bg":{"ind":{"id":30,"label":"Individual Background"},"orig":{"id":31,"label":"Original Background"}},"opac":{"id":40,"val":"0","label":"Black Background Opacity? (To Reduce Visibility of Custom MZD Background Image) 0.0 (Fully Transparent) - 1.0 (Completely Black)"}},"tweakOps":[{"id":1,"OpName":"Touchscreen While Moving","INST":"Enable the touchscreen while moving","DEINST":"Disable the touchscreen again while moving","toolTip":"
    Touchscreen
    Allows the use of the touchscreen while driving.
    Fix Cluster Compass: Some things will be disabled while driving but the touchscreen itself and the cluster compass will work","img":"","safetylvl":"safe","extraOps":true,"advancedOp":false},{"id":2,"OpName":"No More Disclaimer","INST":"Remove disclaimer completely","DEINST":"Restore disclaimer (to 3.5 seconds)","toolTip":"
    No More Disclaimer
    Completely remove the disclaimer or reduce the expansion time of the disclaimer from 3.5 to 0.5 seconds.","img":"","safetylvl":"safe","extraOps":true,"advancedOp":false},{"id":3,"OpName":"Reverse Camera Safety Warning","INST":"Remove the reverse camera safety warning","DEINST":"Restore the safety warning label to the reverse camera","toolTip":"
    Reverse Camera Safety Warning
    No security warning at the bottom when activating the rear camera.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":4,"OpName":"Semi-transparent parking sensor graphics","INST":"Install semi-transparent parking sensor graphics","DEINST":"Remove semi-transp. parking sensor graphics f. proximity sensors","toolTip":"
    Semi-Transparent Parking Sensor Graphics.
    Semitransparent parking sensor graphics for proximity sensors.. When activating the rear camera, the car is displayed at the top right corner.#The graphics now appear semitransparent by installing tweak.","img":"semi-transparent_parking-sensors.jpg","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":5,"OpName":"Main Menu Loop","INST":"Install main_menu_loop","DEINST":"Remove main_menu_loop","toolTip":"
    Main Menu Loop.
    Loop for the main menu.
    You can jump from left to far right, and vice versa.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":6,"OpName":"Improved List Loop","INST":"Install improved_list_loop","DEINST":"Remove improved_list_loop","toolTip":"
    Improved List Loop.
    Loop for all lists and submenu (music, contacts, etc.).
    You can now jump from the top position of a list to the bottom and vice versa.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":7,"OpName":"Shorter Delay Mod","INST":"Install shorter_delay_mod","DEINST":"Remove shorter_delay_mod","toolTip":"
    Shorter Delay Mod.
    Reduces the waiting time for switching between pages with the multi commander from 1.5 to 0.3 seconds.
    Uninstalling Improved List Loop will also uninstall this mod.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":8,"OpName":"Media Order Patch & FLAC Support","INST":"Enable media_order patch and FLAC support","DEINST":"Remove media_order_patching","toolTip":"
    Media Order Patching and FLAC Support
    Music will be sorted alphabetically and not by date with new entries first. Support for audio format FLAC.","img":"","safetylvl":"warning","extraOps":false,"advancedOp":false},{"id":9,"OpName":"Order of Audio Source List","INST":"Change order of the audio source list","DEINST":"Restore order of audio source list back to original","toolTip":"
    Change Order of the Audio Source List.
    The order of the audio source list is arranged as follows:.
  • FMRadio
  • DAB
  • USB_A
  • USB_B
  • btaudio
  • CD
  • SatRadio
  • AhaRadio
  • Pandora
  • StitcherAuxIn
  • amradio
  • DVD
  • TV
  • ","img":"","safetylvl":"warning","extraOps":false,"advancedOp":false},{"id":10,"OpName":"Pause on mute","INST":"Install pause_on_mute","DEINST":"Remove pause_on_mute","toolTip":"
    Pause On Mute.
    When pressing mute (pressing the volume button) played media are also paused.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":11,"OpName":"Remove Message Reply","INST":"Remove automatic message replies","DEINST":"Restore automatic message replies","toolTip":"
    Remove Message Replies
    Removes the text 'Sent from my Mazda Quick Text System' if answering messages.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":12,"OpName":"1 Sec Diag Menu","INST":"Install 1 second diagnostic menu","DEINST":"Remove 1 sec. diagnostic menu","toolTip":"
    1 Sec Diag Menu
    Allows you to open the diagnostic menu by touching the clock at the top right of the display settings menu for one second.","img":"","safetylvl":"warning","extraOps":false,"advancedOp":false},{"id":13,"OpName":"Boot Animation","INST":"Disable boot animation","DEINST":"Boot Animation enable again","toolTip":"
    Boot Animation
    The boot animation that leads to the menu with the red buttons will be disabled.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":14,"OpName":"Bigger Album Art","INST":"Install bigger album art cover","DEINST":"Album art cover back to original","toolTip":"
    Bigger Album Art
    You get a bigger album art graphic.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":15,"OpName":"No Background Behind Buttons","INST":"Remove the background behind buttons","DEINST":"Background behind buttons back to original","toolTip":"
    No Background Behind Buttons
    Remove the background behind the buttons.","img":"NoButtonBackground.jpg","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":16,"OpName":"Change Blank Album Art Frame","INST":"Remove the blank album art frame","DEINST":"Restore the blank album art frame","toolTip":"
    Change Blank Album Art Frame
    The empty album cover frame is removed, which is displayed when there is no entry in the Gracenote database for the artist. Then the image of a radio is displayed, if there is no cover in the MP3 tag too. Supported image formats are: jpg, jpeg, and png (any size). Note: The image chosen will be resized to 146px x 146px BUT NOT CROPPED and converted .png format","img":"","safetylvl":"safe","extraOps":true,"advancedOp":false},{"id":17,"OpName":"Videoplayer","INST":"Install videoplayer","DEINST":"Remove videoplayer","toolTip":"
    Videoplayer
    Add videoplayer app to the application menu.","img":"","safetylvl":"safe","extraOps":false,"advancedOp":false},{"id":18,"OpName":"Swapfile","INST":"Generate swapfile for media player v2","DEINST":"Remove swapfile","toolTip":"
    Swapfile
    The installation of the swap file must be done on a USB drive with music and/or movies, that remains in the car.. The installation files are automatically deleted, the drive may no longer be removed during operation, because the system will use it also as memory.. Only remove the USB drive if the MZD system is off.","img":"","safetylvl":"warning","extraOps":true,"advancedOp":false},{"id":19,"OpName":"Speedometer","INST":"Install speedometer by Diginix","DEINST":"Remove speedometer by Diginix","toolTip":"
    Speedometer With Compass in the Application Menu.
    • Below the speedometer is km/h or mph, depending on the setting
    • Speed range up to 240 km/h
    • Consumption values
    • Optimized graphics modules with new speedometer pointer
    • Small speedometer needle for top speed in the analog part
    • The picture for the speedometer scale has different lengths or bright lines for 5, 10 and 20 km/h jumps
    • Right table english or german German and color / size optimized
    • All numbers have a slight shadow around to better stand out from the background.
    • On travel direction rotating compass central to the current speed
    • Animated overlay in the status with GPS speed and direction of travel in each menu can be prepared by touch at the clock
    • Latitude and longitude in the right table
    • When the Navi or Rear Camera is started, it automatically appears

    For the small speedo in the status bar you have to install date_to_statusbar mod V2.2 too. Therefore it will be automatically selected, if not already done.","img":"mzd_SpeedoCompass.gif","safetylvl":"safe","extraOps":true,"advancedOp":false},{"id":20,"OpName":"Statusbar Tweaks","INST":"Install Statusbar Tweaks","DEINST":"Remove Statusbar Tweaks","toolTip":"
    Statusbar Mods
    Add some Color to your statusbar text.
    Change Colors For:

    App Name: Title of the app or media source.

    Clock: This one is pretty self explanatory.

    Status Notification: Navigation notifications

    Remove Statusbar Background Image And
    Adjust Statusbar Opacity (From 0-1: 0 = transparent, 1 = Black)
    Safe for all FW Versions
    Date In Status Bar Mod.
    Permanently visible date + icons by the clock, even if system messages are displayed.","img":"mzd_datum_icons_all.jpg","safetylvl":"safe","extraOps":true,"advancedOp":false},{"id":22,"OpName":"FuelConsumption Tweak","INST":"Install Fuel Consumption Tweak","DEINST":"Remove Fuel Consumption Tweak","toolTip":"
    Fuel Consumption Tweak.
    Additional display of KM / L (or MPG).","img":"FuelConsumptionTweak.jpg","safetylvl":"safe","extraOps":true,"advancedOp":false},{"id":23,"OpName":"Speedcam patch","INST":"Install Speedcam-Patch","DEINST":"Remove speedcam-patch","toolTip":"
    Speedcam Patch.
    The navigation is so patched so that database for speed cameras are accepted.. You can then copy a file 'speedcam.txt' on the SD card for the navigation, which will be imported.","img":"","safetylvl":"warning","extraOps":true,"advancedOp":false},{"id":24,"OpName":"Castscreen-receiver","INST":"Install Castscreen-Receiver","DEINST":"Remove castscreen-receiver","toolTip":"
    Castscreen receiver.
    After installation you can mirror the smartphone screen at the infotainment display (mirroring).
    • You have to install the castscreen app on your Android Phone (castscreen-1.0.apk) The app can be found in the 'config' folder of your USB drive
    • activate the debug mode on your smartphone
    • connect the smartphone with USB cable to the infotainment system
    • start the app settings: H264, 800x480 @ 160, 1 mbps, then input 127.0.0.1 and press input receiver, then tap Start on right-up corner.
    .","img":"","safetylvl":"warning","extraOps":true,"advancedOp":false},{"id":25,"OpName":"Android Auto Headunit App","INST":"Install Android Auto Headunit App","DEINST":"Remove Android Auto Headunit App","toolTip":"
    Android Car Headunit app. Android car for the infotainment system.

    1. Install the Android app from google play store:HERE.
    2. Connect the phone to USB and pair the phone bluetooth with the CMU
    3. Manually switch to Bluetooth Audio Input.
    4. Click on the AA icon under Applications Menu on the CMU
    5. A black screen with credits should open up first and input
    6. Android Auto will then start. If it does not, pull out the USB and start over again (or check the installation.)
    7. 2 ways to stop AA - Disconnect the USB cable or use the onscreen menu 'Return to Mazda Connect' on last screen with speedo icon..
    8. Once disconnected, the back screen will remain. Press Home Button on the Mazda's Commander to close it. I had to do this because js double click wasn't working..
    **What does not work:**
    1. Reverse camera gets blacked out.
    2. Voice Control
    3. Touch drag / multi touch
    4. Google Maps night mode always on.
    Android Auto Patch!:
    No need input_filter anymore (#12)
    'Remove the input_filter background process. It's not needed since we can use EVIOCGRAB to consume input events before the CMU UI without the /dev/uinput trickery.' /cc @lmagder https://github.com/gartnera/headunit/commit/70958cf33c9facaed11f4b59c11f
    ","img":"AndroidAuto.jpg","safetylvl":"development","extraOps":true,"advancedOp":true}]} diff --git a/app/lang/magyar.min.json b/app/lang/magyar.min.json deleted file mode 100644 index 9cb9db0..0000000 --- a/app/lang/magyar.min.json +++ /dev/null @@ -1,1087 +0,0 @@ -{ - "languages": { - "en": { - "id": 1, - "lang": "Angol" - }, - "de": { - "id": 2, - "lang": "Német" - }, - "fr": { - "id": 3, - "lang": "Francia" - }, - "sp": { - "id": 4, - "lang": "Spanyol" - }, - "pl": { - "id": 5, - "lang": "Lengyel" - }, - "trk": { - "id": 7, - "lang": "Török" - }, - "slv": { - "id": 8, - "lang": "Szlovák" - }, - "hu": { - "id": 8, - "lang": "Magyar" - } - }, - "helpMsgs": [ - { - "id": 0, - "title": "Bemutatás", - "msg": "Telepítő és törlő program, több mint 40 \"Tweak\"-hez a Mazda Infotainment rendszeréhez a következő járművekben: Mazda 2 (DJ), Mazda 3 (BM), Mazda 6 (GJ), Mazda CX-3 (DK), Mazda CX-5 (KE), Mazda MX-5 Roadster (ND) and new 2017 Mazda CX-9 (TC)
    Fiat Spider, Toyota ScionA
    Mi is az a MZD-AIO-TI?
    My Egy jó barátom Siutsch összegyűjtötte az általa használt tweak-ek fájljait, abból a célból, hogy egyesítve egy felületen ki lehessen választani, hogy melyekre van szüksége valakinek és azokat egyszerűen telepíteni és újra törölni tudja. Ebből született egy CMD (command line) alapú program, mely gyorsan elérte a határait és hiányzott a manapság megszokott \"app\"-hatás. Ekkor vettem fel Siutsch-csal a kapcsolatot és felajánlottam neki, hogy együtt csináljunk egy programot számítógépre, amit mindenki egyszerűen tud kezelni és nem igényel különösebb technikai tudást. Ebből lett az itt látható MZD-AIO-TI. \n\n##### Én személyesen minden tweak-et leteszteltem a saját 2016-os Mazda3 FW:55.00.753A-NA MZD-men. Egyelőre ez az app BÉTA TESZT fázisban van, de a fejlesztés hamarosan a végére ér. Két dolgot szeretnék minden tesztelőtől kérni a végleges release előtt: 1. Mindenképpen jelezd a véleményedet és ha kisebb nagyobb hibát találd azt jelentsd nekem. 2. Legyél figyelmes miközben tweak-eket telepítesz vagy törölsz. Nem tudom garantálni a hibátlan működést, de igyekeztem a lehető legktöbbet megtenni azért, hogy ne legyen baj. ###### **Ezért kérlek nagyon ügyelj arra, hogy mit is csinálsz.** \n\nEz az applikáció automatikusan frissül, ha új verzió lesz elérhető.", - "t2": "", - "msg2": "


    " - }, - { - "id": 1, - "title": "Tweakelés", - "msg": "

    Minden változtatás csak a saját felelősségre!

    \n Vedd figyelembe, hogy ezekkel a saját fejegységedbe nyúlsz bele, amely így nem megfelelő használat mellett tönkre is mehet! AnyoneMindenki, aki nem biztos abban, hogy mit is csinál, inkább ne végezze el a változtatásokat egyedül, hanem kérjen a fórum-on segítséget.
    Én nem felelek semmilyen kárért, ami a használatból következik.
    HavingMindazonáltal a MZD-AIO-TI úgy lett fejlesztve, hogy gondoltam a biztonságra is, ezért három kategóriába sorolom a tweak-eket: \n\n - Biztonságos - sokat tesztelt és általánosan is biztonságosnak tekintett - Figyelem - Érzékeny rendszerfájlokat módosít, vagy még nem lett tesztelve. Általában nagy biztonsággal, használható kellő figyelem mellett! Ezek közül a legtöbb rövid időn belül átkerülhet a \"biztonságos\" kategóriába.\n - Fejlesztés alatt - Ezek a tweak-ek fejlesztés alatt álnak, vagy még nem működnek. Csak az Android Auto van jelenleg ezen a szinten, de úgy tűnik, hogy nemrégiben sikerült megoldaniuk a problémákat.", - "t2": "Kompatibilis firmware verziók:", - "msg2": "###### 55.00.650A/753A/760A / 56.00.521A-NA(NA N) \n\n###### 56.00.100A/230A/240B/511A/512A/513C/514A-ADR(4A N) \n\n###### 56.00.100A/230A/511A/512A/513A/513B/513C-EU \n\n###### 56.00.401A/403A-JP | 56.00.100A-CHN \n\n###### 58.00.250A-NA(NA N) / 58.00.251A-ADR(4A N) \n\n59.00.326A/330A/342A/442A/443C-ADR(4A N) \n\n###### 59.00.330A/441A/443A-NA \n\n###### 59.00.330A/331A/443C/447A/449A-EU \n\n###### Csak >= v55. firmware verziókhoz! NE HASZNÁLD V30/31/33 FW-hez VAGY TÖNKRE TESZED A FEJEGYSÉGED, mely így folyamatosan a Mazda logónál fog maradni! A biztonság kedvéért a program leállítja a telepítést, ha egy nem kompatibilis verziót észlel! Ahhoz, hogy ezt felülírd, át kell írnod a tweaks.sh-ban a kódrészt, amely a verzióbiztonságért felel, vagy hozzá kell addnod a saját verziódat a támogatottak listájához. **CSAK SAJÁT FELELŐSSÉGRE!** *A Mazda közösség segítségével idővel az 59.x-es FW verzió is be fog kerülni a támogatott FW-ek listájába.*" - }, - { - "id": 2, - "title": "Visszaállítás", - "msg": "**Szinte minden tweak-et** le lehet törölni, hogy visszaálljon a rendszer az alaphelyzetbe.
    Alapértelmezett háttér:

    \n\n - AZ AIO minden módosított fájlról egy biztonsági mentés készít, a változtatás előtt. Ezeket a fájlokat használja az eredeti állípot visszaállításához. Ezenfelül az AIO szintén tartalmazza az eredeti fájlok másolatát, arra az esetre, ha mégse állnának biztonsági mentések rendelkezésere. Jövőbeni verziókban lesz egy olyan funkció, amely lehetővé teszi, hogy a saját rendszer fájlai legyenek az AIO-ba elmentve, így leegyszerűsítve a jövőbeni verziók támogatását. - Általánosságban kimondható, hogy minden kompatibilis FW verzióval nyugodtan visszaállíthatóak olyan tweak-ek is, melyek nem lettek telepítve, DE tartsd észben, hogy ebben az esetben az AIO átírja az eredeti fájlokat a központi biztonsági mentésben található fájlokkal. Tehát lehetőség szerint, ne törölj olyan tweak-eket, amelyek nem lettek telepítve, hogy ne legyen felesleges változtatás a rendszereden.", - "t2": "Mely beállításokat nem lehet visszaállítani az AIO-val?", - "msg2": "

    MZD-AIO-TI néhány olyan fájlt is módosít, amelyet nem lehet az applikáció segítségével visszaállítani.

    Ez a három fájl soha ne legyen visszaállítva, mert bármely hiba a visszaállítás során ahhoz vezethet, hogy az MZD örökre fennakadjon. Ezek a fájlok csak azért kerülnek változtatásra, hogy ne tudjon a rendszer egy váratlan újraindítást produkálni telepítés közben. **Csak az első indításkor** amikor a telepítő lefut a rendszeren, biztonsági mentést készít ezekről a fájlokról. **NE VÁLTOZTASD MAGAD EZEKET A FÁJLOKAT, KÜLÖNBEN TÖNKRETEHETED A RENDSZEREDET!**\n\n- /jci/sm/sm.conf (Android Auto is módosítja)\n- /jci/opera/opera_home/opera.ini \n- /jci/opera/opera_dir/userjs/fps.js\n\n##### These Ennek a 2 tweak-nek nincs visszaállítási lehetősége, mert ezeknek már alapból működnie kéne.\n\n- Wifi (É-Ameriaki régió)\n- ssh_bringback az 56.00.511A/512A/513B-EU FW verziókhoz" - }, - { - "id": 3, - "title": "Hibaelhárítás", - "msg": "Itt van néhány gyakori probléma és a megoldásuk. \n#### Ha folyamatosan hibákba futsz vagy elakadsz::\n - Általában hozzáférési jogosultságokkal van probléma: a kívánt erőforrás foglalt, vagy le van terhelve. Ez akkor lép fel, ha egy fájlt vagy mappát nem lehet elérni, mert már meg van nyitva, vagy éppen egy másik program használja. Kompilálás alatt zárj be minden mappát és dokumentumot, főleg azokat amelyeket a  MZD-AIO-TI is használ(*pl: '_copy_to_usb'*)\n - ISokszor próbáltam egyszerre az össze tweak kompilálását, ha te esetleg mégis valami hibába futsz folyamatosan, kérlek jelezd. - Ha a telepítő nem indul amikor bedugod az autóban, akkor formázd újra FAT32 formátumra a pendrice-odat és csatlakoztass le minden más USB eszközt. Az is segíthet, ha kikapcsolod a bluetooth-t. A Navigáció SD kártyája maradjon bent.", - "t2": "Probléma a videó lejátszóval", - "msg2": " Próbáld:\n\n- Helyezd a filmjeidet egy 'Movies' nevű mappába! \n\n- Használj H264 videó codec-et és MPEG-4 AAC audió codec-et videókhoz - Csatlakoztass le minden USB eszközt, különösen azokat, amelyek sok MP3-at tartalmaznak - Csak egy MP3-at másolj a videók mellé a pendrivera - Csak kevés videót másolj a pendrive-odra (nem kell törölnöd fájlokat, elég ha megváltoztatod a kiterjesztését *._mp4-re, mert így már nem lesznek felismerve) \n\n- Indítsd újra a gépedet és próbálj meg lejátszani egy videót - Zárd be a lejátszót és indítsd újra - Ha ez nem segít, akkor változtasd meg a hangbemenetet - Néha az első videó akadozik, vagy nem indul el, kattints a \"következő\" gombra, amely így a következő videót fogja elindítani - Támogatott videóformátumok: MP4, AVI, FLV, WMV" - }, - { - "id": 4, - "title": "Hozzájárulás", - "msg": "A kezelői felület az én munkám, de a projekt legfontosabb részei a tweak-ek maguk. Közösségek, mint pl. a Mazda3Revolution Forum és sok fejlesztő tette le az alapokat, melyekre ez a program épül és a jövőbeni fejlesztésre is nagy befolyással lesznek. Ha szeretnéd, hogy a te általad fejlesztett tweak is bekerüljön, akkor teszteld először a lehető legalaposabban. 

    Ha JavaScript vagy AngularJS varázsló vagy, akkor nyugodtan takarítsd fel a kódot (kicsit káosz van benne ... bocsi) vagy implementáld a felületet \"angulárisan\"

    Ez a projekt Copyleft és 
    GNU GPLv3
    LOADING....
    \">GPLv3.0 License
     alatt áll!

    Github Repo", - "t2": "Problémák", - "msg2": "- Az 59.xx.xxx FW verziók app-jei nem láthatók a menüben (Speedometer és Video Player) és a \"dátum a fejlécben\" mod is problémás (az érintett FW verziókon nem lehet telepíteni) - Hogyha nincs elég hely a pendrive-on, akkor legfagy a program a fájlok másolása közben. Ez általában akkor történik, amikor a swap fájlt másoljuk egy olyan pendrive-ra, amely már majdnem tele van. Egy jövőbeni verzió megoldja majd a problémát és egy felugró hibaablak fogja jelezni ezt. - Ha telepítetted a \"háttérkép nélküli gombok\" mod-ot és telepíted a színsémákat, akkor visszaáll a gombok háttere. Ezt megelőzheted, ha mindkét tweak-et egyszere telepíted. - A Google Fordító megpróbálja a kódot néhány helyen lefordítani, ez nem várt dolgokat produkálhat. Használd ezt a fordítóban egy új nyelvre való fordításra, hogy az bekerüljön a jövőbeni verziókba és mások is tudják használni fordításkor." - }, - { - "id": 5, - "title": "Tippek & trükkök", - "msg": "I Itt találhatsz néhány trükköt ennek a programnak a használatáról.
    Itt van egy leírás, hogy hogyan indítsd el a CMU rendszert a gépeden.", - "t2": "Technikai rész", - "msg2": "Ez az app Electron-nal and AngularJS-szel készült" - }, - { - "id": 6, - "title": "Segítség & Beállítások", - "msg": "

    Súgó:

    \n
    Hogyan kell a programot használni:

    Ha hibába futsz, 
    vagy elakadsz akkor:

    Vagy:

    Szereted ezt az app-ot? Adakozással, mutatsd ki, hogy mennyire!:


    ", - "t2": "", - "msg2": "


    " - } - ], - "FAQs": { - "title": "GYIK", - "msg": "Gyakran ismételt kérdések: ", - "q1": "Kompatibilis az AIO az én firmware verziómmal?", - "a1": "A kompatibilis firmware (FW) verziók listája megtalálható a 'Tweaking > kompatibilis firmware verziók' részban, balra ettől az ablaktól. MZD-AIO-TI kiolvassa a telepítés előtt a FW verziót és jelzi, ha nem kompatibilis (vagy még nem lett tesztelve) és a biztonság kedvéért megszakítja a telepítést.", - "q2": "Mennyi ideig tart, míg elindul a telepítés?", - "a2": "Általában 30 mp és 2 perc között kezdődik a telepítés, de néha akár 10 perc is eltelhet a kezdésig.", - "q3": "Ha valami nem sikerül, hogyan tudom könnyébbe tenni, hogy segíteni tudj?", - "a3": "Telepítés/törlés alatt egy log fálj készül (AIO log.txt & MZD-AIO-TI info.txt) és néhány egyáb fájl kerül a pendrivra. Kérlek készíts egy ZIP fájlt (a teljes pendrive tartalmáról) és küldd el nekem vagy töltsd fel valahová (pl. google drive, stb.) és küldd el nekem a linket. VAGY töltsd le ezt a tweak-et, mely le fog másolni néhány fájl-t az MZD-ről és elküldi nekem.", - "q4": "Az AIO 1.x tweakeket le kell törölnöm, mielőtt újratelepítem őket?", - "a4": "Nem, az AIO-val bármelyik tweak-et telepítheted, anélkül, hogy előtte törölnéd az előzőt. MZD-AIO-TI 2.x ugyanazokat a tweak-eket használja, mint az AIO 1.x és ügyeltünk a kompatibilitásra.", - "q5": "Mennyi ideig tart a telepítés/törlés?", - "a5": "Akár 10 percbe is telhet, ha minden tweak ki lett választva (különösen,az egyéni színek és a traffipax patch-ekkel). a JCI mappa biztonsági mentése, szintén eltarthat 10 percig, tehát összesen akár 20 perc is lehet a teljes folyamat.", - "q6": "Mi van akkor, ha vissza akarom állítani a gyári helyzetbe a rendszeremet, de elfelejtettem, hogy mely tweak-eket telepítettem?", - "a6": "A tweak-ek törlése egy biztonságos folyamat, ha a program nem talál biztonsági mentést, akkor a pendrive-on található eredeti fájlokkal fogja átírni az amúgy még eredeti fájlokat az MZD-den. DE: NE CSINÁLD EZT ÚJ VAGY ISMERETLEN FW VERZIÓKKAL! Lsd: \"Visszaállítás\" menüpont.", - "q7": "Meg akarom változtatni a hangforrások sorrendjét, mit tegyek?", - "a7": "Írd át a: /jci/gui/apps/system/js/systemApp.js -ben a 624 - 637 sorokat

    * Ügyelj arra, hogy az utolsó sor ne pontra végződjön, különben megakad rendszered az indulásnál! *
    Dolgozom azon, hogy a tweak maga adjon lehetőséget a sorrend változtatására, anélkül, hogy bele kellene nyúlni a fájlba.", - "q8": "Az AIO-t tudom SD kártyáról is telepíteni?", - "a8": "Nem. Az SD kártya olvasó CSAK satnav térképek használatára való. Az autó USB portját kell használnod, tehát vagy pendrive-ról, vagy egy USB-s SD kártya olvasóról tudod elvégezni a telepítést.", - "q9": "Hogyan tudom újraindítani az MZD rendszert? ", - "a9": "Tartsd a NAV és MUTE gombokat 10 mp-ig nyomva.", - "q10": "Tudnál további tweak-eket írni?", - "a10": "Javítottam több létező tweak-en és a tweak.sh-n is, de van rendes munkám és a kezelői felület fejlesztése is sok időt vesz igénybe. DE vannak saját ötleteim is a jövőre és természetesen javaslatokat is szívesen fogadok, de nem ígérhetem a mihamarabbi teljesítést. Az App jobb alján megtalálhatod az elérhetőségeimet, azon keresztül tudsz üzenni nekem." - }, - "tourMsgs": [ - { - "id": 0, - "msg": "

    Üdvözlet a MZD-AIO-TI-ben!


    Mazda All In One Tweaks telepítő

    Egy telepítő és törlő program több mint 40 \"tweak\"-hez a Mazda MZD Infotainment rendszeréhez." - }, - { - "id": 1, - "msg": "Ezek a főbb tweak-ek. Itt kiválaszthatod telepítésüket vagy törlésüket." - }, - { - "id": 2, - "msg": "Itt találod a kiválasztott tweak-eket és egyéb beállításokat is itt tudsz elvégezni, valamint további információkat találszhatsz a súgóban az egyen pontokhoz, ha rájuk kattintasz." - }, - { - "id": 3, - "msg": "További beállítások, mint pl. JCI mappa biztonsági mentése vagy a Wifi bekapcsolása az Északamerikai verziókhoz." - }, - { - "id": 4, - "msg": "Ezeket a beállításokat lehet visszaállítani a gyári beállításokra, ha kiválasztod az alapértelmezett értékeket." - }, - { - "id": 5, - "msg": "A menük további súgó témákhoz ill. hasznos információkhoz és leírásokhoz tartalmaznak linkeket." - }, - { - "id": 6, - "msg": "Ha kiválasztottad minden szükséges tweak-et, kattints ide a kompilálás elindításához!" - }, - { - "id": 7, - "msg": "Másold a \"_copy_to_usb\" mappa teljes tartalmát egy üres, FAT32 formátumú pendrive-ra. Csatlakoztasd a pendrive-ot az autó USB portjához és a telepítő pár percen belül megkezdi a telepítést. Távolíts el minden egyéb dolgot az USB csatlakozókról, de a NAVIGÁCIÓ SD kártyája maradjon bedugva. Bluetooth és wifi kapcsolatok kikapcsolása is segít. A telepítés végeztél a rendszer automatikusan újraindul, ezután eltávolíthatod a pendrive-ot és élvezheted az új tweak-jeidet." - }, - { - "id": 8, - "msg": "További információk a MazdaTweaks.com!-on" - } - ], - "popupMsgs": [ - { - "id": 0, - "msg": "Kompilálás... Várj..." - }, - { - "id": 1, - "msg": "Tweak fájlok helye" - }, - { - "id": 2, - "msg": "(A jobb eredmény érdekében, formázott pendrive-ot használj)" - }, - { - "id": 3, - "msg": "Másolás a pendrive-ra" - }, - { - "id": 4, - "msg": "Még nem" - }, - { - "id": 5, - "msg": "Pendrive megnyitása" - }, - { - "id": 6, - "msg": "Talált pendrive-ok" - }, - { - "id": 7, - "msg": "Szeretnéd a fájlokat a pendrive-ra másolni?" - }, - { - "id": 8, - "msg": "Válassz egy pendrive-ot, amelyre a fájlok át lesznek másolva" - }, - { - "id": 9, - "msg": "Nem található pendrive. Másold a teljes tartalmat" - }, - { - "id": 10, - "msg": "egy üres, FAT32 formátumú pendrive-ra" - }, - { - "id": 11, - "msg": "Másolás a pendrive-ra" - }, - { - "id": 12, - "msg": "Kérlek várj..." - }, - { - "id": 13, - "msg": "Swapfájl kicsomagolása ide:" - }, - { - "id": 14, - "msg": "Ez eltart pár percig... légy türelemmel." - }, - { - "id": 15, - "msg": "Swapfile mérete: 1 GB." - }, - { - "id": 16, - "msg": "Amíg vársz, itt van pár információ" - }, - { - "id": 17, - "msg": "Újrakezdés" - }, - { - "id": 18, - "msg": "AIO Compile Log mutatása" - }, - { - "id": 19, - "msg": "Kilépés" - }, - { - "id": 20, - "msg": "Siker!" - }, - { - "id": 21, - "msg": "_copy_to_usb mappa törlése másolás után" - } - ], - "mainOps": { - "wifi": { - "id": 0, - "label": "Wifi bekapcsolása (É-Amerika)", - "safetylvl": "safe", - "toolTip": "
    WIFI
    Aktiválja a WIFI hozzáférést az Észak-Amerikai régiós firmware-ekben" - }, - "backup": { - "id": 1, - "label": "JCI mappa mentése", - "safetylvl": "safe", - "toolTip": "
    JCI mappa mentése
    JCI mappáról biztonsági mentés készítése, a tweak-ek telepítése előtt." - }, - "background": { - "id": 2, - "label": "Háttérkép", - "safetylvl": "safe", - "toolTip": "
    Háttér
    Változtasd meg az infotainment rendszer hátterét egy általad választottra. Támogatott kééprípusok: jpg, jpeg, and png (bármilyen méret). Figyelem: Ha egy kép lett kiválasztva, akkor át lesz méretezve 800px x 480px DE NEM LESZ LEVÁGVA és .png formátumba lesz konvertálba. Hogy visszállítsd az eredeti hátteret, válaszd az \"alapértelmezett háttér\" opciót." - }, - "colors": { - "id": 3, - "label": "Saját színek a hangrendszerhez (infotainment)", - "safetylvl": "safe", - "toolTip": "
    Saját színséma
    Változtasd meg az infotainment rendszer színsémáját pirosról (alapértelmezett) a további színek egyikére:
    • kék
    • zöld
    • narancssárga
    • pink
    • lila
    • ezüst
    • sárga
    • carOS
    ", - "toolTip2": "
    The Custom Theme Option:
    Use any theme designed for the MZD Infotainment System or easily apply your own Custom Made Theme.
  • To use any theme: download and unzip the theme
  • Import the config/jci/ folder from the theme into AIO.

  • NOTE: Using This Method Will Copy Only .png Files For Themes
    Using Your Own Custom Made Theme:
  • If no theme is chosen: a folder will be generated here: _copy_to_usb/config/color-schemes/theme/jci/
  • After compiling tweaks, copy your files into the generated jci folder in the same directory location of the images you want to replace.
    WARNING: WHEN USING THIS METHOD EVERYTHING IN THE JCI FOLDER WILL BE COPIED ONTO YOUR SYSTEM IN THE SAME LOCATION. USE RESPONSIBLY.
    ", - "img": "carOS.png" - }, - "sshbringback": { - "id": 4, - "label": "SSH_bringback telepítése (56.00.51x-as verzióhoz)", - "safetylvl": "safe", - "toolTip": "
    SSH_bringback
    **NEM LEHET TÖRÖLNO!** Az 56.00.511 FW verzióval a Mazda eltörölte az SSH hozzáférést. Az SSH_bringback telepítésével, ez újra elérhető lesz. Ez a twek csak akkor kerül telepítésre, ha az 56.00.511 FW verzió van telepítve, 56.00.230-asnál nem történik semmi." - }, - "sdcid": { - "id": 5, - "label": "SD CID", - "safetylvl": "safe", - "toolTip": "
    SD CID
    Kiolvassa a CID-t a navigációs SD kártyáról, ha elérhető." - }, - "backgroundrotator": { - "id": 6, - "label": "Háttérképek váltogatása", - "btntxt": "Képek összeillesztése", - "button": "Kattints ide, hogy összeilleszted a váltogtatnivaló képeket", - "safetylvl": "safe", - "toolTip": "
    Háttérképek váltogatása
    10 perces ciklusokban, változtatja percenként a háttérképet. Figyelem: Telepítés után bármikor kicserélheted az összeillesztett képeket, anélköl, hogy újra kéne telepíteni ezt a tweak-et. Töröld a tweak-et, hogy újra egy háttérképed legyen." - }, - "retain": { - "id": 7, - "label": "Biztonsági mentés megtartása", - "testlabel": "Test Backups", - "safetylvl": "safe", - "toolTip": "
    Copy Backups:

    Copy original backups of modified system files, for safe keeping.

    Test Backups:

    Some tweaks have before and after copys of the files modified during the instalation. If you like that kind of thing they will copied to your-usb/bakups/test/.

    " - }, - "mainmenu": { - "id": 8, - "label": "Main Menu Tweaks", - "safetylvl": "safe", - "toolTip": "
    Main Menu Tweaks

    • Alternative Main Menu Layouts
      • 'Star Points' Layout

      • 'Inverted' Layout

    • 3D Main Menu Label
    • Hide Main Menu Ellipse
    • Smaller Main Menu 'Coins'
    ", - "img": "Alt-layouts.jpg" - }, - "uistyle": { - "id": 9, - "label": "Text Colors", - "safetylvl": "safe", - "toolTip": "

    User Interface Text Style Tweaks

    Customize Your User Interface Style and Text Colors:
    • Song Title
    • Artist & Album
    • Radio Station
    • List Item & Disabled List Item
    • Text Shadow
    " - }, - "offscreenbg": { - "id": 10, - "label": "Off Screen Background", - "btntxt": "Off Screen Default", - "safetylvl": "safe", - "toolTip": "
    Off Screen Background.
    Background Image when \"Turn Display Off and Show Clock\" is chosen in the Settings menu. Also shown during system shutdown." - } - }, - "menu": { - "save": { - "menuId": "0", - "label": "Ment", - "toolTip": "A jelenlegi konfiguráció mentése." - }, - "load": { - "menuId": "1", - "label": "Töltés", - "toolTip": "Utolsó mentett konfiguráció betöltése" - }, - "tour": { - "menuId": "2", - "label": "Bevezetés", - "toolTip": "Bevezetés az MZD-AIO-TI-ba." - }, - "lastcompilelog": { - "menuId": "3", - "label": "Legújabb compile log", - "toolTip": "MZD_LOG" - }, - "installall": { - "menuId": "4", - "label": "Összes telepítése", - "toolTip": "Összes telepítése (kivéve Android Auto és castscreen)" - }, - "uninstallall": { - "menuId": "5", - "label": "Összes törlése", - "toolTip": "Összes tweak törlése" - }, - "resetoptions": { - "menuId": "6", - "label": "Alaphelyzeti beállítások", - "toolTip": "Kiválasztott beállítások törlése." - }, - "reloadapp": { - "menuId": "17", - "label": "App újratöltése", - "toolTip": "Töltsd újra az app-ot" - }, - "copytousb": { - "menuId": "8", - "label": "Másolás pendrive-ra", - "toolTip": "_copy_to_usb mappa megnyitása" - }, - "help": { - "menuId": "9", - "label": "Súgó", - "toolTip": "Kattints a tweak nevére a súgóhoz." - }, - "install": { - "menuId": "10", - "label": "Telepítés" - }, - "uninstall": { - "menuId": "11", - "label": "Törlés" - }, - "languages": { - "menuId": "12", - "label": "Nyelverk" - }, - "close": { - "menuId": "13", - "label": "Bezár" - }, - "clickforhelp": { - "menuId": "14", - "label": "Kattints a súgó megnyitásához" - }, - "tweakstoinstall": { - "menuId": "15", - "label": "Telepítendő tweak-ek" - }, - "file": { - "menuId": "18", - "label": "Fájl" - }, - "window": { - "menuId": "19", - "label": "Ablak" - }, - "download": { - "menuId": "20", - "label": "Letöltés" - }, - "fullscreen": { - "menuId": "20", - "label": "Teljes képernyő" - }, - "translator": { - "menuId": "21", - "label": "Fordítás" - }, - "dlcolors": { - "menuId": "22", - "label": "Töltsd le a színséma fájlokat" - }, - "dlspeedcam": { - "menuId": "22", - "label": "Töltsd le a traffipax patch-hez a fájlokat" - }, - "helppanel": { - "menuId": "23", - "label": "Súgó panel" - }, - "changelog": { - "menuId": "24", - "label": "Változások" - }, - "start": { - "menuId": "16", - "label": "Kompilálás indítása", - "toolTip": "

    Kész?

    Indítsd el a kompilálást!" - }, - "centerwindow": { - "menuId": "", - "label": "Ablak központosítása", - "toolTip": "" - } - }, - "imgOps": [ - { - "id": 0, - "label": "Join multiple images for your infotainment background" - }, - { - "id": 1, - "label": "Select up to 50, 480px X 800px Images (Each Image will be resized to 480x800). Background Rotator Will Show Each Background For X Seconds (Max 300 Seconds = 5 Minutes per img)." - }, - { - "id": 2, - "label": "Húzd a képeket, hogy változtass a sorrenden." - }, - { - "id": 3, - "label": "kiválasztott képek" - }, - { - "id": 4, - "label": "Válassz 10 db képet (Mindegyik magassága: 480px, szélessége: 800px le) vagy " - }, - { - "id": 5, - "label": "Használd a saját már összeillesztett képedet (nincs átméretezés)" - }, - { - "id": 6, - "label": "Ez a kép lesz az infotainment rendszer új háttere." - }, - { - "id": 7, - "label": "Kép mentése másként" - }, - { - "id": 8, - "label": "Újabb készítése" - }, - { - "id": 9, - "label": "Jobb kattintás > \"Kép mentése\" lementi a background.png egy másolatát a \"Letöltések\" mappába." - }, - { - "id": 10, - "label": "perc" - }, - { - "id": 11, - "label": "Képek kiválasztása" - }, - { - "id": 12, - "label": "Képek" - } - ], - "translatorWindow": [ - { - "label": "Fordító" - }, - { - "label": "Alaphelyzet visszaállítása" - }, - { - "label": "Nyelv neve (így lesz elmentve:" - }, - { - "label": "a \"Dokumentumok\" mappádba" - }, - { - "label": "Küldd el a fordítást ide:" - }, - { - "label": "Pull Request" - }, - { - "label": "töltés" - }, - { - "label": "A \"Dokumentumok\" mappába mentce" - }, - { - "label": "Mutasd az explorer-ben" - }, - { - "label": "Fálj betöltése" - }, - { - "label": "Ez a rész a fordítás megkönnyítésére lett létrehozva." - }, - { - "label": "Válaszd ki a fordítási fájlt" - }, - { - "label": "Írd be a fordított nyelv nevét" - }, - { - "label": "VISSZA" - }, - { - "label": "Mentés (Dokumentumok közé)." - }, - { - "label": "Auto-mentés" - } - ], - "colors": { - "red": { - "id": 0, - "label": "Piros (Alapértelmezett)" - }, - "blue": { - "id": 1, - "label": "Kék" - }, - "green": { - "id": 2, - "label": "Zöld" - }, - "silver": { - "id": 3, - "label": "Ezüst" - }, - "pink": { - "id": 4, - "label": "Pink" - }, - "purple": { - "id": 5, - "label": "Lila" - }, - "orange": { - "id": 6, - "label": "Narancssárga" - }, - "yellow": { - "id": 7, - "label": "Sárga" - }, - "smoothred": { - "id": 9, - "label": "Smooth Red" - }, - "caros": { - "id": 8, - "label": "CarOS" - }, - "stormtroopers": { - "id": 10, - "label": "Storm Troopers" - }, - "poker": { - "id": 11, - "label": "Poker" - }, - "mazdalogos": { - "id": 12, - "label": "Mazda Logos" - }, - "floating": { - "id": 13, - "label": "Floating Logo" - }, - "mazda": { - "id": 14, - "label": "Mazda Logos" - }, - "custom": { - "id": 15, - "label": "Custom Theme" - } - }, - "statusbar": { - "main": { - "id": 0, - "label": "Remove Statusbar Background" - }, - "opacity": { - "id": 1, - "label": "Statusbar Opacity" - }, - "app": { - "id": 2, - "label": "App Title" - }, - "clock": { - "id": 3, - "label": "Clock" - }, - "notif": { - "id": 4, - "label": "Status Notifications" - }, - "d2sbinst": { - "id": 5, - "label": "Date To Statusbar Mod" - }, - "d2sbuninst": { - "id": 6, - "label": "Remove Date To Statusbar Mod" - } - }, - "uistyle": { - "body": { - "id": 0, - "label": "Body Text (Audio Artist & Album)" - }, - "listitem": { - "id": 1, - "label": "List Item" - }, - "listitemdisabled": { - "id": 2, - "label": "Disabled List Item" - }, - "title": { - "id": 3, - "label": "Song Title" - }, - "radio": { - "id": 4, - "label": "Radio Station" - }, - "main3d": { - "id": 5, - "label": "3D Main Menu Text" - }, - "ellipse": { - "id": 6, - "label": "Remove Ellipse" - }, - "altlayout": { - "id": 7, - "label": "Alternative Layout" - }, - "shadow": { - "id": 8, - "label": "Text Shadow" - }, - "altulayout": { - "id": 9, - "label": "'Inverted' Layout" - }, - "minicoins": { - "id": 10, - "label": "Smaller 'Coins'" - } - }, - "speedcamOps": [ - { - "id": 0, - "label": "Európa mobil traffipaxokkal" - }, - { - "id": 1, - "label": "Európa mobil traffipaxok nélkül" - }, - { - "id": 2, - "label": "Németország mobil traffipaxokkal" - }, - { - "id": 3, - "label": "Németország mobil traffipaxok nélkül" - }, - { - "id": 4, - "label": "Törökország" - }, - { - "id": 5, - "label": "Saját speedcam.txt fálj használata" - } - ], - "disclaimOps": [ - { - "id": 0, - "label": "Teljes eltávolítás" - }, - { - "id": 1, - "label": "Várakozási idő 0.5 mp-re csökkentése" - } - ], - "fuelOps": [ - { - "id": 0, - "label": "Km/L" - }, - { - "id": 1, - "label": "MPG" - } - ], - "d2sbOps": [ - { - "id": 0, - "label": "V1.0" - }, - { - "id": 1, - "label": "v3.3 (Date Localized)" - }, - { - "id": 2, - "label": "V3.3 (dd.mm.)" - }, - { - "id": 3, - "label": "V3.3 (mm/dd)" - } - ], - "speedoOps": { - "lang": { - "en": { - "id": 0, - "label": "Angol" - }, - "de": { - "id": 1, - "label": "Német" - }, - "sp": { - "id": 2, - "label": "Spanyol" - }, - "pl": { - "id": 3, - "label": "Lengyel" - }, - "sl": { - "id": 4, - "label": "Szlovák" - }, - "tk": { - "id": 5, - "label": "Török" - }, - "fr": { - "id": 6, - "label": "Francia" - }, - "it": { - "id": 7, - "label": "Italian" - } - }, - "xph": { - "mph": { - "id": 10, - "label": "MPH" - }, - "kmh": { - "id": 11, - "label": "KM/H" - } - }, - "sml": { - "gps": { - "id": 20, - "label": "GPS értékei" - }, - "car": { - "id": 21, - "label": "Autó értékei" - }, - "none": { - "id": 22, - "label": "Ne aktiválja" - } - }, - "bg": { - "ind": { - "id": 30, - "label": "Egyéni háttér" - }, - "orig": { - "id": 31, - "label": "eredeti háttér" - } - }, - "opac": { - "id": 40, - "val": "0", - "label": "Fekete háttér átütése? (Az eredeti háttér eltüntetésére) 0.0 (teljesen átlátszó) - 1.0 (teljesen fekete)" - } - }, - "tweakOps": [ - { - "id": 1, - "OpName": "Érintőképernyő menet közben", - "INST": "Lehetővé teszi az érintőképernyő használatát menet közben is", - "DEINST": "Deaktiválja menet közben az érintőképernyőt", - "toolTip": "
    Érintőképernyő
    Lehetővé teszi az érintőképernyő használatát menet közben is.
    Fix Cluster Compass: Some things will be disabled while driving but the touchscreen itself and the cluster compass will work", - "img": "", - "safetylvl": "safe", - "extraOps": true, - "advancedOp": false - }, - { - "id": 2, - "OpName": "Biztonsági figyelmeztetés eltávolítása", - "INST": "Biztonsági figyelmeztetés teljes eltávolítása", - "DEINST": "Biztonsági figyelmeztetés visszaállítása 3,5mp-re", - "toolTip": "
    Biztonsági figyelmeztetés eltávolítása
    Csökkenti a biztonsági figyelmeztetés mutatásának idejét 3.5 mp-ről 0.5 mp-re, vagy teljesen el is törli azt.", - "img": "", - "safetylvl": "safe", - "extraOps": true, - "advancedOp": false - }, - { - "id": 3, - "OpName": "Tolatókamera biztonsági figyelmeztetés", - "INST": "Tolatókamera biztonsági figyelmeztetésének eltávolítása", - "DEINST": "Tolatókamera biztonsági figyelmeztetésének visszaállítása", - "toolTip": "
    Tolatókamera biztonsági figyelmeztetés
    NA tolatókamera biztonsági figyelmeztetésének kikapcsolása.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 4, - "OpName": "Félig átlátszó parkolószenzor grafikák", - "INST": "Félig átlátszó parkolószenzor grafikák telepítése", - "DEINST": "Félig átlátszó parkolószenzor grafikák visszaállítása", - "toolTip": "
    Félig átlátszó parkolószenzor grafikák
    Félig átlátszó parkolószenzor grafikák. A tolatókamera bekapcsolásakor megjelenik egy felülnézeti kép a jobb felső sarokban.#Ezek a grafikák lesznek félig áttetszőek, ha telepíted ezt a tweaket.", - "img": "semi-transparent_parking-sensors.jpg", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 5, - "OpName": "Főmenü loopolása", - "INST": "main_menu_loop telepítése", - "DEINST": "main_menu_loop visszaállítása", - "toolTip": "
    Főmenü loopolása
    Loop a főmenüben
    Balról jobbra lehet ugrani ill. vissza.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 6, - "OpName": "Javított lista loopolás", - "INST": "improved_list_loop telepítése", - "DEINST": "improved_list_loop visszaállítása", - "toolTip": "
    Javított lista loopolás
    Loop minden listához és almenühöz (zene, kapcsolatok, stb.).
    A legfelső pozícióból a legalsóba lehet ugrani, ill. fordítva.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 7, - "OpName": "Rövid késleltetés mod", - "INST": "shorter_delay_mod telepítése", - "DEINST": "shorter_delay_mod visszaállítása", - "toolTip": "
    Rövid késleltetés mod.
    Csökkenti a várakozási időt az oldalankénti lapozásnál 1.5 mp-ről auf 0.3 mp-re.
    A javított lista loopolás tweak törlése ezt a tweak-et is eltávolítja.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 8, - "OpName": "Zeneszámok név szerinti rendezése és FLAC támogatás", - "INST": "media_order patch és FLAC támogatás telepítése", - "DEINST": "media_order patch és FLAC támogatás visszaállítása", - "toolTip": "
    Zeneszámok név szerinti rendezése és FLAC támogatás
    Zenék név szerinti rendezése és nem dátum szerinti rendezése. FLAC formátum támogatása.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 9, - "OpName": "Hangforrások listájának rendezése", - "INST": "Hangforrások listájának megváltoztatása", - "DEINST": "Hangforrások eredeti listájának visszaállítása", - "toolTip": "
    Hangforrások listájának rendezése
    THangforrás lista rendezése:
  • FMRadio
  • DAB
  • USB_A
  • USB_B
  • BT_audio
  • CD
  • SatRadio
  • AhaRadio
  • Pandora
  • Stitcher
  • AuxIn
  • AMradio
  • DVD
  • TV
  • ", - "img": "", - "safetylvl": "warning", - "extraOps": false, - "advancedOp": false - }, - { - "id": 10, - "OpName": "Zenelejátszás megállítása némításkor", - "INST": "pause_on_mute telepítése", - "DEINST": "pause_on_mute visszaállítása", - "toolTip": "
    Zenelejátszás megállítása némításkor
    Elnémításkor (hangerőgomb megnyomásával) a lejátszott médiumok is szünetelnek.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 11, - "OpName": "Automatikus üzenetaláírás törlése", - "INST": "Automatikus üzenetaláírás törlése patch", - "DEINST": "Automatikus üzenetaláírás visszaállítása", - "toolTip": "
    Automatikus üzenetaláírás törlése
    Törli a 'Mazda Quick Text Systemről küldve' sort az üzenetből.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 12, - "OpName": "1 mp diagnózis menü elérés", - "INST": " 1 mp diagnózis menü elérés telepítése", - "DEINST": " 1 mp diagnózis menü elérés törlése", - "toolTip": "
    1 mp diagnózis menü elérés
    Biztosítja, hogy a diagnózis menü az órára való 1 mp-es nyomás után elérhető legyen a képernyő beállítások menüben.", - "img": "", - "safetylvl": "warning", - "extraOps": false, - "advancedOp": false - }, - { - "id": 13, - "OpName": "Boot animáció", - "INST": "Boot animáció törlése", - "DEINST": "Boot animáció visszaállítása", - "toolTip": "
    Boot animáció
    A boot animáció, amelyik a Mazda logó megjelenése után a főmenübe vezet át deaktiválódik.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 14, - "OpName": "Nagyobb album fedőképek", - "INST": "Nagyobb album fedőképek törlése", - "DEINST": "Nagyobb album fedőképek visszaállítása", - "toolTip": "
    Nagyobb album fedőképek
    Nagyobb album fedőképek mutatása.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 15, - "OpName": "Háttérkép nélküli gombok", - "INST": "Háttérkép nélküli gombok telepítése", - "DEINST": "Háttérkép nélküli gombok visszaállítása", - "toolTip": "
    Háttérkép nélküli gombok
    Átlátszóvá teszi a gombok hátterét.", - "img": "NoButtonBackground.jpg", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 16, - "OpName": "Üres album fedőképkeretek megváltoztatása", - "INST": "Üres album fedőképkeretek megváltoztatása", - "DEINST": "Üres album fedőképkeretek visszaállítása", - "toolTip": "
    Üres album fedőképkeretek megváltoztatása
    Az üres albumfedőkép, mely akkor jelenik meg ha nincs az előadóhoz tartozó kép a Gracenote adatbankban, eltűnik. Helyette egy rádió képe lesz látható, akkor is ha nincs fedőkép MP3 \"tag\"-ként. Támogatott fájl formátumok: jpg, jpeg és png (bármely méret). Figyelem: A választott kép át lesz konvertálva 146px x 146px-es méretre, DE NEM LESZ LEVÁGVA, és .png formátumba.", - "img": "", - "safetylvl": "safe", - "extraOps": true, - "advancedOp": false - }, - { - "id": 17, - "OpName": "Videólejátszó", - "INST": "Videólejátszó telepítése", - "DEINST": "Videólejátszó törlése", - "toolTip": "
    Videólejátszó
    Videólejátszó app hozzáadása a főmenühöz.", - "img": "", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 18, - "OpName": "Swapfájl", - "INST": "Media player v2 swapfájl létrehozása", - "DEINST": "Media player v2 swapfájl törlése", - "toolTip": "
    Swapfájl
    Telepítsük a swap fájlt egy olyan pendrivera, amely a kocsiban marad... A telepítő fájlok törlődnek ezután nem szabad a pendrive-ot menet közben leválasztani, mert a rendszer futásához szükséges adatok vannak rajta és tárhelyként is van használva... A pendrive-ot a jövőben csak akkor csatlakoztasd le, ha az MZD ki van kapcsolva.", - "img": "", - "safetylvl": "warning", - "extraOps": true, - "advancedOp": false - }, - { - "id": 19, - "OpName": "Speedometer", - "INST": "Speedometer telepítése", - "DEINST": "Speedometer törlése", - "toolTip": "
    Speedometer íránytűvel App-ként mutatása az alkalmazás menüben
    • a sebességmérő alatt km/h vagy mph látszik a beállítások függvényében
    • Max. mutatható sebesség: 240 km/h
    • Fogyasztási adatoks
    • Optimalizált grafikus elemek új sebességmérővel
    • Kis sebességmérő tű, mely a legnagyobb sebességet mutatja az analóg skálán
    • A skála különböző hosszúságú és világosságú az 5, 10 ill. 20 km/h-s felbontás függvényében
    • Jobboldali táblázat német és angol szövegekre lett optimalizálva
    • Minden számnak van árnyéka a jobb olvashatóság érdekében
    • Haladási iránytól függő iránytű a sebesség körül
    • Animált felület a fejlécben GPS által mért sebességgel és haladási iránnyal, mely egy érintéssel az órára bármelyik menüben előhozható vagy elrejthető
    • Szélességi és hosszúsági fokok a jobboldali táblázatban
    • Ha a navigáció vagy a tolatókamera aktiválódik, automatikusan elindul

    A kis sebességmérő fejlécben való mutatása a \"dátum a fejlécben\" mod V2.2 igényli, ezért ez automatikusan kiválasztásra kerül, ha nem történt még meg..", - "img": "mzd_SpeedoCompass.gif", - "safetylvl": "safe", - "extraOps": true, - "advancedOp": false - }, - { - "id": 20, - "OpName": "Statusbar Tweaks", - "INST": "Install Statusbar Tweaks", - "DEINST": "Remove Statusbar Tweaks", - "toolTip": "
    Statusbar Mods
    Add some Color to your statusbar text.

    Change Colors For:


    App Name: Title of the app or media source.

    Clock: This one is pretty self explanatory.

    Status Notification: Navigation notifications

    Remove Statusbar Background Image And
    Adjust Statusbar Opacity (From 0-1: 0 = transparent, 1 = Black)

    Safe for all FW Versions
    Date In Status Bar Mod.
    Permanently visible date + icons by the clock, even if system messages are displayed.", - "img": "mzd_datum_icons_all.jpg", - "safetylvl": "safe", - "extraOps": true, - "advancedOp": false - }, - { - "id": 22, - "OpName": "Fogyasztás Tweak", - "INST": "Fogyasztás Tweak telepítése", - "DEINST": "Fogyasztás Tweak visszaállítása", - "toolTip": "
    Fogyasztás Tweak
    Fogyasztás mutatása KM/L-ben (vagy MPG-ben)", - "img": "FuelConsumptionTweak.jpg", - "safetylvl": "safe", - "extraOps": false, - "advancedOp": false - }, - { - "id": 23, - "OpName": "Traffipax patch", - "INST": " Traffipax patch telepítése", - "DEINST": " Traffipax patch visszaállítása", - "toolTip": "
    Traffipax patch
    A navigáció patchelése, hogy külsős kamera és traffipax adatbankok is használhatóak legyenek... Lehetőség nyílik a 'speedcam.txt' fájl SD kártyára másolására, amely így importálásra kerül.", - "img": "", - "safetylvl": "warning", - "extraOps": true, - "advancedOp": false - }, - { - "id": 24, - "OpName": "Castscreen vevő", - "INST": "Castscreen vevő telepítése", - "DEINST": "Castscreen vevő visszaállítása", - "toolTip": "
    Castscreen vevő
    Telepítés után a mobiltelefon képernyőjét duplikálni lehet (mirroring) az MZD képernyőjére.
    • Az androidos CastScreen App (castscreen-1.0.apk) telepítése szükséges. Ez megtalálható a 'config' mappában, ha a Tweak ki lett választva,
    • Csatlakoztasd a telefont egy USB kábellel az MZD-hez,
    • Indítsd el az applikációt, beállítások: H264, 800x480 @ 160, 1 Mbps, 127.0.0.1 és \"input receiver\"-t kiválasztani, jobboldalt fent a 'Start' gombot megnyomni.
    .", - "img": "", - "safetylvl": "warning", - "extraOps": true, - "advancedOp": false - }, - { - "id": 25, - "OpName": "Android Auto fejegység applikáció", - "INST": "Android Auto fejegység applikáció telepítése", - "DEINST": "Android Auto fejegység applikáció visszaállítása", - "toolTip": "
    Android Auto fejegység applikáció. Android Auto (AA) az infotainment rendszerhez.

    1. Az Android Applikáció telepítése a Google Play Store-ból::HERE.
    2. Csatlakoztasd a telefont USB-n és bluetooth-on keresztül az Infotainment rendszerhez.
    3. Manuálisan a bluetooth-ot, mint audióbemenetet kiválasztani.
    4. Android Auto indítása az alkalmazásmenüből a fejegységen.
    5. Egy fekete képernyő jelenik meg köszöntemondással a fejlesztőknek, utána automatikusan átáll bluetooth kapcsolatra.
    6. Android Auto elindul. Ha mégsem, akkor húzd ki az USB kábeld és dugd be újra (vagy győződj meg a megfelelő telepítésről).
    7. Két lehetőség van az AA bezárására - Húzdd ki az USB kábelt vagy használd a képernyő menüben a 'Vissza a Mazda Connect-be' legalul a speedo ikonnál...
    8. Kihúzás után megmarad a fekete képernyü. Nyomd meg a \"Home\" gombot a kezelőegységen. Azért kell ezt tenni mert a JavaScript-es dupla kattintás nem működik..
    **Ami még nem működik:**
    1. Tolatókamera képe fekete.
    2. hangvezérlés
    3. Multitouch
    4. Google Maps mindig éjszakai módban van.

    Ahhoz, hogy az Android Auto kattintási eventeket tudjon kezelni, változtass az tweaks.sh-ban, keresés és felülírás a következő sorban: \"button_patch=no\" ==> \"button_patch=yes\" macskakörmök nélkül). Ez az AA rizikós része, bár állítólag már javítva van. Amint eléggé tesztelve lesz és biztonságosnak tekinthető a használata, bele fog kerülni a tweak-ek listájába.", - "img": "AndroidAuto.jpg", - "safetylvl": "development", - "extraOps": true, - "advancedOp": true - } - ] -} diff --git a/app/main.js b/app/main.js index 27d4fec..d7c3d64 100644 --- a/app/main.js +++ b/app/main.js @@ -9,7 +9,7 @@ ** ** ** ************************************************************************** ** \* ************************************************************************** */ -/* jshint esversion:6, -W033, -W117, -W097, -W116 */ +/* jshint esversion:8, -W033, -W117, -W097, -W116 */ 'use strict' const electron = require('electron') const app = electron.app @@ -47,10 +47,11 @@ require('./menus/shortcuts.js') require('./lib/log')(pjson.productName || 'MZD-AIO-TI') var hasColorFiles = fs.existsSync(`${app.getPath('userData')}/color-schemes/`) var hasSpeedCamFiles = fs.existsSync(`${app.getPath('userData')}/speedcam-patch/`) -var iconLoc = path.join(app.getAppPath(), "/icon.icns") -var favicon = "./app/icon.icns" +var iconLoc = path.join(app.getAppPath(), '/icon.icns') +var favicon = './app/icon.icns' +process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true if (process.platform === 'win32') { - iconLoc = path.join(app.getAppPath(), "icon.ico") + iconLoc = path.join(app.getAppPath(), 'icon.ico') favicon = './app/icon.ico' } let nimage = nativeImage.createFromPath(iconLoc) @@ -80,7 +81,7 @@ if (isDev) { console.info('Running in development') app.setPath('home', path.resolve(`${__dirname}`)) console.log(`Home: ${app.getPath('home')}`) - //console.debug(JSON.stringify(pjson)) + // console.debug(JSON.stringify(pjson)) console.debug(JSON.stringify(persistantData.store)) console.debug(JSON.stringify(pjson.config)) } else { @@ -105,12 +106,12 @@ let tray = null let imageJoin = null app.setName(pjson.productName || 'MZD-AIO-TI') -function initialize() { +function initialize () { if (!persistantData.has('copyFolderLocation')) { persistantData.set('copyFolderLocation', app.getPath('desktop')) } - function onClosed() { + function onClosed () { // Dereference used windows downloadwin = null mailform = null @@ -120,7 +121,7 @@ function initialize() { app.quit() } - function createMainWindow() { + function createMainWindow () { let mainWindowState = windowStateKeeper({ defaultWidth: 1280, defaultHeight: 800 @@ -138,6 +139,7 @@ function initialize() { 'icon': favicon, 'webPreferences': { 'nodeIntegration': pjson.config.nodeIntegration || true, // Disabling node integration allows to use libraries such as jQuery/React, etc + 'nodeIntegrationInSubFrames': false, 'preload': path.resolve(path.join(__dirname, 'preload.js')) } }) @@ -145,7 +147,7 @@ function initialize() { // Remove file:// if you need to load http URLs win.loadURL(`file://${__dirname}/${pjson.config.url}`, {}) win.on('closed', onClosed) - win.on('unresponsive', function() { + win.on('unresponsive', function () { var unresponsiveClose = dialog.showMessageBox({ type: 'warning', title: 'Unresponsive', @@ -187,7 +189,7 @@ function initialize() { win.focus() }) - function setCopyLoc(loc) { + function setCopyLoc (loc) { persistantData.set('copyFolderLocation', app.getPath(loc)) win.webContents.send('set-copy-loc', app.getPath(loc)) console.log(`Copy_to_usb: ${persistantData.get('copyFolderLocation')}`) @@ -196,33 +198,33 @@ function initialize() { if (process.platform === 'win32') { tray = new Tray(nimage) var template = [{ - label: 'Location of _copy_to_usb', - submenu: [ - { label: 'Desktop', id: 'desktop', type: 'radio', checked: persistantData.get('copyFolderLocation').includes('Desktop'), click: function(menuItem, browserWindow, event) { setCopyLoc('desktop') } }, - { label: 'Downloads', id: 'downloads', type: 'radio', checked: persistantData.get('copyFolderLocation').includes('Downloads'), click: function(menuItem, browserWindow, event) { setCopyLoc('downloads') } }, - { label: 'Documents', id: 'documents', type: 'radio', checked: persistantData.get('copyFolderLocation').includes('Documents'), click: function(menuItem, browserWindow, event) { setCopyLoc('documents') } } - ] - }, + label: 'Location of _copy_to_usb', + submenu: [ + { label: 'Desktop', id: 'desktop', type: 'radio', checked: persistantData.get('copyFolderLocation').includes('Desktop'), click: function (menuItem, browserWindow, event) { setCopyLoc('desktop') } }, + { label: 'Downloads', id: 'downloads', type: 'radio', checked: persistantData.get('copyFolderLocation').includes('Downloads'), click: function (menuItem, browserWindow, event) { setCopyLoc('downloads') } }, + { label: 'Documents', id: 'documents', type: 'radio', checked: persistantData.get('copyFolderLocation').includes('Documents'), click: function (menuItem, browserWindow, event) { setCopyLoc('documents') } } + ] + }, { type: 'separator' }, - { label: 'Open _copy_to_usb Folder', click: function() { win.webContents.send('open-copy-folder') } }, - { - label: 'Delete _copy_to_usb Folder', - type: 'normal', - click: function(menuItem, browserWindow, event) { - rimraf(path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb')), function(e) { - if (e) { - console.error(e.message) - dialog.showErrorBox(`Error Deleting ${path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb'))}`, `${e.message}`) - } else { - console.log(`Deleted ${path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb'))}`) - win.webContents.send('snackbar-msg', `Deleted ${path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb'))}`) - } - }) - } - }, + { label: 'Open _copy_to_usb Folder', click: function () { win.webContents.send('open-copy-folder') } }, + { + label: 'Delete _copy_to_usb Folder', + type: 'normal', + click: function (menuItem, browserWindow, event) { + rimraf(path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb')), function (e) { + if (e) { + console.error(e.message) + dialog.showErrorBox(`Error Deleting ${path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb'))}`, `${e.message}`) + } else { + console.log(`Deleted ${path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb'))}`) + win.webContents.send('snackbar-msg', `Deleted ${path.normalize(path.join(persistantData.get('copyFolderLocation'), '_copy_to_usb'))}`) + } + }) + } + }, { type: 'separator' }, - { label: 'Fullscreen', click: function() { win.setFullScreen(!win.isFullScreen()) } }, - { label: 'Close', role: 'close', click: function() { win.close() } } + { label: 'Fullscreen', click: function () { win.setFullScreen(!win.isFullScreen()) } }, + { label: 'Close', role: 'close', click: function () { win.close() } } ] var trayMenu = Menu.buildFromTemplate(template) tray.setToolTip('MZD-AIO-TI') @@ -231,14 +233,7 @@ function initialize() { win.isVisible() ? win.hide() : win.show() }) tray.on('double-click', () => { - win.show() - win.setFullScreen(!win.isFullScreen()) - }) - win.on('show', () => { - tray.setHighlightMode('always') - }) - win.on('hide', () => { - tray.setHighlightMode('never') + win.setFullScreen(win.isVisible()) }) } // if (isDev) { @@ -304,6 +299,20 @@ function initialize() { // save some persistant data persistantData.set('visits', v) }) + app.on('web-contents-created', (event, contents) => { + contents.on('new-window', (event, url, frameName, disposition, options) => { + // event.preventDefault() + if(options.webPreferences) { + options.webPreferences.nodeIntegration = false + //console.dir(options.webPreferences) + //console.dir(event) + //console.log(url) + //console.log(disposition) + //console.log(frameName) + //console.dir(options) + } + }) + }) ipc.on('reset-window-size', () => { mainWindow.setSize(1280, 800) mainWindow.center() @@ -361,9 +370,9 @@ function initialize() { // Make this app a single instance app. // The main window will be restored and focused instead of a second window // opened when a person attempts to launch a second instance. -function makeSingleInstance(lock) { +function makeSingleInstance (lock) { if (!lock) { - console.warn("Single Instance App - Quit") + console.warn('Single Instance App - Quit') app.quit() } else { app.on('second-instance', (event, commandLine, workingDirectory) => { @@ -375,53 +384,49 @@ function makeSingleInstance(lock) { } } -function getUSBDrives() { +async function getUSBDrives () { var disks = [] + var dsklst = await drivelist.list() var aioInfo var aioBkups = [] var aioJSON = null - drivelist.list((error, dsklst) => { - if (error) { - console.error(error) - return - } else if (typeof dsklst !== "undefined") { - dsklst.forEach((drive) => { - var sizeGB = Math.round(drive.size / 100000000) / 10 - if (!drive.system && drive.mountpoints[0]) { - console.log(`Raw: ${drive.raw}\n Mountpoint: ${drive.mountpoints[0].path}\n Description: ${drive.description}\n Size: ${sizeGB}GB`) - disks.push({ 'desc': drive.description, 'mp': drive.mountpoints[0].path }) - } - }) - if (typeof disks !== "undefined" && disks.length) { - disks.forEach((drive) => { - try { - if (fs.existsSync(`${drive.mp}/AIO_info.json`)) { - console.log(`Found AIO_info.json on USB Drive - ${drive.mp} ${drive.desc}`) - aioJSON = fs.readFileSync(`${drive.mp}/AIO_info.json`) - } - } catch (e) { - console.dir(e) - dialog.showErrorBox("USB DRIVE ERROR", `Error reading from ${drive.mp} ${drive.desc}: ${e.toString()}. Data on the device might be corrupt.`) - } - }) + if (typeof dsklst !== 'undefined') { + dsklst.forEach((drive) => { + var sizeGB = Math.round(drive.size / 100000000) / 10 + if (!drive.system && drive.mountpoints[0]) { + console.log(`Raw: ${drive.raw}\n Mountpoint: ${drive.mountpoints[0].path}\n Description: ${drive.description}\n Size: ${sizeGB}GB`) + disks.push({ 'desc': drive.description, 'mp': drive.mountpoints[0].path }) } - if (aioJSON) { + }) + if (typeof disks !== 'undefined' && disks.length) { + disks.forEach((drive) => { try { - aioInfo = JSON.parse(aioJSON) - aioBkups = aioInfo.Backups - console.log(aioBkups) - /* console.log(`FW_VER: ${aioInfo.info.CMU_SW_VER}`) - console.log(`AIO_VER: ${aioInfo.info.AIO_VER}`) */ - persistantData.set('FW', aioInfo.info.CMU_SW_VER) - persistantData.set('last_aio', aioInfo.info.AIO_VER) - //_.pullAll(aioBkups) - if (mainWindow) { - mainWindow.webContents.send('aio-info') + if (fs.existsSync(`${drive.mp}/AIO_info.json`)) { + console.log(`Found AIO_info.json on USB Drive - ${drive.mp} ${drive.desc}`) + aioJSON = fs.readFileSync(`${drive.mp}/AIO_info.json`) } - } catch (e) { console.error(e.toString()) } - } + } catch (e) { + console.dir(e) + dialog.showErrorBox('USB DRIVE ERROR', `Error reading from ${drive.mp} ${drive.desc}: ${e.toString()}. Data on the device might be corrupt.`) + } + }) } - }) + if (aioJSON) { + try { + aioInfo = JSON.parse(aioJSON) + aioBkups = aioInfo.Backups + console.log(aioBkups) + /* console.log(`FW_VER: ${aioInfo.info.CMU_SW_VER}`) + console.log(`AIO_VER: ${aioInfo.info.AIO_VER}`) */ + persistantData.set('FW', aioInfo.info.CMU_SW_VER) + persistantData.set('last_aio', aioInfo.info.AIO_VER) + // _.pullAll(aioBkups) + if (mainWindow) { + mainWindow.webContents.send('aio-info') + } + } catch (e) { console.error(e.toString()) } + } + } } /* function createMenu () { return Menu.buildFromTemplate(require('./lib/menu')) @@ -429,15 +434,15 @@ function getUSBDrives() { // Manage Squirrel startup event (Windows) // require('./lib/auto-update/startup')(initialize) -ipc.on('open-file-bg', function(event) { +ipc.on('open-file-bg', function (event) { openBGFolder(backgroundDir, event) }) -ipc.on('open-file-default', function(event) { +ipc.on('open-file-default', function (event) { event.sender.send('selected-bg', defaultDir + 'default.png') // openBGFolder(defaultDir, event) }) -function openBGFolder(path, event) { +function openBGFolder (path, event) { dialog.showOpenDialog({ title: 'MZD-AIO-TI | Background Image Will Be Resized To: 800 px X 480 px and converted to png format.', properties: ['openFile'], @@ -445,11 +450,11 @@ function openBGFolder(path, event) { filters: [ { name: 'Background Image', extensions: ['png', 'jpg', 'jpeg'] } ] - }, function(files) { + }, function (files) { if (files) { event.sender.send('selected-bg', files) } }) } -ipc.on('open-offscreen-bg', function(event) { +ipc.on('open-offscreen-bg', function (event) { dialog.showOpenDialog({ title: 'MZD-AIO-TI | Off Screen Background Image Will Be Resized To: 800 px X 480 px and converted to png format.', properties: ['openFile'], @@ -457,20 +462,20 @@ ipc.on('open-offscreen-bg', function(event) { filters: [ { name: 'Off Screen Background Image', extensions: ['png', 'jpg', 'jpeg'] } ] - }, function(files) { + }, function (files) { if (files) { event.sender.send('selected-offscreen-bg', files) } }) }) -ipc.on('open-offscreen-default', function(event) { +ipc.on('open-offscreen-default', function (event) { event.sender.send('selected-offscreen-bg', defaultDir + 'OffScreenBackground.png') }) -ipc.on('default-blnk-art', function(event) { +ipc.on('default-blnk-art', function (event) { event.sender.send('selected-album-art', blankAlbumArtDir + 'no_artwork_icon.png') }) -ipc.on('transparent-blnk-art', function(event) { +ipc.on('transparent-blnk-art', function (event) { event.sender.send('selected-album-art', blankAlbumArtDir + 'no_artwork_icon_blank.png') }) -ipc.on('open-file-blnk-art', function(event) { +ipc.on('open-file-blnk-art', function (event) { dialog.showOpenDialog({ title: 'MZD-AIO-TI | Blank Album Art Image Will Be Resized To: 146 px X 146 px and converted to png format.', properties: ['openFile'], @@ -478,7 +483,7 @@ ipc.on('open-file-blnk-art', function(event) { filters: [ { name: 'Blank Album Art', extensions: ['png', 'jpg', 'jpeg'] } ] - }, function(files) { + }, function (files) { if (files) { event.sender.send('selected-album-art', files) } }) }) @@ -489,21 +494,21 @@ ipc.on('bg-no-resize', (event, arg) => { filters: [ { name: 'Background Image', extensions: ['png', 'jpg', 'jpeg'] } ] - }, function(files) { + }, function (files) { if (files) { event.sender.send('selected-joined-bg', files) } }) }) -ipc.on('theme-jci', function(event) { +ipc.on('theme-jci', function (event) { openThemeDialog(event) }) -function openThemeDialog(event) { +function openThemeDialog (event) { dialog.showOpenDialog({ title: 'MZD-AIO-TI | Choose The JCI Folder From Any Theme Package.', properties: ['openDirectory'] - }, function(files) { + }, function (files) { if (files) { event.sender.send('custom-theme', files) } else { @@ -532,7 +537,7 @@ ipc.on('download-aio-files', (event, arg) => { downloadZip(`${fileName}`) }) - function downloadZip(arg) { + function downloadZip (arg) { downloadwin = new BrowserWindow({ show: false, frame: false, @@ -542,13 +547,13 @@ ipc.on('download-aio-files', (event, arg) => { } }) resetDL() - downloadwin.loadURL(path.join("http://trevelopment.win", `${arg}`)) + downloadwin.loadURL(path.join('http://trevelopment.win', `${arg}`)) downloadwin.on('closed', () => { downloadwin = null }) } - function resetDL() { + function resetDL () { downloadwin.webContents.session.once('will-download', (event, item, webContents) => { // fileSize = (typeof fileSize === 'undefined') ? item.getTotalBytes() : fileSize; // Set the save path, making Electron not to prompt a save dialog. @@ -559,7 +564,7 @@ ipc.on('download-aio-files', (event, arg) => { if (fs.existsSync(`${savePath}`)) { console.log(`${path.resolve(savePath)} Already Exists`) item.cancel() - extract(`${savePath}`, { dir: `${app.getPath('userData')}` }, function(err) { + extract(`${savePath}`, { dir: `${app.getPath('userData')}` }, function (err) { if (err) { console.error(err) } fs.unlinkSync(`${savePath}`) console.log(`${fileName} unzipped & deleted`) @@ -570,7 +575,7 @@ ipc.on('download-aio-files', (event, arg) => { var fileSize = 107 if (`${fileName}` === 'speedcam-patch.zip') { fileSize += 80 } // var totalSize = parseInt(`${item.getTotalBytes()}`/1000000) - item.on('updated', function(event, state) { + item.on('updated', function (event, state) { if (state === 'interrupted') { mainWindow.webContents.send('notif-progress', 'Download interrupted. Please try again.') console.log('Download is interrupted, canceling') @@ -587,7 +592,7 @@ ipc.on('download-aio-files', (event, arg) => { item.once('done', (event, state) => { if (state === 'completed') { console.log(`${savePath} Downloaded successfully`) - extract(`${savePath}`, { dir: `${app.getPath('userData')}` }, function(err) { + extract(`${savePath}`, { dir: `${app.getPath('userData')}` }, function (err) { if (err) { console.error(err) } fs.unlinkSync(`${savePath}`) console.log(`${fileName} unzipped & deleted`) diff --git a/app/menus/context-menu.js b/app/menus/context-menu.js index 4e25ef5..b5a59c4 100644 --- a/app/menus/context-menu.js +++ b/app/menus/context-menu.js @@ -12,10 +12,10 @@ require('electron-context-menu')({ { type: 'separator' }, { label: 'Full Screen', - accelerator: (function() { - if (process.platform === 'darwin') { return 'Ctrl+Command+F'; } else { return 'F11' } + accelerator: (function () { + if (process.platform === 'darwin') { return 'Ctrl+Command+F' } else { return 'F11' } })(), - click: function(item, focusedWindow) { if (focusedWindow) focusedWindow.setFullScreen(!focusedWindow.isFullScreen()) } + click: function (item, focusedWindow) { if (focusedWindow) focusedWindow.setFullScreen(!focusedWindow.isFullScreen()) } }, { label: 'Minimize', accelerator: 'CmdOrCtrl+M', role: 'minimize' }, { type: 'separator' }, @@ -23,9 +23,9 @@ require('electron-context-menu')({ { label: 'Zoom Out', accelerator: 'CmdOrCtrl+-', role: 'zoomout' }, { label: 'Reset Zoom', accelerator: 'CmdOrCtrl+=', role: 'resetzoom' }, { type: 'separator' }, - { label: 'Save', accelerator: 'CmdOrCtrl+s', click: function(item, focusedWindow) { focusedWindow.webContents.send('save-options') } }, - { label: 'Load', accelerator: 'CmdOrCtrl+l', click: function(item, focusedWindow) { focusedWindow.webContents.send('load-options') } }, - { label: 'Load Last Compile', accelerator: 'CmdOrCtrl+Shift+L', click: function(item, focusedWindow) { focusedWindow.webContents.send('load-last') } }, + { label: 'Save', accelerator: 'CmdOrCtrl+s', click: function (item, focusedWindow) { focusedWindow.webContents.send('save-options') } }, + { label: 'Load', accelerator: 'CmdOrCtrl+l', click: function (item, focusedWindow) { focusedWindow.webContents.send('load-options') } }, + { label: 'Load Last Compile', accelerator: 'CmdOrCtrl+Shift+L', click: function (item, focusedWindow) { focusedWindow.webContents.send('load-last') } }, { type: 'separator' }, { label: 'Reload View', accelerator: 'CmdOrCtrl+R', role: 'reload' }, // , click: function (item, focusedWindow) {if (focusedWindow) focusedWindow.reload()}}, { label: 'Quit', accelerator: 'CmdOrCtrl+Q', role: 'quit' } // , click: function (item, focusedWindow) {if (focusedWindow) focusedWindow.close()} diff --git a/app/menus/menu.js b/app/menus/menu.js index 38315fe..08a4295 100644 --- a/app/menus/menu.js +++ b/app/menus/menu.js @@ -10,7 +10,7 @@ const electron = require('electron') const { BrowserWindow, Menu, app, shell } = electron const ipc = electron.ipcMain -function sendAction(action) { +function sendAction (action) { const win = BrowserWindow.getFocusedWindow() if (process.platform === 'darwin') { win.restore() @@ -18,177 +18,172 @@ function sendAction(action) { win.webContents.send(action) } const viewSubmenu = [{ - label: 'Back', - accelerator: 'CmdOrCtrl+B', - click: function(item, focusedWindow) { - if (focusedWindow) { - focusedWindow.webContents.goBack() - } + label: 'Back', + accelerator: 'CmdOrCtrl+B', + click: function (item, focusedWindow) { + if (focusedWindow) { + focusedWindow.webContents.goBack() + } + } +}, +{ + label: 'Reload', + accelerator: 'CmdOrCtrl+R', + click: function (item, focusedWindow) { + if (focusedWindow) { + focusedWindow.reload() + } + } +}, +{ + type: 'separator' +}, +{ + role: 'togglefullscreen' +}, +{ + label: 'Zoom In', + id: 'zoom-in', + accelerator: 'CmdOrCtrl+Plus', + enabled: false, + click () { + sendAction('zoom-in') + } +}, { + label: 'Zoom Out', + id: 'zoom-out', + accelerator: 'CmdOrCtrl+-', + enabled: false, + click () { + sendAction('zoom-out') + } +}, { + label: 'Reset Zoom', + id: 'zoom-actual', + accelerator: 'CmdOrCtrl+=', + enabled: false, + click () { + sendAction('zoom-actual') + } +} +] + +let template = [{ + label: 'File', + submenu: [{ + label: 'Save', + accelerator: 'CmdOrCtrl+s', + role: 'save', + click: function (item, focusedWindow) { + sendAction('save-options') } }, { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click: function(item, focusedWindow) { - if (focusedWindow) { - focusedWindow.reload() - } + label: 'Load', + accelerator: 'CmdOrCtrl+l', + role: 'load', + click: function (item, focusedWindow) { + sendAction('load-options') + } + + }, + { + label: 'Load Last Compile', + accelerator: 'CmdOrCtrl+Shift+L', + role: 'load', + click: function (item, focusedWindow) { + sendAction('load-last') } }, { type: 'separator' }, { - role: 'togglefullscreen' + label: 'Cut', + accelerator: 'CmdOrCtrl+X', + role: 'cut' }, { - label: 'Zoom In', - id: 'zoom-in', - accelerator: 'CmdOrCtrl+Plus', - enabled: false, - click() { - sendAction('zoom-in') + label: 'Copy', + accelerator: 'CmdOrCtrl+C', + role: 'copy' + }, + { + label: 'Paste', + accelerator: 'CmdOrCtrl+V', + role: 'paste' + }, + { + label: 'Select All', + accelerator: 'CmdOrCtrl+A', + role: 'selectall' + } + ] +}, +{ + label: 'Window', + role: 'window', + submenu: [{ + label: 'Reload', + accelerator: 'CmdOrCtrl+R', + click: function (item, focusedWindow) { + if (focusedWindow) { focusedWindow.reload() } } }, { - label: 'Zoom Out', - id: 'zoom-out', - accelerator: 'CmdOrCtrl+-', - enabled: false, - click() { - sendAction('zoom-out') + label: 'Full Screen', + accelerator: (function () { + if (process.platform === 'darwin') { return 'Ctrl+Command+F' } else { return 'F11' } + })(), + click: function (item, focusedWindow) { + if (focusedWindow) { focusedWindow.setFullScreen(!focusedWindow.isFullScreen()) } } }, { + label: 'Minimize', + accelerator: 'CmdOrCtrl+M', + role: 'minimize' + }] +}, +{ + label: 'Zoom', + role: 'zoom', + submenu: [{ label: 'Reset Zoom', - id: 'zoom-actual', - accelerator: 'CmdOrCtrl+=', - enabled: false, - click() { - sendAction('zoom-actual') - } - } -] - -let template = [{ - label: 'File', - submenu: [{ - label: 'Save', - accelerator: 'CmdOrCtrl+s', - role: 'save', - click: function(item, focusedWindow) { - sendAction('save-options') - } - }, - { - label: 'Load', - accelerator: 'CmdOrCtrl+l', - role: 'load', - click: function(item, focusedWindow) { - sendAction('load-options') - } - - }, - { - label: 'Load Last Compile', - accelerator: 'CmdOrCtrl+Shift+L', - role: 'load', - click: function(item, focusedWindow) { - sendAction('load-last') - } - }, - { - type: 'separator' - }, - { - label: 'Cut', - accelerator: 'CmdOrCtrl+X', - role: 'cut' - }, - { - label: 'Copy', - accelerator: 'CmdOrCtrl+C', - role: 'copy' - }, - { - label: 'Paste', - accelerator: 'CmdOrCtrl+V', - role: 'paste' - }, - { - label: 'Select All', - accelerator: 'CmdOrCtrl+A', - role: 'selectall' - }, - ] - }, - { - label: 'Window', - role: 'window', - submenu: [{ - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.reload(); - } - }, { - label: 'Full Screen', - accelerator: (function() { - if (process.platform === 'darwin') - return 'Ctrl+Command+F'; - else - return 'F11'; - })(), - click: function(item, focusedWindow) { - if (focusedWindow) - focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); - } - }, { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize' - }] + accelerator: '=', + role: 'resetzoom' }, { - label: 'Zoom', - role: 'zoom', - submenu: [{ - label: 'Reset Zoom', - accelerator: '=', - role: "resetzoom" - }, - { - label: 'Zoom In', - accelerator: 'Plus', - role: "zoomin" - }, - { - label: 'Zoom Out', - accelerator: '-', - role: "zoomout" - } - ] + label: 'Zoom In', + accelerator: 'Plus', + role: 'zoomin' }, { - label: 'Help', - role: 'help', - submenu: [ + label: 'Zoom Out', + accelerator: '-', + role: 'zoomout' + } + ] +}, +{ + label: 'Help', + role: 'help', + submenu: [ /* { label: 'Info', click: () => { ipc.emit('open-info-window') } - },*/ - { - label: 'Learn More: MazdaTweaks.com', - click: function() { shell.openExternal('http://aio.trevelopment.win/mazdatweaks') } - }, - { - label: 'Forum: Mazda3Revolution.com', - click: function() { shell.openExternal('http://aio.trevelopment.win/mazda3revolution') } - } - ] - }, - /*{ + }, */ + { + label: 'Learn More: MazdaTweaks.com', + click: function () { shell.openExternal('http://aio.trevelopment.win/mazdatweaks') } + }, + { + label: 'Forum: Mazda3Revolution.com', + click: function () { shell.openExternal('http://aio.trevelopment.win/mazda3revolution') } + } + ] +}, + /* { label: 'Back', accelerator: 'CmdOrCtrl+B', click: function (item, focusedWindow) { @@ -201,14 +196,14 @@ let template = [{ label: 'Close', accelerator: 'CmdOrCtrl+W', role: 'close' - },*/ - { - label: 'Quit', - accelerator: 'CmdOrCtrl+Q', - role: 'quit' - } -]; -/*if (process.platform === 'darwin') { + }, */ +{ + label: 'Quit', + accelerator: 'CmdOrCtrl+Q', + role: 'quit' +} +] +/* if (process.platform === 'darwin') { const name = app.getName(); template.unshift({ label: name, @@ -263,11 +258,11 @@ let template = [{ role: 'front' }); } - }*/ -app.on('ready', function() { + } */ +app.on('ready', function () { const menu = Menu.buildFromTemplate(template) Menu.setApplicationMenu(menu) - return template; + return template }) /* app.on('browser-window-created', function () { @@ -278,4 +273,4 @@ app.on('ready', function() { app.on('window-all-closed', function () { let reopenMenuItem = findReopenMenuItem() if (reopenMenuItem) reopenMenuItem.enabled = true -})*/ +}) */ diff --git a/app/opts/25options.htm b/app/opts/25options.htm index 5dad11c..4b05c82 100644 --- a/app/opts/25options.htm +++ b/app/opts/25options.htm @@ -10,7 +10,7 @@
    - AA v1.10+ + AA v1.12
    @@ -19,6 +19,7 @@
    +
    (to /data/headunit.log)
    @@ -27,7 +28,7 @@ - (flips the heading data 180°) +
    (flips the heading data 180°)
    @@ -61,15 +62,18 @@
    For more information, previous releases, or to check for new releases visit the Headunit Info Page and the Headunit Repository

    Full Changelog

    -

    AIO

    -

    v2.8.4

    -

    Android Auto Headunit App v1.11

    -
    • Tweaked Linux Stack TCP Buffers
    • More Stable HUD support (It is not perfect yet)
      • Detects if HUD is present, if not available the feature is not used
    • Buttons Remapped:
      • Home: AA Home screen
      • Ent: AA Music screen
      • Nav: AA Navigation screen
      • Fav: Switch Audio Focus (MZD <-> AA)
      • Call End (Steering Wheel): Exit AA (when not in active call otherwise reject/end call)
    -

    AIO Tweaks App v1.0

    -
    • Applies CASDK localStorage tweak for saving options (for Video Player app too)
    • Show localStorage Button shows the contents of localStorage (Values saved by Video Player, AIO Tweaks, and CASDK apps)
    • adb kill-server Button kills adb server
    • Check IP Address Button shows IP address (if WIFI or hotspot is connected or else there is no IP address)
    • Wink Test Button shows test wink notification
    • Better behavior from "Start/Stop" Android Auto buttons
    -

    Date 2 Statusbar / Statusbar Speedometer

    -
    • Minor spacing adjustments for date
    • Coolant temp color (blue = under 30º; yellow = under 55º)
    -

    Touchscreen While Driving Option - DVDs While Driving

    -
    • Enable Playing DVDs while driving (DVD Player Required)
    -

    Fuel Consumption Tweak FIXED

    -
    • Added calculations for km/L (as default)
    • Added L/100km option (as converted)
    • Fixed all calculations (L/100km <-> km/L <-> mpg)
    • If you choose the same unit as your default, will show the same value twice - this is expected behavior
      • Example: If your default is mpg and you choose mpg will show same number (in mpg) for both top and bottom values
      • The top value is in your default unit, bottom value is converted to chosen unit
    -

    Semi-Transparent Parking Sensors

    -
    • Shows relevant colors based on distance (Green - Yellow - Orange - Red)
    -

    No More Beeps

    -
    • Fixed for FW v59.00.502+
    -

    Autorun & Recovery

    -
    • Fixed Firewall Recovery (jci-fw.sh)
    • Fixed a bug where selecting autorun before compiling Full System Restore would create an autorun installer.
    • Added additional WARNING message that tweaking ability will be lost (and a chance to cancel uninstallation) when choosing to uninstall on FW 59.00.502+
    -

    CASDK Apps available by default

    • Snake
    • Simple Speedometer
    -

    Mac & Linux Quirks

    -
    • Fixed Blank window sometimes when navigating between Tweaks, CASDK, Autorun, & System Restore views
    • Fixed Some of the "Open" buttons opening incorrect folders or none at all

    • Various other bug fixes

    +

    AIO + CASDK

    + +

    v2.8.5

    + +

    Android Auto Headunit App v1.12

    + +
    • HUD Improvements
    • Wifi Mode: IP Address Detection for Android v9 Pie
    • Button Remaps: (Long Hold = Press for 3+ seconds, action on key up)
      • Exit AA: Long Hold Call End or Back (No longer single click Call End)
      • Take Video Focus: Long Hold Home (If AA has controller focus and loses video focus for any reason)
      • Release Audio Focus: Long Hold Fav (Single click Fav is now Play/Pause for AA audio only)
    + +

    Speedometer v6.1

    + +
    • Websocket rework (for faster update rates)
    • Digital clock font rework (numbers are fixed width like a real digital clock)
      • Digital Clock Before ==> Digital Clock After
    + +

    Autorun & Recovery (& Serial)

    + +
    • Updated for v70.00.335+ (Must perform DURING update or reinstall)
      • Make sure to make the serial connection BEFORE UPDATING TO v70.00.335
      • If you have already updated to v70.00.335 you can reinstall the same version over it.
    • Added Serial Instructions Screen (From help drop-down menu and left side pop-out menu)
    • Autorun installer will use "Skip Confirmation" Option
    + +

    For Unknow FW > v70.00.352

    + +
    • Riskier tweaks will individually prompt to "Install" or "Skip" (At your own risk)
      • No More Disclaimer
      • Order of Audio Source List
      • Date 2 Statusbar
    • All other tweaks compatible with v70.00.335 will install but check the forums for more compatibility info & use caution + +

      Improvements

      + +
      • 🐛 Bug Fixes
      • ☑️ Integrity Checks
      • 🌐 Safety Nets
      diff --git a/package-lock.json b/package-lock.json index d32490a..cece638 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,41 +1,130 @@ { "name": "MZD-AIO-TI", - "version": "2.8.4", + "version": "2.8.5", "lockfileVersion": 1, "requires": true, "dependencies": { "7zip-bin": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-4.1.0.tgz", - "integrity": "sha512-AsnBZN3a8/JcNt+KPkGGODaA4c7l3W5+WpeKgGSbstSLxqWtTXqd1ieJGBQ8IFCtRg8DmmKUcSkIkUc0A4p3YA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.0.3.tgz", + "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", "dev": true }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@develar/schema-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.1.0.tgz", + "integrity": "sha512-qjCqB4ctMig9Gz5bd6lkdFr3bO6arOdQqptdBSpF1ZpCnjofieCciEzkoS9ujY9cMGyllYSCSmBJ3x9OKHXzoA==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "dev": true, "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", "dev": true }, "@types/node": { - "version": "10.12.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.24.tgz", - "integrity": "sha512-GWWbvt+z9G5otRBW8rssOFgRY87J9N/qbhqfjMZ+gUuL6zoL+Hm6gP/8qQBG4jjimqdaNLCehcVapZ/Fs2WjCQ==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.1.1.tgz", + "integrity": "sha512-hx6zWtudh3Arsbl3cXay+JnkvVgCKzCWKv42C9J01N2T2np4h8w5X8u6Tpz5mj38kE3M9FM0Pazx8vKFFMnjLQ==", "dev": true }, "abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, "accessibility-developer-tools": { @@ -45,46 +134,38 @@ "dev": true }, "acorn": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz", - "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==", - "dev": true - }, - "acorn-dynamic-import": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", - "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, "acorn-jsx": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.0.tgz", - "integrity": "sha512-XkB50fn0MURDyww9+UYL3c1yLbOBz0ZFvrdYlGB8l+Ije1oSC75qAqrzSPjYQbdnQUzhlUGNKuesryAv0gxZOg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, "acorn-node": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", - "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", "dev": true, "requires": { - "acorn": "^6.0.2", - "acorn-dynamic-import": "^4.0.0", - "acorn-walk": "^6.1.0", - "xtend": "^4.0.1" + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" } }, "acorn-walk": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.0.0.tgz", + "integrity": "sha512-7Bv1We7ZGuU79zZbb6rRqcpxo3OY+zrdtloZWoyD8fmGX+FeXRjE+iuGkZjSXLVovLzrsvMGMy0EkwA0E0umxg==", "dev": true }, "ajv": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", - "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", - "dev": true, + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -93,31 +174,30 @@ } }, "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", "dev": true }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true, - "optional": true - }, "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", "dev": true, "requires": { - "string-width": "^2.0.0" + "string-width": "^3.0.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "is-fullwidth-code-point": { @@ -127,30 +207,37 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } } } }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, "ansi-escapes": { - "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { @@ -159,50 +246,53 @@ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.0.tgz", + "integrity": "sha512-7kFQgnEaMdRtwf6uSfUnVr9gSGC7faurn+J/Mv90/W+iTtN0405/nLdopfMWwchyxhbGYl6TC4Sccn9TUkGAgg==", "requires": { - "color-convert": "^1.9.0" + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" } }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, "app-builder-bin": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-2.6.3.tgz", - "integrity": "sha512-JL8C41e6yGIchFsHP/q15aGNedAaUakLhkV6ER0Yxafx08sRnlDnlkAkEIKjX7edg/4i7swpGa6CBv1zX9GgCA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.4.3.tgz", + "integrity": "sha512-qMhayIwi3juerQEVJMQ76trObEbfQT0nhUdxZz9a26/3NLT3pE6awmQ8S1cEnrGugaaM5gYqR8OElcDezfmEsg==", "dev": true }, "app-builder-lib": { - "version": "20.38.5", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-20.38.5.tgz", - "integrity": "sha512-vVgM9d9twwlhr+8vNAJOAD9dyVBRk7reuVa1BE1OmvaHb1M+fS8KpvcDKVdBqX9KDHy7zSc57mnIcHgax4/XMA==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-21.2.0.tgz", + "integrity": "sha512-aOX/nv77/Bti6NymJDg7p9T067xD8m1ipIEJR7B4Mm1GsJWpMm9PZdXtCRiMNRjHtQS5KIljT0g17781y6qn5A==", "dev": true, "requires": { - "7zip-bin": "~4.1.0", - "app-builder-bin": "2.6.3", + "7zip-bin": "~5.0.3", + "@develar/schema-utils": "~2.1.0", "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.6", - "builder-util": "9.6.2", - "builder-util-runtime": "8.1.1", + "bluebird-lst": "^1.0.9", + "builder-util": "21.2.0", + "builder-util-runtime": "8.3.0", "chromium-pickle-js": "^0.2.0", "debug": "^4.1.1", - "ejs": "^2.6.1", - "electron-osx-sign": "0.4.11", - "electron-publish": "20.38.5", - "fs-extra-p": "^7.0.0", + "ejs": "^2.6.2", + "electron-publish": "21.2.0", + "fs-extra": "^8.1.0", "hosted-git-info": "^2.7.1", "is-ci": "^2.0.0", - "isbinaryfile": "^4.0.0", - "js-yaml": "^3.12.1", - "lazy-val": "^1.0.3", + "isbinaryfile": "^4.0.2", + "js-yaml": "^3.13.1", + "lazy-val": "^1.0.4", "minimatch": "^3.0.4", - "normalize-package-data": "^2.4.0", - "plist": "^3.0.1", - "read-config-file": "3.2.1", - "sanitize-filename": "^1.6.1", - "semver": "^5.6.0", - "temp-file": "^3.3.2" + "normalize-package-data": "^2.5.0", + "read-config-file": "5.0.0", + "sanitize-filename": "^1.6.2", + "semver": "^6.3.0", + "temp-file": "^3.3.4" }, "dependencies": { "debug": { @@ -214,32 +304,21 @@ "ms": "^2.1.1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } @@ -255,7 +334,7 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "archiver": { "version": "2.1.1", @@ -273,10 +352,29 @@ "zip-stream": "^1.2.0" }, "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "dev": true, + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -286,6 +384,21 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + } } } }, @@ -304,9 +417,9 @@ }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -329,32 +442,14 @@ } }, "argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -362,40 +457,20 @@ "dev": true }, "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" } }, "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, "asn1": { @@ -419,20 +494,16 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" }, "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz", + "integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ==", + "dev": true }, "async-exit-hook": { "version": "2.0.1", @@ -459,49 +530,11 @@ "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", + "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==", "dev": true }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", @@ -517,71 +550,10 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", - "dev": true - } - } - }, "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", "dev": true }, "bcrypt-pbkdf": { @@ -594,103 +566,78 @@ } }, "bindings": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.4.0.tgz", - "integrity": "sha512-7znEVX22Djn+nYjxCWKDne0RRloa9XfYa84yk3s+HkE3LpDYZmhArYr9O9huBoHY3/oXispx5LorIX7Sl2CgSQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "requires": { "file-uri-to-path": "1.0.0" } }, "bl": { - "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", + "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "readable-stream": "^3.0.1" }, "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } } } }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "dev": true, - "requires": { - "inherits": "~2.0.0" - } - }, "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bluebird-lst": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.6.tgz", - "integrity": "sha512-CBWFoPuUPpcvMUxfyr8DKdI5d4kjxFl1h39+VbKxP3KJWJHEsLtuT4pPLkjpxCGU6Ask21tvbnftWXdqIxYldQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", "requires": { - "bluebird": "^3.5.2" + "bluebird": "^3.5.5" } }, "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", + "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", "dev": true, "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^2.4.2", + "cli-boxes": "^2.2.0", + "string-width": "^3.0.0", "term-size": "^1.2.0", + "type-fest": "^0.3.0", "widest-line": "^2.0.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "is-fullwidth-code-point": { @@ -700,74 +647,61 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true } } }, "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" } }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA=", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, "buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", "dev": true, "requires": { "base64-js": "^1.0.2", @@ -778,6 +712,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -786,7 +721,8 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true }, "buffer-crc32": { "version": "0.2.13", @@ -797,44 +733,35 @@ "buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true }, "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "builder-util": { - "version": "9.6.2", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-9.6.2.tgz", - "integrity": "sha512-cWl/0/Q851lesMmXp1IjreeAX1QAWA9e+iU2IT61oh+CvMYJnDwao2m9ZCHammdw2zllrwWu4fOC3gvsb/yOCw==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-21.2.0.tgz", + "integrity": "sha512-Nd6CUb6YgDY8EXAXEIegx+1kzKqyFQ5ZM5BoYkeunAlwz/zDJoH1UCyULjoS5wQe5czNClFQy07zz2bzYD0Z4A==", "dev": true, "requires": { - "7zip-bin": "~4.1.0", - "app-builder-bin": "2.6.3", - "bluebird-lst": "^1.0.6", - "builder-util-runtime": "^8.1.1", + "7zip-bin": "~5.0.3", + "@types/debug": "^4.1.4", + "app-builder-bin": "3.4.3", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", "debug": "^4.1.1", - "fs-extra-p": "^7.0.0", + "fs-extra": "^8.1.0", "is-ci": "^2.0.0", - "js-yaml": "^3.12.1", - "source-map-support": "^0.5.10", - "stat-mode": "^0.2.2", - "temp-file": "^3.3.2" + "js-yaml": "^3.13.1", + "source-map-support": "^0.5.13", + "stat-mode": "^0.3.0", + "temp-file": "^3.3.4" }, "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -844,110 +771,76 @@ "ms": "^2.1.1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true } } }, "builder-util-runtime": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.1.1.tgz", - "integrity": "sha512-+ieS4PMB33vVE2S3ZNWBEQJ1zKmAs/agrBdh7XadE1lKLjrH4aXYuOh9OOGdxqIRldhlhNBaF+yKMMEFOdNVig==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.3.0.tgz", + "integrity": "sha512-CSOdsYqf4RXIHh1HANPbrZHlZ9JQJXSuDDloblZPcWQVN62inyYoTQuSmY3KrgefME2Sv3Kn2MxHvbGQHRf8Iw==", "dev": true, "requires": { - "bluebird-lst": "^1.0.6", "debug": "^4.1.1", - "fs-extra-p": "^7.0.0", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "builtins": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-2.0.0.tgz", - "integrity": "sha1-AYmZZB4RJSGIZS27LbAa04b83EY=", - "dev": true, - "requires": { - "semver": "^5.4.1" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", "dev": true, "requires": { - "callsites": "^0.2.0" + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } } }, "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camelcase": { @@ -966,12 +859,6 @@ "map-obj": "^1.0.0" } }, - "capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -1002,14 +889,40 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + } } }, "chardet": { @@ -1025,9 +938,9 @@ "dev": true }, "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" }, "chromium-pickle-js": { "version": "0.2.0", @@ -1041,39 +954,10 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", "dev": true }, "cli-cursor": { @@ -1086,11 +970,50 @@ } }, "cli-spinners": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", - "integrity": "sha1-ACwZkJEtDVlYDJO9NsBW3pnkJZo=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz", + "integrity": "sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ==", "dev": true }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -1098,20 +1021,26 @@ "dev": true }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "is-fullwidth-code-point": { @@ -1121,22 +1050,23 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } } } @@ -1147,68 +1077,62 @@ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + }, + "dependencies": { + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + } + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha1-30boZ9D8Kuxmo0ZitAapzK//Ww8=", - "dev": true - }, - "compare-version": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", - "integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=", - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true }, "compress-commons": { "version": "1.2.2", @@ -1227,22 +1151,35 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "conf": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/conf/-/conf-2.0.0.tgz", - "integrity": "sha512-iCLzBsGFi8S73EANsEJZz0JnJ/e5VZef/kSaxydYZLAvw0rFNAUx5R7K5leC/CXXR2mZfXWhUvcZOO/dM2D5xg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conf/-/conf-5.0.0.tgz", + "integrity": "sha512-lRNyt+iRD4plYaOSVTxu1zPWpaH0EOxgFIR1l3mpC/DGZ7XzhoGFMKmbl54LAgXcSu6knqWgOwdINkqm58N85A==", "requires": { - "dot-prop": "^4.1.0", - "env-paths": "^1.0.0", - "make-dir": "^1.0.0", - "pkg-up": "^2.0.0", - "write-file-atomic": "^2.3.0" + "ajv": "^6.10.0", + "dot-prop": "^5.0.0", + "env-paths": "^2.2.0", + "json-schema-typed": "^7.0.0", + "make-dir": "^3.0.0", + "pkg-up": "^3.0.1", + "write-file-atomic": "^3.0.0" } }, "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", + "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", "dev": true, "requires": { "dot-prop": "^4.1.0", @@ -1251,6 +1188,49 @@ "unique-string": "^1.0.0", "write-file-atomic": "^2.0.0", "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + } } }, "console-control-strings": { @@ -1264,24 +1244,15 @@ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "copy-dir": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-0.4.0.tgz", - "integrity": "sha512-mIefrD97nE1XX2th570tR5UQvW6/92czEPGe+oTtrxPAJl+KOKLpzcRa+e38WEpmt/IUN1n65KvRMzPblR+fDQ==", - "requires": { - "mkdir-p": "~0.0.4" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-1.2.0.tgz", + "integrity": "sha512-UeaUFUIHqGV4brjQ9bY2mHll/hoxyCak2emgmYG72LkGKABHBdBDKFw0H5nTKt5OzVBkBhkxCwnniJBAE7EGEw==" }, "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", "dev": true }, "core-util-is": { @@ -1308,15 +1279,6 @@ "readable-stream": "^2.0.0" } }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, "crlf": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/crlf/-/crlf-1.1.1.tgz", @@ -1353,14 +1315,6 @@ "source-map": "^0.6.1", "source-map-resolve": "^0.5.2", "urix": "^0.1.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "css-parse": { @@ -1397,12 +1351,11 @@ } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "debug-log": { @@ -1424,11 +1377,11 @@ "dev": true }, "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "requires": { - "mimic-response": "^1.0.0" + "mimic-response": "^2.0.0" } }, "deep-eql": { @@ -1466,124 +1419,53 @@ "clone": "^1.0.2" } }, + "defer-to-connect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.1.tgz", + "integrity": "sha512-J7thop4u3mRTkYRQ+Vpfwy2G5Ehoy82I14+14W4YMDLKdWloI9gSzRbV30s/NckQGVJtPkWNcW4oMAUigTdqiQ==", + "dev": true + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "object-keys": "^1.0.12" - }, - "dependencies": { - "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", - "dev": true - } - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", - "dev": true - } - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "deglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", - "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", - "dev": true, - "requires": { - "find-root": "^1.0.0", - "glob": "^7.0.5", - "ignore": "^3.0.9", - "pkg-config": "^1.1.0", - "run-parallel": "^1.1.2", - "uniq": "^1.0.1" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + "object-keys": "^1.0.12" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true } } }, - "del": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", - "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "deglob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-3.1.0.tgz", + "integrity": "sha512-al10l5QAYaM/PeuXkAr1Y9AQz0LCtWsnJG23pIgh44hDxHFOj36l6qvhfjnIWBYwZOqM1fXUFV9tkjL7JPdGvw==", "dev": true, "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" + "find-root": "^1.0.0", + "glob": "^7.0.5", + "ignore": "^5.0.0", + "pkg-config": "^1.1.0", + "run-parallel": "^1.1.2", + "uniq": "^1.0.1" }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -1593,27 +1475,6 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } } } }, @@ -1629,17 +1490,18 @@ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "dependency-check": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/dependency-check/-/dependency-check-3.3.0.tgz", - "integrity": "sha512-OyKLWiMd3voSfU4FGIbEOMD5Ep/nesxkGTamxe/T0DBax1tl3AKSDEFOONVcxIbQoTpT3DXP2x3DUwTfj6YhOA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/dependency-check/-/dependency-check-4.1.0.tgz", + "integrity": "sha512-nlw+PvhVQwg0gSNNlVUiuRv0765gah9pZEXdQlIFzeSnD85Eex0uM0bkrAWrHdeTzuMGZnR9daxkup/AqqgqzA==", "dev": true, "requires": { - "builtins": "^2.0.0", "debug": "^4.0.0", "detective": "^5.0.2", - "globby": "^8.0.1", + "globby": "^10.0.1", "is-relative": "^1.0.0", + "micromatch": "^4.0.2", "minimist": "^1.2.0", + "pkg-up": "^3.1.0", "read-package-json": "^2.0.10", "resolve": "^1.1.7" }, @@ -1658,12 +1520,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true } } }, @@ -1711,107 +1567,90 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha1-gAwN0eCov7yVg1wgKtIg/jF+WhI=", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha1-CyBdK2rvmCOMooZZioIE0p0KADQ=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" + "path-type": "^4.0.0" } }, "dmg-builder": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.5.4.tgz", - "integrity": "sha512-EaEkF8weXez3iAwgYffjcYfumauUh5x+BggMgn/IuihNIA5/WfzRAUR4wMq9aII2zwArlw+rIrX6ZHKbmtkQmA==", - "dev": true, - "requires": { - "app-builder-lib": "~20.38.5", - "bluebird-lst": "^1.0.6", - "builder-util": "~9.6.2", - "fs-extra-p": "^7.0.0", - "iconv-lite": "^0.4.24", - "js-yaml": "^3.12.1", - "parse-color": "^1.0.0", - "sanitize-filename": "^1.6.1" + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-21.2.0.tgz", + "integrity": "sha512-9cJEclnGy7EyKFCoHDYDf54pub/t92CQapyiUxU0w9Bj2vUvfoDagP1PMiX4XD5rPp96141h9A+QN0OB4VgvQg==", + "dev": true, + "requires": { + "app-builder-lib": "~21.2.0", + "bluebird-lst": "^1.0.9", + "builder-util": "~21.2.0", + "fs-extra": "^8.1.0", + "iconv-lite": "^0.5.0", + "js-yaml": "^3.13.1", + "sanitize-filename": "^1.6.2" }, "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } } } }, "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" } }, + "dom-walk": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" + }, "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", "requires": { - "is-obj": "^1.0.0" + "is-obj": "^2.0.0" } }, "dotenv": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", - "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "dev": true }, "dotenv-expand": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", - "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", "dev": true }, "drivelist": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/drivelist/-/drivelist-6.4.6.tgz", - "integrity": "sha512-FVeQE8GQppabnXm5J3tz3+nNZUWBixLYl2jGuLnCI/LhpopOj6+/fvPMgaWXC/SW/gceVALCx/EBRk8HiXqB5w==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/drivelist/-/drivelist-8.0.9.tgz", + "integrity": "sha512-s25SFYuMDD7WK+/CaOZpXCXCpBU0aJwBwGlg0AkO8ttVTIGEJSdBgjQQdBFeR0Z9Pl/BRGst7YIScv4q2LLo6w==", "requires": { "bindings": "^1.3.0", "debug": "^3.1.0", - "fast-plist": "^0.1.2", - "nan": "^2.10.0", - "prebuild-install": "^4.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } + "mz": "^2.7.0", + "nan": "^2.14.0", + "prebuild-install": "^5.2.4" } }, "duplexer3": { @@ -1831,104 +1670,98 @@ } }, "ejs": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", - "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", "dev": true }, "electron": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/electron/-/electron-4.0.3.tgz", - "integrity": "sha512-wOBYnlv3Xgbwh9DAHBktP3sQcbCBuXMQi1NzPH3EMnbdYNqj+FnTzVLq0RYp0uSzdjR3fhAZ/E6wFSMLaAc5iw==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/electron/-/electron-6.1.7.tgz", + "integrity": "sha512-QhBA/fcYJit2XJGkD2xEfxlWTtTaWYu7qkKVohtVWXpELFqkpel2DCDxet5BTo0qs8ukuZHxlQPnIonODnl2bw==", "dev": true, "requires": { "@types/node": "^10.12.18", "electron-download": "^4.1.0", "extract-zip": "^1.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", + "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==", + "dev": true + } } }, "electron-builder": { - "version": "20.38.5", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-20.38.5.tgz", - "integrity": "sha512-p88IDHhH2J4hA6KwRBJY+OfVZuFtFIShY3Uh/TwYAfbX0v1RhKZytuGdO8sty2zcWxDYX74xDBv+X9oN6qEIRQ==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-21.2.0.tgz", + "integrity": "sha512-x8EXrqFbAb2L3N22YlGar3dGh8vwptbB3ovo3OF6K7NTpcsmM2zEoJv7GhFyX73rNzSG2HaWpXwGAtOp2JWiEw==", "dev": true, "requires": { - "app-builder-lib": "20.38.5", - "bluebird-lst": "^1.0.6", - "builder-util": "9.6.2", - "builder-util-runtime": "8.1.1", + "app-builder-lib": "21.2.0", + "bluebird-lst": "^1.0.9", + "builder-util": "21.2.0", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", - "dmg-builder": "6.5.4", - "fs-extra-p": "^7.0.0", + "dmg-builder": "21.2.0", + "fs-extra": "^8.1.0", "is-ci": "^2.0.0", - "lazy-val": "^1.0.3", - "read-config-file": "3.2.1", - "sanitize-filename": "^1.6.1", - "update-notifier": "^2.5.0", - "yargs": "^12.0.5" + "lazy-val": "^1.0.4", + "read-config-file": "5.0.0", + "sanitize-filename": "^1.6.2", + "update-notifier": "^3.0.1", + "yargs": "^13.3.0" }, "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } } } }, "electron-chromedriver": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/electron-chromedriver/-/electron-chromedriver-3.0.0.tgz", - "integrity": "sha512-xWivZRiPTtDFJt+qXv7Ax/Dmhxj0iqESOxoLZ2szu3fv6k1vYDUDJUMHfdfVAke9D2gBRIgChuGb5j3YEt6hxQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/electron-chromedriver/-/electron-chromedriver-6.0.0.tgz", + "integrity": "sha512-UIhRl0sN5flfUjqActXsFrZQU1NmBObvlxzPnyeud8vhR67TllXCoqfvhQJmIrJAJJK+5M1DFhJ5iTGT++dvkg==", "dev": true, "requires": { - "electron-download": "^4.1.0", - "extract-zip": "^1.6.5" + "electron-download": "^4.1.1", + "extract-zip": "^1.6.7" } }, "electron-context-menu": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-0.10.1.tgz", - "integrity": "sha512-KFkKwFbT6iJUgarEknYuXQlJAT+naJZtSWFBtHf9RiSb70wscWdDNpYoUERzF7FgqYE1Mil4npfRWsjqGLwtog==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/electron-context-menu/-/electron-context-menu-0.14.0.tgz", + "integrity": "sha512-7PuDz0Z3Eebhg/OS3JfPqHrQYl5ApokT/05PPUbNELk0EHBfFZwVcVneOJ05SlaGagK1bfQIXf75WSZt/K23VA==", "requires": { + "cli-truncate": "^2.0.0", "electron-dl": "^1.2.0", "electron-is-dev": "^1.0.1" - }, - "dependencies": { - "electron-is-dev": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.0.1.tgz", - "integrity": "sha512-iwM3EotA9HTXqMGpQRkR/kT8OZqBbdfHTnlwcxsjSLYqY8svvsq0MuujsWCn3/vtgRmDv/PC/gKUUpoZvi5C1w==" - } } }, "electron-debug": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/electron-debug/-/electron-debug-2.1.0.tgz", - "integrity": "sha512-IJkEfMRhU0FxTc9khmAXkRw1AmQVLBiKaUqpDSQPLvZkxBnYsPVCy8tTvriA7eLb5p4oCmu2HmdDCx7laXy7+g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/electron-debug/-/electron-debug-3.0.1.tgz", + "integrity": "sha512-fo3mtDM4Bxxm3DW1I+XcJKfQlUlns4QGWyWGs8OrXK1bBZ2X9HeqYMntYBx78MYRcGY5S/ualuG4GhCnPlaZEA==", "dev": true, "requires": { - "electron-is-dev": "^0.3.0", - "electron-localshortcut": "^3.0.0" - }, - "dependencies": { - "electron-is-dev": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-0.3.0.tgz", - "integrity": "sha1-FOb9pcaOnk7L7/nM8DfL18BcWv4=", - "dev": true - } + "electron-is-dev": "^1.1.0", + "electron-localshortcut": "^3.1.0" } }, "electron-dl": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.12.0.tgz", - "integrity": "sha512-UMc2CL45Ybpvu66LDPYzwmDRmYK4Ivz+wdnTM0eXcNMztvQwhixAk2UPme1c7McqG8bAlKEkQpZn3epmQy4EWg==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.14.0.tgz", + "integrity": "sha512-4okyei42a1mLsvLK7hLrIfd20EQzB18nIlLTwBV992aMSmTGLUEFRTmO1MfSslGNrzD8nuPuy1l/VxO8so4lig==", "requires": { "ext-name": "^5.0.0", "pupa": "^1.0.0", @@ -1952,26 +1785,17 @@ "sumchecker": "^2.0.2" }, "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } + "env-paths": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", + "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", + "dev": true }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true } } }, @@ -1987,97 +1811,76 @@ "dev": true }, "electron-is-dev": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.0.1.tgz", - "integrity": "sha512-iwM3EotA9HTXqMGpQRkR/kT8OZqBbdfHTnlwcxsjSLYqY8svvsq0MuujsWCn3/vtgRmDv/PC/gKUUpoZvi5C1w==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.1.0.tgz", + "integrity": "sha512-Z1qA/1oHNowGtSBIcWk0pcLEqYT/j+13xUw/MYOrBUOL4X7VN0i0KCTf5SqyvMPmW5pSPKbo28wkxMxzZ20YnQ==" }, "electron-localshortcut": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/electron-localshortcut/-/electron-localshortcut-3.1.0.tgz", - "integrity": "sha1-EMH/1Te405FwqvbhVRNB93gN0s4=", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/electron-localshortcut/-/electron-localshortcut-3.2.1.tgz", + "integrity": "sha512-DWvhKv36GsdXKnaFFhEiK8kZZA+24/yFLgtTwJJHc7AFgDjNRIBJZ/jq62Y/dWv9E4ypYwrVWN2bVrCYw1uv7Q==", "dev": true, "requires": { - "debug": "^2.6.8", + "debug": "^4.0.1", "electron-is-accelerator": "^0.1.0", - "keyboardevent-from-electron-accelerator": "^1.1.0", + "keyboardevent-from-electron-accelerator": "^2.0.0", "keyboardevents-areequal": "^0.2.1" - } - }, - "electron-osx-sign": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.11.tgz", - "integrity": "sha512-VVd40nrnVqymvFrY9ZkOYgHJOvexHHYTR3di/SN+mjJ0OWhR1I8BRVj3U+Yamw6hnkZZNKZp52rqL5EFAAPFkQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.0", - "compare-version": "^0.1.2", - "debug": "^2.6.8", - "isbinaryfile": "^3.0.2", - "minimist": "^1.2.0", - "plist": "^3.0.1" }, "dependencies": { - "isbinaryfile": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", - "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "buffer-alloc": "^1.2.0" + "ms": "^2.1.1" } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true } } }, "electron-publish": { - "version": "20.38.5", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-20.38.5.tgz", - "integrity": "sha512-EhdPm6t0nKDfa0r3KjV1kSFcz03VrzgJRv7v5nHkkpQZB6OSmDNlHq7k66NBwQhPK3i4CK+uvehljZAP28vbCA==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-21.2.0.tgz", + "integrity": "sha512-mWavuoWJe87iaeKd0I24dNWIaR+0yRzshjNVqGyK019H766fsPWl3caQJnVKFaEyrZRP397v4JZVG0e7s16AxA==", "dev": true, "requires": { - "bluebird-lst": "^1.0.6", - "builder-util": "~9.6.2", - "builder-util-runtime": "^8.1.1", + "bluebird-lst": "^1.0.9", + "builder-util": "~21.2.0", + "builder-util-runtime": "8.3.0", "chalk": "^2.4.2", - "fs-extra-p": "^7.0.0", - "lazy-val": "^1.0.3", - "mime": "^2.4.0" + "fs-extra": "^8.1.0", + "lazy-val": "^1.0.4", + "mime": "^2.4.4" }, "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } } } }, "electron-rebuild": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-1.8.4.tgz", - "integrity": "sha512-QBUZg1due+R0bww5rNd4gEcsKczyhxyLrxSFZlKihwHRxaiHrGut532JAUe0fRz+VIU4WNSfNKyZ/ZwSGjaDhA==", + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-1.8.8.tgz", + "integrity": "sha512-9a/VGbVpTJcuBaZa8yMcegqJ5flGPYDo363AxXDMxY4ZHPtFMLedGzQW9+720SIS1cvjX8B0zC+vMHO75ncOiA==", "dev": true, "requires": { "colors": "^1.3.3", "debug": "^4.1.1", "detect-libc": "^1.0.3", "fs-extra": "^7.0.1", - "node-abi": "^2.7.0", - "node-gyp": "^3.8.0", - "ora": "^3.0.0", + "node-abi": "^2.11.0", + "node-gyp": "^6.0.1", + "ora": "^3.4.0", "spawn-rx": "^3.0.0", - "yargs": "^12.0.5" + "yargs": "^13.2.4" }, "dependencies": { "debug": { @@ -2099,35 +1902,35 @@ "jsonfile": "^4.0.0", "universalify": "^0.1.0" } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true } } }, "electron-store": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-2.0.0.tgz", - "integrity": "sha512-1WCFYHsYvZBqDsoaS0Relnz0rd81ZkBAI0Fgx7Nq2UWU77rSNs1qxm4S6uH7TCZ0bV3LQpJFk7id/is/ZgoOPA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-4.0.0.tgz", + "integrity": "sha512-qgkDetwB9bz+ZA7mNCQGm6zLJOMT4yBkTZ7f16M9iS0GcI/bOeOeFkLkIaJddTtPca7MOiaUM1imMjFqUfQgSA==", "requires": { - "conf": "^2.0.0" + "conf": "^5.0.0", + "type-fest": "^0.5.2" } }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "requires": { "once": "^1.4.0" } }, "env-paths": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", - "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", + "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" }, "error-ex": { "version": "1.3.2", @@ -2139,22 +1942,36 @@ } }, "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", + "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { "is-callable": "^1.1.4", @@ -2168,87 +1985,49 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, - "escodegen": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", - "dev": true, - "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" - }, - "dependencies": { - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "estraverse": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", - "dev": true - }, - "source-map": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", - "dev": true, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, "eslint": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.4.0.tgz", - "integrity": "sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz", + "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==", "dev": true, "requires": { - "ajv": "^6.5.0", - "babel-code-frame": "^6.26.0", + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", + "espree": "^6.0.0", "esquery": "^1.0.1", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", + "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", + "glob-parent": "^5.0.0", "globals": "^11.7.0", - "ignore": "^4.0.2", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^5.2.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.11.0", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.14", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", "progress": "^2.0.0", - "regexpp": "^2.0.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^4.0.3", - "text-table": "^0.2.0" + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { "ansi-regex": { @@ -2257,6 +2036,12 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -2268,35 +2053,43 @@ "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore": { @@ -2306,23 +2099,23 @@ "dev": true }, "inquirer": { - "version": "5.2.0", - "resolved": "http://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^2.1.0", + "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.3.0", + "lodash": "^4.17.12", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^5.5.2", + "rxjs": "^6.4.0", "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", + "strip-ansi": "^5.1.0", "through": "^2.3.6" } }, @@ -2332,20 +2125,10 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "string-width": { @@ -2356,35 +2139,60 @@ "requires": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } + }, + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "dev": true } } }, "eslint-config-standard": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz", - "integrity": "sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-13.0.1.tgz", + "integrity": "sha512-zLKp4QOgq6JFgRm1dDCVv1Iu0P5uZ4v5Wa4DTOkg2RFMxdCX/9Qf7lz9ezRj2dBRa955cWQF/O/LWEiYWAHbTw==", "dev": true }, "eslint-config-standard-jsx": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-6.0.2.tgz", - "integrity": "sha512-D+YWAoXw+2GIdbMBRAzWwr1ZtvnSf4n4yL0gKGg7ShUOGXkSOLerI17K4F6LdQMJPNMoWYqepzQD/fKY+tXNSg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-7.0.0.tgz", + "integrity": "sha512-OiKOF3MFVmWOCVfsi8GHlVorOEiBsPzAnUhM3c6HML94O2krbdQ/eMABySHgHHOIBYRls9sR9I3lo6O0vXhVEg==", "dev": true }, "eslint-import-resolver-node": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha1-WPFfuDm40FdsqYBBNHaqskcttmo=", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", "dev": true, "requires": { "debug": "^2.6.9", @@ -2394,52 +2202,85 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.0.tgz", + "integrity": "sha512-kCo8pZaNz2dsAW7nCUjuVoI11EBXXpIzfNxmaoLhXoRDOnqXLC4iSGVRdZPhOitfbdEfMEfKOiENaK6wDPZEGw==", "dev": true, "requires": { - "debug": "^2.6.8", - "pkg-dir": "^1.0.0" + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "eslint-plugin-es": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.3.2.tgz", - "integrity": "sha512-xrdbConViY20DhGrt9FwjhDo4fr/9Yus2pYf0xJsdJaCcUzMq7+pAoNH7kSXF6V08bRHMpgDWclYbcr/Sn3hNg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.1.tgz", + "integrity": "sha512-5fa/gR2yR3NxQf+UXkeLeP8FBBl6tSgdrAz1+cF84v1FMM4twGwQoqTnn+QxFLcPOrF4pdKEJKDB/q9GoyJrCA==", "dev": true, "requires": { - "eslint-utils": "^1.3.0", + "eslint-utils": "^1.4.2", "regexpp": "^2.0.1" } }, "eslint-plugin-import": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", - "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", + "version": "2.18.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz", + "integrity": "sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==", "dev": true, "requires": { + "array-includes": "^3.0.3", "contains-path": "^0.1.0", - "debug": "^2.6.8", + "debug": "^2.6.9", "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" + "resolve": "^1.11.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "doctrine": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", @@ -2450,6 +2291,15 @@ "isarray": "^1.0.0" } }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -2462,6 +2312,46 @@ "strip-bom": "^3.0.0" } }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -2471,12 +2361,6 @@ "pify": "^2.0.0" } }, - "pify": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -2498,15 +2382,6 @@ "read-pkg": "^2.0.0" } }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -2516,65 +2391,71 @@ } }, "eslint-plugin-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz", - "integrity": "sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-9.1.0.tgz", + "integrity": "sha512-ZwQYGm6EoV2cfLpE1wxJWsfnKUIXfM/KM09/TlorkukgCAwmkgajEJnPCmyzoFPQQkmvo5DrW/nyKutNIw36Mw==", "dev": true, "requires": { - "eslint-plugin-es": "^1.3.1", + "eslint-plugin-es": "^1.4.0", "eslint-utils": "^1.3.1", - "ignore": "^4.0.2", + "ignore": "^5.1.1", "minimatch": "^3.0.4", - "resolve": "^1.8.1", - "semver": "^5.5.0" + "resolve": "^1.10.1", + "semver": "^6.1.0" }, "dependencies": { - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } } } }, "eslint-plugin-promise": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz", - "integrity": "sha512-Si16O0+Hqz1gDHsys6RtFRrW7cCTB6P7p3OJmKp3Y3dxpQE2qwOA7d3xnV+0mBmrPoi0RBnxlCKvqu70te6wjg==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", "dev": true }, "eslint-plugin-react": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", - "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", + "version": "7.14.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz", + "integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==", "dev": true, "requires": { "array-includes": "^3.0.3", "doctrine": "^2.1.0", "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.2" + "jsx-ast-utils": "^2.1.0", + "object.entries": "^1.1.0", + "object.fromentries": "^2.0.0", + "object.values": "^1.1.0", + "prop-types": "^15.7.2", + "resolve": "^1.10.1" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } } }, "eslint-plugin-standard": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.0.tgz", - "integrity": "sha512-OwxJkR6TQiYMmt1EsNRMe5qG3GsbjlcOhbGUBY4LtavF9DsLaTcoR+j2Tdjqi23oUwKNUqX7qcn5fPStafMdlA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", + "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", "dev": true }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -2582,32 +2463,35 @@ } }, "eslint-utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", - "dev": true + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", "dev": true, "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" } }, "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, "esquery": { @@ -2629,15 +2513,15 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "execa": { @@ -2655,45 +2539,10 @@ "strip-eof": "^1.0.0" } }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "expand-template": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", - "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" }, "ext-list": { "version": "2.2.2", @@ -2718,106 +2567,25 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "external-editor": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { "chardet": "^0.4.0", "iconv-lite": "^0.4.17", "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" }, "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "safer-buffer": ">= 2.1.2 < 3" } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", - "dev": true } } }, @@ -2832,24 +2600,18 @@ "yauzl": "2.4.1" }, "dependencies": { - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -2862,28 +2624,25 @@ "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-glob": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", - "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", + "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", "dev": true, "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2" } }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-levenshtein": { "version": "2.0.6", @@ -2891,10 +2650,14 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fast-plist": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/fast-plist/-/fast-plist-0.1.2.tgz", - "integrity": "sha1-pFr/NFGWAG1AbKbNzQX2kFHvNbg=" + "fastq": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", + "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", + "dev": true, + "requires": { + "reusify": "^1.0.0" + } }, "fd-slicer": { "version": "1.0.1", @@ -2914,13 +2677,12 @@ } }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "^2.0.1" } }, "file-uri-to-path": { @@ -2929,26 +2691,12 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "to-regex-range": "^5.0.1" } }, "find-root": { @@ -2958,29 +2706,62 @@ "dev": true }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, "requires": { - "locate-path": "^2.0.0" + "is-buffer": "~2.0.3" } }, "flat-cache": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.2.tgz", - "integrity": "sha512-KByBY8c98sLUAGpnmjEdWTrtrLZRtZdwds+kAL/ciFXTCb7AZgqKsAnVnYFQj1hxepwO8JKN/8AsRWwLq+RK0A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "del": "^3.0.0", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", "dev": true }, "forever-agent": { @@ -3000,15 +2781,6 @@ "mime-types": "^2.1.12" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -3025,27 +2797,13 @@ "universalify": "^0.1.0" } }, - "fs-extra-p": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-7.0.0.tgz", - "integrity": "sha512-5tg5jBOd0xIXjwj4PDnafOXL5TyPVzjxLby4DPKev53wurEXp7IsojBaD4Lj5M5w7jxw0pbkEU0fFEPmcKoMnA==", + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", "dev": true, "requires": { - "bluebird-lst": "^1.0.6", - "fs-extra": "^7.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } + "minipass": "^2.6.0" } }, "fs.realpath": { @@ -3054,18 +2812,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3103,9 +2849,9 @@ } }, "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, "get-func-name": { @@ -3126,12 +2872,6 @@ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -3159,31 +2899,22 @@ } }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "is-glob": "^4.0.1" } }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } }, "global-dirs": { "version": "0.1.1", @@ -3195,30 +2926,31 @@ } }, "globals": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", - "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "globby": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", - "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -3232,9 +2964,9 @@ } }, "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.0.tgz", + "integrity": "sha512-YlD4kdMqRCQHrhVdonet4TdRtv1/sZKepvoxNT4Nrhrp5HI8XFfc8kFlGlBn2myBo80aGp8Eft259mbcUJhgSg==", "dev": true, "requires": { "glob": "~7.1.1", @@ -3243,9 +2975,9 @@ }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -3274,29 +3006,56 @@ } } }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + } + } + }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true }, "grapheme-splitter": { "version": "1.0.4", @@ -3307,27 +3066,19 @@ "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4=", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, "handlebars": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", - "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "har-schema": { @@ -3337,9 +3088,9 @@ "dev": true }, "har-validator": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.2.tgz", - "integrity": "sha512-OFxb5MZXCUMx43X7O8LK4FKggEQx6yC5QPmOcBnYbJ9UjxEcMcrMbaR0af5HZpqeFopw2GwQRQi34ZXI7YLM5w==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { "ajv": "^6.5.5", @@ -3355,25 +3106,16 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, "has-unicode": { @@ -3381,54 +3123,37 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "highlight.js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz", - "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=", - "dev": true + "version": "9.17.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz", + "integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==", + "dev": true, + "requires": { + "handlebars": "^4.5.3" + } }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", "dev": true }, "http-signature": { @@ -3449,26 +3174,36 @@ "dev": true }, "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.0.tgz", + "integrity": "sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", - "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", "dev": true }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -3499,9 +3234,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.5", @@ -3564,26 +3299,11 @@ } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", - "dev": true - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", "dev": true }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3591,24 +3311,15 @@ "dev": true }, "is-buffer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", - "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", "dev": true }, "is-ci": { @@ -3620,44 +3331,10 @@ "ci-info": "^2.0.0" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, "is-extglob": { @@ -3684,9 +3361,9 @@ } }, "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -3703,39 +3380,21 @@ } }, "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", + "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==", "dev": true }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" }, "is-path-inside": { "version": "1.0.1", @@ -3751,82 +3410,60 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", "dev": true, "requires": { - "has": "^1.0.1" + "has": "^1.0.3" } }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true - }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "^1.0.1" } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -3838,10 +3475,10 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", "dev": true }, "isarray": { @@ -3850,9 +3487,9 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isbinaryfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.0.tgz", - "integrity": "sha512-RBtmso6l2mCaEsUvXngMTIjg3oheXo0MgYzzfT6sk44RYggPnm9fT+cQJAmzRnJIxPHXg9FZglqDJGW28dvcqA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.3.tgz", + "integrity": "sha512-GQ9Gjhp3AsEbo8/L/pA+MYl/c4hRm5O/+uCkF4LMx1a556Wh4/d75H13qu9LldmhU4yKnlfNKBmEcCaze3b2Gw==", "dev": true }, "isexe": { @@ -3861,94 +3498,31 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "istanbul": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", - "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", - "dev": true, - "requires": { - "abbrev": "1.0.x", - "async": "1.x", - "escodegen": "1.8.x", - "esprima": "2.7.x", - "glob": "^5.0.15", - "handlebars": "^4.0.1", - "js-yaml": "3.x", - "mkdirp": "0.5.x", - "nopt": "3.x", - "once": "1.x", - "resolve": "1.1.x", - "supports-color": "^3.1.0", - "which": "^1.1.1", - "wordwrap": "^1.0.0" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, "jquery": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", - "integrity": "sha1-lYzinoHJeQ8xvneS311NlfxX+8o=" + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz", + "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==" }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", - "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", - "esprima": "^3.1.1" + "esprima": "^4.0.0" } }, "jsbn": { @@ -3957,6 +3531,12 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -3972,8 +3552,12 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-schema-typed": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz", + "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -3988,9 +3572,9 @@ "dev": true }, "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -4026,48 +3610,49 @@ } }, "jsx-ast-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", - "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.2.3.tgz", + "integrity": "sha512-EdIHFMm+1BPynpKOpdPqiOsvnIrInRGJD7bzPZdPkjitQEqpdpUuFpq4T0npZFKTiB3RhWFdGN+oqOJIdhDhQA==", "dev": true, "requires": { - "array-includes": "^3.0.3" + "array-includes": "^3.0.3", + "object.assign": "^4.1.0" } }, "keyboardevent-from-electron-accelerator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keyboardevent-from-electron-accelerator/-/keyboardevent-from-electron-accelerator-1.1.0.tgz", - "integrity": "sha1-MkYU9uM0kMN//Fvlh2s+hf4iPIQ=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/keyboardevent-from-electron-accelerator/-/keyboardevent-from-electron-accelerator-2.0.0.tgz", + "integrity": "sha512-iQcmNA0M4ETMNi0kG/q0h/43wZk7rMeKYrXP7sqKIJbHkTU8Koowgzv+ieR/vWJbOwxx5nDC3UnudZ0aLSu4VA==", "dev": true }, "keyboardevents-areequal": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz", - "integrity": "sha1-iBkexzjOn3WRwl6QVt6Si0AncZQ=", + "integrity": "sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==", "dev": true }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "json-buffer": "3.0.0" } }, "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", "dev": true, "requires": { - "package-json": "^4.0.0" + "package-json": "^6.3.0" } }, "lazy-val": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.3.tgz", - "integrity": "sha512-pjCf3BYk+uv3ZcPzEVM0BFvO9Uw58TmlrU0oG5tTrr9Kcid3+kdKxapH8CjdYmVa2nO5wOoZn2rdvZx2PKj/xg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", + "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", "dev": true }, "lazystream": { @@ -4079,15 +3664,6 @@ "readable-stream": "^2.0.5" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -4109,29 +3685,21 @@ "pify": "^2.0.0", "pinkie-promise": "^2.0.0", "strip-bom": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "lodash.assign": { @@ -4143,7 +3711,7 @@ "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, "requires": { "chalk": "^2.0.1" @@ -4185,61 +3753,26 @@ } }, "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", "requires": { - "pify": "^3.0.0" + "semver": "^6.0.0" }, "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "mem": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", - "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^1.0.0", - "p-is-promise": "^1.1.0" - } - }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -4267,75 +3800,64 @@ } }, "merge2": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", - "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", "dev": true }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", - "dev": true - } + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" } }, "mime": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", - "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", "dev": true }, "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", + "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" }, "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "version": "2.1.25", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", + "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", "dev": true, "requires": { - "mime-db": "~1.37.0" + "mime-db": "1.42.0" } }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.0.0.tgz", + "integrity": "sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ==" + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "requires": { + "dom-walk": "^0.1.0" + } }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" } @@ -4345,31 +3867,32 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" }, "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true } } }, - "mkdir-p": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mkdir-p/-/mkdir-p-0.0.7.tgz", - "integrity": "sha1-JMXb4m2jqZ7xWKHu+aXC3Z3laDw=" + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } }, "mkdirp": { "version": "0.5.1", @@ -4387,37 +3910,40 @@ } }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha1-bYrlCPWRZ/lA8rWzxKYSrlDJCuY=", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz", + "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==", "dev": true, "requires": { + "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", + "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.2", + "find-up": "3.0.0", + "glob": "7.1.3", "growl": "1.10.5", - "he": "1.1.1", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", "minimatch": "3.0.4", "mkdirp": "0.5.1", - "supports-color": "5.4.0" + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.0", + "yargs-parser": "13.1.1", + "yargs-unparser": "1.6.0" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -4428,16 +3954,16 @@ "path-is-absolute": "^1.0.0" } }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -4451,9 +3977,9 @@ "integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE=" }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mute-stream": { "version": "0.0.7", @@ -4461,44 +3987,38 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, - "nan": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", - "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha1-uHqKpPwN6P5r6IiVs4mD/yZb0Rk=", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", - "dev": true - } + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" } }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "napi-build-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz", + "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -4506,37 +4026,46 @@ "dev": true }, "node-abi": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.1.tgz", - "integrity": "sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.13.0.tgz", + "integrity": "sha512-9HrZGFVTR5SOu3PZAnAY2hLO36aW1wmA+FDsVkr85BTST32TLCA1H/AEcatVRAsWLyXS3bqUDYCAjq5/QGuSTA==", "requires": { "semver": "^5.4.1" } }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, "node-gyp": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", - "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-6.0.1.tgz", + "integrity": "sha512-udHG4hGe3Ji97AYJbJhaRwuSOuQO7KHnE4ZPH3Sox3tjRZ+bkBsDvfZ7eYA1qwD8eLWr//193x806ss3HFTPRw==", "dev": true, "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "npmlog": "^4.1.2", + "request": "^2.88.0", + "rimraf": "^2.6.3", + "semver": "^5.7.1", + "tar": "^4.4.12", + "which": "^1.3.1" }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -4547,11 +4076,14 @@ "path-is-absolute": "^1.0.0" } }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } } } }, @@ -4561,22 +4093,23 @@ "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" }, "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "requires": { - "abbrev": "1" + "abbrev": "1", + "osenv": "^0.1.4" } }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } @@ -4590,12 +4123,24 @@ "remove-trailing-separator": "^1.0.1" } }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, "npm-install-package": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/npm-install-package/-/npm-install-package-2.1.0.tgz", "integrity": "sha1-1+/jz816sAYUuJbqUxGdyaslkSU=", "dev": true }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -4608,7 +4153,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { "are-we-there-yet": "~1.1.2", "console-control-strings": "~1.1.0", @@ -4631,11 +4176,26 @@ "throttleit": "0.0.2" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, @@ -4655,50 +4215,82 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" }, "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true } } }, - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", - "dev": true + "object.entries": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz", + "integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "object.fromentries": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz", + "integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", "dev": true, "requires": { - "isobject": "^3.0.0" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", "dev": true, "requires": { - "isobject": "^3.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" } }, "once": { @@ -4728,54 +4320,46 @@ } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } + "word-wrap": "~1.2.3" } }, "ora": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-3.0.0.tgz", - "integrity": "sha512-LBS97LFe2RV6GJmXBi6OKcETKyklHNMV0xw7BtsVn2MlsgsydyZetSCbCANr+PFLmDyv4KV88nn0eCKza665Mg==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", "dev": true, "requires": { - "chalk": "^2.3.1", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", - "cli-spinners": "^1.1.0", + "cli-spinners": "^2.0.0", "log-symbols": "^2.2.0", - "strip-ansi": "^4.0.0", + "strip-ansi": "^5.2.0", "wcwidth": "^1.0.1" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } } } @@ -4783,48 +4367,8 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", - "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", - "dev": true, - "requires": { - "execa": "^0.10.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true }, "os-tmpdir": { "version": "1.0.2", @@ -4834,17 +4378,17 @@ "osenv": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha1-hc36+uso6Gd/QW4odZK18/SepBA=", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "requires": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" } }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true }, "p-finally": { @@ -4853,66 +4397,56 @@ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, - "p-is-promise": { - "version": "1.1.0", - "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", - "dev": true - }, "p-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", - "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "requires": { + "p-try": "^2.0.0" + } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" } }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "dev": true - }, "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - } - }, - "parse-color": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz", - "integrity": "sha1-e3SLlag/A/FqlPU15S1/PZRlhhk=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", "dev": true, "requires": { - "color-convert": "~0.5.0" + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" }, "dependencies": { - "color-convert": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", - "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=", + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -4922,18 +4456,6 @@ "error-ex": "^1.2.0" } }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -4957,19 +4479,16 @@ "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true }, "pathval": { "version": "1.1.0", @@ -4988,10 +4507,16 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "picomatch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", + "dev": true + }, "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { @@ -5010,25 +4535,26 @@ } }, "pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-3.1.0.tgz", + "integrity": "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==", "dev": true, "requires": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" + "find-up": "^3.0.0", + "load-json-file": "^5.2.0" }, "dependencies": { "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", + "graceful-fs": "^4.1.15", "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" } }, "parse-json": { @@ -5041,11 +4567,23 @@ "json-parse-better-errors": "^1.0.1" } }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true } } }, @@ -5061,84 +4599,85 @@ } }, "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", "dev": true, "requires": { - "find-up": "^1.0.0" + "find-up": "^2.1.0" }, "dependencies": { "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^2.0.0" } }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "pinkie-promise": "^2.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true } } }, "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "requires": { - "find-up": "^2.1.0" - } - }, - "plist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz", - "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==", - "dev": true, - "requires": { - "base64-js": "^1.2.3", - "xmlbuilder": "^9.0.7", - "xmldom": "0.1.x" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "requires": { + "find-up": "^3.0.0" + } }, "prebuild-install": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-4.0.0.tgz", - "integrity": "sha512-7tayxeYboJX0RbVzdnKyGl2vhQRWr6qfClEXDhOkXjuaOKCw2q8aiuFhONRYVsG/czia7KhpykIlI2S2VaPunA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz", + "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==", "requires": { "detect-libc": "^1.0.3", - "expand-template": "^1.0.2", + "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.0", "mkdirp": "^0.5.1", - "node-abi": "^2.2.0", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", "noop-logger": "^0.1.1", "npmlog": "^4.0.1", - "os-homedir": "^1.0.1", - "pump": "^2.0.1", - "rc": "^1.1.6", - "simple-get": "^2.7.0", - "tar-fs": "^1.13.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0", "which-pm-runs": "^1.0.0" }, @@ -5157,9 +4696,9 @@ "dev": true }, "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, "pretty-bytes": { @@ -5172,15 +4711,20 @@ "meow": "^3.1.0" } }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "progress-stream": { @@ -5194,13 +4738,14 @@ } }, "prop-types": { - "version": "15.6.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", - "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", "dev": true, "requires": { - "loose-envify": "^1.3.1", - "object-assign": "^4.1.1" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" } }, "pseudomap": { @@ -5210,15 +4755,15 @@ "dev": true }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", "dev": true }, "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -5227,8 +4772,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "pupa": { "version": "1.0.0", @@ -5271,70 +4815,56 @@ } } }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==", + "dev": true + }, "read-config-file": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-3.2.1.tgz", - "integrity": "sha512-yW4hZZXdNN+Paij5JVAiTv1lUsAN5QRBU5NqotQqwYdVkUczSmDzm66VLu0eojiZt2zFeYptTFDAYlalDGuHdA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-5.0.0.tgz", + "integrity": "sha512-jIKUu+C84bfnKxyJ5j30CxCqgXWYjZLXuVE/NYlMEpeni+dhESgAeZOZd0JZbg1xTkMmnCdxksDoarkOyfEsOg==", "dev": true, "requires": { - "ajv": "^6.7.0", - "ajv-keywords": "^3.2.0", - "bluebird-lst": "^1.0.6", - "dotenv": "^6.2.0", - "dotenv-expand": "^4.2.0", - "fs-extra-p": "^7.0.0", - "js-yaml": "^3.12.1", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^8.1.0", + "js-yaml": "^3.13.1", "json5": "^2.1.0", - "lazy-val": "^1.0.3" + "lazy-val": "^1.0.4" }, "dependencies": { - "ajv": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz", - "integrity": "sha512-XDN92U311aINL77ieWHmqCcNlwjoP5cHXDxIxbf2MaPYuCXOHS7gHH8jktxeK5omgd52XbSTX6a4Piwd1pQmzA==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "js-yaml": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", - "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } } } }, "read-package-json": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz", - "integrity": "sha1-LoLr2fYTuqbS6+Oqcs7+P2jkH0o=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", + "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", "dev": true, "requires": { "glob": "^7.1.1", "graceful-fs": "^4.1.2", "json-parse-better-errors": "^1.0.1", "normalize-package-data": "^2.0.0", - "slash": "^1.0.0" + "npm-normalize-package-bin": "^1.0.0" }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -5368,12 +4898,6 @@ "pify": "^2.0.0", "pinkie-promise": "^2.0.0" } - }, - "pify": { - "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true } } }, @@ -5409,16 +4933,16 @@ } }, "readable-stream": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.11.tgz", - "integrity": "sha1-B5azH412iAB/8Lk6gIjTSqF8D3I=", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", - "inherits": "~2.0.1", + "inherits": "~2.0.3", "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "safe-buffer": "~5.0.1", - "string_decoder": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, @@ -5447,16 +4971,6 @@ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -5464,22 +4978,22 @@ "dev": true }, "registry-auth-token": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", "dev": true, "requires": { - "rc": "^1.1.6", + "rc": "^1.2.8", "safe-buffer": "^5.0.1" } }, "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", "dev": true, "requires": { - "rc": "^1.0.1" + "rc": "^1.2.8" } }, "remove-trailing-separator": { @@ -5488,18 +5002,6 @@ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, "repeating": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", @@ -5535,14 +5037,6 @@ "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } } }, "require-directory": { @@ -5552,34 +5046,24 @@ "dev": true }, "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } - }, "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", + "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "resolve-url": { @@ -5588,6 +5072,15 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -5598,31 +5091,31 @@ "signal-exit": "^3.0.2" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, "rgb2hex": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.1.9.tgz", - "integrity": "sha512-32iuQzhOjyT+cv9aAFRBJ19JgHwzQwbjUhH3Fj2sWW2EEGAW8fpFrDFP5ndoKDxJaLO06x1hE3kyuIFrUQtybQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.1.10.tgz", + "integrity": "sha512-vKz+kzolWbL3rke/xeTE2+6vHmZnNxGyDnaVW4OckntAIcc7DcZzWkQSfxMDwqHS8vhgySnIFyBUH7lIk6PxvQ==", "dev": true }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", "dev": true, "requires": { "glob": "^7.1.3" }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -5666,38 +5159,29 @@ } }, "rxjs": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", - "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", "dev": true, "requires": { - "symbol-observable": "1.0.1" + "tslib": "^1.9.0" } }, "safe-buffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", - "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "sanitize-filename": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz", - "integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", "dev": true, "requires": { "truncate-utf8-bytes": "^1.0.0" @@ -5706,12 +5190,12 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "semver-diff": { "version": "2.1.0", @@ -5727,29 +5211,6 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -5777,9 +5238,9 @@ }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -5803,11 +5264,11 @@ "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" }, "simple-get": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", - "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", "requires": { - "decompress-response": "^3.3.0", + "decompress-response": "^4.2.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } @@ -5822,130 +5283,28 @@ } }, "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "requires": { - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "dependencies": { "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" } } }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } - }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -5963,18 +5322,18 @@ } }, "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "dev": true, "requires": { - "atob": "^2.1.1", + "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", @@ -5982,21 +5341,13 @@ } }, "source-map-support": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", - "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "source-map-url": { @@ -6016,21 +5367,27 @@ "rxjs": "^6.3.1" }, "dependencies": { - "rxjs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", - "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { - "tslib": "^1.9.0" + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, "spdx-correct": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", - "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -6054,19 +5411,19 @@ } }, "spdx-license-ids": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", - "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "spectron": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/spectron/-/spectron-5.0.0.tgz", - "integrity": "sha512-wJrFe8EZ7xvarYawBPd1pDegmSz81U1jG0rSCx+yXqD1TISUH9ASB21KysLXkPylAnc2vhbpGiWQxrqVFtsiJg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/spectron/-/spectron-8.0.0.tgz", + "integrity": "sha512-MI9+lAamDnw7S0vKaxXjU3g5qaW5KANaFLc+Hgq+QmMCkQbZLt6ukFFGfalmwIuYrmq+yWQPCD4CXgt3VSHrLA==", "dev": true, "requires": { "dev-null": "^0.1.1", - "electron-chromedriver": "~3.0.0", + "electron-chromedriver": "^6.0.0", "request": "^2.87.0", "split": "^1.0.0", "webdriverio": "^4.13.0" @@ -6087,15 +5444,6 @@ "through": "2" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6103,9 +5451,9 @@ "dev": true }, "sshpk": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", - "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -6120,38 +5468,38 @@ } }, "standard": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/standard/-/standard-12.0.1.tgz", - "integrity": "sha512-UqdHjh87OG2gUrNCSM4QRLF5n9h3TFPwrCNyVlkqu31Hej0L/rc8hzKqVvkb2W3x0WMq7PzZdkLfEcBhVOR6lg==", - "dev": true, - "requires": { - "eslint": "~5.4.0", - "eslint-config-standard": "12.0.0", - "eslint-config-standard-jsx": "6.0.2", - "eslint-plugin-import": "~2.14.0", - "eslint-plugin-node": "~7.0.1", - "eslint-plugin-promise": "~4.0.0", - "eslint-plugin-react": "~7.11.1", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/standard/-/standard-13.1.0.tgz", + "integrity": "sha512-h3NaMzsa88+/xtjXCMvdn6EWWdlodsI/HvtsQF+EGwrF9kVNwNha9TkFABU6bSBoNfC79YDyIAq9ekxOMBFkuw==", + "dev": true, + "requires": { + "eslint": "~6.1.0", + "eslint-config-standard": "13.0.1", + "eslint-config-standard-jsx": "7.0.0", + "eslint-plugin-import": "~2.18.0", + "eslint-plugin-node": "~9.1.0", + "eslint-plugin-promise": "~4.2.1", + "eslint-plugin-react": "~7.14.2", "eslint-plugin-standard": "~4.0.0", - "standard-engine": "~9.0.0" + "standard-engine": "~11.0.1" } }, "standard-engine": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-9.0.0.tgz", - "integrity": "sha512-ZfNfCWZ2Xq67VNvKMPiVMKHnMdvxYzvZkf1AH8/cw2NLDBm5LRsxMqvEJpsjLI/dUosZ3Z1d6JlHDp5rAvvk2w==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-11.0.1.tgz", + "integrity": "sha512-WZQ5PpEDfRzPFk+H9xvKVQPQIxKnAQB2cb2Au4NyTCtdw5R0pyMBUZLbPXyFjnlhe8Ae+zfNrWU4m6H5b7cEAg==", "dev": true, "requires": { - "deglob": "^2.1.0", - "get-stdin": "^6.0.0", + "deglob": "^3.0.0", + "get-stdin": "^7.0.0", "minimist": "^1.1.0", - "pkg-conf": "^2.0.0" + "pkg-conf": "^3.1.0" }, "dependencies": { "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", "dev": true }, "minimist": { @@ -6163,32 +5511,11 @@ } }, "stat-mode": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", - "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.3.0.tgz", + "integrity": "sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng==", "dev": true }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -6199,12 +5526,32 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", - "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.0.1" + "safe-buffer": "~5.1.0" } }, "strip-ansi": { @@ -6251,6 +5598,23 @@ "dev": true, "requires": { "debug": "^2.2.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "supports-color": { @@ -6260,40 +5624,60 @@ "dev": true, "requires": { "has-flag": "^3.0.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - } } }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", - "dev": true - }, "table": { - "version": "4.0.3", - "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "is-fullwidth-code-point": { @@ -6302,117 +5686,118 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } } } }, "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", "dev": true, "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } } }, "tar-fs": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", - "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", + "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" - }, - "dependencies": { - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } + "pump": "^3.0.0", + "tar-stream": "^2.0.0" } }, "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", + "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", + "bl": "^3.0.0", + "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" }, "dependencies": { - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, "readable-stream": { - "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", "requires": { - "safe-buffer": "~5.1.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } } } }, "temp-file": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.2.tgz", - "integrity": "sha512-FGKccAW0Mux9hC/2bdUIe4bJRv4OyVo4RpVcuplFird1V/YoplIFbnPZjfzbJSf/qNvRZIRB9/4n/RkI0GziuQ==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.6.tgz", + "integrity": "sha512-7TPldi8QJqRlPIF/Y33mVvo8+xDfi6+aVTCK4CrCaLqCoaOnVtf3SA4hCU0T5nhYDdOC7erw7o2uWfvijlk4Ug==", "dev": true, "requires": { "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.6", - "fs-extra-p": "^7.0.0" + "fs-extra": "^8.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } } }, "term-size": { @@ -6430,6 +5815,22 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, "throttleit": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", @@ -6487,12 +5888,6 @@ } } }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -6505,37 +5900,22 @@ "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "tough-cookie": { @@ -6580,9 +5960,9 @@ } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, "tunnel-agent": { @@ -6614,36 +5994,33 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.3.tgz", + "integrity": "sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==", "dev": true, "optional": true, "requires": { - "commander": "~2.17.1", + "commander": "~2.20.3", "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true, - "optional": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } } }, "unc-path-regex": { @@ -6652,41 +6029,6 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, "uniq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", @@ -6705,49 +6047,9 @@ "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, "unused-filename": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-1.0.0.tgz", @@ -6757,52 +6059,30 @@ "path-exists": "^3.0.0" } }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true - }, "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", + "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", "dev": true, "requires": { - "boxen": "^1.2.1", + "boxen": "^3.0.0", "chalk": "^2.0.1", - "configstore": "^3.0.0", + "configstore": "^4.0.0", + "has-yarn": "^2.1.0", "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", + "is-ci": "^2.0.0", "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", + "is-npm": "^3.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", "semver-diff": "^2.0.0", "xdg-basedir": "^3.0.0" - }, - "dependencies": { - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "dev": true, - "requires": { - "ci-info": "^1.5.0" - } - } } }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", - "dev": true, + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "requires": { "punycode": "^2.1.0" } @@ -6832,20 +6112,14 @@ } }, "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", "dev": true, "requires": { - "prepend-http": "^1.0.1" + "prepend-http": "^2.0.0" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha1-1QyMrHmhn7wg8pEfVuuXP04QBw8=", - "dev": true - }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -6858,9 +6132,15 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", "dev": true }, "validate-npm-package-license": { @@ -6900,9 +6180,9 @@ "dev": true }, "webdriverio": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-4.14.0.tgz", - "integrity": "sha512-642Iqp9en2hvuVINkTfQvWoQCaLb6zJyLHgQFUFLx7s+8l8GnrHzMjkv5DbecZHwnBkhybpphbTW7k0B2ARH5A==", + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-4.14.4.tgz", + "integrity": "sha512-Knp2vzuzP5c5ybgLu+zTwy/l1Gh0bRP4zAr8NWcrStbuomm9Krn9oRF0rZucT6AyORpXinETzmeowFwIoo7mNA==", "dev": true, "requires": { "archiver": "~2.1.0", @@ -6936,9 +6216,9 @@ "dev": true }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -6955,12 +6235,6 @@ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "supports-color": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.0.1.tgz", @@ -6979,9 +6253,9 @@ "dev": true }, "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -7048,19 +6322,90 @@ } } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "wrappy": { @@ -7069,22 +6414,23 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" } }, "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha1-H/YVdcLipOjlENb6TiQ8zhg5mas=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.1.tgz", + "integrity": "sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw==", "requires": { - "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, "xdg-basedir": { @@ -7094,37 +6440,24 @@ "dev": true }, "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "requires": { "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - }, - "dependencies": { - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" - } + "xmlbuilder": "~11.0.0" } }, "xmlbuilder": { - "version": "9.0.7", - "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true - }, - "xmldom": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", - "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", - "dev": true + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true }, "y18n": { "version": "4.0.0", @@ -7139,39 +6472,34 @@ "dev": true }, "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", + "cliui": "^5.0.0", "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", + "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -7179,59 +6507,32 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { + "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "strip-ansi": "^5.1.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } } } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -7239,13 +6540,24 @@ }, "dependencies": { "camelcase": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", - "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true } } }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + }, "yauzl": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", diff --git a/package.json b/package.json index bbde984..c1cf23a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "MZD-AIO-TI", "productName": "MZD All In One Tweaks Installer", "description": "An Installer/Uninstaller for Over 50 System Tweaks for the Mazda MZD Infotainment System.", - "version": "2.8.4", + "version": "2.8.5", "homepage": "http://mazdatweaks.com", "license": "GPL-3.0", "main": "main.js", @@ -14,13 +14,13 @@ }, "repository": { "type": "git", - "url": "https://github.com/Trevelopment/MZD-AIO" + "url": "https://gitlab.com/Trezdog44/MZD-AIO-TI" }, "bugs": { - "url": "https://github.com/Trevelopment/MZD-AIO/issues" + "url": "https://gitlab.com/Trezdog44/MZD-AIO-TI/issues" }, "engines": { - "node": "^10" + "node": "^13" }, "keywords": [ "Mazda", @@ -53,12 +53,13 @@ "build:win32": "npm run prebuild && build --win --ia32 && npm run postbuild && npm run win32copy", "build:linux:x64": "npm run prebuild && build --linux deb AppImage --x64 && npm run postbuild", "build:linux:deb": "./scripts/build_linux_deb.sh", - "win32copy": " mv ./releases/MZD-AIO-TI_Setup_2.8.4.exe ./releases/MZD-AIO-TI_Setup_2.8.4_Win32.exe && mv ./releases/MZD-AIO-TI_Setup_2.8.4.exe.blockmap ./releases/MZD-AIO-TI_Setup_2.8.4_Win32.exe.blockmap", + "win32copy": " mv ./releases/MZD-AIO-TI_Setup_2.8.5.exe ./releases/MZD-AIO-TI_Setup_2.8.5_Win32.exe && mv ./releases/MZD-AIO-TI_Setup_2.8.5.exe.blockmap ./releases/MZD-AIO-TI_Setup_2.8.5_Win32.exe.blockmap", "build": "build", "release": "build", "postbuild": "node build/target.js --clean", "xinstall": "cd app && ncu -u --packageFile package.json && ncu -a --packageFile package.json && npm i && cd .. && ncu -u --packageFile package.json && ncu -a --packageFile package.json && npm i", - "postinstall": "electron-builder install-app-deps" + "postinstall": "install-app-deps && cd app && sh ../node_modules/.bin/electron-rebuild && cd .. && sh ./node_modules/.bin/electron-rebuild", + "dist": "electron-builder" }, "standard": { "globals": [ @@ -86,12 +87,13 @@ "/app/mzd/", "/app/gui/", "/app/views/Photojoiner_files/", - "/app/", - "vendor" + "vendor", + "old_tweak_files", + "scripts" ] }, "jshintConfig": { - "esversion": 6 + "esversion": 8 }, "build": { "appId": "com.trevelopment.mzd-aio-ti", @@ -112,7 +114,7 @@ "owner": "trevelopment", "repo": "MZD-AIO-TI", "package": "MZD-AIO-MAC", - "user": "trevelopment", + "user": "trevelopment" } }, "dmg": { @@ -142,7 +144,7 @@ "owner": "aio", "repo": "aio", "package": "aio", - "user": "Trezdog44", + "user": "Trezdog44" } }, "win": { @@ -154,7 +156,7 @@ "owner": "aio", "repo": "aio", "package": "aio", - "user": "Trezdog44", + "user": "Trezdog44" } }, "directories": { @@ -162,39 +164,40 @@ }, "nsis": { "artifactName": "${productName}_Setup_${version}.${ext}" - } + }, + "forceCodeSigning": false }, "devDependencies": { - "async": "^2.6.2", + "async": "^3.1.0", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", - "dependency-check": "^3.3.0", + "dependency-check": "^4.1.0", "devtron": "^1", - "electron": "4.0.3", - "electron-builder": "^20.38.5", - "electron-debug": "^2.1.0", - "electron-is-dev": "^1.0", - "electron-rebuild": "^1.8.4", - "istanbul": "^0.4", - "mocha": "^5.2.0", - "rimraf": "^2.6.3", + "electron": "^6.1.7", + "electron-builder": "^21.2.0", + "electron-debug": "^3.0.1", + "electron-is-dev": "^1.1.0", + "electron-rebuild": "^1.8.8", + "mocha": "^6.2.2", + "rimraf": "^3.0.0", "shelljs": "^0.8.3", - "spectron": "^5.0.0", - "standard": "^12.0.1" + "spectron": "^8.0.0", + "standard": "^13.1.0" }, "dependencies": { "appender": "^0.0.2", - "bluebird-lst": "^1.0.6", - "copy-dir": "^0.4.0", + "bluebird-lst": "^1.0.9", + "copy-dir": "^1.2.0", "crlf": "^1.1.1", - "drivelist": "^6.4.6", - "electron-context-menu": "^0.10.1", + "drivelist": "^8.0.9", + "electron-context-menu": "^0.14.0", "electron-image-resize": "^1.2.4", - "electron-store": "^2.0.0", + "electron-store": "^4.0.0", "extract-zip": "^1.6.7", - "jquery": "^3.3.1", + "global": "^4.3.2", + "jquery": "^3.4.1", "mkdirp": "^0.5.1", - "node-abi": "^2.7.1", - "xml2js": "^0.4.19" + "node-abi": "^2.13.0", + "xml2js": "^0.4.23" } }