diff --git a/api/__init__.py b/api/__init__.py deleted file mode 100644 index c1bb42d..0000000 --- a/api/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from flask import Blueprint - -api = Blueprint('api', __name__) - -from .controller import * - diff --git a/api/controller/__init__.py b/api/controller/__init__.py deleted file mode 100644 index a27d8eb..0000000 --- a/api/controller/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -import pkgutil -from flask.ext.httpauth import HTTPBasicAuth - -auth = HTTPBasicAuth() - -__all__ = [] - -for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): - __all__.append(module_name) - -from . import * - diff --git a/api/controller/accounts.py b/api/controller/accounts.py deleted file mode 100644 index c7ce08c..0000000 --- a/api/controller/accounts.py +++ /dev/null @@ -1,134 +0,0 @@ -""" - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -""" -from . import auth -from .. import api -from ..model import db, session_scope -from ..model.accounts import Account -from ..model.entries import Entry -from ..model.operations import Operation -from flask import json, request -from sqlalchemy import func, case, cast, extract, distinct -from forms.accounts import AccountIdForm, AccountForm - -@api.route("/accounts", methods=["GET"]) -@auth.login_required -def get_accounts(): - """ - Returns accounts with their solds. - """ - with session_scope() as session: - query = session.query( - Account.id.label("id"), - Account.name.label("name"), - Account.authorized_overdraft.label("authorized_overdraft"), - func.sum(Entry.value).label("future"), - func.sum(case([(Entry.pointed, Entry.value,)], else_=cast(0, db.Numeric(15, 2)))).label("pointed"), - func.sum(case([(Entry.operation_date < func.now(), Entry.value,)], else_=cast(0, db.Numeric(15, 2)))).label("current") - ).outerjoin(Entry).group_by(Account.id).order_by(Account.id) - - return json.dumps([{ - "id": i.id, - "name": i.name, - "authorized_overdraft": i.authorized_overdraft, - "current": str(i.current), - "pointed": str(i.pointed), - "future": str(i.future) - } for i in query.all()]) - -@api.route("/accounts////") -@auth.login_required -def get_account_status(account_id, year, month): - with session_scope() as session: - query = session.query( - func.sum(case([(func.sign(Operation.value) == -1, Operation.value)], else_=0)).label("expenses"), - func.sum(case([(func.sign(Operation.value) == 1, Operation.value)], else_=0)).label("revenues"), - func.sum(Operation.value).label("balance") - ).filter( - Operation.account_id == account_id - ).filter( - func.date_trunc('month', Operation.operation_date) == "%s-%s-01" % (year, month) - ).group_by(Operation.account_id) - - if query.count() == 1: - result = query.one() - revenues = result.revenues - expenses = result.expenses - balance = result.balance - else: - revenues = 0.0 - expenses = 0.0 - balance = 0.0 - - return json.dumps({ - "expenses": str(expenses), - "revenues": str(revenues), - "balance": str(balance) - }) - -@api.route("/accounts//months") -@auth.login_required -def get_months(account_id): - with session_scope() as session: - query = session.query( - distinct(func.lpad(cast(extract("year", Entry.operation_date), db.String), 4, '0')).label("year"), - func.lpad(cast(extract("month", Entry.operation_date), db.String), 2, '0').label("month") - ).filter(Entry.account_id == account_id).order_by("year", "month") - - return json.dumps([{ - "year": i.year, - "month": i.month.rjust(2, '0') - } for i in query.all()]) - -@api.route("/accounts", methods=["PUT"]) -@auth.login_required -def add_account(): - with session_scope() as session: - account = Account(request.json['name'], request.json['authorized_overdraft']) - - session.add(account) - - return json.dumps("Account added.") - - -@api.route("/accounts/", methods=["PUT"]) -@auth.login_required -def update_account(account_id): - account_form = AccountForm() - - if account_form.validate(): - with session_scope() as session: - account = session.query(Account).filter(Account.id == account_id).first() - - account.name = request.json['name'] - account.authorized_overdraft = request.json['authorized_overdraft'] - - session.merge(account) - - return json.dumps("Account #%s updated." % account_id) - else: - return json.dumps({'ok': False, 'error_type': 'validation', 'errors': account_form.errors}) - -@api.route("/accounts/", methods=["DELETE"]) -@auth.login_required -def delete_account(account_id): - with session_scope() as session: - account = session.query(Account).filter(Account.id == account_id).first() - - session.delete(account) - - return json.dumps("Account #%s deleted." % account_id) - diff --git a/api/controller/entries.py b/api/controller/entries.py deleted file mode 100644 index d23cbac..0000000 --- a/api/controller/entries.py +++ /dev/null @@ -1,101 +0,0 @@ -""" - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -""" -from .. import api -from ..model import db, session_scope -from ..model.entries import Entry -from ..model.operations import Operation -from ..model.scheduled_operations import ScheduledOperation -from flask import json, request -from sqlalchemy import func, desc -from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method -from sqlalchemy.orm import sessionmaker, column_property, aliased -from sqlalchemy.sql import func, select, case - -@api.route("/entries///") -def get_entries(account_id, year, month): - """ - Return entries for an account, year, and month. - """ - with session_scope() as session: - base_query = session.query( - Operation, - case(whens={Operation.canceled: None}, else_=func.sum(Operation.value).over(partition_by="canceled", order_by="operation_date, value desc, label desc")).label("sold") - ).filter(Operation.account_id == account_id).order_by( - desc(Operation.operation_date), - Operation.value, - Operation.label, - ).subquery() - - query = session.query(base_query).select_from(base_query).filter(func.date_trunc('month', base_query.c.operation_date) == "%s-%s-01" % (year, month)) - - return json.dumps([{ - "id": i.id, - "pointed": i.pointed, - "operation_date": i.operation_date.strftime("%Y-%m-%d"), - "label": i.label, - "value": str(i.value), - "category": i.category, - "sold": str(i.sold) if not i.canceled else None, - "account_id": i.account_id, - "canceled": i.canceled, - "scheduled_operation_id": i.scheduled_operation_id - } for i in query.all()]) - -@api.route("/entries", methods=["PUT"]) -def add_entry(): - with session_scope() as session: - entry = Entry( - operation_date = request.json['operation_date'], - pointed = request.json['pointed'], - label = request.json['label'], - value = request.json['value'], - category = request.json['category'], - account_id = request.json['account_id'], - scheduled_operation_id = request.json['scheduled_operation_id'] - ) - - session.add(entry) - - return json.dumps("Entry added.") - -@api.route("/entries/", methods=["PUT"]) -def update_entry(entry_id): - with session_scope() as session: - entry = session.query(Entry).filter(Entry.id == entry_id).first() - - entry.id = entry_id - entry.operation_date = request.json['operation_date'] - entry.pointed = request.json['pointed'] - entry.label = request.json['label'] - entry.value = request.json['value'] - entry.category = request.json['category'] - entry.account_id = request.json['account_id'] - entry.scheduled_operation_id = request.json['scheduled_operation_id'] - - session.merge(entry) - - return json.dumps("Entry #%s updated." % entry_id) - -@api.route("/entries/", methods=["DELETE"]) -def delete_entry(entry_id): - with session_scope() as session: - entry = session.query(Entry).filter(Entry.id == entry_id).first() - - session.delete(entry) - - return json.dumps("Entry #%s deleted." % entry_id) - diff --git a/api/controller/scheduled_operations.py b/api/controller/scheduled_operations.py deleted file mode 100644 index f69148e..0000000 --- a/api/controller/scheduled_operations.py +++ /dev/null @@ -1,85 +0,0 @@ -from .. import api -from ..model import db, session_scope -from ..model.scheduled_operations import ScheduledOperation -from flask import json, request -from sqlalchemy import func, desc -from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method -from sqlalchemy.orm import sessionmaker, column_property -from sqlalchemy.sql import func, select - -@api.route("/scheduled_operations/") -def get_scheduled_operations(account_id): - """ - Return entries for an account, year, and month. - """ - with session_scope() as session: - query = session.query( - ScheduledOperation - ).select_from( - session.query(ScheduledOperation) - .filter(ScheduledOperation.account_id == account_id) - .order_by( - desc(ScheduledOperation.day), - ScheduledOperation.value, - ScheduledOperation.label, - ).subquery() - ) - - return json.dumps([{ - "id": i.id, - "start_date": i.start_date.strftime("%Y-%m-%d"), - "stop_date": i.stop_date.strftime("%Y-%m-%d"), - "day": str(i.day), - "frequency": str(i.frequency), - "label": i.label, - "value": str(i.value), - "category": i.category, - "account_id": i.account_id - } for i in query.all()]) - -@api.route("/scheduled_operations", methods=["PUT"]) -def add_scheduled_operation(): - with session_scope() as session: - scheduledOperation = ScheduledOperation( - start_date = request.json['start_date'], - stop_date = request.json['stop_date'], - day = request.json['day'], - frequency = request.json['frequency'], - label = request.json['label'], - value = request.json['value'], - category = request.json['category'], - account_id = request.json['account_id'] - ) - - session.add(scheduledOperation) - - return json.dumps("Scheduled operation added.") - -@api.route("/scheduled_operations/", methods=["PUT"]) -def update_scheduled_operation(scheduled_operation_id): - with session_scope() as session: - scheduledOperation = session.query(ScheduledOperation).filter(ScheduledOperation.id == scheduled_operation_id).first() - - scheduledOperation.id = scheduled_operation_id - scheduledOperation.start_date = request.json['start_date'], - scheduledOperation.stop_date = request.json['stop_date'], - scheduledOperation.day = request.json['day'], - scheduledOperation.frequency = request.json['frequency'], - scheduledOperation.label = request.json['label'] - scheduledOperation.value = request.json['value'] - scheduledOperation.category = request.json['category'] - scheduledOperation.account_id = request.json['account_id'] - - session.merge(scheduledOperation) - - return json.dumps("Scheduled operation #%s updated." % scheduled_operation_id) - -@api.route("/scheduled_operations/", methods=["DELETE"]) -def delete_scheduled_operation(scheduled_operation_id): - with session_scope() as session: - scheduledOperation = session.query(ScheduledOperation).filter(ScheduledOperation.id == scheduled_operation_id).first() - - session.delete(scheduledOperation) - - return json.dumps("Scheduled operation #%s deleted." % scheduled_operation_id) - diff --git a/api/controller/users.py b/api/controller/users.py deleted file mode 100644 index 2abf1c5..0000000 --- a/api/controller/users.py +++ /dev/null @@ -1,29 +0,0 @@ -""" - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Accountant is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -""" - -from . import auth -from .. import api -from ..model import db, session_scope - -@auth.verify_password -def verify_password(username, password): - - if username == 'titi' and password == 'toto': - return True - # Update principal identity - - return False diff --git a/api/model/__init__.py b/api/model/__init__.py deleted file mode 100644 index 58959f2..0000000 --- a/api/model/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -from contextlib import contextmanager -from flask.ext.sqlalchemy import SQLAlchemy -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import scoped_session, sessionmaker - -db = SQLAlchemy() - -@contextmanager -def session_scope(): - #session = scoped_session(sessionmaker(autocommit = False, autoflush = False, bind = engine)) - session = db.session - #Base.query = session.query_property() - - try: - yield session - session.commit() - except: - session.rollback() - raise - finally: - session.close() - -import pkgutil - -__all__ = [] - -for loader, module_name, is_pkg in pkgutil.walk_packages(__path__): - __all__.append(module_name) - -from . import * - diff --git a/api/model/accounts.py b/api/model/accounts.py deleted file mode 100644 index 1bbbaf1..0000000 --- a/api/model/accounts.py +++ /dev/null @@ -1,27 +0,0 @@ -""" - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -""" -from . import db - -class Account(db.Model): - id = db.Column(db.Integer, primary_key = True) - name = db.Column(db.String(200), nullable = False) - authorized_overdraft = db.Column(db.Integer, nullable = True, default = 0) - - def __init__(self, name, authorized_overdraft): - self.name = name - self.authorized_overdraft = authorized_overdraft - diff --git a/api/model/entries.py b/api/model/entries.py deleted file mode 100644 index 225fb39..0000000 --- a/api/model/entries.py +++ /dev/null @@ -1,46 +0,0 @@ -""" - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -""" -from . import db -from .accounts import Account -from .scheduled_operations import ScheduledOperation -from sqlalchemy import func, desc -from sqlalchemy.orm import column_property -from sqlalchemy.sql import func, select - -class Entry(db.Model): - id = db.Column(db.Integer, primary_key=True) - pointed = db.Column(db.Boolean, nullable = False, default = False) - operation_date = db.Column(db.Date, nullable = False) - label = db.Column(db.String(500), nullable = False) - value = db.Column(db.Numeric(15, 2), nullable = False) - account_id = db.Column(db.Integer, db.ForeignKey('account.id')) - scheduled_operation_id = db.Column(db.Integer, db.ForeignKey('scheduled_operation.id')) - - account = db.relationship(Account, backref = db.backref('entry', lazy="dynamic")) - scheduled_operation = db.relationship(ScheduledOperation, backref = db.backref('entry', lazy="dynamic")) - - category = db.Column(db.String(100), nullable = True) - - def __init__(self, pointed, label, value, account_id, operation_date = None, category = None, scheduled_operation_id = None): - self.pointed = pointed - self.operation_date = operation_date - self.label = label - self.value = value - self.account_id = account_id - self.category = category - self.scheduled_operation_id = scheduled_operation_id - diff --git a/api/model/operations.py b/api/model/operations.py deleted file mode 100644 index 42a67aa..0000000 --- a/api/model/operations.py +++ /dev/null @@ -1,48 +0,0 @@ -""" - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -""" -from . import db - -from .accounts import Account -from .scheduled_operations import ScheduledOperation - -from sqlalchemy import func, desc -from sqlalchemy.orm import column_property -from sqlalchemy.sql import func, select - -class Operation(db.Model): - id = db.Column(db.Integer, primary_key=True) - pointed = db.Column(db.Boolean, nullable = False, default = False) - operation_date = db.Column(db.Date, nullable = False) - label = db.Column(db.String(500), nullable = False) - value = db.Column(db.Numeric(15, 2), nullable = False) - account_id = db.Column(db.Integer, db.ForeignKey('account.id')) - scheduled_operation_id = db.Column(db.Integer, db.ForeignKey('scheduled_operation.id')) - - account = db.relationship(Account, backref = db.backref('operation', lazy="dynamic")) - - category = db.Column(db.String(100), nullable = True) - - canceled = db.Column(db.Boolean, nullable = False) - - def __init__(self, pointed, label, value, account_id, operation_date = None, category = None): - self.pointed = pointed - self.operation_date = operation_date - self.label = label - self.value = value - self.account_id = account_id - self.category = category - diff --git a/api/model/scheduled_operations.py b/api/model/scheduled_operations.py deleted file mode 100644 index 098ed62..0000000 --- a/api/model/scheduled_operations.py +++ /dev/null @@ -1,30 +0,0 @@ -from . import db -from .accounts import Account -from sqlalchemy import func, desc -from sqlalchemy.orm import column_property -from sqlalchemy.sql import func, select - -class ScheduledOperation(db.Model): - id = db.Column(db.Integer, primary_key=True) - start_date = db.Column(db.Date, nullable = False) - stop_date = db.Column(db.Date, nullable = False) - day = db.Column(db.Integer, nullable = False) - frequency = db.Column(db.Integer, nullable = False) - label = db.Column(db.String(500), nullable = False) - value = db.Column(db.Numeric(15, 2), nullable = False) - account_id = db.Column(db.Integer, db.ForeignKey('account.id')) - - account = db.relationship(Account, backref = db.backref('scheduled_operation', lazy="dynamic")) - - category = db.Column(db.String(100), nullable = True) - - def __init__(self, start_date, stop_date, day, frequency, label, value, account_id, category = None): - self.start_date = start_date - self.stop_date = stop_date - self.day = day - self.frequency = frequency - self.label = label - self.value = value - self.account_id = account_id - self.category = category - diff --git a/app.py b/app.py deleted file mode 100644 index 3c8d227..0000000 --- a/app.py +++ /dev/null @@ -1,40 +0,0 @@ -""" - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Accountant is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -""" - -from api import api -#from api.controller import login_manager -from api.model import db -from flask import Flask -from flask.ext.sqlalchemy import SQLAlchemy -from frontend import frontend -from sqlalchemy.orm import sessionmaker -import config - -# The app -app = Flask(__name__, static_folder = None) - -app.config['SQLALCHEMY_DATABASE_URI'] = config.db_uri -app.config['SQLALCHEMY_RECORD_QUERIES'] = config.debug -app.config['WTF_CSRF_ENABLED'] = False -app.config['SECRET_KEY'] = 'my_secret_key' - -db.init_app(app) -#login_manager.init_app(app) - -app.register_blueprint(frontend, url_prefix='') -app.register_blueprint(api, url_prefix='/api') - diff --git a/config.py.dist b/config.py.dist deleted file mode 100644 index 1dafb97..0000000 --- a/config.py.dist +++ /dev/null @@ -1,3 +0,0 @@ - -db_uri='postgresql://accountant:accountant@localhost/accountant' -debug=True diff --git a/frontend/__init__.py b/frontend/__init__.py deleted file mode 100644 index 308f2a0..0000000 --- a/frontend/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -from flask import Blueprint, redirect, render_template, jsonify - -frontend = Blueprint('frontend', __name__, template_folder='templates', static_folder='static') - -@frontend.route('/') -def root(): - return redirect('index.html') - -@frontend.route('/index.html') -def index(): - return render_template('index.html') - -@frontend.route('/scheduler.html') -def scheduler(): - return render_template('scheduler.html') - -@frontend.errorhandler(BaseException) -def default_errorhandler(error): - return jsonify(title="Error", text="Error %s" % str(error)), 500 diff --git a/frontend/static/css/main.css b/frontend/static/css/main.css deleted file mode 100644 index b71eb74..0000000 --- a/frontend/static/css/main.css +++ /dev/null @@ -1,7 +0,0 @@ -.italic { - font-style: italic -} - -.stroke { - text-decoration: line-through -} diff --git a/frontend/static/js/accounts.js b/frontend/static/js/accounts.js deleted file mode 100644 index 755f338..0000000 --- a/frontend/static/js/accounts.js +++ /dev/null @@ -1,197 +0,0 @@ -/* - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . - */ -// Account object -function account() { - this.id=ko.observable(); - this.name=ko.observable(); - this.authorized_overdraft=ko.observable(); - this.future=ko.observable(); - this.current=ko.observable(); - this.pointed=ko.observable(); -}; - -// The AccountController. -var AccountController = function($scope, $http, $rootScope, $window) { - // Account store and selection - $scope.account = null; - $scope.accounts = []; - - $scope.savedAccount = null; - $scope.editingAccount = null; - $scope.removedAccount = null; - - $scope.accountClass = function(account) { - if(account == $scope.account) { - return "active"; - } - }; - - $scope.valueClass = function(account, value) { - if(!account) { - return - } - - if(value < account.authorized_overdraft) { - return "text-error"; - } else if(value < 0) { - return "text-warning"; - } - }; - - $scope.addAccount = function() { - $scope.editingAccount = { - id: null, - name: null, - authorized_overdraft: null - }; - - angular.element("#edit-account").modal(); - }; - - $scope.show = function() { - console.debug("show"); - }; - - $scope.editAccount = function(account) { - if(account) { - $scope.editingAccount = account; - $scope.savedAccount = angular.copy(account); - } - }; - - $scope.cancelEditAccount = function(account, modalScope) { - if($scope.savedAccount) { - account.name = $scope.savedAccount.name; - account.authorized_overdraft = $scope.savedAccount.authorized_overdraft; - } - - $scope.editingAccount = null; - $scope.savedAccount = null; - - if(modalScope && modalScope.dismiss) { - modalScope.dismiss(); - } - }; - - $scope.saveAccount = function(account, modalScope) { - // Ajax call to save the entry. - var type; - var url = "/api/accounts"; - - if(account.id) { - url += "/" + account.id; - } - - $http.put(url, angular.toJson(account)).success(function(data) { - $.pnotify({ - type: "success", - title: "Save", - text: data - }); - - $scope.editingAccount = null; - $scope.savedAccount = null; - - if(modalScope && modalScope.dismiss) { - modalScope.dismiss(); - } - - // Reload accounts to update solds. - $scope.loadAccounts(); - }).error(function(data) { - if(data.error_type == 'validation') { - angular.forEach(data.errors, function(errors, field) { - // $scope.form[field].$setValidity('server', false); - //$scope.errors[field] = errors.join(', '); - }); - } else { - $.pnotify({ - type: "error", - title: "Save", - text: data.errors - }); - } - }); - }; - - // Function to remove of an entry. - $scope.accountRemove = function(account, modalScope) { - $http.delete("/api/accounts/" + account.id).success(function (data) { - $.pnotify({ - type: "success", - title: "Save", - text: data - }); - - // Reload accounts to update solds. - $scope.loadAccounts(); - - if(modalScope && modalScope.dismiss) { - modalScope.dismiss(); - } - }); - }; - - // Function to load accounts - $scope.loadAccounts = function() { - $http.get("/api/accounts").success($scope.loadAccounts_success); - }; - - $scope.loadAccounts_success = function (data) { - // Update accounts - $scope.accounts = angular.fromJson(data); - - var accountToSelect = null - - // Reset selected account to the new instance corresponding to the old one. - if($scope.account) { - // Find the new instance of the previously selected account. - angular.forEach($scope.accounts, function(account) { - if(account.id == $scope.account.id) { - accountToSelect = account; - } - }); - } - - // Set selected account to first one if not yet selected - if(!accountToSelect && $scope.accounts.length > 0){ - accountToSelect = $scope.accounts[0]; - } - - // Reset to account to select - $scope.account = accountToSelect; - - $scope.$emit("accountsLoadedEvent", {account: $scope.account}); - }; - - // Callback function to select a new account. - $scope.selectAccount = function(account) { - if(account) { - $scope.account = account; - - $scope.$emit("accountsLoadedEvent", {account: $scope.account}); - } - }; - - $rootScope.$on("entrySavedEvent", $scope.loadAccounts); - $rootScope.$on("entryRemovedEvent", $scope.loadAccounts); - $rootScope.$on("operationSavedEvent", $scope.loadAccounts); - $rootScope.$on("operationRemovedEvent", $scope.loadAccounts); - - $scope.loadAccounts(); -}; - diff --git a/frontend/static/js/entries.js b/frontend/static/js/entries.js deleted file mode 100644 index d134941..0000000 --- a/frontend/static/js/entries.js +++ /dev/null @@ -1,451 +0,0 @@ -/* - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . - */ -var EntryController = function($scope, $http, $rootScope, $filter) { - // Entry store and selection - $scope.entries = []; - $scope.categories = []; - $scope.chartValues = []; - $scope.pieChartValues = []; - $scope.selectedItem = null; - - $scope.account = null; - - // Placeholder for saved value to cancel entry edition - $scope.savedItem = null; - - $scope.entriesLoaded = function(entries) { - var entriesReversed = entries.slice().reverse(); - - var categories = []; - - var chartValues = []; - - var pieChartValuesTmp = {}; - var pieChartValues = []; - - angular.forEach(entriesReversed, function(entry) { - var category = entry.category; - var value = entry.value ? Number(entry.value) : null; - var sold = entry.sold ? Number(entry.sold) : null; - var operation_date = entry.operation_date; - - if(operation_date && sold) { - chartValues.push([entry.operation_date, sold]); - } - - if(category && category != '') { - if(categories.indexOf(category) == -1) { - categories.push(category); - } - - if(value && value < 0.0) { - var oldValue = 0.0; - - if(pieChartValuesTmp[category]) { - oldValue = pieChartValuesTmp[category]; - } - - pieChartValuesTmp[category] = oldValue - value; - } - } - }); - - $scope.chartValues = chartValues; - - // Second pass: transform to an array readable by jqplot. - var pieChartValues = []; - angular.forEach(pieChartValuesTmp, function(value, key) { - pieChartValues.push([key, value]); - }); - - $scope.pieChartValues = pieChartValues; - - //$scope.categories.length = 0; - //$scope.categories.concat(categories); - $scope.categories = categories; - - nv.addGraph($scope.drawChart); - nv.addGraph($scope.drawPieChart); - //$scope.drawPieChart(pieChartValues, "#expense-categories-chart-placeholder"); - //$scope.drawPieChart(); - }; - - $scope.getAccountStatus = function(account, month) { - if(account != null && month != null) { - $http.get("/api/accounts/" + account.id + "/" + month.year + "/" + month.month). - success($scope.getAccountStatus_success); - } - }; - - $scope.getAccountStatus_success = function(status) { - $scope.accountStatus = status; - }; - - // Function to load entries from server for a specific account and month. - $scope.loadEntries = function(account, month) { - if(account) { - $scope.account = account; - } - - // Clean up selected entry. - $scope.selectedItem = null; - $scope.savedItem = null; - - if(account && month) { - $http.get("/api/entries/" + account.id + "/" + month.year + "/" + month.month).success($scope.loadEntries_success); - } else { - $scope.loadEntries_success(null); - } - }; - - // Load entries success callback - $scope.loadEntries_success = function(data) { - var entries = [{ - id: null, - pointed: false, - operation_date: null, - label: null, - value: null, - sold: null, - pointedsold: null, - category: null, - account_id: null, - state: 'new', - canceled: false, - scheduled_operation_id: null - }]; - - if(data) { - entries = entries.concat(angular.fromJson(data)); - } - - $scope.entries = entries; - - $scope.$emit("entriesLoadedEvent", {entries: entries}); - }; - - // Returns the CSS class for a pointed entry. - $scope.pointedEntryClass = function(entry) { - if(entry.pointed) { - return "active"; - } - }; - - // Returns the CSS class for an entry row. - $scope.entryRowClass = function(entry) { - if($scope.isSaved(entry)) { - cssclass=""; - } else { - cssclass="italic"; - } - - if(entry.canceled) { - cssclass += " stroke"; - } - - if(entry.sold < $scope.account.authorized_overdraft) { - cssclass += " danger"; - } else if (entry.sold < 0) { - cssclass += " warning"; - } - - return cssclass; - }; - - // Returns the CSS class for an entry sold. - $scope.entryValueClass = function(sold) { - if(sold && sold < $scope.account.authorized_overdraft) { - return 'text-danger'; - } else if (sold && sold < 0) { - return 'text-warning'; - } - }; - - // Starts editing an entry - $scope.editEntry = function(entry) { - // Cancel previous editing. - if($scope.selectedItem) { - $scope.cancelEditEntry($scope.selectedItem); - } - - // Save current entry values. - $scope.savedItem = angular.copy(entry); - $scope.selectedItem = entry; - - // Enter edit state. - entry.state='edit'; - }; - - // Returns true if the entry is a new one. - $scope.isNew = function(entry) { - return !$scope.isSaved(entry) && (entry.state === 'edit' || entry.state === 'new'); - }; - - // Returns true if the entry is in editing state. - $scope.isEditing = function(entry) { - return entry.state === 'edit' || entry.state === 'new'; - }; - - // Returns true if the entry is in displaying state. - $scope.isDisplaying = function(entry) { - return !entry.state || entry.state === 'display'; - }; - - // Returns true if the entry is a scheduled one. - $scope.isSaved = function(entry) { - return entry.id != null; - } - - $scope.iconSaveClass = function(entry) { - if(!$scope.isSaved(entry)) { - return "fa fa-plus"; - } else if ($scope.isEditing(entry)) { - return "fa fa-floppy-o"; - } - }; - - $scope.iconCancelClass = function(entry) { - if($scope.isNew(entry)) { - return "fa fa-times"; - } else if ($scope.isEditing(entry)) { - return "fa fa-ban"; - } - }; - - // Cancel current editing entry or clears field if a new one. - $scope.cancelEditEntry = function(entry) { - if ($scope.savedItem == null) { - // We are cancelling the new entry, just reset it. - entry.id = null; // id should not change, but just in case... - entry.pointed = false; - entry.operation_date = null; - entry.label = null; - entry.value = null; - entry.account_id = $scope.account.id; // account_id should not change, but just in case... - entry.category = null; - entry.canceled = false; - entry.scheduled_operation_id = null; - - // Reset state to new. - entry.state = 'new'; - } else { - // Reset selected item fields to saved item ones. - entry.id = $scope.savedItem.id; // id should not change, but just in case... - entry.pointed = $scope.savedItem.pointed; - entry.operation_date = $scope.savedItem.operation_date; - entry.label = $scope.savedItem.label; - entry.value = $scope.savedItem.value; - entry.account_id = $scope.savedItem.account_id; // account_id should not change, but just in case... - entry.category = $scope.savedItem.category; - entry.canceled = $scope.savedItem.canceled; - entry.scheduled_operation_id = $scope.savedItem.scheduled_operation_id; - - // Reset saved and selected items to null. - $scope.savedItem = null; - $scope.selectedItem = null; - - // Enter display state. - entry.state = 'display'; - } - }; - - // Points an entry. - $scope.pointEntry = function(entry) { - if(entry.pointed) { - entry.pointed = false; - } else { - entry.pointed = true; - } - - // Save the entry if not new. - if(!$scope.isNew(entry)) { - $scope.saveEntry(entry); - } - }; - - // Saves an entry. - $scope.saveEntry = function(entry) { - // Affects the account ID if not (should never happen) - if(!entry.account_id) { - entry.account_id = $scope.account.id; - } - - // Prepare the Ajax call to save the entry. - var type; - var url = "/api/entries"; - - if($scope.isSaved(entry)) { - url += "/" + entry.id; - } - - // Ajax call to save an entry - $http.put(url, angular.toJson(entry)).success(function(data) { - $.pnotify({ - type: "success", - title: "Save", - text: data - }); - - // $scope.savedItem = null; - - // Send the "entry saved" event. - $scope.$emit("entrySavedEvent", entry); - }); - }; - - $scope.removeEntry = function(entry) { - $scope.removingEntry = entry; - $("#remove_entry").modal({ - keyboard: false, - }); - }; - - $scope.hideRemoveEntryPopup = function() { - $scope.removingEntry = null; - $("#remove_entry").modal("hide"); - }; - - // Removes an entry. - $scope.confirmRemoveEntry = function() { - // Cancel current editing. - if ($scope.removingEntry) { - $http.delete("/api/entries/" + $scope.removingEntry.id).success(function (result) { - $.pnotify({ - type: "success", - title: "Delete", - text: result - }); - - // Send the "entry removed" event. - $scope.$emit("entryRemovedEvent", $scope.removingEntry); - - $scope.hideRemoveEntryPopup(); - }); - } - }; - - $scope.closeModal = function(modalScope) { - // Close the modal dialog - if(modalScope && modalScope.dismiss) { - modalScope.dismiss(); - } - }; - - // Function to draw the sold evolution chart. - $scope.drawChart = function() { - // Clear previous chart - var entries = $scope.chartValues; - console.debug("drawChart", entries); - - var width = 700; - var height = 300; - - //if(entries && entries.length > 1) { - // Prepare for today vertical line. - var today = new Date(); - today.setHours(0); - today.setMinutes(0); - - // Find first and last days to set limits of the x axis. - var day = 24 * 60 * 60 * 1000; - - var firstDate = $filter('date')(new Date(Date.parse(entries[0][0]).valueOf() - day), 'yyyy-MM-dd'); - var lastDate = $filter('date')(new Date(Date.parse(entries[entries.length -1][0]).valueOf() + day), 'yyyy-MM-dd'); - - var chart = nv.models.lineChart().options({ - x: function(d) { return d3.time.format("%Y-%m-%d").parse(d[0]); }, - y: function(d) { return new Number(d[1]); }, - transitionDuration: 250, - showXAxis: true, - showYAxis: true, - width: width, - height: height, - }); - - chart.lines.interpolate("monotone"); - - chart.xAxis - .axisLabel("Date") - .tickFormat(function(d) { - return d3.time.format("%Y-%m-%d")(new Date(d)); - }); - //chart.xAxis.scale().range([firstDate, lastDate]); - - chart.yAxis - .axisLabel("Solde") - .tickFormat(d3.format('.02f')); - - // FIXME add vertical line for today - graph = d3.select("#entries-chart-placeholder").datum([ - { color: "orange", key: "Zero", values:[ - [firstDate, "0"], - [lastDate, "0"] - ]}, - { color: "red", key: "Authorized overdraft", values : [ - [firstDate, new Number($scope.account.authorized_overdraft)], - [lastDate, new Number($scope.account.authorized_overdraft)] - ]}, - { color: "darkblue", key: "Sold evolution", values: entries}, - ]) - .transition().duration(1200) - .attr("width", width) - .attr("height", height) - .call(chart); - - nv.utils.windowResize(chart.update); - - return chart; - }; - - // Function to draw the expense category pie chart. - $scope.drawPieChart = function() { - // FIXME retrieve width and height from DOM - var width = 300; - var height = 300; - - var chart = nv.models.pieChart() - .x(function(d) { console.debug(d); return d[0]; }) - .y(function(d) { return d[1]; }) - .width(width) - .height(height) - .showLabels(true); - - d3.select("#expense-categories-chart-placeholder") - .datum($scope.pieChartValues) - .transition().duration(1200) - .attr('width', width) - .attr('height', height) - .call(chart); - - nv.utils.windowResize(chart.update); - - return chart - }; - - $rootScope.$on("monthsLoadedEvent", function(event, args){ - $scope.loadEntries(args.account, args.month); - }); - - $rootScope.$on("monthsLoadedEvent", function(event, args){ - $scope.getAccountStatus(args.account, args.month); - }); - - $scope.$on("entriesLoadedEvent", function(event, args) { - $scope.entriesLoaded(args.entries); - }); -}; - diff --git a/frontend/static/js/months.js b/frontend/static/js/months.js deleted file mode 100644 index 050bc39..0000000 --- a/frontend/static/js/months.js +++ /dev/null @@ -1,116 +0,0 @@ -/* - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . - */ -// Month object -function month() { - this.year = null; - this.month = null; -} - - -var MonthController = function($scope, $http, $rootScope) { - // Month store and selection - $scope.months = null; - $scope.month = null; - $scope.account = null; - - $scope.monthClass = function(month) { - if(month == $scope.month) { - return "active"; - } - }; - - // Function to load months - $scope.loadMonths = function(account) { - if(account) { - $scope.account = account; - } - - if($scope.account) { - $http.get("/api/accounts/" + $scope.account.id + "/months").success($scope.loadMonths_success); - } else { - $scope.$emit("monthsLoadedEvent", {account: null, month: null}); - } - }; - - $scope.loadMonths_success = function (data) { - // Update months - $scope.months = angular.fromJson(data); - - var monthToSelect = null; - - var today = new Date(); - var currentYear = today.getFullYear().toString(); - var currentMonth = (today.getMonth() + 1 < 10 ? "0" : "") + (today.getMonth() + 1); - var found = false; - - var lastIndex = 0; - - // Add current month if not present. - angular.forEach($scope.months, function(month) { - if(!found) { - if (month.year == currentYear && month.month == currentMonth) { - found = true; - } - - if (parseInt(month.year) < parseInt(currentYear) || (month.year == currentYear && parseInt(month.month) < parseInt(currentMonth))) { - lastIndex++; - } - } - }); - - if(!found) { - $scope.months.splice(lastIndex, 0, {year: currentYear, month: currentMonth}); - } - - // Find the new instance of the previously selected month. - angular.forEach($scope.months, function(month) { - // Reset selected month to the new instance corresponding to the old one - if($scope.month) { - if(month.year == $scope.month.year && month.month == $scope.month.month) { - monthToSelect = month; - } - } - - if(!monthToSelect && month.year == currentYear && month.month == currentMonth) { - monthToSelect = month; - } - }); - - // Set selected month to the last one if not yet selected. - if(!monthToSelect && $scope.months.length > 0) { - monthToSelect = $scope.months[$scope.months.length - 1]; - } - - // Reset to month to select - $scope.month = monthToSelect; - - $scope.$emit("monthsLoadedEvent", {account: $scope.account, month: $scope.month}); - }; - - // Callback function to select a new month. - $scope.selectMonth = function(month) { - if(month) { - $scope.month = month; - $scope.$emit("monthsLoadedEvent", {account: $scope.account, month: month}); - } - }; - - $rootScope.$on("accountsLoadedEvent", function(event, args) { - $scope.loadMonths(args.account); - }); -}; - diff --git a/frontend/static/js/scheduler.js b/frontend/static/js/scheduler.js deleted file mode 100644 index 1e40675..0000000 --- a/frontend/static/js/scheduler.js +++ /dev/null @@ -1,197 +0,0 @@ -/* - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . - */ -var SchedulerController = function($scope, $http, $rootScope, $filter) { - // Operations store and selection - $scope.operations = []; - $scope.selectedOperation = null; - - $scope.account = null; - - // Placeholder for saved value to cancel entry edition - $scope.savedOperation = null; - - $scope.loadOperations = function(account) { - // Clean up selected entry. - $scope.selectedOperation = null; - $scope.savedOperation = null; - - if(account) { - $scope.account = account; - - $http.get("/api/scheduled_operations/" + account.id).success($scope.loadOperations_success); - } else { - $scope.loadOperations_success(null); - } - }; - - $scope.loadOperations_success = function(data) { - var operations = [{ - id: null, - start_date: null, - stop_date: null, - day: null, - frequency: null, - label: null, - account_id: null, - category: null, - state: "edit" - }]; - - if(data) { - operations = operations.concat(angular.fromJson(data)); - } - - $scope.operations = operations; - - $scope.$emit("operationsLoadedEvent", {operations: operations}); - }; - - $scope.iconSaveClass = function(operation) { - if($scope.isNew(operation)) { - return "fa fa-plus"; - } else if ($scope.isEditing(operation)) { - return "fa fa-floppy-o"; - } - }; - - $scope.iconCancelClass = function(operation) { - if($scope.isNew(operation)) { - return "fa fa-times"; - } else if ($scope.isEditing(operation)) { - return "fa fa-ban"; - } - }; - - $scope.isNew = function(operation) { - return !operation.id; - }; - - // Returns true if the entry is in editing state. - $scope.isEditing = function(operation) { - return operation.state === 'edit'; - }; - - $scope.isDisplaying = function(operation) { - return operation.id && (!operation.state || operation.state === 'display'); - }; - - $scope.saveOperation = function(operation) { - if(!operation.account_id) { - operation.account_id = $scope.account.id; - } - - // prepare the Ajax xall to save the sceduled operation. - var type; - var url = "/api/scheduled_operations"; - - if(!$scope.isNew(operation)) { - url += "/" + operation.id; - } - - $http.put(url, angular.toJson(operation)).success(function(data) { - $.pnotify({ - type: "success", - title: "Save", - text: data - }); - - $scope.$emit("operationSavedEvent", operation); - }); - }; - - $scope.editOperation = function(operation) { - // Cancel previous editing. - if($scope.selectedOperation) { - $scope.cancelEditOperation($scope.selectedItem); - } - - // Save current entry values. - $scope.savedOperation = angular.copy(operation); - $scope.selectedOperation = operation; - - // Enter edit state. - operation.state='edit'; - }; - - $scope.cancelEditOperation = function(operation) { - if ($scope.isNew(operation)) { - operation.id = null; - operation.start_date = null; - operation.stop_date = null; - operation.day = null; - operation.frequency = null; - operation.label = null; - operation.value = null; - operation.category = null; - operation.account_id = $scope.account.id; - } else if ($scope.isEditing(operation)) { - if($scope.savedOperation) { - operation.id = $scope.savedOperation.id; - operation.start_date = $scope.savedOperation.start_date; - operation.stop_date = $scope.savedOperation.stop_date; - operation.day = $scope.savedOperation.day; - operation.frequency = $scope.savedOperation.frequency; - operation.label = $scope.savedOperation.label; - operation.value = $scope.savedOperation.value; - operation.category = $scope.savedOperation.category; - operation.account_id = $scope.savedOperation.account_id; - } - - $scope.savedOperation = null; - $scope.selectedOperation = null; - - operation.state = 'display'; - } - }; - - $scope.removeOperation = function(operation, modalScope) { - // Cancel current editing. - if (!$scope.isNew(operation)) { - $http.delete("/api/scheduled_operations/" + operation.id).success(function (result) { - $.pnotify({ - type: "success", - title: "Delete", - text: result - }); - - // Send the "entry removed" event. - $scope.$emit("operationRemovedEvent", operation); - - $scope.closeModal(modalScope); - }).error(function (data) { - $.pnotify({ - type: "error", - title: "Delete", - text: data - }); - - $scope.closeModal(modalScope); - }); - } - }; - - $scope.closeModal = function(modalScope) { - // Close the modal dialog - if(modalScope && modalScope.dismiss) { - modalScope.dismiss(); - } - }; - - $rootScope.$on("accountsLoadedEvent", function(event, args){ - $scope.loadOperations(args.account); - }); -} diff --git a/frontend/static/templates/account_edit.html b/frontend/static/templates/account_edit.html deleted file mode 100644 index 1e0e3ee..0000000 --- a/frontend/static/templates/account_edit.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - diff --git a/frontend/static/templates/account_new.html b/frontend/static/templates/account_new.html deleted file mode 100644 index 63c5f95..0000000 --- a/frontend/static/templates/account_new.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - diff --git a/frontend/static/templates/account_remove.html b/frontend/static/templates/account_remove.html deleted file mode 100644 index 17f1a98..0000000 --- a/frontend/static/templates/account_remove.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - diff --git a/frontend/static/templates/operation_remove.html b/frontend/static/templates/operation_remove.html deleted file mode 100644 index e42a54b..0000000 --- a/frontend/static/templates/operation_remove.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - diff --git a/frontend/static/third-party/pines-notify/jquery.pnotify.default.css b/frontend/static/third-party/pines-notify/jquery.pnotify.default.css deleted file mode 100644 index de1068a..0000000 --- a/frontend/static/third-party/pines-notify/jquery.pnotify.default.css +++ /dev/null @@ -1,83 +0,0 @@ -/* -Document : jquery.pnotify.default.css -Created on : Nov 23, 2009, 3:14:10 PM -Author : Hunter Perrin -Version : 1.2.0 -Link : http://pinesframework.org/pnotify/ -Description: - Default styling for Pines Notify jQuery plugin. -*/ -/* -- Notice */ -.ui-pnotify { -top: 25px; -right: 25px; -position: absolute; -height: auto; -/* Ensures notices are above everything */ -z-index: 9999; -} -/* Hides position: fixed from IE6 */ -html > body .ui-pnotify { -position: fixed; -} -.ui-pnotify .ui-pnotify-shadow { --webkit-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); --moz-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); -box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); -} -.ui-pnotify-container { -background-position: 0 0; -padding: .8em; -height: 100%; -margin: 0; -} -.ui-pnotify-sharp { --webkit-border-radius: 0; --moz-border-radius: 0; -border-radius: 0; -} -.ui-pnotify-closer, .ui-pnotify-sticker { -float: right; -margin-left: .2em; -} -.ui-pnotify-title { -display: block; -margin-bottom: .4em; -} -.ui-pnotify-text { -display: block; -} -.ui-pnotify-icon, .ui-pnotify-icon span { -display: block; -float: left; -margin-right: .2em; -} -/* -- History Pulldown */ -.ui-pnotify-history-container { -position: absolute; -top: 0; -right: 18px; -width: 70px; -border-top: none; -padding: 0; --webkit-border-top-left-radius: 0; --moz-border-top-left-radius: 0; -border-top-left-radius: 0; --webkit-border-top-right-radius: 0; --moz-border-top-right-radius: 0; -border-top-right-radius: 0; -/* Ensures history container is above notices. */ -z-index: 10000; -} -.ui-pnotify-history-container .ui-pnotify-history-header { -padding: 2px; -} -.ui-pnotify-history-container button { -cursor: pointer; -display: block; -width: 100%; -} -.ui-pnotify-history-container .ui-pnotify-history-pulldown { -display: block; -margin: 0 auto; -} \ No newline at end of file diff --git a/frontend/static/third-party/pines-notify/jquery.pnotify.js b/frontend/static/third-party/pines-notify/jquery.pnotify.js deleted file mode 100644 index f72893d..0000000 --- a/frontend/static/third-party/pines-notify/jquery.pnotify.js +++ /dev/null @@ -1,912 +0,0 @@ -/* - * jQuery Pines Notify (pnotify) Plugin 1.2.0 - * - * http://pinesframework.org/pnotify/ - * Copyright (c) 2009-2012 Hunter Perrin - * - * Triple license under the GPL, LGPL, and MPL: - * http://www.gnu.org/licenses/gpl.html - * http://www.gnu.org/licenses/lgpl.html - * http://www.mozilla.org/MPL/MPL-1.1.html - */ - -(function($) { - var history_handle_top, - timer, - body, - jwindow = $(window), - styling = { - jqueryui: { - container: "ui-widget ui-widget-content ui-corner-all", - notice: "ui-state-highlight", - // (The actual jQUI notice icon looks terrible.) - notice_icon: "ui-icon ui-icon-info", - info: "", - info_icon: "ui-icon ui-icon-info", - success: "ui-state-default", - success_icon: "ui-icon ui-icon-circle-check", - error: "ui-state-error", - error_icon: "ui-icon ui-icon-alert", - closer: "ui-icon ui-icon-close", - pin_up: "ui-icon ui-icon-pin-w", - pin_down: "ui-icon ui-icon-pin-s", - hi_menu: "ui-state-default ui-corner-bottom", - hi_btn: "ui-state-default ui-corner-all", - hi_btnhov: "ui-state-hover", - hi_hnd: "ui-icon ui-icon-grip-dotted-horizontal" - }, - bootstrap: { - container: "alert", - notice: "", - notice_icon: "icon-exclamation-sign", - info: "alert-info", - info_icon: "icon-info-sign", - success: "alert-success", - success_icon: "icon-ok-sign", - error: "alert-error", - error_icon: "icon-warning-sign", - closer: "icon-remove", - pin_up: "icon-pause", - pin_down: "icon-play", - hi_menu: "well", - hi_btn: "btn", - hi_btnhov: "", - hi_hnd: "icon-chevron-down" - } - }; - // Set global variables. - var do_when_ready = function(){ - body = $("body"); - jwindow = $(window); - // Reposition the notices when the window resizes. - jwindow.bind('resize', function(){ - if (timer) - clearTimeout(timer); - timer = setTimeout($.pnotify_position_all, 10); - }); - }; - if (document.body) - do_when_ready(); - else - $(do_when_ready); - $.extend({ - pnotify_remove_all: function () { - var notices_data = jwindow.data("pnotify"); - /* POA: Added null-check */ - if (notices_data && notices_data.length) { - $.each(notices_data, function(){ - if (this.pnotify_remove) - this.pnotify_remove(); - }); - } - }, - pnotify_position_all: function () { - // This timer is used for queueing this function so it doesn't run - // repeatedly. - if (timer) - clearTimeout(timer); - timer = null; - // Get all the notices. - var notices_data = jwindow.data("pnotify"); - if (!notices_data || !notices_data.length) - return; - // Reset the next position data. - $.each(notices_data, function(){ - var s = this.opts.stack; - if (!s) return; - s.nextpos1 = s.firstpos1; - s.nextpos2 = s.firstpos2; - s.addpos2 = 0; - s.animation = true; - }); - $.each(notices_data, function(){ - this.pnotify_position(); - }); - }, - pnotify: function(options) { - // Stores what is currently being animated (in or out). - var animating; - - // Build main options. - var opts; - if (typeof options != "object") { - opts = $.extend({}, $.pnotify.defaults); - opts.text = options; - } else { - opts = $.extend({}, $.pnotify.defaults, options); - } - // Translate old pnotify_ style options. - for (var i in opts) { - if (typeof i == "string" && i.match(/^pnotify_/)) - opts[i.replace(/^pnotify_/, "")] = opts[i]; - } - - if (opts.before_init) { - if (opts.before_init(opts) === false) - return null; - } - - // This keeps track of the last element the mouse was over, so - // mouseleave, mouseenter, etc can be called. - var nonblock_last_elem; - // This is used to pass events through the notice if it is non-blocking. - var nonblock_pass = function(e, e_name){ - pnotify.css("display", "none"); - var element_below = document.elementFromPoint(e.clientX, e.clientY); - pnotify.css("display", "block"); - var jelement_below = $(element_below); - var cursor_style = jelement_below.css("cursor"); - pnotify.css("cursor", cursor_style != "auto" ? cursor_style : "default"); - // If the element changed, call mouseenter, mouseleave, etc. - if (!nonblock_last_elem || nonblock_last_elem.get(0) != element_below) { - if (nonblock_last_elem) { - dom_event.call(nonblock_last_elem.get(0), "mouseleave", e.originalEvent); - dom_event.call(nonblock_last_elem.get(0), "mouseout", e.originalEvent); - } - dom_event.call(element_below, "mouseenter", e.originalEvent); - dom_event.call(element_below, "mouseover", e.originalEvent); - } - dom_event.call(element_below, e_name, e.originalEvent); - // Remember the latest element the mouse was over. - nonblock_last_elem = jelement_below; - }; - - // Get our styling object. - var styles = styling[opts.styling]; - - // Create our widget. - // Stop animation, reset the removal timer, and show the close - // button when the user mouses over. - var pnotify = $("
", { - "class": "ui-pnotify "+opts.addclass, - "css": {"display": "none"}, - "mouseenter": function(e){ - if (opts.nonblock) e.stopPropagation(); - if (opts.mouse_reset && animating == "out") { - // If it's animating out, animate back in really quickly. - pnotify.stop(true); - animating = "in"; - pnotify.css("height", "auto").animate({"width": opts.width, "opacity": opts.nonblock ? opts.nonblock_opacity : opts.opacity}, "fast"); - } - if (opts.nonblock) { - // If it's non-blocking, animate to the other opacity. - pnotify.animate({"opacity": opts.nonblock_opacity}, "fast"); - } - // Stop the close timer. - if (opts.hide && opts.mouse_reset) pnotify.pnotify_cancel_remove(); - // Show the buttons. - if (opts.sticker && !opts.nonblock) pnotify.sticker.trigger("pnotify_icon").css("visibility", "visible"); - if (opts.closer && !opts.nonblock) pnotify.closer.css("visibility", "visible"); - }, - "mouseleave": function(e){ - if (opts.nonblock) e.stopPropagation(); - nonblock_last_elem = null; - pnotify.css("cursor", "auto"); - // Animate back to the normal opacity. - if (opts.nonblock && animating != "out") - pnotify.animate({"opacity": opts.opacity}, "fast"); - // Start the close timer. - if (opts.hide && opts.mouse_reset) pnotify.pnotify_queue_remove(); - // Hide the buttons. - if (opts.sticker_hover) - pnotify.sticker.css("visibility", "hidden"); - if (opts.closer_hover) - pnotify.closer.css("visibility", "hidden"); - $.pnotify_position_all(); - }, - "mouseover": function(e){ - if (opts.nonblock) e.stopPropagation(); - }, - "mouseout": function(e){ - if (opts.nonblock) e.stopPropagation(); - }, - "mousemove": function(e){ - if (opts.nonblock) { - e.stopPropagation(); - nonblock_pass(e, "onmousemove"); - } - }, - "mousedown": function(e){ - if (opts.nonblock) { - e.stopPropagation(); - e.preventDefault(); - nonblock_pass(e, "onmousedown"); - } - }, - "mouseup": function(e){ - if (opts.nonblock) { - e.stopPropagation(); - e.preventDefault(); - nonblock_pass(e, "onmouseup"); - } - }, - "click": function(e){ - if (opts.nonblock) { - e.stopPropagation(); - nonblock_pass(e, "onclick"); - } - }, - "dblclick": function(e){ - if (opts.nonblock) { - e.stopPropagation(); - nonblock_pass(e, "ondblclick"); - } - } - }); - pnotify.opts = opts; - // Create a container for the notice contents. - pnotify.container = $("
", {"class": styles.container+" ui-pnotify-container "+(opts.type == "error" ? styles.error : (opts.type == "info" ? styles.info : (opts.type == "success" ? styles.success : styles.notice)))}) - .appendTo(pnotify); - if (opts.cornerclass != "") - pnotify.container.removeClass("ui-corner-all").addClass(opts.cornerclass); - // Create a drop shadow. - if (opts.shadow) - pnotify.container.addClass("ui-pnotify-shadow"); - - // The current version of Pines Notify. - pnotify.pnotify_version = "1.2.0"; - - // This function is for updating the notice. - pnotify.pnotify = function(options) { - // Update the notice. - var old_opts = opts; - if (typeof options == "string") - opts.text = options; - else - opts = $.extend({}, opts, options); - // Translate old pnotify_ style options. - for (var i in opts) { - if (typeof i == "string" && i.match(/^pnotify_/)) - opts[i.replace(/^pnotify_/, "")] = opts[i]; - } - pnotify.opts = opts; - // Update the corner class. - if (opts.cornerclass != old_opts.cornerclass) - pnotify.container.removeClass("ui-corner-all").addClass(opts.cornerclass); - // Update the shadow. - if (opts.shadow != old_opts.shadow) { - if (opts.shadow) - pnotify.container.addClass("ui-pnotify-shadow"); - else - pnotify.container.removeClass("ui-pnotify-shadow"); - } - // Update the additional classes. - if (opts.addclass === false) - pnotify.removeClass(old_opts.addclass); - else if (opts.addclass !== old_opts.addclass) - pnotify.removeClass(old_opts.addclass).addClass(opts.addclass); - // Update the title. - if (opts.title === false) - pnotify.title_container.slideUp("fast"); - else if (opts.title !== old_opts.title) { - if (opts.title_escape) - pnotify.title_container.text(opts.title).slideDown(200); - else - pnotify.title_container.html(opts.title).slideDown(200); - } - // Update the text. - if (opts.text === false) { - pnotify.text_container.slideUp("fast"); - } else if (opts.text !== old_opts.text) { - if (opts.text_escape) - pnotify.text_container.text(opts.text).slideDown(200); - else - pnotify.text_container.html(opts.insert_brs ? String(opts.text).replace(/\n/g, "
") : opts.text).slideDown(200); - } - // Update values for history menu access. - pnotify.pnotify_history = opts.history; - pnotify.pnotify_hide = opts.hide; - // Change the notice type. - if (opts.type != old_opts.type) - pnotify.container.removeClass(styles.error+" "+styles.notice+" "+styles.success+" "+styles.info).addClass(opts.type == "error" ? styles.error : (opts.type == "info" ? styles.info : (opts.type == "success" ? styles.success : styles.notice))); - if (opts.icon !== old_opts.icon || (opts.icon === true && opts.type != old_opts.type)) { - // Remove any old icon. - pnotify.container.find("div.ui-pnotify-icon").remove(); - if (opts.icon !== false) { - // Build the new icon. - $("
", {"class": "ui-pnotify-icon"}) - .append($("", {"class": opts.icon === true ? (opts.type == "error" ? styles.error_icon : (opts.type == "info" ? styles.info_icon : (opts.type == "success" ? styles.success_icon : styles.notice_icon))) : opts.icon})) - .prependTo(pnotify.container); - } - } - // Update the width. - if (opts.width !== old_opts.width) - pnotify.animate({width: opts.width}); - // Update the minimum height. - if (opts.min_height !== old_opts.min_height) - pnotify.container.animate({minHeight: opts.min_height}); - // Update the opacity. - if (opts.opacity !== old_opts.opacity) - pnotify.fadeTo(opts.animate_speed, opts.opacity); - // Update the sticker and closer buttons. - if (!opts.closer || opts.nonblock) - pnotify.closer.css("display", "none"); - else - pnotify.closer.css("display", "block"); - if (!opts.sticker || opts.nonblock) - pnotify.sticker.css("display", "none"); - else - pnotify.sticker.css("display", "block"); - // Update the sticker icon. - pnotify.sticker.trigger("pnotify_icon"); - // Update the hover status of the buttons. - if (opts.sticker_hover) - pnotify.sticker.css("visibility", "hidden"); - else if (!opts.nonblock) - pnotify.sticker.css("visibility", "visible"); - if (opts.closer_hover) - pnotify.closer.css("visibility", "hidden"); - else if (!opts.nonblock) - pnotify.closer.css("visibility", "visible"); - // Update the timed hiding. - if (!opts.hide) - pnotify.pnotify_cancel_remove(); - else if (!old_opts.hide) - pnotify.pnotify_queue_remove(); - pnotify.pnotify_queue_position(); - return pnotify; - }; - - // Position the notice. dont_skip_hidden causes the notice to - // position even if it's not visible. - pnotify.pnotify_position = function(dont_skip_hidden){ - // Get the notice's stack. - var s = pnotify.opts.stack; - if (!s) return; - if (!s.nextpos1) - s.nextpos1 = s.firstpos1; - if (!s.nextpos2) - s.nextpos2 = s.firstpos2; - if (!s.addpos2) - s.addpos2 = 0; - var hidden = pnotify.css("display") == "none"; - // Skip this notice if it's not shown. - if (!hidden || dont_skip_hidden) { - var curpos1, curpos2; - // Store what will need to be animated. - var animate = {}; - // Calculate the current pos1 value. - var csspos1; - switch (s.dir1) { - case "down": - csspos1 = "top"; - break; - case "up": - csspos1 = "bottom"; - break; - case "left": - csspos1 = "right"; - break; - case "right": - csspos1 = "left"; - break; - } - curpos1 = parseInt(pnotify.css(csspos1)); - if (isNaN(curpos1)) - curpos1 = 0; - // Remember the first pos1, so the first visible notice goes there. - if (typeof s.firstpos1 == "undefined" && !hidden) { - s.firstpos1 = curpos1; - s.nextpos1 = s.firstpos1; - } - // Calculate the current pos2 value. - var csspos2; - switch (s.dir2) { - case "down": - csspos2 = "top"; - break; - case "up": - csspos2 = "bottom"; - break; - case "left": - csspos2 = "right"; - break; - case "right": - csspos2 = "left"; - break; - } - curpos2 = parseInt(pnotify.css(csspos2)); - if (isNaN(curpos2)) - curpos2 = 0; - // Remember the first pos2, so the first visible notice goes there. - if (typeof s.firstpos2 == "undefined" && !hidden) { - s.firstpos2 = curpos2; - s.nextpos2 = s.firstpos2; - } - // Check that it's not beyond the viewport edge. - if ((s.dir1 == "down" && s.nextpos1 + pnotify.height() > jwindow.height()) || - (s.dir1 == "up" && s.nextpos1 + pnotify.height() > jwindow.height()) || - (s.dir1 == "left" && s.nextpos1 + pnotify.width() > jwindow.width()) || - (s.dir1 == "right" && s.nextpos1 + pnotify.width() > jwindow.width()) ) { - // If it is, it needs to go back to the first pos1, and over on pos2. - s.nextpos1 = s.firstpos1; - s.nextpos2 += s.addpos2 + (typeof s.spacing2 == "undefined" ? 25 : s.spacing2); - s.addpos2 = 0; - } - // Animate if we're moving on dir2. - if (s.animation && s.nextpos2 < curpos2) { - switch (s.dir2) { - case "down": - animate.top = s.nextpos2+"px"; - break; - case "up": - animate.bottom = s.nextpos2+"px"; - break; - case "left": - animate.right = s.nextpos2+"px"; - break; - case "right": - animate.left = s.nextpos2+"px"; - break; - } - } else - pnotify.css(csspos2, s.nextpos2+"px"); - // Keep track of the widest/tallest notice in the column/row, so we can push the next column/row. - switch (s.dir2) { - case "down": - case "up": - if (pnotify.outerHeight(true) > s.addpos2) - s.addpos2 = pnotify.height(); - break; - case "left": - case "right": - if (pnotify.outerWidth(true) > s.addpos2) - s.addpos2 = pnotify.width(); - break; - } - // Move the notice on dir1. - if (s.nextpos1) { - // Animate if we're moving toward the first pos. - if (s.animation && (curpos1 > s.nextpos1 || animate.top || animate.bottom || animate.right || animate.left)) { - switch (s.dir1) { - case "down": - animate.top = s.nextpos1+"px"; - break; - case "up": - animate.bottom = s.nextpos1+"px"; - break; - case "left": - animate.right = s.nextpos1+"px"; - break; - case "right": - animate.left = s.nextpos1+"px"; - break; - } - } else - pnotify.css(csspos1, s.nextpos1+"px"); - } - // Run the animation. - if (animate.top || animate.bottom || animate.right || animate.left) - pnotify.animate(animate, {duration: 500, queue: false}); - // Calculate the next dir1 position. - switch (s.dir1) { - case "down": - case "up": - s.nextpos1 += pnotify.height() + (typeof s.spacing1 == "undefined" ? 25 : s.spacing1); - break; - case "left": - case "right": - s.nextpos1 += pnotify.width() + (typeof s.spacing1 == "undefined" ? 25 : s.spacing1); - break; - } - } - }; - - // Queue the positiona all function so it doesn't run repeatedly and - // use up resources. - pnotify.pnotify_queue_position = function(milliseconds){ - if (timer) - clearTimeout(timer); - if (!milliseconds) - milliseconds = 10; - timer = setTimeout($.pnotify_position_all, milliseconds); - }; - - // Display the notice. - pnotify.pnotify_display = function() { - // If the notice is not in the DOM, append it. - if (!pnotify.parent().length) - pnotify.appendTo(body); - // Run callback. - if (opts.before_open) { - if (opts.before_open(pnotify) === false) - return; - } - // Try to put it in the right position. - if (opts.stack.push != "top") - pnotify.pnotify_position(true); - // First show it, then set its opacity, then hide it. - if (opts.animation == "fade" || opts.animation.effect_in == "fade") { - // If it's fading in, it should start at 0. - pnotify.show().fadeTo(0, 0).hide(); - } else { - // Or else it should be set to the opacity. - if (opts.opacity != 1) - pnotify.show().fadeTo(0, opts.opacity).hide(); - } - pnotify.animate_in(function(){ - if (opts.after_open) - opts.after_open(pnotify); - - pnotify.pnotify_queue_position(); - - // Now set it to hide. - if (opts.hide) - pnotify.pnotify_queue_remove(); - }); - }; - - // Remove the notice. - pnotify.pnotify_remove = function() { - if (pnotify.timer) { - window.clearTimeout(pnotify.timer); - pnotify.timer = null; - } - // Run callback. - if (opts.before_close) { - if (opts.before_close(pnotify) === false) - return; - } - pnotify.animate_out(function(){ - if (opts.after_close) { - if (opts.after_close(pnotify) === false) - return; - } - pnotify.pnotify_queue_position(); - // If we're supposed to remove the notice from the DOM, do it. - if (opts.remove) - pnotify.detach(); - }); - }; - - // Animate the notice in. - pnotify.animate_in = function(callback){ - // Declare that the notice is animating in. (Or has completed animating in.) - animating = "in"; - var animation; - if (typeof opts.animation.effect_in != "undefined") - animation = opts.animation.effect_in; - else - animation = opts.animation; - if (animation == "none") { - pnotify.show(); - callback(); - } else if (animation == "show") - pnotify.show(opts.animate_speed, callback); - else if (animation == "fade") - pnotify.show().fadeTo(opts.animate_speed, opts.opacity, callback); - else if (animation == "slide") - pnotify.slideDown(opts.animate_speed, callback); - else if (typeof animation == "function") - animation("in", callback, pnotify); - else - pnotify.show(animation, (typeof opts.animation.options_in == "object" ? opts.animation.options_in : {}), opts.animate_speed, callback); - }; - - // Animate the notice out. - pnotify.animate_out = function(callback){ - // Declare that the notice is animating out. (Or has completed animating out.) - animating = "out"; - var animation; - if (typeof opts.animation.effect_out != "undefined") - animation = opts.animation.effect_out; - else - animation = opts.animation; - if (animation == "none") { - pnotify.hide(); - callback(); - } else if (animation == "show") - pnotify.hide(opts.animate_speed, callback); - else if (animation == "fade") - pnotify.fadeOut(opts.animate_speed, callback); - else if (animation == "slide") - pnotify.slideUp(opts.animate_speed, callback); - else if (typeof animation == "function") - animation("out", callback, pnotify); - else - pnotify.hide(animation, (typeof opts.animation.options_out == "object" ? opts.animation.options_out : {}), opts.animate_speed, callback); - }; - - // Cancel any pending removal timer. - pnotify.pnotify_cancel_remove = function() { - if (pnotify.timer) - window.clearTimeout(pnotify.timer); - }; - - // Queue a removal timer. - pnotify.pnotify_queue_remove = function() { - // Cancel any current removal timer. - pnotify.pnotify_cancel_remove(); - pnotify.timer = window.setTimeout(function(){ - pnotify.pnotify_remove(); - }, (isNaN(opts.delay) ? 0 : opts.delay)); - }; - - // Provide a button to close the notice. - pnotify.closer = $("
", { - "class": "ui-pnotify-closer", - "css": {"cursor": "pointer", "visibility": opts.closer_hover ? "hidden" : "visible"}, - "click": function(){ - pnotify.pnotify_remove(); - pnotify.sticker.css("visibility", "hidden"); - pnotify.closer.css("visibility", "hidden"); - } - }) - .append($("", {"class": styles.closer})) - .appendTo(pnotify.container); - if (!opts.closer || opts.nonblock) - pnotify.closer.css("display", "none"); - - // Provide a button to stick the notice. - pnotify.sticker = $("
", { - "class": "ui-pnotify-sticker", - "css": {"cursor": "pointer", "visibility": opts.sticker_hover ? "hidden" : "visible"}, - "click": function(){ - opts.hide = !opts.hide; - if (opts.hide) - pnotify.pnotify_queue_remove(); - else - pnotify.pnotify_cancel_remove(); - $(this).trigger("pnotify_icon"); - } - }) - .bind("pnotify_icon", function(){ - $(this).children().removeClass(styles.pin_up+" "+styles.pin_down).addClass(opts.hide ? styles.pin_up : styles.pin_down); - }) - .append($("", {"class": styles.pin_up})) - .appendTo(pnotify.container); - if (!opts.sticker || opts.nonblock) - pnotify.sticker.css("display", "none"); - - // Add the appropriate icon. - if (opts.icon !== false) { - $("
", {"class": "ui-pnotify-icon"}) - .append($("", {"class": opts.icon === true ? (opts.type == "error" ? styles.error_icon : (opts.type == "info" ? styles.info_icon : (opts.type == "success" ? styles.success_icon : styles.notice_icon))) : opts.icon})) - .prependTo(pnotify.container); - } - - // Add a title. - pnotify.title_container = $("

", { - "class": "ui-pnotify-title" - }) - .appendTo(pnotify.container); - if (opts.title === false) - pnotify.title_container.hide(); - else if (opts.title_escape) - pnotify.title_container.text(opts.title); - else - pnotify.title_container.html(opts.title); - - // Add text. - pnotify.text_container = $("
", { - "class": "ui-pnotify-text" - }) - .appendTo(pnotify.container); - if (opts.text === false) - pnotify.text_container.hide(); - else if (opts.text_escape) - pnotify.text_container.text(opts.text); - else - pnotify.text_container.html(opts.insert_brs ? String(opts.text).replace(/\n/g, "
") : opts.text); - - // Set width and min height. - if (typeof opts.width == "string") - pnotify.css("width", opts.width); - if (typeof opts.min_height == "string") - pnotify.container.css("min-height", opts.min_height); - - // The history variable controls whether the notice gets redisplayed - // by the history pull down. - pnotify.pnotify_history = opts.history; - // The hide variable controls whether the history pull down should - // queue a removal timer. - pnotify.pnotify_hide = opts.hide; - - // Add the notice to the notice array. - var notices_data = jwindow.data("pnotify"); - if (notices_data == null || typeof notices_data != "object") - notices_data = []; - if (opts.stack.push == "top") - notices_data = $.merge([pnotify], notices_data); - else - notices_data = $.merge(notices_data, [pnotify]); - jwindow.data("pnotify", notices_data); - // Now position all the notices if they are to push to the top. - if (opts.stack.push == "top") - pnotify.pnotify_queue_position(1); - - // Run callback. - if (opts.after_init) - opts.after_init(pnotify); - - if (opts.history) { - // If there isn't a history pull down, create one. - var history_menu = jwindow.data("pnotify_history"); - if (typeof history_menu == "undefined") { - history_menu = $("
", { - "class": "ui-pnotify-history-container "+styles.hi_menu, - "mouseleave": function(){ - history_menu.animate({top: "-"+history_handle_top+"px"}, {duration: 100, queue: false}); - } - }) - .append($("
", {"class": "ui-pnotify-history-header", "text": "Redisplay"})) - .append($("
- -
-
- {% block body %}{% endblock %} -
-
- - {% block footer %}{% endblock %} - - - - - - - - - - - - - - - - - - - - - - - - {% block js %}{% endblock %} - - - - - diff --git a/frontend/templates/remove_entry.html b/frontend/templates/remove_entry.html deleted file mode 100644 index bf87d7c..0000000 --- a/frontend/templates/remove_entry.html +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/frontend/templates/scheduler.html b/frontend/templates/scheduler.html deleted file mode 100644 index aeeaaeb..0000000 --- a/frontend/templates/scheduler.html +++ /dev/null @@ -1,106 +0,0 @@ -{# - This file is part of Accountant. - - Accountant is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Foobar is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with Accountant. If not, see . -#} -{% extends "layout.html" %} -{% block body %} - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Date de débutDate de finJourFréq.Libellé de l'opérationMontantCatégorieActions
- - [[operation.start_date]] - - - [[operation.stop_date]] - - - [[operation.day]] - - - [[operation.frequency]] - - - [[operation.label]] - - - [[operation.value]] - - - [[operation.category]] - -
- - - -
- -
- - - -
-
-
-{% endblock %} - -{% block js %} - - - -{% endblock %} - diff --git a/manage.py b/manage.py index 4bfd013..0b29e2d 100755 --- a/manage.py +++ b/manage.py @@ -1,7 +1,8 @@ +#!/usr/bin/env python from flask.ext.script import Manager -from flask.ext.migrate import Migrate, MigrateCommand +from flask.ext.migrate import MigrateCommand -from app import app +from accountant import app manager = Manager(app) manager.add_command('db', MigrateCommand)