Skip to content

Commit

Permalink
Merge branch 'multi-select'
Browse files Browse the repository at this point in the history
* multi-select:
  Some minor visual adjustments
  Implement partial export via multiple selection
  Move export logic and ui into separate component
  implement multi-select feature allow deleting multiple records
  • Loading branch information
MaKleSoft committed Oct 31, 2017
2 parents e202dac + 8bebe94 commit a66409e
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 125 deletions.
6 changes: 6 additions & 0 deletions app/src/ui/data/data.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@
this.dispatch("record-deleted", record);
}

deleteRecords(records) {
records.forEach((r) => r.remove());
this.saveCollection();
this.dispatch("records-changed");
}

addRecords(records) {
this.collection.add(records);
this.saveCollection();
Expand Down
50 changes: 50 additions & 0 deletions app/src/ui/export/export-dialog.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<link rel="import" href="../../styles/shared.html">
<link rel="import" href="../base/base.html">
<link rel="import" href="../dialog/dialog.html">

<dom-module id="pl-export-dialog">

<template>
<style include="shared">
.message {
font-weight: bold;
}
</style>

<pl-dialog id="dialog">
<div class="message">[[ $l("Export {0} Records", records.length) ]]</div>
<pl-export records="[[ records ]]" on-click="_close" class="tiles-2"></pl-export>
</pl-dialog>

</template>

<script>
(function() {

const { BaseElement, LocaleMixin } = padlock;

class PlExportDialog extends LocaleMixin(BaseElement) {

static get is() { return "pl-export-dialog"; }

static get properties() { return {
records: Array
}; }

_close() {
this.$.dialog.open = false;
}

export(records) {
this.records = records;
this.$.dialog.open = true;
}

}

window.customElements.define(PlExportDialog.is, PlExportDialog);

})();
</script>

</dom-module>
169 changes: 169 additions & 0 deletions app/src/ui/export/export.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<link rel="import" href="../../styles/shared.html">
<link rel="import" href="../base/base.html">
<link rel="import" href="../data/data.html">
<link rel="import" href="../dialog/dialog-mixin.html">
<link rel="import" href="../icon/icon.html">
<link rel="import" href="../locale/locale.html">

<dom-module id="pl-export">

<template>

<style include="shared">
:host {
display: block;
}

.row {
display: flex;
align-items: center;
}

.label {
padding: 0 15px;
flex: 1;
}

pl-icon {
width: 50px;
height: 50px;
}
</style>

<div class="tiles tiles-1 row">
<div class="label">[[ $l("As CSV") ]]</div>
<pl-icon icon="copy" class="tap" on-click="_copyCSV"></pl-icon>
<pl-icon icon="download" class="tap" on-click="_downloadCSV" hidden$="[[ _isMobile() ]]"></pl-icon>
</div>
<div class="tiles tiles-2 row">
<div class="label">[[ $l("As Encrypted File") ]]</div>
<pl-icon icon="copy" class="tap" on-click="_copyEncrypted"></pl-icon>
<pl-icon icon="download" class="tap" on-click="_downloadEncrypted" hidden$="[[ _isMobile() ]]"></pl-icon>
</div>

</template>

<script>
/* global zxcvbn */
(() => {

const exportCSVWarning = $l(
"WARNING: Exporting to CSV format will save your data without encyryption of any " +
"kind which means it can be read by anyone. We strongly recommend exporting your data as " +
"a secure, encrypted file, instead! Are you sure you want to proceed?"
);

const { LocaleMixin, DialogMixin, DataMixin, BaseElement } = padlock;
const { applyMixins } = padlock.util;
const { isCordova, setClipboard } = padlock.platform;
const { toPadlock, toCSV } = padlock.exp;

class PlExport extends applyMixins(
BaseElement,
DataMixin,
LocaleMixin,
DialogMixin
) {

static get is() { return "pl-export"; }

static get properties() { return {
records: Array
}; }

_downloadCSV() {
this.confirm(exportCSVWarning, $l("Download"), $l("Cancel"))
.then((confirm) => {
if (confirm) {
setTimeout(() => {
const date = new Date().toISOString().substr(0, 10);
const fileName = `padlock-export-${date}.csv`;
const csv = toCSV(this.records);
const a = document.createElement("a");
a.href = `data:application/octet-stream,${encodeURIComponent(csv)}`;
a.download = fileName;
a.click();
this.dispatch("data-exported");
}, 500);
}
});
}

_copyCSV() {
this.confirm(exportCSVWarning, $l("Copy to Clipboard"), $l("Cancel"))
.then((confirm) => {
if (confirm) {
setClipboard(toCSV(this.records))
.then(() => this.alert($l("Your data has successfully been copied to the system " +
"clipboard. You can now paste it into the spreadsheet program of your choice.")));
this.dispatch("data-exported");
}
});
}

_getEncryptedData() {
return this.prompt($l("Please choose a password to protect your data. This may be the same as " +
"your master password or something else, but make sure it is sufficiently strong!"),
$l("Enter Password"), "password", $l("Confirm"), $l("Cancel"))
.then((pwd) => {
if (!pwd) {
if (pwd === "") {
this.alert($l("Please enter a password!"));
}
return Promise.reject();
}
if (zxcvbn(pwd).score < 2) {
return this.confirm($l(
"WARNING: The password you entered is weak which makes it easier for " +
"attackers to break the encryption used to protect your data. Try to use a longer " +
"password or include a variation of uppercase, lowercase and special characters as " +
"well as numbers."
), $l("Use Anyway"), $l("Choose Different Password")).then((confirm) => {
if (!confirm) {
return Promise.reject();
}

return toPadlock(this.records, pwd);
});
} else {
return toPadlock(this.records, pwd);
}
});
}

_downloadEncrypted() {
this._getEncryptedData()
.then((data) => {
const a = document.createElement("a");
const date = new Date().toISOString().substr(0, 10);
const fileName = `padlock-export-${date}.pls`;
a.href = `data:application/octet-stream,${encodeURIComponent(data)}`;
a.download = fileName;
setTimeout(() => {
a.click();
this.dispatch("data-exported");
}, 500);
});
}

_copyEncrypted() {
this._getEncryptedData()
.then((data) => {
setClipboard(data)
.then(() => this.alert($l("Your data has successfully been copied to the system clipboard.")));
this.dispatch("data-exported");
});
}

_isMobile() {
return isCordova();
}

}

window.customElements.define(PlExport.is, PlExport);

})();
</script>

</dom-module>
12 changes: 12 additions & 0 deletions app/src/ui/icon/icon.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,18 @@
content: "\f070";
}

:host([icon="checked"]) > div::before {
content: "\f046";
}

:host([icon="unchecked"]) > div::before {
content: "\f096";
}

:host([icon="share"]) > div::before {
content: "\f045";
}

:host([icon="logo"]) > div::before {
font-family: "Padlock";
content: "\0041";
Expand Down
Loading

0 comments on commit a66409e

Please sign in to comment.