Permalink
Browse files

Convert user interface to React 0.14.7.

  • Loading branch information...
1 parent ca155a8 commit 35e0b9208ca2955c8cb85b86d534a840cfe84356 @DavidAnson committed Feb 23, 2016
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
Oops, something went wrong.
Oops, something went wrong.

0 comments on commit 35e0b92

Please sign in to comment.