Permalink
Browse files

Convert user interface to React 0.14.7.

  • Loading branch information...
DavidAnson committed Feb 23, 2016
1 parent ca155a8 commit 35e0b9208ca2955c8cb85b86d534a840cfe84356
Showing with 412 additions and 198 deletions.
  1. +1 −1 LICENSE
  2. +4 −142 default.htm
  3. +29 −54 default.js
  4. +4 −1 offline.appcache
  5. +12 −0 react-dom.min.js
  6. +16 −0 react.min.js
  7. +3 −0 render.js
  8. +343 −0 render.jsx
View
@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014-2015 David Anson
Copyright (c) 2014-2016 David Anson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
View
@@ -15,148 +15,10 @@
<title>PassWeb</title>
</head>
<body>
<h1>PassWeb</h1>
<div id="loginPage">
<form id="loginForm" data-bind="submit: submit" autocomplete="off">
<div>
<input type="text" data-bind="textInput: username" placeholder="Name" required="required"/>
</div>
<div>
<input type="password" data-bind="textInput: password" placeholder="Password" autofocus="autofocus"/>
</div>
<div>
<input type="submit" value="Unlock"/>
</div>
<div>
<label>
<input type="checkbox" data-bind="checked: cache" autocomplete="off"/>
<span>Cache encrypted passwords for offline use</span>
</label>
</div>
</form>
<div class="small important">Important: Only use PassWeb on trusted devices!</div>
<div id="faqs" class="separate" style="display: none" data-bind="visible: true">
<ul data-bind="foreach: $root"><!--
--><li>
<div class="block">
<div class="question" data-bind="text: question"></div>
<div class="answer" data-bind="text: answer"></div>
</div>
</li><!--
--></ul>
</div>
<div class="small separate">Copyright &copy; 2014-2015 by <a href="http://dlaa.me/">David Anson</a>.</div>
</div>
<div id="mainPage" style="display: none">
<input id="filter" type="text" data-bind="textInput: filter" placeholder="Search" accesskey="s"/>
<ul id="entriesList" data-bind="foreach: entries"><!--
--><li data-bind="visible: visible">
<div class="block">
<div class="banner">
<div data-bind="visible: website, attr: { title: id }" class="title ellipsis"><a data-bind="text: id, attr: { href: website }" href="#" target="_blank"></a></div>
<div data-bind="visible: !website, text: id, attr: { title: id }" class="title ellipsis"></div>
<a data-bind="click: $root.edit" href="#" class="edit"><img src="Resources/Edit.svg" alt="Edit" title="Edit" class="icon"/></a>
<a data-bind="click: $root.remove" href="#" class="remove"><img src="Resources/Close.svg" alt="Delete" title="Delete" class="icon"/></a>
</div>
<div class="userpass">
<div>&nbsp;</div>
<div class="username"><a data-bind="text: username, click: $root.copyusername" href="#" class="ellipsis"></a></div>
<div class="password" data-bind="css: { weak: weak }, attr: { title: weak }"><a data-bind="text: $($element).attr('data-mask'), click: $root.copypassword" data-mask="********" href="#" class="ellipsis"></a></div>
</div>
<div class="notes" data-bind="visible: notes">
<pre data-bind="text: notes, visible: false" class="content"></pre>
<div class="drawer">
<a data-bind="click: $root.togglenotes" href="#" class="handle"><img src="Resources/ArrowDown.svg" alt="Notes" title="Notes" class="icon"/></a>
</div>
</div>
</div>
</li><!--
--></ul>
<form id="entryForm" data-bind="submit: submit" autocomplete="off">
<div data-bind="visible: !expanded()">
<a data-bind="click: expand, attr: { accesskey: linkAccessKey }" href="#">New entry...</a>
</div>
<div data-bind="visible: expanded">
<div>
<input type="text" data-bind="textInput: id, attr: { accesskey: inputAccessKey }" placeholder="Title" required="required"/>
</div>
<div>
<input type="text" data-bind="textInput: username" placeholder="User name"/>
</div>
<div>
<input id="password" data-bind="textInput: password, attr: { type: passwordInput }" placeholder="Password" required="required"/>
</div>
<div>
<input type="url" data-bind="textInput: website" placeholder="URL"/>
</div>
<div>
<textarea data-bind="textInput: notes" rows="3" placeholder="Notes"></textarea>
</div>
<div class="buttons">
<a data-bind="click: generatePassword" href="#" class="generate" accesskey="g"><img src="Resources/Lock.svg" alt="Generate password" title="Generate password" class="icon"/></a>
<a data-bind="click: clickSubmit" href="#" class="update"><img src="Resources/Save.svg" alt="Save" title="Save" class="icon"/></a>
<a data-bind="click: clear" href="#" class="clear"><img src="Resources/Undo.svg" alt="Clear" title="Clear" class="icon"/></a>
</div>
<input type="submit" tabindex="-1"/>
<div class="passwordSettings" data-bind="visible: generating">
<div>
<span class="radioLabel">
<input type="radio" name="passwordLength" data-bind="checked: passwordLength" value="8" id="passwordLength8"/><label for="passwordLength8">8</label>
</span><span class="radioLabel">
<input type="radio" name="passwordLength" data-bind="checked: passwordLength" value="12" id="passwordLength12"/><label for="passwordLength12">12</label>
</span><span class="radioLabel">
<input type="radio" name="passwordLength" data-bind="checked: passwordLength" value="16" id="passwordLength16"/><label for="passwordLength16">16</label>
</span><span class="radioLabel">
<input type="radio" name="passwordLength" data-bind="checked: passwordLength" value="24" id="passwordLength24"/><label for="passwordLength24">24</label>
</span><span class="radioLabel">
<input type="radio" name="passwordLength" data-bind="checked: passwordLength" value="32" id="passwordLength32"/><label for="passwordLength32">32</label>
</span>
</div>
<div>
<span class="checkLabel">
<input type="checkbox" data-bind="checked: passwordLower" id="passwordCharactersLower"/><label for="passwordCharactersLower">Lower-case</label>
</span><span class="checkLabel">
<input type="checkbox" data-bind="checked: passwordUpper" id="passwordCharactersUpper"/><label for="passwordCharactersUpper">Upper-case</label>
</span>
</div>
<div>
<span class="checkLabel">
<input type="checkbox" data-bind="checked: passwordNumbers" id="passwordCharactersNumbers"/><label for="passwordCharactersNumbers">Numbers</label>
</span><span class="checkLabel">
<input type="checkbox" data-bind="checked: passwordSymbols" id="passwordCharactersSymbols"/><label for="passwordCharactersSymbols">Symbols</label>
</span>
</div>
</div>
</div>
</form>
<div class="small"><strong>Reminder</strong>: PassWeb resets after 3 minutes of inactivity. Unsaved edits are discarded, so save promptly!</div>
<div class="separate"></div>
<div class="small">
<a href="#">[Change master password]</a>
</div>
</div>
<div id="status">
<div data-bind="visible: progress" style="display: none">
<img src="Resources/Waiting.svg" alt="Busy" title="Busy" class="icon"/>
<span data-bind="text: progress"></span>
</div>
<ul data-bind="foreach: errors, visible: errors().length" style="display: none">
<li>
<span class="dismiss">
<a data-bind="click: $parent.removeError" href="#" class="remove"><img src="Resources/Close.svg" alt="Dismiss" title="Dismiss" class="icon"/></a>
</span>
<img src="Resources/Warning.svg" alt="Warning" title="Warning" class="icon"/>
<span data-bind="text: message"></span>
</li>
</ul>
</div>
<div id="appContainer"></div>
<script src="react.min.js"></script>
<script src="react-dom.min.js"></script>
<script src="render.js"></script>
<script src="jquery-2.1.4.min.js"></script>
<script src="knockout-3.4.0.js"></script>
<script src="lz-string.min.js"></script>
View
@@ -1,5 +1,5 @@
/* jshint browser: true, jquery: true, bitwise: true, curly: true, eqeqeq: true, forin: true, freeze: true, immed: true, indent: 4, latedef: true, newcap: true, noarg: true, noempty: true, nonbsp: true, nonew: true, quotmark: double, undef: true, unused: true, strict: true, trailing: true */
/* global ko, CryptoJS, LZString */
/* global render, ko, CryptoJS, LZString */
(function (undefined) {
"use strict";
@@ -44,11 +44,9 @@
// Delete any previously saved data
removeFromLocalStorage();
}
$("#loginPage").hide();
enableMainPage(true);
readFromLocalStorage();
readFromRemoteStorage();
return false;
};
}
var loginForm = new LoginForm();
@@ -87,16 +85,16 @@
self.timestamp = 0;
self.entries = ko.observableArray();
self.filter = ko.observable("");
self.visibleEntries = ko.observableArray(self.entries());
// Filters the entries according to the search text
function filterEntries() {
var filterUpper = self.filter().toLocaleUpperCase();
self.entries().forEach(function (entry) {
var visible = (0 === filterUpper.length) ||
((-1 !== entry.id.toLocaleUpperCase().indexOf(filterUpper)) ||
(-1 !== (entry.username || "").toLocaleUpperCase().indexOf(filterUpper)));
entry.visible(visible);
});
self.visibleEntries(self.entries().filter(function (entry) {
return (0 === filterUpper.length) ||
(-1 !== entry.id.toLocaleUpperCase().indexOf(filterUpper)) ||
(-1 !== (entry.username || "").toLocaleUpperCase().indexOf(filterUpper));
}));
}
self.entries.subscribe(filterEntries);
self.filter.subscribe(filterEntries);
@@ -114,14 +112,8 @@
};
// Toggles the display of the notes field for an entry
self.togglenotes = function (entry, event) {
self.togglenotes = function () {
resetInactivityTimeout();
var content = $(event.target).closest(".notes").find(".content").first();
if (content.is(":visible")) {
content.hide();
} else {
content.show();
}
};
// Populates the entry field with an entry's data
@@ -212,11 +204,6 @@
self.passwordUpper = ko.observable(true);
self.passwordNumbers = ko.observable(true);
self.passwordSymbols = ko.observable(true);
self.linkAccessKey = ko.observable("n");
self.inputAccessKey = ko.observable(null);
self.passwordInput = ko.computed(function () {
return self.generating() ? "text" : "password";
});
// Clears the entry form
self.clear = function () {
@@ -259,8 +246,7 @@
password: self.password(),
website: self.website(),
notes: $.trim(self.notes()),
weak: isWeakPassword(self.password()),
visible: ko.observable(true)
weak: isWeakPassword(self.password())
};
var existing = userData.entries().filter(function (e) {
return 0 === entryComparer(e, entry);
@@ -284,7 +270,6 @@
// Validation for browsers that don't support HTML validation
window.alert("Incomplete or invalid entry.");
}
return false;
};
// Simulates a click of submit button so browser will run HTML form validation
@@ -295,12 +280,7 @@
// Expands the entry form
self.expand = function () {
resetInactivityTimeout();
self.linkAccessKey(null);
self.inputAccessKey("n");
self.expanded(true);
var entryFormElement = $("#entryForm");
entryFormElement[0].scrollIntoView();
entryFormElement.find("input")[0].focus();
self.expanded(self.expanded() + 1);
};
// Generates a random/secure password
@@ -329,7 +309,6 @@
}
self.password(password);
}
$("#password").select();
self.generating(self.generating() + 1);
};
@@ -358,13 +337,11 @@
var entryForm = new EntryForm();
// Enables the main page UI
var loginPageVisible = ko.observable(true);
var mainPageVisible = ko.observable(false);
function enableMainPage(enable) {
var mainPage = $("#mainPage");
if (enable) {
mainPage.show();
} else {
mainPage.hide();
}
loginPageVisible(false);
mainPageVisible(enable);
}
// Merges imported data with what has already been loaded
@@ -390,7 +367,6 @@
}).sort(entryComparer);
data.entries.forEach(function (e) {
e.weak = isWeakPassword(e.password);
e.visible = ko.observable(true);
});
if (0 === userData.timestamp) {
// No data has been loaded yet; use imported data as-is
@@ -749,21 +725,20 @@
},
];
$(function () {
// Initialize
ko.applyBindings(loginForm, $("#loginForm")[0]);
ko.applyBindings(faqs, $("#faqs")[0]);
ko.applyBindings(status, $("#status")[0]);
ko.applyBindings(userData, $("#entriesList")[0]);
ko.applyBindings(userData, $("#filter")[0]);
ko.applyBindings(entryForm, $("#entryForm")[0]);
$("#mainPage input").add("#mainPage textarea").on("input", resetInactivityTimeout);
$(window).on("scroll", resetInactivityTimeout);
$("#mainPage .small a").on("click", function (event) {
changeMasterPassword();
event.preventDefault();
});
// setTimeout call works around an Internet Explorer bug where textarea/placeholder's input event fires asynchronously on load (http://dlaa.me/blog/post/inputplaceholder)
window.setTimeout(clearInactivityTimeout, 10);
// Initialize
render({
app: {
loginPageVisible: loginPageVisible,
mainPageVisible: mainPageVisible,
changeMasterPassword: changeMasterPassword,
resetInactivityTimeout: resetInactivityTimeout
},
loginForm: loginForm,
faqs: faqs,
status: status,
userData: userData,
entryForm: entryForm
});
// setTimeout call works around an Internet Explorer bug where textarea/placeholder's input event fires asynchronously on load (http://dlaa.me/blog/post/inputplaceholder)
window.setTimeout(clearInactivityTimeout, 10);
})();
View
@@ -1,5 +1,5 @@
CACHE MANIFEST
# 2015-12-16
# 2016-02-22
aes.js
default.css
default.htm
@@ -8,6 +8,9 @@ favicon.ico
jquery-2.1.4.min.js
knockout-3.4.0.js
lz-string.min.js
react.min.js
react-dom.min.js
render.js
sha512.js
Resources/background.png
Resources/favicon-114.png
View
@@ -0,0 +1,12 @@
/**
* ReactDOM v0.14.7
*
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e(require("react"));else if("function"==typeof define&&define.amd)define(["react"],e);else{var f;f="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,f.ReactDOM=e(f.React)}}(function(e){return e.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED});
View

Large diffs are not rendered by default.

Oops, something went wrong.
Oops, something went wrong.

0 comments on commit 35e0b92

Please sign in to comment.