/* * File Manager NotePad * * Licensed Virtual the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License * for the specific language governing permissions and limitations under the License. * * Change History: * * Date Who What * ---- --- ---- * 07Oct2025 thebearmay Add the Utilities Page * Fixed the 500 error when exiting * 29Nov2025 getHubFiles() error */ //#include thebearmay.uiInputElements static String version() { return '1.0.4' } definition ( name: "fmNotePad", namespace: "thebearmay", author: "Jean P. May, Jr.", description: "File Manager Notepad - Utility to edit small text files in FM", category: "Utility", importUrl: "https://raw.githubusercontent.com/thebearmay/hubitat/main/apps/fmNotepad.groovy", installOnOpen: true, oauth: false, singleThreaded: true, iconUrl: "", iconX2Url: "" ) preferences { page name: "decisionPage" page name: "mainPage" page name: "uiPage" } mappings { } def installed() { // log.trace "installed()" state?.isInstalled = true initialize() } def updated(){ // log.trace "updated()" if(!state?.isInstalled) { state?.isInstalled = true } if(debugEnable) runIn(1800,logsOff) } def initialize(){ app.removeSetting('fileText') app.removeSetting('fName') app.removeSetting('saveName') } void logsOff(){ app.updateSetting("debugEnable",[value:"false",type:"bool"]) } def decisionPage(){ dynamicPage (name: "decisionPage") { section("") { if(!page2Def) mainPage() else uiPage() } } } def mainPage(){ dynamicPage (name: "mainPage", title: "

FM Notepad v${version()}

", install: true, uninstall: true) { section(""){ fList = listFiles().fList settings.each { if(it.key.startsWith('sA')) app.removeSetting("${it.key}") } String p2 = getInputElemStr([name:"utilPage",type:"href",icon:[name:"build"],title:" ",destPage:"uiPage",width:"2em",radius:"15px", hoverText:"File Utilities"]) String fElem = getInputElemStr( [name:"fName", type:"enum", title:"Open File", options:fList, multiple:false, width:"15em", background:"#ADD8E6", radius:"15px"]) String saveBtn = getInputElemStr( [name:"saveBtn", type:"button", title:"Save As", multiple:false, width:"5em", background:"#FF000A", radius:"15px"]) String saveName = getInputElemStr( [name:"saveFileName", type:"text", title:"Save as Name",multiple:false, width:"15em", background:"#ADD8E6", radius:"15px", defaultValue:fName]) String tStr = "${ttStyleStr}
" if((!saveFileName || saveFileName == null || saveFileName == 'null') && fName != null ){ app.updateSetting('saveFileName',[value:"$fName",type:'text']) paragraph "" } if(fName != null) { if(fileText && state.lastFile == fName) fBuff = fileText else { state.lastFile = fName app.removeSetting('fileText') app.updateSetting('saveFileName',[value:"$fName",type:'text']) fBuff = new String(downloadHubFile("${fName}"), "UTF-8") app.updateSetting('fileText',[value:"""${fBuff}""",type:'text']) saveName = getInputElemStr( [name:"saveFileName", type:"text", title:"Save as Name",multiple:false, width:"15em", background:"#ADD8E6", radius:"15px", defaultValue:fName]) tStr = "${ttStyleStr}
${fElem}${saveName}${p2}
${saveBtn}
" } String fData = getInputElemStr( [name:"fileText", type:"textarea", title:"File Content", height:"60vh", background:"#E3E3E3", radius:"15px", defaultValue:"""${fBuff}"""]) tStr +="" } else if(!fName ){ if(saveFileName == state.lastFile) { app.updateSetting('saveFileName',[value:'newFile.txt',type:'text']) app.removeSetting('fileText') } String newBtn = getInputElemStr( [name:"newFileBtn", type:"button", title:"Create New File", multiple:false, width:"12em", background:"#00FF0A", radius:"15px"]) saveName = getInputElemStr( [name:"saveFileName", type:"text", title:"Save as Name",multiple:false, width:"15em", background:"#ADD8E6", radius:"15px", defaultValue:'newFile.txt']) tStr = "${ttStyleStr}
${fElem}${saveName}${p2}
${saveBtn}
${fData}
${saveBtn}
" } else if(!saveFileName || saveFileName == null || saveFileName == 'null'){ fBuff = '' app.removeSetting('fileText') } tStr += "
${fElem}${saveName}${p2}
${newBtn}
" paragraph tStr if(state.execSave) { state.execSave = false saveFiles("${saveFileName}") paragraph "" } if(state.newFile) { state.newFile = false app.updateSetting('fileText',[value:' ',type:'text']) retName = saveFiles("${saveFileName}") app.updateSetting('fName',[value:"${retName}",type:'text']) paragraph "" } } } } def uiPage(){ dynamicPage (name: "uiPage", title: "

FM Notepad v${version()}

", install: true, uninstall: true) { section(""){ String p1 = getInputElemStr([name:"utilPage",type:"href",icon:[name:"create"],title:" ",destPage:"mainPage",width:"2em",radius:"15px", hoverText:" Editor Page"]) paragraph "${ttStyleStr}
${p1}
" fList = listFiles().fList paragraph listTable() if(state.btnEdit){ state.btnEdit = false inx = appLocation().lastIndexOf("/") paragraph "" } } } } String listTable() { fList = listFiles().fList ArrayList tHead = ["","","","Name","Rename/Copy to",""] String X = "" String O = "" String settingsIcon = "settings_applications" String removeIcon = "" String str = "" str += "
" + "" tHead.each { str += "" } str += "" int tSize=0 fList.each{ if(it.size() > tSize) tSize = it.size() } int rowNum = 0 fList.each { if(rowNum % 2 == 1) rColor = '#ffffff' else rColor = '#f0f0f0' rowNum++ editIcon = getInputElemStr([name:"edit${it}",type:"button",icon:[name:"edit"],title:" ", width:"2.5em",radius:"15px", hoverText:" Edit "]) delIcon = getInputElemStr([name:"del${it}",type:"button",icon:[name:"he-bin"],title:" ", width:"2.5em",radius:"15px", hoverText:" Delete "]) copyIcon = getInputElemStr([name:"copy${it}",type:"button",icon:[name:"content_copy"],title:" ", width:"2.5em",radius:"15px", hoverText:" Copy "]) renIcon = getInputElemStr([name:"ren${it}",type:"button",icon:[name:"autorenew"],title:" ", width:"3em",radius:"15px", hoverText:" Rename "]) target = getInputElemStr( [name:"sA${it}", type:"text", title:" ",multiple:false, width:"${tSize*0.55}em", background:"#ADD8E6", radius:"15px", defaultValue:"${it}"]) str += "" } String defPage = getInputElemStr([name:"page2Def",type:"bool",title:"Make this the Default Page",background:"#ADD8E6", width:"20em",radius:"15px", hoverText:" Use as the starting page instead of the editor "]) str += "
${it}
${editIcon}${copyIcon}${renIcon}${it}${target}${delIcon}
${defPage}
" return str } @SuppressWarnings('unused') HashMap listFiles(retType='nameOnly'){ fileList = [] json=getHubFiles() json.each { if(it.type == 'file') fileList << it.name.trim() } if(debugEnabled) log.debug fileList.sort() if(retType == 'json') return [jStr: json] else return [fList: fileList.sort()] } String toCamelCase(init) { if (init == null) return null; while(init.contains(' ')){ init = init.replace(' ', ' ') } String ret = "" List word = init.split(" ") if(word.size == 1) return init word.each{ ret+=Character.toUpperCase(it.charAt(0)) ret+=it.substring(1).toLowerCase() } ret="${Character.toLowerCase(ret.charAt(0))}${ret.substring(1)}" if(debugEnabled) log.debug "toCamelCase return $ret" return ret; } String saveFiles(fName2){ if(!saveFileName || saveFileName == null || saveFileName == 'null') saveFileName = fName2 while(fName2.startsWith('.')) { fName2 = fName2.substring(1,) } if(fName2.contains(' ')) fName2 = toCamelCase(fName2) uploadHubFile("${fName2}",fileText.getBytes("UTF-8")) app.removeSetting('fileText') app.removeSetting('fName') app.removeSetting('saveFileName') return fName2 } def appButtonHandler(btn) { switch(btn) { case "newFileBtn": state.newFile = true break case "saveBtn": state.execSave = true break default: if(btn.startsWith('edit')){ app.updateSetting('fName',[value:"${btn.substring(4,)}",type:'enum']) state.btnEdit = true } else if(btn.startsWith('del')){ deleteHubFile(btn.substring(3,)) } else if(btn.startsWith('copy')){ target = btn.substring(4,) if(!settings["sA${target}"]) break fBuff = downloadHubFile("${target}") uploadHubFile("${settings["sA${target}"]}",fBuff) } else if(btn.startsWith('ren')){ target = btn.substring(3,) if(!settings["sA${target}"] || settings["sA${target}"] == "${target}" ) break fBuff = downloadHubFile("${target}") uploadHubFile("${settings["sA${target}"]}",fBuff) deleteHubFile(target) } else { log.error "Undefined button $btn pushed" } break } } /* * * Set of methods for UI elements * * * Licensed Virtual the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * on an "AS IS" BASIS, WIyTHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License * for the specific language governing permissions and limitations under the License. * * Date Who Description * ---------- -------------- ------------------------------------------------------------------------- * 11Mar2025 thebearmay Add checkbox uiType, add trackColor and switchColor for type = bool * 13Mar2025 Added hoverText, code cleanup * 15Mar2025 Expand btnIcon to handle he- and fa- icons * 18Mar2025 Add btnDivHide to hide/display div's (uiType='divHide') * 03Apr2025 Enable a default value for enums * 04Apr2025 Size option for icons * 23May2025 Add device. to capability * 07Oct2025 Add textarea uiType */ import groovy.transform.Field import java.text.SimpleDateFormat library ( base: "app", author: "Jean P. May Jr.", category: "UI", description: "Set of methods that allow the customization of the INPUT UI Elements", name: "uiInputElements", namespace: "thebearmay", importUrl: "https://raw.githubusercontent.com/thebearmay/hubitat/main/libraries/uiInputElements.groovy", version: "0.0.8", documentationLink: "" ) /************************************************************************ * Note: If using hoverText, you must add $ttStyleStr to at least one * * element display * ************************************************************************/ String getInputElemStr(HashMap opt){ switch (opt.type){ case "text": return inputItem(opt) break case "number": return inputItem(opt) break case "decimal": return inputItem(opt) break case "date": return inputItem(opt) break case "time": return inputItem(opt) break case "password": return inputItem(opt) break case "color": return inputItem(opt) break case "textarea": return inputTarea(opt) break case "enum": return inputEnum(opt) break case "mode": return inputEnum(opt) break case "bool": return inputBool(opt) break case "checkbox": return inputCheckbox(opt) break case "button": return buttonLink(opt) break case "icon": return btnIcon(opt) break case "href": return buttonHref(opt) break case "divHide": return btnDivHide(opt) break default: if(opt.type && (opt.type.contains('capability') || opt.type.contains('device'))) return inputCap(opt) else return "Type ${opt.type} is not supported" break } } String appLocation() { return "http://${location.hub.localIP}/installedapp/configure/${app.id}/" } /***************************************************************************** * Returns a string that will create an input element for an app - limited to * * text, password, number, date and time inputs currently * * * * HashMap fields: * * name - (required) name to store the input as a setting, no spaces or * * special characters * * type - (required) input type * * title - displayed description for the input element * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * multiple - true/ * * defaultValue - default for the field * * radius - CSS border radius value (rounded corners) * * hoverText - Text to display as a tool tip * *****************************************************************************/ String inputItem(HashMap opt) { if(!opt.name || !opt.type) return "Error missing name or type" if(settings[opt.name] != null){ if(opt.type != 'time') { opt.defaultValue = settings[opt.name] } else { SimpleDateFormat sdf = new SimpleDateFormat('HH:mm') SimpleDateFormat sdfIn = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") opt.defaultValue = sdf.format(sdfIn.parse(settings[opt.name])) } } typeAlt = opt.type if(opt.type == 'number') { step = ' step=\"1\" ' } else if (opt.type == 'decimal') { step = ' step=\"any\" ' typeAlt = 'number' } else { step = ' ' } String computedStyle = '' if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(!opt.multiple) opt.multiple = false if(opt.hoverText && opt.hoverText != 'null'){ opt.title ="${opt.title}
${btnIcon([name:'fa-circle-info'])}${opt.hoverText}
" } String retVal = "
" retVal+="
" retVal+="
" retVal+="
Save
" return retVal } /***************************************************************************** * Returns a string that will create an textArea element for an app - * * * * HashMap fields: * * name - (required) name to store the input as a setting, no spaces or * * special characters * * type - (required) input type * * title - displayed description for the input element * * width - CSS descriptor for field width * * height - CSS descriptor for field height * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * defaultValue - default for the field * * radius - CSS border radius value (rounded corners) * * hoverText - Text to display as a tool tip * *****************************************************************************/ String inputTarea(HashMap opt) { if(!opt.name || !opt.type) return "Error missing name or type" typeAlt = opt.type String computedStyle = 'resize:both;' if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.height) computedStyle += "height:${opt.height};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(opt.hoverText && opt.hoverText != 'null'){ opt.title ="${opt.title}
${btnIcon([name:'fa-circle-info'])}${opt.hoverText}
" } String retVal = "
" retVal+="
" retVal+="
" //retVal+="
Save
" return retVal } /***************************************************************************** * Returns a string that will create an input capability element for an app * * * * HashMap fields: * * name - (required) name to store the input as a setting, no spaces or * * special characters * * type - (required) capability type, 'capability.' * * title - displayed description for the input element * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * multiple - true/ * * radius - CSS border radius value (rounded corners) * * hoverText - Text to display as a tool tip * *****************************************************************************/ String inputCap(HashMap opt) { String computedStyle = '' if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize}" if(opt.radius) computedStyle += "border-radius:${opt.radius};" else opt.radius = '1px' if(!opt.multiple) opt.multiple = false String dList = '' String idList = '' int i=0 if(settings["${opt.name}"]){ ArrayList devNameId = [] settings["${opt.name}"].each{ devNameId.add([name:"${it.displayName}", devId:it.deviceId]) } ArrayList devNameIdSorted = devNameId.sort(){it.name} devNameIdSorted.each{ if(i>0) { dList +='
' idList += ',' } dList+="${it.name}" idList+="${it.devId}" i++ } } else { dList = 'Click to set' } String capAlt = opt.type.replace('.','') if(opt.hoverText && opt.hoverText != 'null') opt.title ="${opt.title}
${btnIcon([name:'fa-circle-info'])}${opt.hoverText}
" String retVal = "
" retVal += "
"//${computedStyle} //retVal += "
" retVal += "" retVal += "
Update
" return retVal } /***************************************************************************** * Returns a string that will create an input enum or mode element for an app * * * * HashMap fields: * * name - (required) name to store the input as a setting, no spaces or * * special characters * * type - (required) capability type, * * title - displayed description for the input element * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * multiple - true/ * * options - list of values for the enum (modes will autofill) * * defaultValue - default for the field * * radius - CSS border radius value (rounded corners) * * hoverText - Text to display as a tool tip * *****************************************************************************/ String inputEnum(HashMap opt){ String computedStyle = '' if(opt.type == 'mode') opt.options = location.getModes() if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(!opt.multiple) { opt.multiple = false mult = ' ' } else { mult = 'multiple' } if(opt.hoverText && opt.hoverText != 'null') opt.title ="${opt.title}
${btnIcon([name:'fa-circle-info'])}${opt.hoverText}
" String retVal = "
" retVal += "
" retVal += "" return retVal } /***************************************************************************** * Returns a string that will create an input boolean element for an app * * * * HashMap fields: * * name - (required) name to store the input as a setting, no spaces or * * special characters * * type - (required) capability type, * * title - displayed description for the input element * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * defaultValue - default for the field * * radius - CSS border radius value (rounded corners) * * trackColor - CSS color descriptor for the switch track * * switchColor - CSS color descriptor for the switch knob * * hoverText - Text to display as a tool tip * *****************************************************************************/ String inputBool(HashMap opt) { if(!opt.name || !opt.type) return "Error missing name or type" if(opt.hoverText && opt.hoverText != 'null') opt.title ="${opt.title}
${btnIcon([name:'fa-circle-info'])}${opt.hoverText}
" String computedStyle = '' if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(!opt.multiple) opt.multiple = false String trackColor = ' ' String switchColor = ' ' if(opt.trackColor) trackColor = "background-color:$opt.trackColor" if(opt.switchColor) switchColor = "background-color:$opt.switchColor" if(settings["${opt.name}"]) opt.defaultValue = settings["${opt.name}"] String retVal = "
" retVal += "" retVal+="
" retVal += "" retVal += "
" retVal += "" retVal += "
" return retVal } /***************************************************************************** * Returns a string that will create an input checkbox element for an app * * * * HashMap fields: * * name - (required) name to store the input as a setting, no spaces or * * special characters * * type - (required) capability type, * * title - displayed description for the input element * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * defaultValue - default for the field * * radius - CSS border radius value (rounded corners) * * cBoxColor - CSS color descriptor for the checkbox color * * hoverText - Text to display as a tool tip * *****************************************************************************/ String inputCheckbox(HashMap opt) { if(!opt.name || !opt.type) return "Error missing name or type" if(opt.hoverText && opt.hoverText != 'null') opt.title ="${opt.title}
${btnIcon([name:'fa-circle-info'])}${opt.hoverText}
" opt.type = 'bool' String computedStyle = '' if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(!opt.multiple) opt.multiple = false if(settings["${opt.name}"]) opt.defaultValue = settings["${opt.name}"] else opt.defaultValue = false if(!opt.cBoxColor) opt.cBoxColor = '#000000' String cbClass = 'he-checkbox-unchecked' if(opt.defaultValue) cbClass = 'he-checkbox-checked' String retVal = "
" retVal += "" retVal+="
" retVal += "" retVal += "
" retVal += "" retVal += "
" return retVal } /***************************************************************************** * Returns a string that will create an button element for an app * * * * HashMap fields: * * name - (required) name to identify the button, no spaces or * * special characters * * title - (required) button label * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * radius - CSS border radius descriptor (corner rounding) * * hoverText - Text to display as a tool tip * *****************************************************************************/ String buttonLink(HashMap opt) { //modified slightly from jtp10181's code if(!opt.name || !opt.title ) return "Error missing name or title" String computedStyle = 'cursor:pointer;text-align:center;box-shadow: 2px 2px 4px #71797E;' if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(!opt.icon) opt.icon = [name:'fa-circle-info'] if(opt.hoverText && opt.hoverText != 'null') opt.title ="${opt.title}
${btnIcon(opt.icon)}${opt.hoverText}
" return "
${opt.title}
" } /***************************************************************************** * Returns a string that will create an button HREF element for an app * * * * HashMap fields: * * name - (required) name to identify the button, no spaces or * * special characters * * title - (required) button label * * destPage - (required unless using destUrl) name of the app page to go to * * destUrl - (required unless using destPage) URL for the external page * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * radius - CSS border radius descriptor (corner rounding) * *****************************************************************************/ String buttonHref(HashMap opt) { //modified jtp10181's code if(!opt.name || !opt.title ) return "Error missing name or title" if(!opt.destPage && !opt.destUrl) return "Error missing Destination info" String computedStyle = 'cursor:pointer;text-align:center;box-shadow: 2px 2px 4px #71797E;' if(opt.width) computedStyle += "width:${opt.width};min-width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(!opt.icon) opt.icon = [name:'fa-circle-info'] if(opt.destPage) { inx = appLocation().lastIndexOf("/") dest = appLocation().substring(0,inx)+"/${opt.destPage}" } else if(opt.destUrl) { dest=opt.destUrl } if(opt.hoverText && opt.hoverText != 'null') opt.title ="${opt.title}
${btnIcon(opt.icon)}${opt.hoverText}
" return "
${opt.title}
" } /***************************************************************************** * Returns a string that will create an button element to hide/display a div * * for an app * * HashMap fields: * * name - (required) name to identify the button, no spaces or * * special characters * * title - (required) button label * * divName - (require) name of the division to hide or display * * hidden - if true will hide the div immediately * * width - CSS descriptor for field width * * background - CSS color descriptor for the input background color * * color - CSS color descriptor for text color * * fontSize - CSS text size descriptor * * radius - CSS border radius descriptor (corner rounding) * *****************************************************************************/ String btnDivHide(HashMap opt) { if(!opt.name || !opt.title || !opt.divName) return "Error missing name, title or division" String computedStyle = 'cursor:pointer;box-shadow: 2px 2px 4px #71797E;' if(!opt.width) opt.width = '100%' computedStyle += "width:${opt.width};" if(opt.background) computedStyle += "background-color:${opt.background};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.fontSize) computedStyle += "font-size:${opt.fontSize};" if(opt.radius) computedStyle += "border-radius:${opt.radius};" if(!opt.icon) opt.icon = [name:'fa-circle-info'] if(opt.destPage) { inx = appLocation().lastIndexOf("/") dest = appLocation().substring(0,inx)+"/${opt.destPage}" } else if(opt.destUrl) { dest=opt.destUrl } String btnElem = "" String script= "" if(opt.hidden){ btnElem = "" script="" } opt.title = "${btnElem} ${opt.title}" if(opt.hoverText && opt.hoverText != 'null') opt.title ="${opt.title}
${btnIcon(opt.icon)}${opt.hoverText}
" return "$script
${opt.title}
" } /***************************************************************************** * Returns a string that will create an button icon element for an app from * * the materials-icon font * * * * name - (required) name of the icon to create * *****************************************************************************/ String btnIcon(HashMap opt) { //modified from jtp10181's code String computedStyle = ' ' if(opt.size) computedStyle += "font-size:${opt.size};" if(opt.color) computedStyle += "color:${opt.color};" if(opt.name.startsWith('he')) return "" else if(opt.name.startsWith('fa')) return ""//fa-circle-info else return "${opt.name}" } /***************************************************************************** * Code sample that returns a string that will create a standard HE table * *****************************************************************************/ /* String listTable() { ArrayList tHead = ["","Disable","Name","Device","Attributes","Interval","Output File",""] String X = "" String O = "" String settingsIcon = "settings_applications" String removeIcon = "" String str = "$tableStyle
" + "" tHead.each { str += "" } str += "" ... } */ @Field static String ttStyleStr = "" @Field static String tableStyle = ""
${it}