diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..469e17fbe --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +*~ +*.pyc +AUTHORS +ChangeLog +MANIFEST +dist/ +.venv/ +build/* +build-stamp +cover/* +doc/build/ +doc/source/api/ +stackalytics.egg-info/ +.autogenerated +.coverage +.testrepository/ +.tox/ diff --git a/.gitreview b/.gitreview new file mode 100644 index 000000000..c03d88e51 --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=review.openstack.org +port=29418 +project=stackforge/stackalytics.git diff --git a/.testr.conf b/.testr.conf new file mode 100644 index 000000000..2109af6ce --- /dev/null +++ b/.testr.conf @@ -0,0 +1,4 @@ +[DEFAULT] +test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ./tests $LISTOPT $IDOPTION +test_id_option=--load-list $IDFILE +test_list_option=--list diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..68c771a09 --- /dev/null +++ b/LICENSE @@ -0,0 +1,176 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..f1c38fb2e --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,9 @@ +include AUTHORS +include README.rst +include ChangeLog +include LICENSE + +exclude .gitignore +exclude .gitreview + +global-exclude *.pyc diff --git a/README.md b/README.md deleted file mode 100644 index 7b76b05fe..000000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -stackalytics -============ - -OpenStack analytics dashboard diff --git a/README.rst b/README.rst new file mode 100644 index 000000000..0deb3e489 --- /dev/null +++ b/README.rst @@ -0,0 +1,15 @@ +Stackalytics - OpenStack analytics dashboard +============================================ + +Application Features +-------------------- +OpenStack Stats is a service that automatically analyzes OpenStack git repos and displays statistics on contribution. The features are: + * Extraction of author information from git log, store it in the database; + * Calculate metrics on number of lines changed (LOC) and commits; + * Mapping authors to companies and launchpad ids; + * Filter statistics by time, modules, companies, authors; + * Extract blueprint and bug ids from commit messages; + * Auto-update of database. + + + diff --git a/bin/full-update b/bin/full-update new file mode 100755 index 000000000..c6d290cb7 --- /dev/null +++ b/bin/full-update @@ -0,0 +1,31 @@ +#!/bin/bash + +if [[ -z $STACKALYTICS_HOME ]]; then +echo "Variable STACKALYTICS_HOME must be specified" +exit +fi + +echo "Analytics home is $STACKALYTICS_HOME" + +DASHBOARD_CONF='$STACKALYTICS_HOME/conf/dashboard.conf' + +TOP_DIR=$(cd $(dirname "$0") && pwd) + +DB_FILE=`mktemp -u --tmpdir=$STACKALYTICS_HOME/data stackalytics-XXXXXXXXXXXX.sqlite` +TEMP_CONF=`mktemp -u` + +cd $TOP_DIR/../scripts/ +./pull-repos.sh + +cd $TOP_DIR/../ +./bin/stackalytics --config-file $STACKALYTICS_HOME/conf/analytics.conf --db-database $DB_FILE --verbose + +DATE=`date -u +'%d-%b-%y %H:%M %Z'` + +echo DATABASE = \'$DB_FILE\' >> $TEMP_CONF +echo LAST_UPDATE = \'$DATE\' >> $TEMP_CONF + +#rm $DASHBOARD_CONF +#mv $TEMP_CONF $DASHBOARD_CONF + +echo "Data is refreshed, please restart service" diff --git a/bin/grab-unmapped b/bin/grab-unmapped new file mode 100755 index 000000000..ea1f54071 --- /dev/null +++ b/bin/grab-unmapped @@ -0,0 +1,5 @@ +#!/bin/bash + +TOP_DIR=$(cd $(dirname "$0") && pwd) + +./tools/with_venv.sh python scripts/launchpad/grab-unmapped-launchpad-ids.py \ No newline at end of file diff --git a/bin/stackalytics b/bin/stackalytics new file mode 100755 index 000000000..253fd9334 --- /dev/null +++ b/bin/stackalytics @@ -0,0 +1,11 @@ +#!.venv/bin/python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +import os +import sys +sys.path.insert(0, os.getcwd()) + +from pycvsanaly2.main import main + + +main() diff --git a/bin/stackalytics-dashboard b/bin/stackalytics-dashboard new file mode 100755 index 000000000..63f184008 --- /dev/null +++ b/bin/stackalytics-dashboard @@ -0,0 +1,11 @@ +#!.venv/bin/python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +import os +import sys +sys.path.insert(0, os.getcwd()) + +from dashboard.dashboard import app + + +app.run() diff --git a/bin/update b/bin/update new file mode 100755 index 000000000..d6f1ae358 --- /dev/null +++ b/bin/update @@ -0,0 +1,18 @@ +#!/bin/bash + +if [[ -z $STACKALYTICS_HOME ]]; then + echo "Variable STACKALYTICS_HOME must be specified" + exit +fi + +echo "Analytics home is $STACKALYTICS_HOME" + +CONF="$STACKALYTICS_HOME/conf/analytics.conf" + +TOP_DIR=$(cd $(dirname "$0") && pwd) +cd $TOP_DIR/../scripts/ +./pull-repos.sh + +echo "Updating data" +cd $TOP_DIR/../ +./bin/stackalytics --config-file $CONF --db-database $STACKALYTICS_HOME/data/stackalyticss.sqlite --verbose diff --git a/dashboard/__init__.py b/dashboard/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dashboard/dashboard.py b/dashboard/dashboard.py new file mode 100644 index 000000000..1ca1d080e --- /dev/null +++ b/dashboard/dashboard.py @@ -0,0 +1,987 @@ +# Copyright (C) 2013 Mirantis Inc +# +# Author: Ilya Shakhat + +import cgi + +import datetime as DT +import functools +import itertools +import json +import re +import sqlite3 +import time +import urllib + +import flask +from flask.ext import gravatar as gravatar_ext +from werkzeug.contrib import cache as cache_package + +DATABASE = 'stackalytics.sqlite' +LAST_UPDATE = None +DEBUG = False +CACHE_ENABLED = False +CACHE_EXPIRATION = 5 * 60 +CACHE_TYPE = 'simple' + +# create our little application :) +app = flask.Flask(__name__) +app.config.from_object(__name__) +app.config.from_envvar('DASHBOARD_CONF', silent=True) + +if app.config['CACHE_TYPE'] == 'memcached': + cache = cache_package.MemcachedCache(['127.0.0.1:11211']) +else: + cache = cache_package.SimpleCache() + + +# DB COMMON FUNCS ************************************************************ + + +def get_db(): + """Opens a new database connection if there is none yet for the + current application context. + """ + top = flask._app_ctx_stack.top + if not hasattr(top, 'sqlite_db'): + top.sqlite_db = sqlite3.dbapi2.connect(app.config['DATABASE']) + top.sqlite_db.row_factory = sqlite3.dbapi2.Row + return top.sqlite_db + + +@app.teardown_appcontext +def close_database(exception): + """Closes the database again at the end of the request.""" + top = flask._app_ctx_stack.top + if hasattr(top, 'sqlite_db'): + top.sqlite_db.close() + + +def query_db(query, args=(), one=False): + """Queries the database and returns a list of dictionaries.""" + app.logger.debug(query) + cur = get_db().execute(query, args) + rv = cur.fetchall() + return (rv[0] if rv else None) if one else rv + + +# DECORATORS ***************************************************************** + +def cached(timeout=app.config['CACHE_EXPIRATION'], key='view/%s', params=None): + def decorator(f): + @functools.wraps(f) + def decorated_function(*args, **kwargs): + if app.config['CACHE_ENABLED']: + cache_key = key % flask.request.path + if params: + cache_key += '/' + '/'.join( + [param + '=' + (flask.request.args.get(param) or '') + for param in params] + ) + cache_key = cache_key.replace(' ', '+') + app.logger.debug('Cache key %s' % cache_key) + rv = cache.get(cache_key) + app.logger.debug('Got value from the cache \n%s' % rv) + if rv is not None: + return rv + rv = f(*args, **kwargs) + cache.set(cache_key, rv, timeout=timeout) + app.logger.debug('Set the cache \n%s' % rv) + return rv + else: + return f(*args, **kwargs) + return decorated_function + return decorator + + +def templated(template=None): + def decorator(f): + @functools.wraps(f) + def decorated_function(*args, **kwargs): + template_name = template + if template_name is None: + template_name = (flask.request.endpoint.replace('.', '/') + + '.html') + ctx = f(*args, **kwargs) + if ctx is None: + ctx = {} + elif not isinstance(ctx, dict): + return ctx + + # put parameters into template + metric = flask.request.args.get('metric') + if metric not in METRIC_LABELS: + metric = None + ctx['metric'] = metric or DEFAULT_METRIC + + period = flask.request.args.get('period') + if period not in PERIOD_LABELS: + period = None + ctx['period'] = period or DEFAULT_PERIOD + ctx['metric_label'] = METRIC_LABELS[ctx['metric']] + ctx['period_label'] = PERIOD_LABELS[ctx['period']] + + project_type = flask.request.args.get('project_type') + if project_type not in PROJECT_TYPES: + project_type = None + ctx['project_type'] = project_type or DEFAULT_PROJECT_TYPE + + ctx['last_update'] = app.config['LAST_UPDATE'] + + return flask.render_template(template_name, **ctx) + return decorated_function + return decorator + + +def verified(): + def decorator(f): + @functools.wraps(f) + def decorated_function(*args, **kwargs): + if 'project_type' in kwargs: + if kwargs['project_type'] not in ['CORE', 'INCUBATION', 'ALL']: + flask.abort(404) + if 'module' in kwargs: + res = query_db('select 1 from repositories where name = ?', + [kwargs['module'] + '.git']) + if not res: + flask.abort(404) + if 'company' in kwargs: + company = urllib.unquote_plus(kwargs['company']).lower() + res = query_db('select companies.name from people ' + 'join companies ' + 'on people.company_id = companies.id ' + 'where lower(companies.name) = ?', + [company]) + if not res: + flask.abort(404) + kwargs['company'] = res[0][0] + if 'engineer' in kwargs: + res = query_db('select 1 from people where launchpad_id = ?', + [kwargs['engineer']]) + if not res: + flask.abort(404) + return f(*args, **kwargs) + return decorated_function + return decorator + + +# UTIL FUNCS ***************************************************************** + +def clear_text(s): + a = cgi.escape('\n'.join([a.strip() for a in s.split('\n') if a.strip()])) + first, nl, remain = a.partition('\n') + return '' + first + '' + nl + nl + remain + + +def link_blueprint(s, module): + return re.sub(r'(blueprint\s+)([\w-]+)', + r'\1\2', + s) + + +def link_bug(s): + return re.sub(r'([B|b]ug\s+)#?([\d]{5,7})', + r'\1\2', + s) + + +def link_change_id(s): + return re.sub(r'(I[0-9a-f]{40})', + r'\1', + s) + + +def filter_over_limit(data, limit): + if 1 < limit < len(data): + s = 0 + for rec in data[limit - 1:]: + s += rec['rank'] + data[limit - 1] = data[0].copy() + data[limit - 1]['name'] = 'others' + data[limit - 1]['rank'] = s + data = data[:limit] + return data + + +def paste_links(data, base_uri, metric, period, project_type): + for one in data: + if one['name']: + one['link'] = ('' + (one['name']) + '') + else: + one['link'] = 'Unmapped' + return data + + +def index_column(data): + n = 1 + for one in data: + if one['name'] is None or one['name'][0] == '*': + one['index'] = '' + else: + one['index'] = n + n += 1 + return data + +DEFAULT_METRIC = 'loc' +DEFAULT_PERIOD = 'havana' +DEFAULT_PROJECT_TYPE = 'incubation' + +PERIODS = { + 'all': (DT.date(2010, 05, 1), DT.date(2013, 10, 1)), + 'essex': (DT.date(2011, 10, 1), DT.date(2012, 04, 1)), + 'folsom': (DT.date(2012, 04, 1), DT.date(2012, 10, 1)), + 'grizzly': (DT.date(2012, 10, 1), DT.date(2013, 04, 1)), + 'havana': (DT.date(2013, 04, 1), DT.date(2013, 10, 1)), +} + +INDEPENDENT = '*independent' + +METRIC_LABELS = { + 'loc': 'Lines of code', + 'commits': 'Commits', +} + +PERIOD_LABELS = { + 'all': 'All times', + 'six_months': 'Last 6 months', + 'essex': 'Essex', + 'folsom': 'Folsom', + 'grizzly': 'Grizzly', + 'havana': 'Havana', +} + +PROJECT_TYPES = { + 'core': ['core'], + 'incubation': ['core', 'incubation'], + 'all': ['core', 'incubation', 'dev'], +} + +ISSUE_TYPES = ['bug', 'blueprint'] + + +def extract_time_period(period): + begin = DT.date(2010, 2, 1) + end = DT.datetime.now().date() + + if not period or period == 'six_months': + begin = end - DT.timedelta(days=182) + elif period == 'all': + begin = PERIODS[period][0] + elif period in PERIODS: + begin, end = PERIODS[period] + + return begin, end + + +def parse_time_period(period): + begin, end = extract_time_period(period) + return DT.date.isoformat(begin), DT.date.isoformat(end) + + +def parse_date_from_string_to_timestamp(datestring): + d = DT.datetime.strptime(datestring, "%Y-%m-%d %H:%M:%S") + return time.mktime(d.timetuple()) + + +def get_period_filter(period): + return ''' + and scmlog.date > ? and scmlog.date <= ? + ''' + + +def get_metric_filter(metric): + if metric == 'loc': + metric_filter = 'sum(commits_lines.added) + sum(commits_lines.removed)' + else: + metric_filter = 'count(*)' + return metric_filter + + +def get_project_type_filter(project_type): + if not project_type: + project_type = DEFAULT_PROJECT_TYPE + types = PROJECT_TYPES[project_type] + fts = ["repositories.project_type = '%s'" % t for t in types] + return 'and (' + ' or '.join(fts) + ')' + + +def extract_params(): + module = flask.request.args.get('module') + limit = int(flask.request.args.get('limit') or 0) + period = flask.request.args.get('period') or DEFAULT_PERIOD + metric = flask.request.args.get('metric') or DEFAULT_METRIC + project_type = (flask.request.args.get('project_type') + or DEFAULT_PROJECT_TYPE) + return module, limit, period, metric, project_type + + +def row2dict(a): + r = {} + for key in a.keys(): + r.update({key: a[key]}) + return r + + +# UI HANDLERS **************************************************************** +# these handle page rendering + +@app.route('/') +@templated('companies.html') +def overview(): + return {} + + +@app.errorhandler(404) +def page_not_found(e): + return flask.render_template('404.html'), 404 + + +@app.route('/companies') +@app.route('/companies/') +@app.route('/modules') +@app.route('/modules/') +def redirects(): + return flask.redirect(flask.url_for('overview')) + + +@app.route('/companies/') +@templated() +@cached(params=['period', 'project_type']) +@verified() +def company_details(company): + details = contribution_details(flask.request.args.get('period'), + flask.request.args.get('project_type'), + company=company) + details.update({ + 'company': company, + }) + return details + + +@app.route('/engineers/') +@templated() +def engineers(): + return {} + + +@app.route('/modules/') +@templated() +@cached() +@verified() +def module_details(module): + commits_res = query_db(''' +select scmlog.date, scmlog.message, people.launchpad_id, people.name, + people.email, companies.name as company from scmlog + join people on scmlog.author_id = people.id + join companies on people.company_id = companies.id +where + people.launchpad_id not null + and scmlog.id in ( + select actions.commit_id from actions + join branches on branches.id = actions.branch_id + where branches.name = 'master' + ) + and scmlog.repository_id in ( + select repositories.id from repositories + where repositories.name = ? + ) +order by scmlog.date desc +limit 50 + ''', [module + '.git']) + + commits = [] + for record in commits_res: + message = record['message'] + + m = re.search(r'bug\s+(\d{5,7})', message) + if m: + ref = ('Bug: ' + m.group(1) + '') + else: + m = re.search(r'blueprint\s+([\w-]+)', message) + if m: + ref = ('Blueprint: ' + '' + + m.group(1) + '') + else: + ref = None + + m = re.search(r'(I[0-9a-f]{40})', message) + if m: + change_id = m.group(1) + else: + change_id = None + + company = record['company'] + if company == INDEPENDENT: + company = None + + text = message.split('\n')[0].strip() + + commits.append( + {'date': parse_date_from_string_to_timestamp(record['date']), + 'ref': ref, 'text': text, + 'change_id': change_id, + 'launchpad_id': record['launchpad_id'], + 'name': record['name'], 'email': record['email'], + 'company': company}) + + return {'module': module, 'commits': commits} + + +def contribution_details(period, project_type, engineer=None, company=None): + if engineer: + people_filter = 'people.launchpad_id' + people_param = engineer + elif company: + people_filter = 'companies.name' + people_param = company + else: + return None + + time_period = parse_time_period(period) + + commits_res = query_db(''' +select scmlog.message, scmlog.date, repositories.name as repo, + details.change_id, details.issue_type, details.issue_id, + details.commit_type, commits_lines.added, commits_lines.removed + from scmlog + join repositories on scmlog.repository_id = repositories.id + join details on scmlog.id = details.commit_id + join commits_lines on commits_lines.commit_id = scmlog.id +where + scmlog.author_id in ( + select people.id from people + join companies on people.company_id = companies.id + where ''' + people_filter + ''' = ? + ) + and scmlog.id in ( + select actions.commit_id from actions + join branches on branches.id = actions.branch_id + where branches.name = 'master' + ) + ''' + get_period_filter(period) + + get_project_type_filter(project_type) + ''' +order by scmlog.date desc + ''', [people_param, time_period[0], time_period[1]]) + + blueprints = set() + bugs = set() + commits = [] + code_only_commits = 0 + test_only_commits = 0 + code_and_test_commits = 0 + loc = 0 + + for c in commits_res: + module = c['repo'].rpartition('.')[0] + issue_type = c['issue_type'] + issue_id = c['issue_id'] + commit_type = c['commit_type'] + loc += c['added'] + c['removed'] + + is_code = commit_type & 0x1 + if commit_type == 1: + code_only_commits += 1 + is_test = commit_type & 0x2 + if commit_type == 2: + test_only_commits += 1 + if commit_type == 3: + code_and_test_commits += 1 + + if issue_type == 'blueprint': + blueprints.add((issue_id, module)) + elif issue_type == 'bug': + bugs.add((issue_id, is_code, is_test)) + + commits.append({ + 'message': link_change_id(link_bug(link_blueprint( + clear_text(c['message']), module))), + 'date': parse_date_from_string_to_timestamp(c['date']), + 'module': module, + 'is_code': is_code, + 'is_test': is_test, + 'added_loc': c['added'], + 'removed_loc': c['removed'], + }) + + return { + 'commits': commits, + 'blueprints': sorted(blueprints), + 'bugs': sorted(bugs, key=lambda rec: rec[0]), + 'code_only_commits': code_only_commits, + 'test_only_commits': test_only_commits, + 'code_and_test_commits': code_and_test_commits, + 'code_commits': (code_only_commits + test_only_commits + + code_and_test_commits), + 'non_code_commits': (len(commits) - code_only_commits - + test_only_commits - code_and_test_commits), + 'loc': loc, + } + + +@app.route('/engineers/') +@templated() +@cached(params=['period', 'project_type']) +@verified() +def engineer_details(engineer): + details_res = query_db(''' + select people.name, companies.name as company, + launchpad_id, email from people + join companies on people.company_id = companies.id + where people.launchpad_id = ? and end_date is null + ''', [engineer]) + + if not details_res: + flask.abort(404) + + details = row2dict(details_res[0]) + + commits = contribution_details(flask.request.args.get('period'), + flask.request.args.get('project_type'), + engineer=engineer) + commits.update({ + 'engineer': engineer, + 'details': details, + }) + + return commits + + +@app.route('/commits/') +@app.route('/commits/') +@templated() +@cached(params=['module', 'period', 'project_type']) +@verified() +def commits(issue_type=None): + if issue_type is not None and issue_type not in ISSUE_TYPES: + flask.abort(404) + + module, limit, period, metric, project_type = extract_params() + time_period = parse_time_period(period) + + res = query_db(''' +select scmlog.date, scmlog.message, repositories.name as repo, + details.issue_id, details.issue_type, details.change_id, + people.launchpad_id, people.name as author, companies.name as company, + people.email + from scmlog +join people on people.id = scmlog.author_id +join companies on people.company_id = companies.id +join repositories on repositories.id = scmlog.repository_id +join details on details.commit_id = scmlog.id +where + 1 = 1 +''' + get_period_filter(period) + get_project_type_filter(project_type) + ''' +order by scmlog.date desc +limit 2000 + ''', [time_period[0], time_period[1]]) + + issues = {} + for rec in res: + #todo make it right (e.g. paging) + if len(issues) > 200: + break + + if issue_type is not None and issue_type != rec['issue_type']: + continue + + module = rec['repo'].rpartition('.')[0] + timestamp = parse_date_from_string_to_timestamp(rec['date']) + item = { + 'message': link_change_id(link_bug(link_blueprint( + clear_text(rec['message']), module))), + 'date': timestamp, + 'change_id': rec['change_id'], + 'author': rec['author'], + 'company': rec['company'], + 'launchpad_id': rec['launchpad_id'], + 'email': rec['email'], + 'module': module, + } + + if issue_type is None: + key = DT.datetime.utcfromtimestamp(timestamp).strftime('%d %b %Y') + else: + key = rec['issue_id'] + + if key in issues: + issues[key].append(item) + else: + issues[key] = [item] + + return {'issue_type': issue_type, + 'issues': sorted( + [{'issue_id': key, 'items': value} for key, value in + issues.iteritems()], key=lambda rec: rec['items'][0]['date'], + reverse=True)} + + +@app.route('/unmapped') +@templated() +def unmapped(): + res = query_db(''' + select name, email from people + where launchpad_id is null + ''') + + if not res: + flask.abort(404) + + res = [{'name': a['name'], 'email': a['email']} for a in res + if (re.match(r'[\w\d._-]+@[\w\d_.-]+$', a['email']) and + a['name'] and a['name'] != 'root')] + + return {'details': res} + + +# AJAX HANDLERS ************************************************************** +# these handle data retrieval for tables and charts + + +@app.route('/data/companies') +@cached(params=['limit', 'module', 'period', 'metric', 'project_type']) +def get_companies(): + module, limit, period, metric, project_type = extract_params() + + params = [] + + if module: + module_filter = ''' + and scmlog.repository_id in ( + select repositories.id from repositories + where repositories.name = ? + ) + ''' + params.append(module + '.git') + else: + module_filter = '' + + metric_filter = get_metric_filter(metric) + + time_period = parse_time_period(period) + params.append(time_period[0]) + params.append(time_period[1]) + + raw = query_db(''' +select companies.name as company, ''' + metric_filter + ''' as rank from scmlog + join people on scmlog.author_id = people.id + join companies on people.company_id = companies.id + join commits_lines on commits_lines.commit_id = scmlog.id + join repositories on scmlog.repository_id = repositories.id +where + companies.name != '*robots' + and scmlog.id in ( + select actions.commit_id from actions + join branches on branches.id = actions.branch_id + where branches.name = 'master' + )''' + module_filter + get_period_filter(period) + + get_project_type_filter(project_type) + ''' +group by people.company_id +order by rank desc + ''', params) + + data = [{'name': rec['company'], 'rank': rec['rank']} + for rec in raw + if rec['company'] is not None] + data = index_column( + paste_links(filter_over_limit(data, limit), 'companies/', metric, + period, project_type)) + return json.dumps({'aaData': data}) + + +@app.route('/data/companies/') +@cached(params=['limit', 'period', 'metric', 'project_type']) +@verified() +def get_company_details(company): + module, limit, period, metric, project_type = extract_params() + time_period = parse_time_period(period) + + raw = query_db(''' +select ''' + get_metric_filter(metric) + ''' as rank, people.name, + people.launchpad_id from people +left join ( +select * from scmlog + join actions on actions.commit_id = scmlog.id + join branches on branches.id = actions.branch_id + join repositories on scmlog.repository_id = repositories.id + where branches.name = 'master' +''' + get_period_filter(period) + get_project_type_filter(project_type) + ''' +group by scmlog.id +) as scm on people.id = scm.author_id +join commits_lines on commits_lines.commit_id = scm.id +join companies on people.company_id = companies.id +where companies.name = ? +group by people.name +order by rank desc + ''', [time_period[0], time_period[1], company]) + + data = [{'rank': rec[0], 'name': rec[1], 'launchpad_id': rec[2]} + for rec in raw] + data = index_column(filter_over_limit(data, limit)) + for one in data: + if one['launchpad_id']: + one['link'] = ('' + + (one['name']) + '') + else: + one['link'] = one['name'] + return json.dumps({'aaData': data}) + + +@app.route('/data/modules') +@cached(params=['limit', 'company', 'engineer', 'period', 'metric', + 'project_type']) +def get_modules(): + module, limit, period, metric, project_type = extract_params() + company = flask.request.args.get('company') + engineer = flask.request.args.get('engineer') + + params = [] + + if engineer: + eng_filter = "and people.launchpad_id = ?" + params.append(engineer) + else: + eng_filter = '' + if company: + company_filter = "and companies.name = ?" + params.append(company) + else: + # if no company filter out all robots + company_filter = "and companies.name != '*robots'" + + time_period = parse_time_period(period) + params.append(time_period[0]) + params.append(time_period[1]) + + raw = query_db(''' +select repositories.name as repo, ''' + get_metric_filter(metric) + ''' as rank +from scmlog + join people on scmlog.author_id = people.id + join repositories on scmlog.repository_id = repositories.id + join commits_lines on commits_lines.commit_id = scmlog.id + join companies on people.company_id = companies.id +where + scmlog.id in ( + select actions.commit_id from actions + join branches on branches.id = actions.branch_id + where branches.name = 'master' + ) +''' + eng_filter + company_filter + get_period_filter(period) + + get_project_type_filter(project_type) + ''' +group by scmlog.repository_id +order by rank desc + ''', params) + + data = [{'name': rec[0].rpartition('.')[0], 'rank': rec[1]} for rec in raw] + data = index_column( + paste_links(filter_over_limit(data, limit), 'modules/', metric, period, + project_type)) + return json.dumps({'aaData': data}) + + +@app.route('/data/engineers') +@cached(params=['limit', 'module', 'period', 'metric', 'project_type']) +def get_engineers(): + module, limit, period, metric, project_type = extract_params() + + params = [] + + if module: + module_filter = ''' + and scmlog.repository_id in ( + select repositories.id from repositories + where repositories.name = ? + ) + ''' + params.append(module + '.git') + else: + module_filter = '' + + metric_filter = get_metric_filter(metric) + + time_period = parse_time_period(period) + params.append(time_period[0]) + params.append(time_period[1]) + + raw = query_db(''' +select people.name, people.launchpad_id, ''' + metric_filter + ''' as rank +from scmlog + join people on scmlog.author_id = people.id + join commits_lines on commits_lines.commit_id = scmlog.id + join repositories on scmlog.repository_id = repositories.id +where + people.email != 'review@openstack.org' + and people.email != 'jenkins@review.openstack.org' + and people.email != 'jenkins@openstack.org' + and scmlog.id in ( + select actions.commit_id from actions + join branches on branches.id = actions.branch_id + where branches.name = 'master' + )''' + module_filter + get_period_filter(period) + + get_project_type_filter(project_type) + + ''' + group by people.name + order by rank desc + ''', params) + + data = [{'name': rec['name'], 'rank': rec['rank'], + 'launchpad_id': rec['launchpad_id']} for rec in raw] + data = index_column(filter_over_limit(data, limit)) + for one in data: + if one['launchpad_id']: + one['link'] = ('' + + (one['name']) + '') + else: + one['link'] = one['name'] + return json.dumps({'aaData': data}) + + +@app.route('/data/timeline') +@cached(params=['company', 'engineer', 'period', 'metric', 'project_type']) +def get_timeline(): + + company = flask.request.args.get('company') + engineer = flask.request.args.get('engineer') + module, limit, period, metric, project_type = extract_params() + + params = [] + if company: + company_filter = 'and companies.name = ?' + params.append(company) + else: + company_filter = "and companies.name != '*robots'" + + if engineer: + engineer_filter = ''' + and scmlog.author_id in ( + select people.id from people + where people.launchpad_id = ? + ) + ''' + params.append(engineer) + else: + engineer_filter = '' + + if module: + module_filter = ''' + and scmlog.repository_id in ( + select repositories.id from repositories + where repositories.name = ? + ) + ''' + params.append(module + '.git') + else: + module_filter = '' + + records = query_db(''' +select scmlog.date, commits_lines.added + commits_lines.removed as rank +from scmlog +join commits_lines on commits_lines.commit_id = scmlog.id +join people on people.id = scmlog.author_id +join repositories on scmlog.repository_id = repositories.id +join companies on people.company_id = companies.id +where + scmlog.id in ( + select actions.commit_id from actions + join branches on branches.id = actions.branch_id + where branches.name = 'master' + ) +''' + company_filter + engineer_filter + module_filter + + get_project_type_filter(project_type) + ''' +order by scmlog.date + ''', params) + + start_date = DT.date(2010, 5, 1) + + def mkdate2(datestring): + return DT.datetime.strptime(datestring, "%Y-%m-%d %H:%M:%S").date() + + def week(date): + return (date - start_date).days // 7 + + def week_rev(n): + return start_date + DT.timedelta(days=n * 7) + + dct_rank = {} + dct_count = {} + t = map(lambda (rec): [mkdate2(str(rec[0])), rec[1]], records) + + for key, grp in itertools.groupby(t, key=lambda (pair): week(pair[0])): + grp_as_list = list(grp) + dct_rank[key] = sum([x[1] for x in grp_as_list]) + dct_count[key] = len(grp_as_list) + + last = week(DT.datetime.now().date()) + res_rank = [] + res_count = [] + + for n in range(1, last + 1): + if n not in dct_rank: + dct_rank[n] = 0 + dct_count[n] = 0 + + rev = week_rev(n) + res_rank.append([str(rev) + ' 0:00AM', dct_rank[n]]) + res_count.append([str(rev) + ' 0:00AM', dct_count[n]]) + + begin, end = extract_time_period(period) + begin = week(begin) + end = week(end) + u_begin = len(res_count) - 52 + u_end = len(res_count) + + if period == 'all': + begin = 0 + u_begin = 0 + end = u_end + elif period != 'six_months': + if u_end > end + 13: + u_end = end + 13 + u_begin = u_end - 52 + + return json.dumps([res_count[u_begin:u_end], + res_count[begin:end], + res_rank[u_begin:u_end]]) + + +# JINJA FILTERS ************************************************************** +# some useful filters to help with data formatting + +@app.template_filter('datetimeformat') +def format_datetime(timestamp): + return DT.datetime.utcfromtimestamp(timestamp).strftime('%d %b %Y @ %H:%M') + + +@app.template_filter('launchpadmodule') +def format_launchpad_module_link(module): + return '%s' % (module, module) + + +@app.template_filter('encode') +def safe_encode(s): + return urllib.quote_plus(s) + + +gravatar = gravatar_ext.Gravatar(app, + size=100, + rating='g', + default='wavatar', + force_default=False, + force_lower=False) + +# APPLICATION LAUNCHER ******************************************************* + +if __name__ == '__main__': + app.run('0.0.0.0') diff --git a/dashboard/static/css/jquery.dataTables.css b/dashboard/static/css/jquery.dataTables.css new file mode 100644 index 000000000..13c6d920a --- /dev/null +++ b/dashboard/static/css/jquery.dataTables.css @@ -0,0 +1,252 @@ + +/* + * Table + */ +table.dataTable { + border-spacing:0; + margin: 0 auto; + clear: both; + width: 100%; +} + +table.dataTable thead th { +font-size: 18px; +font-weight: normal; +border-right: 1px solid #CCC; +background-color: #F0F3FA; +text-align: left; +font-weight: normal; +background-image: none; +border-bottom: 1px dotted #CECECE; +text-shadow: 1px 1px 0px white; +padding: 5px 6px; +text-align: center; +border-top-left-radius: 5px; +border-top-right-radius: 5px; + cursor: pointer; + *cursor: hand; +} + +table.dataTable tfoot th { + padding: 3px 18px 3px 10px; + border-top: 1px solid black; + font-weight: bold; +} + +table.dataTable td { + padding: 3px 10px; +} + +table.dataTable td.center, +table.dataTable td.dataTables_empty { + text-align: center; +} + +table.dataTable tr.odd { background-color: #fbfafa; } +table.dataTable tr.even { background-color: white; } + +table.dataTable tr.odd td.sorting_1 { background-color: #eef1f4; border-right: 1px solid #CCC; } +table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; } +table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; } +table.dataTable tr.even td.sorting_1 { background-color: #f8f9fa; border-right: 1px solid #CCC; } +table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; } +table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; } + + +/* + * Table wrapper + */ +.dataTables_wrapper { + position: relative; + clear: both; + *zoom: 1; +} + + +/* + * Page length menu + */ +.dataTables_length { + float: left; + color:#bcc1cb; + font-style:italic; +} + + +/* + * Filter + */ +.dataTables_filter { + float: right; + text-align: right; + margin-bottom: 25px; +} + +.dataTables_filter label { + color:#bcc1cb; + font-style:italic; +} + + +/* + * Table information + */ +.dataTables_info { + clear: both; + float: left; + margin-top: 10px; + color:#bcc1cb; + font-style:italic; +} + + +/* + * Pagination + */ +.dataTables_paginate { + float: right; + text-align: right; + margin-top: 10px; +} + +/* Two button pagination - previous / next */ +.paginate_disabled_previous, +.paginate_enabled_previous, +.paginate_disabled_next, +.paginate_enabled_next { + height: 19px; + float: left; + cursor: pointer; + *cursor: hand; + color: #111 !important; +} +.paginate_disabled_previous:hover, +.paginate_enabled_previous:hover, +.paginate_disabled_next:hover, +.paginate_enabled_next:hover { + text-decoration: none !important; +} +.paginate_disabled_previous:active, +.paginate_enabled_previous:active, +.paginate_disabled_next:active, +.paginate_enabled_next:active { + outline: none; +} + +.paginate_disabled_previous, +.paginate_disabled_next { + color: #666 !important; +} +.paginate_disabled_previous, +.paginate_enabled_previous { + padding-left: 23px; +} +.paginate_disabled_next, +.paginate_enabled_next { + padding-right: 23px; + margin-left: 10px; +} + +.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; } +.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; } +.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; } + +.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; } +.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; } +.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; } + +/* Full number pagination */ +.paging_full_numbers { + height: 22px; + line-height: 22px; +} +.paging_full_numbers a:active { + outline: none +} +.paging_full_numbers a:hover { + text-decoration: none; +} + +.paging_full_numbers a.paginate_active { + text-decoration: none; + cursor: pointer; + padding: 0.2em 0.5em; + -moz-border-radius: 3px; + border-radius: 3px; + margin: 4px; + font-weight: normal; + color: #9f3729; + text-shadow: 1px 1px 0px #ff7d6c; + background: #d3301a; +} + +.paging_full_numbers a.paginate_button { + text-decoration: none; + cursor: pointer; + padding: 0.2em 0.5em; + background: #edeff1; + -moz-border-radius: 3px; + border-radius: 3px; + text-shadow: 1px 1px 0px white; + margin: 4px; + border: 1px solid #e0e2e4; +} + +.paging_full_numbers a.paginate_button:hover { + border-color: #bc2814; + background: #d3301a; + color: white; + text-shadow: -1px -1px 0px #992010; +} + + + + +/* + * Processing indicator + */ +.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 250px; + height: 30px; + margin-left: -125px; + margin-top: -15px; + padding: 14px 0 2px 0; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 14px; + background-color: white; +} + + +/* + * Sorting + */ +.sorting { background: url('../images/sort_both.png') no-repeat center right; } +.sorting_asc { background: url('../images/sort_asc.png') no-repeat center right; } +.sorting_desc { background: url('../images/sort_desc.png') no-repeat center right; } + +.sorting_asc_disabled { background: url('../images/sort_asc_disabled.png') no-repeat center right; } +.sorting_desc_disabled { background: url('../images/sort_desc_disabled.png') no-repeat center right; } + +table.dataTable thead th:active, +table.dataTable thead td:active { + outline: none; +} + + +/* + * Scrolling + */ +.dataTables_scroll { + clear: both; +} + +.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} + diff --git a/dashboard/static/css/jquery.dataTables_themeroller.css b/dashboard/static/css/jquery.dataTables_themeroller.css new file mode 100644 index 000000000..cf1d4ed79 --- /dev/null +++ b/dashboard/static/css/jquery.dataTables_themeroller.css @@ -0,0 +1,244 @@ + + +/* + * Table + */ +table.dataTable { + margin: 0 auto; + clear: both; + width: 100%; + border-collapse: collapse; +} + +table.dataTable thead th { + padding: 3px 0px 3px 10px; + cursor: pointer; + *cursor: hand; +} + +table.dataTable tfoot th { + padding: 3px 10px; +} + +table.dataTable td { + padding: 3px 10px; +} + +table.dataTable td.center, +table.dataTable td.dataTables_empty { + text-align: center; +} + +table.dataTable tr.odd { background-color: #E2E4FF; } +table.dataTable tr.even { background-color: white; } + +table.dataTable tr.odd td.sorting_1 { background-color: #D3D6FF; } +table.dataTable tr.odd td.sorting_2 { background-color: #DADCFF; } +table.dataTable tr.odd td.sorting_3 { background-color: #E0E2FF; } +table.dataTable tr.even td.sorting_1 { background-color: #EAEBFF; } +table.dataTable tr.even td.sorting_2 { background-color: #F2F3FF; } +table.dataTable tr.even td.sorting_3 { background-color: #F9F9FF; } + + +/* + * Table wrapper + */ +.dataTables_wrapper { + position: relative; + clear: both; + *zoom: 1; +} +.dataTables_wrapper .ui-widget-header { + font-weight: normal; +} +.dataTables_wrapper .ui-toolbar { + padding: 5px; +} + + +/* + * Page length menu + */ +.dataTables_length { + float: left; +} + + +/* + * Filter + */ +.dataTables_filter { + float: right; + text-align: right; +} + + +/* + * Table information + */ +.dataTables_info { + padding-top: 3px; + clear: both; + float: left; +} + + +/* + * Pagination + */ +.dataTables_paginate { + float: right; + text-align: right; +} + +.dataTables_paginate .ui-button { + margin-right: -0.1em !important; +} + +.paging_two_button .ui-button { + float: left; + cursor: pointer; + * cursor: hand; +} + +.paging_full_numbers .ui-button { + padding: 2px 6px; + margin: 0; + cursor: pointer; + * cursor: hand; + color: #333 !important; +} + +/* Two button pagination - previous / next */ +.paginate_disabled_previous, +.paginate_enabled_previous, +.paginate_disabled_next, +.paginate_enabled_next { + height: 19px; + float: left; + cursor: pointer; + *cursor: hand; + color: #111 !important; +} +.paginate_disabled_previous:hover, +.paginate_enabled_previous:hover, +.paginate_disabled_next:hover, +.paginate_enabled_next:hover { + text-decoration: none !important; +} +.paginate_disabled_previous:active, +.paginate_enabled_previous:active, +.paginate_disabled_next:active, +.paginate_enabled_next:active { + outline: none; +} + +.paginate_disabled_previous, +.paginate_disabled_next { + color: #666 !important; +} +.paginate_disabled_previous, +.paginate_enabled_previous { + padding-left: 23px; +} +.paginate_disabled_next, +.paginate_enabled_next { + padding-right: 23px; + margin-left: 10px; +} + +.paginate_enabled_previous { background: url('../images/back_enabled.png') no-repeat top left; } +.paginate_enabled_previous:hover { background: url('../images/back_enabled_hover.png') no-repeat top left; } +.paginate_disabled_previous { background: url('../images/back_disabled.png') no-repeat top left; } + +.paginate_enabled_next { background: url('../images/forward_enabled.png') no-repeat top right; } +.paginate_enabled_next:hover { background: url('../images/forward_enabled_hover.png') no-repeat top right; } +.paginate_disabled_next { background: url('../images/forward_disabled.png') no-repeat top right; } + +/* Full number pagination */ +.paging_full_numbers a:active { + outline: none +} +.paging_full_numbers a:hover { + text-decoration: none; +} + +.paging_full_numbers a.paginate_button, +.paging_full_numbers a.paginate_active { + border: 1px solid #aaa; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + padding: 2px 5px; + margin: 0 3px; + cursor: pointer; + *cursor: hand; + color: #333 !important; +} + +.paging_full_numbers a.paginate_button { + background-color: #ddd; +} + +.paging_full_numbers a.paginate_button:hover { + background-color: #ccc; + text-decoration: none !important; +} + +.paging_full_numbers a.paginate_active { + background-color: #99B3FF; +} + + +/* + * Processing indicator + */ +.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 250px; + height: 30px; + margin-left: -125px; + margin-top: -15px; + padding: 14px 0 2px 0; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 14px; + background-color: white; +} + + +/* + * Sorting + */ +table.dataTable thead th div.DataTables_sort_wrapper { + position: relative; + padding-right: 20px; +} + +table.dataTable thead th div.DataTables_sort_wrapper span { + position: absolute; + top: 50%; + margin-top: -8px; + right: 0; +} + +table.dataTable th:active { + outline: none; +} + + +/* + * Scrolling + */ +.dataTables_scroll { + clear: both; +} + +.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} + diff --git a/dashboard/static/css/jquery.jqplot.min.css b/dashboard/static/css/jquery.jqplot.min.css new file mode 100644 index 000000000..01e249369 --- /dev/null +++ b/dashboard/static/css/jquery.jqplot.min.css @@ -0,0 +1 @@ +.jqplot-target{position:relative;color:black;font-family:"PT Sans",Arial,sans-serif;font-size:1em;text-shadow: 1px 1px 0 rgba(255,255,255, 0.5);}.jqplot-axis{font-size:.75em;}.jqplot-xaxis{margin-top:10px;}.jqplot-x2axis{margin-bottom:10px;}.jqplot-yaxis{margin-right:10px;}.jqplot-y2axis,.jqplot-y3axis,.jqplot-y4axis,.jqplot-y5axis,.jqplot-y6axis,.jqplot-y7axis,.jqplot-y8axis,.jqplot-y9axis,.jqplot-yMidAxis{margin-left:10px;margin-right:10px;}.jqplot-axis-tick,.jqplot-xaxis-tick,.jqplot-yaxis-tick,.jqplot-x2axis-tick,.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick,.jqplot-yMidAxis-tick{position:absolute;white-space:pre;}.jqplot-xaxis-tick{top:0;left:15px;vertical-align:top;}.jqplot-x2axis-tick{bottom:0;left:15px;vertical-align:bottom;}.jqplot-yaxis-tick{right:0;top:15px;text-align:right;}.jqplot-yaxis-tick.jqplot-breakTick{right:-20px;margin-right:0;padding:1px 5px 1px 5px;z-index:2;font-size:1.5em;}.jqplot-y2axis-tick,.jqplot-y3axis-tick,.jqplot-y4axis-tick,.jqplot-y5axis-tick,.jqplot-y6axis-tick,.jqplot-y7axis-tick,.jqplot-y8axis-tick,.jqplot-y9axis-tick{left:0;top:15px;text-align:left;}.jqplot-yMidAxis-tick{text-align:center;white-space:nowrap;}.jqplot-xaxis-label{margin-top:10px;font-size:11pt;position:absolute;}.jqplot-x2axis-label{margin-bottom:10px;font-size:11pt;position:absolute;}.jqplot-yaxis-label{margin-right:10px;font-size:11pt;position:absolute;}.jqplot-yMidAxis-label{font-size:11pt;position:absolute;}.jqplot-y2axis-label,.jqplot-y3axis-label,.jqplot-y4axis-label,.jqplot-y5axis-label,.jqplot-y6axis-label,.jqplot-y7axis-label,.jqplot-y8axis-label,.jqplot-y9axis-label{font-size:11pt;margin-left:10px;position:absolute;}.jqplot-meterGauge-tick{font-size:.75em;color:#999;}.jqplot-meterGauge-label{font-size:1em;color:#999;}table.jqplot-table-legend{margin-top:12px;margin-bottom:12px;margin-left:12px;margin-right:12px;}table.jqplot-table-legend,table.jqplot-cursor-legend{background-color:rgba(255,255,255,0.6);border:none;position:absolute;font-size:13px; color:#192233;}td.jqplot-table-legend{vertical-align:middle;}td.jqplot-seriesToggle:hover,td.jqplot-seriesToggle:active{cursor:pointer;}.jqplot-table-legend .jqplot-series-hidden{text-decoration:line-through;}div.jqplot-table-legend-swatch-outline{/*border:1px solid #ccc;padding:1px;*/}div.jqplot-table-legend-swatch{width:0;height:0;border-top-width:5px;border-bottom-width:5px;border-left-width:6px;border-right-width:6px;border-top-style:solid;border-bottom-style:solid;border-left-style:solid;border-right-style:solid;}.jqplot-title{top:0;left:0;padding-bottom:.5em;font-size:1.2em;}table.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;}.jqplot-cursor-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-highlighter-tooltip,.jqplot-canvasOverlay-tooltip{border:1px solid #ccc;font-size:.75em;white-space:nowrap;background:rgba(208,208,208,0.5);padding:1px;}.jqplot-point-label{font-size:.75em;z-index:2;}td.jqplot-cursor-legend-swatch{vertical-align:middle;text-align:center;}div.jqplot-cursor-legend-swatch{width:1.2em;height:.7em;}.jqplot-error{text-align:center;}.jqplot-error-message{position:relative;top:46%;display:inline-block;}div.jqplot-bubble-label{font-size:.8em;padding-left:2px;padding-right:2px;color:rgb(20%,20%,20%);}div.jqplot-bubble-label.jqplot-bubble-label-highlight{background:rgba(90%,90%,90%,0.7);}div.jqplot-noData-container{text-align:center;background-color:rgba(96%,96%,96%,0.3);} \ No newline at end of file diff --git a/dashboard/static/css/style.css b/dashboard/static/css/style.css new file mode 100644 index 000000000..bf93fe8f1 --- /dev/null +++ b/dashboard/static/css/style.css @@ -0,0 +1,474 @@ +html, body { + font-family: 'PT Sans', arial, sans-serif; + font-size: 14px; + background: url(../images/osstats_tile.jpg) repeat-x; + height: 100%; + color: #41454d; + margin: 0; +} + +a { + color: #D32F1A; + text-decoration: none; +} + +a:hover { + color: #F00; +} + +p { + font-size: 15px; + color: #41454D; + font-style: normal; + margin: 6px 0px 15px 0px; +} + +div.Xpage { + width: 960px; + margin: 0 auto; +} + +div.Xpage h2 { + font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif; + font-size: 23px; + font-weight: normal; + font-style: normal; + padding-top: 10px; + margin-bottom: 10px; + padding-left: 10px; + text-shadow: 1px 1px 0 #fff; +} + +input[type="text"], +input[type="password"] { + background: #f8f9f9; + padding: 0 5px 0 5px; + min-height: 24px; + border: none; + border-bottom: 1px solid white; + border-right: 1px solid white; + -moz-border-radius: 3px; + border-radius: 3px; + text-shadow: 1px 1px 0 white; + -moz-box-shadow: inset 2px 2px 7px #D3D8DD; + -webkit-box-shadow: inset 2px 2px 7px #D3D8DD; + box-shadow: inset 2px 2px 7px #D3D8DD; +} + +input[type="submit"] { + background: #f8f9f9; + padding: 0 5px 0 5px; + min-height: 24px; + border: none; + border-bottom: 1px solid white; + border-right: 1px solid white; + -moz-border-radius: 2px; + border-radius: 2px; + text-shadow: 1px 1px 0 white; + -moz-box-shadow: inset 2px 2px 7px #D3D8DD; + -webkit-box-shadow: inset 2px 2px 7px #D3D8DD; + box-shadow: inset 2px 2px 7px #D3D8DD; +} + +div.page { + background: white; + border: 1px solid #e9eaef; + width: 90%; + margin: 10px auto; +} + +div.page h1 { + background: white; + margin: 0; + padding: 0.1em 0.2em; + color: black; + font-weight: normal; +} + +div.drops { + font-size: 15px; + height: 60px; +} + +div.drops label { + color: #909cb5; +} + +span.drop_period { + margin-top: 6px; + display: block; + height: 30px; + float: right; +} + +span.drop_metric { + margin-top: 6px; + margin-right: 1em; + display: block; + height: 30px; + float: right; +} + +select { + background: #f8f9f9; + padding: 0 5px 0 5px; + min-height: 24px; + border: none; + border-bottom: 1px solid white; + border-right: 1px solid white; + -moz-border-radius: 2px; + border-radius: 2px; + text-shadow: 1px 1px 0 white; + -moz-box-shadow: inset 2px 2px 7px #D3D8DD; + -webkit-box-shadow: inset 2px 2px 7px #D3D8DD; + box-shadow: inset 2px 2px 7px #D3D8DD; +} + +div.aheader { + height: 60px; + background: #e0e9f2; + text-shadow: 1px 1px 0 #fff; +} + +div.aheader h1 { + font-size: 36px; + color: #a8b3bd; + text-shadow: 1px 1px 0 #fff; +} + +div.aheader h1 a { + font-weight: bold; + color: #637f99; + text-decoration: none; + text-shadow: 1px 1px 0 #fff; +} + +div.page div.navigation { + text-shadow: 1px 1px 0 #fff; + background: #fbfafa; + padding: 4px 10px; + border-top: 1px dashed #e9eaef; + border-bottom: 1px dashed #e9eaef; + color: #909cb5; + font-size: 10pt; +} + +div.page div.navigation a { + color: #444; + font-weight: bold; +} + +div.page h2 { + margin: 10px 0 0 10px; + color: #a41200; +} + +div.page div.body { + padding: 10px; +} + +div.page div.footer { + background: #eee; + color: #888; + padding: 1em 1em; + font-size: 9pt; +} + +div.page ul.messages { + list-style: none; + margin: 0; + padding: 0; +} + +div.page ul.messages li { + margin: 10px 0; + padding: 5px; + background: #F0FAF9; + border: 1px solid #DBF3F1; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + min-height: 48px; +} + +div.page ul.messages p { + margin: 0; +} + +div.page ul.messages li img { + float: left; + padding: 0 10px 0 0; +} + +div.page ul.messages li small { + font-size: 0.9em; + color: #888; +} + +div.page div.twitbox { + margin: 10px 0; + padding: 5px; + background: #F0FAF9; + border: 1px solid #94E2DA; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +div.page div.twitbox h3 { + margin: 0; + font-size: 1em; + color: #2C7E76; +} + +div.page div.twitbox p { + margin: 0; +} + +div.page div.twitbox input[type="text"] { + width: 585px; +} + +div.page div.twitbox input[type="submit"] { + width: 70px; + margin-left: 5px; +} + +ul.flashes { + list-style: none; + margin: 10px 10px 0 10px; + padding: 0; +} + +ul.flashes li { + background: #B9F3ED; + border: 1px solid #81CEC6; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + padding: 4px; + font-size: 13px; +} + +div.error { + margin: 10px 0; + background: #FAE4E4; + border: 1px solid #DD6F6F; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + padding: 4px; + font-size: 13px; +} + +.spacer { + height: 20px; + clear: both; +} + +table#left_list td { + font-size: 15px; +} + +table#right_list td { + font-size: 15px; +} + +div#left_list_wrapper { + margin-top: 20px; +} + +div#right_list_wrapper { + margin-top: 20px; +} + +.message { + white-space: pre-wrap; +} + +a[href^="https://blueprints"]:after { + content: "↗"; + opacity: 0.3; +} + +a[href^="https://review"]:after { + content: "↗"; + opacity: 0.3; +} + +a[href^="https://bugs"]:after { + content: "↗"; + opacity: 0.3; +} + +a[href^="https://launchpad"]:after { + content: "↗"; + opacity: 0.3; +} + +#analytics_header { + height: 25px; + width: 960px; + margin: 0 auto; + clear: both; +} + +#analytics_header h3 { + font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif; + font-weight: normal; + font-style: normal; + font-size: 24px; + color: black; + padding-top: 30px; + text-shadow: 1px 1px 0 #fff; + margin: 0px; +} + +#analytics_header p { + font-family: georgia, serif; + font-weight: normal; + font-style: italic; + font-size: 16px; + margin: 0; + padding: 0; + color: #647280; + line-height: 1.1em; + text-shadow: 1px 1px 0 #fff; +} + +.paging_full_numbers { + font-size: 9pt; +} + +/* MIRANTIS CSS*/ + +#miraheader { + margin: 0 auto; + width: 960px; +} + +#top-menu { + height: 30px; +} + +#ttopmenu { + float: right; + height: 20px; + overflow: hidden; + margin-top: 10px; +} + +#ttopmenu a { + font-size: 13px; + font-style: italic; + color: #A7B6C3; +} + +#ttopmenu a:hover { + color: #6e8598; +} + +#main-menu { + height: 47px; + margin-top: 30px; + text-align: right; + position: relative; +} + +a.glink { + color: black; + font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif; + font-size: 19px; + padding: 5px 5px 5px 12px; + white-space: nowrap; + text-decoration: none; +} + +a.glink:hover { + color: #d3301a; +} + +.subglobalNav { + color: black; + position: absolute; + font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif; + font-size: 14px; + white-space: nowrap; + text-decoration: none; + right: 0px; + padding-top: 10px; +} + +.subglobalNav a { + color: black; + text-decoration: none; + padding: 2px 7px 2px 7px; + margin-left: 12px; +} + +.subglobalNav a:hover { + color: #fff; + background: #CB2E19; + -moz-border-radius: 2px; + border-radius: 2px; + margin-left: 12px; + text-shadow: -1px -1px 0px #7F2114; +} + +a.act { + color: #d3301a !important; +} + +a.act:hover { + color: #fff !important; + background: #CB2E19; +} + +a.active { + color: #d3301a; +} + +#dummy { + height: 115px; + margin-top: 20px; + width: 100%; +} + +#footer { + height: 115px; + margin-top: -120px; + background: url(../images/footer_tile.jpg) repeat-x; + font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif; + font-size: 17px; + line-height: 21px; + text-shadow: 1px 1px 0px white; + +} + +#foottable td { + padding-top: 20px; +} + +#footer_content { + width: 960px; + margin: 4px auto auto auto; + height: 110px; +} + +.fgeneral { + color: black; +} + +.fgeneralblue { + color: #43678a; +} + +.fslogan { + font-family: 'PT Sans', arial, sans-serif; + font-style: italic; + color: #43678a; + font-size: 13px; +} + +#fbox { + padding-left: 10px; + border-left: 1px solid #d5dbe1; +} + +/* MIRANTIS CSS*/ \ No newline at end of file diff --git a/dashboard/static/css/ui-darkness/images/animated-overlay.gif b/dashboard/static/css/ui-darkness/images/animated-overlay.gif new file mode 100644 index 000000000..d441f75eb Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/animated-overlay.gif differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png b/dashboard/static/css/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png new file mode 100644 index 000000000..9d57f7653 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png b/dashboard/static/css/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png new file mode 100644 index 000000000..110058b31 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_glass_20_555555_1x400.png b/dashboard/static/css/ui-darkness/images/ui-bg_glass_20_555555_1x400.png new file mode 100644 index 000000000..cc977f5e9 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_glass_20_555555_1x400.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png b/dashboard/static/css/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png new file mode 100644 index 000000000..48bb6d5e9 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png b/dashboard/static/css/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png new file mode 100644 index 000000000..b4c7f25e4 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png b/dashboard/static/css/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png new file mode 100644 index 000000000..3823bfadb Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png b/dashboard/static/css/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png new file mode 100644 index 000000000..8a9305cf6 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png b/dashboard/static/css/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png new file mode 100644 index 000000000..7ba06eda6 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png b/dashboard/static/css/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png new file mode 100644 index 000000000..182fbad3e Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-icons_222222_256x240.png b/dashboard/static/css/ui-darkness/images/ui-icons_222222_256x240.png new file mode 100644 index 000000000..c1cb1170c Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-icons_222222_256x240.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-icons_4b8e0b_256x240.png b/dashboard/static/css/ui-darkness/images/ui-icons_4b8e0b_256x240.png new file mode 100644 index 000000000..232832a5a Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-icons_4b8e0b_256x240.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-icons_a83300_256x240.png b/dashboard/static/css/ui-darkness/images/ui-icons_a83300_256x240.png new file mode 100644 index 000000000..bb22520bb Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-icons_a83300_256x240.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-icons_cccccc_256x240.png b/dashboard/static/css/ui-darkness/images/ui-icons_cccccc_256x240.png new file mode 100644 index 000000000..571103925 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-icons_cccccc_256x240.png differ diff --git a/dashboard/static/css/ui-darkness/images/ui-icons_ffffff_256x240.png b/dashboard/static/css/ui-darkness/images/ui-icons_ffffff_256x240.png new file mode 100644 index 000000000..da11f0a12 Binary files /dev/null and b/dashboard/static/css/ui-darkness/images/ui-icons_ffffff_256x240.png differ diff --git a/dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.css b/dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.css new file mode 100644 index 000000000..31b21626c --- /dev/null +++ b/dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.css @@ -0,0 +1,1175 @@ +/*! jQuery UI - v1.10.1 - 2013-03-04 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Segoe%20UI%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=333333&bgTextureHeader=gloss_wave&bgImgOpacityHeader=25&borderColorHeader=333333&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=000000&bgTextureContent=inset_soft&bgImgOpacityContent=25&borderColorContent=666666&fcContent=ffffff&iconColorContent=cccccc&bgColorDefault=555555&bgTextureDefault=glass&bgImgOpacityDefault=20&borderColorDefault=666666&fcDefault=eeeeee&iconColorDefault=cccccc&bgColorHover=0078a3&bgTextureHover=glass&bgImgOpacityHover=40&borderColorHover=59b4d4&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=f58400&bgTextureActive=inset_soft&bgImgOpacityActive=30&borderColorActive=ffaf0f&fcActive=ffffff&iconColorActive=222222&bgColorHighlight=eeeeee&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=80&borderColorHighlight=cccccc&fcHighlight=2e7db2&iconColorHighlight=4b8e0b&bgColorError=ffc73d&bgTextureError=glass&bgImgOpacityError=40&borderColorError=ffb73d&fcError=111111&iconColorError=a83300&bgColorOverlay=5c5c5c&bgTextureOverlay=flat&bgImgOpacityOverlay=50&opacityOverlay=80&bgColorShadow=cccccc&bgTextureShadow=flat&bgImgOpacityShadow=30&opacityShadow=60&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px +* Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); +} + +.ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; +} + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-accordion .ui-accordion-header { + display: block; + cursor: pointer; + position: relative; + margin-top: 2px; + padding: .5em .5em .5em .7em; + min-height: 0; /* support: IE7 */ +} +.ui-accordion .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-noicons { + padding-left: .7em; +} +.ui-accordion .ui-accordion-icons .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-header .ui-accordion-header-icon { + position: absolute; + left: .5em; + top: 50%; + margin-top: -8px; +} +.ui-accordion .ui-accordion-content { + padding: 1em 2.2em; + border-top: 0; + overflow: auto; +} +.ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; +} +.ui-button { + display: inline-block; + position: relative; + padding: 0; + line-height: normal; + margin-right: .1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: visible; /* removes extra width in IE */ +} +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2.2em; +} +/* button elements seem to need a little more width */ +button.ui-button-icon-only { + width: 2.4em; +} +.ui-button-icons-only { + width: 3.4em; +} +button.ui-button-icons-only { + width: 3.7em; +} + +/* button text element */ +.ui-button .ui-button-text { + display: block; + line-height: normal; +} +.ui-button-text-only .ui-button-text { + padding: .4em 1em; +} +.ui-button-icon-only .ui-button-text, +.ui-button-icons-only .ui-button-text { + padding: .4em; + text-indent: -9999999px; +} +.ui-button-text-icon-primary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 1em .4em 2.1em; +} +.ui-button-text-icon-secondary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 2.1em .4em 1em; +} +.ui-button-text-icons .ui-button-text { + padding-left: 2.1em; + padding-right: 2.1em; +} +/* no icon support for input elements, provide padding by default */ +input.ui-button { + padding: .4em 1em; +} + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon, +.ui-button-text-icon-primary .ui-icon, +.ui-button-text-icon-secondary .ui-icon, +.ui-button-text-icons .ui-icon, +.ui-button-icons-only .ui-icon { + position: absolute; + top: 50%; + margin-top: -8px; +} +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} +.ui-button-text-icon-primary .ui-button-icon-primary, +.ui-button-text-icons .ui-button-icon-primary, +.ui-button-icons-only .ui-button-icon-primary { + left: .5em; +} +.ui-button-text-icon-secondary .ui-button-icon-secondary, +.ui-button-text-icons .ui-button-icon-secondary, +.ui-button-icons-only .ui-button-icon-secondary { + right: .5em; +} + +/* button sets */ +.ui-buttonset { + margin-right: 7px; +} +.ui-buttonset .ui-button { + margin-left: 0; + margin-right: -.3em; +} + +/* workarounds */ +/* reset extra padding in Firefox, see h5bp.com/l */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-datepicker { + width: 17em; + padding: .2em .2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: .2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month-year { + width: 100%; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 49%; +} +.ui-datepicker table { + width: 100%; + font-size: .9em; + border-collapse: collapse; + margin: 0 0 .4em; +} +.ui-datepicker th { + padding: .7em .3em; + text-align: center; + font-weight: bold; + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: .2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto .4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} + +/* RTL support */ +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} +.ui-dialog { + position: absolute; + top: 0; + left: 0; + padding: .2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: .4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: .1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: .3em; + top: 50%; + width: 21px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: .5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: .5em; + padding: .3em 1em .5em .4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: .5em .4em .5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-se { + width: 12px; + height: 12px; + right: -5px; + bottom: -5px; + background-position: 16px 16px; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-menu { + list-style: none; + padding: 2px; + margin: 0; + display: block; + outline: none; +} +.ui-menu .ui-menu { + margin-top: -3px; + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + padding: 0; + width: 100%; +} +.ui-menu .ui-menu-divider { + margin: 5px -2px 5px -2px; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-menu-item a { + text-decoration: none; + display: block; + padding: 2px .4em; + line-height: 1.5; + min-height: 0; /* support: IE7 */ + font-weight: normal; +} +.ui-menu .ui-menu-item a.ui-state-focus, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} + +.ui-menu .ui-state-disabled { + font-weight: normal; + margin: .4em 0 .2em; + line-height: 1.5; +} +.ui-menu .ui-state-disabled a { + cursor: default; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item a { + position: relative; + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: .2em; + left: .2em; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + position: static; + float: right; +} +.ui-progressbar { + height: 2em; + text-align: left; + overflow: hidden; +} +.ui-progressbar .ui-progressbar-value { + margin: -1px; + height: 100%; +} +.ui-progressbar .ui-progressbar-overlay { + background: url("images/animated-overlay.gif"); + height: 100%; + filter: alpha(opacity=25); + opacity: 0.25; +} +.ui-progressbar-indeterminate .ui-progressbar-value { + background-image: none; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: .7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* For IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: .8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -.3em; + margin-left: -.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: .8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -.3em; + margin-left: 0; + margin-bottom: -.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} +.ui-spinner { + position: relative; + display: inline-block; + overflow: hidden; + padding: 0; + vertical-align: middle; +} +.ui-spinner-input { + border: none; + background: none; + color: inherit; + padding: 0; + margin: .2em 0; + vertical-align: middle; + margin-left: .4em; + margin-right: 22px; +} +.ui-spinner-button { + width: 16px; + height: 50%; + font-size: .5em; + padding: 0; + margin: 0; + text-align: center; + position: absolute; + cursor: default; + display: block; + overflow: hidden; + right: 0; +} +/* more specificity required here to overide default borders */ +.ui-spinner a.ui-spinner-button { + border-top: none; + border-bottom: none; + border-right: none; +} +/* vertical centre icon */ +.ui-spinner .ui-icon { + position: absolute; + margin-top: -8px; + top: 50%; + left: 0; +} +.ui-spinner-up { + top: 0; +} +.ui-spinner-down { + bottom: 0; +} + +/* TR overrides */ +.ui-spinner .ui-icon-triangle-1-s { + /* need to fix icons sprite */ + background-position: -65px -16px; +} +.ui-tabs { + position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: .2em; +} +.ui-tabs .ui-tabs-nav { + margin: 0; + padding: .2em .2em 0; +} +.ui-tabs .ui-tabs-nav li { + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px .2em 0 0; + border-bottom: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav li a { + float: left; + padding: .5em 1em; + text-decoration: none; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active { + margin-bottom: -1px; + padding-bottom: 1px; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active a, +.ui-tabs .ui-tabs-nav li.ui-state-disabled a, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading a { + cursor: text; +} +.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { + cursor: pointer; +} +.ui-tabs .ui-tabs-panel { + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; +} +.ui-tooltip { + padding: 8px; + position: absolute; + z-index: 9999; + max-width: 300px; + -webkit-box-shadow: 0 0 5px #aaa; + box-shadow: 0 0 5px #aaa; +} +body .ui-tooltip { + border-width: 2px; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: Segoe UI,Arial,sans-serif; + font-size: 1.1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: Segoe UI,Arial,sans-serif; + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #666666; + background: #000000 url(images/ui-bg_inset-soft_25_000000_1x100.png) 50% bottom repeat-x; + color: #ffffff; +} +.ui-widget-content a { + color: #ffffff; +} +.ui-widget-header { + border: 1px solid #333333; + background: #333333 url(images/ui-bg_gloss-wave_25_333333_500x100.png) 50% 50% repeat-x; + color: #ffffff; + font-weight: bold; +} +.ui-widget-header a { + color: #ffffff; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #666666; + background: #555555 url(images/ui-bg_glass_20_555555_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #eeeeee; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #eeeeee; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #59b4d4; + background: #0078a3 url(images/ui-bg_glass_40_0078a3_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #ffffff; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited { + color: #ffffff; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #ffaf0f; + background: #f58400 url(images/ui-bg_inset-soft_30_f58400_1x100.png) 50% 50% repeat-x; + font-weight: bold; + color: #ffffff; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #ffffff; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #cccccc; + background: #eeeeee url(images/ui-bg_highlight-soft_80_eeeeee_1x100.png) 50% top repeat-x; + color: #2e7db2; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #2e7db2; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #ffb73d; + background: #ffc73d url(images/ui-bg_glass_40_ffc73d_1x400.png) 50% 50% repeat-x; + color: #111111; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #111111; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #111111; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; + background-position: 16px 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url(images/ui-icons_cccccc_256x240.png); +} +.ui-widget-header .ui-icon { + background-image: url(images/ui-icons_ffffff_256x240.png); +} +.ui-state-default .ui-icon { + background-image: url(images/ui-icons_cccccc_256x240.png); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url(images/ui-icons_ffffff_256x240.png); +} +.ui-state-active .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png); +} +.ui-state-highlight .ui-icon { + background-image: url(images/ui-icons_4b8e0b_256x240.png); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url(images/ui-icons_a83300_256x240.png); +} + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 6px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 6px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 6px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 6px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #5c5c5c url(images/ui-bg_flat_50_5c5c5c_40x100.png) 50% 50% repeat-x; + opacity: .8; + filter: Alpha(Opacity=80); +} +.ui-widget-shadow { + margin: -7px 0 0 -7px; + padding: 7px; + background: #cccccc url(images/ui-bg_flat_30_cccccc_40x100.png) 50% 50% repeat-x; + opacity: .6; + filter: Alpha(Opacity=60); + border-radius: 8px; +} diff --git a/dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.min.css b/dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.min.css new file mode 100644 index 000000000..f04ce0771 --- /dev/null +++ b/dashboard/static/css/ui-darkness/jquery-ui-1.10.1.custom.min.css @@ -0,0 +1,5 @@ +/*! jQuery UI - v1.10.1 - 2013-03-04 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Segoe%20UI%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=333333&bgTextureHeader=gloss_wave&bgImgOpacityHeader=25&borderColorHeader=333333&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=000000&bgTextureContent=inset_soft&bgImgOpacityContent=25&borderColorContent=666666&fcContent=ffffff&iconColorContent=cccccc&bgColorDefault=555555&bgTextureDefault=glass&bgImgOpacityDefault=20&borderColorDefault=666666&fcDefault=eeeeee&iconColorDefault=cccccc&bgColorHover=0078a3&bgTextureHover=glass&bgImgOpacityHover=40&borderColorHover=59b4d4&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=f58400&bgTextureActive=inset_soft&bgImgOpacityActive=30&borderColorActive=ffaf0f&fcActive=ffffff&iconColorActive=222222&bgColorHighlight=eeeeee&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=80&borderColorHighlight=cccccc&fcHighlight=2e7db2&iconColorHighlight=4b8e0b&bgColorError=ffc73d&bgTextureError=glass&bgImgOpacityError=40&borderColorError=ffb73d&fcError=111111&iconColorError=a83300&bgColorOverlay=5c5c5c&bgTextureOverlay=flat&bgImgOpacityOverlay=50&opacityOverlay=80&bgColorShadow=cccccc&bgTextureShadow=flat&bgImgOpacityShadow=30&opacityShadow=60&thicknessShadow=7px&offsetTopShadow=-7px&offsetLeftShadow=-7px&cornerRadiusShadow=8px +* Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:21px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Segoe UI,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Segoe UI,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #666;background:#000 url(images/ui-bg_inset-soft_25_000000_1x100.png) 50% bottom repeat-x;color:#fff}.ui-widget-content a{color:#fff}.ui-widget-header{border:1px solid #333;background:#333 url(images/ui-bg_gloss-wave_25_333333_500x100.png) 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #666;background:#555 url(images/ui-bg_glass_20_555555_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#eee}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#eee;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #59b4d4;background:#0078a3 url(images/ui-bg_glass_40_0078a3_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#fff}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#fff;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #ffaf0f;background:#f58400 url(images/ui-bg_inset-soft_30_f58400_1x100.png) 50% 50% repeat-x;font-weight:bold;color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #ccc;background:#eee url(images/ui-bg_highlight-soft_80_eeeeee_1x100.png) 50% top repeat-x;color:#2e7db2}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#2e7db2}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #ffb73d;background:#ffc73d url(images/ui-bg_glass_40_ffc73d_1x400.png) 50% 50% repeat-x;color:#111}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#111}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#111}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px;background-position:16px 16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(images/ui-icons_cccccc_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_ffffff_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_cccccc_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_ffffff_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_4b8e0b_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_a83300_256x240.png)}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:6px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:6px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:6px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:6px}.ui-widget-overlay{background:#5c5c5c url(images/ui-bg_flat_50_5c5c5c_40x100.png) 50% 50% repeat-x;opacity:.8;filter:Alpha(Opacity=80)}.ui-widget-shadow{margin:-7px 0 0 -7px;padding:7px;background:#ccc url(images/ui-bg_flat_30_cccccc_40x100.png) 50% 50% repeat-x;opacity:.6;filter:Alpha(Opacity=60);border-radius:8px} \ No newline at end of file diff --git a/dashboard/static/demo_page.css b/dashboard/static/demo_page.css new file mode 100644 index 000000000..ba5b2a6c3 --- /dev/null +++ b/dashboard/static/demo_page.css @@ -0,0 +1,122 @@ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * General page setup + */ +#dt_example { + font: 80%/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; + margin: 0; + padding: 0; + color: #333; + background-color: #fff; +} + + +#dt_example #container { + width: 800px; + margin: 30px auto; + padding: 0; +} + + +#dt_example #footer { + margin: 50px auto 0 auto; + padding: 0; +} + +#dt_example #demo { + margin: 30px auto 0 auto; +} + +#dt_example .demo_jui { + margin: 30px auto 0 auto; +} + +#dt_example .big { + font-size: 1.3em; + font-weight: bold; + line-height: 1.6em; + color: #4E6CA3; +} + +#dt_example .spacer { + height: 20px; + clear: both; +} + +#dt_example .clear { + clear: both; +} + +#dt_example pre { + padding: 15px; + background-color: #F5F5F5; + border: 1px solid #CCCCCC; +} + +#dt_example h1 { + margin-top: 2em; + font-size: 1.3em; + font-weight: normal; + line-height: 1.6em; + color: #4E6CA3; + border-bottom: 1px solid #B0BED9; + clear: both; +} + +#dt_example h2 { + font-size: 1.2em; + font-weight: normal; + line-height: 1.6em; + color: #4E6CA3; + clear: both; +} + +#dt_example a { + color: #0063DC; + text-decoration: none; +} + +#dt_example a:hover { + text-decoration: underline; +} + +#dt_example ul { + color: #4E6CA3; +} + +.css_right { + float: right; +} + +.css_left { + float: left; +} + +.demo_links { + float: left; + width: 50%; + margin-bottom: 1em; +} + +#demo_info { + padding: 5px; + border: 1px solid #B0BED9; + height: 100px; + width: 100%; + overflow: auto; +} + +#dt_example code { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 2px 4px !important; + white-space: nowrap; + font-size: 0.9em; + + color: #D14; + background-color: #F7F7F9; + + border: 1px solid #E1E1E8; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} diff --git a/dashboard/static/demo_table.css b/dashboard/static/demo_table.css new file mode 100644 index 000000000..12f352dac --- /dev/null +++ b/dashboard/static/demo_table.css @@ -0,0 +1,577 @@ +/* + * File: demo_table.css + * CVS: $Id$ + * Description: CSS descriptions for DataTables demo pages + * Author: Allan Jardine + * Created: Tue May 12 06:47:22 BST 2009 + * Modified: $Date$ by $Author$ + * Language: CSS + * Project: DataTables + * + * Copyright 2009 Allan Jardine. All Rights Reserved. + * + * *************************************************************************** + * DESCRIPTION + * + * The styles given here are suitable for the demos that are used with the standard DataTables + * distribution (see www.datatables.net). You will most likely wish to modify these styles to + * meet the layout requirements of your site. + * + * Common issues: + * 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is + * no conflict between the two pagination types. If you want to use full_numbers pagination + * ensure that you either have "example_alt_pagination" as a body class name, or better yet, + * modify that selector. + * Note that the path used for Images is relative. All images are by default located in + * ../images/ - relative to this CSS file. + */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables features + */ + +.dataTables_wrapper { + position: relative; + clear: both; + zoom: 1; /* Feeling sorry for IE */ +} + +.dataTables_processing { + position: absolute; + top: 50%; + left: 50%; + width: 250px; + height: 30px; + margin-left: -125px; + margin-top: -15px; + padding: 14px 0 2px 0; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 14px; + background-color: white; +} + +.dataTables_length { + width: 40%; + float: left; +} + +.dataTables_filter { + width: 50%; + float: right; + text-align: right; +} + +.dataTables_info { + width: 60%; + float: left; +} + +.dataTables_paginate { + float: right; + text-align: right; +} + +/* Pagination nested */ +.paginate_disabled_previous, .paginate_enabled_previous, +.paginate_disabled_next, .paginate_enabled_next { + height: 19px; + float: left; + cursor: pointer; + *cursor: hand; + color: #111 !important; +} +.paginate_disabled_previous:hover, .paginate_enabled_previous:hover, +.paginate_disabled_next:hover, .paginate_enabled_next:hover { + text-decoration: none !important; +} +.paginate_disabled_previous:active, .paginate_enabled_previous:active, +.paginate_disabled_next:active, .paginate_enabled_next:active { + outline: none; +} + +.paginate_disabled_previous, +.paginate_disabled_next { + color: #666 !important; +} +.paginate_disabled_previous, .paginate_enabled_previous { + padding-left: 23px; +} +.paginate_disabled_next, .paginate_enabled_next { + padding-right: 23px; + margin-left: 10px; +} + +.paginate_disabled_previous { + background: url('../images/back_disabled.png') no-repeat top left; +} + +.paginate_enabled_previous { + background: url('../images/back_enabled.png') no-repeat top left; +} +.paginate_enabled_previous:hover { + background: url('../images/back_enabled_hover.png') no-repeat top left; +} + +.paginate_disabled_next { + background: url('../images/forward_disabled.png') no-repeat top right; +} + +.paginate_enabled_next { + background: url('../images/forward_enabled.png') no-repeat top right; +} +.paginate_enabled_next:hover { + background: url('../images/forward_enabled_hover.png') no-repeat top right; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables display + */ +table.display { + margin: 0 auto; + clear: both; + width: 100%; + + /* Note Firefox 3.5 and before have a bug with border-collapse + * ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 ) + * border-spacing: 0; is one possible option. Conditional-css.com is + * useful for this kind of thing + * + * Further note IE 6/7 has problems when calculating widths with border width. + * It subtracts one px relative to the other browsers from the first column, and + * adds one to the end... + * + * If you want that effect I'd suggest setting a border-top/left on th/td's and + * then filling in the gaps with other borders. + */ +} + +table.display thead th { + padding: 3px 18px 3px 10px; + border-bottom: 1px solid black; + font-weight: bold; + cursor: pointer; + * cursor: hand; +} + +table.display tfoot th { + padding: 3px 18px 3px 10px; + border-top: 1px solid black; + font-weight: bold; +} + +table.display tr.heading2 td { + border-bottom: 1px solid #aaa; +} + +table.display td { + padding: 3px 10px; +} + +table.display td.center { + text-align: center; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables sorting + */ + +.sorting_asc { + background: url('../images/sort_asc.png') no-repeat center right; +} + +.sorting_desc { + background: url('../images/sort_desc.png') no-repeat center right; +} + +.sorting { + background: url('../images/sort_both.png') no-repeat center right; +} + +.sorting_asc_disabled { + background: url('../images/sort_asc_disabled.png') no-repeat center right; +} + +.sorting_desc_disabled { + background: url('../images/sort_desc_disabled.png') no-repeat center right; +} + +table.display thead th:active, +table.display thead td:active { + outline: none; +} + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables row classes + */ +table.display tr.odd.gradeA { + background-color: #ddffdd; +} + +table.display tr.even.gradeA { + background-color: #eeffee; +} + +table.display tr.odd.gradeC { + background-color: #ddddff; +} + +table.display tr.even.gradeC { + background-color: #eeeeff; +} + +table.display tr.odd.gradeX { + background-color: #ffdddd; +} + +table.display tr.even.gradeX { + background-color: #ffeeee; +} + +table.display tr.odd.gradeU { + background-color: #ddd; +} + +table.display tr.even.gradeU { + background-color: #eee; +} + + +tr.odd { + background-color: #E2E4FF; +} + +tr.even { + background-color: white; +} + + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Misc + */ +.dataTables_scroll { + clear: both; +} + +.dataTables_scrollBody { + *margin-top: -1px; + -webkit-overflow-scrolling: touch; +} + +.top, .bottom { + padding: 15px; + background-color: #F5F5F5; + border: 1px solid #CCCCCC; +} + +.top .dataTables_info { + float: none; +} + +.clear { + clear: both; +} + +.dataTables_empty { + text-align: center; +} + +tfoot input { + margin: 0.5em 0; + width: 100%; + color: #444; +} + +tfoot input.search_init { + color: #999; +} + +td.group { + background-color: #d1cfd0; + border-bottom: 2px solid #A19B9E; + border-top: 2px solid #A19B9E; +} + +td.details { + background-color: #d1cfd0; + border: 2px solid #A19B9E; +} + + +.example_alt_pagination div.dataTables_info { + width: 40%; +} + +.paging_full_numbers { + width: 400px; + height: 22px; + line-height: 22px; +} + +.paging_full_numbers a:active { + outline: none +} + +.paging_full_numbers a:hover { + text-decoration: none; +} + +.paging_full_numbers a.paginate_button, + .paging_full_numbers a.paginate_active { + border: 1px solid #aaa; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + padding: 2px 5px; + margin: 0 3px; + cursor: pointer; + *cursor: hand; + color: #333 !important; +} + +.paging_full_numbers a.paginate_button { + background-color: #ddd; +} + +.paging_full_numbers a.paginate_button:hover { + background-color: #ccc; + text-decoration: none !important; +} + +.paging_full_numbers a.paginate_active { + background-color: #99B3FF; +} + +table.display tr.even.row_selected td { + background-color: #B0BED9; +} + +table.display tr.odd.row_selected td { + background-color: #9FAFD1; +} + + +/* + * Sorting classes for columns + */ +/* For the standard odd/even */ +tr.odd td.sorting_1 { + background-color: #D3D6FF; +} + +tr.odd td.sorting_2 { + background-color: #DADCFF; +} + +tr.odd td.sorting_3 { + background-color: #E0E2FF; +} + +tr.even td.sorting_1 { + background-color: #EAEBFF; +} + +tr.even td.sorting_2 { + background-color: #F2F3FF; +} + +tr.even td.sorting_3 { + background-color: #F9F9FF; +} + + +/* For the Conditional-CSS grading rows */ +/* + Colour calculations (based off the main row colours) + Level 1: + dd > c4 + ee > d5 + Level 2: + dd > d1 + ee > e2 + */ +tr.odd.gradeA td.sorting_1 { + background-color: #c4ffc4; +} + +tr.odd.gradeA td.sorting_2 { + background-color: #d1ffd1; +} + +tr.odd.gradeA td.sorting_3 { + background-color: #d1ffd1; +} + +tr.even.gradeA td.sorting_1 { + background-color: #d5ffd5; +} + +tr.even.gradeA td.sorting_2 { + background-color: #e2ffe2; +} + +tr.even.gradeA td.sorting_3 { + background-color: #e2ffe2; +} + +tr.odd.gradeC td.sorting_1 { + background-color: #c4c4ff; +} + +tr.odd.gradeC td.sorting_2 { + background-color: #d1d1ff; +} + +tr.odd.gradeC td.sorting_3 { + background-color: #d1d1ff; +} + +tr.even.gradeC td.sorting_1 { + background-color: #d5d5ff; +} + +tr.even.gradeC td.sorting_2 { + background-color: #e2e2ff; +} + +tr.even.gradeC td.sorting_3 { + background-color: #e2e2ff; +} + +tr.odd.gradeX td.sorting_1 { + background-color: #ffc4c4; +} + +tr.odd.gradeX td.sorting_2 { + background-color: #ffd1d1; +} + +tr.odd.gradeX td.sorting_3 { + background-color: #ffd1d1; +} + +tr.even.gradeX td.sorting_1 { + background-color: #ffd5d5; +} + +tr.even.gradeX td.sorting_2 { + background-color: #ffe2e2; +} + +tr.even.gradeX td.sorting_3 { + background-color: #ffe2e2; +} + +tr.odd.gradeU td.sorting_1 { + background-color: #c4c4c4; +} + +tr.odd.gradeU td.sorting_2 { + background-color: #d1d1d1; +} + +tr.odd.gradeU td.sorting_3 { + background-color: #d1d1d1; +} + +tr.even.gradeU td.sorting_1 { + background-color: #d5d5d5; +} + +tr.even.gradeU td.sorting_2 { + background-color: #e2e2e2; +} + +tr.even.gradeU td.sorting_3 { + background-color: #e2e2e2; +} + + +/* + * Row highlighting example + */ +.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted { + background-color: #ECFFB3; +} + +.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted { + background-color: #E6FF99; +} + +.ex_highlight_row #example tr.even:hover { + background-color: #ECFFB3; +} + +.ex_highlight_row #example tr.even:hover td.sorting_1 { + background-color: #DDFF75; +} + +.ex_highlight_row #example tr.even:hover td.sorting_2 { + background-color: #E7FF9E; +} + +.ex_highlight_row #example tr.even:hover td.sorting_3 { + background-color: #E2FF89; +} + +.ex_highlight_row #example tr.odd:hover { + background-color: #E6FF99; +} + +.ex_highlight_row #example tr.odd:hover td.sorting_1 { + background-color: #D6FF5C; +} + +.ex_highlight_row #example tr.odd:hover td.sorting_2 { + background-color: #E0FF84; +} + +.ex_highlight_row #example tr.odd:hover td.sorting_3 { + background-color: #DBFF70; +} + + +/* + * KeyTable + */ +table.KeyTable td { + border: 3px solid transparent; +} + +table.KeyTable td.focus { + border: 3px solid #3366FF; +} + +table.display tr.gradeA { + background-color: #eeffee; +} + +table.display tr.gradeC { + background-color: #ddddff; +} + +table.display tr.gradeX { + background-color: #ffdddd; +} + +table.display tr.gradeU { + background-color: #ddd; +} + +div.box { + height: 100px; + padding: 10px; + overflow: auto; + border: 1px solid #8080FF; + background-color: #E5E5FF; +} diff --git a/dashboard/static/demo_table_jui.css b/dashboard/static/demo_table_jui.css new file mode 100644 index 000000000..a210af51a --- /dev/null +++ b/dashboard/static/demo_table_jui.css @@ -0,0 +1,501 @@ +/* + * File: demo_table_jui.css + * CVS: $Id$ + * Description: CSS descriptions for DataTables demo pages + * Author: Allan Jardine + * Created: Tue May 12 06:47:22 BST 2009 + * Modified: $Date$ by $Author$ + * Language: CSS + * Project: DataTables + * + * Copyright 2009 Allan Jardine. All Rights Reserved. + * + * *************************************************************************** + * DESCRIPTION + * + * The styles given here are suitable for the demos that are used with the standard DataTables + * distribution (see www.datatables.net). You will most likely wish to modify these styles to + * meet the layout requirements of your site. + * + * Common issues: + * 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is + * no conflict between the two pagination types. If you want to use full_numbers pagination + * ensure that you either have "example_alt_pagination" as a body class name, or better yet, + * modify that selector. + * Note that the path used for Images is relative. All images are by default located in + * ../images/ - relative to this CSS file. + */ + + +/* + * jQuery UI specific styling + */ + +.paging_two_button .ui-button { + float: left; + cursor: pointer; + * cursor: hand; +} + +.paging_full_numbers .ui-button { + padding: 2px 6px; + margin: 0; + cursor: pointer; + * cursor: hand; + color: #333 !important; +} + +.dataTables_paginate .ui-button { + margin-right: -0.1em !important; +} + +.paging_full_numbers { + width: 350px !important; +} + +.dataTables_wrapper .ui-toolbar { + padding: 5px; +} + +.dataTables_paginate { + width: auto; +} + +.dataTables_info { + padding-top: 3px; +} + +table.display thead th { + padding: 3px 0px 3px 10px; + cursor: pointer; + * cursor: hand; +} + +div.dataTables_wrapper .ui-widget-header { + font-weight: normal; +} + + +/* + * Sort arrow icon positioning + */ +table.display thead th div.DataTables_sort_wrapper { + position: relative; + padding-right: 20px; +} + +table.display thead th div.DataTables_sort_wrapper span { + position: absolute; + top: 50%; + margin-top: -8px; + right: 0; +} + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Everything below this line is the same as demo_table.css. This file is + * required for 'cleanliness' of the markup + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables features + */ + +.dataTables_wrapper { + position: relative; + clear: both; +} + +.dataTables_processing { + position: absolute; + top: 0px; + left: 50%; + width: 250px; + margin-left: -125px; + border: 1px solid #ddd; + text-align: center; + color: #999; + font-size: 11px; + padding: 2px 0; +} + +.dataTables_length { + width: 40%; + float: left; +} + +.dataTables_filter { + width: 50%; + float: right; + text-align: right; +} + +.dataTables_info { + width: 50%; + float: left; +} + +.dataTables_paginate { + float: right; + text-align: right; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables display + */ +table.display { + margin: 0 auto; + width: 100%; + clear: both; + border-collapse: collapse; +} + +table.display tfoot th { + padding: 3px 0px 3px 10px; + font-weight: bold; + font-weight: normal; +} + +table.display tr.heading2 td { + border-bottom: 1px solid #aaa; +} + +table.display td { + padding: 3px 10px; +} + +table.display td.center { + text-align: center; +} + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables sorting + */ + +.sorting_asc { + background: url('../images/sort_asc.png') no-repeat center right; +} + +.sorting_desc { + background: url('../images/sort_desc.png') no-repeat center right; +} + +.sorting { + background: url('../images/sort_both.png') no-repeat center right; +} + +.sorting_asc_disabled { + background: url('../images/sort_asc_disabled.png') no-repeat center right; +} + +.sorting_desc_disabled { + background: url('../images/sort_desc_disabled.png') no-repeat center right; +} + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * DataTables row classes + */ +table.display tr.odd.gradeA { + background-color: #ddffdd; +} + +table.display tr.even.gradeA { + background-color: #eeffee; +} + + + + +table.display tr.odd.gradeA { + background-color: #ddffdd; +} + +table.display tr.even.gradeA { + background-color: #eeffee; +} + +table.display tr.odd.gradeC { + background-color: #ddddff; +} + +table.display tr.even.gradeC { + background-color: #eeeeff; +} + +table.display tr.odd.gradeX { + background-color: #ffdddd; +} + +table.display tr.even.gradeX { + background-color: #ffeeee; +} + +table.display tr.odd.gradeU { + background-color: #ddd; +} + +table.display tr.even.gradeU { + background-color: #eee; +} + + +tr.odd { + background-color: #E2E4FF; +} + +tr.even { + background-color: white; +} + + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Misc + */ +.dataTables_scroll { + clear: both; +} + +.dataTables_scrollBody { + -webkit-overflow-scrolling: touch; +} + +.top, .bottom { + padding: 15px; + background-color: #F5F5F5; + border: 1px solid #CCCCCC; +} + +.top .dataTables_info { + float: none; +} + +.clear { + clear: both; +} + +.dataTables_empty { + text-align: center; +} + +tfoot input { + margin: 0.5em 0; + width: 100%; + color: #444; +} + +tfoot input.search_init { + color: #999; +} + +td.group { + background-color: #d1cfd0; + border-bottom: 2px solid #A19B9E; + border-top: 2px solid #A19B9E; +} + +td.details { + background-color: #d1cfd0; + border: 2px solid #A19B9E; +} + + +.example_alt_pagination div.dataTables_info { + width: 40%; +} + +.paging_full_numbers a.paginate_button, + .paging_full_numbers a.paginate_active { + border: 1px solid #aaa; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + padding: 2px 5px; + margin: 0 3px; + cursor: pointer; + *cursor: hand; + color: #333 !important; +} + +.paging_full_numbers a.paginate_button { + background-color: #ddd; +} + +.paging_full_numbers a.paginate_button:hover { + background-color: #ccc; + text-decoration: none !important; +} + +.paging_full_numbers a.paginate_active { + background-color: #99B3FF; +} + +table.display tr.even.row_selected td { + background-color: #B0BED9; +} + +table.display tr.odd.row_selected td { + background-color: #9FAFD1; +} + + +/* + * Sorting classes for columns + */ +/* For the standard odd/even */ +tr.odd td.sorting_1 { + background-color: #D3D6FF; +} + +tr.odd td.sorting_2 { + background-color: #DADCFF; +} + +tr.odd td.sorting_3 { + background-color: #E0E2FF; +} + +tr.even td.sorting_1 { + background-color: #EAEBFF; +} + +tr.even td.sorting_2 { + background-color: #F2F3FF; +} + +tr.even td.sorting_3 { + background-color: #F9F9FF; +} + + +/* For the Conditional-CSS grading rows */ +/* + Colour calculations (based off the main row colours) + Level 1: + dd > c4 + ee > d5 + Level 2: + dd > d1 + ee > e2 + */ +tr.odd.gradeA td.sorting_1 { + background-color: #c4ffc4; +} + +tr.odd.gradeA td.sorting_2 { + background-color: #d1ffd1; +} + +tr.odd.gradeA td.sorting_3 { + background-color: #d1ffd1; +} + +tr.even.gradeA td.sorting_1 { + background-color: #d5ffd5; +} + +tr.even.gradeA td.sorting_2 { + background-color: #e2ffe2; +} + +tr.even.gradeA td.sorting_3 { + background-color: #e2ffe2; +} + +tr.odd.gradeC td.sorting_1 { + background-color: #c4c4ff; +} + +tr.odd.gradeC td.sorting_2 { + background-color: #d1d1ff; +} + +tr.odd.gradeC td.sorting_3 { + background-color: #d1d1ff; +} + +tr.even.gradeC td.sorting_1 { + background-color: #d5d5ff; +} + +tr.even.gradeC td.sorting_2 { + background-color: #e2e2ff; +} + +tr.even.gradeC td.sorting_3 { + background-color: #e2e2ff; +} + +tr.odd.gradeX td.sorting_1 { + background-color: #ffc4c4; +} + +tr.odd.gradeX td.sorting_2 { + background-color: #ffd1d1; +} + +tr.odd.gradeX td.sorting_3 { + background-color: #ffd1d1; +} + +tr.even.gradeX td.sorting_1 { + background-color: #ffd5d5; +} + +tr.even.gradeX td.sorting_2 { + background-color: #ffe2e2; +} + +tr.even.gradeX td.sorting_3 { + background-color: #ffe2e2; +} + +tr.odd.gradeU td.sorting_1 { + background-color: #c4c4c4; +} + +tr.odd.gradeU td.sorting_2 { + background-color: #d1d1d1; +} + +tr.odd.gradeU td.sorting_3 { + background-color: #d1d1d1; +} + +tr.even.gradeU td.sorting_1 { + background-color: #d5d5d5; +} + +tr.even.gradeU td.sorting_2 { + background-color: #e2e2e2; +} + +tr.even.gradeU td.sorting_3 { + background-color: #e2e2e2; +} + + +/* + * Row highlighting example + */ +.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted { + background-color: #ECFFB3; +} + +.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted { + background-color: #E6FF99; +} \ No newline at end of file diff --git a/dashboard/static/images/back_disabled.png b/dashboard/static/images/back_disabled.png new file mode 100644 index 000000000..881de7976 Binary files /dev/null and b/dashboard/static/images/back_disabled.png differ diff --git a/dashboard/static/images/back_enabled.png b/dashboard/static/images/back_enabled.png new file mode 100644 index 000000000..c608682b0 Binary files /dev/null and b/dashboard/static/images/back_enabled.png differ diff --git a/dashboard/static/images/back_enabled_hover.png b/dashboard/static/images/back_enabled_hover.png new file mode 100644 index 000000000..d300f1064 Binary files /dev/null and b/dashboard/static/images/back_enabled_hover.png differ diff --git a/dashboard/static/images/footer_tile.jpg b/dashboard/static/images/footer_tile.jpg new file mode 100644 index 000000000..577137b04 Binary files /dev/null and b/dashboard/static/images/footer_tile.jpg differ diff --git a/dashboard/static/images/forward_disabled.png b/dashboard/static/images/forward_disabled.png new file mode 100644 index 000000000..6a6ded7de Binary files /dev/null and b/dashboard/static/images/forward_disabled.png differ diff --git a/dashboard/static/images/forward_enabled.png b/dashboard/static/images/forward_enabled.png new file mode 100644 index 000000000..a4e6b5384 Binary files /dev/null and b/dashboard/static/images/forward_enabled.png differ diff --git a/dashboard/static/images/forward_enabled_hover.png b/dashboard/static/images/forward_enabled_hover.png new file mode 100644 index 000000000..fc46c5ebf Binary files /dev/null and b/dashboard/static/images/forward_enabled_hover.png differ diff --git a/dashboard/static/images/mirantis_logo.gif b/dashboard/static/images/mirantis_logo.gif new file mode 100644 index 000000000..4811c18b5 Binary files /dev/null and b/dashboard/static/images/mirantis_logo.gif differ diff --git a/dashboard/static/images/noise_lightblue.jpg b/dashboard/static/images/noise_lightblue.jpg new file mode 100644 index 000000000..45ca62d2b Binary files /dev/null and b/dashboard/static/images/noise_lightblue.jpg differ diff --git a/dashboard/static/images/noise_lightgray.jpg b/dashboard/static/images/noise_lightgray.jpg new file mode 100644 index 000000000..4b6936b12 Binary files /dev/null and b/dashboard/static/images/noise_lightgray.jpg differ diff --git a/dashboard/static/images/osstats_tile.jpg b/dashboard/static/images/osstats_tile.jpg new file mode 100644 index 000000000..016bc32be Binary files /dev/null and b/dashboard/static/images/osstats_tile.jpg differ diff --git a/dashboard/static/images/sort_asc.png b/dashboard/static/images/sort_asc.png new file mode 100644 index 000000000..a88d7975f Binary files /dev/null and b/dashboard/static/images/sort_asc.png differ diff --git a/dashboard/static/images/sort_asc_disabled.png b/dashboard/static/images/sort_asc_disabled.png new file mode 100644 index 000000000..4e144cf0b Binary files /dev/null and b/dashboard/static/images/sort_asc_disabled.png differ diff --git a/dashboard/static/images/sort_both.png b/dashboard/static/images/sort_both.png new file mode 100644 index 000000000..18670406b Binary files /dev/null and b/dashboard/static/images/sort_both.png differ diff --git a/dashboard/static/images/sort_desc.png b/dashboard/static/images/sort_desc.png new file mode 100644 index 000000000..def071ed5 Binary files /dev/null and b/dashboard/static/images/sort_desc.png differ diff --git a/dashboard/static/images/sort_desc_disabled.png b/dashboard/static/images/sort_desc_disabled.png new file mode 100644 index 000000000..7824973cc Binary files /dev/null and b/dashboard/static/images/sort_desc_disabled.png differ diff --git a/dashboard/static/jquery.dataTables.js b/dashboard/static/jquery.dataTables.js new file mode 100644 index 000000000..1d8a220ba --- /dev/null +++ b/dashboard/static/jquery.dataTables.js @@ -0,0 +1,12099 @@ +/** + * @summary DataTables + * @description Paginate, search and sort HTML tables + * @version 1.9.4 + * @file jquery.dataTables.js + * @author Allan Jardine (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * + * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd + * + * This source file 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 license files for details. + * + * For details please refer to: http://www.datatables.net + */ + +/*jslint evil: true, undef: true, browser: true */ +/*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns*/ + +(/** @lends */function( window, document, undefined ) { + +(function( factory ) { + "use strict"; + + // Define as an AMD module if possible + if ( typeof define === 'function' && define.amd ) + { + define( ['jquery'], factory ); + } + /* Define using browser globals otherwise + * Prevent multiple instantiations if the script is loaded twice + */ + else if ( jQuery && !jQuery.fn.dataTable ) + { + factory( jQuery ); + } +} +(/** @lends */function( $ ) { + "use strict"; + /** + * DataTables is a plug-in for the jQuery Javascript library. It is a + * highly flexible tool, based upon the foundations of progressive + * enhancement, which will add advanced interaction controls to any + * HTML table. For a full list of features please refer to + * DataTables.net. + * + * Note that the DataTable object is not a global variable but is + * aliased to jQuery.fn.DataTable and jQuery.fn.dataTable through which + * it may be accessed. + * + * @class + * @param {object} [oInit={}] Configuration object for DataTables. Options + * are defined by {@link DataTable.defaults} + * @requires jQuery 1.3+ + * + * @example + * // Basic initialisation + * $(document).ready( function { + * $('#example').dataTable(); + * } ); + * + * @example + * // Initialisation with configuration options - in this case, disable + * // pagination and sorting. + * $(document).ready( function { + * $('#example').dataTable( { + * "bPaginate": false, + * "bSort": false + * } ); + * } ); + */ + var DataTable = function( oInit ) + { + + + /** + * Add a column to the list used for the table with default values + * @param {object} oSettings dataTables settings object + * @param {node} nTh The th element for this column + * @memberof DataTable#oApi + */ + function _fnAddColumn( oSettings, nTh ) + { + var oDefaults = DataTable.defaults.columns; + var iCol = oSettings.aoColumns.length; + var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { + "sSortingClass": oSettings.oClasses.sSortable, + "sSortingClassJUI": oSettings.oClasses.sSortJUI, + "nTh": nTh ? nTh : document.createElement('th'), + "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', + "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], + "mData": oDefaults.mData ? oDefaults.oDefaults : iCol + } ); + oSettings.aoColumns.push( oCol ); + + /* Add a column specific filter */ + if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null ) + { + oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch ); + } + else + { + var oPre = oSettings.aoPreSearchCols[ iCol ]; + + /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */ + if ( oPre.bRegex === undefined ) + { + oPre.bRegex = true; + } + + if ( oPre.bSmart === undefined ) + { + oPre.bSmart = true; + } + + if ( oPre.bCaseInsensitive === undefined ) + { + oPre.bCaseInsensitive = true; + } + } + + /* Use the column options function to initialise classes etc */ + _fnColumnOptions( oSettings, iCol, null ); + } + + + /** + * Apply options for a column + * @param {object} oSettings dataTables settings object + * @param {int} iCol column index to consider + * @param {object} oOptions object with sType, bVisible and bSearchable etc + * @memberof DataTable#oApi + */ + function _fnColumnOptions( oSettings, iCol, oOptions ) + { + var oCol = oSettings.aoColumns[ iCol ]; + + /* User specified column options */ + if ( oOptions !== undefined && oOptions !== null ) + { + /* Backwards compatibility for mDataProp */ + if ( oOptions.mDataProp && !oOptions.mData ) + { + oOptions.mData = oOptions.mDataProp; + } + + if ( oOptions.sType !== undefined ) + { + oCol.sType = oOptions.sType; + oCol._bAutoType = false; + } + + $.extend( oCol, oOptions ); + _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); + + /* iDataSort to be applied (backwards compatibility), but aDataSort will take + * priority if defined + */ + if ( oOptions.iDataSort !== undefined ) + { + oCol.aDataSort = [ oOptions.iDataSort ]; + } + _fnMap( oCol, oOptions, "aDataSort" ); + } + + /* Cache the data get and set functions for speed */ + var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; + var mData = _fnGetObjectDataFn( oCol.mData ); + + oCol.fnGetData = function (oData, sSpecific) { + var innerData = mData( oData, sSpecific ); + + if ( oCol.mRender && (sSpecific && sSpecific !== '') ) + { + return mRender( innerData, sSpecific, oData ); + } + return innerData; + }; + oCol.fnSetData = _fnSetObjectDataFn( oCol.mData ); + + /* Feature sorting overrides column specific when off */ + if ( !oSettings.oFeatures.bSort ) + { + oCol.bSortable = false; + } + + /* Check that the class assignment is correct for sorting */ + if ( !oCol.bSortable || + ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) ) + { + oCol.sSortingClass = oSettings.oClasses.sSortableNone; + oCol.sSortingClassJUI = ""; + } + else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 ) + { + oCol.sSortingClass = oSettings.oClasses.sSortable; + oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI; + } + else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 ) + { + oCol.sSortingClass = oSettings.oClasses.sSortableAsc; + oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed; + } + else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 ) + { + oCol.sSortingClass = oSettings.oClasses.sSortableDesc; + oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed; + } + } + + + /** + * Adjust the table column widths for new data. Note: you would probably want to + * do a redraw after calling this function! + * @param {object} oSettings dataTables settings object + * @memberof DataTable#oApi + */ + function _fnAdjustColumnSizing ( oSettings ) + { + /* Not interested in doing column width calculation if auto-width is disabled */ + if ( oSettings.oFeatures.bAutoWidth === false ) + { + return false; + } + + _fnCalculateColumnWidths( oSettings ); + for ( var i=0 , iLen=oSettings.aoColumns.length ; i