Make userlisting load data; add more style
+var baseURL = '';
+
+// The API state is static so that any instance can use login-dependent API
+// calls
+enyo.kind({
+ name: "blerg.API",
+ kind: "Component",
+ statics: {
+ apiInitialized: false,
+ loggedIn: false,
+ username: "",
+ },
+ create: function() {
+ this.inherited(arguments);
+ if (blerg.API.apiInitialized) {
+ if (blerg.API.loggedIn) {
+ setTimeout(function() {
+ this.bubble('onLoginSuccessful', {username: blerg.API.username});
+ }.bind(this), 0);
+ }
+ return;
+ }
+
+ if (enyo.getCookie('auth') && enyo.getCookie('username')) {
+ blerg.API.loggedIn = true;
+ blerg.API.username = enyo.getCookie('username');
+ // Defer the signal until everything's initialized
+ setTimeout(function() {
+ this.bubble('onLoginSuccessful', {username: blerg.API.username});
+ }.bind(this), 0);
+ }
+
+ blerg.API.apiInitialized = true;
+ },
+ signup: function(username, password) {
+ var req = new enyo.Ajax({
+ url: baseURL + '/create',
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ if (inResponse.status == 'success') {
+ this.bubble('onSignupSuccess', {username: username});
+ } else {
+ this.bubble('onSignupFailure', {username: username});
+ }
+ }.bind(this));
+ req.error(function() {
+ this.bubble('onSignupFailure', {username: username});
+ }.bind(this));
+ req.go({
+ username: username,
+ password: password,
+ });
+ },
+ login: function(username, password) {
+ var req = new enyo.Ajax({
+ url: baseURL + '/login',
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ if (inResponse.status == 'success') {
+ blerg.API.loggedIn = true;
+ blerg.API.username = username;
+ enyo.setCookie('username', username);
+ this.bubble('onLoginSuccessful', {username: username});
+ } else {
+ enyo.setCookie('username', '', {"Max-Age": 0});
+ this.bubble('onLoginFailed');
+ }
+ }.bind(this));
+ req.go({
+ username: username,
+ password: password
+ });
+ },
+ logout: function() {
+ var req = new enyo.Ajax({
+ url: baseURL + '/logout',
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ blerg.API.loggedIn = false;
+ enyo.setCookie('auth', '', {"Max-Age": 0});
+ this.bubble('onLogoutSuccessful');
+ }.bind(this));
+ req.go({
+ username: blerg.API.username
+ });
+ enyo.setCookie('username', '', {"Max-Age": 0});
+ },
+ changePassword: function(oldpassword, newpassword) {
+ var req = new enyo.Ajax({
+ url: baseURL + '/passwd',
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ if (inResponse.status == 'success') {
+ this.bubble('onPasswordChangeSuccessful');
+ } else {
+ this.bubble('onPasswordChangeFailed');
+ }
+ }.bind(this));
+ req.go({
+ username: blerg.API.username,
+ password: oldpassword,
+ new_password: newpassword
+ });
+ },
+ loadUserRecords: function(username, from ,to) {
+ var url;
+ if (from != undefined && to != undefined) {
+ url = baseURL + '/get/' + username + '/' + from + '-' + to;
+ } else {
+ url = baseURL + '/get/' + username;
+ }
+
+ var req = new enyo.Ajax({
+ url: url
+ });
+ req.response(function(inSender, inResponse) {
+ this.bubble('onItemsLoaded', {
+ type: 'user',
+ username: username,
+ from: from,
+ to: to,
+ entries: inResponse
+ });
+ }.bind(this));
+ req.error(function(inSender, inResponse) {
+ if (inResponse == 404)
+ this.bubble('onUserNotFound');
+ else
+ this.bubble('onAPIError', {response: inResponse});
+ }.bind(this));
+ req.go();
+ },
+ loadTagRecords: function(type, tag) {
+ var url;
+ switch(type) {
+ case 'tag':
+ // Apache eats the hash, even encoded. Probably a security
+ // feature.
+ url = baseURL + '/tag/H' + tag;
+ break;
+ case 'ref':
+ url = baseURL + '/tag/%40' + tag;
+ break;
+ default:
+ throw new Error("Invalid tag type: " + type);
+ return;
+ }
+ var req = new enyo.Ajax({
+ url: url
+ });
+ req.response(function(inSender, inResponse) {
+ this.bubble('onItemsLoaded', {
+ type: 'tag',
+ tagType: type,
+ tag: tag,
+ entries: inResponse
+ });
+ }.bind(this));
+ req.go();
+ },
+ getFeedInfo: function() {
+ if (!blerg.API.loggedIn)
+ throw new Error('Cannot request feed status when not logged in');
+
+ var req = new enyo.Ajax({
+ url: baseURL + '/feedinfo',
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ this.bubble('onFeedInfo', inResponse);
+ }.bind(this));
+ req.go({
+ username: blerg.API.username
+ });
+ },
+ loadFeed: function() {
+ if (!blerg.API.loggedIn)
+ throw new Error('Cannot request feed status when not logged in');
+
+ var req = new enyo.Ajax({
+ url: baseURL + '/feed',
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ this.bubble('onItemsLoaded', {
+ type: "feed",
+ entries: inResponse
+ });
+ }.bind(this));
+ req.go({
+ username: blerg.API.username
+ });
+ },
+ getSubscriptionStatus: function(username) {
+ var req = new enyo.Ajax({
+ url: baseURL + '/feedinfo/' + username,
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ this.bubble('onSubscriptionStatus', {
+ username: username,
+ subscribed: inResponse.subscribed
+ });
+ }.bind(this));
+ req.go({
+ username: blerg.API.username
+ });
+ },
+ subscribe: function(username) {
+ var req = new enyo.Ajax({
+ url: baseURL + '/subscribe/' + username,
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ this.bubble('onSubscriptionStatus', {
+ username: username,
+ subscribed: inResponse.status == "success"
+ });
+ }.bind(this));
+ req.go({
+ username: blerg.API.username
+ });
+ },
+ unsubscribe: function(username) {
+ var req = new enyo.Ajax({
+ url: baseURL + '/unsubscribe/' + username,
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ this.bubble('onSubscriptionStatus', {
+ username: username,
+ subscribed: inResponse.status != "success"
+ });
+ }.bind(this));
+ req.go({
+ username: blerg.API.username
+ });
+ },
+ post: function(data) {
+ var req = new enyo.Ajax({
+ url: baseURL + '/put',
+ method: 'POST'
+ });
+ req.response(function(inSender, inResponse) {
+ if (inResponse && inResponse.status == 'success') {
+ this.bubble('onPostSuccessful', {
+ username: blerg.API.username,
+ data: data
+ });
+ } else {
+ this.bubble('onPostFailed', {
+ username: blerg.API.username,
+ data: data
+ });
+ }
+ }.bind(this));
+ req.go({
+ username: blerg.API.username,
+ data: data
+ });
+ }
+});
body {
+ font: Prelude, sans-serif;
}
.navigator-breadcrumbs {
display: block;
width: 100%;
padding: 8pt;
- margin: 8pt 0;
+}
+
+.vertical-button + .vertical-button {
+ margin-top: 8pt;
}
.crumb-button {
}
.record {
- margin-bottom: 8pt;
+ margin: 8pt 0 8pt 0;
+ font-size: 12pt;
+}
+
+.record + hr {
+ width: 50%;
+ border: none;
+ border-bottom: 1px solid #AAB;
+ margin: 12pt auto;
+}
+
+.record p {
+ margin: 8pt 0 0 0;
+}
+
+.record .info {
+ color: #8F8F8F;
+ font-size: small;
+ font-style: italic;
+ margin-top: 2pt;
+}
+
+.record .info a {
+ color: #8F8F8F;
}
-.record > p {
- margin-top: 0;
+.record h1 {
+ font-size: 18pt;
+ margin: 8pt 0 1em 0;
+}
+
+.record h2 {
+ font-size: 16pt;
+ margin: 8pt 0 1em 0;
+}
+
+.record h3 {
+ font-size: 14pt;
+ margin: 8pt 0 1em 0;
+}
+
+.record h4 {
+ font-size: 14pt;
+ font-weight: normal;
+ margin: 8pt 0 1em 0;
+}
+
+.record h5 {
+ font-size: 14pt;
+ font-weight: normal;
+ font-style: italic;
+ margin: 8pt 0 1em 0;
}
+enyo.kind({
+ name: "blerg.PasswdDialog",
+ kind: "onyx.Popup",
+ classes: "blerg-dialog",
+ autoDismiss: true,
+ centered: true,
+ floating: true,
+ modal: true,
+ components: [
+ {tag: "h2", content: "Change Password"},
+ {name: "spinner", kind: "OldSchoolSpinner", showing: false, style: "position: absolute; top: 8px; right: 8px;"},
+ {kind: "onyx.Groupbox", components: [
+ {kind: "onyx.InputDecorator", components: [
+ {name: "oldpassword", kind: "onyx.Input", placeholder: "Old Password", type: "password"}
+ ]}
+ ]},
+ {kind: "onyx.Groupbox", components: [
+ {kind: "onyx.InputDecorator", components: [
+ {name: "password1", kind: "onyx.Input", placeholder: "New Password", type: "password"}
+ ]},
+ {kind: "onyx.InputDecorator", components: [
+ {name: "password2", kind: "onyx.Input", placeholder: "New Password (again)", type: "password"}
+ ]}
+ ]},
+ {name: "changePasswordError", tag: "p", showing: false, classes: "blerg-error", content: "I couldn't change your password. Are you sure you have the right old password?"},
+ {name: "passwordMatchError", tag: "p", showing: false, classes: "blerg-error", content: "Your new passwords don't match."},
+ {name: "changeButton", kind: "onyx.Button", content: "Change", onclick: "changeClick", classes: "onyx.affirmative"},
+ {kind: "onyx.Button", content: "Cancel", onclick: "cancelClick", classes: "onyx-negative"},
+ {name: "api", kind: "blerg.API",
+ onPasswordChangeSuccessful: "passwordChangeSuccessful",
+ onPasswordChangeFailed: "passwordChangeFailed"}
+ ],
+ hideErrors: function() {
+ this.$.changePasswordError.hide();
+ this.$.passwordMatchError.hide();
+ },
+ changeClick: function() {
+ this.hideErrors();
+ if (this.$.oldpassword.getValue() == '') {
+ this.$.changePasswordError.show();
+ return;
+ }
+ if (this.$.password1.getValue() != this.$.password2.getValue()) {
+ this.$.passwordMatchError.show();
+ return;
+ }
+ this.$.changeButton.setDisabled(true);
+ this.$.spinner.show();
+ this.$.spinner.start();
+ this.$.api.changePassword(this.$.oldpassword.getValue(), this.$.password1.getValue());
+ },
+ cancelClick: function() {
+ this.hide();
+ },
+ passwordChangeSuccessful: function(inSender, inEvent) {
+ this.$.oldpassword.setValue('');
+ this.$.password1.setValue('');
+ this.$.password2.setValue('');
+ this.$.changeButton.setDisabled(false);
+ this.$.spinner.hide();
+ this.$.spinner.stop();
+ this.cancelClick();
+ alert("Password Changed Successfully");
+ },
+ passwordChangeFailed: function(inSender, inEvent) {
+ this.$.changeButton.setDisabled(false);
+ this.$.spinner.hide();
+ this.$.spinner.stop();
+ this.hideErrors();
+ this.$.changePasswordError.show();
+ }
+});
+enyo.kind({
+ name: "blerg.SignupDialog",
+ kind: "onyx.Popup",
+ classes: "blerg-dialog",
+ autoDismiss: true,
+ centered: true,
+ floating: true,
+ modal: true,
+ components: [
+ {tag: "h2", content: "Sign Up"},
+ {name: "spinner", kind: "OldSchoolSpinner", showing: false, style: "position: absolute; top: 8px; right: 8px;"},
+ {kind: "onyx.Groupbox", components: [
+ {kind: "onyx.InputDecorator", components: [
+ {name: "username", kind: "onyx.Input", placeholder: "Username"}
+ ]},
+ {kind: "onyx.InputDecorator", components: [
+ {name: "password", kind: "onyx.Input", placeholder: "Password", type: "password"}
+ ]}
+ ]},
+ {name: "message", tag: "p", content: "No, really, that's all I need. I don't want to send you email. It's too much work to program in email updates. :-P"},
+ {name: "signupError", tag: "p", showing: false, classes: "blerg-error", content: "I couldn't sign you up. That username is already in use, or something went wrong on the backend. *shrug*"},
+ {name: "signupButton", kind: "onyx.Button", content: "Signup", onclick: "signupClick", classes: "onyx-affirmative"},
+ {kind: "onyx.Button", content: "Cancel", onclick: "cancelClick", classes: "onyx-negative"},
+ {name: "api", kind: "blerg.API",
+ onSignupSuccess: "signupSuccess",
+ onSignupFailure: "signupFailure"}
+ ],
+ signupClick: function() {
+ this.$.signupButton.setDisabled(true);
+ this.$.spinner.show();
+ this.$.spinner.start();
+ this.$.api.signup(this.$.username.getValue(), this.$.password.getValue());
+ },
+ cancelClick: function() {
+ this.$.signupError.hide();
+ this.$.message.show();
+ this.$.username.setValue('');
+ this.$.password.setValue('');
+ this.hide();
+ },
+ signupSuccess: function(inSender, inEvent) {
+ this.$.signupButton.setDisabled(false);
+ this.$.spinner.hide();
+ this.$.spinner.stop();
+ this.bubble('onTryLogin', {
+ username: this.$.username.getValue(),
+ password: this.$.password.getValue()
+ });
+ this.cancelClick();
+ },
+ signupFailure: function(inSender, inEvent) {
+ this.$.signupButton.setDisabled(false);
+ this.$.spinner.hide();
+ this.$.spinner.stop();
+ this.$.message.hide();
+ this.$.signupError.show();
+ }
+});
published: {
user: null
},
+ items: [],
+ lastItem: null,
components: [
{name: "title", content: "Listing", tag: "h2"},
- {name: "list", kind: "List", classes: "listing-content", onSetupItem: "setupItem", count:10, fit: true, components: [
- {name: "record", kind: "blerg.Record", ontap: "itemTap"}
- ]}
+ {name: "list", kind: "List", classes: "listing-content", onSetupItem: "setupItem", fit: true, components: [
+ {name: "record", kind: "blerg.Record", ontap: "itemTap"},
+ {name: "separator", tag: "hr"}
+ ]},
+ {name: "api", kind: "blerg.API",
+ onItemsLoaded: "itemsLoaded"}
],
create: function() {
this.inherited(arguments);
this.userChanged();
},
+ setupItem: function(inSender, inEvent) {
+ var r = this.items[inEvent.index];
+ this.$.record.setTimestamp(r.timestamp);
+ this.$.record.setData(r.data);
+ this.$.record.setRecord(r.record);
+ if (inEvent.index == this.items.length - 1) {
+ this.$.separator.hide();
+ } else {
+ this.$.separator.show();
+ }
+ },
userChanged: function() {
- this.title = "@" + this.user
- this.$.title.setContent(this.title);
+ if (this.user != null) {
+ this.title = "@" + this.user
+ this.$.title.setContent(this.title);
+ this.items = [];
+ this.lastItem = null;
+ this.loadItems();
+ }
},
- setupItem: function(inSender, inEvent) {
- this.$.record.setAuthor("Blerger");
- this.$.record.setTimestamp(new Date().getTime() / 1000);
- this.$.record.setData("Blerg " + inEvent.index);
+ loadItems: function() {
+ if (this.lastItem == null) {
+ this.$.api.loadUserRecords(this.user);
+ } else {
+ var to = this.lastItem - 1;
+ if (to >= 0) {
+ var from = to > 50 ? to - 50 : 0;
+ this.$.api.loadUserRecords(this.user, from, to);
+ }
+ }
+ },
+ itemsLoaded: function(inSender, inEvent) {
+ this.items = this.items.concat(inEvent.entries);
+ this.lastItem = inEvent.from;
+ this.$.list.setCount(this.items.length);
+ this.$.list.refresh();
},
itemTap: function(inSender, inEvent) {
- this.bubble('onNavigate', {kind: "UserListing", user: inEvent.originator.getAuthor()});
}
});
kind: "Listing",
title: "Blërg",
components: [
+ {tag: 'h2', content: "Welcome to Blërg!"},
{kind: "Scroller", classes: "listing-content", components: [
- {content: "Welcome to Blërg!"},
{kind: "onyx.Button", classes: "onyx-affirmative vertical-button", content: "Create an account"},
{kind: "onyx.Button", classes: "vertical-button", content: "Log In"},
{kind: "onyx.Button", classes: "vertical-button", content: "Listing", ontap: "showListing"},
]}
],
showListing: function() {
- this.bubble('onNavigate', {kind: "UserListing", user: "user" + Math.floor(Math.random() * 1000)});
+ this.bubble('onNavigate', {kind: "UserListing", user: "bytex64"});
}
});
enyo.depends(
'$lib/layout',
'$lib/onyx',
+ 'API.js',
'Util.js',
+ 'SignupDialog.js',
+ 'PasswdDialog.js',
'Blerg.css',
'Blerg.js',
'Record.js',