Ported task list prototype to Angular Dart. Migrating client codebase to Dart.

This commit is contained in:
Dorian 2013-12-08 01:08:49 -05:00
parent 66cda56502
commit b18ac3ad32
15 changed files with 188 additions and 102 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ passenger_wsgi.py
rookeries_webapp_config.cfg rookeries_webapp_config.cfg
rookeries/static/node_modules rookeries/static/node_modules
rookeries/static/css/penguin-*-theme.css rookeries/static/css/penguin-*-theme.css
rookeries/static/dart/rookeries.dart.*js*
rookeries/static/dart/packages rookeries/static/dart/packages
rookeries/static/dart/test/packages rookeries/static/dart/test/packages
rookeries/static/dart/pubspec.lock rookeries/static/dart/pubspec.lock

View File

@ -35,8 +35,8 @@ from rookeries.core import decorators
@app.route("/") @app.route("/")
def serve_landing_page(): def serve_landing_page():
# TODO Get rid of this. nav_menu = generate_menu(bool(session.get('logged_in')))
return serve_static_file("index.html") return render_template("base.html", navigation_menu=nav_menu)
@app.route("/tasks") @app.route("/tasks")
@ -45,13 +45,6 @@ def serve_tasks():
return render_template("base.html", navigation_menu=nav_menu) return render_template("base.html", navigation_menu=nav_menu)
@app.route("/legacy")
def serve_legacy_js():
# TODO This is deprecated.
nav_menu = generate_menu(bool(session.get('logged_in')))
return render_template("legacy_base.html", navigation_menu=nav_menu)
@app.before_request @app.before_request
def before_session(): def before_session():
g.db_session = database.init_db_session(app.config["DATABASE_URI"]) g.db_session = database.init_db_session(app.config["DATABASE_URI"])
@ -66,8 +59,7 @@ def generate_menu(logged_in):
# TODO Make this generated from the "activated" modules. # TODO Make this generated from the "activated" modules.
menu = [{'name': "Home", 'url': "/"}, menu = [{'name': "Home", 'url': "/"},
{'name': "Tasks", 'url': "/tasks"}, {'name': "Tasks", 'url': "/tasks"},
{'name': "FAQ", 'url': "/docs/faq"}, {'name': "About", 'url': "/about"}]
{'name': "License", 'url': "/docs/license"}]
if logged_in: if logged_in:
menu.append({'name': "Your Profile", 'url': "/user_profile"}) menu.append({'name': "Your Profile", 'url': "/user_profile"})

View File

@ -1,5 +1,5 @@
/** /**
* Rookeries frontend - Controllers * Rookeries frontend - CSS theme switcher.
* *
* (c) Copyright 2013 Dorian Pula * (c) Copyright 2013 Dorian Pula
* @license: AGPL v3 * @license: AGPL v3
@ -8,6 +8,8 @@
part of rookeries; part of rookeries;
// TODO Document and test.
// TODO Consider changing this controller into a directive or component.
/** /**
* Toggle between themes. * Toggle between themes.
* Based off : http://stackoverflow.com/questions/16514330/angularjs-switch-stylesheets-based-on-user-input * Based off : http://stackoverflow.com/questions/16514330/angularjs-switch-stylesheets-based-on-user-input

View File

@ -1,13 +1,16 @@
name: rookeries_client name: rookeries_client
version: 0.0.2 version: 0.0.2
environment: #environment:
sdk: '>=0.8.10+6 <2.0.0' # sdk: '>=0.8.10+6 <2.0.0'
dependencies: dependencies:
angular: any angular: any
browser: any browser: any
js: any js: any
# markdown: any
# bootjack: any
# ice_code_editor: 0.0.12
# angular: # angular:
# git: https://github.com/angular/angular.dart.git # git: https://github.com/angular/angular.dart.git

View File

@ -8,16 +8,27 @@
library rookeries; library rookeries;
import 'dart:async';
import 'dart:convert';
import 'dart:html';
import 'package:intl/intl.dart';
import 'package:angular/angular.dart'; import 'package:angular/angular.dart';
import 'package:di/di.dart'; import 'package:di/di.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
part 'controllers.dart'; part 'controllers.dart';
part 'tasks.dart';
// Rookeries app. // Rookeries app.
class RookeriesApp extends Module { class RookeriesApp extends Module {
RookeriesApp() { RookeriesApp() {
type(SwitchThemeController); type(SwitchThemeController);
type(TaskListController);
type(TaskDetailsController);
type(CheckmarkFilter);
type(DateFormatFilter);
} }
} }

View File

@ -0,0 +1,106 @@
/**
* Rookeries frontend - Tasks app
*
* (c) Copyright 2013 Dorian Pula
* @license: AGPL v3
* @author: Dorian Pula [dorian.pula@amber-penguin-software.ca]
*/
part of rookeries;
class Task {
int id;
String state;
String description;
String priority;
DateTime due_date;
String icon;
bool checked;
Task(this.id, this.state, this.description, this.priority, this.due_date, this.icon, this.checked);
factory Task.fromJsonMap(Map json) {
return new Task(json['id'], json['state'], json['description'], json['priority'],
DateTime.parse(json['due_date']), json['icon'], json['checked']);
}
}
// Controls the task list.
@NgController(
selector: '[task-list]',
publishAs: 'task_list')
class TaskListController {
Http _http;
List<Task> task_list =[];
TaskListController(Http this._http) {
_fetchTasks();
}
void _fetchTasks() {
_http.get('/api/tasks')
.then((HttpResponse response) {
for (Map task in response.data) {
task_list.add(new Task.fromJsonMap(task));
}
}, onError: (Object obj) {
print('Oops. Didn\'t get the list of tasks.');
print(obj);
});
}
void popup(Task task) {
var task_id = task.id;
document.window.alert('I am task #$task_id');
}
}
@NgFilter(name: 'checkmark')
class CheckmarkFilter {
call(input) {
if (input is bool) {
return input ? "\u2713" : "\u2718";
}
}
}
@NgFilter(name: 'date_format')
class DateFormatFilter {
call(date) {
if (date is DateTime) {
DateFormat formatter = new DateFormat("yyyy-MMM-dd");
return formatter.format(date);
}
}
}
// Controls the task details
@NgController(
selector: '[task-details]',
publishAs: 'task')
class TaskDetailsController {
Http _http;
Task task;
TaskDetailsController(Http this._http) {
_fetchTask();
}
void _fetchTask() {
_http.get('/api/tasks')
.then((HttpResponse response) {
task = new Task.fromJsonMap(response.body);
}, onError: (Object obj) {
print('Oops. Didn\'t get the list of tasks.');
print(obj);
});
}
}

View File

@ -59,19 +59,6 @@ rookeriesApp.controller(
}]); }]);
// Toggle between themes.
// Based off : http://stackoverflow.com/questions/16514330/angularjs-switch-stylesheets-based-on-user-input
rookeriesApp.controller(
"SwitchThemeCtrl", ["$scope", "Theme", function ($scope, Theme) {
// Use a nice theme object here.
$scope.theme = Theme.init("daytime");
$scope.switchTheme = function() {
$scope.theme.switch_theme();
}
}]);
rookeriesApp.controller( rookeriesApp.controller(
"NavMenuCtrl", ["$scope", "$state", "NavMenu", function($scope, $state, NavMenu) { "NavMenuCtrl", ["$scope", "$state", "NavMenu", function($scope, $state, NavMenu) {

View File

@ -23,44 +23,6 @@ rookeriesApp
}); });
}]) }])
// Gets the theme dependent on the type of theme being used.
.factory("Theme", function() {
var Theme = {
name: "",
alternative_theme: "",
icon_colour_flag: "",
// Initialize the theme object.
init: function(theme_name) {
"use strict";
if (theme_name === "daytime") {
Theme.name = "daytime";
Theme.alternative_theme = "evening";
Theme.icon_colour_flag = " ";
} else {
Theme.name = "evening";
Theme.alternative_theme = "daytime";
Theme.icon_colour_flag = "icon-white";
}
return Theme;
},
// Allow for switching the themes.
switch_theme: function() {
"use strict";
Theme.init(Theme.alternative_theme);
}
};
return Theme.init("daytime");
} )
// Setup for the navigation menu. // Setup for the navigation menu.
.factory("NavMenu", ["$state", function($state) { .factory("NavMenu", ["$state", function($state) {

View File

@ -1,4 +1,7 @@
<div> <div task-details>
My task ID is {{ task.id }}... <br /><br /> <ul>
I talk about {{ task.description }}. <li>My task ID is {{ task.id }}.</li>
<li>I talk about {{ task.description }}.</li>
<li>I am due on {{ task.due_date | date_format }}</li>
</ul>
</div> </div>

View File

@ -47,15 +47,15 @@ def task_experiment(task_id):
def generate_experimental_task_list(): def generate_experimental_task_list():
task_list = [{ task_list = [{
"id": 1, "state": "Done", "description": "Build out basic ui layout for tasks.", "priority": "Normal", "id": 1, "state": "Done", "description": "Build out basic ui layout for tasks.", "priority": "Normal",
"due_date": "2013 July 05", "icon": "icon-android", "checked": False "due_date": "2013-07-05", "icon": "icon-android", "checked": False
}, { }, {
"id": 2, "state": "In Progress", "description": "Add Angular JS application for tasks.", "id": 2, "state": "In Progress", "description": "Add Angular JS application for tasks.",
"priority": "Urgent", "due_date": "2013 July 05", "icon": "icon-linux", "checked": True "priority": "Urgent", "due_date": "2013-07-05", "icon": "icon-linux", "checked": True
}, { }, {
"id": 3, "state": "Not Started", "description": "Profit ???", "id": 3, "state": "Not Started", "description": "Profit ???",
"priority": "Normal", "due_date": "2013 July 05", "icon": "icon-bug", "checked": False "priority": "Normal", "due_date": "2013-07-05", "icon": "icon-bug", "checked": False
}, { }, {
"id": 4, "state": "Done", "description": "Should be the last task", "priority": "Normal", "id": 4, "state": "Done", "description": "Should be the last task", "priority": "Normal",
"due_date": "2013 December 05", "icon": "icon-save", "checked": True "due_date": "2013-12-05", "icon": "icon-save", "checked": True
}] }]
return task_list return task_list

View File

@ -2,13 +2,13 @@
{# TODO Figure out how to get rid of scope in Angular directive. #} {# TODO Figure out how to get rid of scope in Angular directive. #}
<html ng-app switch-theme> <html ng-app switch-theme>
<head> <head>
{% include "page_header.html" %} {% block page_headers %}{% include "page_header.html" %}{% endblock %}
</head> </head>
<body> <body>
{% block scripts %} {% block scripts %}
<script type="application/dart" src="static/dart/rookeries.dart"></script> <script type="application/dart" src="static/dart/rookeries.dart"></script>
<script src="static/dart/packages/browser/dart.js"></script> <script src="static/dart/packages/browser/dart.js"></script>
{% endblock %} {% endblock %}
{% include "header.html" %} {% include "header.html" %}

View File

@ -1,6 +1,48 @@
{# Body content section #} {# Body content section #}
<div class="col-lg-8 ice-floe" ui-view="content_body_view"> <div class="col-lg-8 ice-floe">
{% block body_content %} {% block body_content %}
{# Insert in Angular apps and regular Jinja2 templates here. -->#} {# Insert in Angular apps and regular Jinja2 templates here. #}
{# TODO Move out into partial or something. #}
{% raw %}
<div task-list>
<h1>Tasks</h1>
<a href="#"><i class="icon-plus"></i> Add New Project</a>
<h2>Project Name <i class="icon-edit"></i> <i class="icon-remove"></i></h2>
<p>Project description here.</p>
<a href="#"><i class="icon-plus"></i> Add New Task</a>
<table class="table-bordered table-striped table">
<thead>
<tr>
<th scope="col">State</th>
<th scope="col">Task</th>
<th scope="col">Priority</th>
<th scope="col">Due Date</th>
<th scope="col">Details [XP]</th>
<th scope="col" colspan="2">Actions</th>
</tr>
</thead>
<tbody>
<!-- tr>
<td><i class="icon-ok"></i> Done</td>
<td><i class="icon-time"></i> In Progress</td>
<td><i class="icon-tasks"></i> Not Started</td>
</tr -->
<!--<tr ng-repeat="task in tasks_list.list | orderBy:orderProp">-->
<tr ng-repeat="task in task_list.task_list">
<td><i class="icon-tasks"></i> {{ task.state }}</td>
<td>{{ task.description }}</td>
<td>{{ task.priority }} - <i ng-class="task.icon"> </i></td>
<td>{{ task.due_date | date_format }} - {{ task.checked | checkmark }}</td>
<td><a ng-href="#/tasks/{{ task.id }}">Details</a></td>
<td><i class="icon-edit" ng-click="task_list.popup(task)"></i></td>
<td><i class="icon-remove"></i></td>
</tr>
</tbody>
</table>
</div>
{% endraw %}
{% endblock %} {% endblock %}
</div> </div>

View File

@ -1,23 +0,0 @@
{# TODO Purge out legacy AngularJS code #}
{% extends "base.html" %}
{% body scripts %}
<script src="static/js/angular.min.js"></script>
<script src="static/js/angular-resource.min.js"></script>
<script src="static/js/ui-bootstrap-tpls-0.4.0.min.js"></script>
<script src="static/js/angular-ui-router-0.0.1.min.js"></script>
<script src="static/js/showdown-0.3.1.min.js"></script>
<script src="static/js/rookeries-application.js"></script>
<script src="static/js/rookeries-controllers.js"></script>
<script src="static/js/rookeries-directives.js"></script>
<script src="static/js/rookeries-filters.js"></script>
<script src="static/js/rookeries-services.js"></script>
{% endbody %}
{% body content %}
<!--Sidebar navigation content-->
<div class="col-lg-2 col-offset-1 ice-menu" ui-view="nav_menu_view"></div>
<!--Body content-->
<div class="col-lg-8 ice-floe" ui-view="content_body_view"></div>
{% endbody %}

View File

@ -14,6 +14,6 @@
<link rel="stylesheet" type="text/css" media="screen" ng-href="static/css/penguin-{{ theme.name }}-theme.css" /> <link rel="stylesheet" type="text/css" media="screen" ng-href="static/css/penguin-{{ theme.name }}-theme.css" />
{% endraw %} {% endraw %}
<link rel="stylesheet" type="text/css" media="screen" href="http://openfontlibrary.org/face/lavoir" /> <!-- link rel="stylesheet" type="text/css" media="screen" href="http://openfontlibrary.org/face/lavoir" />
<link rel="stylesheet" type="text/css" media="screen" href="http://openfontlibrary.org/face/benveno" /> <link rel="stylesheet" type="text/css" media="screen" href="http://openfontlibrary.org/face/benveno" />
<link rel="stylesheet" type="text/css" media="screen" href="http://openfontlibrary.org/face/consolamono" /> <link rel="stylesheet" type="text/css" media="screen" href="http://openfontlibrary.org/face/consolamono" /-->