Init git repo

master
Skylar Ittner 4 years ago
commit 76b216f85b

7
.gitignore vendored

@ -0,0 +1,7 @@
node_modules/
www/node_modules/
platforms
nbproject/private
plugins
*yarn-error.log
*npm-debug.log

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" id="vote.lecte.Lecte" version="1.0.0">
<name>Lecte</name>
<description>
Community voting and reputation app.
</description>
<author email="dev@netsyms.com" href="https://netsyms.com">
Netsyms Technologies
</author>
<content src="index.html"/>
<plugin name="cordova-plugin-whitelist" spec="1"/>
<access origin="*"/>
<allow-intent href="http://*/*"/>
<allow-intent href="https://*/*"/>
<allow-intent href="tel:*"/>
<allow-intent href="sms:*"/>
<allow-intent href="mailto:*"/>
<allow-intent href="geo:*"/>
<access launch-external="yes" origin="geo:*" />
<platform name="android">
<allow-intent href="market:*" />
<preference name="HeaderColor" value="#4CAF50" />
<resource-file src="/res/android/drawable/ic_launcher_background.xml" target="/app/src/main/res/drawable/ic_launcher_background.xml" />
<resource-file src="/res/android/drawable/ic_launcher_foreground.xml" target="/app/src/main/res/drawable/ic_launcher_foreground.xml" />
<resource-file src="res/android/mipmap-anydpi-v26/ic_launcher.xml" target="app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" />
<icon background="res/android/drawable/ic_launcher_background.xml" density="mdpi" foreground="res/android/drawable/ic_launcher_foreground.xml" src="res/android/mipmap-mdpi/ic_launcher.png" />
<icon background="res/android/drawable/ic_launcher_background.xml" density="hdpi" foreground="res/android/drawable/ic_launcher_foreground.xml" src="res/android/mipmap-hdpi/ic_launcher.png" />
<icon background="res/android/drawable/ic_launcher_background.xml" density="xhdpi" foreground="res/android/drawable/ic_launcher_foreground.xml" src="res/android/mipmap-xhdpi/ic_launcher.png" />
<icon background="res/android/drawable/ic_launcher_background.xml" density="xxhdpi" foreground="res/android/drawable/ic_launcher_foreground.xml" src="res/android/mipmap-xxhdpi/ic_launcher.png" />
<icon background="res/android/drawable/ic_launcher_background.xml" density="xxxhdpi" foreground="res/android/drawable/ic_launcher_foreground.xml" src="res/android/mipmap-xxxhdpi/ic_launcher.png" />
</platform>
<platform name="ios">
<allow-intent href="itms:*"/>
<allow-intent href="itms-apps:*"/>
</platform>
<hook src="scripts/npm_prepare.sh" type="before_prepare" />
</widget>

@ -0,0 +1,23 @@
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under 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.
#
-->
# Cordova Hooks
Cordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system to customize cordova commands. See Hooks Guide for more details: http://cordova.apache.org/docs/en/edge/guide_appdev_hooks_index.md.html#Hooks%20Guide.

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under 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.
-->
<!--
Generated file; DO NOT EDIT.
-->
<project name="Lecte" basedir="..">
<property file="nbproject/configs/${config}.properties" />
<scriptdef name="checkVersion" language="javascript">
<attribute name="first" />
<attribute name="property" />
<![CDATA[
var first = attributes.get("first");
if (first >= "3.0.0") {
project.setProperty(attributes.get("property"), true);
}
]]>
</scriptdef>
<scriptdef name="forDevice" language="javascript">
<![CDATA[
var dev = project.getProperty("device");
if (dev == "device") {
project.setProperty("build.for.device", true);
}
]]>
</scriptdef>
<target name="check-cordova-project">
<condition property="cordova.project">
<or>
<available file=".cordova"/>
<available file="hooks"/>
</or>
</condition>
</target>
<target name="upgrade-to-cordova-project" depends="check-cordova-project,check-cordova-version" unless="cordova.project">
<echo level="info" message="${cordova.command} -d create ${java.io.tmpdir}/nb_temp_project com.coolappz.${project.name} ${project.name}" />
<delete dir="${java.io.tmpdir}/nb_temp_project"/>
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" failonerror="true" >
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="-d"/>
<arg value="create"/>
<arg value="${java.io.tmpdir}/nb_temp_project"/>
<arg value="com.coolappz.${project.name}"/>
<arg value="${project.name}" />
</exec>
<copy todir="." overwrite="true" failonerror="false">
<fileset dir="${java.io.tmpdir}/nb_temp_project"/>
</copy>
<delete dir="${java.io.tmpdir}/nb_temp_project"/>
<delete dir="www"/>
<copy todir="www" failonerror="false" quiet="true" >
<fileset dir="${site.root}"/>
</copy>
</target>
<target name="create-hello-world" depends="check-cordova-version">
<echo level="info" message="${cordova.command} -d create www_nb_temp com.coolappz.${project.name} ${project.name}" />
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" failonerror="true">
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="-d"/>
<arg value="create"/>
<arg value="www_nb_temp"/>
<arg value="com.coolappz.${project.name}"/>
<arg value="${project.name}" />
</exec>
<delete dir="www"/>
<mkdir dir="www"/>
<move file="www_nb_temp/www" tofile="www"/>
<delete dir="www_nb_temp"/>
<delete file="www/config.xml"/>
</target>
<taskdef
classname="org.netbeans.modules.cordova.updatetask.ReadConfigTask"
classpath="${update.task.jar}"
name="readconfig"/>
<taskdef
classname="org.netbeans.modules.cordova.updatetask.PluginTask"
classpath="${update.task.jar}"
name="plugintask"/>
<target name="check-cordova-version">
<property environment="env"/>
<checkVersion first="${cordova.version}" property="cordova.ver.3"/>
<fail message="Cordova version 3 or greater required." unless="cordova.ver.3"/>
<readconfig/>
<forDevice/>
</target>
<target name="check-android-template">
<available file="platforms/android" property="android.generated.exists"/>
</target>
<target name="check-ios-template">
<available file="platforms/ios" property="ios.generated.exists"/>
</target>
<target name="create-android" depends="check-android-template,check-cordova-version,upgrade-to-cordova-project" unless="android.generated.exists">
<echo level="info" message="${cordova.command} -d platform add android"/>
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" failonerror="true">
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="-d"/>
<arg value="platform"/>
<arg value="add"/>
<arg value="android"/>
</exec>
</target>
<target name="create-ios" depends="check-ios-template,check-cordova-version,upgrade-to-cordova-project" unless="ios.generated.exists">
<echo level="info" message="${cordova.command} -d platform add ios"/>
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" dir="." failonerror="true">
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="-d"/>
<arg value="platform"/>
<arg value="add"/>
<arg value="ios"/>
</exec>
</target>
<target name="rebuild-ios" depends="clean-ios,build-ios"/>
<target name="build-ios" depends="create-ios,update-plugins,update-ios,build-ios-xcodebuild,build-ios-ipa"/>
<target name="build-ios-xcodebuild">
<property name="path" location="platforms/ios/build"/>
<exec executable="xcodebuild" dir="platforms/ios" failonerror="true">
<arg value="-project"/>
<arg value="${project.name}.xcodeproj"/>
<arg value="ARCHS=${ios.build.arch}"/>
<arg value="-target"/>
<arg value="${project.name}"/>
<arg value="-configuration"/>
<arg value="Release"/>
<arg value="-sdk"/>
<arg value="${ios.build.sdk}" />
<arg value="build"/>
<arg value="CONFIGURATION_BUILD_DIR=${path}"/>
</exec>
</target>
<target name="build-ios-ipa" if="build.for.device">
<exec executable="xcrun" dir="platforms/ios/build" failonerror="true">
<env key="CODESIGN_ALLOCATE" value="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate" />
<arg value="-sdk"/>
<arg value="${ios.build.sdk}" />
<arg value="PackageApplication"/>
<arg value="-v"/>
<arg value="${project.name}.app"/>
<arg value="-o"/>
<arg value="${basedir}/platforms/ios/build/${project.name}.ipa"/>
<arg value="--sign"/>
<arg value="${ios.certificate.name}"/>
<arg value="--embed"/>
<arg value="${ios.provisioning.profile}"/>
</exec>
<available file="${basedir}/platforms/ios/build/${project.name}.ipa" property="ipa.found"/>
<fail unless="ipa.found" message="PackageApplication failed."/>
</target>
<target name="sim-ios" depends="build-ios,ios-run-device,ios-run-simulator">
</target>
<target name="ios-run-device" if="build.for.device">
<echo>
Install "${basedir}/platforms/ios/build/${project.name}.ipa" through iTunes and run it.
</echo>
<exec executable="open" failonerror="true">
<arg value="${basedir}/platforms/ios/build/${project.name}.ipa"/>
</exec>
</target>
<target name="ios-run-simulator" unless="build.for.device">
<exec executable="killall" dir="platforms/ios/build">
<arg value="launchd_sim"/>
</exec>
<exec executable="${ios.sim.exec}" dir="platforms/ios/build">
<arg line="launch ${project.name}.app ${ios.device.args} --exit"/>
</exec>
</target>
<target name="update-plugins">
<plugintask/>
</target>
<target name="update-android">
<echo level="info" message="${cordova.command} prepare android"/>
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" failonerror="true">
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="prepare"/>
<arg value="android"/>
</exec>
</target>
<target name="update-ios">
<echo level="info" message="${cordova.command} prepare ios"/>
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" failonerror="true">
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="prepare"/>
<arg value="ios"/>
</exec>
</target>
<target name="rebuild-android" depends="clean-android,build-android"/>
<target name="build-android" depends="create-android,update-plugins">
<echo level="info" message="${cordova.command} -d build android"/>
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" failonerror="true">
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="-d"/>
<arg value="build"/>
<arg value="android"/>
</exec>
</target>
<target name="sim-android" depends="create-android,update-plugins">
<echo level="info" message="${cordova.command} -d ${android.target.device.arg} android"/>
<exec executable="${cordova.command}" resolveexecutable="true" searchpath="true" failonerror="true">
<env key="${cordova.path.key}" path="${cordova.path.value}:${android.sdk.home}/tools:${android.sdk.home}/platform-tools:${jdk.home}/bin:${ant.home}/bin:${jdk.home}/bin"/>
<env key="JAVA_HOME" path="${jdk.home}"/>
<arg value="-d"/>
<arg value="${android.target.device.arg}"/>
<arg value="android"/>
</exec>
</target>
<target name="clean-android" depends="check-android-template" if="android.generated.exists">
<exec executable="./gradlew" dir="platforms/android">
<arg value="clean" />
</exec>
</target>
<target name="clean-ios" depends="check-ios-template" if="ios.generated.exists">
<exec executable="platforms/ios/cordova/clean" />
</target>
</project>

@ -0,0 +1,3 @@
device=emulator
display.name=Android Emulator
type=android

@ -0,0 +1,3 @@
device=device
display.name=Android Device
type=android

@ -0,0 +1,5 @@
device=emulator
display.name=iPhone Simulator
ios.build.arch=i386
ios.build.sdk=
type=ios

@ -0,0 +1,5 @@
device=device
display.name=iPhone Device
ios.build.arch=armv7 armv7s
ios.build.sdk=
type=ios

@ -0,0 +1,48 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under 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.
# This is a list of plugins installed in your project
# You can delete or add new plugins
#
# Format is following:
# id.of.plugin=url_of_repository
#
# Corresponding "id.of.plugin" can be found in the plugin's plugin.xml file:
# <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="foo.bar.plugin" version="0.0.1">
#
# This list contains all core cordova plugins.
#
# For more information about plugins see http://cordova.apache.org/blog/releases/2013/07/23/cordova-3.html
#
cordova-plugin-device=https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git
cordova-plugin-network-information=https://git-wip-us.apache.org/repos/asf/cordova-plugin-network-information.git
cordova-plugin-battery-status=https://git-wip-us.apache.org/repos/asf/cordova-plugin-battery-status.git
cordova-plugin-device-motion=https://git-wip-us.apache.org/repos/asf/cordova-plugin-device-motion.git
cordova-plugin-device-orientation=https://git-wip-us.apache.org/repos/asf/cordova-plugin-device-orientation.git
cordova-plugin-geolocation=https://git-wip-us.apache.org/repos/asf/cordova-plugin-geolocation.git
cordova-plugin-camera=https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git
cordova-plugin-media-capture=https://git-wip-us.apache.org/repos/asf/cordova-plugin-media-capture.git
cordova-plugin-media=https://git-wip-us.apache.org/repos/asf/cordova-plugin-media.git
cordova-plugin-file=https://git-wip-us.apache.org/repos/asf/cordova-plugin-file.git
cordova-plugin-file-transfer=https://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer.git
cordova-plugin-dialogs=https://git-wip-us.apache.org/repos/asf/cordova-plugin-dialogs.git
cordova-plugin-vibration=https://git-wip-us.apache.org/repos/asf/cordova-plugin-vibration.git
cordova-plugin-contacts=https://git-wip-us.apache.org/repos/asf/cordova-plugin-contacts.git
cordova-plugin-globalization=https://git-wip-us.apache.org/repos/asf/cordova-plugin-globalization.git
cordova-plugin-splashscreen=https://git-wip-us.apache.org/repos/asf/cordova-plugin-splashscreen.git
cordova-plugin-console=https://git-wip-us.apache.org/repos/asf/cordova-plugin-console.git

@ -0,0 +1,7 @@
auxiliary.org-netbeans-modules-cordova.cordova_5f_build_5f_script_5f_version=52
auxiliary.org-netbeans-modules-cordova.phonegap=true
file.reference.Lecte-test=test
file.reference.Lecte-www=www
files.encoding=UTF-8
site.root.folder=${file.reference.Lecte-www}
test.folder=${file.reference.Lecte-test}

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.web.clientproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/clientside-project/1">
<name>Lecte</name>
</data>
</configuration>
</project>

@ -0,0 +1,34 @@
{
"name": "vote.lecte.lecte",
"displayName": "Lecte",
"version": "1.0.0",
"description": "",
"main": "www/index.html",
"window": {
"icon": "res/logo.png",
"id": "vote.lecte.Lecte_window_main_00001",
"frame": true
},
"user_agent": "Mozilla/5.0 (%osinfo) %name/%ver NW.js/%nwver WebKit/%webkit_ver Chromium/%chromium_ver",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"ecosystem:cordova"
],
"author": "Netsyms Technologies",
"license": "MPL-2.0",
"dependencies": {
"cordova-android": "^8.1.0"
},
"cordova": {
"plugins": {
"cordova-plugin-geolocation": {},
"cordova-plugin-inappbrowser": {},
"cordova-plugin-whitelist": {},
"cordova-plugin-device": {},
"cordova-plugin-statusbar": {},
"cordova-plugin-headercolor": {}
}
}
}

@ -0,0 +1,11 @@
#!/bin/bash
echo "Generating credits files..."
cd www
yarn licenses generate-disclaimer > ../license-credits.md
cd ..
yarn licenses generate-disclaimer >> license-credits.md
cp www/pages/credits.template.html www/pages/credits.html
sed -e "/{{credits}}/r license-credits.md" -e "/{{credits}}/d" -i www/pages/credits.html

@ -0,0 +1,5 @@
#!/bin/sh
./scripts/www_npm_install.sh
./scripts/generate_credits.sh
./scripts/remove_bloat.sh

@ -0,0 +1,79 @@
#!/bin/bash
# This script removes some stuff in `www/node_modules` that the app doesn't need to run.
# It removes about 6MB from the build size.
echo "Removing bloat in node_modules..."
pwd
cd www/node_modules
rm -rf {ansicolors,buffer-from,cardinal,concat-stream,core-util-is,csscolorparser}
rm -rf {dom7,earcut,esprima,geojson-vt,gl-matrix,grid-index,ieee754,inherits,isarray}
rm -rf {kdbush,leaflet-geometryutil,@mapbox,minimist,murmurhash-js}
rm -rf {path-to-regexp,pbf,potpack,process-nextick-args}
rm -rf {protocol-buffers-schema,quickselect,readable-stream,redeyed,resolve-protobuf-schema}
rm -rf {rw,safe-buffer,sharkdown,split,ssr-window,string_decoder,supercluster}
rm -rf {template7,text-encoding,through,tinyqueue,ts-custom-error,typedarray}
rm -rf {util-deprecate,vt-pbf,wgs84}
# Make npm stop complaining that these don't exist by actually removing them
rm -rf .bin/*
cd bwip-js
rm -rf {bin,examples,src,barcode.ps,demo.html,stb_truetype.h}
rm -rf dist/bwip-js.js
rm -rf dist/node-bwipjs.js
cd ..
cd @fortawesome/fontawesome-free
rm -rf {js,less,metadata,scss,sprites,svgs}
find css -type f -not -name 'all.min.css' -delete
cd ../..
cd framework7
rm -rf components
rm -rf lazy-components
rm -rf less
rm -rf modules
rm -rf utils
rm -f framework7.*
rm -f framework7-lite.*
find css -type f -not -name 'framework7.bundle.min.css' -delete
find js -type f -not -name 'framework7.bundle.min.js' -delete
cd ..
cd jquery
rm -rf src
rm -rf external
find dist -type f -not -name 'jquery.min.js' -delete
cd ..
cd leaflet
rm -rf {CHANGELOG.md,src}
find dist -type f -not -name 'leaflet.css' -not -name 'leaflet.js' -delete
cd ..
cd leaflet.locatecontrol
rm -rf {CHANGELOG.md,README.md,src}
find dist -type f -not -name 'L.Control.Locate.min.css' -not -name 'L.Control.Locate.min.js' -delete
cd ..
cd leaflet.markercluster
rm -rf {build,example,spec,src,CHANGELOG.md}
find dist -type f -not -name 'leaflet.markercluster.js' -not -name 'MarkerCluster.css' -not -name 'MarkerCluster.Default.css' -delete
cd ..
cd material-design-icons
# Remove everything except the icon font and license, but also exclude the
# current and parent folder (. , ..) so rm won't complain about refusing
# to delete the whole filesystem
find . -maxdepth 1 -not -name '.' -not -name 'LICENSE' -not -name 'iconfont' -exec rm -rf {} \;
cd ..
cd mapbox-gl
rm -rf {build,flow-typed,src}
find dist -type f -not -name 'mapbox-gl.css' -not -name 'mapbox-gl.js' -delete
rm -rf dist/style-spec
cd ..
echo "Cleanup finished"

@ -0,0 +1,7 @@
#!/bin/bash
echo "Installing node modules in www/..."
cd www
npm install
cd ..

@ -0,0 +1,93 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
Framework7 and FontAwesome both have a .fab class
*/
.fafab {
font-family: "Font Awesome 5 Brands";
}
.fab {
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
font-family: var(--f7-font-family);
font-size: var(--f7-font-size);
line-height: var(--f7-line-height);
}
.page-content-fab-pad {
padding-bottom: var(--f7-fab-size);
}
.navbar, .item-link .item-title, .item-media, .item-divider, .item-label, .fab, .button, .noselect {
user-select: none;
}
.navbar-inner {
-webkit-app-region: drag;
}
.navbar-inner > * {
-webkit-app-region: no-drag;
}
/*
* Material icons are too big and disrupt the flow of text
*/
.block .material-icons {
font-size: var(--f7-block-font-size);
}
.material-icons.material-icons-24px {
font-size: 24px;
}
.material-icons-intext .material-icons {
font-size: var(--f7-block-font-size);
}
#mapbox {
width: 100%;
height: 100%;
background-color: #e8e5d8;
}
#mapbox .user-marker {
width: 25px;
height: 25px;
background-image: url(../images/user.png);
background-size: contain;
}
/* Allow tapping/clicking on package markers
* when the location dot is overlapping them
*/
#mapbox .mapboxgl-user-location-dot {
pointer-events: none;
}
.no-animation * {
-webkit-transition: 10ms !important;
-moz-transition: 10ms !important;
-o-transition: 10ms !important;
-ms-transition: 10ms !important;
transition: 10ms !important;
}
/*
Allow easily changing help text to reflect finger/mouse usage.
*/
.clicktext {
display: none;
}
@media (pointer:fine) {
.taptext {
display: none;
}
.clicktext {
display: initial;
}
}

@ -0,0 +1,16 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
We want the backdrops to be there so there aren't accidental touches,
but we don't want them to obscure anything.
*/
.actions-backdrop.backdrop-in, .custom-modal-backdrop.backdrop-in,
.dialog-backdrop.backdrop-in, .popover-backdrop.backdrop-in,
.popup-backdrop.backdrop-in, .preloader-backdrop.backdrop-in,
.sheet-backdrop.backdrop-in {
opacity: 0;
}

@ -0,0 +1,16 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
* Color adjustments for better OLED performance
*/
:root #app.theme-dark {
--f7-page-bg-color: #020202;
--f7-list-bg-color: #020202;
--f7-popover-bg-color: #020202;
--f7-sheet-bg-color: #020202;
}

@ -0,0 +1,79 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*
Created on : Apr 3, 2020, 11:55:50 AM
Author : Skylar Ittner
*/
.only-tablet {
display: none;
}
@media all and (min-width: 768px) {
.only-tablet {
display: inherit;
}
.no-tablet {
display: none;
}
.page.tabbed .tabbar {
/* Remove tab switcher at bottom of page */
display: none;
height: 0;
}
.page.tabbed .tabs {
/* Put tabs next to each other */
display: flex;
}
.page.tabbed .tabs .tab {
/* un-hide "non-active" tabs */
display: block;
/* Make FABs stay where they should */
position: relative;
}
.page.tabbed .tabs .tab.tab-67 {
width: 66.67% !important;
}
.page.tabbed .tabs .tab.tab-33 {
width: 33.33% !important;
}
.page.tabbed .page-content {
padding-top: 0;
padding-bottom: 0;
}
.elevation-tablet {
/* .elevation-3 */
box-shadow: var(--f7-elevation-3)!important;
}
.page.tabbed .tabs .tab:not(:first-child) {
/*box-shadow: inset 5px 0 9px -5px rgba(0,0,0,0.3);*/
border-left: 1px solid rgba(0,0,0,0.1);
}
.page.tabbed .fab {
margin-bottom: 0;
}
.sheet-backdrop.backdrop-in {
visibility: hidden;
}
.padding-bottom-tablet {
padding-bottom: 3rem !important;
}
#mapbox {
height: calc(100% - var(--f7-navbar-height));
}
}
@media all and (min-width: 768px) and (min-height: 700px) {
.margin-top-tablet {
margin-top: 1rem;
}
}

@ -0,0 +1,42 @@
/*
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#web-barcode-ui {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999999;
display: block;
background: rgba(0,0,0,0.75);
}
#web-barcode-ui.hidden {
display: none;
}
#web-barcode-ui video#barcode-viewer {
max-width: calc(100% - 2em);
max-height: calc(100% - 2em);
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 1em;
}
#web-barcode-ui .text {
position: absolute;
left: 0;
bottom: 0;
width: 100vw;
padding: 1em 5px 1em 5px;
color: white;
text-align: center;
background: rgba(0,0,0,0.5);
}

@ -0,0 +1,60 @@
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src:
local('Roboto'),
local('Roboto-Regular'),
url('Roboto_400.woff') format('woff'),
url('Roboto_400.woff2') format('woff2');
}
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src:
local('Roboto Italic'),
local('Roboto-Italic'),
url('Roboto_400i.woff') format('woff'),
url('Roboto_400i.woff2') format('woff2');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src:
local('Roboto Medium'),
local('Roboto-Medium'),
url('Roboto_500.woff') format('woff'),
url('Roboto_500.woff2') format('woff2');
}
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src:
local('Roboto Medium Italic'),
local('Roboto-MediumItalic'),
url('Roboto_500i.woff') format('woff'),
url('Roboto_500i.woff2') format('woff2');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src:
local('Roboto Bold'),
local('Roboto-Bold'),
url('Roboto_700.woff') format('woff'),
url('Roboto_700.woff2') format('woff2');
}
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 700;
src:
local('Roboto Bold Italic'),
local('Roboto-BoldItalic'),
url('Roboto_700i.woff') format('woff'),
url('Roboto_700i.woff2') format('woff2');
}

@ -0,0 +1,31 @@
<!DOCTYPE html>
<!--
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<html>
<head>
<title>Loading</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
*,html,body {
background-color: #fff;
font-family: Roboto, Ubuntu, sans-serif;
text-align: center;
}
div {
margin-top: 1rem;
}
</style>
</head>
<body>
<div>Loading...</div>
<script src="../settings.js"></script>
<script>
window.location.href = SETTINGS.loginurl;
</script>
</body>
</html>

@ -0,0 +1,152 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
var autofillDB = {};
var autofillStreetDB = [];
if (getStorage("autofill_db") != null) {
autofillDB = JSON.parse(getStorage("autofill_db"));
}
if (getStorage("autofill_streetdb") != null) {
autofillStreetDB = JSON.parse(getStorage("autofill_streetdb"));
}
function addressToNumberAndStreet(address) {
var number = "";
var street = "";
var addressRegex = RegExp("^[0-9]+ .+$");
if (addressRegex.test(address)) {
number = address.split(" ", 2)[0];
street = address.substring(address.indexOf(' ') + 1);
}
return [number, street];
}
function addAutofillEntry(address) {
var [number, street] = addressToNumberAndStreet(address);
if (number == "" || street == "") {
return;
}
if (typeof autofillDB[number] == 'undefined') {
autofillDB[number] = [
[street, 1]
];
} else {
var found = false;
for (var i = 0; i < autofillDB[number].length; i++) {
if (autofillDB[number][i][0] == street) {
autofillDB[number][i][1]++;
found = true;
break;
}
}
if (!found) {
autofillDB[number].push([street, 1]);
}
}
setStorage("autofill_db", JSON.stringify(autofillDB));
var found = false;
for (var i = 0; i < autofillStreetDB.length; i++) {
if (autofillStreetDB[i][0] == street) {
autofillStreetDB[i][1]++;
found = true;
break;
}
}
if (!found) {
autofillStreetDB.push([street, 1]);
}
setStorage("autofill_streetdb", JSON.stringify(autofillStreetDB));
}
function searchAutofill(q, number) {
var byNumber = [];
if (typeof number != 'undefined') {
byNumber = searchAutofillByNumber(number, q);
}
var byStreet = [];
if (q.length > 0) {
byStreet = searchAutofillByStreet(q);
}
return byNumber.concat(byStreet.filter((item) => byNumber.indexOf(item) < 0));
}
function searchAutofillByNumber(number, q) {
if (typeof autofillDB[number] == 'undefined') {
return [];
}
var sorted = autofillDB[number].sort(function (a, b) {
return b[1] - a[1];
});
var query = false;
if (typeof q != 'undefined' && q != "") {
query = true;
}
var streets = [];
for (var i = 0; i < sorted.length; i++) {
// if there's no search query OR if the query matches the current item
if (!query || (query && sorted[i][0].toLowerCase().includes(q))) {
streets.push(sorted[i][0]);
}
}
return streets;
}
function searchAutofillByStreet(q) {
var streets = [];
var sortedDB = autofillStreetDB.sort(function (a, b) {
return b[1] - a[1];
});
//console.log(sortedDB);
q = q.toLowerCase();
for (var i = 0; i < sortedDB.length; i++) {
//console.log(sortedDB[i][0].toLowerCase().indexOf(q));
if (sortedDB[i][0].toLowerCase().includes(q)) {
streets.push(sortedDB[i][0]);
}
}
return streets;
}
function setupStreetAutofill(streetBox, numberBox) {
app.autocomplete.create({
inputEl: streetBox,
openIn: 'dropdown',
/* If we set valueProperty to "id" then input value on select will be set according to this property */
valueProperty: 'name', //object's "value" property name
textProperty: 'name', //object's "text" property name
limit: 10, //limit to 10 results
typeahead: true,
dropdownPlaceholderText: '',
source: function (query, render) {
var streets = searchAutofill(query, $(numberBox).val());
render(streets);
}
});
}

@ -0,0 +1,27 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function setTabSwipable() {
var page = $(".page[data-name=discover]");
// If the page has grown larger, refresh to disable swiping tabs
if (page.width() >= 768 && $(".tabs-swipeable-wrap")[0]) {
router.refreshPage();
} else if (page.width() < 768 && !$(".tabs-swipeable-wrap")[0]) {
router.refreshPage();
}
}
$(window).on('resize', setTabSwipable);
setTabSwipable();
// Adjust the map when opening its tab
$(".view-main").on("click", ".tab-link#map-tab-link", function () {
var center = map.getCenter();
map.resize();
map.setCenter(center);
});

@ -0,0 +1,191 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
var lastGpsUpdateTimestamp = 0;
var userPosition = {
coords: {
latitude: 0.0,
longitude: 0.0,
accuracy: 999999
},
updated: 0
};
// Preload last known location while GPS warms up
if (getStorage("user_latitude") != null && getStorage("user_longitude") != null) {
userPosition.coords.latitude = getStorage("user_latitude");
userPosition.coords.longitude = getStorage("user_longitude");
}
// Request the user's IP geolocation as a poor substitute for an actual location
// Should improve UX for weather tool at least
$.ajax({
url: SETTINGS.geoipapi,
dataType: 'json',
timeout: 10 * 1000,
success: function (resp) {
if (resp.status == "OK" && userPosition.coords.accuracy > 99999) {
userPosition.coords.latitude = resp.location.latitude;
userPosition.coords.longitude = resp.location.longitude;
userPosition.coords.accuracy = 99999;
userPosition.updated = time();
}
}
});
var geoerrorcount = 0;
var mapLocationControlStarted = false;
if ("geolocation" in navigator) {
navigator.geolocation.watchPosition(function (position) {
userPosition.coords = position.coords;
userPosition.updated = time();
setStorage("user_latitude", userPosition.coords.latitude);
setStorage("user_longitude", userPosition.coords.longitude);
if (mapLocationControlStarted) {
// Don't send location at an interval less than one minute
var currentTimestamp = Math.floor(Date.now() / 1000);
if (lastGpsUpdateTimestamp < (currentTimestamp - 60)) {
lastGpsUpdateTimestamp = currentTimestamp;
// TODO: check if user logged in, and if so send approx. location
// to allow discovery
}
} else {
if (map != null) {
map.startLocateControl();
mapLocationControlStarted = true;
}
}
}, function (err) {
if (typeof error == "function") {
error(err.message);
}
}, {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
});
} else {
geoerrorcount++;
console.log("Warn", "Geolocation error #" + geoerrorcount + ": ", error);
// Stop showing error toasts if they're happening a lot
if (geoerrorcount <= 3) {
app.toast.show({
text: '<i class="fas fa-compass"></i> ' + error,
position: "bottom",
destroyOnClose: true,
closeTimeout: 1000 * 3
});
}
}
/**
* Calculate distance between two GPS points using Vincenty Formula.
*
* From Aman Singh https://stackoverflow.com/q/30536869
*
* @param {type} lat1
* @param {type} lon1
* @param {type} lat2
* @param {type} lon2
* @returns {Number} distance in meters
*/
function getDistance(lat1, lon1, lat2, lon2) {
var toRad = function (value) {
return value * Math.PI / 180;
}
var a = 6378137, b = 6356752.314245, f = 1 / 298.257223563;
var L = toRad(lon2 - lon1);
var U1 = Math.atan((1 - f) * Math.tan(toRad(lat1)));
var U2 = Math.atan((1 - f) * Math.tan(toRad(lat2)));
var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
var lambda = L, lambdaP, iterLimit = 100;
do
{
var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
var sinSigma = Math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda) + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
if (sinSigma == 0)
return 0;
var cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
var sigma = Math.atan2(sinSigma, cosSigma);
var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
var cosSqAlpha = 1 - sinAlpha * sinAlpha;
var cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
if (isNaN(cos2SigmaM))
cos2SigmaM = 0;
var C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
lambdaP = lambda;
lambda = L + (1 - C) * f * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
} while (Math.abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0);
if (iterLimit == 0)
return NaN
var uSq = cosSqAlpha * (a * a - b * b) / (b * b);
var A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
var B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
var deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
var s = b * A * (sigma - deltaSigma);
return s;
}
/**
* Return a formatted string with units corresponding to a number of meters.
* Respects user "units" setting ("metric" or "imperial").
* @param number meters
* @param bool space Add a space between number and units. Default true.
* @returns string "1000 ft", "2 mi", "3 km",
*/
function getDisplayDistance(meters, space) {
if (typeof space == 'undefined') {
space = true;
}
var units = getStorage("units");
if (units == null) {
units = "metric";
}
var number = Math.round(meters);
var label = "m";
if (units == "imperial") {
// Convert to feet
number = Math.round(number * 3.28084);
label = "ft";
if (number >= 1320) { // 0.25 miles
number = (number / 5280);
if (number < 10) {
number = number.toFixed(2);
} else {
number = Math.round(number);
}
label = "mi";
}
} else {
if (number >= 1000) {
number = (number / 1000);
if (number < 16) {
number = number.toFixed(1);
} else {
number = Math.round(number);
}
label = "km";
}
}
if (space) {
return number + " " + label;
}
return number + "" + label;
}

@ -0,0 +1,37 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
$(window).on("message", function (e) {
var data = e.originalEvent.data;
var parts = data.split("&");
var u = "";
var p = "";
for (var i = 0; i < parts.length; i++) {
if (parts[i].startsWith("user:")) {
u = parts[i].replace("user:", "");
} else if (parts[i].startsWith("password:")) {
p = parts[i].replace("password:", "");
}
}
if (u != "" && p != "") {
setStorage("username", u);
setStorage("password", p);
// Reset last change so we won't overwrite server settings
setStorage("lastchange", 0, true);
app.toast.show({
text: "You are now logged in!",
position: "bottom",
destroyOnClose: true,
closeTimeout: 1000 * 3
});
restartApplication();
} else {
app.dialog.alert("There was a problem. Try again later.", "Error");
}
});

@ -0,0 +1,162 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var $$ = Dom7;
// Detect platform and run platform-specific setup code
// for Cordova, NW.js, or the browser
initPlatform();
var app = new Framework7({
root: "#app",
name: "Lecte",
id: "vote.lecte.Lecte",
theme: "md",
card: {
swipeToClose: false
},
popup: {
backdrop: true
},
popover: {
backdrop: true
},
init: true,
initOnDeviceReady: false,
routes: routes
});
var mainView = app.views.create('.view-main', {
url: "/",
animate: true
});
var router = mainView.router;
function restartApplication() {
window.location = "index.html";
}
router.on("pageInit", function (pagedata) {
pagedata.$el.find('script').each(function (el) {
if ($$(this).attr('src')) {
var s = document.createElement('script');
s.src = $$(this).attr('src');
$$('head').append(s);
} else {
eval($$(this).text());
}
});
// Stop text selection from popping a system toolbar even after changing pages
if (window.getSelection) {
window.getSelection().removeAllRanges();
} else if (document.selection) {
document.selection.empty();
}
});
/**
* Perform back button behavior.
* Call this function whenever the equivalent to the Android back button is pressed.
* @returns {undefined}
*/
function handleBackButton() {
// Close map sheet if it's open
if ($(".sheet-modal").hasClass("modal-in")) {
app.sheet.close();
} else if ($(".searchbar-enabled")[0]) {
app.searchbar.disable();
} else if (scanningBarcode) {
return;
} else {
router.back({force: true, ignoreCache: true});
}
// Stop text selection from popping a system toolbar even after changing pages
if (window.getSelection) {
window.getSelection().removeAllRanges();
} else if (document.selection) {
document.selection.empty();
}
}
$(document).keyup(function (e) {
if (e.key === "Escape" || e.keyCode == 27) {
handleBackButton();
}
});
router.on("routeChange", function (newRoute) {
console.log("Info", "Navigating to ", newRoute.path);
});
function setAppTheme(theme) {
if (theme == "light") {
$("#app").removeClass("theme-dark");
if (platform_type == "cordova" && cordova.platformId == 'android' && typeof StatusBar !== 'undefined') {
StatusBar.styleDefault();
StatusBar.backgroundColorByHexString("#E0E0E0");
}
} else if (theme == "dark") {
$("#app").addClass("theme-dark");
if (platform_type == "cordova" && cordova.platformId == 'android' && typeof StatusBar !== 'undefined') {
StatusBar.styleLightContent();
StatusBar.backgroundColorByHexString("#000000");
}
}
}
function applyColorTheme() {
if (getStorage("apptheme") == "dark") {
setAppTheme("dark");
} else if (getStorage("apptheme") == "light") {
setAppTheme("light");
} else {
// automatic theme, default light
if (typeof Framework7.device.prefersColorScheme() !== 'undefined' && Framework7.device.prefersColorScheme() == "dark") {
setAppTheme("dark");
} else {
setAppTheme("light");
}
}
}
/**
* Turn animations on or off.
* @param {boolean} on true for on, false for off.
* @returns {undefined}
*/
function toggleAnimations(on) {
if (on) {
$("#app").removeClass("no-animation");
} else {
$("#app").addClass("no-animation");
}
mainView.params.animate = on;
}
/**
* Turn animations on or off while considering user preferences.
* @param boolean enabled true to enable, false to disable, undefined to use animation=on/off setting.
* @returns {undefined}
*/
function setAnimations(enabled) {
if (getStorage("animation") == null) {
setStorage("animation", "auto");
}
if (typeof enabled !== "undefined") {
toggleAnimations(enabled == true);
return;
}
if (getStorage("animation") == "off") {
toggleAnimations(false);
} else if (getStorage("animation") == "on") {
toggleAnimations(true);
}
}
applyColorTheme();
setAnimations();
router.navigate("/discover");

@ -0,0 +1,91 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
var map = null;
var maptype = "mapbox";
function createMap() {
if (getStorage("maptype") == null) {
setStorage("maptype", "mapbox");
}
maptype = getStorage("maptype");
if (maptype == "mapbox") {
if (mapboxgl.supported()) {
map = mapboxMap();
} else {
console.log("Warn", "mapbox-gl not supported, falling back to Leaflet");
maptype = "leaflet";
map = leafletMap();
}
} else {
map = leafletMap();
}
map.updateUserLayer();
}
/**
* Destroy and re-create the map.
* @returns {undefined}
*/
function reloadMap() {
try {
if (map != null && typeof map != 'undefined') {
var mapcenter = map.getCenter();
var mapzoom = map.getZoom();
if (map.maptype == "mapbox") {
var mapbearing = map.getBearing();
var mappitch = map.getPitch();
}
map.off();
map.remove();
map = null;
if (document.getElementById("mapbox") != null) {
createMap();
if (map.maptype == "mapbox") {
map.jumpTo({
center: mapcenter,
zoom: mapzoom,
bearing: mapbearing,
pitch: mappitch
});
} else {
map.setView(mapcenter, mapzoom);
}
} else {
console.log("Info", "Not re-creating map because #mapbox is not in DOM. Creation will be automatically triggered when map page is loaded.");
}
} else {
createMap();
}
} catch (ex) {
// oh well ¯\(°_o)/¯
console.log(ex);
}
}
function setMapLocation(latitude, longitude) {
if (map == null) {
return;
}
map.setMapLocation(latitude, longitude);
}
function animateMapIn(latitude, longitude, zoom, heading) {
if (map == null) {
return;
}
if (typeof zoom == 'undefined') {
zoom = 14;
}
if (typeof heading == 'undefined') {
heading = 0;
}
map.animateMapIn(latitude, longitude, zoom, heading);
}

@ -0,0 +1,119 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function leafletMap() {
var map = L.map('mapbox', {
zoomSnap: 0.25,
minZoom: 1,
maxZoom: 19,
zoom: 12,
center: L.latLng(46.5966, -112.0180),
attributionControl: false
});
map.maptype = "leaflet";
if (getStorage("mapsource") == null) {
setStorage("mapsource", "liberty");
}
$("#mapbox").css("background-color", SETTINGS.maptileurls[getStorage("mapsource")].bgcolor);
L.tileLayer(SETTINGS.maptileurls[getStorage("mapsource")].url, {
minZoom: 1,
maxZoom: 19
}).addTo(map);
map.locateControl = L.control.locate({
flyTo: false, // Hopefully this will lower the number of map tile requests when location is found
showPopup: false,
locateOptions: {
enableHighAccuracy: true,
maxZoom: getStorage("trackzoom") == null ? 16 : getStorage("trackzoom") * 1
},
setView: "untilPanOrZoom",
icon: "far fa-compass",
iconLoading: "far fa-compass fa-spin"
}).addTo(map);
map.userlayer = L.markerClusterGroup();
map.userlayer.addTo(map);
map.setView({lat: userPosition.coords.latitude, lng: userPosition.coords.longitude}, 2);
map.startLocateControl = function () {
map.locateControl.start();
}
map.stopLocateControl = function () {
}
map.setMapHeading = function (heading) {
}
map.setMapLocation = function (latitude, longitude) {
map.setView({
lng: longitude,
lat: latitude
});
}
map.updateUserLayer = function () {
map.userlayer.clearLayers();
//console.log(data);
for (var i = 0; i < data.length; i++) {
// JavaScript variable scope and anonymous functions are dumb
// This is necessary, otherwise all the on(click)s will fire for the last iteration
// of the loop, or something like that
(function (datai) {
var iconUrl = getMapIconForUser(datai);
//console.log(iconName);
var icon = L.icon({
iconUrl: iconUrl,
iconSize: [25, 25],
iconAnchor: [12.5, 12.5]
});
var marker = L.marker(
[
datai.coords[0],
datai.coords[1]
],
{
icon: icon
})
.on("click", function () {
openProfilePopup(datai.id)
});
map.userlayer.addLayer(marker);
})(data[i]);
}
}
map.animateMapIn = function (latitude, longitude, zoom, heading) {
if (typeof zoom == 'undefined') {
zoom = 14;
}
if (typeof heading == 'undefined') {
heading = 0;
}
map.flyTo([latitude, longitude], zoom);
// Set min zoom after some time to fly in
setTimeout(function () {
map.setMinZoom(12);
map.setZoom(zoom);
}, 1000);
}
return map;
}

@ -0,0 +1,142 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// If true, we'll do a fancy zoom/pan in
// Otherwise we'll just jump to the correct location
var firstload = true;
function mapboxMap() {
if (getStorage("mapsource") == null) {
setStorage("mapsource", "liberty");
}
$("#mapbox").css("background-color", SETTINGS.maptileurls[getStorage("mapsource")].bgcolor);
mapboxgl.accessToken = '';
var map = new mapboxgl.Map({
container: 'mapbox',
style: SETTINGS.maptileurls[getStorage("mapsource")].json,
attributionControl: false,
dragPan: true,
pitch: 0,
zoom: 2,
maxZoom: 19
});
map.maptype = "mapbox";
map.addControl(new mapboxgl.NavigationControl({
visualizePitch: true
}), 'top-left');
map.addControl(
new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true,
timeout: 10 * 1000
},
fitBoundsOptions: {
maxZoom: getStorage("trackzoom") == null ? 16 : getStorage("trackzoom") * 1
},
trackUserLocation: true
}), 'top-left'
);
if (getStorage("mapscale") !== "false") {
map.addControl(
new mapboxgl.ScaleControl({
unit: getStorage("units") == "imperial" ? "imperial" : "metric"
})
);
}
map.startLocateControl = function () {
// stub
}
map.stopLocateControl = function () {
// stub
}
map.mapEasing = function (t) {
return t * (2 - t);
}
map.setMapHeading = function (heading) {
if (typeof heading == 'number') {
map.easeTo({
bearing: heading,
easing: map.mapEasing
});
}
}
map.setMapLocation = function (latitude, longitude) {
map.easeTo({
center: [
longitude,
latitude
]
});
}
map.updateUserLayer = function () {
var oldmarkers = document.getElementsByClassName("user-marker");
if (oldmarkers.length > 0) {
markerparent = oldmarkers[0].parentNode;
while (oldmarkers.length > 0) {
markerparent.removeChild(oldmarkers[0]);
}
}
for (var i = 0; i < data.length; i++) {
// JavaScript variable scope and anonymous functions are dumb
// This is necessary, otherwise all the on(click)s will fire for the last iteration
// of the loop, or something like that
(function (datai) {
var iconUrl = getMapIconForUser(datai);
//console.log(iconName);
var el = document.createElement("div");
el.className = "package-marker";
el.style = "background-image: url(" + iconUrl + ");";
el.addEventListener('click', function () {
openProfilePopup(datai.id);
});
new mapboxgl.Marker(el)
.setLngLat([datai.coords[1], datai.coords[0]])
.addTo(map);
})(data[i]);
}
}
map.animateMapIn = function (latitude, longitude, zoom, heading) {
if (typeof zoom == 'undefined') {
zoom = 16;
}
if (typeof heading == 'undefined') {
heading = 0;
}
map.jumpTo({
center: [
longitude,
latitude
],
speed: 1,
zoom: zoom,
heading: heading,
pitch: 0
});
}
map.animateMapIn(userPosition.coords.latitude, userPosition.coords.longitude, 12);
return map;
}

@ -0,0 +1,166 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
var platform_type = "";
var platform_theme = "md";
var app_version = "unknown";
var nw_tray = null;
/**
* If true and animations are set to "auto", animations should be disabled.
* @type Boolean
*/
var auto_disable_animations = false;
var openBrowser = function (url) {
window.open(url);
}
var openSystemBrowser = function (url) {
window.open(url);
}
var scanningBarcode = false;
var getLocation = function (success, error) {
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(function (position) {
success(position);
}, function (err) {
if (typeof error == "function") {
error(err.message);
}
}, {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
});
} else {
if (typeof error == "function") {
error("Location is unavailable.");
}
}
}
var watchLocation = function (success, error) {
if ("geolocation" in navigator) {
navigator.geolocation.watchPosition(function (position) {
success(position);
}, function (err) {
if (typeof error == "function") {
error(err.message);
}
}, {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0
});
} else {
if (typeof error == "function") {
error("Location is unavailable.");
}
}
}
function initCordova() {
platform_type = "cordova";
// Handle back button to close things
document.addEventListener("backbutton", handleBackButton, false);
document.addEventListener("deviceready", function () {
// Make sure the status bar color is set properly
applyColorTheme();
}, false);
openBrowser = function (url) {
cordova.InAppBrowser.open(url, '_blank', 'location=yes');
}
openExternalBrowser = function (url) {
window.open(url, '_system', '');
}
// Handle geo: urls
$("#app").on("click", ".geolink", function (evt) {
window.open($(this).attr("href"), "_system");
evt.preventDefault();
});
}
function initNW() {
platform_type = "nw";
platform_theme = "md";
openBrowser = function (url) {
nw.Window.open(url, {
id: url
}, function (browserwin) {
// Add menubar so the user can navigate around if they click a link
var browsermenu = new nw.Menu({type: 'menubar'});
browsermenu.append(new nw.MenuItem({
label: "Back",
click: function () {
browserwin.window.history.back();
}
}));
browsermenu.append(new nw.MenuItem({
label: "Forward",
click: function () {
browserwin.window.history.forward();
}
}));
browsermenu.append(new nw.MenuItem({
label: "Home",
click: function () {
browserwin.window.location.href = url;
}
}));
browserwin.menu = browsermenu;
});
}
openExternalBrowser = function (url) {
require('nw.gui').Shell.openExternal(url);
}
// Handle geo: urls
$("#app").on("click", ".geolink", function (evt) {
require('nw.gui').Shell.openExternal($(this).attr("href"));
evt.preventDefault();
});
}
function initBrowser() {
platform_type = "browser";
platform_theme = "md";
openBrowser = function (url) {
window.open(url);
}
openExternalBrowser = function (url) {
window.open(url);
}
$("#app").on("click", ".geolink", function (evt) {
window.open($(this).attr("href"), "_blank");
evt.preventDefault();
});
}
function initPlatform() {
if (typeof cordova !== 'undefined') {
initCordova();
} else if (typeof nw !== 'undefined') {
initNW();
} else {
initBrowser();
}
$.getJSON("package.json", function (data) {
app_version = data.version;
});
}

@ -0,0 +1,142 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function logout() {
app.dialog.confirm(
"Are you sure you want to log out?",
"Log out?",
function () {
localStorage.removeItem('password');
localStorage.removeItem('username');
localStorage.removeItem('lastsync');
restartApplication();
}
);
}
function resyncAndRestart() {
app.toast.show({
text: "Syncing settings and restarting...",
position: "bottom",
destroyOnClose: true,
closeTimeout: 1000 * 10
});
syncNow(function () {
restartApplication();
});
}
function clearCaches() {
app.toast.show({
text: "Clearing caches. You may need to restart the app to see a difference.",
position: "bottom",
destroyOnClose: true,
closeTimeout: 1000 * 10
});
setStorage("geocode_cache", "{}");
if ('caches' in window) {
clearAllCaches();
}
}
$('.item-link[data-setting=apptheme] select').on("change", function () {
setStorage("apptheme", $('.item-link[data-setting=apptheme] select').val());
applyColorTheme();
});
$('.item-link[data-setting=animation] select').on("change", function () {
setStorage("animation", $('.item-link[data-setting=animation] select').val());
if (getStorage("animation") != "auto") {
setAnimations();
}
if (getStorage("animation") == "auto") {
toggleAnimations(auto_disable_animations == false);
}
});
$('.item-content[data-setting=showhelp] .toggle input').on("change", function () {
var checked = $(this).prop('checked');
setStorage("show_help", checked);
});
$('.item-content[data-setting=oldhomeui] .toggle input').on("change", function () {
var checked = $(this).prop('checked');
setStorage("oldhomeui", checked);
});
$('.item-link[data-setting=units] select').on("change", function () {
setStorage("units", $('.item-link[data-setting=units] select').val());
});
$('.item-link[data-setting=trackzoom] select').on("change", function () {
setStorage("trackzoom", $('.item-link[data-setting=trackzoom] select').val());
});
$('.item-content[data-setting=wakelock] .toggle input').on("change", function () {
var checked = $(this).prop('checked');
setStorage("wakelock", checked);
if (platform_type == "cordova") {
loadSettings();
} else {
app.toast.show({
text: "This setting won't do anything on your device.",
position: "bottom",
destroyOnClose: true,
closeTimeout: 1000 * 10
});
}
});
$('.item-content[data-setting=alertvolume] .range-slider').on('range:changed', function (e, range) {
var val = app.range.get(".item-content[data-setting=alertvolume] .range-slider").getValue();
setStorage("alertvolume", val);
setVolume("alert", val);
playSound("alert");
});
$('.item-content[data-setting=alertradius] .range-slider').on('range:changed', function (e, range) {
var val = app.range.get(".item-content[data-setting=alertradius] .range-slider").getValue();
setStorage("alertradius", val);
});
$('.item-content[data-setting=alertinterval] .range-slider').on('range:changed', function (e, range) {
var val = app.range.get(".item-content[data-setting=alertinterval] .range-slider").getValue();
setStorage("alertinterval", val);
});
$('.item-link[data-setting=mapsource] select').on("change", function () {
setStorage("mapsource", $('.item-link[data-setting=mapsource] select').val());
reloadMap();
});
$('.item-content[data-setting=mapscale] .toggle input').on("change", function () {
var checked = $(this).prop('checked');
setStorage("mapscale", checked ? "true" : "false");
reloadMap();
});
$('.item-content[data-setting=maptype] .toggle input').on("change", function () {
var checked = $(this).prop('checked');
setStorage("maptype", checked ? "leaflet" : "mapbox");
maptype = checked ? "leaflet" : "mapbox";
reloadMap();
});
$('.item-link[data-setting=alertsound] select').on("change", function () {
setStorage("alertsound", $('.item-link[data-setting=alertsound] select').val());
// Reload sound effect stuff to apply new sound
initSFX();
// Play the selected sound
playSound("alert");
});

@ -0,0 +1,58 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* Save something to persistent storage.
* @param {string} key
* @param {string} value non-string values are converted to strings.
* @param {bool} nochangeupdate If true, the lastchange setting won't be updated.
* @returns {undefined}
*/
function setStorage(key, value, nochangeupdate) {
if (typeof nochangeupdate == 'undefined') {
nochangeupdate = false;
}
localStorage.setItem(key, value);
if (!nochangeupdate && !SETTINGS.synckeyblacklist.includes(key)) {
localStorage.setItem("lastchange", Date.now() / 1000);
}
}
/**
* Get an item from persistent storage.
* @param {type} key
* @returns {DOMString}
*/
function getStorage(key) {
return localStorage.getItem(key);
}
/**
* Check if an item is in the persistent storage.
* @param {string} key
* @returns {Boolean}
*/
function inStorage(key) {
return localStorage.getItem(key) != null;
}
/**
* Get all item from persistent storage.
* @returns {Array} [{key: "", value: ""},...]
*/
function getAllStorage() {
var all = [];
for (var key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
all.push({
key: key,
value: getStorage(key)
});
}
}
return all;
}

@ -0,0 +1,111 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
function gatherSyncData() {
var data = {
localStorage: {},
changed: getStorage("lastchange") == null ? 0 : getStorage("lastchange"),
};
if (!inStorage("lastsync")) {
// first time syncing to the server, let's make sure
// the server settings take precedence
data.changed = 1;
}
var allitems = getAllStorage();
for (var i = 0; i < allitems.length; i++) {
var key = allitems[i].key;
var value = allitems[i].value;
if (SETTINGS.synckeyblacklist.includes(key)) {
continue;
}
data.localStorage[key] = value;
}
return data;
}
function syncDataToLocalStorage(data) {
for (var key in data.localStorage) {
if (data.localStorage.hasOwnProperty(key)) {
setStorage(key, data.localStorage[key], true);
}
}
}
function resolveSync(remotedata) {
var localchangetime = getStorage("lastchange");
if (remotedata.changed == null) {
// The server has nothing, this is the first sync
return true;
}
if (localchangetime == null) {
// No local setting changes but since we've gotten this far,
// the server has stuff for us
syncDataToLocalStorage(remotedata);
return true;
}
if (localchangetime < remotedata.changed) {
// The server has newer stuff for us
syncDataToLocalStorage(remotedata);
return true;
}
if (localchangetime >= remotedata.changed) {
// Our local data is newer or the same as the server copy
return true;
}
return false;
}
function syncNow(callback) {
var username = getStorage("username");
var password = getStorage("password");
if (username == null || password == null) {
return false;
}
var data = gatherSyncData();
$.post(SETTINGS.syncapi, {
username: username,
password: password,
data: JSON.stringify(data)
}, function (resp) {
if (resp.status == "OK") {
resolveSync(resp.data);
setStorage("lastsync", Date.now() / 1000);
if (typeof callback == "function") {
callback();
}
}
}, "json");
return true;
}
function loadSettings() {
applyColorTheme();
if (platform_type == "cordova") {
if (getStorage("wakelock") == "true") {
window.powerManagement.acquire(function () {
console.log("Info", 'Wakelock acquired');
}, function () {
console.log("Warn", 'Failed to acquire wakelock');
});
} else {
window.powerManagement.release(function () {
console.log("Info", 'Wakelock released');
}, function () {
console.log("Warn", 'Failed to release wakelock');
});
}
}
}
syncNow(loadSettings);
// Sync every two minutes
setInterval(function () {
syncNow(loadSettings);
}, 1000 * 60 * 2);

@ -0,0 +1,275 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* Generate a UUID.
* From https://stackoverflow.com/a/2117523
* @returns {String}
*/
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/**
* Take a UNIX timestamp (seconds since Jan 1 1970) and format it.
* (Mostly) compatible with PHP's date() function.
* @param {String} date format string, see https://www.php.net/manual/en/function.date.php
* @param {Integer} timestamp UNIX timestamp
* @return {String}
*/
function formatTimestamp(format, timestamp) {
if (typeof timestamp == "undefined") {
timestamp = time();
}
var date = new Date(timestamp * 1000);
var out = "";
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
for (var i = 0; i < format.length; i++) {
var c = format.charAt(i);
// Handle backslash-escaped characters
if (c == "\\" && i < format.length - 1) {
out += format.charAt(i + 1);
i++;
continue;
}
switch (c) {
case "d":
var d = date.getDate();
if (d < 10) {
out += "0";
}
out += d;
break;
case "D":
out += days[date.getDay()].substring(0, 3);
break;
case "j":
out += date.getDate();
break;
case "l":
out += days[date.getDay()];
break;
case "N":
// TODO
break;
case "S":
// TODO
break;
case "w":
out += date.getDay();
break;
case "z":
// TODO
break;
case "W":
// TODO
break;
case "F":
out += months[date.getMonth()];
break;
case "m":
var m = date.getMonth() + 1;
if (m < 10) {
out += "0";
}
out += m;
break;
case "M":
out += months[date.getMonth()].substring(0, 3);
break;
case "n":
out += date.getMonth() + 1;
break;
case "t":
// TODO
break;
case "L":
// TODO
break;
case "o":
// TODO
break;
case "Y":
out += date.getFullYear();
break;
case "y":
var y = (date.getFullYear() + "");
out += y.substring(y.length - 2);
break;
case "a":
if (date.getHours() < 12) {
out += "am";
} else {
out += "pm";
}
break;
case "A":
if (date.getHours() < 12) {
out += "AM";
} else {
out += "PM";
}
break;
case "B":
// TODO
break;
case "g":
var h = date.getHours() % 12;
if (h == 0) {
h = 12;
}
out += h;
break;
case "G":
out += date.getHours();
break;
case "h":
var h = date.getHours() % 12;
if (h == 0) {
h = 12;
}
if (h < 10) {
out += "0";
}
out += h;
break;
case "H":
var h = date.getHours();
if (h < 10) {
out += "0";
}
out += h;
break;
case "i":
var ii = date.getMinutes();
if (ii < 10) {
out += "0";
}
out += ii;
break;
case "s":
var s = date.getSeconds();
if (s < 10) {
out += "0";
}
out += s;
break;
case "u":
out += date.getMilliseconds() * 1000;
break;
case "v":
out += date.getMilliseconds();
break;
case "e":
// TODO
break;
case "I":
// TODO
break;
case "O":
var off = date.getTimezoneOffset();
var m = off % 60;
var h = (off - m) / 60;
if (off >= 0) {
out += "+";
} else {
out += "-";
}
if (h < 10) {
out += "0";
}
out += h;
if (m < 10) {
out += "0";
}
out += m;
break;
case "P":
var off = date.getTimezoneOffset();
var m = off % 60;
var h = (off - m) / 60;
if (off >= 0) {
out += "+";
} else {
out += "-";
}
if (h < 10) {
out += "0";
}
out += h;
out += ":";
if (m < 10) {
out += "0";
}
out += m;
break;
case "T":
// TODO
break;
case "Z":
out += date.getTimezoneOffset() * 60;
break;
case "c":
out += formatTimestamp(timestamp, "Y-m-d\\TH:i:sP");
break;
case "r":
out += formatTimestamp(timestamp, "D, j M Y G:i:s O");
break;
case "U":
out += Math.round(timestamp);
break;
default:
out += c;
}
}
return out;
}
function timestampToDateTimeString(timestamp) {
return timestampToDateString(timestamp) + " " + timestampToTimeString(timestamp);
}
function timestampToDateString(timestamp) {
var date = new Date(timestamp * 1000);
return date.toLocaleDateString();
}
function timestampToTimeString(timestamp) {
var date = new Date(timestamp * 1000);
var pm = date.getHours() >= 12;
var hours = date.getHours() > 12 ? date.getHours() - 12 : date.getHours();
hours = (hours == 0 ? 12 : hours);
var minutes = date.getMinutes();
var time = hours + ":" + (minutes < 10 ? "0" + minutes : minutes) + " " + (pm ? "PM" : "AM");
return time;
}
/**
* Get the current UNIX timestamp in seconds.
* @returns {Number}
*/
function time() {
return Date.now() / 1000;
}
/**
* Get the number of seconds between now and the given timestamp.
* @param {Number} compareto
* @returns {Number}
*/
function timeDiff(compareto) {
return time() - compareto;
}

@ -0,0 +1,53 @@
<!DOCTYPE html>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<title>Lecte</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="assets/images/icons/logo.svg" />
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="node_modules/framework7/css/framework7.bundle.min.css" />
<link rel="stylesheet" href="node_modules/@fortawesome/fontawesome-free/css/all.min.css" />
<link rel="stylesheet" href="node_modules/material-design-icons/iconfont/material-icons.css" />
<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css" />
<link rel="stylesheet" href="node_modules/leaflet.markercluster/dist/MarkerCluster.css" />
<link rel="stylesheet" href="node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css" />
<link rel="stylesheet" href="node_modules/leaflet.locatecontrol/dist/L.Control.Locate.min.css" />
<link rel="stylesheet" href="node_modules/mapbox-gl/dist/mapbox-gl.css">
<link rel="stylesheet" href="assets/css/app.css" />
<link rel="stylesheet" href="assets/css/backdrop.css" />
<link rel="stylesheet" href="assets/css/oled.css" />
<link rel="stylesheet" href="assets/fonts/roboto/Roboto.css" />
<link rel="stylesheet" href="assets/css/tablet.css" />
<script src="cordova.js"></script>
<div id="app" class="color-theme-green">
<div class="view view-main"></div>
</div>
<script src="node_modules/framework7/js/framework7.bundle.min.js"></script>
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/leaflet/dist/leaflet.js"></script>
<script src="node_modules/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
<script src="node_modules/mapbox-gl/dist/mapbox-gl.js"></script>
<script src="node_modules/leaflet.locatecontrol/dist/L.Control.Locate.min.js"></script>
<script src="settings.js"></script>
<script src="assets/js/storage.js"></script>
<script src="assets/js/platform.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/location.js"></script>
<script src="assets/js/map_leaflet.js"></script>
<script src="assets/js/map_mapbox.js"></script>
<script src="assets/js/map.js"></script>
<script src="routes.js"></script>
<script src="assets/js/main.js"></script>

@ -0,0 +1,57 @@
{
"name": "Lecte",
"short_name": "Lecte",
"icons": [
{
"src": "assets/images/icons/32x32.png",
"sizes": "32x32",
"type": "image/png"
},
{
"src": "assets/images/icons/128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "assets/images/icons/144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "assets/images/icons/152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "assets/images/icons/192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/images/icons/256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "assets/images/icons/512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"scope": "/",
"lang": "en-US",
"categories": ["social", "lifestyle", "travel"],
"prefer_related_applications": true,
"related_applications": [
{
"platform": "play",
"url": "https://play.google.com/store/apps/details?id=vote.lecte.Lecte",
"id": "vote.lecte.Lecte"
}
],
"start_url": "index.html",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#4CAF50",
"iarc_rating_id": ""
}

@ -0,0 +1,18 @@
{
"name": "Lecte",
"version": "1.0.0",
"main": "index.html",
"license": "MPL-2.0",
"dependencies": {
"@fortawesome/fontawesome-free": "^5.12.1",
"framework7": "^5.5.1",
"jquery": "^3.4.1",
"leaflet": "^1.5.1",
"leaflet-geometryutil": "^0.9.1",
"leaflet.locatecontrol": "^0.67.0",
"leaflet.markercluster": "^1.4.1",
"mapbox-gl": "^1.8.1",
"material-design-icons": "^3.0.1"
},
"devDependencies": {}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,112 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="credits">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a href="#" class="link icon-only back">
<i class="icon icon-back"></i>
</a>
</div>
<div class="title">Credits</div>
</div>
</div>
<div class="page-content">
<div class="block">
<p>This program is licensed under the Mozilla Public License 2.0.
To get the source code, visit https://source.netsyms.com/Netsyms/Lecte.
<br>
This application relies on and is bundled with third-party code.
See below for the their licenses and where to find source code.
</div>
<div class="block">
<h2>Map Data and Styles</h2>
<p>
Map data &copy; <a href="http://www.openmaptiles.org/" target="_system">OpenMapTiles</a>, &copy; <a href="https://www.openstreetmap.org/copyright" target="_system">OpenStreetMap</a> contributors.
</p>
<h4>OSM Liberty map style</h4>
<pre style="white-space: pre-line; overflow-wrap: break-word;">
Mapbox Open Styles are copyright (c) 2014, Mapbox, all rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Mapbox nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The visual design features of the Mapbox Open Styles (also known as the "look and feel" of the map) are licensed under the Creative Commons Attribution 3.0 license. To view a copy of the license, visit http://creativecommons.org/licenses/by/3.0/. Attribution need not be provided on map images, but should be reasonably accessable from maps based on on these styles (for example, in a webpage linked from copyright notice on the map).
</pre>
<p>
The look and feel of the OSM liberty map design is also derived (although heavily altered) from OSM Bright from Mapbox Open Styles which is licensed under the Creative Commons Attribution 3.0 license.
<br>OSM Liberty is using the Maki POI icon set which is licensed under CC0 1.0 Universal.
<br>OSM Liberty is using the Roboto font family (Copyright 2011 Google). Roboto is licensed under the Apache License, Version 2.0.
</p>
<h4>Klokantech Terrain map style</h4>
<p>
The visual design features of the Klokantech Terrain style (also known as the "look and feel" of
the map) are licensed under the <a href="http://creativecommons.org/licenses/by/4.0/" target="_system">Creative Commons Attribution 4.0 license</a>.
</p>
<pre style="white-space: pre-line; overflow-wrap: break-word;">
Copyright (c) 2016, KlokanTech.com & OpenMapTiles contributors.
Copyright (c) 2014, Mapbox.
All rights reserved.
Modifications by KlokanTech.com & OpenMapTiles contributors.
Derived from "Mapbox Open Styles" https://github.com/mapbox/mapbox-gl-styles
# Code license: BSD 3-Clause License
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</pre>
</div>
<div class="block">
<h2>Code and Libraries</h2>
<pre style="white-space: pre-line; overflow-wrap: break-word;">
{{credits}}
</pre>
</div>
</div>
</div>

@ -0,0 +1,69 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page tabbed" data-name="discover">
<div class="navbar no-tablet">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a class="link" onclick="router.back({force: true, ignoreCache: true})">
<i class="icon icon-back"></i>
<span class="if-not-md">Back</span>
</a>
</div>
<div class="title">Discover</div>
</div>
</div>
<div class="toolbar tabbar toolbar-bottom">
<div class="toolbar-inner">
<a href="#ranking-tab" class="tab-link tab-link-active">Ranking</a>
<a href="#map-tab" id="map-tab-link" class="tab-link">Map</a>
</div>
</div>
{{#if nottablet}}
<div class="tabs-swipeable-wrap">
{{/if}}
<div class="tabs">
<div id="ranking-tab" class="tab tab-active tab-33">
<div class="navbar only-tablet">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a class="link" onclick="router.back({force: true, ignoreCache: true})">
<i class="icon icon-back"></i>
<span class="if-not-md">Back</span>
</a>
</div>
<div class="title">Ranking</div>
</div>
</div>
<div class="page-content row justify-content-center margin-top-tablet padding-bottom-tablet">
<div class="list no-margin-top col-100 medium-80 large-50 elevation-tablet">
<ul>
</ul>
</div>
</div>
</div>
<div id="map-tab" class="page-content tab tab-67">
<div class="navbar only-tablet">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="title">Nearby</div>
</div>
</div>
<div id="mapbox"></div>
</div>
</div>
{{#if nottablet}}
</div>
{{/if}}
<script src="assets/js/discover.js"></script>
</div>

@ -0,0 +1,24 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="login">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a href="#" class="link icon-only back">
<i class="icon icon-back"></i>
</a>
</div>
<div class="title">Log In</div>
</div>
</div>
<div class="page-content" style="overflow-y: hidden;"> <!-- overflow-y:hidden removes an annoying pointless scrollbar that wiggles a few pixels up and down -->
<iframe src="assets/iframeloading.html" id="loginframe" style="border: 0; width: 100%; height: calc(100vh - var(--f7-navbar-height));"></iframe>
</div>
<script src="assets/js/login.js"></script>
</div>

@ -0,0 +1,17 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="profile">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="title">Lecte</div>
</div>
</div>
<div class="page-content noselect">
</div>
</div>

@ -0,0 +1,113 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="settings">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="left">
<a href="#" class="link icon-only" onclick="router.back({force: true, ignoreCache: true})">
<i class="icon icon-back"></i>
</a>
</div>
<div class="title">{{page_title}}</div>
</div>
</div>
<div class="page-content noselect">
<div class="row justify-content-center">
<div class="col-100 medium-60 large-50 xlarge-40 elevation-tablet margin-top-tablet">
<div class="list media-list no-hairlines no-margin-top no-margin-bottom tablet-inset">
<ul>
{{#each settings}}
<li>
{{#if link}}
<div class="item-content item-link" data-setting="{{setting}}" onclick="{{onclick}}">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">{{title}}</div>
</div>
<div class="item-text">{{text}}</div>
</div>
</div>
{{else}}
{{#if toggle}}
<div class="item-content" data-setting="{{setting}}">
<div class="item-inner">
<div style="display: flex; justify-content: between;">
<div class="item-title">
{{title}}
</div>
<div class="item-after" onclick="{
{
onclick
}
}">
<label class="toggle toggle-init">
<input type="checkbox" {{#if checked}}checked{{/if}}>
<span class="toggle-icon"></span>
</label>
</div>
</div>
<div class="item-text">{{text}}</div>
</div>
</div>
{{else}}
{{#if slider}}
<div class="item-content" data-setting="{{setting}}">
<div class="item-inner">
<div class="item-title" style="background-color: rgba(0,0,0,0);">
{{title}}
</div>
<div class="item-subtitle padding-horizontal padding-top">
<div class="range-slider range-slider-init padding-top margin-top" data-label="true">
<input type="range" min="{{min}}" max="{{max}}" step="{{step}}" value="{{value}}">
</div>
</div>
</div>
</div>
{{else}}
{{#if select}}
<a class="item-link smart-select smart-select-init" data-open-in="popover" data-setting="{{setting}}">
<select>
{{#each options}}
<option value="{{value}}"{{#if selected}} selected{{/if}}>{{label}}</option>
{{/each}}
</select>
<div class="item-content">
<div class="item-inner">
<div class="item-title">{{title}}</div>
</div>
</div>
</a>
{{else}}
<div class="item-content" data-setting="{{setting}}" onclick="{
{
onclick
}
}">
<div class="item-inner">
<div class="item-title-row">
<div class="item-title">{{title}}</div>
</div>
<div class="item-text">{{text}}</div>
</div>
</div>
{{/if}}
{{/if}}
{{/if}}
{{/if}}
</li>
{{/each}}
</ul>
</div>
</div>
</div>
</div>
<script src="assets/js/settings.js"></script>
</div>

@ -0,0 +1,17 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<div class="page" data-name="welcome">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner">
<div class="title">Lecte</div>
</div>
</div>
<div class="page-content noselect">
</div>
</div>

@ -0,0 +1,245 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
var routes = [
{
path: '/welcome',
name: 'welcome',
templateUrl: "pages/welcome.html"
},
{
path: '/profile',
name: 'profile',
templateUrl: "pages/profile.html"
},
{
path: '/discover',
name: 'discover',
async: function (routeTo, routeFrom, resolve, reject) {
let tablet = $(window).width() >= 768;
resolve({
templateUrl: "pages/discover.html"
}, {
context: {
nottablet: !tablet
}
})
},
on: {
pageAfterIn: function () {
reloadMap();
}
}
},
{
path: '/settings',
name: 'settings',
async: function (routeTo, routeFrom, resolve, reject) {
var settings = [];
if (getStorage("username") != null && getStorage("password") != null) {
settings.push(
{
setting: "account",
title: "Account",
text: "Logged in as " + getStorage("username")
},
{
setting: "logout",
title: "",
text: "Log out",
link: true,
onclick: "logout()"
}
);
} else {
settings.push(
{
setting: "login",
title: "Log In / Sign Up",
text: "Sign up or log in to vote or create a profile.",
onclick: "router.navigate('/login')",
link: true
}
);
}
settings.push(
{
setting: "maps",
title: "Map",
text: "Change map settings.",
onclick: "router.navigate('/settings/maps')",
link: true
},
{
setting: "display",
title: "Display and Appearance",
text: "Change the app theme.",
onclick: "router.navigate('/settings/display')",
link: true
}
);
settings.push(
{
setting: "versions",
title: "Lecte app v" + app_version,
text: "Copyright &copy; 2020 David Seyler and Netsyms Technologies. Licensed under the Mozilla Public License 2.0.",
onclick: ""
},
{
setting: "opensource",
title: "Credits and open source info",
text: "",
onclick: "router.navigate('/credits')",
link: true
},
{
setting: "privacy",
title: "Privacy policy and legal",
text: "",
onclick: "openBrowser('https://netsyms.com/legal?pk_campaign=LecteApp')",
link: true
});
resolve({
templateUrl: './pages/settings.html'
}, {
context: {
page_title: "Settings",
settings: settings
}
});
},
routes: [
{
path: '/maps',
name: 'settings',
async: function (routeTo, routeFrom, resolve, reject) {
var mapstyles = [];
for (var id in SETTINGS.maptileurls) {
if (SETTINGS.maptileurls.hasOwnProperty(id)) {
mapstyles.push({
value: id,
label: SETTINGS.maptileurls[id].name,
selected: getStorage("mapsource") == id
});
}
}
var settings = [
{
setting: "mapsource",
title: "Map style",
select: true,
options: mapstyles,
text: "Choose which map style to use."
},
{
setting: "units",
title: "Measurement units",
select: true,
options: [
{
value: "metric",
label: "Meters/Kilometers",
selected: getStorage("units") == "metric"
},
{
value: "imperial",
label: "Feet/Miles",
selected: getStorage("units") == "imperial"
}
]
},
{
setting: "mapscale",
title: "Map Scale Ruler",
text: "Show a scale in the corner of the map.",
toggle: true,
checked: getStorage("mapscale") !== "false",
onclick: ""
},
{
setting: "maptype",
title: "Alternative map",
text: "Turn this on if you have problems with the map.",
toggle: true,
checked: getStorage("maptype") == "leaflet",
onclick: ""
}
];
resolve({
templateUrl: './pages/settings.html'
}, {
context: {
page_title: "Map Settings",
settings: settings
}
});
}
},
{
path: '/display',
name: 'settings',
async: function (routeTo, routeFrom, resolve, reject) {
var settings = [
{
setting: "apptheme",
title: "Color theme",
select: true,
options: [
{
value: "auto",
label: "Auto",
selected: getStorage("apptheme") == null || getStorage("apptheme") == "auto"
},
{
value: "dark",
label: "Dark",
selected: getStorage("apptheme") == "dark"
},
{
value: "light",
label: "Light",
selected: getStorage("apptheme") == "light"
}
]
},
{
setting: "animation",
title: "Animations",
select: true,
options: [
{
value: "auto",
label: "On",
selected: getStorage("animation") == null || getStorage("animation") == "auto" || getStorage("animation") == "on"
},
{
value: "off",
label: "Off",
selected: getStorage("animation") == "off"
}
]
}
];
resolve({
templateUrl: './pages/settings.html'
}, {
context: {
page_title: "Display Settings",
settings: settings
}
});
}
}
]
},
{
path: '/credits',
url: './pages/credits.html',
name: 'credits'
}
];

@ -0,0 +1,42 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
var SETTINGS = {
maptileurls: {
liberty: {
url: "https://maps.netsyms.net/styles/osm-liberty/{z}/{x}/{y}.png",
json: "https://maps.netsyms.net/styles/osm-liberty/style.json",
name: "Liberty",
bgcolor: "#EFEFEF"
},
terrain: {
url: "https://maps.netsyms.net/styles/klokantech-terrain/{z}/{x}/{y}.png",
json: "https://maps.netsyms.net/styles/klokantech-terrain/style.json",
name: "Terrain",
bgcolor: "#EDF5F3"
},
fiord: {
url: "https://maps.netsyms.net/styles/fiord-color/{z}/{x}/{y}.png",
json: "https://maps.netsyms.net/styles/fiord-color/style.json",
name: "Dark Fiord",
bgcolor: "#45516E"
},
oledblack: {
url: "https://maps.netsyms.net/styles/oled-black/{z}/{x}/{y}.png",
json: "https://maps.netsyms.net/styles/oled-black/style.json",
name: "OLED Black",
bgcolor: "#000000"
}
},
synckeyblacklist: [
"username", "password",
"user_latitude", "user_longitude",
"lastsync", "lastchange"
],
geocodeapi: "https://api.lecte.vote/geocode.php",
geoipapi: "https://api.lecte.vote/geoip.php",
loginurl: "https://auth.lecte.vote/login/"
}
Loading…
Cancel
Save