├── .bowerrc
├── .gitignore
├── Gruntfile.js
├── LICENSE
├── README.md
├── TODO.md
├── WebContent
├── app-built.html
├── app.html
├── css
│ ├── bootstrap
│ │ ├── accordion.less
│ │ ├── alerts.less
│ │ ├── bootstrap.less
│ │ ├── breadcrumbs.less
│ │ ├── button-groups.less
│ │ ├── buttons-custom.less
│ │ ├── buttons.less
│ │ ├── carousel.less
│ │ ├── close.less
│ │ ├── code.less
│ │ ├── component-animations.less
│ │ ├── dropdowns.less
│ │ ├── forms.less
│ │ ├── grid.less
│ │ ├── hero-unit.less
│ │ ├── labels-badges.less
│ │ ├── layouts.less
│ │ ├── media.less
│ │ ├── mixins.less
│ │ ├── modals.less
│ │ ├── navbar.less
│ │ ├── navs.less
│ │ ├── pager.less
│ │ ├── pagination.less
│ │ ├── popovers.less
│ │ ├── progress-bars.less
│ │ ├── reset.less
│ │ ├── responsive-1200px-min.less
│ │ ├── responsive-767px-max.less
│ │ ├── responsive-768px-979px.less
│ │ ├── responsive-navbar.less
│ │ ├── responsive-utilities.less
│ │ ├── responsive.less
│ │ ├── scaffolding.less
│ │ ├── sprites.less
│ │ ├── tables.less
│ │ ├── thumbnails.less
│ │ ├── tooltip.less
│ │ ├── type.less
│ │ ├── utilities.less
│ │ ├── variables.less
│ │ └── wells.less
│ ├── custom
│ │ ├── overrides.less
│ │ ├── sprites.less
│ │ ├── style-BAK1.less
│ │ ├── style.less
│ │ └── variables.less
│ ├── ie8.css
│ ├── images
│ │ ├── activity-spinner-16-combined.gif
│ │ ├── bitmap16-white.png
│ │ ├── bitmap16.png
│ │ ├── bitmap40-linkColor.png
│ │ ├── bitmap40-linkColorHover.png
│ │ ├── bitmap40-white.png
│ │ ├── bitmap40.png
│ │ ├── glyphicons-halflings-white.png
│ │ ├── glyphicons-halflings.png
│ │ ├── loading.gif
│ │ ├── x_x5F_alt18.png
│ │ └── x_x5F_alt23.png
│ ├── jquery.qtip-2.0.1-108.css
│ ├── jquery.qtip-2.0.1-57.css
│ ├── ng-grid.css
│ └── style.less
└── scripts
│ ├── app
│ ├── constants.js
│ ├── main
│ │ ├── main.js
│ │ ├── navbar.html
│ │ └── navbarCtrl.js
│ ├── modules
│ │ ├── categories
│ │ │ ├── categoriesCtrl.js
│ │ │ ├── categoriesTemplate.html
│ │ │ ├── categoryDirective.js
│ │ │ ├── categoryTemplate.html
│ │ │ ├── deleteTemplate.html
│ │ │ ├── main.js
│ │ │ └── main.metadata.json
│ │ ├── expenses
│ │ │ ├── chartPopup.tpl.html
│ │ │ ├── chartPopupModule.js
│ │ │ ├── chartPopupService.js
│ │ │ ├── expensesCtrl.js
│ │ │ ├── expensesTemplate.html
│ │ │ ├── main.js
│ │ │ ├── main.metadata.json
│ │ │ └── pieChartDirective.js
│ │ └── index
│ │ │ ├── indexCtrl.js
│ │ │ ├── indexTemplate.html
│ │ │ ├── main.js
│ │ │ └── main.metadata.json
│ └── shared
│ │ ├── dao
│ │ ├── categoriesDao.js
│ │ ├── expensesDao.js
│ │ └── userDao.js
│ │ └── model
│ │ └── Expense.js
│ ├── empty.js
│ ├── globals.js
│ ├── lib
│ ├── Chart.js
│ └── lazyload.js
│ ├── require-cfg.js
│ └── util
│ ├── lib
│ └── angular-require-lazy
│ │ ├── bootstrap.js
│ │ ├── currentModule.js
│ │ ├── lazyAngularUtils.js
│ │ ├── ngLazy.js
│ │ ├── promiseAdaptorAngular.js
│ │ ├── routeConfig.js
│ │ ├── templateCache.js
│ │ ├── templateCacheBuilder.js
│ │ └── util.js
│ ├── loginPrompt.html
│ ├── loginPrompt.js
│ ├── menuEntries.js
│ ├── modalTemplates.js
│ ├── resourceUtils.js
│ ├── returnService.js
│ ├── urlUtils.js
│ └── viewUtils.js
├── WebTests
└── scripts
│ ├── app
│ ├── modules
│ │ └── categories
│ │ │ └── categoryDirective.spec.js
│ └── shared
│ │ └── dao
│ │ └── expensesDao.spec.js
│ ├── mocks
│ ├── app
│ │ └── shared
│ │ │ └── dao
│ │ │ └── categoriesDao.js
│ ├── lazy-registry.js
│ ├── require-cfg.js
│ └── test-main.js
│ └── test-main.js
├── app.js
├── bower.json
├── build-scripts
├── app.build-grunt.json
├── discoverModules.js
├── grunt
│ └── grunt.js
├── karma
│ ├── index.js
│ ├── preInstrumentedPreprocessor.js
│ └── reporter.js
└── options-grunt.js
├── build-stats
├── .gitignore
├── amd.html
├── bundles.html
├── deps.html
├── f.js
├── index.html
├── modules.html
└── stats.js
├── karma-coverage.conf.js
├── karma.conf.js
├── package.json
└── sonar-project.properties
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "WebContent/scripts/lib",
3 | "json": "bower.json"
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .directory
2 | node_modules/*
3 | WebContent/scripts/lib/*
4 | !WebContent/scripts/lib/lazyload.js
5 | !WebContent/scripts/lib/Chart.js
6 | build/*
7 | /build-coverage/*
8 | /.sonar/
9 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | var options = require("./build-scripts/options-grunt.js"),
3 | config = require("./build-scripts/app.build-grunt.json");
4 |
5 | grunt.initConfig({
6 | instrument: {
7 | sources: {
8 | files: [{
9 | expand: true,
10 | cwd: "WebContent/",
11 | src: ["scripts/app/**/*.js", "scripts/util/**/*.js"],
12 | dest: "build-coverage/instrumented"
13 | }],
14 | options: {
15 | baseline: "build-coverage/baseline.json"
16 | }
17 | }
18 | },
19 | copy: {
20 | images: {
21 | expand: true,
22 | cwd: "WebContent/css/",
23 | src: ["images/**"],
24 | dest: "build/css/"
25 | }
26 | },
27 | less: {
28 | compile: {
29 | options: {
30 | yuicompress: true
31 | },
32 | files: {
33 | "build/css/css/style.css": "WebContent/css/style.less"
34 | }
35 | }
36 | },
37 | require_lazy_grunt: {
38 | options: {
39 | buildOptions: options,
40 | config: config,
41 | callback: function(modules, pmresult) {
42 | // This callback is optional; included here just for demonstration purposes.
43 | var fs = require("fs"), util = require("util"), path = require("path");
44 | fs.writeFileSync(path.join(options.outputBaseDir+"-stats", "modules.js"), "angular.module(\"app\").value(\"modules\"," + util.inspect(modules,{depth:null,colors:false}) + ");");
45 | fs.writeFileSync(path.join(options.outputBaseDir+"-stats", "bundles.js"), "angular.module(\"app\").value(\"bundles\"," + util.inspect(pmresult.bundles,{depth:null,colors:false}) + ");");
46 | }
47 | }
48 | },
49 | karma: {
50 | options: {
51 | configFile: "karma.conf.js"
52 | },
53 | single: {
54 | singleRun: true,
55 | reporters: "dots"
56 | },
57 | coverage: {
58 | singleRun: true,
59 | configFile: "karma-coverage.conf.js"
60 | }
61 | },
62 | clean: ["build/*","build-coverage/*"]
63 | });
64 |
65 | grunt.loadNpmTasks("grunt-contrib-copy");
66 | grunt.loadNpmTasks("grunt-contrib-less");
67 | grunt.loadNpmTasks("require-lazy-grunt");
68 | grunt.loadNpmTasks("grunt-contrib-clean");
69 | grunt.loadNpmTasks("grunt-karma");
70 | grunt.loadTasks("build-scripts/grunt");
71 |
72 | grunt.registerTask("default", ["less:compile","copy:images","require_lazy_grunt"]);
73 | grunt.registerTask("test", ["karma:single"]);
74 | grunt.registerTask("coverage", ["instrument","karma:coverage"]);
75 | };
76 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Nikos Paraskevopoulos
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | - Write the "How To Configure a Project With angular-require-lazy" guide
2 | - Investigate the implementation of routeConfig in terms of ngLazy
3 |
--------------------------------------------------------------------------------
/WebContent/app-built.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Expenses
6 |
7 |
8 |
9 |
12 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/WebContent/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Expenses
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/accordion.less:
--------------------------------------------------------------------------------
1 | //
2 | // Accordion
3 | // --------------------------------------------------
4 |
5 |
6 | // Parent container
7 | .accordion {
8 | margin-bottom: @baseLineHeight;
9 | }
10 |
11 | // Group == heading + body
12 | .accordion-group {
13 | margin-bottom: 2px;
14 | border: 1px solid #e5e5e5;
15 | .border-radius(@baseBorderRadius);
16 | }
17 | .accordion-heading {
18 | border-bottom: 0;
19 | }
20 | .accordion-heading .accordion-toggle {
21 | display: block;
22 | padding: 8px 15px;
23 | }
24 |
25 | // General toggle styles
26 | .accordion-toggle {
27 | cursor: pointer;
28 | }
29 |
30 | // Inner needs the styles because you can't animate properly with any styles on the element
31 | .accordion-inner {
32 | padding: 9px 15px;
33 | border-top: 1px solid #e5e5e5;
34 | }
35 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/alerts.less:
--------------------------------------------------------------------------------
1 | //
2 | // Alerts
3 | // --------------------------------------------------
4 |
5 |
6 | // Base styles
7 | // -------------------------
8 |
9 | .alert {
10 | padding: 8px 35px 8px 14px;
11 | margin-bottom: @baseLineHeight;
12 | text-shadow: 0 1px 0 rgba(255,255,255,.5);
13 | background-color: @warningBackground;
14 | border: 1px solid @warningBorder;
15 | .border-radius(@baseBorderRadius);
16 | }
17 | .alert,
18 | .alert h4 {
19 | // Specified for the h4 to prevent conflicts of changing @headingsColor
20 | color: @warningText;
21 | }
22 | .alert h4 {
23 | margin: 0;
24 | }
25 |
26 | // Adjust close link position
27 | .alert .close {
28 | position: relative;
29 | top: -2px;
30 | right: -21px;
31 | line-height: @baseLineHeight;
32 | }
33 |
34 |
35 | // Alternate styles
36 | // -------------------------
37 |
38 | .alert-success {
39 | background-color: @successBackground;
40 | border-color: @successBorder;
41 | color: @successText;
42 | }
43 | .alert-success h4 {
44 | color: @successText;
45 | }
46 | .alert-danger,
47 | .alert-error {
48 | background-color: @errorBackground;
49 | border-color: @errorBorder;
50 | color: @errorText;
51 | }
52 | .alert-danger h4,
53 | .alert-error h4 {
54 | color: @errorText;
55 | }
56 | .alert-info {
57 | background-color: @infoBackground;
58 | border-color: @infoBorder;
59 | color: @infoText;
60 | }
61 | .alert-info h4 {
62 | color: @infoText;
63 | }
64 |
65 |
66 | // Block alerts
67 | // -------------------------
68 |
69 | .alert-block {
70 | padding-top: 14px;
71 | padding-bottom: 14px;
72 | }
73 | .alert-block > p,
74 | .alert-block > ul {
75 | margin-bottom: 0;
76 | }
77 | .alert-block p + p {
78 | margin-top: 5px;
79 | }
80 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/bootstrap.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v2.3.1
3 | *
4 | * Copyright 2012 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world @twitter by @mdo and @fat.
9 | */
10 |
11 | // Core variables and mixins
12 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc
13 | @import "mixins.less";
14 |
15 | // CSS Reset
16 | @import "reset.less";
17 |
18 | // Grid system and page structure
19 | @import "scaffolding.less";
20 | @import "grid.less";
21 | @import "layouts.less";
22 |
23 | // Base CSS
24 | @import "type.less";
25 | //@import "code.less";
26 | @import "forms.less";
27 | //@import "tables.less";
28 |
29 | // Components: common
30 | //@import "sprites.less";
31 | //@import "dropdowns.less";
32 | //@import "wells.less";
33 | @import "component-animations.less";
34 | //@import "close.less";
35 |
36 | // Components: Buttons & Alerts
37 | @import "buttons.less";
38 | //@import "button-groups.less";
39 | //@import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less
40 |
41 | // Components: Nav
42 | @import "navs.less";
43 | @import "navbar.less";
44 | //@import "breadcrumbs.less";
45 | //@import "pagination.less";
46 | //@import "pager.less";
47 |
48 | // Components: Popovers
49 | @import "modals.less";
50 | //@import "tooltip.less";
51 | //@import "popovers.less";
52 |
53 | // Components: Misc
54 | //@import "thumbnails.less";
55 | //@import "media.less";
56 | //@import "labels-badges.less";
57 | //@import "progress-bars.less";
58 | //@import "accordion.less";
59 | //@import "carousel.less";
60 | //@import "hero-unit.less";
61 |
62 | // Utility classes
63 | @import "utilities.less"; // Has to be last to override when necessary
64 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/breadcrumbs.less:
--------------------------------------------------------------------------------
1 | //
2 | // Breadcrumbs
3 | // --------------------------------------------------
4 |
5 |
6 | .breadcrumb {
7 | padding: 8px 15px;
8 | margin: 0 0 @baseLineHeight;
9 | list-style: none;
10 | background-color: #f5f5f5;
11 | .border-radius(@baseBorderRadius);
12 | > li {
13 | display: inline-block;
14 | .ie7-inline-block();
15 | text-shadow: 0 1px 0 @white;
16 | > .divider {
17 | padding: 0 5px;
18 | color: #ccc;
19 | }
20 | }
21 | > .active {
22 | color: @grayLight;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/button-groups.less:
--------------------------------------------------------------------------------
1 | //
2 | // Button groups
3 | // --------------------------------------------------
4 |
5 |
6 | // Make the div behave like a button
7 | .btn-group {
8 | position: relative;
9 | display: inline-block;
10 | .ie7-inline-block();
11 | font-size: 0; // remove as part 1 of font-size inline-block hack
12 | vertical-align: middle; // match .btn alignment given font-size hack above
13 | white-space: nowrap; // prevent buttons from wrapping when in tight spaces (e.g., the table on the tests page)
14 | .ie7-restore-left-whitespace();
15 | }
16 |
17 | // Space out series of button groups
18 | .btn-group + .btn-group {
19 | margin-left: 5px;
20 | }
21 |
22 | // Optional: Group multiple button groups together for a toolbar
23 | .btn-toolbar {
24 | font-size: 0; // Hack to remove whitespace that results from using inline-block
25 | margin-top: @baseLineHeight / 2;
26 | margin-bottom: @baseLineHeight / 2;
27 | > .btn + .btn,
28 | > .btn-group + .btn,
29 | > .btn + .btn-group {
30 | margin-left: 5px;
31 | }
32 | }
33 |
34 | // Float them, remove border radius, then re-add to first and last elements
35 | .btn-group > .btn {
36 | position: relative;
37 | .border-radius(0);
38 | }
39 | .btn-group > .btn + .btn {
40 | margin-left: -1px;
41 | }
42 | .btn-group > .btn,
43 | .btn-group > .dropdown-menu,
44 | .btn-group > .popover {
45 | font-size: @baseFontSize; // redeclare as part 2 of font-size inline-block hack
46 | }
47 |
48 | // Reset fonts for other sizes
49 | .btn-group > .btn-mini {
50 | font-size: @fontSizeMini;
51 | }
52 | .btn-group > .btn-small {
53 | font-size: @fontSizeSmall;
54 | }
55 | .btn-group > .btn-large {
56 | font-size: @fontSizeLarge;
57 | }
58 |
59 | // Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
60 | .btn-group > .btn:first-child {
61 | margin-left: 0;
62 | .border-top-left-radius(@baseBorderRadius);
63 | .border-bottom-left-radius(@baseBorderRadius);
64 | }
65 | // Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it
66 | .btn-group > .btn:last-child,
67 | .btn-group > .dropdown-toggle {
68 | .border-top-right-radius(@baseBorderRadius);
69 | .border-bottom-right-radius(@baseBorderRadius);
70 | }
71 | // Reset corners for large buttons
72 | .btn-group > .btn.large:first-child {
73 | margin-left: 0;
74 | .border-top-left-radius(@borderRadiusLarge);
75 | .border-bottom-left-radius(@borderRadiusLarge);
76 | }
77 | .btn-group > .btn.large:last-child,
78 | .btn-group > .large.dropdown-toggle {
79 | .border-top-right-radius(@borderRadiusLarge);
80 | .border-bottom-right-radius(@borderRadiusLarge);
81 | }
82 |
83 | // On hover/focus/active, bring the proper btn to front
84 | .btn-group > .btn:hover,
85 | .btn-group > .btn:focus,
86 | .btn-group > .btn:active,
87 | .btn-group > .btn.active {
88 | z-index: 2;
89 | }
90 |
91 | // On active and open, don't show outline
92 | .btn-group .dropdown-toggle:active,
93 | .btn-group.open .dropdown-toggle {
94 | outline: 0;
95 | }
96 |
97 |
98 |
99 | // Split button dropdowns
100 | // ----------------------
101 |
102 | // Give the line between buttons some depth
103 | .btn-group > .btn + .dropdown-toggle {
104 | padding-left: 8px;
105 | padding-right: 8px;
106 | .box-shadow(~"inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
107 | *padding-top: 5px;
108 | *padding-bottom: 5px;
109 | }
110 | .btn-group > .btn-mini + .dropdown-toggle {
111 | padding-left: 5px;
112 | padding-right: 5px;
113 | *padding-top: 2px;
114 | *padding-bottom: 2px;
115 | }
116 | .btn-group > .btn-small + .dropdown-toggle {
117 | *padding-top: 5px;
118 | *padding-bottom: 4px;
119 | }
120 | .btn-group > .btn-large + .dropdown-toggle {
121 | padding-left: 12px;
122 | padding-right: 12px;
123 | *padding-top: 7px;
124 | *padding-bottom: 7px;
125 | }
126 |
127 | .btn-group.open {
128 |
129 | // The clickable button for toggling the menu
130 | // Remove the gradient and set the same inset shadow as the :active state
131 | .dropdown-toggle {
132 | background-image: none;
133 | .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
134 | }
135 |
136 | // Keep the hover's background when dropdown is open
137 | .btn.dropdown-toggle {
138 | background-color: @btnBackgroundHighlight;
139 | }
140 | .btn-primary.dropdown-toggle {
141 | background-color: @btnPrimaryBackgroundHighlight;
142 | }
143 | .btn-warning.dropdown-toggle {
144 | background-color: @btnWarningBackgroundHighlight;
145 | }
146 | .btn-danger.dropdown-toggle {
147 | background-color: @btnDangerBackgroundHighlight;
148 | }
149 | .btn-success.dropdown-toggle {
150 | background-color: @btnSuccessBackgroundHighlight;
151 | }
152 | .btn-info.dropdown-toggle {
153 | background-color: @btnInfoBackgroundHighlight;
154 | }
155 | .btn-inverse.dropdown-toggle {
156 | background-color: @btnInverseBackgroundHighlight;
157 | }
158 | }
159 |
160 |
161 | // Reposition the caret
162 | .btn .caret {
163 | margin-top: 8px;
164 | margin-left: 0;
165 | }
166 | // Carets in other button sizes
167 | .btn-large .caret {
168 | margin-top: 6px;
169 | }
170 | .btn-large .caret {
171 | border-left-width: 5px;
172 | border-right-width: 5px;
173 | border-top-width: 5px;
174 | }
175 | .btn-mini .caret,
176 | .btn-small .caret {
177 | margin-top: 8px;
178 | }
179 | // Upside down carets for .dropup
180 | .dropup .btn-large .caret {
181 | border-bottom-width: 5px;
182 | }
183 |
184 |
185 |
186 | // Account for other colors
187 | .btn-primary,
188 | .btn-warning,
189 | .btn-danger,
190 | .btn-info,
191 | .btn-success,
192 | .btn-inverse {
193 | .caret {
194 | border-top-color: @white;
195 | border-bottom-color: @white;
196 | }
197 | }
198 |
199 |
200 |
201 | // Vertical button groups
202 | // ----------------------
203 |
204 | .btn-group-vertical {
205 | display: inline-block; // makes buttons only take up the width they need
206 | .ie7-inline-block();
207 | }
208 | .btn-group-vertical > .btn {
209 | display: block;
210 | float: none;
211 | max-width: 100%;
212 | .border-radius(0);
213 | }
214 | .btn-group-vertical > .btn + .btn {
215 | margin-left: 0;
216 | margin-top: -1px;
217 | }
218 | .btn-group-vertical > .btn:first-child {
219 | .border-radius(@baseBorderRadius @baseBorderRadius 0 0);
220 | }
221 | .btn-group-vertical > .btn:last-child {
222 | .border-radius(0 0 @baseBorderRadius @baseBorderRadius);
223 | }
224 | .btn-group-vertical > .btn-large:first-child {
225 | .border-radius(@borderRadiusLarge @borderRadiusLarge 0 0);
226 | }
227 | .btn-group-vertical > .btn-large:last-child {
228 | .border-radius(0 0 @borderRadiusLarge @borderRadiusLarge);
229 | }
230 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/buttons-custom.less:
--------------------------------------------------------------------------------
1 | //
2 | // Buttons
3 | // --------------------------------------------------
4 |
5 |
6 | // Base styles
7 | // --------------------------------------------------
8 |
9 | // Core
10 | .btn {
11 | display: inline-block;
12 | .ie7-inline-block();
13 | padding: 4px 12px;
14 | margin-bottom: 0; // For input.btn
15 | font-size: @baseFontSize;
16 | line-height: @baseLineHeight;
17 | text-align: center;
18 | vertical-align: middle;
19 | cursor: pointer;
20 | // .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75));
21 | background-color: mix(@btnBackground, @btnBackgroundHighlight, 60%);
22 | // border: 1px solid @btnBorder;
23 | border: 1px solid mix(@btnBackground, @btnBackgroundHighlight, 60%);
24 | *border: 0; // Remove the border to prevent IE7's black border on input:focus
25 | // border-bottom-color: darken(@btnBorder, 10%);
26 | .border-radius(@baseBorderRadius);
27 | .ie7-restore-left-whitespace(); // Give IE7 some love
28 | // .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
29 |
30 | // Hover/focus state
31 | &:hover,
32 | &:focus {
33 | color: @grayDark;
34 | text-decoration: none;
35 | // background-position: 0 -15px;
36 |
37 | // transition is only when going to hover/focus, otherwise the background
38 | // behind the gradient (there for IE<=9 fallback) gets mismatched
39 | // .transition(background-position .1s linear);
40 | background-color: @btnBackgroundHighlight;
41 | border: 1px solid @btnBackgroundHighlight;
42 | }
43 |
44 | // Focus state for keyboard and accessibility
45 | &:focus {
46 | .tab-focus();
47 | }
48 |
49 | // Active state
50 | &.active,
51 | &:active {
52 | background-image: none;
53 | outline: 0;
54 | .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
55 | }
56 |
57 | // Disabled state
58 | &.disabled,
59 | &[disabled] {
60 | cursor: default;
61 | background-image: none;
62 | .opacity(65);
63 | .box-shadow(none);
64 | }
65 |
66 | }
67 |
68 |
69 |
70 | // Button Sizes
71 | // --------------------------------------------------
72 |
73 | // Large
74 | .btn-large {
75 | padding: @paddingLarge;
76 | font-size: @fontSizeLarge;
77 | .border-radius(@borderRadiusLarge);
78 | }
79 | .btn-large [class^="icon-"],
80 | .btn-large [class*=" icon-"] {
81 | margin-top: 4px;
82 | }
83 |
84 | // Small
85 | .btn-small {
86 | padding: @paddingSmall;
87 | font-size: @fontSizeSmall;
88 | .border-radius(@borderRadiusSmall);
89 | }
90 | .btn-small [class^="icon-"],
91 | .btn-small [class*=" icon-"] {
92 | margin-top: 0;
93 | }
94 | .btn-mini [class^="icon-"],
95 | .btn-mini [class*=" icon-"] {
96 | margin-top: -1px;
97 | }
98 |
99 | // Mini
100 | .btn-mini {
101 | padding: @paddingMini;
102 | font-size: @fontSizeMini;
103 | .border-radius(@borderRadiusSmall);
104 | }
105 |
106 |
107 | // Block button
108 | // -------------------------
109 |
110 | .btn-block {
111 | display: block;
112 | width: 100%;
113 | padding-left: 0;
114 | padding-right: 0;
115 | .box-sizing(border-box);
116 | }
117 |
118 | // Vertically space out multiple block buttons
119 | .btn-block + .btn-block {
120 | margin-top: 5px;
121 | }
122 |
123 | // Specificity overrides
124 | input[type="submit"],
125 | input[type="reset"],
126 | input[type="button"] {
127 | &.btn-block {
128 | width: 100%;
129 | }
130 | }
131 |
132 |
133 |
134 | // Alternate buttons
135 | // --------------------------------------------------
136 |
137 | // Provide *some* extra contrast for those who can get it
138 | .btn-primary.active,
139 | .btn-warning.active,
140 | .btn-danger.active,
141 | .btn-success.active,
142 | .btn-info.active,
143 | .btn-inverse.active {
144 | color: rgba(255,255,255,.75);
145 | }
146 |
147 | // Set the backgrounds
148 | // -------------------------
149 | .btn-primary {
150 | .buttonBackground(@btnPrimaryBackground, @btnPrimaryBackgroundHighlight);
151 | }
152 | // Warning appears are orange
153 | .btn-warning {
154 | .buttonBackground(@btnWarningBackground, @btnWarningBackgroundHighlight);
155 | }
156 | // Danger and error appear as red
157 | .btn-danger {
158 | .buttonBackground(@btnDangerBackground, @btnDangerBackgroundHighlight);
159 | }
160 | // Success appears as green
161 | .btn-success {
162 | color: white;
163 | // .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight);
164 | background-color: mix(@btnSuccessBackground, @btnSuccessBackgroundHighlight, 60%);
165 | // border: 1px solid @btnBorder;
166 | border: 1px solid mix(@btnSuccessBackground, @btnSuccessBackgroundHighlight, 60%);
167 | // Hover/focus state
168 | &:hover,
169 | &:focus {
170 | color: white;
171 | background-color: @btnSuccessBackgroundHighlight;
172 | border: 1px solid @btnSuccessBackgroundHighlight;
173 | }
174 | }
175 | // Info appears as a neutral blue
176 | .btn-info {
177 | .buttonBackground(@btnInfoBackground, @btnInfoBackgroundHighlight);
178 | }
179 | // Inverse appears as dark gray
180 | .btn-inverse {
181 | .buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight);
182 | }
183 |
184 |
185 | // Cross-browser Jank
186 | // --------------------------------------------------
187 |
188 | button.btn,
189 | input[type="submit"].btn {
190 |
191 | // Firefox 3.6 only I believe
192 | &::-moz-focus-inner {
193 | padding: 0;
194 | border: 0;
195 | }
196 |
197 | // IE7 has some default padding on button controls
198 | *padding-top: 3px;
199 | *padding-bottom: 3px;
200 |
201 | &.btn-large {
202 | *padding-top: 7px;
203 | *padding-bottom: 7px;
204 | }
205 | &.btn-small {
206 | *padding-top: 3px;
207 | *padding-bottom: 3px;
208 | }
209 | &.btn-mini {
210 | *padding-top: 1px;
211 | *padding-bottom: 1px;
212 | }
213 | }
214 |
215 |
216 | // Link buttons
217 | // --------------------------------------------------
218 |
219 | // Make a button look and behave like a link
220 | .btn-link,
221 | .btn-link:active,
222 | .btn-link[disabled] {
223 | background-color: transparent;
224 | background-image: none;
225 | .box-shadow(none);
226 | }
227 | .btn-link {
228 | border-color: transparent;
229 | cursor: pointer;
230 | color: @linkColor;
231 | .border-radius(0);
232 | }
233 | .btn-link:hover,
234 | .btn-link:focus {
235 | color: @linkColorHover;
236 | text-decoration: underline;
237 | background-color: transparent;
238 | }
239 | .btn-link[disabled]:hover,
240 | .btn-link[disabled]:focus {
241 | color: @grayDark;
242 | text-decoration: none;
243 | }
244 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/buttons.less:
--------------------------------------------------------------------------------
1 | //
2 | // Buttons
3 | // --------------------------------------------------
4 |
5 |
6 | // Base styles
7 | // --------------------------------------------------
8 |
9 | // Core
10 | .btn {
11 | display: inline-block;
12 | .ie7-inline-block();
13 | padding: 4px 12px;
14 | margin-bottom: 0; // For input.btn
15 | font-size: @baseFontSize;
16 | line-height: @baseLineHeight;
17 | text-align: center;
18 | vertical-align: middle;
19 | cursor: pointer;
20 | .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75));
21 | border: 1px solid @btnBorder;
22 | *border: 0; // Remove the border to prevent IE7's black border on input:focus
23 | border-bottom-color: darken(@btnBorder, 10%);
24 | .border-radius(@baseBorderRadius);
25 | .ie7-restore-left-whitespace(); // Give IE7 some love
26 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
27 |
28 | // Hover/focus state
29 | &:hover,
30 | &:focus {
31 | color: @grayDark;
32 | text-decoration: none;
33 | background-position: 0 -15px;
34 |
35 | // transition is only when going to hover/focus, otherwise the background
36 | // behind the gradient (there for IE<=9 fallback) gets mismatched
37 | .transition(background-position .1s linear);
38 | }
39 |
40 | // Focus state for keyboard and accessibility
41 | &:focus {
42 | .tab-focus();
43 | }
44 |
45 | // Active state
46 | &.active,
47 | &:active {
48 | background-image: none;
49 | outline: 0;
50 | .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
51 | }
52 |
53 | // Disabled state
54 | &.disabled,
55 | &[disabled] {
56 | cursor: default;
57 | background-image: none;
58 | .opacity(65);
59 | .box-shadow(none);
60 | }
61 |
62 | }
63 |
64 |
65 |
66 | // Button Sizes
67 | // --------------------------------------------------
68 |
69 | // Large
70 | .btn-large {
71 | padding: @paddingLarge;
72 | font-size: @fontSizeLarge;
73 | .border-radius(@borderRadiusLarge);
74 | }
75 | .btn-large [class^="icon-"],
76 | .btn-large [class*=" icon-"] {
77 | margin-top: 4px;
78 | }
79 |
80 | // Small
81 | .btn-small {
82 | padding: @paddingSmall;
83 | font-size: @fontSizeSmall;
84 | .border-radius(@borderRadiusSmall);
85 | }
86 | .btn-small [class^="icon-"],
87 | .btn-small [class*=" icon-"] {
88 | margin-top: 0;
89 | }
90 | .btn-mini [class^="icon-"],
91 | .btn-mini [class*=" icon-"] {
92 | margin-top: -1px;
93 | }
94 |
95 | // Mini
96 | .btn-mini {
97 | padding: @paddingMini;
98 | font-size: @fontSizeMini;
99 | .border-radius(@borderRadiusSmall);
100 | }
101 |
102 |
103 | // Block button
104 | // -------------------------
105 |
106 | .btn-block {
107 | display: block;
108 | width: 100%;
109 | padding-left: 0;
110 | padding-right: 0;
111 | .box-sizing(border-box);
112 | }
113 |
114 | // Vertically space out multiple block buttons
115 | .btn-block + .btn-block {
116 | margin-top: 5px;
117 | }
118 |
119 | // Specificity overrides
120 | input[type="submit"],
121 | input[type="reset"],
122 | input[type="button"] {
123 | &.btn-block {
124 | width: 100%;
125 | }
126 | }
127 |
128 |
129 |
130 | // Alternate buttons
131 | // --------------------------------------------------
132 |
133 | // Provide *some* extra contrast for those who can get it
134 | .btn-primary.active,
135 | .btn-warning.active,
136 | .btn-danger.active,
137 | .btn-success.active,
138 | .btn-info.active,
139 | .btn-inverse.active {
140 | color: rgba(255,255,255,.75);
141 | }
142 |
143 | // Set the backgrounds
144 | // -------------------------
145 | .btn-primary {
146 | .buttonBackground(@btnPrimaryBackground, @btnPrimaryBackgroundHighlight);
147 | }
148 | // Warning appears are orange
149 | .btn-warning {
150 | .buttonBackground(@btnWarningBackground, @btnWarningBackgroundHighlight);
151 | }
152 | // Danger and error appear as red
153 | .btn-danger {
154 | .buttonBackground(@btnDangerBackground, @btnDangerBackgroundHighlight);
155 | }
156 | // Success appears as green
157 | .btn-success {
158 | .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight);
159 | }
160 | // Info appears as a neutral blue
161 | .btn-info {
162 | .buttonBackground(@btnInfoBackground, @btnInfoBackgroundHighlight);
163 | }
164 | // Inverse appears as dark gray
165 | .btn-inverse {
166 | .buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight);
167 | }
168 |
169 |
170 | // Cross-browser Jank
171 | // --------------------------------------------------
172 |
173 | button.btn,
174 | input[type="submit"].btn {
175 |
176 | // Firefox 3.6 only I believe
177 | &::-moz-focus-inner {
178 | padding: 0;
179 | border: 0;
180 | }
181 |
182 | // IE7 has some default padding on button controls
183 | *padding-top: 3px;
184 | *padding-bottom: 3px;
185 |
186 | &.btn-large {
187 | *padding-top: 7px;
188 | *padding-bottom: 7px;
189 | }
190 | &.btn-small {
191 | *padding-top: 3px;
192 | *padding-bottom: 3px;
193 | }
194 | &.btn-mini {
195 | *padding-top: 1px;
196 | *padding-bottom: 1px;
197 | }
198 | }
199 |
200 |
201 | // Link buttons
202 | // --------------------------------------------------
203 |
204 | // Make a button look and behave like a link
205 | .btn-link,
206 | .btn-link:active,
207 | .btn-link[disabled] {
208 | background-color: transparent;
209 | background-image: none;
210 | .box-shadow(none);
211 | }
212 | .btn-link {
213 | border-color: transparent;
214 | cursor: pointer;
215 | color: @linkColor;
216 | .border-radius(0);
217 | }
218 | .btn-link:hover,
219 | .btn-link:focus {
220 | color: @linkColorHover;
221 | text-decoration: underline;
222 | background-color: transparent;
223 | }
224 | .btn-link[disabled]:hover,
225 | .btn-link[disabled]:focus {
226 | color: @grayDark;
227 | text-decoration: none;
228 | }
229 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/carousel.less:
--------------------------------------------------------------------------------
1 | //
2 | // Carousel
3 | // --------------------------------------------------
4 |
5 |
6 | .carousel {
7 | position: relative;
8 | margin-bottom: @baseLineHeight;
9 | line-height: 1;
10 | }
11 |
12 | .carousel-inner {
13 | overflow: hidden;
14 | width: 100%;
15 | position: relative;
16 | }
17 |
18 | .carousel-inner {
19 |
20 | > .item {
21 | display: none;
22 | position: relative;
23 | .transition(.6s ease-in-out left);
24 |
25 | // Account for jankitude on images
26 | > img,
27 | > a > img {
28 | display: block;
29 | line-height: 1;
30 | }
31 | }
32 |
33 | > .active,
34 | > .next,
35 | > .prev { display: block; }
36 |
37 | > .active {
38 | left: 0;
39 | }
40 |
41 | > .next,
42 | > .prev {
43 | position: absolute;
44 | top: 0;
45 | width: 100%;
46 | }
47 |
48 | > .next {
49 | left: 100%;
50 | }
51 | > .prev {
52 | left: -100%;
53 | }
54 | > .next.left,
55 | > .prev.right {
56 | left: 0;
57 | }
58 |
59 | > .active.left {
60 | left: -100%;
61 | }
62 | > .active.right {
63 | left: 100%;
64 | }
65 |
66 | }
67 |
68 | // Left/right controls for nav
69 | // ---------------------------
70 |
71 | .carousel-control {
72 | position: absolute;
73 | top: 40%;
74 | left: 15px;
75 | width: 40px;
76 | height: 40px;
77 | margin-top: -20px;
78 | font-size: 60px;
79 | font-weight: 100;
80 | line-height: 30px;
81 | color: @white;
82 | text-align: center;
83 | background: @grayDarker;
84 | border: 3px solid @white;
85 | .border-radius(23px);
86 | .opacity(50);
87 |
88 | // we can't have this transition here
89 | // because webkit cancels the carousel
90 | // animation if you trip this while
91 | // in the middle of another animation
92 | // ;_;
93 | // .transition(opacity .2s linear);
94 |
95 | // Reposition the right one
96 | &.right {
97 | left: auto;
98 | right: 15px;
99 | }
100 |
101 | // Hover/focus state
102 | &:hover,
103 | &:focus {
104 | color: @white;
105 | text-decoration: none;
106 | .opacity(90);
107 | }
108 | }
109 |
110 | // Carousel indicator pips
111 | // -----------------------------
112 | .carousel-indicators {
113 | position: absolute;
114 | top: 15px;
115 | right: 15px;
116 | z-index: 5;
117 | margin: 0;
118 | list-style: none;
119 |
120 | li {
121 | display: block;
122 | float: left;
123 | width: 10px;
124 | height: 10px;
125 | margin-left: 5px;
126 | text-indent: -999px;
127 | background-color: #ccc;
128 | background-color: rgba(255,255,255,.25);
129 | border-radius: 5px;
130 | }
131 | .active {
132 | background-color: #fff;
133 | }
134 | }
135 |
136 | // Caption for text below images
137 | // -----------------------------
138 |
139 | .carousel-caption {
140 | position: absolute;
141 | left: 0;
142 | right: 0;
143 | bottom: 0;
144 | padding: 15px;
145 | background: @grayDark;
146 | background: rgba(0,0,0,.75);
147 | }
148 | .carousel-caption h4,
149 | .carousel-caption p {
150 | color: @white;
151 | line-height: @baseLineHeight;
152 | }
153 | .carousel-caption h4 {
154 | margin: 0 0 5px;
155 | }
156 | .carousel-caption p {
157 | margin-bottom: 0;
158 | }
159 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/close.less:
--------------------------------------------------------------------------------
1 | //
2 | // Close icons
3 | // --------------------------------------------------
4 |
5 |
6 | .close {
7 | float: right;
8 | font-size: 20px;
9 | font-weight: bold;
10 | line-height: @baseLineHeight;
11 | color: @black;
12 | text-shadow: 0 1px 0 rgba(255,255,255,1);
13 | .opacity(20);
14 | &:hover,
15 | &:focus {
16 | color: @black;
17 | text-decoration: none;
18 | cursor: pointer;
19 | .opacity(40);
20 | }
21 | }
22 |
23 | // Additional properties for button version
24 | // iOS requires the button element instead of an anchor tag.
25 | // If you want the anchor version, it requires `href="#"`.
26 | button.close {
27 | padding: 0;
28 | cursor: pointer;
29 | background: transparent;
30 | border: 0;
31 | -webkit-appearance: none;
32 | }
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/code.less:
--------------------------------------------------------------------------------
1 | //
2 | // Code (inline and blocK)
3 | // --------------------------------------------------
4 |
5 |
6 | // Inline and block code styles
7 | code,
8 | pre {
9 | padding: 0 3px 2px;
10 | #font > #family > .monospace;
11 | font-size: @baseFontSize - 2;
12 | color: @grayDark;
13 | .border-radius(3px);
14 | }
15 |
16 | // Inline code
17 | code {
18 | padding: 2px 4px;
19 | color: #d14;
20 | background-color: #f7f7f9;
21 | border: 1px solid #e1e1e8;
22 | white-space: nowrap;
23 | }
24 |
25 | // Blocks of code
26 | pre {
27 | display: block;
28 | padding: (@baseLineHeight - 1) / 2;
29 | margin: 0 0 @baseLineHeight / 2;
30 | font-size: @baseFontSize - 1; // 14px to 13px
31 | line-height: @baseLineHeight;
32 | word-break: break-all;
33 | word-wrap: break-word;
34 | white-space: pre;
35 | white-space: pre-wrap;
36 | background-color: #f5f5f5;
37 | border: 1px solid #ccc; // fallback for IE7-8
38 | border: 1px solid rgba(0,0,0,.15);
39 | .border-radius(@baseBorderRadius);
40 |
41 | // Make prettyprint styles more spaced out for readability
42 | &.prettyprint {
43 | margin-bottom: @baseLineHeight;
44 | }
45 |
46 | // Account for some code outputs that place code tags in pre tags
47 | code {
48 | padding: 0;
49 | color: inherit;
50 | white-space: pre;
51 | white-space: pre-wrap;
52 | background-color: transparent;
53 | border: 0;
54 | }
55 | }
56 |
57 | // Enable scrollable blocks of code
58 | .pre-scrollable {
59 | max-height: 340px;
60 | overflow-y: scroll;
61 | }
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/component-animations.less:
--------------------------------------------------------------------------------
1 | //
2 | // Component animations
3 | // --------------------------------------------------
4 |
5 |
6 | .fade {
7 | opacity: 0;
8 | .transition(opacity .15s linear);
9 | &.in {
10 | opacity: 1;
11 | }
12 | }
13 |
14 | .collapse {
15 | position: relative;
16 | height: 0;
17 | overflow: hidden;
18 | .transition(height .35s ease);
19 | &.in {
20 | height: auto;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/dropdowns.less:
--------------------------------------------------------------------------------
1 | //
2 | // Dropdown menus
3 | // --------------------------------------------------
4 |
5 |
6 | // Use the .menu class on any element within the topbar or ul.tabs and you'll get some superfancy dropdowns
7 | .dropup,
8 | .dropdown {
9 | position: relative;
10 | }
11 | .dropdown-toggle {
12 | // The caret makes the toggle a bit too tall in IE7
13 | *margin-bottom: -3px;
14 | }
15 | .dropdown-toggle:active,
16 | .open .dropdown-toggle {
17 | outline: 0;
18 | }
19 |
20 | // Dropdown arrow/caret
21 | // --------------------
22 | .caret {
23 | display: inline-block;
24 | width: 0;
25 | height: 0;
26 | vertical-align: top;
27 | border-top: 4px solid @black;
28 | border-right: 4px solid transparent;
29 | border-left: 4px solid transparent;
30 | content: "";
31 | }
32 |
33 | // Place the caret
34 | .dropdown .caret {
35 | margin-top: 8px;
36 | margin-left: 2px;
37 | }
38 |
39 | // The dropdown menu (ul)
40 | // ----------------------
41 | .dropdown-menu {
42 | position: absolute;
43 | top: 100%;
44 | left: 0;
45 | z-index: @zindexDropdown;
46 | display: none; // none by default, but block on "open" of the menu
47 | float: left;
48 | min-width: 160px;
49 | padding: 5px 0;
50 | margin: 2px 0 0; // override default ul
51 | list-style: none;
52 | background-color: @dropdownBackground;
53 | border: 1px solid #ccc; // Fallback for IE7-8
54 | border: 1px solid @dropdownBorder;
55 | *border-right-width: 2px;
56 | *border-bottom-width: 2px;
57 | .border-radius(6px);
58 | .box-shadow(0 5px 10px rgba(0,0,0,.2));
59 | -webkit-background-clip: padding-box;
60 | -moz-background-clip: padding;
61 | background-clip: padding-box;
62 |
63 | // Aligns the dropdown menu to right
64 | &.pull-right {
65 | right: 0;
66 | left: auto;
67 | }
68 |
69 | // Dividers (basically an hr) within the dropdown
70 | .divider {
71 | .nav-divider(@dropdownDividerTop, @dropdownDividerBottom);
72 | }
73 |
74 | // Links within the dropdown menu
75 | > li > a {
76 | display: block;
77 | padding: 3px 20px;
78 | clear: both;
79 | font-weight: normal;
80 | line-height: @baseLineHeight;
81 | color: @dropdownLinkColor;
82 | white-space: nowrap;
83 | }
84 | }
85 |
86 | // Hover/Focus state
87 | // -----------
88 | .dropdown-menu > li > a:hover,
89 | .dropdown-menu > li > a:focus,
90 | .dropdown-submenu:hover > a,
91 | .dropdown-submenu:focus > a {
92 | text-decoration: none;
93 | color: @dropdownLinkColorHover;
94 | #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%));
95 | }
96 |
97 | // Active state
98 | // ------------
99 | .dropdown-menu > .active > a,
100 | .dropdown-menu > .active > a:hover,
101 | .dropdown-menu > .active > a:focus {
102 | color: @dropdownLinkColorActive;
103 | text-decoration: none;
104 | outline: 0;
105 | #gradient > .vertical(@dropdownLinkBackgroundActive, darken(@dropdownLinkBackgroundActive, 5%));
106 | }
107 |
108 | // Disabled state
109 | // --------------
110 | // Gray out text and ensure the hover/focus state remains gray
111 | .dropdown-menu > .disabled > a,
112 | .dropdown-menu > .disabled > a:hover,
113 | .dropdown-menu > .disabled > a:focus {
114 | color: @grayLight;
115 | }
116 | // Nuke hover/focus effects
117 | .dropdown-menu > .disabled > a:hover,
118 | .dropdown-menu > .disabled > a:focus {
119 | text-decoration: none;
120 | background-color: transparent;
121 | background-image: none; // Remove CSS gradient
122 | .reset-filter();
123 | cursor: default;
124 | }
125 |
126 | // Open state for the dropdown
127 | // ---------------------------
128 | .open {
129 | // IE7's z-index only goes to the nearest positioned ancestor, which would
130 | // make the menu appear below buttons that appeared later on the page
131 | *z-index: @zindexDropdown;
132 |
133 | & > .dropdown-menu {
134 | display: block;
135 | }
136 | }
137 |
138 | // Right aligned dropdowns
139 | // ---------------------------
140 | .pull-right > .dropdown-menu {
141 | right: 0;
142 | left: auto;
143 | }
144 |
145 | // Allow for dropdowns to go bottom up (aka, dropup-menu)
146 | // ------------------------------------------------------
147 | // Just add .dropup after the standard .dropdown class and you're set, bro.
148 | // TODO: abstract this so that the navbar fixed styles are not placed here?
149 | .dropup,
150 | .navbar-fixed-bottom .dropdown {
151 | // Reverse the caret
152 | .caret {
153 | border-top: 0;
154 | border-bottom: 4px solid @black;
155 | content: "";
156 | }
157 | // Different positioning for bottom up menu
158 | .dropdown-menu {
159 | top: auto;
160 | bottom: 100%;
161 | margin-bottom: 1px;
162 | }
163 | }
164 |
165 | // Sub menus
166 | // ---------------------------
167 | .dropdown-submenu {
168 | position: relative;
169 | }
170 | // Default dropdowns
171 | .dropdown-submenu > .dropdown-menu {
172 | top: 0;
173 | left: 100%;
174 | margin-top: -6px;
175 | margin-left: -1px;
176 | .border-radius(0 6px 6px 6px);
177 | }
178 | .dropdown-submenu:hover > .dropdown-menu {
179 | display: block;
180 | }
181 |
182 | // Dropups
183 | .dropup .dropdown-submenu > .dropdown-menu {
184 | top: auto;
185 | bottom: 0;
186 | margin-top: 0;
187 | margin-bottom: -2px;
188 | .border-radius(5px 5px 5px 0);
189 | }
190 |
191 | // Caret to indicate there is a submenu
192 | .dropdown-submenu > a:after {
193 | display: block;
194 | content: " ";
195 | float: right;
196 | width: 0;
197 | height: 0;
198 | border-color: transparent;
199 | border-style: solid;
200 | border-width: 5px 0 5px 5px;
201 | border-left-color: darken(@dropdownBackground, 20%);
202 | margin-top: 5px;
203 | margin-right: -10px;
204 | }
205 | .dropdown-submenu:hover > a:after {
206 | border-left-color: @dropdownLinkColorHover;
207 | }
208 |
209 | // Left aligned submenus
210 | .dropdown-submenu.pull-left {
211 | // Undo the float
212 | // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere.
213 | float: none;
214 |
215 | // Positioning the submenu
216 | > .dropdown-menu {
217 | left: -100%;
218 | margin-left: 10px;
219 | .border-radius(6px 0 6px 6px);
220 | }
221 | }
222 |
223 | // Tweak nav headers
224 | // -----------------
225 | // Increase padding from 15px to 20px on sides
226 | .dropdown .dropdown-menu .nav-header {
227 | padding-left: 20px;
228 | padding-right: 20px;
229 | }
230 |
231 | // Typeahead
232 | // ---------
233 | .typeahead {
234 | z-index: 1051;
235 | margin-top: 2px; // give it some space to breathe
236 | .border-radius(@baseBorderRadius);
237 | }
238 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/grid.less:
--------------------------------------------------------------------------------
1 | //
2 | // Grid system
3 | // --------------------------------------------------
4 |
5 |
6 | // Fixed (940px)
7 | #grid > .core(@gridColumnWidth, @gridGutterWidth);
8 |
9 | // Fluid (940px)
10 | #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth);
11 |
12 | // Reset utility classes due to specificity
13 | [class*="span"].hide,
14 | .row-fluid [class*="span"].hide {
15 | display: none;
16 | }
17 |
18 | [class*="span"].pull-right,
19 | .row-fluid [class*="span"].pull-right {
20 | float: right;
21 | }
22 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/hero-unit.less:
--------------------------------------------------------------------------------
1 | //
2 | // Hero unit
3 | // --------------------------------------------------
4 |
5 |
6 | .hero-unit {
7 | padding: 60px;
8 | margin-bottom: 30px;
9 | font-size: 18px;
10 | font-weight: 200;
11 | line-height: @baseLineHeight * 1.5;
12 | color: @heroUnitLeadColor;
13 | background-color: @heroUnitBackground;
14 | .border-radius(6px);
15 | h1 {
16 | margin-bottom: 0;
17 | font-size: 60px;
18 | line-height: 1;
19 | color: @heroUnitHeadingColor;
20 | letter-spacing: -1px;
21 | }
22 | li {
23 | line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/labels-badges.less:
--------------------------------------------------------------------------------
1 | //
2 | // Labels and badges
3 | // --------------------------------------------------
4 |
5 |
6 | // Base classes
7 | .label,
8 | .badge {
9 | display: inline-block;
10 | padding: 2px 4px;
11 | font-size: @baseFontSize * .846;
12 | font-weight: bold;
13 | line-height: 14px; // ensure proper line-height if floated
14 | color: @white;
15 | vertical-align: baseline;
16 | white-space: nowrap;
17 | text-shadow: 0 -1px 0 rgba(0,0,0,.25);
18 | background-color: @grayLight;
19 | }
20 | // Set unique padding and border-radii
21 | .label {
22 | .border-radius(3px);
23 | }
24 | .badge {
25 | padding-left: 9px;
26 | padding-right: 9px;
27 | .border-radius(9px);
28 | }
29 |
30 | // Empty labels/badges collapse
31 | .label,
32 | .badge {
33 | &:empty {
34 | display: none;
35 | }
36 | }
37 |
38 | // Hover/focus state, but only for links
39 | a {
40 | &.label:hover,
41 | &.label:focus,
42 | &.badge:hover,
43 | &.badge:focus {
44 | color: @white;
45 | text-decoration: none;
46 | cursor: pointer;
47 | }
48 | }
49 |
50 | // Colors
51 | // Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute)
52 | .label,
53 | .badge {
54 | // Important (red)
55 | &-important { background-color: @errorText; }
56 | &-important[href] { background-color: darken(@errorText, 10%); }
57 | // Warnings (orange)
58 | &-warning { background-color: @orange; }
59 | &-warning[href] { background-color: darken(@orange, 10%); }
60 | // Success (green)
61 | &-success { background-color: @successText; }
62 | &-success[href] { background-color: darken(@successText, 10%); }
63 | // Info (turquoise)
64 | &-info { background-color: @infoText; }
65 | &-info[href] { background-color: darken(@infoText, 10%); }
66 | // Inverse (black)
67 | &-inverse { background-color: @grayDark; }
68 | &-inverse[href] { background-color: darken(@grayDark, 10%); }
69 | }
70 |
71 | // Quick fix for labels/badges in buttons
72 | .btn {
73 | .label,
74 | .badge {
75 | position: relative;
76 | top: -1px;
77 | }
78 | }
79 | .btn-mini {
80 | .label,
81 | .badge {
82 | top: 0;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/layouts.less:
--------------------------------------------------------------------------------
1 | //
2 | // Layouts
3 | // --------------------------------------------------
4 |
5 |
6 | // Container (centered, fixed-width layouts)
7 | .container {
8 | .container-fixed();
9 | }
10 |
11 | // Fluid layouts (left aligned, with sidebar, min- & max-width content)
12 | .container-fluid {
13 | padding-right: @gridGutterWidth;
14 | padding-left: @gridGutterWidth;
15 | .clearfix();
16 | }
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/media.less:
--------------------------------------------------------------------------------
1 | // Media objects
2 | // Source: http://stubbornella.org/content/?p=497
3 | // --------------------------------------------------
4 |
5 |
6 | // Common styles
7 | // -------------------------
8 |
9 | // Clear the floats
10 | .media,
11 | .media-body {
12 | overflow: hidden;
13 | *overflow: visible;
14 | zoom: 1;
15 | }
16 |
17 | // Proper spacing between instances of .media
18 | .media,
19 | .media .media {
20 | margin-top: 15px;
21 | }
22 | .media:first-child {
23 | margin-top: 0;
24 | }
25 |
26 | // For images and videos, set to block
27 | .media-object {
28 | display: block;
29 | }
30 |
31 | // Reset margins on headings for tighter default spacing
32 | .media-heading {
33 | margin: 0 0 5px;
34 | }
35 |
36 |
37 | // Media image alignment
38 | // -------------------------
39 |
40 | .media > .pull-left {
41 | margin-right: 10px;
42 | }
43 | .media > .pull-right {
44 | margin-left: 10px;
45 | }
46 |
47 |
48 | // Media list variation
49 | // -------------------------
50 |
51 | // Undo default ul/ol styles
52 | .media-list {
53 | margin-left: 0;
54 | list-style: none;
55 | }
56 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/modals.less:
--------------------------------------------------------------------------------
1 | //
2 | // Modals
3 | // --------------------------------------------------
4 |
5 | // Background
6 | .modal-backdrop {
7 | position: fixed;
8 | top: 0;
9 | right: 0;
10 | bottom: 0;
11 | left: 0;
12 | z-index: @zindexModalBackdrop;
13 | background-color: @black;
14 | // Fade for backdrop
15 | &.fade { opacity: 0; }
16 | }
17 |
18 | .modal-backdrop,
19 | .modal-backdrop.fade.in {
20 | .opacity(80);
21 | }
22 |
23 | // Base modal
24 | .modal {
25 | position: fixed;
26 | top: 10%;
27 | left: 50%;
28 | z-index: @zindexModal;
29 | width: 560px;
30 | margin-left: -280px;
31 | background-color: @white;
32 | border: 1px solid #999;
33 | border: 1px solid rgba(0,0,0,.3);
34 | *border: 1px solid #999; /* IE6-7 */
35 | .border-radius(6px);
36 | .box-shadow(0 3px 7px rgba(0,0,0,0.3));
37 | .background-clip(padding-box);
38 | // Remove focus outline from opened modal
39 | outline: none;
40 |
41 | &.fade {
42 | .transition(e('opacity .3s linear, top .3s ease-out'));
43 | top: -25%;
44 | }
45 | &.fade.in { top: 10%; }
46 | }
47 | .modal-header {
48 | padding: 9px 15px;
49 | border-bottom: 1px solid #eee;
50 | // Close icon
51 | .close { margin-top: 2px; }
52 | // Heading
53 | h3 {
54 | margin: 0;
55 | line-height: 30px;
56 | }
57 | }
58 |
59 | // Body (where all modal content resides)
60 | .modal-body {
61 | position: relative;
62 | overflow-y: auto;
63 | max-height: 400px;
64 | padding: 15px;
65 | }
66 | // Remove bottom margin if need be
67 | .modal-form {
68 | margin-bottom: 0;
69 | }
70 |
71 | // Footer (for actions)
72 | .modal-footer {
73 | padding: 14px 15px 15px;
74 | margin-bottom: 0;
75 | text-align: right; // right align buttons
76 | background-color: #f5f5f5;
77 | border-top: 1px solid #ddd;
78 | .border-radius(0 0 6px 6px);
79 | .box-shadow(inset 0 1px 0 @white);
80 | .clearfix(); // clear it in case folks use .pull-* classes on buttons
81 |
82 | // Properly space out buttons
83 | .btn + .btn {
84 | margin-left: 5px;
85 | margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
86 | }
87 | // but override that for button groups
88 | .btn-group .btn + .btn {
89 | margin-left: -1px;
90 | }
91 | // and override it for block buttons as well
92 | .btn-block + .btn-block {
93 | margin-left: 0;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/pager.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pager pagination
3 | // --------------------------------------------------
4 |
5 |
6 | .pager {
7 | margin: @baseLineHeight 0;
8 | list-style: none;
9 | text-align: center;
10 | .clearfix();
11 | }
12 | .pager li {
13 | display: inline;
14 | }
15 | .pager li > a,
16 | .pager li > span {
17 | display: inline-block;
18 | padding: 5px 14px;
19 | background-color: #fff;
20 | border: 1px solid #ddd;
21 | .border-radius(15px);
22 | }
23 | .pager li > a:hover,
24 | .pager li > a:focus {
25 | text-decoration: none;
26 | background-color: #f5f5f5;
27 | }
28 | .pager .next > a,
29 | .pager .next > span {
30 | float: right;
31 | }
32 | .pager .previous > a,
33 | .pager .previous > span {
34 | float: left;
35 | }
36 | .pager .disabled > a,
37 | .pager .disabled > a:hover,
38 | .pager .disabled > a:focus,
39 | .pager .disabled > span {
40 | color: @grayLight;
41 | background-color: #fff;
42 | cursor: default;
43 | }
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/pagination.less:
--------------------------------------------------------------------------------
1 | //
2 | // Pagination (multiple pages)
3 | // --------------------------------------------------
4 |
5 | // Space out pagination from surrounding content
6 | .pagination {
7 | margin: @baseLineHeight 0;
8 | }
9 |
10 | .pagination ul {
11 | // Allow for text-based alignment
12 | display: inline-block;
13 | .ie7-inline-block();
14 | // Reset default ul styles
15 | margin-left: 0;
16 | margin-bottom: 0;
17 | // Visuals
18 | .border-radius(@baseBorderRadius);
19 | .box-shadow(0 1px 2px rgba(0,0,0,.05));
20 | }
21 | .pagination ul > li {
22 | display: inline; // Remove list-style and block-level defaults
23 | }
24 | .pagination ul > li > a,
25 | .pagination ul > li > span {
26 | float: left; // Collapse white-space
27 | padding: 4px 12px;
28 | line-height: @baseLineHeight;
29 | text-decoration: none;
30 | background-color: @paginationBackground;
31 | border: 1px solid @paginationBorder;
32 | border-left-width: 0;
33 | }
34 | .pagination ul > li > a:hover,
35 | .pagination ul > li > a:focus,
36 | .pagination ul > .active > a,
37 | .pagination ul > .active > span {
38 | background-color: @paginationActiveBackground;
39 | }
40 | .pagination ul > .active > a,
41 | .pagination ul > .active > span {
42 | color: @grayLight;
43 | cursor: default;
44 | }
45 | .pagination ul > .disabled > span,
46 | .pagination ul > .disabled > a,
47 | .pagination ul > .disabled > a:hover,
48 | .pagination ul > .disabled > a:focus {
49 | color: @grayLight;
50 | background-color: transparent;
51 | cursor: default;
52 | }
53 | .pagination ul > li:first-child > a,
54 | .pagination ul > li:first-child > span {
55 | border-left-width: 1px;
56 | .border-left-radius(@baseBorderRadius);
57 | }
58 | .pagination ul > li:last-child > a,
59 | .pagination ul > li:last-child > span {
60 | .border-right-radius(@baseBorderRadius);
61 | }
62 |
63 |
64 | // Alignment
65 | // --------------------------------------------------
66 |
67 | .pagination-centered {
68 | text-align: center;
69 | }
70 | .pagination-right {
71 | text-align: right;
72 | }
73 |
74 |
75 | // Sizing
76 | // --------------------------------------------------
77 |
78 | // Large
79 | .pagination-large {
80 | ul > li > a,
81 | ul > li > span {
82 | padding: @paddingLarge;
83 | font-size: @fontSizeLarge;
84 | }
85 | ul > li:first-child > a,
86 | ul > li:first-child > span {
87 | .border-left-radius(@borderRadiusLarge);
88 | }
89 | ul > li:last-child > a,
90 | ul > li:last-child > span {
91 | .border-right-radius(@borderRadiusLarge);
92 | }
93 | }
94 |
95 | // Small and mini
96 | .pagination-mini,
97 | .pagination-small {
98 | ul > li:first-child > a,
99 | ul > li:first-child > span {
100 | .border-left-radius(@borderRadiusSmall);
101 | }
102 | ul > li:last-child > a,
103 | ul > li:last-child > span {
104 | .border-right-radius(@borderRadiusSmall);
105 | }
106 | }
107 |
108 | // Small
109 | .pagination-small {
110 | ul > li > a,
111 | ul > li > span {
112 | padding: @paddingSmall;
113 | font-size: @fontSizeSmall;
114 | }
115 | }
116 | // Mini
117 | .pagination-mini {
118 | ul > li > a,
119 | ul > li > span {
120 | padding: @paddingMini;
121 | font-size: @fontSizeMini;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/popovers.less:
--------------------------------------------------------------------------------
1 | //
2 | // Popovers
3 | // --------------------------------------------------
4 |
5 |
6 | .popover {
7 | position: absolute;
8 | top: 0;
9 | left: 0;
10 | z-index: @zindexPopover;
11 | display: none;
12 | max-width: 276px;
13 | padding: 1px;
14 | text-align: left; // Reset given new insertion method
15 | background-color: @popoverBackground;
16 | -webkit-background-clip: padding-box;
17 | -moz-background-clip: padding;
18 | background-clip: padding-box;
19 | border: 1px solid #ccc;
20 | border: 1px solid rgba(0,0,0,.2);
21 | .border-radius(6px);
22 | .box-shadow(0 5px 10px rgba(0,0,0,.2));
23 |
24 | // Overrides for proper insertion
25 | white-space: normal;
26 |
27 | // Offset the popover to account for the popover arrow
28 | &.top { margin-top: -10px; }
29 | &.right { margin-left: 10px; }
30 | &.bottom { margin-top: 10px; }
31 | &.left { margin-left: -10px; }
32 | }
33 |
34 | .popover-title {
35 | margin: 0; // reset heading margin
36 | padding: 8px 14px;
37 | font-size: 14px;
38 | font-weight: normal;
39 | line-height: 18px;
40 | background-color: @popoverTitleBackground;
41 | border-bottom: 1px solid darken(@popoverTitleBackground, 5%);
42 | .border-radius(5px 5px 0 0);
43 |
44 | &:empty {
45 | display: none;
46 | }
47 | }
48 |
49 | .popover-content {
50 | padding: 9px 14px;
51 | }
52 |
53 | // Arrows
54 | //
55 | // .arrow is outer, .arrow:after is inner
56 |
57 | .popover .arrow,
58 | .popover .arrow:after {
59 | position: absolute;
60 | display: block;
61 | width: 0;
62 | height: 0;
63 | border-color: transparent;
64 | border-style: solid;
65 | }
66 | .popover .arrow {
67 | border-width: @popoverArrowOuterWidth;
68 | }
69 | .popover .arrow:after {
70 | border-width: @popoverArrowWidth;
71 | content: "";
72 | }
73 |
74 | .popover {
75 | &.top .arrow {
76 | left: 50%;
77 | margin-left: -@popoverArrowOuterWidth;
78 | border-bottom-width: 0;
79 | border-top-color: #999; // IE8 fallback
80 | border-top-color: @popoverArrowOuterColor;
81 | bottom: -@popoverArrowOuterWidth;
82 | &:after {
83 | bottom: 1px;
84 | margin-left: -@popoverArrowWidth;
85 | border-bottom-width: 0;
86 | border-top-color: @popoverArrowColor;
87 | }
88 | }
89 | &.right .arrow {
90 | top: 50%;
91 | left: -@popoverArrowOuterWidth;
92 | margin-top: -@popoverArrowOuterWidth;
93 | border-left-width: 0;
94 | border-right-color: #999; // IE8 fallback
95 | border-right-color: @popoverArrowOuterColor;
96 | &:after {
97 | left: 1px;
98 | bottom: -@popoverArrowWidth;
99 | border-left-width: 0;
100 | border-right-color: @popoverArrowColor;
101 | }
102 | }
103 | &.bottom .arrow {
104 | left: 50%;
105 | margin-left: -@popoverArrowOuterWidth;
106 | border-top-width: 0;
107 | border-bottom-color: #999; // IE8 fallback
108 | border-bottom-color: @popoverArrowOuterColor;
109 | top: -@popoverArrowOuterWidth;
110 | &:after {
111 | top: 1px;
112 | margin-left: -@popoverArrowWidth;
113 | border-top-width: 0;
114 | border-bottom-color: @popoverArrowColor;
115 | }
116 | }
117 |
118 | &.left .arrow {
119 | top: 50%;
120 | right: -@popoverArrowOuterWidth;
121 | margin-top: -@popoverArrowOuterWidth;
122 | border-right-width: 0;
123 | border-left-color: #999; // IE8 fallback
124 | border-left-color: @popoverArrowOuterColor;
125 | &:after {
126 | right: 1px;
127 | border-right-width: 0;
128 | border-left-color: @popoverArrowColor;
129 | bottom: -@popoverArrowWidth;
130 | }
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/progress-bars.less:
--------------------------------------------------------------------------------
1 | //
2 | // Progress bars
3 | // --------------------------------------------------
4 |
5 |
6 | // ANIMATIONS
7 | // ----------
8 |
9 | // Webkit
10 | @-webkit-keyframes progress-bar-stripes {
11 | from { background-position: 40px 0; }
12 | to { background-position: 0 0; }
13 | }
14 |
15 | // Firefox
16 | @-moz-keyframes progress-bar-stripes {
17 | from { background-position: 40px 0; }
18 | to { background-position: 0 0; }
19 | }
20 |
21 | // IE9
22 | @-ms-keyframes progress-bar-stripes {
23 | from { background-position: 40px 0; }
24 | to { background-position: 0 0; }
25 | }
26 |
27 | // Opera
28 | @-o-keyframes progress-bar-stripes {
29 | from { background-position: 0 0; }
30 | to { background-position: 40px 0; }
31 | }
32 |
33 | // Spec
34 | @keyframes progress-bar-stripes {
35 | from { background-position: 40px 0; }
36 | to { background-position: 0 0; }
37 | }
38 |
39 |
40 |
41 | // THE BARS
42 | // --------
43 |
44 | // Outer container
45 | .progress {
46 | overflow: hidden;
47 | height: @baseLineHeight;
48 | margin-bottom: @baseLineHeight;
49 | #gradient > .vertical(#f5f5f5, #f9f9f9);
50 | .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
51 | .border-radius(@baseBorderRadius);
52 | }
53 |
54 | // Bar of progress
55 | .progress .bar {
56 | width: 0%;
57 | height: 100%;
58 | color: @white;
59 | float: left;
60 | font-size: 12px;
61 | text-align: center;
62 | text-shadow: 0 -1px 0 rgba(0,0,0,.25);
63 | #gradient > .vertical(#149bdf, #0480be);
64 | .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
65 | .box-sizing(border-box);
66 | .transition(width .6s ease);
67 | }
68 | .progress .bar + .bar {
69 | .box-shadow(~"inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)");
70 | }
71 |
72 | // Striped bars
73 | .progress-striped .bar {
74 | #gradient > .striped(#149bdf);
75 | .background-size(40px 40px);
76 | }
77 |
78 | // Call animation for the active one
79 | .progress.active .bar {
80 | -webkit-animation: progress-bar-stripes 2s linear infinite;
81 | -moz-animation: progress-bar-stripes 2s linear infinite;
82 | -ms-animation: progress-bar-stripes 2s linear infinite;
83 | -o-animation: progress-bar-stripes 2s linear infinite;
84 | animation: progress-bar-stripes 2s linear infinite;
85 | }
86 |
87 |
88 |
89 | // COLORS
90 | // ------
91 |
92 | // Danger (red)
93 | .progress-danger .bar, .progress .bar-danger {
94 | #gradient > .vertical(#ee5f5b, #c43c35);
95 | }
96 | .progress-danger.progress-striped .bar, .progress-striped .bar-danger {
97 | #gradient > .striped(#ee5f5b);
98 | }
99 |
100 | // Success (green)
101 | .progress-success .bar, .progress .bar-success {
102 | #gradient > .vertical(#62c462, #57a957);
103 | }
104 | .progress-success.progress-striped .bar, .progress-striped .bar-success {
105 | #gradient > .striped(#62c462);
106 | }
107 |
108 | // Info (teal)
109 | .progress-info .bar, .progress .bar-info {
110 | #gradient > .vertical(#5bc0de, #339bb9);
111 | }
112 | .progress-info.progress-striped .bar, .progress-striped .bar-info {
113 | #gradient > .striped(#5bc0de);
114 | }
115 |
116 | // Warning (orange)
117 | .progress-warning .bar, .progress .bar-warning {
118 | #gradient > .vertical(lighten(@orange, 15%), @orange);
119 | }
120 | .progress-warning.progress-striped .bar, .progress-striped .bar-warning {
121 | #gradient > .striped(lighten(@orange, 15%));
122 | }
123 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/reset.less:
--------------------------------------------------------------------------------
1 | //
2 | // Reset CSS
3 | // Adapted from http://github.com/necolas/normalize.css
4 | // --------------------------------------------------
5 |
6 |
7 | // Display in IE6-9 and FF3
8 | // -------------------------
9 |
10 | article,
11 | aside,
12 | details,
13 | figcaption,
14 | figure,
15 | footer,
16 | header,
17 | hgroup,
18 | nav,
19 | section {
20 | display: block;
21 | }
22 |
23 | // Display block in IE6-9 and FF3
24 | // -------------------------
25 |
26 | audio,
27 | canvas,
28 | video {
29 | display: inline-block;
30 | *display: inline;
31 | *zoom: 1;
32 | }
33 |
34 | // Prevents modern browsers from displaying 'audio' without controls
35 | // -------------------------
36 |
37 | audio:not([controls]) {
38 | display: none;
39 | }
40 |
41 | // Base settings
42 | // -------------------------
43 |
44 | html {
45 | font-size: 100%;
46 | -webkit-text-size-adjust: 100%;
47 | -ms-text-size-adjust: 100%;
48 | }
49 | // Focus states
50 | a:focus {
51 | .tab-focus();
52 | }
53 | // Hover & Active
54 | a:hover,
55 | a:active {
56 | outline: 0;
57 | }
58 |
59 | // Prevents sub and sup affecting line-height in all browsers
60 | // -------------------------
61 |
62 | sub,
63 | sup {
64 | position: relative;
65 | font-size: 75%;
66 | line-height: 0;
67 | vertical-align: baseline;
68 | }
69 | sup {
70 | top: -0.5em;
71 | }
72 | sub {
73 | bottom: -0.25em;
74 | }
75 |
76 | // Img border in a's and image quality
77 | // -------------------------
78 |
79 | img {
80 | /* Responsive images (ensure images don't scale beyond their parents) */
81 | max-width: 100%; /* Part 1: Set a maxium relative to the parent */
82 | width: auto\9; /* IE7-8 need help adjusting responsive images */
83 | height: auto; /* Part 2: Scale the height according to the width, otherwise you get stretching */
84 |
85 | vertical-align: middle;
86 | border: 0;
87 | -ms-interpolation-mode: bicubic;
88 | }
89 |
90 | // Prevent max-width from affecting Google Maps
91 | #map_canvas img,
92 | .google-maps img {
93 | max-width: none;
94 | }
95 |
96 | // Forms
97 | // -------------------------
98 |
99 | // Font size in all browsers, margin changes, misc consistency
100 | button,
101 | input,
102 | select,
103 | textarea {
104 | margin: 0;
105 | font-size: 100%;
106 | vertical-align: middle;
107 | }
108 | button,
109 | input {
110 | *overflow: visible; // Inner spacing ie IE6/7
111 | line-height: normal; // FF3/4 have !important on line-height in UA stylesheet
112 | }
113 | button::-moz-focus-inner,
114 | input::-moz-focus-inner { // Inner padding and border oddities in FF3/4
115 | padding: 0;
116 | border: 0;
117 | }
118 | button,
119 | html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls.
120 | input[type="reset"],
121 | input[type="submit"] {
122 | -webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS.
123 | cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others.
124 | }
125 | label,
126 | select,
127 | button,
128 | input[type="button"],
129 | input[type="reset"],
130 | input[type="submit"],
131 | input[type="radio"],
132 | input[type="checkbox"] {
133 | cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others.
134 | }
135 | input[type="search"] { // Appearance in Safari/Chrome
136 | .box-sizing(content-box);
137 | -webkit-appearance: textfield;
138 | }
139 | input[type="search"]::-webkit-search-decoration,
140 | input[type="search"]::-webkit-search-cancel-button {
141 | -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5
142 | }
143 | textarea {
144 | overflow: auto; // Remove vertical scrollbar in IE6-9
145 | vertical-align: top; // Readability and alignment cross-browser
146 | }
147 |
148 |
149 | // Printing
150 | // -------------------------
151 | // Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css
152 |
153 | @media print {
154 |
155 | * {
156 | text-shadow: none !important;
157 | color: #000 !important; // Black prints faster: h5bp.com/s
158 | background: transparent !important;
159 | box-shadow: none !important;
160 | }
161 |
162 | a,
163 | a:visited {
164 | text-decoration: underline;
165 | }
166 |
167 | a[href]:after {
168 | content: " (" attr(href) ")";
169 | }
170 |
171 | abbr[title]:after {
172 | content: " (" attr(title) ")";
173 | }
174 |
175 | // Don't show links for images, or javascript/internal links
176 | .ir a:after,
177 | a[href^="javascript:"]:after,
178 | a[href^="#"]:after {
179 | content: "";
180 | }
181 |
182 | pre,
183 | blockquote {
184 | border: 1px solid #999;
185 | page-break-inside: avoid;
186 | }
187 |
188 | thead {
189 | display: table-header-group; // h5bp.com/t
190 | }
191 |
192 | tr,
193 | img {
194 | page-break-inside: avoid;
195 | }
196 |
197 | img {
198 | max-width: 100% !important;
199 | }
200 |
201 | @page {
202 | margin: 0.5cm;
203 | }
204 |
205 | p,
206 | h2,
207 | h3 {
208 | orphans: 3;
209 | widows: 3;
210 | }
211 |
212 | h2,
213 | h3 {
214 | page-break-after: avoid;
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/responsive-1200px-min.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Large desktop and up
3 | // --------------------------------------------------
4 |
5 |
6 | @media (min-width: 1200px) {
7 |
8 | // Fixed grid
9 | #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200);
10 |
11 | // Fluid grid
12 | #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200);
13 |
14 | // Input grid
15 | #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200);
16 |
17 | // Thumbnails
18 | .thumbnails {
19 | margin-left: -@gridGutterWidth1200;
20 | }
21 | .thumbnails > li {
22 | margin-left: @gridGutterWidth1200;
23 | }
24 | .row-fluid .thumbnails {
25 | margin-left: 0;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/responsive-767px-max.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Landscape phone to desktop/tablet
3 | // --------------------------------------------------
4 |
5 |
6 | @media (max-width: 767px) {
7 |
8 | // Padding to set content in a bit
9 | body {
10 | padding-left: 20px;
11 | padding-right: 20px;
12 | }
13 | // Negative indent the now static "fixed" navbar
14 | .navbar-fixed-top,
15 | .navbar-fixed-bottom,
16 | .navbar-static-top {
17 | margin-left: -20px;
18 | margin-right: -20px;
19 | }
20 | // Remove padding on container given explicit padding set on body
21 | .container-fluid {
22 | padding: 0;
23 | }
24 |
25 | // TYPOGRAPHY
26 | // ----------
27 | // Reset horizontal dl
28 | .dl-horizontal {
29 | dt {
30 | float: none;
31 | clear: none;
32 | width: auto;
33 | text-align: left;
34 | }
35 | dd {
36 | margin-left: 0;
37 | }
38 | }
39 |
40 | // GRID & CONTAINERS
41 | // -----------------
42 | // Remove width from containers
43 | .container {
44 | width: auto;
45 | }
46 | // Fluid rows
47 | .row-fluid {
48 | width: 100%;
49 | }
50 | // Undo negative margin on rows and thumbnails
51 | .row,
52 | .thumbnails {
53 | margin-left: 0;
54 | }
55 | .thumbnails > li {
56 | float: none;
57 | margin-left: 0; // Reset the default margin for all li elements when no .span* classes are present
58 | }
59 | // Make all grid-sized elements block level again
60 | [class*="span"],
61 | .uneditable-input[class*="span"], // Makes uneditable inputs full-width when using grid sizing
62 | .row-fluid [class*="span"] {
63 | float: none;
64 | display: block;
65 | width: 100%;
66 | margin-left: 0;
67 | .box-sizing(border-box);
68 | }
69 | .span12,
70 | .row-fluid .span12 {
71 | width: 100%;
72 | .box-sizing(border-box);
73 | }
74 | .row-fluid [class*="offset"]:first-child {
75 | margin-left: 0;
76 | }
77 |
78 | // FORM FIELDS
79 | // -----------
80 | // Make span* classes full width
81 | .input-large,
82 | .input-xlarge,
83 | .input-xxlarge,
84 | input[class*="span"],
85 | select[class*="span"],
86 | textarea[class*="span"],
87 | .uneditable-input {
88 | .input-block-level();
89 | }
90 | // But don't let it screw up prepend/append inputs
91 | .input-prepend input,
92 | .input-append input,
93 | .input-prepend input[class*="span"],
94 | .input-append input[class*="span"] {
95 | display: inline-block; // redeclare so they don't wrap to new lines
96 | width: auto;
97 | }
98 | .controls-row [class*="span"] + [class*="span"] {
99 | margin-left: 0;
100 | }
101 |
102 | // Modals
103 | .modal {
104 | position: fixed;
105 | top: 20px;
106 | left: 20px;
107 | right: 20px;
108 | width: auto;
109 | margin: 0;
110 | &.fade { top: -100px; }
111 | &.fade.in { top: 20px; }
112 | }
113 |
114 | }
115 |
116 |
117 |
118 | // UP TO LANDSCAPE PHONE
119 | // ---------------------
120 |
121 | @media (max-width: 480px) {
122 |
123 | // Smooth out the collapsing/expanding nav
124 | .nav-collapse {
125 | -webkit-transform: translate3d(0, 0, 0); // activate the GPU
126 | }
127 |
128 | // Block level the page header small tag for readability
129 | .page-header h1 small {
130 | display: block;
131 | line-height: @baseLineHeight;
132 | }
133 |
134 | // Update checkboxes for iOS
135 | input[type="checkbox"],
136 | input[type="radio"] {
137 | border: 1px solid #ccc;
138 | }
139 |
140 | // Remove the horizontal form styles
141 | .form-horizontal {
142 | .control-label {
143 | float: none;
144 | width: auto;
145 | padding-top: 0;
146 | text-align: left;
147 | }
148 | // Move over all input controls and content
149 | .controls {
150 | margin-left: 0;
151 | }
152 | // Move the options list down to align with labels
153 | .control-list {
154 | padding-top: 0; // has to be padding because margin collaspes
155 | }
156 | // Move over buttons in .form-actions to align with .controls
157 | .form-actions {
158 | padding-left: 10px;
159 | padding-right: 10px;
160 | }
161 | }
162 |
163 | // Medias
164 | // Reset float and spacing to stack
165 | .media .pull-left,
166 | .media .pull-right {
167 | float: none;
168 | display: block;
169 | margin-bottom: 10px;
170 | }
171 | // Remove side margins since we stack instead of indent
172 | .media-object {
173 | margin-right: 0;
174 | margin-left: 0;
175 | }
176 |
177 | // Modals
178 | .modal {
179 | top: 10px;
180 | left: 10px;
181 | right: 10px;
182 | }
183 | .modal-header .close {
184 | padding: 10px;
185 | margin: -10px;
186 | }
187 |
188 | // Carousel
189 | .carousel-caption {
190 | position: static;
191 | }
192 |
193 | }
194 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/responsive-768px-979px.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Tablet to desktop
3 | // --------------------------------------------------
4 |
5 |
6 | @media (min-width: 768px) and (max-width: 979px) {
7 |
8 | // Fixed grid
9 | #grid > .core(@gridColumnWidth768, @gridGutterWidth768);
10 |
11 | // Fluid grid
12 | #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768);
13 |
14 | // Input grid
15 | #grid > .input(@gridColumnWidth768, @gridGutterWidth768);
16 |
17 | // No need to reset .thumbnails here since it's the same @gridGutterWidth
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/responsive-navbar.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Navbar
3 | // --------------------------------------------------
4 |
5 |
6 | // TABLETS AND BELOW
7 | // -----------------
8 | @media (max-width: @navbarCollapseWidth) {
9 |
10 | // UNFIX THE TOPBAR
11 | // ----------------
12 | // Remove any padding from the body
13 | body {
14 | padding-top: 0;
15 | }
16 | // Unfix the navbars
17 | .navbar-fixed-top,
18 | .navbar-fixed-bottom {
19 | position: static;
20 | }
21 | .navbar-fixed-top {
22 | margin-bottom: @baseLineHeight;
23 | }
24 | .navbar-fixed-bottom {
25 | margin-top: @baseLineHeight;
26 | }
27 | .navbar-fixed-top .navbar-inner,
28 | .navbar-fixed-bottom .navbar-inner {
29 | padding: 5px;
30 | }
31 | .navbar .container {
32 | width: auto;
33 | padding: 0;
34 | }
35 | // Account for brand name
36 | .navbar .brand {
37 | padding-left: 10px;
38 | padding-right: 10px;
39 | margin: 0 0 0 -5px;
40 | }
41 |
42 | // COLLAPSIBLE NAVBAR
43 | // ------------------
44 | // Nav collapse clears brand
45 | .nav-collapse {
46 | clear: both;
47 | }
48 | // Block-level the nav
49 | .nav-collapse .nav {
50 | float: none;
51 | margin: 0 0 (@baseLineHeight / 2);
52 | }
53 | .nav-collapse .nav > li {
54 | float: none;
55 | }
56 | .nav-collapse .nav > li > a {
57 | margin-bottom: 2px;
58 | }
59 | .nav-collapse .nav > .divider-vertical {
60 | display: none;
61 | }
62 | .nav-collapse .nav .nav-header {
63 | color: @navbarText;
64 | text-shadow: none;
65 | }
66 | // Nav and dropdown links in navbar
67 | .nav-collapse .nav > li > a,
68 | .nav-collapse .dropdown-menu a {
69 | padding: 9px 15px;
70 | font-weight: bold;
71 | color: @navbarLinkColor;
72 | .border-radius(3px);
73 | }
74 | // Buttons
75 | .nav-collapse .btn {
76 | padding: 4px 10px 4px;
77 | font-weight: normal;
78 | .border-radius(@baseBorderRadius);
79 | }
80 | .nav-collapse .dropdown-menu li + li a {
81 | margin-bottom: 2px;
82 | }
83 | .nav-collapse .nav > li > a:hover,
84 | .nav-collapse .nav > li > a:focus,
85 | .nav-collapse .dropdown-menu a:hover,
86 | .nav-collapse .dropdown-menu a:focus {
87 | background-color: @navbarBackground;
88 | }
89 | .navbar-inverse .nav-collapse .nav > li > a,
90 | .navbar-inverse .nav-collapse .dropdown-menu a {
91 | color: @navbarInverseLinkColor;
92 | }
93 | .navbar-inverse .nav-collapse .nav > li > a:hover,
94 | .navbar-inverse .nav-collapse .nav > li > a:focus,
95 | .navbar-inverse .nav-collapse .dropdown-menu a:hover,
96 | .navbar-inverse .nav-collapse .dropdown-menu a:focus {
97 | background-color: @navbarInverseBackground;
98 | }
99 | // Buttons in the navbar
100 | .nav-collapse.in .btn-group {
101 | margin-top: 5px;
102 | padding: 0;
103 | }
104 | // Dropdowns in the navbar
105 | .nav-collapse .dropdown-menu {
106 | position: static;
107 | top: auto;
108 | left: auto;
109 | float: none;
110 | display: none;
111 | max-width: none;
112 | margin: 0 15px;
113 | padding: 0;
114 | background-color: transparent;
115 | border: none;
116 | .border-radius(0);
117 | .box-shadow(none);
118 | }
119 | .nav-collapse .open > .dropdown-menu {
120 | display: block;
121 | }
122 |
123 | .nav-collapse .dropdown-menu:before,
124 | .nav-collapse .dropdown-menu:after {
125 | display: none;
126 | }
127 | .nav-collapse .dropdown-menu .divider {
128 | display: none;
129 | }
130 | .nav-collapse .nav > li > .dropdown-menu {
131 | &:before,
132 | &:after {
133 | display: none;
134 | }
135 | }
136 | // Forms in navbar
137 | .nav-collapse .navbar-form,
138 | .nav-collapse .navbar-search {
139 | float: none;
140 | padding: (@baseLineHeight / 2) 15px;
141 | margin: (@baseLineHeight / 2) 0;
142 | border-top: 1px solid @navbarBackground;
143 | border-bottom: 1px solid @navbarBackground;
144 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)");
145 | }
146 | .navbar-inverse .nav-collapse .navbar-form,
147 | .navbar-inverse .nav-collapse .navbar-search {
148 | border-top-color: @navbarInverseBackground;
149 | border-bottom-color: @navbarInverseBackground;
150 | }
151 | // Pull right (secondary) nav content
152 | .navbar .nav-collapse .nav.pull-right {
153 | float: none;
154 | margin-left: 0;
155 | }
156 | // Hide everything in the navbar save .brand and toggle button */
157 | .nav-collapse,
158 | .nav-collapse.collapse {
159 | overflow: hidden;
160 | height: 0;
161 | }
162 | // Navbar button
163 | .navbar .btn-navbar {
164 | display: block;
165 | }
166 |
167 | // STATIC NAVBAR
168 | // -------------
169 | .navbar-static .navbar-inner {
170 | padding-left: 10px;
171 | padding-right: 10px;
172 | }
173 |
174 |
175 | }
176 |
177 |
178 | // DEFAULT DESKTOP
179 | // ---------------
180 |
181 | @media (min-width: @navbarCollapseDesktopWidth) {
182 |
183 | // Required to make the collapsing navbar work on regular desktops
184 | .nav-collapse.collapse {
185 | height: auto !important;
186 | overflow: visible !important;
187 | }
188 |
189 | }
190 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/responsive-utilities.less:
--------------------------------------------------------------------------------
1 | //
2 | // Responsive: Utility classes
3 | // --------------------------------------------------
4 |
5 |
6 | // IE10 Metro responsive
7 | // Required for Windows 8 Metro split-screen snapping with IE10
8 | // Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/
9 | @-ms-viewport{
10 | width: device-width;
11 | }
12 |
13 | // Hide from screenreaders and browsers
14 | // Credit: HTML5 Boilerplate
15 | .hidden {
16 | display: none;
17 | visibility: hidden;
18 | }
19 |
20 | // Visibility utilities
21 |
22 | // For desktops
23 | .visible-phone { display: none !important; }
24 | .visible-tablet { display: none !important; }
25 | .hidden-phone { }
26 | .hidden-tablet { }
27 | .hidden-desktop { display: none !important; }
28 | .visible-desktop { display: inherit !important; }
29 |
30 | // Tablets & small desktops only
31 | @media (min-width: 768px) and (max-width: 979px) {
32 | // Hide everything else
33 | .hidden-desktop { display: inherit !important; }
34 | .visible-desktop { display: none !important ; }
35 | // Show
36 | .visible-tablet { display: inherit !important; }
37 | // Hide
38 | .hidden-tablet { display: none !important; }
39 | }
40 |
41 | // Phones only
42 | @media (max-width: 767px) {
43 | // Hide everything else
44 | .hidden-desktop { display: inherit !important; }
45 | .visible-desktop { display: none !important; }
46 | // Show
47 | .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior
48 | // Hide
49 | .hidden-phone { display: none !important; }
50 | }
51 |
52 | // Print utilities
53 | .visible-print { display: none !important; }
54 | .hidden-print { }
55 |
56 | @media print {
57 | .visible-print { display: inherit !important; }
58 | .hidden-print { display: none !important; }
59 | }
60 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/responsive.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Responsive v2.3.1
3 | *
4 | * Copyright 2012 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world @twitter by @mdo and @fat.
9 | */
10 |
11 |
12 | // Responsive.less
13 | // For phone and tablet devices
14 | // -------------------------------------------------------------
15 |
16 |
17 | // REPEAT VARIABLES & MIXINS
18 | // -------------------------
19 | // Required since we compile the responsive stuff separately
20 |
21 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc
22 | @import "mixins.less";
23 |
24 |
25 | // RESPONSIVE CLASSES
26 | // ------------------
27 |
28 | @import "responsive-utilities.less";
29 |
30 |
31 | // MEDIA QUERIES
32 | // ------------------
33 |
34 | // Large desktops
35 | @import "responsive-1200px-min.less";
36 |
37 | // Tablets to regular desktops
38 | @import "responsive-768px-979px.less";
39 |
40 | // Phones to portrait tablets and narrow desktops
41 | @import "responsive-767px-max.less";
42 |
43 |
44 | // RESPONSIVE NAVBAR
45 | // ------------------
46 |
47 | // From 979px and below, show a button to toggle navbar contents
48 | @import "responsive-navbar.less";
49 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/scaffolding.less:
--------------------------------------------------------------------------------
1 | //
2 | // Scaffolding
3 | // --------------------------------------------------
4 |
5 |
6 | // Body reset
7 | // -------------------------
8 |
9 | body {
10 | margin: 0;
11 | font-family: @baseFontFamily;
12 | font-size: @baseFontSize;
13 | line-height: @baseLineHeight;
14 | color: @textColor;
15 | background-color: @bodyBackground;
16 | }
17 |
18 |
19 | // Links
20 | // -------------------------
21 |
22 | a {
23 | color: @linkColor;
24 | text-decoration: none;
25 | }
26 | a:hover,
27 | a:focus {
28 | color: @linkColorHover;
29 | text-decoration: underline;
30 | }
31 |
32 |
33 | // Images
34 | // -------------------------
35 |
36 | // Rounded corners
37 | .img-rounded {
38 | .border-radius(6px);
39 | }
40 |
41 | // Add polaroid-esque trim
42 | .img-polaroid {
43 | padding: 4px;
44 | background-color: #fff;
45 | border: 1px solid #ccc;
46 | border: 1px solid rgba(0,0,0,.2);
47 | .box-shadow(0 1px 3px rgba(0,0,0,.1));
48 | }
49 |
50 | // Perfect circle
51 | .img-circle {
52 | .border-radius(500px); // crank the border-radius so it works with most reasonably sized images
53 | }
54 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/tables.less:
--------------------------------------------------------------------------------
1 | //
2 | // Tables
3 | // --------------------------------------------------
4 |
5 |
6 | // BASE TABLES
7 | // -----------------
8 |
9 | table {
10 | max-width: 100%;
11 | background-color: @tableBackground;
12 | border-collapse: collapse;
13 | border-spacing: 0;
14 | }
15 |
16 | // BASELINE STYLES
17 | // ---------------
18 |
19 | .table {
20 | width: 100%;
21 | margin-bottom: @baseLineHeight;
22 | // Cells
23 | th,
24 | td {
25 | padding: 8px;
26 | line-height: @baseLineHeight;
27 | text-align: left;
28 | vertical-align: top;
29 | border-top: 1px solid @tableBorder;
30 | }
31 | th {
32 | font-weight: bold;
33 | }
34 | // Bottom align for column headings
35 | thead th {
36 | vertical-align: bottom;
37 | }
38 | // Remove top border from thead by default
39 | caption + thead tr:first-child th,
40 | caption + thead tr:first-child td,
41 | colgroup + thead tr:first-child th,
42 | colgroup + thead tr:first-child td,
43 | thead:first-child tr:first-child th,
44 | thead:first-child tr:first-child td {
45 | border-top: 0;
46 | }
47 | // Account for multiple tbody instances
48 | tbody + tbody {
49 | border-top: 2px solid @tableBorder;
50 | }
51 |
52 | // Nesting
53 | .table {
54 | background-color: @bodyBackground;
55 | }
56 | }
57 |
58 |
59 |
60 | // CONDENSED TABLE W/ HALF PADDING
61 | // -------------------------------
62 |
63 | .table-condensed {
64 | th,
65 | td {
66 | padding: 4px 5px;
67 | }
68 | }
69 |
70 |
71 | // BORDERED VERSION
72 | // ----------------
73 |
74 | .table-bordered {
75 | border: 1px solid @tableBorder;
76 | border-collapse: separate; // Done so we can round those corners!
77 | *border-collapse: collapse; // IE7 can't round corners anyway
78 | border-left: 0;
79 | .border-radius(@baseBorderRadius);
80 | th,
81 | td {
82 | border-left: 1px solid @tableBorder;
83 | }
84 | // Prevent a double border
85 | caption + thead tr:first-child th,
86 | caption + tbody tr:first-child th,
87 | caption + tbody tr:first-child td,
88 | colgroup + thead tr:first-child th,
89 | colgroup + tbody tr:first-child th,
90 | colgroup + tbody tr:first-child td,
91 | thead:first-child tr:first-child th,
92 | tbody:first-child tr:first-child th,
93 | tbody:first-child tr:first-child td {
94 | border-top: 0;
95 | }
96 | // For first th/td in the first row in the first thead or tbody
97 | thead:first-child tr:first-child > th:first-child,
98 | tbody:first-child tr:first-child > td:first-child,
99 | tbody:first-child tr:first-child > th:first-child {
100 | .border-top-left-radius(@baseBorderRadius);
101 | }
102 | // For last th/td in the first row in the first thead or tbody
103 | thead:first-child tr:first-child > th:last-child,
104 | tbody:first-child tr:first-child > td:last-child,
105 | tbody:first-child tr:first-child > th:last-child {
106 | .border-top-right-radius(@baseBorderRadius);
107 | }
108 | // For first th/td (can be either) in the last row in the last thead, tbody, and tfoot
109 | thead:last-child tr:last-child > th:first-child,
110 | tbody:last-child tr:last-child > td:first-child,
111 | tbody:last-child tr:last-child > th:first-child,
112 | tfoot:last-child tr:last-child > td:first-child,
113 | tfoot:last-child tr:last-child > th:first-child {
114 | .border-bottom-left-radius(@baseBorderRadius);
115 | }
116 | // For last th/td (can be either) in the last row in the last thead, tbody, and tfoot
117 | thead:last-child tr:last-child > th:last-child,
118 | tbody:last-child tr:last-child > td:last-child,
119 | tbody:last-child tr:last-child > th:last-child,
120 | tfoot:last-child tr:last-child > td:last-child,
121 | tfoot:last-child tr:last-child > th:last-child {
122 | .border-bottom-right-radius(@baseBorderRadius);
123 | }
124 |
125 | // Clear border-radius for first and last td in the last row in the last tbody for table with tfoot
126 | tfoot + tbody:last-child tr:last-child td:first-child {
127 | .border-bottom-left-radius(0);
128 | }
129 | tfoot + tbody:last-child tr:last-child td:last-child {
130 | .border-bottom-right-radius(0);
131 | }
132 |
133 | // Special fixes to round the left border on the first td/th
134 | caption + thead tr:first-child th:first-child,
135 | caption + tbody tr:first-child td:first-child,
136 | colgroup + thead tr:first-child th:first-child,
137 | colgroup + tbody tr:first-child td:first-child {
138 | .border-top-left-radius(@baseBorderRadius);
139 | }
140 | caption + thead tr:first-child th:last-child,
141 | caption + tbody tr:first-child td:last-child,
142 | colgroup + thead tr:first-child th:last-child,
143 | colgroup + tbody tr:first-child td:last-child {
144 | .border-top-right-radius(@baseBorderRadius);
145 | }
146 |
147 | }
148 |
149 |
150 |
151 |
152 | // ZEBRA-STRIPING
153 | // --------------
154 |
155 | // Default zebra-stripe styles (alternating gray and transparent backgrounds)
156 | .table-striped {
157 | tbody {
158 | > tr:nth-child(odd) > td,
159 | > tr:nth-child(odd) > th {
160 | background-color: @tableBackgroundAccent;
161 | }
162 | }
163 | }
164 |
165 |
166 | // HOVER EFFECT
167 | // ------------
168 | // Placed here since it has to come after the potential zebra striping
169 | .table-hover {
170 | tbody {
171 | tr:hover > td,
172 | tr:hover > th {
173 | background-color: @tableBackgroundHover;
174 | }
175 | }
176 | }
177 |
178 |
179 | // TABLE CELL SIZING
180 | // -----------------
181 |
182 | // Reset default grid behavior
183 | table td[class*="span"],
184 | table th[class*="span"],
185 | .row-fluid table td[class*="span"],
186 | .row-fluid table th[class*="span"] {
187 | display: table-cell;
188 | float: none; // undo default grid column styles
189 | margin-left: 0; // undo default grid column styles
190 | }
191 |
192 | // Change the column widths to account for td/th padding
193 | .table td,
194 | .table th {
195 | &.span1 { .tableColumns(1); }
196 | &.span2 { .tableColumns(2); }
197 | &.span3 { .tableColumns(3); }
198 | &.span4 { .tableColumns(4); }
199 | &.span5 { .tableColumns(5); }
200 | &.span6 { .tableColumns(6); }
201 | &.span7 { .tableColumns(7); }
202 | &.span8 { .tableColumns(8); }
203 | &.span9 { .tableColumns(9); }
204 | &.span10 { .tableColumns(10); }
205 | &.span11 { .tableColumns(11); }
206 | &.span12 { .tableColumns(12); }
207 | }
208 |
209 |
210 |
211 | // TABLE BACKGROUNDS
212 | // -----------------
213 | // Exact selectors below required to override .table-striped
214 |
215 | .table tbody tr {
216 | &.success > td {
217 | background-color: @successBackground;
218 | }
219 | &.error > td {
220 | background-color: @errorBackground;
221 | }
222 | &.warning > td {
223 | background-color: @warningBackground;
224 | }
225 | &.info > td {
226 | background-color: @infoBackground;
227 | }
228 | }
229 |
230 | // Hover states for .table-hover
231 | .table-hover tbody tr {
232 | &.success:hover > td {
233 | background-color: darken(@successBackground, 5%);
234 | }
235 | &.error:hover > td {
236 | background-color: darken(@errorBackground, 5%);
237 | }
238 | &.warning:hover > td {
239 | background-color: darken(@warningBackground, 5%);
240 | }
241 | &.info:hover > td {
242 | background-color: darken(@infoBackground, 5%);
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/thumbnails.less:
--------------------------------------------------------------------------------
1 | //
2 | // Thumbnails
3 | // --------------------------------------------------
4 |
5 |
6 | // Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files
7 |
8 | // Make wrapper ul behave like the grid
9 | .thumbnails {
10 | margin-left: -@gridGutterWidth;
11 | list-style: none;
12 | .clearfix();
13 | }
14 | // Fluid rows have no left margin
15 | .row-fluid .thumbnails {
16 | margin-left: 0;
17 | }
18 |
19 | // Float li to make thumbnails appear in a row
20 | .thumbnails > li {
21 | float: left; // Explicity set the float since we don't require .span* classes
22 | margin-bottom: @baseLineHeight;
23 | margin-left: @gridGutterWidth;
24 | }
25 |
26 | // The actual thumbnail (can be `a` or `div`)
27 | .thumbnail {
28 | display: block;
29 | padding: 4px;
30 | line-height: @baseLineHeight;
31 | border: 1px solid #ddd;
32 | .border-radius(@baseBorderRadius);
33 | .box-shadow(0 1px 3px rgba(0,0,0,.055));
34 | .transition(all .2s ease-in-out);
35 | }
36 | // Add a hover/focus state for linked versions only
37 | a.thumbnail:hover,
38 | a.thumbnail:focus {
39 | border-color: @linkColor;
40 | .box-shadow(0 1px 4px rgba(0,105,214,.25));
41 | }
42 |
43 | // Images and captions
44 | .thumbnail > img {
45 | display: block;
46 | max-width: 100%;
47 | margin-left: auto;
48 | margin-right: auto;
49 | }
50 | .thumbnail .caption {
51 | padding: 9px;
52 | color: @gray;
53 | }
54 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/tooltip.less:
--------------------------------------------------------------------------------
1 | //
2 | // Tooltips
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .tooltip {
8 | position: absolute;
9 | z-index: @zindexTooltip;
10 | display: block;
11 | visibility: visible;
12 | font-size: 11px;
13 | line-height: 1.4;
14 | .opacity(0);
15 | &.in { .opacity(80); }
16 | &.top { margin-top: -3px; padding: 5px 0; }
17 | &.right { margin-left: 3px; padding: 0 5px; }
18 | &.bottom { margin-top: 3px; padding: 5px 0; }
19 | &.left { margin-left: -3px; padding: 0 5px; }
20 | }
21 |
22 | // Wrapper for the tooltip content
23 | .tooltip-inner {
24 | max-width: 200px;
25 | padding: 8px;
26 | color: @tooltipColor;
27 | text-align: center;
28 | text-decoration: none;
29 | background-color: @tooltipBackground;
30 | .border-radius(@baseBorderRadius);
31 | }
32 |
33 | // Arrows
34 | .tooltip-arrow {
35 | position: absolute;
36 | width: 0;
37 | height: 0;
38 | border-color: transparent;
39 | border-style: solid;
40 | }
41 | .tooltip {
42 | &.top .tooltip-arrow {
43 | bottom: 0;
44 | left: 50%;
45 | margin-left: -@tooltipArrowWidth;
46 | border-width: @tooltipArrowWidth @tooltipArrowWidth 0;
47 | border-top-color: @tooltipArrowColor;
48 | }
49 | &.right .tooltip-arrow {
50 | top: 50%;
51 | left: 0;
52 | margin-top: -@tooltipArrowWidth;
53 | border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0;
54 | border-right-color: @tooltipArrowColor;
55 | }
56 | &.left .tooltip-arrow {
57 | top: 50%;
58 | right: 0;
59 | margin-top: -@tooltipArrowWidth;
60 | border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth;
61 | border-left-color: @tooltipArrowColor;
62 | }
63 | &.bottom .tooltip-arrow {
64 | top: 0;
65 | left: 50%;
66 | margin-left: -@tooltipArrowWidth;
67 | border-width: 0 @tooltipArrowWidth @tooltipArrowWidth;
68 | border-bottom-color: @tooltipArrowColor;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/type.less:
--------------------------------------------------------------------------------
1 | //
2 | // Typography
3 | // --------------------------------------------------
4 |
5 |
6 | // Body text
7 | // -------------------------
8 |
9 | p {
10 | margin: 0 0 @baseLineHeight / 2;
11 | }
12 | .lead {
13 | margin-bottom: @baseLineHeight;
14 | font-size: @baseFontSize * 1.5;
15 | font-weight: 200;
16 | line-height: @baseLineHeight * 1.5;
17 | }
18 |
19 |
20 | // Emphasis & misc
21 | // -------------------------
22 |
23 | // Ex: 14px base font * 85% = about 12px
24 | small { font-size: 85%; }
25 |
26 | strong { font-weight: bold; }
27 | em { font-style: italic; }
28 | cite { font-style: normal; }
29 |
30 | // Utility classes
31 | .muted { color: @grayLight; }
32 | a.muted:hover,
33 | a.muted:focus { color: darken(@grayLight, 10%); }
34 |
35 | .text-warning { color: @warningText; }
36 | a.text-warning:hover,
37 | a.text-warning:focus { color: darken(@warningText, 10%); }
38 |
39 | .text-error { color: @errorText; }
40 | a.text-error:hover,
41 | a.text-error:focus { color: darken(@errorText, 10%); }
42 |
43 | .text-info { color: @infoText; }
44 | a.text-info:hover,
45 | a.text-info:focus { color: darken(@infoText, 10%); }
46 |
47 | .text-success { color: @successText; }
48 | a.text-success:hover,
49 | a.text-success:focus { color: darken(@successText, 10%); }
50 |
51 | .text-left { text-align: left; }
52 | .text-right { text-align: right; }
53 | .text-center { text-align: center; }
54 |
55 |
56 | // Headings
57 | // -------------------------
58 |
59 | h1, h2, h3, h4, h5, h6 {
60 | margin: (@baseLineHeight / 2) 0;
61 | font-family: @headingsFontFamily;
62 | font-weight: @headingsFontWeight;
63 | line-height: @baseLineHeight;
64 | color: @headingsColor;
65 | text-rendering: optimizelegibility; // Fix the character spacing for headings
66 | small {
67 | font-weight: normal;
68 | line-height: 1;
69 | color: @grayLight;
70 | }
71 | }
72 |
73 | h1,
74 | h2,
75 | h3 { line-height: @baseLineHeight * 2; }
76 |
77 | h1 { font-size: @baseFontSize * 2.75; } // ~38px
78 | h2 { font-size: @baseFontSize * 2.25; } // ~32px
79 | h3 { font-size: @baseFontSize * 1.75; } // ~24px
80 | h4 { font-size: @baseFontSize * 1.25; } // ~18px
81 | h5 { font-size: @baseFontSize; }
82 | h6 { font-size: @baseFontSize * 0.85; } // ~12px
83 |
84 | h1 small { font-size: @baseFontSize * 1.75; } // ~24px
85 | h2 small { font-size: @baseFontSize * 1.25; } // ~18px
86 | h3 small { font-size: @baseFontSize; }
87 | h4 small { font-size: @baseFontSize; }
88 |
89 |
90 | // Page header
91 | // -------------------------
92 |
93 | .page-header {
94 | padding-bottom: (@baseLineHeight / 2) - 1;
95 | margin: @baseLineHeight 0 (@baseLineHeight * 1.5);
96 | border-bottom: 1px solid @grayLighter;
97 | }
98 |
99 |
100 |
101 | // Lists
102 | // --------------------------------------------------
103 |
104 | // Unordered and Ordered lists
105 | ul, ol {
106 | padding: 0;
107 | margin: 0 0 @baseLineHeight / 2 25px;
108 | }
109 | ul ul,
110 | ul ol,
111 | ol ol,
112 | ol ul {
113 | margin-bottom: 0;
114 | }
115 | li {
116 | line-height: @baseLineHeight;
117 | }
118 |
119 | // Remove default list styles
120 | ul.unstyled,
121 | ol.unstyled {
122 | margin-left: 0;
123 | list-style: none;
124 | }
125 |
126 | // Single-line list items
127 | ul.inline,
128 | ol.inline {
129 | margin-left: 0;
130 | list-style: none;
131 | > li {
132 | display: inline-block;
133 | .ie7-inline-block();
134 | padding-left: 5px;
135 | padding-right: 5px;
136 | }
137 | }
138 |
139 | // Description Lists
140 | dl {
141 | margin-bottom: @baseLineHeight;
142 | }
143 | dt,
144 | dd {
145 | line-height: @baseLineHeight;
146 | }
147 | dt {
148 | font-weight: bold;
149 | }
150 | dd {
151 | margin-left: @baseLineHeight / 2;
152 | }
153 | // Horizontal layout (like forms)
154 | .dl-horizontal {
155 | .clearfix(); // Ensure dl clears floats if empty dd elements present
156 | dt {
157 | float: left;
158 | width: @horizontalComponentOffset - 20;
159 | clear: left;
160 | text-align: right;
161 | .text-overflow();
162 | }
163 | dd {
164 | margin-left: @horizontalComponentOffset;
165 | }
166 | }
167 |
168 | // MISC
169 | // ----
170 |
171 | // Horizontal rules
172 | hr {
173 | margin: @baseLineHeight 0;
174 | border: 0;
175 | border-top: 1px solid @hrBorder;
176 | border-bottom: 1px solid @white;
177 | }
178 |
179 | // Abbreviations and acronyms
180 | abbr[title],
181 | // Added data-* attribute to help out our tooltip plugin, per https://github.com/twitter/bootstrap/issues/5257
182 | abbr[data-original-title] {
183 | cursor: help;
184 | border-bottom: 1px dotted @grayLight;
185 | }
186 | abbr.initialism {
187 | font-size: 90%;
188 | text-transform: uppercase;
189 | }
190 |
191 | // Blockquotes
192 | blockquote {
193 | padding: 0 0 0 15px;
194 | margin: 0 0 @baseLineHeight;
195 | border-left: 5px solid @grayLighter;
196 | p {
197 | margin-bottom: 0;
198 | font-size: @baseFontSize * 1.25;
199 | font-weight: 300;
200 | line-height: 1.25;
201 | }
202 | small {
203 | display: block;
204 | line-height: @baseLineHeight;
205 | color: @grayLight;
206 | &:before {
207 | content: '\2014 \00A0';
208 | }
209 | }
210 |
211 | // Float right with text-align: right
212 | &.pull-right {
213 | float: right;
214 | padding-right: 15px;
215 | padding-left: 0;
216 | border-right: 5px solid @grayLighter;
217 | border-left: 0;
218 | p,
219 | small {
220 | text-align: right;
221 | }
222 | small {
223 | &:before {
224 | content: '';
225 | }
226 | &:after {
227 | content: '\00A0 \2014';
228 | }
229 | }
230 | }
231 | }
232 |
233 | // Quotes
234 | q:before,
235 | q:after,
236 | blockquote:before,
237 | blockquote:after {
238 | content: "";
239 | }
240 |
241 | // Addresses
242 | address {
243 | display: block;
244 | margin-bottom: @baseLineHeight;
245 | font-style: normal;
246 | line-height: @baseLineHeight;
247 | }
248 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/utilities.less:
--------------------------------------------------------------------------------
1 | //
2 | // Utility classes
3 | // --------------------------------------------------
4 |
5 |
6 | // Quick floats
7 | .pull-right {
8 | float: right;
9 | }
10 | .pull-left {
11 | float: left;
12 | }
13 |
14 | // Toggling content
15 | .hide {
16 | display: none;
17 | }
18 | .show {
19 | display: block;
20 | }
21 |
22 | // Visibility
23 | .invisible {
24 | visibility: hidden;
25 | }
26 |
27 | // For Affix plugin
28 | .affix {
29 | position: fixed;
30 | }
31 |
--------------------------------------------------------------------------------
/WebContent/css/bootstrap/wells.less:
--------------------------------------------------------------------------------
1 | //
2 | // Wells
3 | // --------------------------------------------------
4 |
5 |
6 | // Base class
7 | .well {
8 | min-height: 20px;
9 | padding: 19px;
10 | margin-bottom: 20px;
11 | background-color: @wellBackground;
12 | border: 1px solid darken(@wellBackground, 7%);
13 | .border-radius(@baseBorderRadius);
14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
15 | blockquote {
16 | border-color: #ddd;
17 | border-color: rgba(0,0,0,.15);
18 | }
19 | }
20 |
21 | // Sizes
22 | .well-large {
23 | padding: 24px;
24 | .border-radius(@borderRadiusLarge);
25 | }
26 | .well-small {
27 | padding: 9px;
28 | .border-radius(@borderRadiusSmall);
29 | }
30 |
--------------------------------------------------------------------------------
/WebContent/css/custom/overrides.less:
--------------------------------------------------------------------------------
1 | @import "../bootstrap/variables.less";
2 | @import "../bootstrap/mixins.less";
3 |
4 | .navbar-fixed-top .navbar-inner,
5 | .navbar-fixed-bottom .navbar-inner {
6 | padding: 0;
7 | }
8 |
9 | .btn:focus, select:focus {
10 | outline: none;
11 | }
12 |
13 |
14 |
15 |
16 | .btn {
17 | display: inline-block;
18 | .ie7-inline-block();
19 | padding: 4px 12px;
20 | margin-bottom: 0; // For input.btn
21 | font-size: @baseFontSize;
22 | line-height: @baseLineHeight;
23 | text-align: center;
24 | vertical-align: middle;
25 | cursor: pointer;
26 | // .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75));
27 | background-image: none;
28 | .box-shadow(none);
29 | background-color: mix(@btnBackground, @btnBackgroundHighlight, 60%);
30 | // border: 1px solid @btnBorder;
31 | border: 1px solid mix(@btnBackground, @btnBackgroundHighlight, 60%);
32 | *border: 0; // Remove the border to prevent IE7's black border on input:focus
33 | // border-bottom-color: darken(@btnBorder, 10%);
34 | .border-radius(@baseBorderRadius);
35 | .ie7-restore-left-whitespace(); // Give IE7 some love
36 | // .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
37 |
38 | // Hover/focus state
39 | &:hover,
40 | &:focus {
41 | color: @grayDark;
42 | text-decoration: none;
43 | // background-position: 0 -15px;
44 |
45 | // transition is only when going to hover/focus, otherwise the background
46 | // behind the gradient (there for IE<=9 fallback) gets mismatched
47 | // .transition(background-position .1s linear);
48 | background-color: @btnBackgroundHighlight;
49 | border: 1px solid @btnBackgroundHighlight;
50 | }
51 |
52 | // Focus state for keyboard and accessibility
53 | &:focus {
54 |
55 | }
56 |
57 | // Active state
58 | &.active,
59 | &:active {
60 | background-image: none;
61 | outline: 0;
62 | .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
63 | }
64 |
65 | // Disabled state
66 | &.disabled,
67 | &[disabled] {
68 | cursor: default;
69 | background-image: none;
70 | .opacity(65);
71 | .box-shadow(none);
72 | }
73 |
74 | }
75 |
76 | .btn-success {
77 | color: white;
78 | // .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight);
79 | background-color: mix(@btnSuccessBackground, @btnSuccessBackgroundHighlight, 60%);
80 | // border: 1px solid @btnBorder;
81 | border: 1px solid mix(@btnSuccessBackground, @btnSuccessBackgroundHighlight, 60%);
82 | // Hover/focus state
83 | &:hover,
84 | &:focus {
85 | color: white;
86 | background-color: @btnSuccessBackgroundHighlight;
87 | border: 1px solid @btnSuccessBackgroundHighlight;
88 | }
89 | }
90 | .btn-danger {
91 | color: white;
92 | background-color: mix(@btnDangerBackground, @btnDangerBackgroundHighlight, 60%);
93 | border: 1px solid mix(@btnDangerBackground, @btnDangerBackgroundHighlight, 60%);
94 | // Hover/focus state
95 | &:hover,
96 | &:focus {
97 | color: white;
98 | background-color: @btnDangerBackgroundHighlight;
99 | border: 1px solid @btnDangerBackgroundHighlight;
100 | }
101 | }
102 |
103 |
104 |
105 | textarea,
106 | input[type="text"],
107 | input[type="password"],
108 | input[type="datetime"],
109 | input[type="datetime-local"],
110 | input[type="date"],
111 | input[type="month"],
112 | input[type="time"],
113 | input[type="week"],
114 | input[type="number"],
115 | input[type="email"],
116 | input[type="url"],
117 | input[type="search"],
118 | input[type="tel"],
119 | input[type="color"],
120 | .uneditable-input,
121 | .uneditable-textarea {
122 | .box-shadow(none);
123 | // This disables the "halo" effect on focus
124 | // &:focus {
125 | // .box-shadow(none);
126 | // }
127 | }
128 |
--------------------------------------------------------------------------------
/WebContent/css/custom/sprites.less:
--------------------------------------------------------------------------------
1 | // extract from bootstrap/sprites.less - include only what you need
2 | [class^="icon-"],
3 | [class*=" icon-"] {
4 | display: inline-block;
5 | width: 14px;
6 | height: 14px;
7 | // .ie7-restore-right-whitespace();
8 | line-height: 14px;
9 | vertical-align: text-top;
10 | background-image: url("@{iconSpritePath}");
11 | background-position: 14px 14px;
12 | background-repeat: no-repeat;
13 | margin-top: 1px;
14 | }
15 |
16 | .icon-edit { background-position: -96px -72px; }
17 | .icon-remove { background-position: -312px 0; }
18 | .icon-return { background-position: -48px -168px; }
19 | ///////////////////////////////////////////////////////////////////////////////
20 | ///////////////////////////////////////////////////////////////////////////////
21 | ///////////////////////////////////////////////////////////////////////////////
22 |
23 | .iconsetup(@dim,@path) {
24 | display: inline-block;
25 | width: @dim;
26 | height: @dim;
27 | line-height: @dim;
28 | vertical-align: text-top;
29 | background-image: url("@{path}");
30 | background-repeat: no-repeat;
31 | }
32 | .iconsm(@x, @y) {
33 | background-position: -@iconDimSm*@x -@iconDimSm*@y;
34 | }
35 | .iconlg(@x, @y) {
36 | background-position: -@iconDimLg*@x -@iconDimLg*@y;
37 | }
38 |
39 |
40 | [class^="iconsm-"],
41 | [class*=" iconsm-"] {
42 | .iconsetup(@iconDimSm,@iconSmSpritePath)
43 | }
44 | [class^="iconlg-"],
45 | [class*=" iconlg-"] {
46 | .iconsetup(@iconDimLg,@iconLgSpritePath)
47 | }
48 |
49 | .iconsm-back { .iconsm(@iconBackX,@iconBackY); }
50 | .iconlg-back { .iconlg(@iconBackX,@iconBackY); }
51 | .iconsm-x { .iconsm(@iconXX,@iconXY); }
52 | .iconlg-x { .iconlg(@iconXX,@iconXY); }
53 | .iconsm-trash { .iconsm(@iconTrashX,@iconTrashY); }
54 | .iconlg-trash { .iconlg(@iconTrashX,@iconTrashY); }
55 | .iconsm-pencil1 { .iconsm(@iconPencil1X,@iconPencil1Y); }
56 | .iconlg-pencil1 { .iconlg(@iconPencil1X,@iconPencil1Y); }
57 | .iconsm-pencil2 { .iconsm(@iconPencil2X,@iconPencil2Y); }
58 | .iconlg-pencil2 { .iconlg(@iconPencil2X,@iconPencil2Y); }
59 | .iconsm-pie { .iconsm(@iconPieX,@iconPieY); }
60 | .iconlg-pie { .iconlg(@iconPieX,@iconPieY); }
61 |
--------------------------------------------------------------------------------
/WebContent/css/custom/style-BAK1.less:
--------------------------------------------------------------------------------
1 | @import "../bootstrap/variables.less";
2 | @import "../bootstrap/mixins.less";
3 |
4 | body {
5 | padding-top: @navbarHeight;
6 | }
7 |
8 | label {
9 | display: inline-block;
10 | padding-left: @inputBorderRadius + 1px; // 1px for the border
11 | }
12 |
13 | .control-action {
14 | float: right;
15 | padding: 0 1px;
16 | opacity: 0;
17 | transition: opacity 0.3s;
18 | -webkit-transition: opacity 0.3s;
19 |
20 | &:hover {
21 | background-color: @textColor;
22 |
23 | i {
24 | background-image: url("@{iconWhiteSpritePath}");
25 | }
26 | }
27 | }
28 |
29 | .validation-msg {
30 | font-size: 0.8em;
31 | display: none;
32 | }
33 |
34 | .control-group {
35 | &:hover {
36 | .control-action {
37 | opacity: 1;
38 | }
39 | }
40 |
41 | &.error {
42 | input, textarea {
43 | padding-left: 25px;
44 | }
45 |
46 | .msg-ind {
47 | display: block;
48 | }
49 | }
50 |
51 | // &.required {
52 | // label:before {
53 | // content: "(*) ";
54 | // color: @infoText;
55 | // font-weight: bold;
56 | // }
57 | // }
58 | }
59 |
60 | .controls{
61 | position: relative;
62 | }
63 |
64 | @msgIndDimension: 18px;
65 | .msg-ind {
66 | background-image: url("../images/x_x5F_alt18.png");
67 | background-position: center center;
68 | // background-color: @inputBackground;
69 | background-repeat: no-repeat;
70 | width: @msgIndDimension;
71 | height: @msgIndDimension;
72 | position: absolute;
73 | left: 5px;
74 | top: (@inputHeight - @msgIndDimension) / 2;
75 | cursor: pointer;
76 | display: none;
77 | }
78 |
79 |
80 |
81 | @import "sprites.less";
82 |
--------------------------------------------------------------------------------
/WebContent/css/custom/style.less:
--------------------------------------------------------------------------------
1 | @import "../bootstrap/variables.less";
2 | @import "variables.less";
3 | @import "../bootstrap/mixins.less";
4 |
5 | body {
6 | padding-top: @navbarHeight;
7 | }
8 |
9 | label {
10 | display: inline-block;
11 | padding-left: @inputBorderRadius + 1px; // 1px for the border
12 | }
13 |
14 | .control-action {
15 | float: right;
16 | padding: 0 1px;
17 | // opacity: 0;
18 | .transition(opacity 0.3s);
19 |
20 | &:hover {
21 | background-color: @textColor;
22 |
23 | i {
24 | background-image: url("@{iconSmWhiteSpritePath}");
25 | }
26 | }
27 | }
28 | //
29 | //.validation-msg {
30 | // font-size: 0.8em;
31 | // display: none;
32 | //}
33 | ////////////////////////////////////////////////////////////////////////
34 | ///// DEPRECATED
35 | //.link-action {
36 | // padding: 1px 1px 0 1px;
37 | // &:hover {
38 | // background-color: @textColor;
39 | //
40 | // [class^="iconsm-"],
41 | // [class*=" iconsm-"] {
42 | // background-image: url("@{iconSmWhiteSpritePath}");
43 | // }
44 | // [class^="iconlg-"],
45 | // [class*=" iconlg-"] {
46 | // background-image: url("@{iconLgWhiteSpritePath}");
47 | // }
48 | // }
49 | //}
50 | ////////////////////////////////////////////////////////////////////////
51 | .link-action {
52 | //a {
53 | [class^="iconsm-"],
54 | [class*=" iconsm-"] {
55 | background-image: url("@{iconLgLinkColorSpritePath}");
56 | }
57 | [class^="iconlg-"],
58 | [class*=" iconlg-"] {
59 | background-image: url("@{iconLgLinkColorSpritePath}");
60 | }
61 |
62 | &:hover {
63 | [class^="iconsm-"],
64 | [class*=" iconsm-"] {
65 | background-image: url("@{iconLgLinkColorHoverSpritePath}");
66 | }
67 | [class^="iconlg-"],
68 | [class*=" iconlg-"] {
69 | background-image: url("@{iconLgLinkColorHoverSpritePath}");
70 | }
71 | }
72 | }
73 |
74 | .control-group {
75 | .control-action {
76 | .opacity(0);
77 | }
78 |
79 | &:hover {
80 | .control-action {
81 | .opacity(100);
82 | }
83 | }
84 |
85 | input, select {
86 | // see http://stackoverflow.com/questions/2226666/background-image-for-select-dropdown-does-not-work-in-chrome
87 | // -webkit-appearance: none;
88 | padding-left: 23px;
89 | background-image: url("@{iconSpritePath}");
90 | background-position: -480px -1px;
91 | background-repeat: no-repeat;
92 |
93 | &:focus {
94 | background-position: -480px -31px;
95 | }
96 | }
97 |
98 | &.required {
99 | input, select {
100 | background-position: -480px -61px;
101 |
102 | &:focus {
103 | background-position: -480px -91px;
104 | }
105 | }
106 | }
107 |
108 | &.error {
109 | input, select {
110 | background-position: -480px -181px;
111 |
112 | &:focus {
113 | background-position: -480px -211px;
114 | }
115 | }
116 | }
117 |
118 | input.ng-valid, select.ng-valid {
119 | background-position: -480px -121px;
120 |
121 | &:focus {
122 | background-position: -480px -151px;
123 | }
124 | }
125 | }
126 |
127 | // chrome does not support backgrounds in selects, so reset the padding too
128 | @media screen and (-webkit-min-device-pixel-ratio:0) {
129 | .control-group select {
130 | background-image: none;
131 | padding-left: 6px;
132 | }
133 | }
134 |
135 | .controls{
136 | position: relative;
137 | }
138 |
139 | @msgIndDimension: 18px;
140 | .msg-ind {
141 | width: @msgIndDimension;
142 | height: @msgIndDimension;
143 | position: absolute;
144 | left: 1px;
145 | top: (@inputHeight - @msgIndDimension) / 2;
146 | cursor: pointer;
147 | display: block;
148 |
149 | p {
150 | display: none;
151 | }
152 | }
153 |
154 | .qtip-content {
155 | p {
156 | margin: 2px 0;
157 | }
158 | }
159 |
160 | // a bootstrap grid cell that contains anchor commands
161 | .grid-command-cell {
162 | p {
163 | padding: 4px 12px; // make it similar to .btn
164 | text-align: center;
165 | }
166 | }
167 |
168 | .icobusysm {
169 | .iconsetup(@iconDimSm,"../images/activity-spinner-16-combined.gif");
170 | background-position: 0 0;
171 | }
172 |
173 |
174 | ///////////////////////////////////////////////////////////////////////////////
175 | // categories view specific
176 | ul.category-list {
177 | list-style: none;
178 | margin: 0;
179 |
180 | li {
181 | float: left;
182 | width: 33.3%;
183 | .box-sizing(border-box);
184 | padding: 0 0 6px;
185 |
186 | div {
187 | border: 1px solid @inputBorder;
188 | .border-radius(@inputBorderRadius);
189 | padding: 3px;
190 | position: relative; // position container for the control-action
191 |
192 | &.dflt-category {
193 | background-color: @grayLighter;
194 | .control-action {
195 | display: none;
196 | }
197 | .icobusysm {
198 | background-position: -@iconDimSm 0;
199 | }
200 | }
201 |
202 | p {
203 | margin: 0;
204 | overflow: hidden;
205 | text-overflow: ellipsis;
206 | white-space: nowrap;
207 | padding-right: 20px;
208 | }
209 |
210 | .control-action, span {
211 | position: absolute;
212 | top: 50%;
213 | right: 3px;
214 | margin-top: -@baseLineHeight/2;
215 | }
216 |
217 | span {
218 | display: none;
219 | }
220 |
221 | &.pending {
222 | a.control-action {
223 | display: none;
224 | }
225 | span {
226 | display: inline;
227 | }
228 | }
229 |
230 | &.deleted {
231 | p {
232 | text-decoration: line-through;
233 | }
234 | }
235 | }
236 |
237 | &:nth-child(3n+1) {
238 | padding-right: 4px;
239 | }
240 | &:nth-child(3n+2) {
241 | padding-left: 2px;
242 | padding-right: 2px;
243 | }
244 | &:nth-child(3n+0) {
245 | padding-left: 4px;
246 | }
247 | }
248 | }
249 |
250 |
251 | ///////////////////////////////////////////////////////////////////////////////
252 | // effects
253 | /*
254 | .drop-in-setup {
255 | .transition(all linear 1.3s);
256 | line-height: 0;
257 | // .opacity(0);
258 | // height: 0;
259 | overflow: hidden;
260 |
261 | &.drop-in-start {
262 | line-height: @baseLineHeight;
263 | // .opacity(100);
264 | // height: @baseLineHeight;
265 | // background-color: red;
266 | }
267 | }
268 |
269 | .drop-out-setup {
270 | .transition(all linear 1.3s);
271 | line-height: @baseLineHeight;
272 | // .opacity(100);
273 | // height: @baseLineHeight;
274 | // overflow: hidden;
275 |
276 | &.drop-out-start {
277 | line-height: 0;
278 | // .opacity(0);
279 | // height: 0;
280 | // background-color: green;
281 | }
282 | }
283 | */
284 |
285 |
286 | ///////////////////////////////////////////////////////////////////////////////
287 | // grid
288 | .grid-style {
289 | border: 1px solid rgb(212,212,212);
290 | width: 100%;
291 | height: 300px;
292 | }
293 |
294 |
295 | ///////////////////////////////////////////////////////////////////////////////
296 | @import "sprites.less";
297 |
--------------------------------------------------------------------------------
/WebContent/css/custom/variables.less:
--------------------------------------------------------------------------------
1 | @iconDimSm: 16px;
2 | @iconDimLg: 40px;
3 |
4 | @iconSmSpritePath: "../images/bitmap16.png";
5 | @iconSmWhiteSpritePath: "../images/bitmap16-white.png";
6 | @iconLgSpritePath: "../images/bitmap40.png";
7 | @iconLgWhiteSpritePath: "../images/bitmap40-white.png";
8 | @iconLgLinkColorSpritePath: "../images/bitmap40-linkColor.png";
9 | @iconLgLinkColorHoverSpritePath: "../images/bitmap40-linkColorHover.png";
10 |
11 | @iconBackX: 0;
12 | @iconBackY: 0;
13 | @iconXX: 1;
14 | @iconXY: 0;
15 | @iconTrashX: 2;
16 | @iconTrashY: 0;
17 | @iconPencil1X: 3;
18 | @iconPencil1Y: 0;
19 | @iconPencil2X: 4;
20 | @iconPencil2Y: 0;
21 | @iconPieX: 5;
22 | @iconPieY: 0;
23 |
--------------------------------------------------------------------------------
/WebContent/css/ie8.css:
--------------------------------------------------------------------------------
1 | .input-block-level {
2 | min-height: 20px;
3 | }
4 | .msg-ind {
5 | background-color: white;
6 | filter: alpha(opacity=1);
7 | }
8 |
--------------------------------------------------------------------------------
/WebContent/css/images/activity-spinner-16-combined.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/activity-spinner-16-combined.gif
--------------------------------------------------------------------------------
/WebContent/css/images/bitmap16-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/bitmap16-white.png
--------------------------------------------------------------------------------
/WebContent/css/images/bitmap16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/bitmap16.png
--------------------------------------------------------------------------------
/WebContent/css/images/bitmap40-linkColor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/bitmap40-linkColor.png
--------------------------------------------------------------------------------
/WebContent/css/images/bitmap40-linkColorHover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/bitmap40-linkColorHover.png
--------------------------------------------------------------------------------
/WebContent/css/images/bitmap40-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/bitmap40-white.png
--------------------------------------------------------------------------------
/WebContent/css/images/bitmap40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/bitmap40.png
--------------------------------------------------------------------------------
/WebContent/css/images/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/WebContent/css/images/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/glyphicons-halflings.png
--------------------------------------------------------------------------------
/WebContent/css/images/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/loading.gif
--------------------------------------------------------------------------------
/WebContent/css/images/x_x5F_alt18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/x_x5F_alt18.png
--------------------------------------------------------------------------------
/WebContent/css/images/x_x5F_alt23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nikospara/angular-require-lazy/b071c66fc4ae6e5c147bc338a87ddf1553e93e8b/WebContent/css/images/x_x5F_alt23.png
--------------------------------------------------------------------------------
/WebContent/css/style.less:
--------------------------------------------------------------------------------
1 | @import "bootstrap/bootstrap.less";
2 | @import "custom/style.less";
3 | @import "bootstrap/responsive.less";
4 | @import "custom/overrides.less";
5 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/constants.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | return {
3 | HOME_PATH: "/index"
4 | };
5 | });
6 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/main/main.js:
--------------------------------------------------------------------------------
1 | define([
2 | // injected dependencies
3 | "angular", "util/lib/angular-require-lazy/bootstrap", "./navbarCtrl", "lazy-registry", "util/lib/angular-require-lazy/routeConfig", "app/constants",
4 | // side-effect deps
5 | "templateCache!./navbar.html",
6 | // side-effect, non-AMD deps
7 | "lib/angular-route/angular-route", "lib/angular-ui-bootstrap/src/modal/modal"
8 | ],
9 | function(angular, bootstrap, navbarCtrl, lazyRegistry, routeConfig, constants) {
10 |
11 | var main = angular.module("main", ["ngRoute", "ui.bootstrap.collapse", "ui.bootstrap.modal"]);
12 |
13 | main.config(["$routeProvider", addAllRoutes]);
14 |
15 | main.controller("NavbarCtrl", navbarCtrl);
16 |
17 | bootstrap(document, main);
18 |
19 | return main;
20 |
21 | function addAllRoutes($routeProvider) {
22 | var module, i, modules = lazyRegistry.getModules();
23 | for( i=0; i < modules.length; i++ ) {
24 | module = modules[i];
25 | addAllRoutesForModule($routeProvider, module);
26 | }
27 | $routeProvider.otherwise({redirectTo: constants.HOME_PATH});
28 | }
29 |
30 | function addAllRoutesForModule($routeProvider, module) {
31 | var routes, i, route;
32 | if( module.metadata && module.metadata["angular-routes"] ) {
33 | routes = module.metadata["angular-routes"];
34 | for( i=0; i < routes.length; i++ ) {
35 | route = routes[i];
36 | $routeProvider.when(route.path, routeConfig.fromAmdModule(route,module));
37 | }
38 | }
39 | }
40 | });
41 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/main/navbar.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
EXPENSES
9 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/main/navbarCtrl.js:
--------------------------------------------------------------------------------
1 | define([
2 | "jquery", "util/menuEntries", "app/constants",
3 | "lib/angular-ui-bootstrap/src/collapse/collapse"
4 | ],
5 | function($, menuEntries, constants) {
6 | "use strict";
7 |
8 | NavbarCtrl.$inject = ["$scope", "$location", "$route"];
9 | function NavbarCtrl($scope, $location, $route) {
10 |
11 | $.extend($scope, {
12 | isNavbarCollapsed: true,
13 | menuEntries: menuEntries,
14 | isActive: isActive,
15 | isHome: isHome,
16 | homePath: homePath
17 | });
18 |
19 | function isActive(menuEntry) {
20 | return $route.current.locals && $route.current.locals.amdModule && $route.current.locals.amdModule.name === menuEntry.moduleName;
21 | }
22 |
23 | function isHome() {
24 | return $location.path() === constants.HOME_PATH;
25 | }
26 |
27 | function homePath() {
28 | return constants.HOME_PATH;
29 | }
30 | }
31 |
32 | return NavbarCtrl;
33 | });
34 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/categories/categoriesCtrl.js:
--------------------------------------------------------------------------------
1 | define([
2 | "jquery", "util/viewUtils", "currentModule", "text!./deleteTemplate.html",
3 | "templateCache!./categoriesTemplate.html", "./categoryDirective", "app/shared/dao/categoriesDao",
4 | "lib/angular-ui-bootstrap/src/modal/modal", "util/returnService"
5 | ],
6 | function($, viewUtils, currentModule, templateDelete) {
7 | "use strict";
8 |
9 | var ADD_LABEL = "Add", RENAME_LABEL = "Rename", opts;
10 |
11 | opts = {
12 | backdrop: "static",
13 | keyboard: false,
14 | template: templateDelete
15 | };
16 |
17 | EditCategoriesCtrl.$inject = ["$scope", "$q", "$modal", "returnService", "categoriesDao"];
18 | function EditCategoriesCtrl($scope, $q, $modal, returnService, categoriesDao) {
19 |
20 | var lastAddedCategoryKey;
21 |
22 | $.extend($scope, {
23 | categories: categoriesDao.fetchCachedForCurrentUser(),
24 | form: {
25 | name: null
26 | },
27 | executeLabel: initExecuteLabel(),
28 | execute: execute,
29 | cancel: cancel,
30 | selectedCategoryForEdit: initSelectedCategoryForEdit(),
31 | selectCategoryForEdit: selectCategoryForEdit,
32 | hasCancel: initHasCancel(),
33 | deleteCategory: deleteCategory,
34 | isPushed: initIsPushed(),
35 | doReturn: doReturn
36 | });
37 |
38 | function execute(event) {
39 | if( $scope.selectedCategoryForEdit != null ) updateCategory();
40 | else addCategory();
41 | }
42 |
43 | function updateCategory() {
44 | var oldName = $scope.selectedCategoryForEdit.name;
45 | $scope.selectedCategoryForEdit.name = $scope.form.name;
46 | categoriesDao.updateCategory($scope.selectedCategoryForEdit).then(
47 | function success() {
48 | cancel();
49 | },
50 | function failure() {
51 | $scope.selectedCategoryForEdit.name = oldName;
52 | }
53 | );
54 | }
55 |
56 | function addCategory() {
57 | var newcat = categoriesDao.addCategory($scope.form.name);
58 | newcat.$$promise.then(function() {
59 | lastAddedCategoryKey = newcat.key;
60 | });
61 | $scope.form.name = null;
62 | $scope.editCategoriesForm.$setPristine();
63 | }
64 |
65 | function cancel(event) {
66 | viewUtils.preprocessAnchorEvt(event);
67 | $scope.selectedCategoryForEdit = null;
68 | $scope.form.name = null;
69 | $scope.hasCancel = false;
70 | $scope.executeLabel = ADD_LABEL;
71 | }
72 |
73 | function selectCategoryForEdit(c) {
74 | if( c.key == null ) return;
75 | $scope.selectedCategoryForEdit = c;
76 | $scope.form.name = c.name;
77 | $scope.hasCancel = true;
78 | $scope.executeLabel = RENAME_LABEL;
79 | }
80 |
81 | function deleteCategory(c) {
82 | if( c.key == null ) return;
83 | opts.controller = ["$scope", "$modalInstance", DeleteCtrl];
84 | var d = $modal.open(opts);
85 | d.result.then(function(result) {
86 | if( result === "yes" ) {
87 | categoriesDao.deleteCategory(c);
88 | }
89 | });
90 |
91 | function DeleteCtrl($scope, $modalInstance) {
92 | $scope.category = c;
93 | $scope.close = function(result) {
94 | $modalInstance.close(result);
95 | };
96 | }
97 | }
98 |
99 | function initHasCancel() {
100 | return false;
101 | }
102 |
103 | function initSelectedCategoryForEdit() {
104 | return null;
105 | }
106 |
107 | function initExecuteLabel() {
108 | return ADD_LABEL;
109 | }
110 |
111 | function initIsPushed() {
112 | return returnService.isPushed();
113 | }
114 |
115 | function doReturn() {
116 | returnService.doReturn({categoryKey: lastAddedCategoryKey});
117 | }
118 | }
119 |
120 | return EditCategoriesCtrl;
121 | });
122 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/categories/categoriesTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Categories
5 |
6 |
7 |
45 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/categories/categoryDirective.js:
--------------------------------------------------------------------------------
1 | define(["angular", "util/viewUtils", "currentModule", "text!./categoryTemplate.html", "app/shared/dao/userDao"],
2 | function(angular, viewUtils, currentModule, template) {
3 | "use strict";
4 |
5 | currentModule.directive("category", ["userDao", function(userDao) {
6 | return {
7 | restrict: "A",
8 | template: template,
9 | replace: true,
10 | scope: {
11 | category: "=",
12 | edit: "&",
13 | remove: "&"
14 | },
15 | link: function(scope, element, attrs) {
16 | angular.extend(scope, {
17 | defaultCategoryId: null,
18 | editCb: editCb,
19 | removeCb: removeCb
20 | });
21 |
22 | function editCb(event,c) {
23 | viewUtils.preprocessAnchorEvt(event);
24 | scope.edit({c:c});
25 | }
26 |
27 | function removeCb(event,c) {
28 | viewUtils.preprocessAnchorEvt(event);
29 | scope.remove({c:c});
30 | }
31 |
32 | (function initDefaultCategoryId() {
33 | return userDao.getUserData().then(function(userData) {
34 | scope.defaultCategoryId = userData.defaultCategoryId;
35 | });
36 | })();
37 | }
38 | };
39 | }]);
40 | });
41 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/categories/categoryTemplate.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/categories/deleteTemplate.html:
--------------------------------------------------------------------------------
1 |
4 |
5 | Are you sure you want to delete {{ category.name }}?
6 |
7 |
11 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/categories/main.js:
--------------------------------------------------------------------------------
1 | define(["angular", "./categoriesCtrl", "currentModule"], function(angular, categoriesCtrl, currentModule) {
2 | "use strict";
3 |
4 | var m = angular.module("categories", currentModule.combineDependencies([]));
5 |
6 | m.controller("EditCategoriesCtrl", categoriesCtrl);
7 |
8 | return m;
9 | });
10 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/categories/main.metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "angular-routes": [
3 | {
4 | "path": "/categories",
5 | "controller": "EditCategoriesCtrl",
6 | "template": "app/modules/categories/categoriesTemplate.html",
7 | "display": "Categories",
8 | "weight": 100
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/chartPopup.tpl.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/chartPopupModule.js:
--------------------------------------------------------------------------------
1 | define([
2 | "angular", "currentModule", "templateCache!./chartPopup.tpl.html",
3 | // side-effect deps
4 | "./pieChartDirective", "./chartPopupService",
5 | "lib/angular-ui-bootstrap/src/modal/modal"
6 | ],
7 | function(angular, currentModule, chartPopupTemplate) {
8 | "use strict";
9 |
10 | var m = angular.module("chartPopup", currentModule.combineDependencies([]));
11 |
12 | return m;
13 | });
14 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/chartPopupService.js:
--------------------------------------------------------------------------------
1 | define(["angular", "currentModule", "templateCache!./chartPopup.tpl.html", "./pieChartDirective"],
2 | function(angular, currentModule, chartPopupTemplate) {
3 | "use strict";
4 |
5 | var opts = {
6 | backdrop: "static",
7 | keyboard: false,
8 | templateUrl: chartPopupTemplate.path
9 | };
10 |
11 | function mapExpensesForCharting(expenses) {
12 | var map = {}, result = [], i, tmp;
13 | for( i=0; i < expenses.length; i++ ) {
14 | tmp = map[expenses[i].categoryId];
15 | if( !tmp ) {
16 | tmp = { value:0, label:"Category " + expenses[i].categoryId };
17 | map[expenses[i].categoryId] = tmp;
18 | result.push(tmp);
19 | }
20 | tmp.value += expenses[i].amount;
21 | }
22 | return result;
23 | }
24 |
25 | currentModule.addDependencies().service("chartPopup", ["$modal", function($modal) {
26 |
27 | function show(expenses) {
28 | var d;
29 |
30 | opts.controller = ["$scope", ChartCtrl];
31 | d = $modal.open(opts);
32 |
33 | function ChartCtrl($scope) {
34 | angular.extend($scope, {
35 | data: mapExpensesForCharting(expenses)
36 | });
37 | }
38 | }
39 |
40 | return {
41 | show: show
42 | };
43 | }]);
44 | });
45 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/expensesCtrl.js:
--------------------------------------------------------------------------------
1 | define([
2 | "angular", "app/shared/model/Expense", "ngLazy!./chartPopupModule",
3 | // side-effect deps
4 | "app/shared/dao/userDao", "app/shared/dao/expensesDao", "templateCache!./expensesTemplate.html", "lib/ng-grid-bower/ng-grid", "lib/angular-ui-bootstrap/src/modal/modal"
5 | ],
6 | function(angular, Expense, chartPopupModule) {
7 | "use strict";
8 |
9 | ExpensesCtrl.$inject = ["$scope", "expensesDao", "userDao", "$injector"];
10 | function ExpensesCtrl($scope, expensesDao, userDao, $injector) {
11 | angular.extend($scope, {
12 | defaultCategoryId: initDefaultCategoryId(),
13 | expenses: initExpenses(),
14 | gridOptions: initGridOptions(),
15 | chart: chart,
16 | format: function(x) {
17 | // TODO
18 | return x;
19 | }
20 | });
21 |
22 | function initDefaultCategoryId() {
23 | return userDao.getUserData().then(function(userData) {
24 | return userData.defaultCategoryId;
25 | });
26 | }
27 |
28 | function initExpenses() {
29 | // TODO Determine month and year, route params
30 | var ret = [];
31 | expensesDao.fetch(2013,undefined,ret);
32 | return ret;
33 | }
34 |
35 | function initGridOptions() {
36 | return {
37 | data: "expenses",
38 | multiSelect: false,
39 | keepLastSelected: false,
40 | //selectedItems: $scope.mySelections,
41 | //showFooter:true,
42 | columnDefs: [
43 | {
44 | field: "date",
45 | displayName: "Date",
46 | width: "****",
47 | // cellFilter: "date: 'dd/MM/yyyy'"
48 | cellTemplate: '{{ row.getProperty(col.field) | date: "dd/MM/yyyy" }}
',
49 | },{
50 | field: "reason",
51 | displayName: "Reason",
52 | width: "*********"
53 | },{
54 | field: "amount",
55 | displayName: "Amount",
56 | width: "****",
57 | cellClass: "text-right",
58 | cellTemplate: '{{ format(row.getProperty(col.field)) }}
',
59 | headerClass: "text-left"
60 | },{
61 | field: "categoryId",
62 | displayName: "Category",
63 | width: "*******"
64 | },{
65 | field: "special",
66 | displayName: "",
67 | width: "*",
68 | sortable: false
69 | }
70 | ]
71 | };
72 | }
73 |
74 | function chart($event, expenses) {
75 | $event.preventDefault();
76 | chartPopupModule.get().then(
77 | function() {
78 | $injector.invoke(["chartPopup", function(chartPopup) {
79 | chartPopup.show(expenses);
80 | }]);
81 | },
82 | function() {
83 |
84 | }
85 | );
86 | }
87 | }
88 |
89 | return ExpensesCtrl;
90 | });
91 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/expensesTemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Expenses
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/main.js:
--------------------------------------------------------------------------------
1 | define(["angular", "./expensesCtrl", "currentModule"], function(angular, expensesCtrl, currentModule) {
2 | "use strict";
3 |
4 | var m = angular.module("expenses", currentModule.combineDependencies([]));
5 |
6 | m.controller("ExpensesCtrl", expensesCtrl);
7 |
8 | return m;
9 | });
10 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/main.metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "angular-routes": [
3 | {
4 | "path": "/expenses",
5 | "controller": "ExpensesCtrl",
6 | "template": "app/modules/expenses/expensesTemplate.html",
7 | "display": "Expenses",
8 | "weight": 200
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/expenses/pieChartDirective.js:
--------------------------------------------------------------------------------
1 | define(["angular", "currentModule", "lib/Chart"], function(angular, currentModule, Chart) {
2 | "use strict";
3 |
4 | var COLORS = [
5 | ["#F7464A","#FF5A5E"],
6 | ["#46BFBD","#5AD3D1"],
7 | ["#FDB45C","#FFC870"]
8 | ];
9 |
10 | function preprocessData(data) {
11 | var i, colorIndex = 0;
12 | for( i=0; i < data.length; i++ ) {
13 | if( data[i].color == null ) {
14 | data[i].color = COLORS[colorIndex][0];
15 | data[i].highlight = COLORS[colorIndex][1];
16 | colorIndex += 1;
17 | }
18 | }
19 | }
20 |
21 | currentModule.directive("pieChart", function() {
22 | return {
23 | restrict: "A",
24 | scope: {
25 | data: "=pieChart"
26 | },
27 | link: function(scope, elem, attrs) {
28 | var ctx, pieChart;
29 | preprocessData(scope.data);
30 | ctx = elem[0].getContext("2d");
31 | pieChart = new Chart(ctx).Pie(scope.data, {
32 | animationEasing: "easeOutQuint",
33 | legendTemplate:
34 | '' +
35 | '<% for (var i=0; i' +
36 | '- \"><%if(segments[i].label){%><%=segments[i].label%><%}%>
' +
37 | '<%}%>' +
38 | '
'
39 | });
40 | }
41 | };
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/index/indexCtrl.js:
--------------------------------------------------------------------------------
1 | define([
2 | "angular", "app/shared/model/Expense", "app/shared/dao/userDao",
3 | "app/shared/dao/categoriesDao", "app/shared/dao/expensesDao", "templateCache!./indexTemplate.html", "util/returnService"
4 | ],
5 | function(angular, Expense) {
6 | "use strict";
7 |
8 | IndexCtrl.$inject = ["$scope", "returnService", "expensesDao", "categoriesDao", "userDao"];
9 | function IndexCtrl($scope, returnService, expensesDao, categoriesDao, userDao) {
10 |
11 | angular.extend($scope, {
12 | categories: categoriesDao.fetchCachedForCurrentUser(),
13 | form: initExpense(),
14 | enter: enter,
15 | editCategories: editCategories
16 | });
17 |
18 | function initExpense() {
19 | var retData, e = returnService.get("expense");
20 | if( e == null ) {
21 | e = new Expense();
22 | userDao.getUserData().then(function(userData) {
23 | e.categoryId = userData.defaultCategoryId;
24 | });
25 | }
26 | else {
27 | retData = returnService.getReturnedData();
28 | if( retData && typeof(retData.categoryKey) === "number" ) e.categoryId = retData.categoryKey;
29 | }
30 | return e;
31 | }
32 |
33 | function enter(event) {
34 | expensesDao.add($scope.form);
35 | // TODO Clear
36 | }
37 |
38 | function editCategories(event) {
39 | returnService.put("expense", $scope.form);
40 | returnService.push();
41 | }
42 | }
43 |
44 | return IndexCtrl;
45 | });
46 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/index/indexTemplate.html:
--------------------------------------------------------------------------------
1 |
44 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/index/main.js:
--------------------------------------------------------------------------------
1 | define(["angular", "./indexCtrl", "currentModule"], function(angular, indexCtrl, currentModule) {
2 | "use strict";
3 |
4 | var m = angular.module("index", currentModule.combineDependencies([]));
5 |
6 | m.controller("IndexCtrl", indexCtrl);
7 |
8 | return m;
9 | });
10 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/modules/index/main.metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "angular-routes": [
3 | {
4 | "path": "/index",
5 | "controller": "IndexCtrl",
6 | "template": "app/modules/index/indexTemplate.html",
7 | "display": "Home",
8 | "weight": 0
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/shared/dao/categoriesDao.js:
--------------------------------------------------------------------------------
1 | define(["angular", "currentModule", "./userDao", "lib/angular-resource/angular-resource"],
2 | function(angular, currentModule) {
3 | "use strict";
4 |
5 | var RC_URL = "api/user/:id/categories";
6 |
7 | currentModule.addDependencies("ngResource").service("categoriesDao", ["$resource", "$q", "userDao", function($resource, $q, userDao) {
8 | var cachedCategories = null, cachedCategoriesMap = null, rc;
9 |
10 | rc = $resource(RC_URL, {}, {
11 | deleteCategory: { url: RC_URL+"/:key", method:"DELETE" },
12 | updateCategory: { method:"PUT" }
13 | });
14 |
15 | function fetchForCurrentUser(result) {
16 | if( result != null ) {
17 | result.$$status = "PENDING";
18 | }
19 | return userDao.getUserData().then(
20 | function gotUserData(userData) {
21 | return rc.get({id:userData.id}).$promise;
22 | },
23 | function errorGettingUserData(response) {
24 | return $q.reject(response);
25 | }
26 | ).then(
27 | function success(data) {
28 | if( data && data.payload && angular.isArray(result) ) {
29 | angular.copy(data.payload,result);
30 | }
31 | if( result != null ) {
32 | result.$$status = "SUCCESS";
33 | }
34 | return data;
35 | },
36 | function failure(response) {
37 | if( result != null ) {
38 | result.$$status = "FAILURE";
39 | }
40 | return $q.reject(response);
41 | }
42 | );
43 | }
44 |
45 | function fetchCachedForCurrentUser() {
46 | if( cachedCategories == null ) {
47 | cachedCategories = [];
48 | fetchForCurrentUser(cachedCategories).then(makeCachedCategoriesMap);
49 | }
50 | return cachedCategories;
51 | }
52 |
53 | function updateCategory(c) {
54 | c.$$status = "PENDING";
55 | return userDao.getUserData().then(
56 | function gotUserData(userData) {
57 | return rc.updateCategory({id:userData.id},{name:c.name, key:c.key}).$promise;
58 | },
59 | function errorGettingUserData(response) {
60 | return $q.reject(response);
61 | }
62 | ).then(
63 | function success(data) {
64 | if( data && data.payload === true ) {
65 | c.$$status = "SUCCESS";
66 | return data;
67 | }
68 | else {
69 | // business failure
70 | c.$$status = "FAILURE";
71 | return $q.reject(data);
72 | }
73 | },
74 | function failure(response) {
75 | c.$$status = "FAILURE";
76 | return $q.reject(response);
77 | }
78 | );
79 | }
80 |
81 | function deleteCategory(c) {
82 | c.$$status = "PENDING";
83 | c.$$deleted = true;
84 | return userDao.getUserData().then(
85 | function gotUserData(userData) {
86 | return rc.deleteCategory({id:userData.id,key:c.key},null).$promise;
87 | },
88 | function errorGettingUserData(response) {
89 | return $q.reject(response);
90 | }
91 | ).then(
92 | function success(data) {
93 | if( data && data.payload === true ) {
94 | c.$$status = "SUCCESS";
95 | removeFromCache(c);
96 | return data;
97 | }
98 | else {
99 | // business failure
100 | return deletionFailed(c,data);
101 | }
102 | },
103 | function failure(response) {
104 | return deletionFailed(c,response);
105 | }
106 | );
107 | }
108 |
109 | function removeFromCache(c) {
110 | var index = cachedCategories.indexOf(c);
111 | if( index >= 0 ) cachedCategories.splice(index,1);
112 | if( cachedCategoriesMap !== null ) delete cachedCategoriesMap[c.key];
113 | }
114 |
115 | function deletionFailed(c, reason) {
116 | c.$$status = "FAILURE";
117 | delete c.$$deleted;
118 | return $q.reject(reason);
119 | }
120 |
121 | function addCategory(name) {
122 | var c = {key:null, name:name, $$status:"PENDING", $$promise:null};
123 | cachedCategories.push(c);
124 | c.$$promise = userDao.getUserData().then(
125 | function gotUserData(userData) {
126 | return rc.save({id:userData.id},c).$promise;
127 | },
128 | function errorGettingUserData(response) {
129 | return $q.reject(response);
130 | }
131 | ).then(
132 | function success(data) {
133 | delete c.$$promise;
134 | if( data && data.payload && data.payload.key ) {
135 | c.$$status = "SUCCESS";
136 | c.key = data.payload.key;
137 | mapCategory(c);
138 | return data;
139 | }
140 | else {
141 | // business failure
142 | return additionFailed(c,data);
143 | }
144 | },
145 | function failure(response) {
146 | delete c.$$promise;
147 | return additionFailed(c,response);
148 | }
149 | );
150 | return c;
151 | }
152 |
153 | function additionFailed(c,reason) {
154 | var index = cachedCategories.indexOf(c);
155 | if( index >= 0 ) cachedCategories.splice(index,1);
156 | c.$$status = "FAILURE";
157 | return $q.reject(reason);
158 | }
159 |
160 | function clearCache() {
161 | cachedCategories = null;
162 | cachedCategoriesMap = null;
163 | }
164 |
165 | function makeCachedCategoriesMap() {
166 | var i, c;
167 | cachedCategoriesMap = {};
168 | for( i=0; i < cachedCategories.length; i++ ) {
169 | c = cachedCategories[i];
170 | cachedCategoriesMap[c.key] = c;
171 | }
172 | }
173 |
174 | function mapCategory(c) {
175 | if( cachedCategoriesMap === null ) cachedCategoriesMap = {};
176 | cachedCategoriesMap[c.key] = c;
177 | }
178 |
179 | function promiseForKey(key) {
180 | throw new Error("UNIMPLEMENTED");
181 | }
182 |
183 | return {
184 | fetchForCurrentUser: fetchForCurrentUser,
185 | fetchCachedForCurrentUser: fetchCachedForCurrentUser,
186 | addCategory: addCategory,
187 | deleteCategory: deleteCategory,
188 | updateCategory: updateCategory,
189 | promiseForKey: promiseForKey,
190 | clearCache: clearCache
191 | };
192 | }]);
193 | });
194 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/shared/dao/expensesDao.js:
--------------------------------------------------------------------------------
1 | define([
2 | "app/shared/model/Expense", "angular", "currentModule",
3 | "lib/angular-resource/angular-resource", "./userDao", "lib/angular-resource/angular-resource"
4 | ],
5 | function(Expense, angular, currentModule) {
6 | "use strict";
7 |
8 | currentModule.addDependencies("ngResource").service("expensesDao", ["$resource", "$q", "userDao", function($resource, $q, userDao) {
9 | var rc;
10 |
11 | rc = $resource("api/user/:id/expenses", {}, {});
12 |
13 | function fetch(year,month,result) {
14 | if( result != null ) {
15 | result.$$status = "PENDING";
16 | }
17 | return userDao.getUserData().then(
18 | function gotUserData(userData) {
19 | return rc.get({id:userData.id, year:year, month:month}).$promise;
20 | },
21 | function errorGettingUserData(response) {
22 | return $q.reject(response);
23 | }
24 | ).then(
25 | function success(data) {
26 | if( data && data.payload && angular.isArray(result) ) {
27 | angular.copy(data.payload,result);
28 | }
29 | if( result != null ) {
30 | result.$$status = "SUCCESS";
31 | }
32 | return data;
33 | },
34 | function failure(response) {
35 | if( result != null ) {
36 | result.$$status = "FAILURE";
37 | }
38 | return $q.reject(response);
39 | }
40 | );
41 | }
42 |
43 | function add(expense) {
44 | return userDao.getUserData().then(
45 | function gotUserData(userData) {
46 | return rc.save({id:userData.id}, expense).$promise;
47 | },
48 | function errorGettingUserData(response) {
49 | return $q.reject(response);
50 | }
51 | );
52 | }
53 |
54 | return {
55 | fetch: fetch,
56 | add: add
57 | };
58 | }]);
59 | });
60 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/shared/dao/userDao.js:
--------------------------------------------------------------------------------
1 | define(["angular", "currentModule", "util/loginPrompt", "lib/angular-resource/angular-resource"],
2 | function(angular, currentModule) {
3 | "use strict";
4 |
5 | currentModule.addDependencies("ngResource").service("userDao", ["$http", "$q", "loginPrompt", function($http, $q, loginPrompt) {
6 | var userData = null, loggedIn = false, loginPending = false;
7 |
8 | function login(username, password) {
9 | userData = $q.defer(); // overwrite previous value; this is a new login
10 | return $http.post("api/user/login", {username:username,password:password}).then(
11 | function loginSucceeded(response) {
12 | loggedIn = true;
13 | userData.resolve(response.data);
14 | return response.data;
15 | },
16 | function loginFailed(response) {
17 | loggedIn = false;
18 | if( userData !== null ) userData.reject();
19 | return $q.reject(response);
20 | }
21 | );
22 | }
23 |
24 | function isLoggedIn() {
25 | return loggedIn;
26 | }
27 |
28 | function getUserData(triggerLogin) {
29 | var d = userData || $q.defer();
30 | if( userData == null ) {
31 | userData = d;
32 | if( !loginPending && triggerLogin !== false ) {
33 | loginPending = true;
34 | loginPrompt().then(
35 | function(loginData) {
36 | return login(loginData.username,loginData.password);
37 | },
38 | function(err) {
39 | return $q.reject(err);
40 | }
41 | ).then(
42 | function(result) {
43 | d.resolve(result);
44 | loginPending = false;
45 | },
46 | function(err) {
47 | d.reject(err);
48 | loginPending = false;
49 | return $q.reject(err);
50 | }
51 | );
52 | }
53 | }
54 | return d.promise;
55 | }
56 |
57 | return {
58 | getUserData: getUserData,
59 | login: login,
60 | isLoggedIn: isLoggedIn
61 | };
62 | }]);
63 | });
64 |
--------------------------------------------------------------------------------
/WebContent/scripts/app/shared/model/Expense.js:
--------------------------------------------------------------------------------
1 | define(["jquery"],function($) {
2 | "use strict";
3 |
4 | function Expense(json) {
5 | json = json || {};
6 | if( typeof(json.date) === "string" ) json.date = new Date(json.date);
7 | $.extend(this, json);
8 | }
9 |
10 | Expense.prototype = {
11 | key: null,
12 | date: null,
13 | amount: null,
14 | reason: null,
15 | categoryId: null,
16 | special: null
17 | };
18 | Expense.prototype.constructor = Expense;
19 |
20 | Expense.amountValidators = [
21 | ["positive", function(thisObj, value, validationContext) {
22 | validationContext.setMessage("Must be positive");
23 | return value == null || value > 0;
24 | }]
25 | ];
26 |
27 | return Expense;
28 | });
29 |
--------------------------------------------------------------------------------
/WebContent/scripts/empty.js:
--------------------------------------------------------------------------------
1 | // empty file to trick the optimizer
--------------------------------------------------------------------------------
/WebContent/scripts/globals.js:
--------------------------------------------------------------------------------
1 | // given by server-side template
2 |
--------------------------------------------------------------------------------
/WebContent/scripts/require-cfg.js:
--------------------------------------------------------------------------------
1 | var require = {
2 | baseUrl: "scripts",
3 |
4 | paths: {
5 | "angular": "lib/angular/angular"
6 | },
7 |
8 | config: {
9 |
10 | },
11 |
12 | map: {
13 | "*": {
14 | "text": "lib/requirejs-text/text",
15 | // this must match the libLazy property in build-scripts/options-grunt.js
16 | "lazy": "lib/require-lazy/lazy",
17 | "lazy-builder": "lib/require-lazy/lazy-builder",
18 | "promise-adaptor": "util/lib/angular-require-lazy/promiseAdaptorAngular",
19 | "currentModule": "util/lib/angular-require-lazy/currentModule",
20 | "templateCache": "util/lib/angular-require-lazy/templateCache",
21 | "ngLazy": "util/lib/angular-require-lazy/ngLazy",
22 | "ngLazyBuilder": "util/lib/angular-require-lazy/ngLazyBuilder"
23 | }
24 | },
25 |
26 | shim: {
27 | "globals": {
28 | exports: "globals"
29 | },
30 | "angular": {
31 | exports: "angular"
32 | },
33 | "lib/angular-ui-bootstrap/src/transition/transition": {
34 | deps: ["angular"]
35 | },
36 | "lib/angular-ui-bootstrap/src/collapse/collapse": {
37 | deps: ["angular", "lib/angular-ui-bootstrap/src/transition/transition"]
38 | },
39 | "lib/angular-ui-bootstrap/src/modal/modal": {
40 | deps: ["angular","util/modalTemplates", "lib/angular-ui-bootstrap/src/transition/transition"]
41 | },
42 | "lib/angular-route/angular-route": {
43 | deps: ["angular"]
44 | },
45 | "lib/angular-resource/angular-resource": {
46 | deps: ["angular"]
47 | }
48 | }
49 | };
50 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/bootstrap.js:
--------------------------------------------------------------------------------
1 | define(["angular", "./lazyAngularUtils", "./currentModule"], function(angular, lazyAngularUtils, currentModule) {
2 | "use strict";
3 |
4 | function bootstrap(element, mainModule) {
5 | var injector;
6 | mainModule.config(lazyAngularUtils.cacheInternals);
7 | mainModule.run(lazyAngularUtils.captureQ);
8 | currentModule.resolveWith(mainModule);
9 | lazyAngularUtils.makeLazyAngular();
10 | injector = angular.bootstrap(element, [mainModule.name]);
11 | bootstrap.injector = injector;
12 | return injector;
13 | }
14 |
15 | return bootstrap;
16 | });
17 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/currentModule.js:
--------------------------------------------------------------------------------
1 | define(["angular", "./util"], function(angular, util) {
2 | "use strict";
3 |
4 | var runBlocks = [], moduleDependenciesSet = [], currentModuleProxy = {}, makeArray = util.makeArray;
5 |
6 | currentModuleProxy.addDependencies = function() {
7 | for( var i=0; i < arguments.length; i++ ) {
8 | if( typeof(arguments[i]) === "string" ) {
9 | addToSet(moduleDependenciesSet, arguments[i]);
10 | }
11 | else if( angular.isArray(arguments[i]) ) {
12 | addAllToSet(moduleDependenciesSet, arguments[i]);
13 | }
14 | }
15 | return currentModuleProxy;
16 | };
17 |
18 | function addToSet(set, d) {
19 | if( d && set.indexOf(d) < 0 ) {
20 | set.push(d);
21 | }
22 | }
23 |
24 | function addAllToSet(set, deps) {
25 | for( var i=0; i < deps.length; i++ ) {
26 | if( typeof(deps[i]) === "string" ) {
27 | addToSet(set, deps[i]);
28 | }
29 | }
30 | }
31 |
32 | currentModuleProxy.combineDependencies = function(deps) {
33 | var i, ret = angular.copy(deps);
34 | addAllToSet(ret, moduleDependenciesSet);
35 | return ret;
36 | };
37 |
38 | // Angular API
39 | currentModuleProxy.factory = function() {
40 | runBlocks.push(["factory", makeArray(arguments)]);
41 | return currentModuleProxy;
42 | };
43 |
44 | currentModuleProxy.directive = function() {
45 | runBlocks.push(["directive", makeArray(arguments)]);
46 | return currentModuleProxy;
47 | };
48 |
49 | currentModuleProxy.filter = function() {
50 | runBlocks.push(["filter", makeArray(arguments)]);
51 | return currentModuleProxy;
52 | };
53 |
54 | currentModuleProxy.controller = function() {
55 | runBlocks.push(["controller", makeArray(arguments)]);
56 | return currentModuleProxy;
57 | };
58 |
59 | currentModuleProxy.provider = function() {
60 | runBlocks.push(["provider", makeArray(arguments)]);
61 | return currentModuleProxy;
62 | };
63 |
64 | currentModuleProxy.service = function() {
65 | runBlocks.push(["service", makeArray(arguments)]);
66 | return currentModuleProxy;
67 | };
68 |
69 | currentModuleProxy.run = function(r) {
70 | runBlocks.push(["run",[r]]);
71 | return currentModuleProxy;
72 | };
73 |
74 | currentModuleProxy.value = function() {
75 | runBlocks.push(["value", makeArray(arguments)]);
76 | return currentModuleProxy;
77 | };
78 |
79 | currentModuleProxy.constant = function() {
80 | runBlocks.push(["constant", makeArray(arguments)]);
81 | return currentModuleProxy;
82 | };
83 |
84 | currentModuleProxy.animation = function() {
85 | runBlocks.push(["animation", makeArray(arguments)]);
86 | return currentModuleProxy;
87 | };
88 |
89 | // TODO Only config() is missing from the angular.module interface; decide if we can handle it and how
90 |
91 | currentModuleProxy.resolveWith = function(realModule) {
92 | var i, b;
93 | for( i=0; i < runBlocks.length; i++ ) {
94 | b = runBlocks[i];
95 | realModule[b[0]].apply(realModule,b[1]);
96 | }
97 | runBlocks = [];
98 | moduleDependenciesSet = [];
99 | };
100 |
101 | return currentModuleProxy;
102 | });
103 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/lazyAngularUtils.js:
--------------------------------------------------------------------------------
1 | define(["angular", "./promiseAdaptorAngular"], function(angular, promiseAdaptor) {
2 | "use strict";
3 |
4 | var lazyAngularUtils, eagerAngularModuleFn = angular.module, cachedInternals = {}, lazyModules = {};
5 |
6 | function makeLazyModule(name, cachedInternals) {
7 | var lazyModule = {
8 | name: name,
9 | realModule: null,
10 | __runBlocks: [],
11 | factory: function() {
12 | cachedInternals.$provide.factory.apply(null, arguments);
13 | return lazyModule;
14 | },
15 | directive: function() {
16 | cachedInternals.$compileProvider.directive.apply(null, arguments);
17 | return lazyModule;
18 | },
19 | filter: function() {
20 | cachedInternals.$filterProvider.register.apply(null, arguments);
21 | return lazyModule;
22 | },
23 | controller: function() {
24 | cachedInternals.$controllerProvider.register.apply(null, arguments);
25 | return lazyModule;
26 | },
27 | provider: function() {
28 | cachedInternals.$provide.provider.apply(null, arguments);
29 | return lazyModule;
30 | },
31 | service: function() {
32 | cachedInternals.$provide.service.apply(null, arguments);
33 | return lazyModule;
34 | },
35 | run: function(r) {
36 | this.__runBlocks.push(r);
37 | return lazyModule;
38 | },
39 | value: function() {
40 | cachedInternals.$provide.value.apply(null, arguments);
41 | return lazyModule;
42 | },
43 | constant: function() {
44 | cachedInternals.$provide.constant.apply(null, arguments);
45 | return lazyModule;
46 | },
47 | animation: function() {
48 | cachedInternals.$animateProvider.register.apply(null, arguments);
49 | return lazyModule;
50 | }
51 | // TODO Only config() is missing from the angular.module interface; decide if we can handle it and how
52 | };
53 | return lazyModule;
54 | }
55 |
56 | function makeLazyAngular() {
57 | angular.module = function(name, requires, configFn) {
58 | var ret, realModule;
59 | if( typeof(requires) === "undefined" ) {
60 | if( lazyModules.hasOwnProperty(name) ) ret = lazyModules[name];
61 | else ret = eagerAngularModuleFn.call(angular, name);
62 | }
63 | else {
64 | //if( configFn != null ) throw new Error("config function unimplemented yet, module: " + name);
65 | ret = makeLazyModule(name, cachedInternals);
66 | lazyModules[name] = ret;
67 | ret.realModule = eagerAngularModuleFn.call(angular, name, requires, configFn);
68 | lazyAngularUtils.modulesQueue.push(ret);
69 | }
70 | return ret;
71 | };
72 | }
73 |
74 | function initLazyModules(injector) {
75 | var i, modulesQueue = lazyAngularUtils.modulesQueue;
76 | if( modulesQueue != null && modulesQueue.length > 0 ) {
77 | // TODO Run lazy config functions, not implemented yet
78 | // for( i=0; i < modulesQueue.length; i++ ) {
79 | // callConfigBlocks(injector, modulesQueue[i]);
80 | // }
81 | for( i=0; i < modulesQueue.length; i++ ) {
82 | callRunBlocks(injector, modulesQueue[i]);
83 | }
84 | modulesQueue.splice(0);
85 | }
86 | }
87 |
88 | function callRunBlocks(injector, module) {
89 | var i, blocks;
90 | blocks = module.__runBlocks || [];
91 | for( i=0; i < blocks.length; i++ ) {
92 | injector.invoke(blocks[i]);
93 | }
94 | }
95 |
96 | cacheInternals.$inject = ["$provide", "$compileProvider", "$filterProvider", "$controllerProvider", "$animateProvider"];
97 | function cacheInternals($provide, $compileProvider, $filterProvider, $controllerProvider, $animateProvider) {
98 | cachedInternals.$provide = $provide;
99 | cachedInternals.$compileProvider = $compileProvider;
100 | cachedInternals.$filterProvider = $filterProvider;
101 | cachedInternals.$controllerProvider = $controllerProvider;
102 | cachedInternals.$animateProvider = $animateProvider;
103 | }
104 |
105 | lazyAngularUtils = {
106 | cacheInternals: cacheInternals,
107 | captureQ: ["$q", promiseAdaptor.setQ],
108 | makeLazyAngular: makeLazyAngular,
109 | initLazyModules: initLazyModules,
110 | modulesQueue: []
111 | };
112 |
113 | return lazyAngularUtils;
114 | });
115 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/ngLazy.js:
--------------------------------------------------------------------------------
1 | define(["module", "./promiseAdaptorAngular", "./currentModule", "./lazyAngularUtils", "./bootstrap"],
2 | function(module, promiseAdaptor, currentModule, lazyAngularUtils, bootstrap) {
3 | "use strict";
4 |
5 | /** RequireJS module loader entry point. */
6 | function load(name, parentRequire, onload, config) {
7 | parentRequire(["lazy!" + name], function(stubModule) {
8 | if( !config || !config.isBuild ) {
9 | doDevTimeLoad(stubModule, onload);
10 | }
11 | else {
12 | onload(stubModule);
13 | }
14 | });
15 | }
16 |
17 | function doDevTimeLoad(stubModule, onload) {
18 | var realGet = stubModule.get, cachedRealModule, gotRealModule = false;
19 |
20 | stubModule.get = function() {
21 | var d = promiseAdaptor.makeDeferred();
22 | if( gotRealModule ) {
23 | d.resolve(cachedRealModule);
24 | }
25 | else {
26 | realGet.apply(stubModule).then(
27 | function(realModule) {
28 | currentModule.resolveWith(realModule);
29 | lazyAngularUtils.initLazyModules(bootstrap.injector);
30 | d.resolve(realModule);
31 | cachedRealModule = realModule;
32 | gotRealModule = true;
33 | realGet = null;
34 | },
35 | function error(err) {
36 | d.reject(err);
37 | }
38 | );
39 | }
40 | return promiseAdaptor.makePromise(d);
41 | };
42 |
43 | onload(stubModule);
44 | }
45 |
46 | return {
47 | load: load
48 | };
49 | });
50 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/promiseAdaptorAngular.js:
--------------------------------------------------------------------------------
1 | define(["angular"], function() {
2 | "use strict";
3 |
4 | var $q = null;
5 |
6 | return {
7 | makeDeferred: function() {
8 | return $q.defer();
9 | },
10 | makePromise: function(deferred) {
11 | return deferred.promise;
12 | },
13 | all: function(promises) {
14 | return $q.all(promises);
15 | },
16 | setQ: function(value) {
17 | $q = value;
18 | }
19 | };
20 | });
21 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/routeConfig.js:
--------------------------------------------------------------------------------
1 | /** This is based on angularjs-requirejs-lazy-controllers from github. */
2 | define(["./currentModule", "./lazyAngularUtils"], function(currentModule, lazyAngularUtils) {
3 | "use strict";
4 |
5 | function fromAmdModule(route,module) {
6 | var defer, templateDefer, loaded = false;
7 |
8 | return {
9 | controller: route.controller,
10 | resolve: {
11 | module: ["$q", "$route", "$templateCache", "$injector", function($q, $route, $templateCache, $injector) {
12 | if( typeof($route.current.template) !== "function" ) {
13 | if( templateDefer == null ) templateDefer = $q.defer();
14 | $route.current.template = function() {
15 | return templateDefer.promise;
16 | };
17 | };
18 |
19 | if( defer == null ) {
20 | defer = $q.defer();
21 |
22 | $q.when(module.get()).then(
23 | function(m) {
24 | if( m == null ) {
25 | defer.reject("module " + module.name + " does not export anything");
26 | return;
27 | }
28 |
29 | currentModule.resolveWith(m);
30 | // init any angular modules that were lazy loaded
31 | lazyAngularUtils.initLazyModules($injector);
32 | loaded = true;
33 | templateDefer.resolve($templateCache.get(route.template));
34 | defer.resolve(m);
35 | }, function(err) {
36 | // TODO
37 | defer.reject(err);
38 | }
39 | );
40 | }
41 |
42 | return defer.promise;
43 | }],
44 | amdModule: function() {
45 | return module;
46 | }
47 | }
48 | };
49 | }
50 |
51 | return {
52 | fromAmdModule: fromAmdModule
53 | };
54 | });
55 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/templateCache.js:
--------------------------------------------------------------------------------
1 | define(["module", "./currentModule"], function(module, currentModule) {
2 | "use strict";
3 |
4 | /** RequireJS module loader entry point. */
5 | function load(name, parentRequire, onload, config) {
6 | parentRequire(["text!" + name], function(t) {
7 | if( !config || !config.isBuild ) {
8 | currentModule.run(["$templateCache", function($templateCache) {
9 | $templateCache.put(name, t);
10 | }]);
11 | }
12 | onload({
13 | text: t,
14 | path: name
15 | });
16 | });
17 | }
18 |
19 | return {
20 | load: load
21 | };
22 | });
23 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/templateCacheBuilder.js:
--------------------------------------------------------------------------------
1 | //////////////////////////////////////
2 | // THIS IS OUTDATED AND UNUSED !!! //
3 | //////////////////////////////////////
4 | define(["module"], function(module) {
5 | "use strict";
6 |
7 | return {
8 | load: function(name, parentRequire, onload, config) {
9 | parentRequire(["text!" + name], function(t) {
10 | onload(t);
11 | });
12 | },
13 | write: function(pluginName, moduleName, write) {
14 | var text = "define('" + pluginName + "!" + moduleName + "',['currentModule','text!" + moduleName + "'],function(currentModule, t) {\n";
15 | text += "\tcurrentModule.run(['$templateCache', function($templateCache) {\n";
16 | text += "\t\t$templateCache.put('" + moduleName + "', t);\n";
17 | text += "\t}]);\n";
18 | text += "});\n";
19 | write(text);
20 | }
21 | };
22 | });
23 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/lib/angular-require-lazy/util.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | "use strict";
3 |
4 | function makeArray(arr) {
5 | var ret = arr, i, x;
6 | if( arr != null && !angular.isArray(arr) ) {
7 | ret =[];
8 | if( angular.isNumber(arr.length) ) {
9 | for( i=0; i < arr.length; i++ ) {
10 | x = arr[i];
11 | ret.push(x);
12 | }
13 | }
14 | }
15 | return ret;
16 | }
17 |
18 | return {
19 | makeArray: makeArray
20 | };
21 | });
22 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/loginPrompt.html:
--------------------------------------------------------------------------------
1 |
4 |
5 | IN PROGRESS...
6 |
7 |
10 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/loginPrompt.js:
--------------------------------------------------------------------------------
1 | define(["currentModule", "text!./loginPrompt.html", "lib/angular-ui-bootstrap/src/modal/modal"],
2 | function(currentModule, template) {
3 | "use strict";
4 |
5 | currentModule.service("loginPrompt", ["$modal", function($modal) {
6 | var
7 | isOpen = false,
8 |
9 | opts = {
10 | backdrop: "static",
11 | keyboard: false,
12 | template: template
13 | };
14 |
15 | function promptLogin() {
16 | isOpen = true;
17 | var d = $modal.open(opts);
18 | d.result["finally"](function() {
19 | isOpen = false;
20 | });
21 | return d.result;
22 | }
23 |
24 | promptLogin.isOpen = function() {
25 | return isOpen;
26 | };
27 |
28 | return promptLogin;
29 | }]);
30 | });
31 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/menuEntries.js:
--------------------------------------------------------------------------------
1 | define(["lazy-registry"], function(lazyRegistry) {
2 | "use strict";
3 |
4 | function makeMenuEntries() {
5 | var i, ret = [], module, modules = lazyRegistry.getModules();
6 | for( i=0; i < modules.length; i++ ) {
7 | module = modules[i];
8 | addMenuEntry(module,ret);
9 | }
10 | ret.sort(function(a,b) { return a.weight-b.weight; });
11 | return ret;
12 | }
13 |
14 | function addMenuEntry(module, entries) {
15 | if( module.metadata && module.metadata["angular-routes"] ) {
16 | var i, meta = module.metadata["angular-routes"];
17 | for( i=0; i < meta.length; i++ ) {
18 | entries.push({
19 | display: meta[i].display,
20 | path: meta[i].path,
21 | moduleName: module.name,
22 | weight: meta[i].weight
23 | });
24 | }
25 | }
26 | }
27 |
28 | return makeMenuEntries();
29 | });
30 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/modalTemplates.js:
--------------------------------------------------------------------------------
1 | define(["text!lib/angular-ui-bootstrap/template/modal/backdrop.html","text!lib/angular-ui-bootstrap/template/modal/window.html","currentModule"],
2 | function(backdropTemplate,windowTemplate,currentModule) {
3 | "use strict";
4 | currentModule.run(["$templateCache", function($templateCache) {
5 | $templateCache.put("template/modal/backdrop.html", backdropTemplate);
6 | $templateCache.put("template/modal/window.html", windowTemplate);
7 | }]);
8 | });
9 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/resourceUtils.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | "use strict";
3 |
4 | function transformResponse(data, headersGetter) {
5 | try {
6 | if( data != null && data != "" ) data = JSON.parse(data);
7 | else data = null;
8 | }
9 | catch(e) {
10 | return { $error: e, $rc: "FAILURE" };
11 | }
12 | if( data != null && typeof(data.payload) !== "undefined" ) {
13 | var ret = data.payload || [];
14 | if( $.isArray(data.messages) ) ret.$messages = data.messages;
15 | if( typeof(data.hasMore) === "boolean" ) ret.$hasMore = data.hasMore;
16 | if( data.exception == null ) {
17 | ret.$rc = "SUCCESS";
18 | }
19 | else {
20 | ret.$rc = "FAILURE";
21 | ret.$exception = data.exception;
22 | }
23 | return ret;
24 | }
25 | else return data;
26 | }
27 |
28 | return {
29 | transformResponse: transformResponse
30 | };
31 | });
32 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/returnService.js:
--------------------------------------------------------------------------------
1 | define(["currentModule"], function(currentModule) {
2 | "use strict";
3 |
4 | currentModule.service("returnService", ["$rootScope", "$location", function($rootScope, $location) {
5 | var stack = [], pushing = false, pushed = false, returning = false, returned = false, startController = null, currentState = null,
6 | currentPushedData = null, currentReturnedData = null;
7 |
8 | $rootScope.$on("$routeChangeSuccess", function(event, currentRoute, previousRoute) {
9 | if( pushing ) {
10 | // TODO
11 | }
12 | else if( returning ) {
13 | // TODO
14 | }
15 | else {
16 | clear();
17 | }
18 | startController = null;
19 | pushing = false;
20 | returning = false;
21 | });
22 |
23 | $rootScope.$on("$routeChangeStart", function(event, nextRoute, currentRoute) {
24 | startController = currentRoute.controller;
25 | });
26 |
27 | $rootScope.$on("$routeChangeError", function(event, currentRoute, previousRoute, rejection) {
28 | if( pushing ) {
29 | // TODO
30 | }
31 | else if( returning ) {
32 | // TODO
33 | }
34 | else {
35 | clear();
36 | }
37 | startController = null;
38 | pushing = false;
39 | returning = false;
40 | });
41 |
42 | function push(data, targetView) {
43 | pushing = true;
44 | stack.push({
45 | location: $location.hash(),
46 | currentState: currentState,
47 | currentPushedData: currentPushedData,
48 | pushed: pushed,
49 | returned: returned
50 | });
51 | currentState = null;
52 | currentPushedData = data;
53 | // set those here because the view gets rendered before the routeChangeSuccess event
54 | pushed = true;
55 | returned = false;
56 | if( typeof(targetView) === "string" ) $location.hash(targetView);
57 | }
58 |
59 | function doReturn(data) {
60 | var frame = stack.pop();
61 | returning = true;
62 | currentState = frame.currentState;
63 | currentPushedData = frame.currentPushedData;
64 | currentReturnedData = data;
65 | pushed = frame.pushed;
66 | returned = true;
67 | $location.hash(frame.location);
68 | }
69 |
70 | function getPushedData() {
71 | if( pushed ) return currentPushedData;
72 | else return null;
73 | }
74 |
75 | function getReturnedData() {
76 | if( returned ) return currentReturnedData;
77 | else return null;
78 | }
79 |
80 | function clear() {
81 | stack = [];
82 | currentState = null;
83 | currentPushedData = null;
84 | currentReturnedData = null;
85 | pushed = false;
86 | returned = false;
87 | }
88 |
89 | function isPushed() {
90 | return pushed;
91 | }
92 |
93 | function isReturned() {
94 | return returned;
95 | }
96 |
97 | function put(key, value) {
98 | if( currentState === null ) currentState = {};
99 | currentState[key] = value;
100 | }
101 |
102 | function get(key) {
103 | if( currentState === null ) return;
104 | return currentState[key];
105 | }
106 |
107 | return {
108 | push: push,
109 | doReturn: doReturn,
110 | getPushedData: getPushedData,
111 | getReturnedData: getReturnedData,
112 | clear: clear,
113 | isPushed: isPushed,
114 | isReturned: isReturned,
115 | put: put,
116 | get: get
117 | };
118 | }]);
119 | });
120 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/urlUtils.js:
--------------------------------------------------------------------------------
1 | define(["jquery", "globals"], function($, globals) {
2 | "use strict";
3 |
4 | var pathParamRe = /\{([a-zA-Z0-9]+)\}/;
5 |
6 | function Route(uri) {
7 | if( !(this instanceof Route) ) return new Route(uri);
8 | this._uri = $.trim(uri);
9 | }
10 |
11 | Route.prototype = {
12 | _uri: null,
13 | _uriComponents: null,
14 | _uriParams: null,
15 |
16 | applyParams: function(params) {
17 | var x, ret, comp, val;
18 | if( this._uriParams === null ) this._extractUriComponents();
19 | params = $.extend({}, params);
20 | ret = {
21 | uri: null,
22 | queryParams: params
23 | };
24 | comp = this._uriComponents.slice(0);
25 | for( x in this._uriParams ) {
26 | if( !this._uriParams.hasOwnProperty(x) ) continue;
27 | val = params[x];
28 | if( val == null ) throw new Error("required path param " + x + " missing from params - Route(" + this._uri + ")");
29 | if( $.isFunction(val) ) val = val();
30 | comp[this._uriParams[x]] = val;
31 | delete params[x];
32 | }
33 | ret.uri = "/" + comp.join("/");
34 | return ret;
35 | },
36 |
37 | _extractUriComponents: function() {
38 | var split, tmp, i, params={}, components=[];
39 | split = this._uri.split("/");
40 | for( i=0; i < split.length; i++ ) {
41 | if( !split[i] ) continue;
42 | if( pathParamRe.test(split[i]) ) {
43 | tmp = pathParamRe.exec(split[i])[1];
44 | params[tmp] = i;
45 | components.push(tmp);
46 | }
47 | else components.push(split[i]);
48 | }
49 | this._uriComponents = components;
50 | this._uriParams = params;
51 | },
52 |
53 | append: function(path) {
54 | var newUri = appendPath(this._uri, path);
55 | return new Route(newUri);
56 | }
57 | };
58 |
59 | function appendPath(pathNow, path) {
60 | if( path != null ) {
61 | path = ""+path;
62 | var nowEndsWithSlash = (pathNow.length > 0 && pathNow.charAt(pathNow.length-1) === "/"),
63 | pathStartsWithSlash = (path.length > 0 && path.charAt(0) === "/");
64 | if( nowEndsWithSlash && pathStartsWithSlash ) {
65 | pathNow += path.substring(1);
66 | }
67 | else if( (nowEndsWithSlash && !pathStartsWithSlash) || (!nowEndsWithSlash && pathStartsWithSlash) ) {
68 | pathNow += path;
69 | }
70 | else {
71 | pathNow += "/" + path;
72 | }
73 | }
74 | return pathNow;
75 | }
76 |
77 | function makeContextPath(path) {
78 | return appendPath(globals.contextPath.substr(1), path);
79 | }
80 |
81 | return {
82 | contextPath: globals.contextPath,
83 | Route: Route,
84 | appendPath: appendPath,
85 | makeContextPath: makeContextPath
86 | };
87 | });
88 |
--------------------------------------------------------------------------------
/WebContent/scripts/util/viewUtils.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | "use strict";
3 |
4 | function preprocessAnchorEvt(event) {
5 | if( event ) {
6 | if( typeof(event.preventDefault) === "function" ) event.preventDefault();
7 | if( event.currentTarget ) $(event.currentTarget).blur();
8 | }
9 | }
10 |
11 | return {
12 | preprocessAnchorEvt: preprocessAnchorEvt
13 | };
14 | });
15 |
--------------------------------------------------------------------------------
/WebTests/scripts/app/modules/categories/categoryDirective.spec.js:
--------------------------------------------------------------------------------
1 | define(["app/modules/categories/categoryDirective", "angular"], function(categoryDirective, angular) {
2 | describe("The categoryDirective", function() {
3 | var scope, wrapperElement, element, $compile;
4 |
5 | function compile(html) {
6 | wrapperElement = angular.element('' + html + '
');
7 | element = wrapperElement.find("div");
8 | $compile(wrapperElement)(scope);
9 | scope.$digest();
10 | }
11 |
12 | beforeEach(module("test-main"));
13 |
14 | beforeEach(inject(function($rootScope, _$compile_) {
15 | scope = $rootScope.$new();
16 | $compile = _$compile_;
17 | }));
18 |
19 | afterEach(function() {
20 | scope.$destroy();
21 | wrapperElement = element = null;
22 | });
23 |
24 | it("should pass", function() {
25 | scope.c = {
26 | key: "abc",
27 | name: "Abc"
28 | };
29 | scope.selectCategoryForEdit = jasmine.createSpy("selectCategoryForEdit");
30 | scope.deleteCategory = jasmine.createSpy("deleteCategory");
31 | compile('Span');
32 | // var editLink = element.find("a:not(.control-action)");
33 | var editLink = wrapperElement[0].querySelectorAll("a:not(.control-action)");
34 | //console.log(wrapperElement.html());
35 | expect(editLink.length).toBe(1);
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/WebTests/scripts/app/shared/dao/expensesDao.spec.js:
--------------------------------------------------------------------------------
1 | define(["app/shared/dao/expensesDao"], function(expensesDao) {
2 | describe("The expensesDao", function() {
3 | beforeEach(module("test-main"));
4 |
5 | it("should pass", function() {
6 | expect(1).toBe(1); //dummy
7 | });
8 | });
9 | });
10 |
--------------------------------------------------------------------------------
/WebTests/scripts/mocks/app/shared/dao/categoriesDao.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | return {};
3 | });
4 |
--------------------------------------------------------------------------------
/WebTests/scripts/mocks/lazy-registry.js:
--------------------------------------------------------------------------------
1 | define(['lazy','require','promise-adaptor'], function(lazy,require,promiseAdaptor) {
2 | var moduleList = [];
3 | function registerModule(m) {
4 | moduleList.push(m);
5 | lazy.registerModule(m);
6 | }
7 | registerModule(new lazy.Stub('app/modules/categories/main',require,null,null,{"angular-routes":[{"path":"/categories","controller":"EditCategoriesCtrl","template":"app/modules/categories/categoriesTemplate.html","display":"Categories","weight":100}]}));
8 | registerModule(new lazy.Stub('app/modules/expenses/main',require,null,null,{"angular-routes":[{"path":"/expenses","controller":"ExpensesCtrl","template":"app/modules/expenses/expensesTemplate.html","display":"Expenses","weight":200}]}));
9 | registerModule(new lazy.Stub('app/modules/index/main',require,null,null,{"angular-routes":[{"path":"/index","controller":"IndexCtrl","template":"app/modules/index/indexTemplate.html","display":"Home","weight":0}]}));
10 | return {
11 | getModules: function() { return moduleList; },
12 | getModule: lazy.getModule,
13 | get: function(moduleName) {
14 | var m = lazy.getModule(moduleName);
15 | if( m != null ) return m.get();
16 | else {
17 | var d = promiseAdaptor.makeDeferred();
18 | d.reject('does not exist');
19 | return promiseAdaptor.makePromise(d);
20 | }
21 | }
22 | };
23 | });
24 |
--------------------------------------------------------------------------------
/WebTests/scripts/mocks/require-cfg.js:
--------------------------------------------------------------------------------
1 | var require_config_main = require;
2 | delete require;
3 |
--------------------------------------------------------------------------------
/WebTests/scripts/mocks/test-main.js:
--------------------------------------------------------------------------------
1 | define([
2 | // injected dependencies
3 | "angular", "app/main/navbarCtrl",
4 | // side-effect deps
5 | "templateCache!app/main/navbar.html",
6 | // side-effect, non-AMD deps
7 | "lib/angular-route/angular-route", "lib/angular-ui-bootstrap/src/modal/modal"
8 | ],
9 | function(angular, navbarCtrl, navbarTemplate) {
10 | "use strict";
11 |
12 | var main = angular.module("test-main", ["ngMock", "ngRoute", "ui.bootstrap.collapse", "ui.bootstrap.modal"]);
13 |
14 | main.controller("NavbarCtrl", navbarCtrl);
15 |
16 | return main;
17 | });
18 |
--------------------------------------------------------------------------------
/WebTests/scripts/test-main.js:
--------------------------------------------------------------------------------
1 | var allTestFiles = [];
2 | var TEST_REGEXP = /(spec|test)\.js$/i;
3 |
4 | var globals = {
5 | contextPath: "/base"
6 | }, baseUrl;
7 |
8 |
9 | var pathToModule = function(path) {
10 | // return path.replace(/^\/base\/WebContent\/scripts\//, '').replace(/\.js$/, '');
11 | return path.replace(/^\/base\/WebContent\/scripts\//, '');
12 | };
13 |
14 | Object.keys(window.__karma__.files).forEach(function(file) {
15 | if( TEST_REGEXP.test(file) && file.indexOf('/base/WebContent/scripts/lib/') !== 0 ) {
16 | // Normalize paths to RequireJS module names.
17 | allTestFiles.push(pathToModule(file));
18 | }
19 | });
20 |
21 |
22 | require_config_main.paths["angular-mocks"] = "lib/angular-mocks/angular-mocks";
23 | require_config_main.shim["angular-mocks"] = {
24 | deps: ["angular"]
25 | };
26 |
27 |
28 | require.config({
29 | // Karma serves files under /base, which is the basePath from your config file
30 | baseUrl: '/base/WebContent/scripts',
31 |
32 | paths: require_config_main.paths,
33 |
34 | shim: require_config_main.shim,
35 |
36 | map: {
37 | "*": {
38 | "lazy-registry": "mocks/lazy-registry"
39 | },
40 | "app/shared/dao/expensesDao": {
41 | "util/resource": "mocks/util/resource"
42 | }
43 | },
44 |
45 | callback: function() {
46 | // we need to duplicate the Angular bootstrapping functionality from bootstrap.js
47 | require(["angular", "util/lib/angular-require-lazy/bootstrap", "angular-mocks"],
48 | function(angular, bootstrap) {
49 | // dynamically load all test files
50 | require(allTestFiles, function() {
51 | var main = angular.module("test-main", ["ngMock", "ui.bootstrap.modal"]);
52 | bootstrap(document, main);
53 | window.__karma__.start();
54 | });
55 | });
56 | }
57 | });
58 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var
2 | fs = require("fs"),
3 | express = require("express"),
4 | app = express(),
5 | options = require("./build-scripts/options-grunt.js"),
6 | shared = require("require-lazy").shared;
7 |
8 | app.use(express.logger('dev'));
9 | app.use(express.static(__dirname + '/build'));
10 | app.use(express.static(__dirname + '/WebContent'));
11 |
12 | // lazy registry
13 | app.get("/scripts/lazy-registry.js", getLazyRegistry);
14 |
15 | // API ////////////////////////////////////////////////////////////////////////
16 | app.post("/api/user/login", express.bodyParser(), function(req, res) {
17 | //console.log(req.body); // works as expected
18 | res.json({id:1, defaultCategoryId:1, preferences:null});
19 | });
20 |
21 | app.get("/api/user/:id/categories", function(req, res) {
22 | console.log(req.route.params.id); // works as expected
23 | res.json({
24 | "payload": [
25 | {"key": 1, "name": "Other"},
26 | {"key": 2, "name": "Rent"},
27 | {"key": 3, "name": "Food"},
28 | {"key": 4, "name": "Entertainment"}
29 | ]
30 | });
31 | });
32 |
33 | app.post("/api/user/:id/categories", singleStringBodyParser, function(req, res) {
34 | //console.log(require("util").inspect(req));
35 | //
36 | // $.ajax("/api/user/1/categories",{dataType:"json",contentType:"application/json",type:"POST",data:"CatName"}).then(function(x){console.log(x);})
37 | //
38 | ///////////////////////////////////////////////////////////////////////////
39 | // res.json({
40 | // "payload": {"key": parseInt(Math.random()*1000+1000), "name": req.body}
41 | // });
42 | ///////////////////////////////////////////////////////////////////////////
43 | setTimeout(function() { // simulate delay
44 | res.json({
45 | "payload": {"key": parseInt(Math.random()*1000+1000), "name": req.body}
46 | });
47 | }, 3000);
48 | });
49 |
50 | app.put("/api/user/:id/categories", express.bodyParser(), function(req, res) {
51 | var c = req.body;
52 | console.log("Changing name of category with key ", c.key, " to ", c.name);
53 | setTimeout(function() { // simulate delay
54 | res.json({
55 | "payload": Math.random() < 0.7 // simulate success with 70% chance
56 | });
57 | }, 1000);
58 | });
59 |
60 | app["delete"]("/api/user/:id/categories/:key", express.bodyParser(), function(req, res) {
61 | setTimeout(function() { // simulate delay
62 | res.json({
63 | "payload": true
64 | });
65 | }, 3000);
66 | });
67 |
68 | app.post("/api/user/:userid/expenses", express.bodyParser(), function(req, res) {
69 | console.log(req.body);
70 | res.json({id:1});
71 | });
72 |
73 | app.get("/api/user/:id/expenses", function(req, res) {
74 | console.log(req.route.params.id + " - " + req.query.year + "/" + req.query.month); // works as expected
75 | res.json({
76 | "payload": [
77 | {key:1, date:"2013-08-07T21:00:01.000Z", amount: 10, reason: "One", categoryId: 1, special: null},
78 | {key:2, date:"2013-08-08T21:00:02.000Z", amount: 12, reason: "Two", categoryId: 2, special: null},
79 | {key:3, date:"2013-08-08T21:00:03.000Z", amount: 14, reason: "Three", categoryId: 3, special: null},
80 | {key:4, date:"2013-08-08T21:00:04.000Z", amount: 15, reason: "Four", categoryId: 1, special: null},
81 | {key:5, date:"2013-08-08T21:00:05.000Z", amount: 18, reason: "Five", categoryId: 1, special: null},
82 | {key:11, date:"2013-08-08T21:00:11.000Z", amount: 10, reason: "One", categoryId: 2, special: null},
83 | {key:12, date:"2013-08-08T21:00:12.000Z", amount: 12, reason: "Two", categoryId: 2, special: null},
84 | {key:13, date:"2013-08-08T21:00:13.000Z", amount: 14, reason: "Three", categoryId: 1, special: null},
85 | {key:14, date:"2013-08-08T21:00:14.000Z", amount: 15, reason: "Four", categoryId: 1, special: null},
86 | {key:15, date:"2013-08-08T21:00:15.000Z", amount: 18, reason: "Five", categoryId: 1, special: null},
87 | {key:21, date:"2013-08-08T21:00:21.000Z", amount: 10, reason: "One", categoryId: 3, special: null},
88 | {key:22, date:"2013-08-08T21:00:22.000Z", amount: 12, reason: "Two", categoryId: 1, special: null},
89 | {key:23, date:"2013-08-08T21:00:23.000Z", amount: 14, reason: "Three", categoryId: 1, special: null},
90 | {key:24, date:"2013-08-08T21:00:24.000Z", amount: 15, reason: "Four", categoryId: 1, special: null},
91 | {key:25, date:"2013-08-09T21:00:25.000Z", amount: 18, reason: "Five", categoryId: 2, special: null}
92 | ]
93 | });
94 | });
95 | ///////////////////////////////////////////////////////////////////////////////
96 |
97 | app.listen(8110);
98 | console.log("Server running at http://localhost:8110 - get app.html or app-built.html");
99 |
100 |
101 | function getLazyRegistry(req, res) {
102 | var modules, text, i, metadata, pmresult;
103 |
104 | modules = options.discoverModules();
105 | pmresult = makePmresult(modules);
106 | text = shared.createModulesRegistryText(pmresult, options, {
107 | inludeModuleName: false,
108 | generateBody: true,
109 | nullBundleDeps: true,
110 | writeBundleRegistrations: false
111 | });
112 |
113 | res.type("application/javascript");
114 | res.send(text);
115 |
116 |
117 | function makePmresult(modules) {
118 | var i, dummyParents = ["DUMMY"], pmresult = {
119 | modulesArray: []
120 | };
121 |
122 | for( i=0; i < modules.length; i++ ) {
123 | pmresult.modulesArray.push({
124 | name: modules[i],
125 | index: i,
126 | parents: dummyParents
127 | });
128 | }
129 |
130 | return pmresult;
131 | }
132 | }
133 |
134 | function singleStringBodyParser(req, res, next) {
135 | var buf = "";
136 | req.setEncoding("utf8");
137 | req.on("data", onData);
138 | req.on("end", onEnd);
139 |
140 | function onData(chunk) {
141 | buf += chunk;
142 | }
143 |
144 | function onEnd() {
145 | req.body = buf;
146 | next();
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-expenses",
3 | "version": "0.6.2",
4 | "private": true,
5 | "dependencies": {
6 | "angular": "1.3.x",
7 | "angular-ui-bootstrap": "0.13.4",
8 | "requirejs": "latest",
9 | "requirejs-text": "latest",
10 | "almond": "latest",
11 | "jquery": "~2.1",
12 | "less.js": "1.7.2",
13 | "require-lazy": "latest",
14 | "ng-grid-bower": "latest",
15 | "angular-route": "1.3.x",
16 | "angular-resource": "1.3.x",
17 | "chartjs": "*"
18 | },
19 | "devDependencies": {
20 | "angular-mocks": "1.3.x"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/build-scripts/app.build-grunt.json:
--------------------------------------------------------------------------------
1 | {
2 | "appDir": "../WebContent/",
3 | "baseUrl": "scripts/",
4 | "mainConfigFile": "WebContent/scripts/require-cfg.js",
5 | "dir": "../build/IRRELEVANT",
6 | "inlineText": true,
7 | "name": "app/main/main",
8 | "optimize": "none",
9 | "normalizeDirDefines": true,
10 |
11 | "paths": {
12 | "jquery": "empty:",
13 | "angular": "empty:"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/build-scripts/discoverModules.js:
--------------------------------------------------------------------------------
1 | var path = require("path"), fs = require("fs");
2 |
3 | function discoverModules() {
4 | var modulesDir = path.normalize(path.join(__dirname, "..", "WebContent", "scripts", "app", "modules")),
5 | filenames = fs.readdirSync(modulesDir),
6 | stat, i, res = [];
7 | for( i=0; i < filenames.length; i++ ) {
8 | stat = fs.statSync(path.join(modulesDir, filenames[i], "main.metadata.json"));
9 | if( stat != null && stat.isFile() ) {
10 | res.push("app/modules/" + filenames[i] + "/main");
11 | }
12 | }
13 | return res;
14 | // return ["app/modules/index","app/modules/categories","app/modules/expenses"];
15 | }
16 |
17 | module.exports = discoverModules;
18 |
--------------------------------------------------------------------------------
/build-scripts/grunt/grunt.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | grunt.registerMultiTask("instrument", "Instrument with istanbul", function() {
3 | var istanbul = require("istanbul"),
4 | instrumenter,
5 | options,
6 | instrumenterOptions,
7 | baselineCollector;
8 |
9 | options = this.options({
10 | });
11 |
12 | if( options.baseline ) {
13 | baselineCollector = new istanbul.Collector();
14 | }
15 |
16 | instrumenterOptions = {
17 | coverageVariable: options.coverageVariable || "__coverage__",
18 | embedSource: options.embedSource || false,
19 | preserveComments: options.preserveComments || false,
20 | noCompact: options.noCompact || false,
21 | noAutoWrap: options.noAutoWrap || false,
22 | codeGenerationOptions: options.codeGenerationOptions,
23 | debug: options.debug || false,
24 | walkDebug: options.walkDebug || false
25 | };
26 |
27 | instrumenter = new istanbul.Instrumenter(instrumenterOptions);
28 |
29 | this.files.forEach(function(f) {
30 | //console.log(f.src, " -> ", f.dest);
31 | if( f.src.length !== 1 ) {
32 | throw new Error("encountered src with length: " + f.src.length + ": " + JSON.stringify(f.src));
33 | }
34 | var filename = f.src[0],
35 | code = grunt.file.read(filename, {encoding: grunt.file.defaultEncoding}),
36 | result = instrumenter.instrumentSync(code, filename),
37 | baseline,
38 | coverage;
39 |
40 | if( options.baseline ) {
41 | baseline = instrumenter.lastFileCoverage();
42 | coverage = {};
43 | coverage[baseline.path] = baseline;
44 | baselineCollector.add(coverage);
45 | }
46 |
47 | grunt.file.write(f.dest, result, {encoding: grunt.file.defaultEncoding});
48 | });
49 |
50 | if( options.baseline ) {
51 | grunt.file.write(options.baseline, JSON.stringify(baselineCollector.getFinalCoverage()), {encoding: grunt.file.defaultEncoding});
52 | }
53 | });
54 | };
55 |
--------------------------------------------------------------------------------
/build-scripts/karma/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "preprocessor:preInstrumented": ["factory", require("./preInstrumentedPreprocessor")],
3 | "reporter:coverage": ["type", require("./reporter")]
4 | };
5 |
--------------------------------------------------------------------------------
/build-scripts/karma/preInstrumentedPreprocessor.js:
--------------------------------------------------------------------------------
1 | var path = require("path"),
2 | fs = require("fs");
3 |
4 | createPreInstrumentedPreprocessor.$inject = ["args", "config.preInstrumentedPreprocessor", "config.basePath", "logger", "helper"];
5 | function createPreInstrumentedPreprocessor(args, config, basePath, logger, helper) {
6 | var STRIP_PREFIX_RE = new RegExp("^" + path.join(basePath, config.stripPrefix).replace(/\\/g, "\\\\"));
7 |
8 | function instrumentedFilePath(file) {
9 | return path.join(basePath, config.basePath, path.normalize(file.originalPath).replace(STRIP_PREFIX_RE, ""));
10 | }
11 |
12 | return function(content, file, done) {
13 | fs.readFile(instrumentedFilePath(file), {encoding:"utf8"}, function(err, instrumentedContent) {
14 | if( err ) throw err;
15 | done(instrumentedContent);
16 | });
17 | };
18 | }
19 |
20 | module.exports = createPreInstrumentedPreprocessor;
21 |
--------------------------------------------------------------------------------
/build-scripts/karma/reporter.js:
--------------------------------------------------------------------------------
1 | // DERIVED FROM THE COVERAGE REPORTER OF KARMA, https://github.com/karma-runner/karma-coverage/blob/master/lib/reporter.js
2 | var path = require('path');
3 | var fs = require('fs');
4 | var util = require('util');
5 | var istanbul = require('istanbul');
6 | var dateformat = require('dateformat');
7 |
8 |
9 | var Store = istanbul.Store;
10 |
11 | var BasePathStore = function(opts) {
12 | Store.call(this, opts);
13 | opts = opts || {};
14 | this.basePath = opts.basePath;
15 | this.delegate = Store.create('fslookup');
16 | };
17 | BasePathStore.TYPE = 'basePathlookup';
18 | util.inherits(BasePathStore, Store);
19 |
20 | Store.mix(BasePathStore, {
21 | keys : function() {
22 | return this.delegate.keys();
23 | },
24 | toKey : function(key) {
25 | if (key.indexOf('./') === 0) { return path.join(this.basePath, key); }
26 | return key;
27 | },
28 | get : function(key) {
29 | return this.delegate.get(this.toKey(key));
30 | },
31 | hasKey : function(key) {
32 | return this.delegate.hasKey(this.toKey(key));
33 | },
34 | set : function(key, contents) {
35 | return this.delegate.set(this.toKey(key), contents);
36 | }
37 | });
38 |
39 |
40 | // TODO(vojta): inject only what required (config.basePath, config.coverageReporter)
41 | var CoverageReporter = function(rootConfig, helper, logger) {
42 | var log = logger.create('coverage');
43 | var config = rootConfig.coverageReporter || {};
44 | var basePath = rootConfig.basePath;
45 | var reporters = config.reporters;
46 | var baseLine;
47 |
48 | if (config.baseLine) {
49 | baseLine = JSON.parse(fs.readFileSync(path.join(basePath, config.baseLine), {encoding:"utf8"}));
50 | }
51 |
52 | if (!helper.isDefined(reporters)) {
53 | reporters = [config];
54 | }
55 |
56 | this.adapters = [];
57 | var collectors;
58 | var pendingFileWritings = 0;
59 | var fileWritingFinished = function() {};
60 |
61 | function writeEnd() {
62 | if (!--pendingFileWritings) {
63 | // cleanup collectors
64 | Object.keys(collectors).forEach(function(key) {
65 | collectors[key].dispose();
66 | });
67 | fileWritingFinished();
68 | }
69 | }
70 |
71 | /**
72 | * Generate the output directory from the `coverageReporter.dir` and
73 | * `coverageReporter.subdir` options.
74 | *
75 | * @param {String} browserName - The browser name
76 | * @param {String} dir - The given option
77 | * @param {String|Function} subdir - The given option
78 | *
79 | * @return {String} - The output directory
80 | */
81 | function generateOutputDir(browserName, dir, subdir) {
82 | dir = dir || 'coverage';
83 | subdir = subdir || browserName;
84 |
85 | if (typeof subdir === 'function') {
86 | subdir = subdir(browserName);
87 | }
88 |
89 | return path.join(dir, subdir);
90 | }
91 |
92 | this.onRunStart = function(browsers) {
93 | collectors = Object.create(null);
94 |
95 | // TODO(vojta): remove once we don't care about Karma 0.10
96 | if (browsers) {
97 | browsers.forEach(function(browser) {
98 | collectors[browser.id] = new istanbul.Collector();
99 | });
100 | }
101 | };
102 |
103 | this.onBrowserStart = function(browser) {
104 | var collector = new istanbul.Collector();
105 | if( baseLine ) {
106 | collector.add(baseLine);
107 | }
108 | collectors[browser.id] = collector;
109 | };
110 |
111 | this.onBrowserComplete = function(browser, result) {
112 | var collector = collectors[browser.id];
113 |
114 | if (!collector) {
115 | return;
116 | }
117 |
118 | if (result && result.coverage) {
119 | collector.add(result.coverage);
120 | }
121 | };
122 |
123 | this.onSpecComplete = function(browser, result) {
124 | if (result.coverage) {
125 | collectors[browser.id].add(result.coverage);
126 | }
127 | };
128 |
129 | this.onRunComplete = function(browsers) {
130 | reporters.forEach(function(reporterConfig) {
131 | browsers.forEach(function(browser) {
132 |
133 | var collector = collectors[browser.id];
134 | if (collector) {
135 | pendingFileWritings++;
136 |
137 | var outputDir = helper.normalizeWinPath(path.resolve(basePath, generateOutputDir(browser.name,
138 | reporterConfig.dir || config.dir,
139 | reporterConfig.subdir || config.subdir)));
140 |
141 | helper.mkdirIfNotExists(outputDir, function() {
142 | log.debug('Writing coverage to %s', outputDir);
143 | var options = helper.merge({}, reporterConfig, {
144 | dir : outputDir,
145 | sourceStore : new BasePathStore({
146 | basePath : basePath
147 | })
148 | });
149 | var reporter = istanbul.Report.create(reporterConfig.type || 'html', options);
150 | try {
151 | reporter.writeReport(collector, true);
152 | } catch (e) {
153 | log.error(e);
154 | }
155 | writeEnd();
156 | });
157 | }
158 |
159 | });
160 | });
161 | };
162 |
163 | this.onExit = function(done) {
164 | if (pendingFileWritings) {
165 | fileWritingFinished = done;
166 | } else {
167 | done();
168 | }
169 | };
170 | };
171 |
172 | CoverageReporter.$inject = ['config', 'helper', 'logger'];
173 |
174 | // PUBLISH
175 | module.exports = CoverageReporter;
176 |
--------------------------------------------------------------------------------
/build-scripts/options-grunt.js:
--------------------------------------------------------------------------------
1 | var
2 | path = require("path"),
3 | fs = require("fs"),
4 | discoverModules = require("./discoverModules");
5 |
6 | module.exports = {
7 | // this must match the map['*'].lazy property in require-cfg.js
8 | libLazy: "lib/require-lazy/lazy",
9 | basePath: path.normalize(path.join(__dirname, "..", "WebContent")),
10 | outputBaseDir: path.normalize(path.join(__dirname, "..", "build")),
11 | discoverModules: discoverModules,
12 | retrieveMetaForModule: retrieveMetaForModule,
13 | makeBuildRelativePath: function(x) {
14 | return path.normalize(path.join(__dirname, "..", x));
15 | }
16 | };
17 |
18 | function retrieveMetaForModule(moduleName) {
19 | var
20 | stat = null,
21 | filename = path.normalize(path.join(__dirname, "../WebContent/scripts/", moduleName + ".metadata.json")),
22 | ret = null;
23 | try {
24 | stat = fs.statSync(filename);
25 | }
26 | catch(ignore) {}
27 | if( stat !== null && stat.isFile() ) {
28 | try {
29 | ret = fs.readFileSync(filename);
30 | ret = JSON.parse(ret);
31 | }
32 | catch(e) {
33 | ret = null;
34 | console.log(e);
35 | }
36 | }
37 | return ret;
38 | }
39 |
--------------------------------------------------------------------------------
/build-stats/.gitignore:
--------------------------------------------------------------------------------
1 | modules.js
2 | bundles.js
3 |
4 |
--------------------------------------------------------------------------------
/build-stats/amd.html:
--------------------------------------------------------------------------------
1 |
2 | AMD Modules
3 |
4 |
5 |
6 | | {{k}} |
7 | {{v.id}} |
8 | Exclusive |
9 | {{v.includedIn}} |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/build-stats/bundles.html:
--------------------------------------------------------------------------------
1 |
2 | Bundles
3 |
4 |
5 | -
6 | {{bundle.id}} Exclusive: {{bundle.exclusive}} Included in: {{bundle.includedIn}}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/build-stats/deps.html:
--------------------------------------------------------------------------------
1 |
2 |
+–
3 | {{heading}}
…:
4 |
5 |
6 |
7 | | # |
8 | AMD Module |
9 | Bundle |
10 |
11 |
12 |
13 |
14 | | {{$index+1}}. |
15 | {{dep}} |
16 | {{depsToBundleMap[dep].id}} |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/build-stats/f.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var obj = {
4 | internal : {}
5 | };
6 |
7 | Object.freeze(obj);
8 | obj.internal.a = "aValue";
9 |
10 | console.log(obj.internal.a); // "aValue"
11 |
12 | // To make obj fully immutable, freeze each object in obj.
13 | // To do so, we use this function.
14 |
15 | function deepFreeze (o) {
16 | var prop, propKey;
17 | Object.freeze(o); // First freeze the object.
18 | for (propKey in o) {
19 | prop = o[propKey];
20 | if (!o.hasOwnProperty(propKey) || !(typeof prop === "object") || Object.isFrozen(prop)) {
21 | // If the object is on the prototype, not an object, or is already frozen,
22 | // skip it. Note that this might leave an unfrozen reference somewhere in the
23 | // object if there is an already frozen object containing an unfrozen object.
24 | continue;
25 | }
26 |
27 | deepFreeze(prop); // Recursively call deepFreeze.
28 | }
29 | }
30 |
31 | var obj2 = {
32 | internal : {}
33 | };
34 |
35 | deepFreeze(obj2);
36 | obj2.internal.a = "anotherValue";
37 | console.log(obj2.internal.a); // undefined
38 |
--------------------------------------------------------------------------------
/build-stats/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Stats
6 |
29 |
30 |
31 |
32 |
35 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/build-stats/modules.html:
--------------------------------------------------------------------------------
1 |
2 | Modules
3 |
4 |
5 | -
6 | {{mname}} {{module.hash}}
7 |
8 |
9 | Parents:
10 | [
]
13 |
14 |
15 |
16 | Bundle Dependencies:
17 | [
]
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/build-stats/stats.js:
--------------------------------------------------------------------------------
1 | var app = angular.module("app", ["ngRoute"]);
2 |
3 | app.config(function($routeProvider) {
4 | $routeProvider.when("/modules", {controller:"ModulesCtrl", templateUrl:"modules.html", reloadOnSearch:false});
5 | $routeProvider.when("/bundles", {controller:"BundlesCtrl", templateUrl:"bundles.html", reloadOnSearch:false});
6 | $routeProvider.when("/amd", {controller:"AmdCtrl", templateUrl:"amd.html", reloadOnSearch:false});
7 | $routeProvider.otherwise({redirectTo: "/modules"});
8 | });
9 |
10 | app.controller("ModulesCtrl", function($scope, modules, $location) {
11 | $scope.modules = modules;
12 |
13 | $scope.toggle = function(x, $event) {
14 | $event.preventDefault();
15 | if( x == null ) return;
16 | if( x.$ui == null ) x.$ui = {};
17 | if( x.$ui.on = !x.$ui.on ) {
18 | // $location.replace();
19 | // $location.search("m", x.name);
20 | }
21 | // else {
22 | // if( $location.search("m") === x.name ) {
23 | // $location.replace();
24 | // $location.search("m", null);
25 | // }
26 | // }
27 | };
28 |
29 | $scope.collapseAll = function() {
30 | var x;
31 | for( x in modules ) {
32 | if( !modules.hasOwnProperty(x) ) continue;
33 | x = modules[x];
34 | if( x.$ui ) {
35 | x.$ui.on = false;
36 | x.$ui.depsOn = false;
37 | }
38 | }
39 | };
40 | });
41 |
42 | app.controller("BundlesCtrl", function($scope, bundles, $location) {
43 | $scope.bundles = bundles.bundlesArray;
44 |
45 | initSelection();
46 |
47 | $scope.toggle = function(x, $event) {
48 | $event.preventDefault();
49 | if( x == null ) return;
50 | if( x.$ui == null ) x.$ui = {};
51 | if( x.$ui.on = !x.$ui.on ) {
52 | // $location.replace();
53 | // $location.search("b", x.name);
54 | }
55 | };
56 |
57 | $scope.collapseAll = function() {
58 | var x;
59 | for( x in $scope.bundles ) {
60 | if( !$scope.bundles.hasOwnProperty(x) ) continue;
61 | x = $scope.bundles[x];
62 | if( x.$ui ) {
63 | x.$ui.on = false;
64 | x.$ui.depsOn = false;
65 | }
66 | }
67 | };
68 |
69 | function initSelection() {
70 | var selection = $location.search().b, i;
71 | if( selection ) {
72 | for( i=0; i < $scope.bundles.length; i++ ) {
73 | if( $scope.bundles[i].id === selection ) {
74 | if( $scope.bundles[i].$ui == null ) $scope.bundles[i].$ui = {};
75 | $scope.bundles[i].$ui.on = true;
76 | break;
77 | }
78 | }
79 | }
80 | }
81 | });
82 |
83 | app.directive("depsList", function() {
84 | return {
85 | restrict: "EA",
86 | templateUrl: "deps.html",
87 | replace: true,
88 | scope: {
89 | x: "=item",
90 | deps: "=",
91 | flag: "=",
92 | heading: "@"
93 | },
94 | controller: function($scope, bundles) {
95 | $scope.depsToBundleMap = bundles.depsToBundleMap;
96 | $scope.toggleDeps = function($event) {
97 | $event.preventDefault();
98 | $scope.flag = !$scope.flag;
99 | };
100 | }
101 | };
102 | });
103 |
104 | app.controller("SanityCtrl", function($scope, bundles, modules) {
105 | });
106 |
107 | app.controller("AmdCtrl", function($scope, bundles, modules) {
108 | $scope.depsToBundleMap = bundles.depsToBundleMap;
109 | });
110 |
--------------------------------------------------------------------------------
/karma-coverage.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | // base path that will be used to resolve all patterns (eg. files, exclude)
4 | basePath: '',
5 |
6 | // frameworks to use
7 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
8 | frameworks: [
9 | 'jasmine',
10 | 'requirejs',
11 | 'angular-require-lazy'
12 | ],
13 |
14 | plugins: [
15 | 'karma-phantomjs-launcher',
16 | 'karma-jasmine',
17 | 'karma-requirejs',
18 | // TODO Add our RequireJS configuration by using an inlined plugin, see http://karma-runner.github.io/0.12/config/plugins.html
19 | {
20 | 'framework:angular-require-lazy': ['factory', (function() {
21 | function alrPlugin(files) {
22 | files.unshift({pattern: __dirname + '/WebTests/scripts/mocks/require-cfg.js', included: true, served: true, watched: false});
23 | files.unshift({pattern: __dirname + '/WebContent/scripts/require-cfg.js', included: true, served: true, watched: false});
24 | }
25 | alrPlugin.$inject = ['config.files'];
26 | return alrPlugin;
27 | })()]
28 | },
29 | require('./build-scripts/karma')
30 | ],
31 |
32 | // list of files / patterns to load in the browser
33 | files: [
34 | 'WebTests/scripts/test-main.js',
35 | {pattern: 'WebContent/scripts/lib/jquery/dist/jquery.js', included: true},
36 | {pattern: 'WebContent/scripts/**/*.html', included: false},
37 | {pattern: 'WebContent/scripts/*.js', included: false},
38 | {pattern: 'WebContent/scripts/app/**/*.js', included: false},
39 | {pattern: 'WebContent/scripts/util/**/*.js', included: false},
40 | {pattern: 'WebContent/scripts/lib/**/*.js', included: false},
41 | {pattern: 'WebTests/scripts/**/*.js', included: false}
42 | ],
43 |
44 | // list of files to exclude
45 | exclude: [
46 | 'WebContent/scripts/lib/**/*.spec.js'
47 | ],
48 |
49 | // preprocess matching files before serving them to the browser
50 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
51 | preprocessors: {
52 | 'WebContent/scripts/app/**/*.js': 'preInstrumented',
53 | 'WebContent/scripts/util/**/*.js': 'preInstrumented'
54 | },
55 |
56 | preInstrumentedPreprocessor: {
57 | basePath: 'build-coverage/instrumented',
58 | stripPrefix: 'WebContent'
59 | },
60 |
61 | // test results reporter to use
62 | // possible values: 'dots', 'progress'
63 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
64 | reporters: [
65 | 'progress',
66 | 'coverage'
67 | ],
68 |
69 | coverageReporter: {
70 | type: 'lcov',
71 | dir: 'build-coverage/report',
72 | subdir: function(browser) {
73 | return 'output';
74 | },
75 | baseLine: 'build-coverage/baseline.json'
76 | },
77 |
78 | // web server port
79 | port: 9876,
80 |
81 | // enable / disable colors in the output (reporters and logs)
82 | colors: true,
83 |
84 | // level of logging
85 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
86 | logLevel: config.LOG_INFO,
87 |
88 | // enable / disable watching file and executing tests whenever any file changes
89 | autoWatch: true,
90 |
91 | // start these browsers
92 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
93 | // browsers: ['Firefox'],
94 | browsers: ['PhantomJS'],
95 |
96 | // Continuous Integration mode
97 | // if true, Karma captures browsers, runs the tests and exits
98 | singleRun: false
99 | });
100 | };
101 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | // base path that will be used to resolve all patterns (eg. files, exclude)
4 | basePath: '',
5 |
6 | // frameworks to use
7 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
8 | frameworks: [
9 | 'jasmine',
10 | 'requirejs',
11 | 'angular-require-lazy'
12 | ],
13 |
14 | plugins: [
15 | 'karma-phantomjs-launcher',
16 | 'karma-jasmine',
17 | 'karma-requirejs',
18 | // TODO Add our RequireJS configuration by using an inlined plugin, see http://karma-runner.github.io/0.12/config/plugins.html
19 | {
20 | 'framework:angular-require-lazy': ['factory', (function() {
21 | function alrPlugin(files) {
22 | files.unshift({pattern: __dirname + '/WebTests/scripts/mocks/require-cfg.js', included: true, served: true, watched: false});
23 | files.unshift({pattern: __dirname + '/WebContent/scripts/require-cfg.js', included: true, served: true, watched: false});
24 | }
25 | alrPlugin.$inject = ['config.files'];
26 | return alrPlugin;
27 | })()]
28 | }
29 | ],
30 |
31 | // list of files / patterns to load in the browser
32 | files: [
33 | 'WebTests/scripts/test-main.js',
34 | {pattern: 'WebContent/scripts/lib/jquery/dist/jquery.js', included: true},
35 | {pattern: 'WebContent/scripts/**/*.html', included: false},
36 | {pattern: 'WebContent/scripts/*.js', included: false},
37 | {pattern: 'WebContent/scripts/app/**/*.js', included: false},
38 | {pattern: 'WebContent/scripts/util/**/*.js', included: false},
39 | {pattern: 'WebContent/scripts/lib/**/*.js', included: false},
40 | {pattern: 'WebTests/scripts/**/*.js', included: false}
41 | ],
42 |
43 | // list of files to exclude
44 | exclude: [
45 | 'WebContent/scripts/lib/**/*.spec.js'
46 | ],
47 |
48 | // preprocess matching files before serving them to the browser
49 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
50 | preprocessors: {
51 |
52 | },
53 |
54 | // test results reporter to use
55 | // possible values: 'dots', 'progress'
56 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
57 | reporters: ['progress'],
58 |
59 | // web server port
60 | port: 9876,
61 |
62 | // enable / disable colors in the output (reporters and logs)
63 | colors: true,
64 |
65 | // level of logging
66 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
67 | logLevel: config.LOG_INFO,
68 |
69 | // enable / disable watching file and executing tests whenever any file changes
70 | autoWatch: true,
71 |
72 | // start these browsers
73 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
74 | // browsers: ['Firefox'],
75 | browsers: ['PhantomJS'],
76 |
77 | // Continuous Integration mode
78 | // if true, Karma captures browsers, runs the tests and exits
79 | singleRun: false
80 | });
81 | };
82 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-expenses",
3 | "description": "An experiment for mixing Angular, RequireJS and require-lazy",
4 | "version": "0.6.2",
5 | "private": true,
6 | "dependencies": {
7 | "express": "3.x",
8 | "require-lazy": ">=0.3.8"
9 | },
10 | "devDependencies": {
11 | "grunt": "~0.4",
12 | "require-lazy-grunt": ">=0.2.0",
13 | "grunt-contrib-clean": "*",
14 | "grunt-contrib-copy": "*",
15 | "grunt-contrib-less": "0.12.0",
16 | "grunt-karma": "*",
17 | "bower": "*",
18 | "karma": "*",
19 | "karma-jasmine": "~0.2.0",
20 | "karma-chrome-launcher": "*",
21 | "karma-firefox-launcher": "*",
22 | "karma-requirejs": "*",
23 | "karma-phantomjs-launcher": "*",
24 | "istanbul": "*",
25 | "dateformat": "~1.0.6"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.projectKey=nikospara:angular-require-lazy
2 | sonar.projectName=angular-require-lazy
3 | sonar.projectVersion=0.6.0
4 | sonar.language=js
5 | sonar.sources=WebContent/scripts/app,WebContent/scripts/util
6 | sonar.sourceEncoding=UTF-8
7 | # To import the LCOV report
8 | sonar.javascript.lcov.reportPath=build-coverage/report/output/lcov.info
9 |
--------------------------------------------------------------------------------