├── .eslintrc ├── .gitignore ├── .travis.yml ├── app ├── css │ ├── app.css │ ├── normalize.css │ └── unsemantic-grid-responsive.css ├── index.html ├── js │ ├── app.js │ ├── controller │ │ ├── edit_todo.js │ │ ├── footer.js │ │ ├── imprint.js │ │ ├── index.js │ │ ├── todo.js │ │ └── todo_list.js │ └── service │ │ ├── imprint.js │ │ ├── index.js │ │ └── todos.js └── views │ ├── imprint.html │ └── todos.html ├── bin ├── browserify.sh ├── start-selenium.sh └── watchify.sh ├── gulpfile.js ├── karma.conf.js ├── karma.conf.js.travis ├── package.json ├── protractor.conf.js ├── protractor.conf.js.travis ├── readme.markdown └── test ├── browserified ├── .gitignore └── index.html ├── e2e ├── delete_todo_spec.js ├── edit_todo_spec.js ├── list_todo_spec.js ├── new_todo_spec.js ├── pages │ └── todo_page.js └── select_todo_spec.js ├── mocha.opts └── unit ├── controller ├── edit_todo.js └── todo_list.js └── service ├── imprint.js └── todos.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "mocha": true, 5 | "node": true, 6 | "amd": false 7 | }, 8 | "rules": { 9 | "no-alert": 2, 10 | "no-array-constructor": 2, 11 | "no-bitwise": 0, 12 | "no-caller": 2, 13 | "no-catch-shadow": 2, 14 | "no-comma-dangle": 0, 15 | "no-cond-assign": 2, 16 | "no-console": 2, 17 | "no-constant-condition": 2, 18 | "no-control-regex": 2, 19 | "no-debugger": 2, 20 | "no-delete-var": 2, 21 | "no-div-regex": 0, 22 | "no-dupe-keys": 2, 23 | "no-else-return": 0, 24 | "no-empty": 2, 25 | "no-empty-character-class": 2, 26 | "no-empty-label": 2, 27 | "no-eq-null": 0, 28 | "no-eval": 2, 29 | "no-ex-assign": 2, 30 | "no-extend-native": 2, 31 | "no-extra-boolean-cast": 2, 32 | "no-extra-parens": 0, 33 | "no-extra-semi": 2, 34 | "no-fallthrough": 2, 35 | "no-floating-decimal": 0, 36 | "no-func-assign": 2, 37 | "no-global-strict": 0, 38 | "no-implied-eval": 2, 39 | "no-invalid-regexp": 2, 40 | "no-iterator": 2, 41 | "no-label-var": 2, 42 | "no-labels": 2, 43 | "no-lone-blocks": 2, 44 | "no-lonely-if": 0, 45 | "no-loop-func": 2, 46 | "no-mixed-requires": [0, false], 47 | "no-multi-str": 2, 48 | "no-native-reassign": 2, 49 | "no-negated-in-lhs": 2, 50 | "no-nested-ternary": 0, 51 | "no-new": 2, 52 | "no-new-func": 2, 53 | "no-new-object": 2, 54 | "no-new-require": 0, 55 | "no-new-wrappers": 2, 56 | "no-obj-calls": 2, 57 | "no-octal": 2, 58 | "no-octal-escape": 2, 59 | "no-path-concat": 0, 60 | "no-plusplus": 0, 61 | "no-process-exit": 2, 62 | "no-proto": 2, 63 | "no-redeclare": 2, 64 | "no-regex-spaces": 2, 65 | "no-restricted-modules": 0, 66 | "no-return-assign": 2, 67 | "no-script-url": 2, 68 | "no-self-compare": 0, 69 | "no-sequences": 2, 70 | "no-shadow": 2, 71 | "no-shadow-restricted-names": 2, 72 | "no-spaced-func": 2, 73 | "semi-spacing": 2, 74 | "no-sparse-arrays": 2, 75 | "no-sync": 0, 76 | "no-ternary": 0, 77 | "no-undef": 2, 78 | "no-undef-init": 2, 79 | "no-underscore-dangle": 2, 80 | "no-unreachable": 2, 81 | "no-unused-expressions": 0, 82 | "no-unused-vars": [2, {"vars": "local", "args": "after-used"}], 83 | "no-use-before-define": 0, 84 | "no-warning-comments": [0, { "terms": ["todo", "fixme", "xxx"], "location": "start" }], 85 | "no-with": 2, 86 | "no-extra-parens": 2, 87 | "yoda": [2, "never"], 88 | 89 | "block-scoped-var": 0, 90 | "brace-style": [0, "1tbs"], 91 | "camelcase": 2, 92 | "complexity": [0, 11], 93 | "consistent-return": 2, 94 | "consistent-this": [0, "that"], 95 | "curly": [2, "all"], 96 | "default-case": 0, 97 | "dot-notation": 2, 98 | "eqeqeq": 2, 99 | "func-names": 0, 100 | "func-style": [0, "declaration"], 101 | "guard-for-in": 0, 102 | "max-depth": [0, 4], 103 | "max-len": [0, 80, 4], 104 | "max-nested-callbacks": [0, 2], 105 | "max-params": [0, 3], 106 | "max-statements": [0, 10], 107 | "handle-callback-err": 0, 108 | "new-cap": 0, 109 | "new-parens": 2, 110 | "one-var": 0, 111 | "quote-props": 0, 112 | "quotes": [2, "single"], 113 | "radix": 0, 114 | "semi": 2, 115 | "sort-vars": 0, 116 | "space-after-keywords": [0, "always"], 117 | "space-in-brackets": [0, "never"], 118 | "space-infix-ops": 2, 119 | "space-return-throw-case": 2, 120 | "space-unary-word-ops": 0, 121 | "strict": [2, "global"], 122 | "use-isnan": 2, 123 | "valid-jsdoc": 0, 124 | "valid-typeof": 2, 125 | "wrap-iife": 0, 126 | "wrap-regex": 0 127 | }, 128 | "globals": { 129 | "browser": true, 130 | "by": true, 131 | "element": true, 132 | "expect": true, 133 | "protractor": true, 134 | "xdescribe": true, 135 | "xit": true 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | # vim tmp files 4 | *.swp 5 | *.un~ 6 | 7 | app/ngmin 8 | app/ngAnnotate 9 | app/dist 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | - '4' 5 | - '5' 6 | 7 | before_script: 8 | - npm install -g phantomjs@1.9.8 9 | - cp protractor.conf.js.travis protractor.conf.js 10 | - cp karma.conf.js.travis karma.conf.js 11 | - export DISPLAY=:99.0 12 | - sh -e /etc/init.d/xvfb start 13 | -------------------------------------------------------------------------------- /app/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #ddd; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | padding: 20px; 5 | } 6 | 7 | img { 8 | vertical-align: middle; 9 | } 10 | 11 | input { 12 | font: inherit; 13 | font-family: inherit; 14 | margin: 0; 15 | } 16 | 17 | .content { 18 | max-width: 960px; 19 | } 20 | 21 | .span-save { 22 | text-decoration: none; 23 | vertical-align: middle; 24 | } 25 | 26 | .margins { 27 | margin-top: 2px; 28 | margin-bottom: 3px; 29 | margin-left: 3px; 30 | margin-right: 3px; 31 | } 32 | 33 | .padding { 34 | padding-top: 2px; 35 | padding-bottom: 2px; 36 | padding-left: 7px; 37 | padding-top: 2px; 38 | } 39 | 40 | .rounded-box { 41 | border-width: 0px; 42 | border-radius: 4px; 43 | } 44 | 45 | button { 46 | margin: 0em; 47 | font: -webkit-small-control; 48 | color: initial; 49 | letter-spacing: normal; 50 | word-spacing: normal; 51 | text-transform: none; 52 | text-indent: 0px; 53 | text-shadow: none; 54 | display: inline-block; 55 | text-align: start; 56 | } 57 | 58 | .btn { 59 | display: inline-block; 60 | font-weight: normal; 61 | text-align: center; 62 | vertical-align: middle; 63 | cursor: pointer; 64 | background-image: none; 65 | border: 1px solid ; 66 | white-space: nowrap; 67 | padding: 6px 12px; 68 | font-size: 14px; 69 | line-height: 1.42857143; 70 | border-radius: 4px; 71 | -webkit-user-select: none; 72 | -moz-user-select: none; 73 | -ms-user-select: none; 74 | user-select: none; 75 | color: #ccc; 76 | background-color: #203040; 77 | border-color: #102030; 78 | } 79 | 80 | .btn:hover, .btn:focus, .btn:active { 81 | color: #fff; 82 | border-color: #102030; 83 | background-color: #506070; 84 | } 85 | 86 | .dark-blue-bg { 87 | background-color: #203040; 88 | } 89 | 90 | .medium-blue-bg { 91 | background-color: #304050; 92 | } 93 | 94 | .text-on-blue { 95 | color: #ccc; 96 | } 97 | 98 | .sidebar-heading { 99 | border-top-left-radius: 4px; 100 | border-top-right-radius: 4px; 101 | padding-top: 7px; 102 | padding-bottom: 7px; 103 | padding-left: 7px; 104 | font-size: 1.3em; 105 | } 106 | 107 | .sidebar-heading-skin { 108 | border-bottom-style: solid; 109 | border-bottom-width: 1px; 110 | border-bottom-color: #071720; 111 | } 112 | 113 | .sidebar-item-borders { 114 | color: inherit; 115 | border-top-width: 1px; 116 | border-top-style: solid; 117 | border-top-color: #304050; 118 | border-bottom-width: 1px; 119 | border-bottom-style: solid; 120 | border-bottom-color: #071720; 121 | border-right-width: 0px; 122 | border-left-width: 0px; 123 | } 124 | 125 | .sidebar-item-borders:last-child { 126 | border-bottom-width: 0px; 127 | border-bottom-left-radius: 4px; 128 | border-bottom-right-radius: 4px; 129 | } 130 | 131 | .sidebar-item { 132 | display: block; 133 | padding: 5px 15px; 134 | position: relative; 135 | color: inherit; 136 | text-decoration: inherit; 137 | } 138 | 139 | .sidebar-item-inactive { 140 | cursor: pointer; 141 | } 142 | 143 | /* highlight hovered item a bit... */ 144 | a:hover.sidebar-item { 145 | color: #eee; 146 | text-decoration: inherit; 147 | } 148 | /* ...but not if it is already selected */ 149 | a:hover.sidebar-item-active { 150 | color: inherit; 151 | text-decoration: inherit; 152 | } 153 | 154 | /* needs to be defined after sidebar-item */ 155 | .sidebar-item-active { 156 | font-weight: bold; 157 | border-top-color: #031017; 158 | border-bottom-color: #203040; 159 | background-image: none; 160 | background-color: #102030; 161 | cursor: default; 162 | } 163 | 164 | /* in headline */ 165 | .current-item { 166 | font-size: 18px; 167 | font-weight: bold; 168 | height: 28px; 169 | line-height: 36px; 170 | } 171 | 172 | .current-item-edit { 173 | width: 80%; 174 | color: #333; 175 | line-height: 18px; 176 | } 177 | 178 | .todo-text { 179 | height: 200px; 180 | background-color: #eee; 181 | } 182 | 183 | .todo-text-edit { 184 | width: 97%; 185 | } 186 | 187 | .footer { 188 | font-size: small; 189 | width: 100%; 190 | text-align: center; 191 | } 192 | -------------------------------------------------------------------------------- /app/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.0 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined in IE 8/9. 28 | */ 29 | 30 | article, 31 | aside, 32 | details, 33 | figcaption, 34 | figure, 35 | footer, 36 | header, 37 | hgroup, 38 | main, 39 | nav, 40 | section, 41 | summary { 42 | display: block; 43 | } 44 | 45 | /** 46 | * 1. Correct `inline-block` display not defined in IE 8/9. 47 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 48 | */ 49 | 50 | audio, 51 | canvas, 52 | progress, 53 | video { 54 | display: inline-block; /* 1 */ 55 | vertical-align: baseline; /* 2 */ 56 | } 57 | 58 | /** 59 | * Prevent modern browsers from displaying `audio` without controls. 60 | * Remove excess height in iOS 5 devices. 61 | */ 62 | 63 | audio:not([controls]) { 64 | display: none; 65 | height: 0; 66 | } 67 | 68 | /** 69 | * Address `[hidden]` styling not present in IE 8/9. 70 | * Hide the `template` element in IE, Safari, and Firefox < 22. 71 | */ 72 | 73 | [hidden], 74 | template { 75 | display: none; 76 | } 77 | 78 | /* Links 79 | ========================================================================== */ 80 | 81 | /** 82 | * Remove the gray background color from active links in IE 10. 83 | */ 84 | 85 | a { 86 | background: transparent; 87 | } 88 | 89 | /** 90 | * Improve readability when focused and also mouse hovered in all browsers. 91 | */ 92 | 93 | a:active, 94 | a:hover { 95 | outline: 0; 96 | } 97 | 98 | /* Text-level semantics 99 | ========================================================================== */ 100 | 101 | /** 102 | * Address styling not present in IE 8/9, Safari 5, and Chrome. 103 | */ 104 | 105 | abbr[title] { 106 | border-bottom: 1px dotted; 107 | } 108 | 109 | /** 110 | * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 111 | */ 112 | 113 | b, 114 | strong { 115 | font-weight: bold; 116 | } 117 | 118 | /** 119 | * Address styling not present in Safari 5 and Chrome. 120 | */ 121 | 122 | dfn { 123 | font-style: italic; 124 | } 125 | 126 | /** 127 | * Address variable `h1` font-size and margin within `section` and `article` 128 | * contexts in Firefox 4+, Safari 5, and Chrome. 129 | */ 130 | 131 | h1 { 132 | font-size: 2em; 133 | margin: 0.67em 0; 134 | } 135 | 136 | /** 137 | * Address styling not present in IE 8/9. 138 | */ 139 | 140 | mark { 141 | background: #ff0; 142 | color: #000; 143 | } 144 | 145 | /** 146 | * Address inconsistent and variable font size in all browsers. 147 | */ 148 | 149 | small { 150 | font-size: 80%; 151 | } 152 | 153 | /** 154 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 155 | */ 156 | 157 | sub, 158 | sup { 159 | font-size: 75%; 160 | line-height: 0; 161 | position: relative; 162 | vertical-align: baseline; 163 | } 164 | 165 | sup { 166 | top: -0.5em; 167 | } 168 | 169 | sub { 170 | bottom: -0.25em; 171 | } 172 | 173 | /* Embedded content 174 | ========================================================================== */ 175 | 176 | /** 177 | * Remove border when inside `a` element in IE 8/9. 178 | */ 179 | 180 | img { 181 | border: 0; 182 | } 183 | 184 | /** 185 | * Correct overflow displayed oddly in IE 9. 186 | */ 187 | 188 | svg:not(:root) { 189 | overflow: hidden; 190 | } 191 | 192 | /* Grouping content 193 | ========================================================================== */ 194 | 195 | /** 196 | * Address margin not present in IE 8/9 and Safari 5. 197 | */ 198 | 199 | figure { 200 | margin: 1em 40px; 201 | } 202 | 203 | /** 204 | * Address differences between Firefox and other browsers. 205 | */ 206 | 207 | hr { 208 | -moz-box-sizing: content-box; 209 | box-sizing: content-box; 210 | height: 0; 211 | } 212 | 213 | /** 214 | * Contain overflow in all browsers. 215 | */ 216 | 217 | pre { 218 | overflow: auto; 219 | } 220 | 221 | /** 222 | * Address odd `em`-unit font size rendering in all browsers. 223 | */ 224 | 225 | code, 226 | kbd, 227 | pre, 228 | samp { 229 | font-family: monospace, monospace; 230 | font-size: 1em; 231 | } 232 | 233 | /* Forms 234 | ========================================================================== */ 235 | 236 | /** 237 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 238 | * styling of `select`, unless a `border` property is set. 239 | */ 240 | 241 | /** 242 | * 1. Correct color not being inherited. 243 | * Known issue: affects color of disabled elements. 244 | * 2. Correct font properties not being inherited. 245 | * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. 246 | */ 247 | 248 | button, 249 | input, 250 | optgroup, 251 | select, 252 | textarea { 253 | color: inherit; /* 1 */ 254 | font: inherit; /* 2 */ 255 | margin: 0; /* 3 */ 256 | } 257 | 258 | /** 259 | * Address `overflow` set to `hidden` in IE 8/9/10. 260 | */ 261 | 262 | button { 263 | overflow: visible; 264 | } 265 | 266 | /** 267 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 268 | * All other form control elements do not inherit `text-transform` values. 269 | * Correct `button` style inheritance in Firefox, IE 8+, and Opera 270 | * Correct `select` style inheritance in Firefox. 271 | */ 272 | 273 | button, 274 | select { 275 | text-transform: none; 276 | } 277 | 278 | /** 279 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 280 | * and `video` controls. 281 | * 2. Correct inability to style clickable `input` types in iOS. 282 | * 3. Improve usability and consistency of cursor style between image-type 283 | * `input` and others. 284 | */ 285 | 286 | button, 287 | html input[type="button"], /* 1 */ 288 | input[type="reset"], 289 | input[type="submit"] { 290 | -webkit-appearance: button; /* 2 */ 291 | cursor: pointer; /* 3 */ 292 | } 293 | 294 | /** 295 | * Re-set default cursor for disabled elements. 296 | */ 297 | 298 | button[disabled], 299 | html input[disabled] { 300 | cursor: default; 301 | } 302 | 303 | /** 304 | * Remove inner padding and border in Firefox 4+. 305 | */ 306 | 307 | button::-moz-focus-inner, 308 | input::-moz-focus-inner { 309 | border: 0; 310 | padding: 0; 311 | } 312 | 313 | /** 314 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 315 | * the UA stylesheet. 316 | */ 317 | 318 | input { 319 | line-height: normal; 320 | } 321 | 322 | /** 323 | * It's recommended that you don't attempt to style these elements. 324 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 325 | * 326 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 327 | * 2. Remove excess padding in IE 8/9/10. 328 | */ 329 | 330 | input[type="checkbox"], 331 | input[type="radio"] { 332 | box-sizing: border-box; /* 1 */ 333 | padding: 0; /* 2 */ 334 | } 335 | 336 | /** 337 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 338 | * `font-size` values of the `input`, it causes the cursor style of the 339 | * decrement button to change from `default` to `text`. 340 | */ 341 | 342 | input[type="number"]::-webkit-inner-spin-button, 343 | input[type="number"]::-webkit-outer-spin-button { 344 | height: auto; 345 | } 346 | 347 | /** 348 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 349 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome 350 | * (include `-moz` to future-proof). 351 | */ 352 | 353 | input[type="search"] { 354 | -webkit-appearance: textfield; /* 1 */ 355 | -moz-box-sizing: content-box; 356 | -webkit-box-sizing: content-box; /* 2 */ 357 | box-sizing: content-box; 358 | } 359 | 360 | /** 361 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 362 | * Safari (but not Chrome) clips the cancel button when the search input has 363 | * padding (and `textfield` appearance). 364 | */ 365 | 366 | input[type="search"]::-webkit-search-cancel-button, 367 | input[type="search"]::-webkit-search-decoration { 368 | -webkit-appearance: none; 369 | } 370 | 371 | /** 372 | * Define consistent border, margin, and padding. 373 | */ 374 | 375 | fieldset { 376 | border: 1px solid #c0c0c0; 377 | margin: 0 2px; 378 | padding: 0.35em 0.625em 0.75em; 379 | } 380 | 381 | /** 382 | * 1. Correct `color` not being inherited in IE 8/9. 383 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 384 | */ 385 | 386 | legend { 387 | border: 0; /* 1 */ 388 | padding: 0; /* 2 */ 389 | } 390 | 391 | /** 392 | * Remove default vertical scrollbar in IE 8/9. 393 | */ 394 | 395 | textarea { 396 | overflow: auto; 397 | } 398 | 399 | /** 400 | * Don't inherit the `font-weight` (applied by a rule above). 401 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 402 | */ 403 | 404 | optgroup { 405 | font-weight: bold; 406 | } 407 | 408 | /* Tables 409 | ========================================================================== */ 410 | 411 | /** 412 | * Remove most spacing between table cells. 413 | */ 414 | 415 | table { 416 | border-collapse: collapse; 417 | border-spacing: 0; 418 | } 419 | 420 | td, 421 | th { 422 | padding: 0; 423 | } 424 | -------------------------------------------------------------------------------- /app/css/unsemantic-grid-responsive.css: -------------------------------------------------------------------------------- 1 | /* ============================================ */ 2 | /* This file has a mobile-to-desktop breakpoint */ 3 | /* ============================================ */ 4 | @media screen and (max-width: 400px) { 5 | @-ms-viewport { 6 | width: 320px; 7 | } 8 | } 9 | @media all { 10 | .clear { 11 | clear: both; 12 | display: block; 13 | overflow: hidden; 14 | visibility: hidden; 15 | width: 0; 16 | height: 0; 17 | } 18 | 19 | .grid-container:before, .clearfix:before, 20 | .grid-container:after, 21 | .clearfix:after { 22 | content: "."; 23 | display: block; 24 | overflow: hidden; 25 | visibility: hidden; 26 | font-size: 0; 27 | line-height: 0; 28 | width: 0; 29 | height: 0; 30 | } 31 | 32 | .grid-container:after, .clearfix:after { 33 | clear: both; 34 | } 35 | 36 | .grid-container, .clearfix { 37 | /* */ 38 | *zoom: 1; 39 | /* */ 40 | } 41 | 42 | .grid-container { 43 | margin-left: auto; 44 | margin-right: auto; 45 | max-width: 1200px; 46 | padding-left: 10px; 47 | padding-right: 10px; 48 | } 49 | 50 | .grid-5, .mobile-grid-5, .grid-10, .mobile-grid-10, .grid-15, .mobile-grid-15, .grid-20, .mobile-grid-20, .grid-25, .mobile-grid-25, .grid-30, .mobile-grid-30, .grid-35, .mobile-grid-35, .grid-40, .mobile-grid-40, .grid-45, .mobile-grid-45, .grid-50, .mobile-grid-50, .grid-55, .mobile-grid-55, .grid-60, .mobile-grid-60, .grid-65, .mobile-grid-65, .grid-70, .mobile-grid-70, .grid-75, .mobile-grid-75, .grid-80, .mobile-grid-80, .grid-85, .mobile-grid-85, .grid-90, .mobile-grid-90, .grid-95, .mobile-grid-95, .grid-100, .mobile-grid-100, .grid-33, .mobile-grid-33, .grid-66, .mobile-grid-66 { 51 | -webkit-box-sizing: border-box; 52 | -moz-box-sizing: border-box; 53 | box-sizing: border-box; 54 | padding-left: 10px; 55 | padding-right: 10px; 56 | /* */ 57 | *padding-left: 0; 58 | *padding-right: 0; 59 | /* */ 60 | } 61 | .grid-5 > *, .mobile-grid-5 > *, .grid-10 > *, .mobile-grid-10 > *, .grid-15 > *, .mobile-grid-15 > *, .grid-20 > *, .mobile-grid-20 > *, .grid-25 > *, .mobile-grid-25 > *, .grid-30 > *, .mobile-grid-30 > *, .grid-35 > *, .mobile-grid-35 > *, .grid-40 > *, .mobile-grid-40 > *, .grid-45 > *, .mobile-grid-45 > *, .grid-50 > *, .mobile-grid-50 > *, .grid-55 > *, .mobile-grid-55 > *, .grid-60 > *, .mobile-grid-60 > *, .grid-65 > *, .mobile-grid-65 > *, .grid-70 > *, .mobile-grid-70 > *, .grid-75 > *, .mobile-grid-75 > *, .grid-80 > *, .mobile-grid-80 > *, .grid-85 > *, .mobile-grid-85 > *, .grid-90 > *, .mobile-grid-90 > *, .grid-95 > *, .mobile-grid-95 > *, .grid-100 > *, .mobile-grid-100 > *, .grid-33 > *, .mobile-grid-33 > *, .grid-66 > *, .mobile-grid-66 > * { 62 | /* */ 63 | *margin-left: expression((!this.className.match(/grid-[1-9]/) && this.currentStyle.display === "block" && this.currentStyle.width === "auto") && "10px"); 64 | *margin-right: expression((!this.className.match(/grid-[1-9]/) && this.currentStyle.display === "block" && this.currentStyle.width === "auto") && "10px"); 65 | /* */ 66 | } 67 | 68 | .grid-parent { 69 | padding-left: 0; 70 | padding-right: 0; 71 | } 72 | } 73 | @media screen and (max-width: 767px) { 74 | .mobile-grid-100:before, 75 | .mobile-grid-100:after { 76 | content: "."; 77 | display: block; 78 | overflow: hidden; 79 | visibility: hidden; 80 | font-size: 0; 81 | line-height: 0; 82 | width: 0; 83 | height: 0; 84 | } 85 | 86 | .mobile-grid-100:after { 87 | clear: both; 88 | } 89 | 90 | .mobile-grid-100 { 91 | /* */ 92 | *zoom: 1; 93 | /* */ 94 | } 95 | 96 | .mobile-push-5, 97 | .mobile-pull-5, .mobile-push-10, 98 | .mobile-pull-10, .mobile-push-15, 99 | .mobile-pull-15, .mobile-push-20, 100 | .mobile-pull-20, .mobile-push-25, 101 | .mobile-pull-25, .mobile-push-30, 102 | .mobile-pull-30, .mobile-push-35, 103 | .mobile-pull-35, .mobile-push-40, 104 | .mobile-pull-40, .mobile-push-45, 105 | .mobile-pull-45, .mobile-push-50, 106 | .mobile-pull-50, .mobile-push-55, 107 | .mobile-pull-55, .mobile-push-60, 108 | .mobile-pull-60, .mobile-push-65, 109 | .mobile-pull-65, .mobile-push-70, 110 | .mobile-pull-70, .mobile-push-75, 111 | .mobile-pull-75, .mobile-push-80, 112 | .mobile-pull-80, .mobile-push-85, 113 | .mobile-pull-85, .mobile-push-90, 114 | .mobile-pull-90, .mobile-push-95, 115 | .mobile-pull-95, .mobile-push-33, 116 | .mobile-pull-33, .mobile-push-66, 117 | .mobile-pull-66 { 118 | position: relative; 119 | } 120 | 121 | .hide-on-mobile { 122 | display: none !important; 123 | } 124 | 125 | .mobile-grid-5 { 126 | float: left; 127 | width: 5%; 128 | /* */ 129 | *width: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 130 | /* */ 131 | } 132 | 133 | .mobile-prefix-5 { 134 | margin-left: 5%; 135 | } 136 | 137 | .mobile-suffix-5 { 138 | margin-right: 5%; 139 | } 140 | 141 | .mobile-push-5 { 142 | left: 5%; 143 | /* */ 144 | *left: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 145 | /* */ 146 | } 147 | 148 | .mobile-pull-5 { 149 | left: -5%; 150 | /* */ 151 | *left: expression(Math.floor(-0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 152 | /* */ 153 | } 154 | 155 | .mobile-grid-10 { 156 | float: left; 157 | width: 10%; 158 | /* */ 159 | *width: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 160 | /* */ 161 | } 162 | 163 | .mobile-prefix-10 { 164 | margin-left: 10%; 165 | } 166 | 167 | .mobile-suffix-10 { 168 | margin-right: 10%; 169 | } 170 | 171 | .mobile-push-10 { 172 | left: 10%; 173 | /* */ 174 | *left: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 175 | /* */ 176 | } 177 | 178 | .mobile-pull-10 { 179 | left: -10%; 180 | /* */ 181 | *left: expression(Math.floor(-0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 182 | /* */ 183 | } 184 | 185 | .mobile-grid-15 { 186 | float: left; 187 | width: 15%; 188 | /* */ 189 | *width: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 190 | /* */ 191 | } 192 | 193 | .mobile-prefix-15 { 194 | margin-left: 15%; 195 | } 196 | 197 | .mobile-suffix-15 { 198 | margin-right: 15%; 199 | } 200 | 201 | .mobile-push-15 { 202 | left: 15%; 203 | /* */ 204 | *left: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 205 | /* */ 206 | } 207 | 208 | .mobile-pull-15 { 209 | left: -15%; 210 | /* */ 211 | *left: expression(Math.floor(-0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 212 | /* */ 213 | } 214 | 215 | .mobile-grid-20 { 216 | float: left; 217 | width: 20%; 218 | /* */ 219 | *width: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 220 | /* */ 221 | } 222 | 223 | .mobile-prefix-20 { 224 | margin-left: 20%; 225 | } 226 | 227 | .mobile-suffix-20 { 228 | margin-right: 20%; 229 | } 230 | 231 | .mobile-push-20 { 232 | left: 20%; 233 | /* */ 234 | *left: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 235 | /* */ 236 | } 237 | 238 | .mobile-pull-20 { 239 | left: -20%; 240 | /* */ 241 | *left: expression(Math.floor(-0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 242 | /* */ 243 | } 244 | 245 | .mobile-grid-25 { 246 | float: left; 247 | width: 25%; 248 | /* */ 249 | *width: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 250 | /* */ 251 | } 252 | 253 | .mobile-prefix-25 { 254 | margin-left: 25%; 255 | } 256 | 257 | .mobile-suffix-25 { 258 | margin-right: 25%; 259 | } 260 | 261 | .mobile-push-25 { 262 | left: 25%; 263 | /* */ 264 | *left: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 265 | /* */ 266 | } 267 | 268 | .mobile-pull-25 { 269 | left: -25%; 270 | /* */ 271 | *left: expression(Math.floor(-0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 272 | /* */ 273 | } 274 | 275 | .mobile-grid-30 { 276 | float: left; 277 | width: 30%; 278 | /* */ 279 | *width: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 280 | /* */ 281 | } 282 | 283 | .mobile-prefix-30 { 284 | margin-left: 30%; 285 | } 286 | 287 | .mobile-suffix-30 { 288 | margin-right: 30%; 289 | } 290 | 291 | .mobile-push-30 { 292 | left: 30%; 293 | /* */ 294 | *left: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 295 | /* */ 296 | } 297 | 298 | .mobile-pull-30 { 299 | left: -30%; 300 | /* */ 301 | *left: expression(Math.floor(-0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 302 | /* */ 303 | } 304 | 305 | .mobile-grid-35 { 306 | float: left; 307 | width: 35%; 308 | /* */ 309 | *width: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 310 | /* */ 311 | } 312 | 313 | .mobile-prefix-35 { 314 | margin-left: 35%; 315 | } 316 | 317 | .mobile-suffix-35 { 318 | margin-right: 35%; 319 | } 320 | 321 | .mobile-push-35 { 322 | left: 35%; 323 | /* */ 324 | *left: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 325 | /* */ 326 | } 327 | 328 | .mobile-pull-35 { 329 | left: -35%; 330 | /* */ 331 | *left: expression(Math.floor(-0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 332 | /* */ 333 | } 334 | 335 | .mobile-grid-40 { 336 | float: left; 337 | width: 40%; 338 | /* */ 339 | *width: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 340 | /* */ 341 | } 342 | 343 | .mobile-prefix-40 { 344 | margin-left: 40%; 345 | } 346 | 347 | .mobile-suffix-40 { 348 | margin-right: 40%; 349 | } 350 | 351 | .mobile-push-40 { 352 | left: 40%; 353 | /* */ 354 | *left: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 355 | /* */ 356 | } 357 | 358 | .mobile-pull-40 { 359 | left: -40%; 360 | /* */ 361 | *left: expression(Math.floor(-0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 362 | /* */ 363 | } 364 | 365 | .mobile-grid-45 { 366 | float: left; 367 | width: 45%; 368 | /* */ 369 | *width: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 370 | /* */ 371 | } 372 | 373 | .mobile-prefix-45 { 374 | margin-left: 45%; 375 | } 376 | 377 | .mobile-suffix-45 { 378 | margin-right: 45%; 379 | } 380 | 381 | .mobile-push-45 { 382 | left: 45%; 383 | /* */ 384 | *left: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 385 | /* */ 386 | } 387 | 388 | .mobile-pull-45 { 389 | left: -45%; 390 | /* */ 391 | *left: expression(Math.floor(-0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 392 | /* */ 393 | } 394 | 395 | .mobile-grid-50 { 396 | float: left; 397 | width: 50%; 398 | /* */ 399 | *width: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 400 | /* */ 401 | } 402 | 403 | .mobile-prefix-50 { 404 | margin-left: 50%; 405 | } 406 | 407 | .mobile-suffix-50 { 408 | margin-right: 50%; 409 | } 410 | 411 | .mobile-push-50 { 412 | left: 50%; 413 | /* */ 414 | *left: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 415 | /* */ 416 | } 417 | 418 | .mobile-pull-50 { 419 | left: -50%; 420 | /* */ 421 | *left: expression(Math.floor(-0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 422 | /* */ 423 | } 424 | 425 | .mobile-grid-55 { 426 | float: left; 427 | width: 55%; 428 | /* */ 429 | *width: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 430 | /* */ 431 | } 432 | 433 | .mobile-prefix-55 { 434 | margin-left: 55%; 435 | } 436 | 437 | .mobile-suffix-55 { 438 | margin-right: 55%; 439 | } 440 | 441 | .mobile-push-55 { 442 | left: 55%; 443 | /* */ 444 | *left: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 445 | /* */ 446 | } 447 | 448 | .mobile-pull-55 { 449 | left: -55%; 450 | /* */ 451 | *left: expression(Math.floor(-0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 452 | /* */ 453 | } 454 | 455 | .mobile-grid-60 { 456 | float: left; 457 | width: 60%; 458 | /* */ 459 | *width: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 460 | /* */ 461 | } 462 | 463 | .mobile-prefix-60 { 464 | margin-left: 60%; 465 | } 466 | 467 | .mobile-suffix-60 { 468 | margin-right: 60%; 469 | } 470 | 471 | .mobile-push-60 { 472 | left: 60%; 473 | /* */ 474 | *left: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 475 | /* */ 476 | } 477 | 478 | .mobile-pull-60 { 479 | left: -60%; 480 | /* */ 481 | *left: expression(Math.floor(-0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 482 | /* */ 483 | } 484 | 485 | .mobile-grid-65 { 486 | float: left; 487 | width: 65%; 488 | /* */ 489 | *width: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 490 | /* */ 491 | } 492 | 493 | .mobile-prefix-65 { 494 | margin-left: 65%; 495 | } 496 | 497 | .mobile-suffix-65 { 498 | margin-right: 65%; 499 | } 500 | 501 | .mobile-push-65 { 502 | left: 65%; 503 | /* */ 504 | *left: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 505 | /* */ 506 | } 507 | 508 | .mobile-pull-65 { 509 | left: -65%; 510 | /* */ 511 | *left: expression(Math.floor(-0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 512 | /* */ 513 | } 514 | 515 | .mobile-grid-70 { 516 | float: left; 517 | width: 70%; 518 | /* */ 519 | *width: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 520 | /* */ 521 | } 522 | 523 | .mobile-prefix-70 { 524 | margin-left: 70%; 525 | } 526 | 527 | .mobile-suffix-70 { 528 | margin-right: 70%; 529 | } 530 | 531 | .mobile-push-70 { 532 | left: 70%; 533 | /* */ 534 | *left: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 535 | /* */ 536 | } 537 | 538 | .mobile-pull-70 { 539 | left: -70%; 540 | /* */ 541 | *left: expression(Math.floor(-0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 542 | /* */ 543 | } 544 | 545 | .mobile-grid-75 { 546 | float: left; 547 | width: 75%; 548 | /* */ 549 | *width: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 550 | /* */ 551 | } 552 | 553 | .mobile-prefix-75 { 554 | margin-left: 75%; 555 | } 556 | 557 | .mobile-suffix-75 { 558 | margin-right: 75%; 559 | } 560 | 561 | .mobile-push-75 { 562 | left: 75%; 563 | /* */ 564 | *left: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 565 | /* */ 566 | } 567 | 568 | .mobile-pull-75 { 569 | left: -75%; 570 | /* */ 571 | *left: expression(Math.floor(-0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 572 | /* */ 573 | } 574 | 575 | .mobile-grid-80 { 576 | float: left; 577 | width: 80%; 578 | /* */ 579 | *width: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 580 | /* */ 581 | } 582 | 583 | .mobile-prefix-80 { 584 | margin-left: 80%; 585 | } 586 | 587 | .mobile-suffix-80 { 588 | margin-right: 80%; 589 | } 590 | 591 | .mobile-push-80 { 592 | left: 80%; 593 | /* */ 594 | *left: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 595 | /* */ 596 | } 597 | 598 | .mobile-pull-80 { 599 | left: -80%; 600 | /* */ 601 | *left: expression(Math.floor(-0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 602 | /* */ 603 | } 604 | 605 | .mobile-grid-85 { 606 | float: left; 607 | width: 85%; 608 | /* */ 609 | *width: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 610 | /* */ 611 | } 612 | 613 | .mobile-prefix-85 { 614 | margin-left: 85%; 615 | } 616 | 617 | .mobile-suffix-85 { 618 | margin-right: 85%; 619 | } 620 | 621 | .mobile-push-85 { 622 | left: 85%; 623 | /* */ 624 | *left: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 625 | /* */ 626 | } 627 | 628 | .mobile-pull-85 { 629 | left: -85%; 630 | /* */ 631 | *left: expression(Math.floor(-0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 632 | /* */ 633 | } 634 | 635 | .mobile-grid-90 { 636 | float: left; 637 | width: 90%; 638 | /* */ 639 | *width: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 640 | /* */ 641 | } 642 | 643 | .mobile-prefix-90 { 644 | margin-left: 90%; 645 | } 646 | 647 | .mobile-suffix-90 { 648 | margin-right: 90%; 649 | } 650 | 651 | .mobile-push-90 { 652 | left: 90%; 653 | /* */ 654 | *left: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 655 | /* */ 656 | } 657 | 658 | .mobile-pull-90 { 659 | left: -90%; 660 | /* */ 661 | *left: expression(Math.floor(-0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 662 | /* */ 663 | } 664 | 665 | .mobile-grid-95 { 666 | float: left; 667 | width: 95%; 668 | /* */ 669 | *width: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 670 | /* */ 671 | } 672 | 673 | .mobile-prefix-95 { 674 | margin-left: 95%; 675 | } 676 | 677 | .mobile-suffix-95 { 678 | margin-right: 95%; 679 | } 680 | 681 | .mobile-push-95 { 682 | left: 95%; 683 | /* */ 684 | *left: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 685 | /* */ 686 | } 687 | 688 | .mobile-pull-95 { 689 | left: -95%; 690 | /* */ 691 | *left: expression(Math.floor(-0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 692 | /* */ 693 | } 694 | 695 | .mobile-grid-33 { 696 | float: left; 697 | width: 33.33333%; 698 | /* */ 699 | *width: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 700 | /* */ 701 | } 702 | 703 | .mobile-prefix-33 { 704 | margin-left: 33.33333%; 705 | } 706 | 707 | .mobile-suffix-33 { 708 | margin-right: 33.33333%; 709 | } 710 | 711 | .mobile-push-33 { 712 | left: 33.33333%; 713 | /* */ 714 | *left: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 715 | /* */ 716 | } 717 | 718 | .mobile-pull-33 { 719 | left: -33.33333%; 720 | /* */ 721 | *left: expression(Math.floor(-0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 722 | /* */ 723 | } 724 | 725 | .mobile-grid-66 { 726 | float: left; 727 | width: 66.66667%; 728 | /* */ 729 | *width: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 730 | /* */ 731 | } 732 | 733 | .mobile-prefix-66 { 734 | margin-left: 66.66667%; 735 | } 736 | 737 | .mobile-suffix-66 { 738 | margin-right: 66.66667%; 739 | } 740 | 741 | .mobile-push-66 { 742 | left: 66.66667%; 743 | /* */ 744 | *left: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 745 | /* */ 746 | } 747 | 748 | .mobile-pull-66 { 749 | left: -66.66667%; 750 | /* */ 751 | *left: expression(Math.floor(-0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 752 | /* */ 753 | } 754 | 755 | .mobile-grid-100 { 756 | clear: both; 757 | width: 100%; 758 | } 759 | } 760 | @media screen and (min-width: 768px) { 761 | .grid-100:before, 762 | .grid-100:after { 763 | content: "."; 764 | display: block; 765 | overflow: hidden; 766 | visibility: hidden; 767 | font-size: 0; 768 | line-height: 0; 769 | width: 0; 770 | height: 0; 771 | } 772 | 773 | .grid-100:after { 774 | clear: both; 775 | } 776 | 777 | .grid-100 { 778 | /* */ 779 | *zoom: 1; 780 | /* */ 781 | } 782 | 783 | .push-5, 784 | .pull-5, .push-10, 785 | .pull-10, .push-15, 786 | .pull-15, .push-20, 787 | .pull-20, .push-25, 788 | .pull-25, .push-30, 789 | .pull-30, .push-35, 790 | .pull-35, .push-40, 791 | .pull-40, .push-45, 792 | .pull-45, .push-50, 793 | .pull-50, .push-55, 794 | .pull-55, .push-60, 795 | .pull-60, .push-65, 796 | .pull-65, .push-70, 797 | .pull-70, .push-75, 798 | .pull-75, .push-80, 799 | .pull-80, .push-85, 800 | .pull-85, .push-90, 801 | .pull-90, .push-95, 802 | .pull-95, .push-33, 803 | .pull-33, .push-66, 804 | .pull-66 { 805 | position: relative; 806 | } 807 | 808 | .hide-on-desktop { 809 | display: none !important; 810 | } 811 | 812 | .grid-5 { 813 | float: left; 814 | width: 5%; 815 | /* */ 816 | *width: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 817 | /* */ 818 | } 819 | 820 | .prefix-5 { 821 | margin-left: 5%; 822 | } 823 | 824 | .suffix-5 { 825 | margin-right: 5%; 826 | } 827 | 828 | .push-5 { 829 | left: 5%; 830 | /* */ 831 | *left: expression(Math.floor(0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 832 | /* */ 833 | } 834 | 835 | .pull-5 { 836 | left: -5%; 837 | /* */ 838 | *left: expression(Math.floor(-0.05 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 839 | /* */ 840 | } 841 | 842 | .grid-10 { 843 | float: left; 844 | width: 10%; 845 | /* */ 846 | *width: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 847 | /* */ 848 | } 849 | 850 | .prefix-10 { 851 | margin-left: 10%; 852 | } 853 | 854 | .suffix-10 { 855 | margin-right: 10%; 856 | } 857 | 858 | .push-10 { 859 | left: 10%; 860 | /* */ 861 | *left: expression(Math.floor(0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 862 | /* */ 863 | } 864 | 865 | .pull-10 { 866 | left: -10%; 867 | /* */ 868 | *left: expression(Math.floor(-0.1 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 869 | /* */ 870 | } 871 | 872 | .grid-15 { 873 | float: left; 874 | width: 15%; 875 | /* */ 876 | *width: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 877 | /* */ 878 | } 879 | 880 | .prefix-15 { 881 | margin-left: 15%; 882 | } 883 | 884 | .suffix-15 { 885 | margin-right: 15%; 886 | } 887 | 888 | .push-15 { 889 | left: 15%; 890 | /* */ 891 | *left: expression(Math.floor(0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 892 | /* */ 893 | } 894 | 895 | .pull-15 { 896 | left: -15%; 897 | /* */ 898 | *left: expression(Math.floor(-0.15 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 899 | /* */ 900 | } 901 | 902 | .grid-20 { 903 | float: left; 904 | width: 20%; 905 | /* */ 906 | *width: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 907 | /* */ 908 | } 909 | 910 | .prefix-20 { 911 | margin-left: 20%; 912 | } 913 | 914 | .suffix-20 { 915 | margin-right: 20%; 916 | } 917 | 918 | .push-20 { 919 | left: 20%; 920 | /* */ 921 | *left: expression(Math.floor(0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 922 | /* */ 923 | } 924 | 925 | .pull-20 { 926 | left: -20%; 927 | /* */ 928 | *left: expression(Math.floor(-0.2 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 929 | /* */ 930 | } 931 | 932 | .grid-25 { 933 | float: left; 934 | width: 25%; 935 | /* */ 936 | *width: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 937 | /* */ 938 | } 939 | 940 | .prefix-25 { 941 | margin-left: 25%; 942 | } 943 | 944 | .suffix-25 { 945 | margin-right: 25%; 946 | } 947 | 948 | .push-25 { 949 | left: 25%; 950 | /* */ 951 | *left: expression(Math.floor(0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 952 | /* */ 953 | } 954 | 955 | .pull-25 { 956 | left: -25%; 957 | /* */ 958 | *left: expression(Math.floor(-0.25 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 959 | /* */ 960 | } 961 | 962 | .grid-30 { 963 | float: left; 964 | width: 30%; 965 | /* */ 966 | *width: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 967 | /* */ 968 | } 969 | 970 | .prefix-30 { 971 | margin-left: 30%; 972 | } 973 | 974 | .suffix-30 { 975 | margin-right: 30%; 976 | } 977 | 978 | .push-30 { 979 | left: 30%; 980 | /* */ 981 | *left: expression(Math.floor(0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 982 | /* */ 983 | } 984 | 985 | .pull-30 { 986 | left: -30%; 987 | /* */ 988 | *left: expression(Math.floor(-0.3 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 989 | /* */ 990 | } 991 | 992 | .grid-35 { 993 | float: left; 994 | width: 35%; 995 | /* */ 996 | *width: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 997 | /* */ 998 | } 999 | 1000 | .prefix-35 { 1001 | margin-left: 35%; 1002 | } 1003 | 1004 | .suffix-35 { 1005 | margin-right: 35%; 1006 | } 1007 | 1008 | .push-35 { 1009 | left: 35%; 1010 | /* */ 1011 | *left: expression(Math.floor(0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1012 | /* */ 1013 | } 1014 | 1015 | .pull-35 { 1016 | left: -35%; 1017 | /* */ 1018 | *left: expression(Math.floor(-0.35 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1019 | /* */ 1020 | } 1021 | 1022 | .grid-40 { 1023 | float: left; 1024 | width: 40%; 1025 | /* */ 1026 | *width: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1027 | /* */ 1028 | } 1029 | 1030 | .prefix-40 { 1031 | margin-left: 40%; 1032 | } 1033 | 1034 | .suffix-40 { 1035 | margin-right: 40%; 1036 | } 1037 | 1038 | .push-40 { 1039 | left: 40%; 1040 | /* */ 1041 | *left: expression(Math.floor(0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1042 | /* */ 1043 | } 1044 | 1045 | .pull-40 { 1046 | left: -40%; 1047 | /* */ 1048 | *left: expression(Math.floor(-0.4 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1049 | /* */ 1050 | } 1051 | 1052 | .grid-45 { 1053 | float: left; 1054 | width: 45%; 1055 | /* */ 1056 | *width: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1057 | /* */ 1058 | } 1059 | 1060 | .prefix-45 { 1061 | margin-left: 45%; 1062 | } 1063 | 1064 | .suffix-45 { 1065 | margin-right: 45%; 1066 | } 1067 | 1068 | .push-45 { 1069 | left: 45%; 1070 | /* */ 1071 | *left: expression(Math.floor(0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1072 | /* */ 1073 | } 1074 | 1075 | .pull-45 { 1076 | left: -45%; 1077 | /* */ 1078 | *left: expression(Math.floor(-0.45 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1079 | /* */ 1080 | } 1081 | 1082 | .grid-50 { 1083 | float: left; 1084 | width: 50%; 1085 | /* */ 1086 | *width: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1087 | /* */ 1088 | } 1089 | 1090 | .prefix-50 { 1091 | margin-left: 50%; 1092 | } 1093 | 1094 | .suffix-50 { 1095 | margin-right: 50%; 1096 | } 1097 | 1098 | .push-50 { 1099 | left: 50%; 1100 | /* */ 1101 | *left: expression(Math.floor(0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1102 | /* */ 1103 | } 1104 | 1105 | .pull-50 { 1106 | left: -50%; 1107 | /* */ 1108 | *left: expression(Math.floor(-0.5 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1109 | /* */ 1110 | } 1111 | 1112 | .grid-55 { 1113 | float: left; 1114 | width: 55%; 1115 | /* */ 1116 | *width: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1117 | /* */ 1118 | } 1119 | 1120 | .prefix-55 { 1121 | margin-left: 55%; 1122 | } 1123 | 1124 | .suffix-55 { 1125 | margin-right: 55%; 1126 | } 1127 | 1128 | .push-55 { 1129 | left: 55%; 1130 | /* */ 1131 | *left: expression(Math.floor(0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1132 | /* */ 1133 | } 1134 | 1135 | .pull-55 { 1136 | left: -55%; 1137 | /* */ 1138 | *left: expression(Math.floor(-0.55 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1139 | /* */ 1140 | } 1141 | 1142 | .grid-60 { 1143 | float: left; 1144 | width: 60%; 1145 | /* */ 1146 | *width: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1147 | /* */ 1148 | } 1149 | 1150 | .prefix-60 { 1151 | margin-left: 60%; 1152 | } 1153 | 1154 | .suffix-60 { 1155 | margin-right: 60%; 1156 | } 1157 | 1158 | .push-60 { 1159 | left: 60%; 1160 | /* */ 1161 | *left: expression(Math.floor(0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1162 | /* */ 1163 | } 1164 | 1165 | .pull-60 { 1166 | left: -60%; 1167 | /* */ 1168 | *left: expression(Math.floor(-0.6 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1169 | /* */ 1170 | } 1171 | 1172 | .grid-65 { 1173 | float: left; 1174 | width: 65%; 1175 | /* */ 1176 | *width: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1177 | /* */ 1178 | } 1179 | 1180 | .prefix-65 { 1181 | margin-left: 65%; 1182 | } 1183 | 1184 | .suffix-65 { 1185 | margin-right: 65%; 1186 | } 1187 | 1188 | .push-65 { 1189 | left: 65%; 1190 | /* */ 1191 | *left: expression(Math.floor(0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1192 | /* */ 1193 | } 1194 | 1195 | .pull-65 { 1196 | left: -65%; 1197 | /* */ 1198 | *left: expression(Math.floor(-0.65 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1199 | /* */ 1200 | } 1201 | 1202 | .grid-70 { 1203 | float: left; 1204 | width: 70%; 1205 | /* */ 1206 | *width: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1207 | /* */ 1208 | } 1209 | 1210 | .prefix-70 { 1211 | margin-left: 70%; 1212 | } 1213 | 1214 | .suffix-70 { 1215 | margin-right: 70%; 1216 | } 1217 | 1218 | .push-70 { 1219 | left: 70%; 1220 | /* */ 1221 | *left: expression(Math.floor(0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1222 | /* */ 1223 | } 1224 | 1225 | .pull-70 { 1226 | left: -70%; 1227 | /* */ 1228 | *left: expression(Math.floor(-0.7 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1229 | /* */ 1230 | } 1231 | 1232 | .grid-75 { 1233 | float: left; 1234 | width: 75%; 1235 | /* */ 1236 | *width: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1237 | /* */ 1238 | } 1239 | 1240 | .prefix-75 { 1241 | margin-left: 75%; 1242 | } 1243 | 1244 | .suffix-75 { 1245 | margin-right: 75%; 1246 | } 1247 | 1248 | .push-75 { 1249 | left: 75%; 1250 | /* */ 1251 | *left: expression(Math.floor(0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1252 | /* */ 1253 | } 1254 | 1255 | .pull-75 { 1256 | left: -75%; 1257 | /* */ 1258 | *left: expression(Math.floor(-0.75 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1259 | /* */ 1260 | } 1261 | 1262 | .grid-80 { 1263 | float: left; 1264 | width: 80%; 1265 | /* */ 1266 | *width: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1267 | /* */ 1268 | } 1269 | 1270 | .prefix-80 { 1271 | margin-left: 80%; 1272 | } 1273 | 1274 | .suffix-80 { 1275 | margin-right: 80%; 1276 | } 1277 | 1278 | .push-80 { 1279 | left: 80%; 1280 | /* */ 1281 | *left: expression(Math.floor(0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1282 | /* */ 1283 | } 1284 | 1285 | .pull-80 { 1286 | left: -80%; 1287 | /* */ 1288 | *left: expression(Math.floor(-0.8 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1289 | /* */ 1290 | } 1291 | 1292 | .grid-85 { 1293 | float: left; 1294 | width: 85%; 1295 | /* */ 1296 | *width: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1297 | /* */ 1298 | } 1299 | 1300 | .prefix-85 { 1301 | margin-left: 85%; 1302 | } 1303 | 1304 | .suffix-85 { 1305 | margin-right: 85%; 1306 | } 1307 | 1308 | .push-85 { 1309 | left: 85%; 1310 | /* */ 1311 | *left: expression(Math.floor(0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1312 | /* */ 1313 | } 1314 | 1315 | .pull-85 { 1316 | left: -85%; 1317 | /* */ 1318 | *left: expression(Math.floor(-0.85 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1319 | /* */ 1320 | } 1321 | 1322 | .grid-90 { 1323 | float: left; 1324 | width: 90%; 1325 | /* */ 1326 | *width: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1327 | /* */ 1328 | } 1329 | 1330 | .prefix-90 { 1331 | margin-left: 90%; 1332 | } 1333 | 1334 | .suffix-90 { 1335 | margin-right: 90%; 1336 | } 1337 | 1338 | .push-90 { 1339 | left: 90%; 1340 | /* */ 1341 | *left: expression(Math.floor(0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1342 | /* */ 1343 | } 1344 | 1345 | .pull-90 { 1346 | left: -90%; 1347 | /* */ 1348 | *left: expression(Math.floor(-0.9 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1349 | /* */ 1350 | } 1351 | 1352 | .grid-95 { 1353 | float: left; 1354 | width: 95%; 1355 | /* */ 1356 | *width: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1357 | /* */ 1358 | } 1359 | 1360 | .prefix-95 { 1361 | margin-left: 95%; 1362 | } 1363 | 1364 | .suffix-95 { 1365 | margin-right: 95%; 1366 | } 1367 | 1368 | .push-95 { 1369 | left: 95%; 1370 | /* */ 1371 | *left: expression(Math.floor(0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1372 | /* */ 1373 | } 1374 | 1375 | .pull-95 { 1376 | left: -95%; 1377 | /* */ 1378 | *left: expression(Math.floor(-0.95 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1379 | /* */ 1380 | } 1381 | 1382 | .grid-33 { 1383 | float: left; 1384 | width: 33.33333%; 1385 | /* */ 1386 | *width: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1387 | /* */ 1388 | } 1389 | 1390 | .prefix-33 { 1391 | margin-left: 33.33333%; 1392 | } 1393 | 1394 | .suffix-33 { 1395 | margin-right: 33.33333%; 1396 | } 1397 | 1398 | .push-33 { 1399 | left: 33.33333%; 1400 | /* */ 1401 | *left: expression(Math.floor(0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1402 | /* */ 1403 | } 1404 | 1405 | .pull-33 { 1406 | left: -33.33333%; 1407 | /* */ 1408 | *left: expression(Math.floor(-0.33333 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1409 | /* */ 1410 | } 1411 | 1412 | .grid-66 { 1413 | float: left; 1414 | width: 66.66667%; 1415 | /* */ 1416 | *width: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1417 | /* */ 1418 | } 1419 | 1420 | .prefix-66 { 1421 | margin-left: 66.66667%; 1422 | } 1423 | 1424 | .suffix-66 { 1425 | margin-right: 66.66667%; 1426 | } 1427 | 1428 | .push-66 { 1429 | left: 66.66667%; 1430 | /* */ 1431 | *left: expression(Math.floor(0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1432 | /* */ 1433 | } 1434 | 1435 | .pull-66 { 1436 | left: -66.66667%; 1437 | /* */ 1438 | *left: expression(Math.floor(-0.66667 * (this.parentNode.offsetWidth - parseFloat(this.parentNode.currentStyle.paddingLeft) - parseFloat(this.parentNode.currentStyle.paddingRight))) + "px"); 1439 | /* */ 1440 | } 1441 | 1442 | .grid-100 { 1443 | clear: both; 1444 | width: 100%; 1445 | } 1446 | } 1447 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular and Browserify 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | 16 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('es5-shim'); 4 | require('es5-sham'); 5 | 6 | require('jquery'); 7 | var angular = require('angular'); 8 | require('angular-route'); 9 | 10 | var app = angular.module('todoApp', [ 'ngRoute' ]); 11 | 12 | app.constant('VERSION', require('../../package.json').version); 13 | 14 | require('./service'); 15 | require('./controller'); 16 | 17 | app.config(function($routeProvider) { 18 | 19 | $routeProvider.when('/todos', { 20 | templateUrl: 'views/todos.html', 21 | controller: 'TodoCtrl', 22 | }) 23 | .when('/imprint', { 24 | templateUrl: 'views/imprint.html', 25 | controller: 'ImprintCtrl', 26 | }) 27 | .otherwise({ 28 | redirectTo: '/todos', 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /app/js/controller/edit_todo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function($scope, TodoService) { 4 | 5 | var backupForCancel; 6 | var creatingNew = false; 7 | 8 | $scope.editMode = false; 9 | 10 | $scope.create = function() { 11 | $scope.$parent.todo = TodoService.create(); 12 | backupForCancel = null; 13 | creatingNew = true; 14 | $scope.editMode = true; 15 | }; 16 | 17 | $scope.edit = function() { 18 | if ($scope.editMode) { 19 | return; 20 | } 21 | backupForCancel = copy($scope.$parent.todo); 22 | creatingNew = false; 23 | $scope.editMode = true; 24 | }; 25 | 26 | $scope.save = function() { 27 | if (creatingNew) { 28 | TodoService.insert($scope.$parent.todo); 29 | } 30 | $scope.editMode = false; 31 | creatingNew = false; 32 | backupForCancel = null; 33 | }; 34 | 35 | $scope.cancel = function() { 36 | if (!creatingNew) { 37 | // rollback edits 38 | $scope.$parent.todo.title = backupForCancel.title; 39 | $scope.$parent.todo.due = backupForCancel.due; 40 | $scope.$parent.todo.text = backupForCancel.text; 41 | } else { 42 | // discard new todo, set active todo to some arbitrary todo 43 | $scope.$parent.todo = TodoService.getTodos()[0]; 44 | creatingNew = false; 45 | } 46 | $scope.editMode = false; 47 | }; 48 | 49 | $scope.remove = function() { 50 | TodoService.remove($scope.$parent.todo); 51 | // set active todo to some arbitrary todo 52 | $scope.$parent.todo = TodoService.getTodos()[0]; 53 | }; 54 | 55 | function copy(todo) { 56 | return { 57 | title: todo.title, 58 | due: todo.due, 59 | text: todo.text, 60 | }; 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /app/js/controller/footer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function($scope, VERSION) { 4 | $scope.version = VERSION; 5 | }; 6 | -------------------------------------------------------------------------------- /app/js/controller/imprint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function($scope, ImprintService) { 4 | $scope.text = ImprintService.getText(); 5 | }; 6 | -------------------------------------------------------------------------------- /app/js/controller/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = require('angular').module('todoApp'); 4 | 5 | app.controller('EditTodoCtrl', require('./edit_todo')); 6 | app.controller('FooterCtrl', require('./footer')); 7 | app.controller('TodoCtrl', require('./todo')); 8 | app.controller('TodoListCtrl', require('./todo_list')); 9 | app.controller('ImprintCtrl', require('./imprint')); 10 | -------------------------------------------------------------------------------- /app/js/controller/todo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function($scope, TodoService) { 4 | $scope.todo = TodoService.getTodos()[0]; 5 | }; 6 | -------------------------------------------------------------------------------- /app/js/controller/todo_list.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function($scope, TodoService) { 4 | 5 | $scope.getTodos = TodoService.getTodos.bind(TodoService); 6 | 7 | $scope.select = function(todo) { 8 | $scope.$parent.todo = todo; 9 | }; 10 | 11 | $scope.getCssClass = function(todo) { 12 | if (todo === $scope.$parent.todo) { 13 | return ['sidebar-item-active']; 14 | } else { 15 | return ['sidebar-item-inactive']; 16 | } 17 | }; 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /app/js/service/imprint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function() { 4 | 5 | var text = 'Example app for using AngularJS with Browserify - ' + 6 | 'by Bastian Krol. Use at your own risk :P'; 7 | 8 | this.getText = function() { 9 | return text; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /app/js/service/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var app = require('angular').module('todoApp'); 4 | 5 | app.service('ImprintService', require('./imprint')); 6 | app.service('TodoService', require('./todos')); 7 | -------------------------------------------------------------------------------- /app/js/service/todos.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function() { 4 | 5 | var todos = [{ 6 | title: 'Buy milk', 7 | due: createDate(0, 0, 0, 18, 0), 8 | text: 'We are out of milk and coffee without milk is just unbearable.', 9 | }, { 10 | title: 'Write blog post', 11 | due: createDate(0, 0, 1, 14, 0), 12 | text: 'Write a blog post about how to integrate AngularJS and Browserify ' + 13 | 'for http://angularjs.de/', 14 | }, { 15 | title: 'Finish talk proposal', 16 | due: createDate(0, 0, 7, 23, 30), 17 | text: 'Finalize the talk proposal for FoobarConf. Call for papers ' + 18 | 'deadline is on Tuesday.', 19 | }, { 20 | title: 'World Domination', 21 | due: createDate(5, 0, 0, 12, 0), 22 | text: 'Because, who wouldn\'t want that?', 23 | }]; 24 | 25 | this.getTodos = function() { 26 | return todos; 27 | }; 28 | 29 | this.create = function() { 30 | return { 31 | title: '', 32 | due: createDate(0, 0, 1, 12, 0), 33 | text: '', 34 | }; 35 | }; 36 | 37 | this.insert = function(todo) { 38 | todos.push(todo); 39 | }; 40 | 41 | this.remove = function(todo) { 42 | todos = todos.filter(function(t) { return t !== todo; }); 43 | }; 44 | 45 | function createDate(year, month, day, hour, minute) { 46 | var now = new Date(); 47 | return new Date( 48 | now.getFullYear() + year, 49 | now.getMonth() + month, 50 | now.getDate() + day, 51 | hour, minute, 0, 0 52 | ); 53 | } 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /app/views/imprint.html: -------------------------------------------------------------------------------- 1 |
2 | {{ text }} 3 |
4 | 5 |

6 | 7 | Shut up and take me to the todo list! 8 | -------------------------------------------------------------------------------- /app/views/todos.html: -------------------------------------------------------------------------------- 1 |

2 |
3 | 4 |
5 | 10 | 11 | 12 |
13 |
14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 |
23 |
24 | 29 |
30 |
31 | 32 |
33 | Due: 34 | {{ todo.due | date : 'short' }} 35 |
36 | 37 |
41 | 42 |
43 |
46 | 47 |
48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 |
56 |
57 | 58 | 59 | 60 | 61 |
62 |
63 |
64 | -------------------------------------------------------------------------------- /bin/browserify.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to browserify without Gulp - usually Gulp is used to browserify and 4 | # build everything. 5 | 6 | browserify_cmd=node_modules/browserify/bin/cmd.js 7 | 8 | bin_path=`dirname $0` 9 | pushd $bin_path/.. > /dev/null 10 | mkdir app/dist 2> /dev/null 11 | 12 | $browserify_cmd \ 13 | --entry app/js/app.js \ 14 | --outfile app/dist/app.js \ 15 | --debug \ 16 | --verbose 17 | 18 | $browserify_cmd \ 19 | test/unit/controller/*.js \ 20 | test/unit/service/*.js \ 21 | --outfile test/browserified/browserified_tests.js \ 22 | --debug \ 23 | --verbose 24 | 25 | popd > /dev/null 26 | -------------------------------------------------------------------------------- /bin/start-selenium.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to start selenium server for protractor tests. 4 | 5 | bin_path=`dirname $0` 6 | pushd $bin_path/.. > /dev/null 7 | 8 | node_modules/protractor/bin/webdriver-manager start 9 | 10 | # In case the selenium server does not stop after testing: 11 | # Type the following link into a browser: 12 | # http://localhost:4444/selenium-server/driver/?cmd=shutDownSeleniumServer 13 | 14 | popd > /dev/null 15 | -------------------------------------------------------------------------------- /bin/watchify.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script continuously browserifies the client side JavaScript, same as the 4 | # Gulp build would do. It gives faster turnaround times than a full Gulp 5 | # build. It does not execute JSHint or minification, just the browserify stuff. 6 | # Using this script only makes sense when index.html references the non-minified 7 | # build (that is, app/dist/app.js, not app/dist/app.min.js). 8 | 9 | # This script assumes that watchify is installed globally. To do that execute 10 | # npm install -g watchify 11 | 12 | # The watchify process is started in the background. Use 13 | # pkill -f watchify or pkill -f "node.*watchify" 14 | # to stop them. 15 | 16 | bin_path=`dirname $0` 17 | pushd $bin_path/.. > /dev/null 18 | mkdir app/dist 2> /dev/null 19 | 20 | watchify \ 21 | --entry app/js/app.js \ 22 | --outfile app/dist/app.js \ 23 | --debug \ 24 | --verbose \ 25 | & 26 | 27 | watchify \ 28 | test/unit/controller/*.js \ 29 | test/unit/service/*.js \ 30 | --outfile test/browserified/browserified_tests.js \ 31 | --debug \ 32 | --verbose \ 33 | & 34 | 35 | popd > /dev/null 36 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var browserify = require('browserify') 4 | , del = require('del') 5 | , source = require('vinyl-source-stream') 6 | , vinylPaths = require('vinyl-paths') 7 | , glob = require('glob') 8 | , Server = require('karma').Server 9 | , gulp = require('gulp'); 10 | 11 | // Load all gulp plugins listed in package.json 12 | var gulpPlugins = require('gulp-load-plugins')({ 13 | pattern: ['gulp-*', 'gulp.*'], 14 | replaceString: /\bgulp[\-.]/ 15 | }); 16 | 17 | // Define file path variables 18 | var paths = { 19 | root: 'app/', // App root path 20 | src: 'app/js/', // Source path 21 | dist: 'app/dist/', // Distribution path 22 | test: 'test/', // Test path 23 | }; 24 | 25 | /* 26 | * Useful tasks: 27 | * - gulp fast: 28 | * - linting 29 | * - unit tests 30 | * - browserification 31 | * - no minification, does not start server. 32 | * - gulp watch: 33 | * - starts server with live reload enabled 34 | * - lints, unit tests, browserifies and live-reloads changes in browser 35 | * - no minification 36 | * - gulp: 37 | * - linting 38 | * - unit tests 39 | * - browserification 40 | * - minification and browserification of minified sources 41 | * - start server for e2e tests 42 | * - run Protractor End-to-end tests 43 | * - stop server immediately when e2e tests have finished 44 | * 45 | * At development time, you should usually just have 'gulp watch' running in the 46 | * background all the time. Use 'gulp' before releases. 47 | */ 48 | 49 | var liveReload = true; 50 | 51 | gulp.task('clean', function () { 52 | return gulp 53 | .src([paths.root + 'ngAnnotate', paths.dist], {read: false}) 54 | .pipe(vinylPaths(del)); 55 | }); 56 | 57 | gulp.task('lint', function () { 58 | return gulp 59 | .src(['gulpfile.js', 60 | paths.src + '**/*.js', 61 | paths.test + '**/*.js', 62 | '!' + paths.src + 'third-party/**', 63 | '!' + paths.test + 'browserified/**', 64 | ]) 65 | .pipe(gulpPlugins.eslint()) 66 | .pipe(gulpPlugins.eslint.format()); 67 | }); 68 | 69 | gulp.task('unit', function () { 70 | return gulp.src([ 71 | paths.test + 'unit/**/*.js' 72 | ]) 73 | .pipe(gulpPlugins.mocha({reporter: 'dot'})); 74 | }); 75 | 76 | gulp.task('browserify', /*['lint', 'unit'],*/ function () { 77 | return browserify(paths.src + 'app.js', {debug: true}) 78 | .bundle() 79 | .pipe(source('app.js')) 80 | .pipe(gulp.dest(paths.dist)) 81 | .pipe(gulpPlugins.connect.reload()); 82 | }); 83 | 84 | gulp.task('ngAnnotate', ['lint', 'unit'], function () { 85 | return gulp.src([ 86 | paths.src + '**/*.js', 87 | '!' + paths.src + 'third-party/**', 88 | ]) 89 | .pipe(gulpPlugins.ngAnnotate()) 90 | .pipe(gulp.dest(paths.root + 'ngAnnotate')); 91 | }); 92 | 93 | gulp.task('browserify-min', ['ngAnnotate'], function () { 94 | return browserify(paths.root + 'ngAnnotate/app.js') 95 | .bundle() 96 | .pipe(source('app.min.js')) 97 | .pipe(gulpPlugins.streamify(gulpPlugins.uglify({mangle: false}))) 98 | .pipe(gulp.dest(paths.dist)); 99 | }); 100 | 101 | gulp.task('browserify-tests', function () { 102 | var bundler = browserify({debug: true}); 103 | glob 104 | .sync(paths.test + 'unit/**/*.js') 105 | .forEach(function (file) { 106 | bundler.add(file); 107 | }); 108 | return bundler 109 | .bundle() 110 | .pipe(source('browserified_tests.js')) 111 | .pipe(gulp.dest(paths.test + 'browserified')); 112 | }); 113 | 114 | gulp.task('karma', ['browserify-tests'], function (done) { 115 | new Server({ 116 | configFile: __dirname + '/karma.conf.js', 117 | singleRun: true 118 | }, done).start(); 119 | }); 120 | 121 | gulp.task('server', ['browserify'], function () { 122 | gulpPlugins.connect.server({ 123 | root: 'app', 124 | livereload: liveReload, 125 | }); 126 | }); 127 | 128 | gulp.task('e2e', ['server'], function () { 129 | return gulp.src([paths.test + 'e2e/**/*.js']) 130 | .pipe(gulpPlugins.protractor.protractor({ 131 | configFile: 'protractor.conf.js', 132 | args: ['--baseUrl', 'http://127.0.0.1:8080'], 133 | })) 134 | .on('error', function (e) { 135 | throw e; 136 | }) 137 | .on('end', function () { 138 | gulpPlugins.connect.serverClose(); 139 | }); 140 | }); 141 | 142 | gulp.task('watch', function () { 143 | gulp.start('server'); 144 | gulp.watch([ 145 | paths.src + '**/*.js', 146 | '!' + paths.src + 'third-party/**', 147 | paths.test + '**/*.js', 148 | ], ['fast']); 149 | }); 150 | 151 | gulp.task('fast', ['clean'], function () { 152 | gulp.start('browserify'); 153 | }); 154 | 155 | gulp.task('default', ['clean'], function () { 156 | liveReload = false; 157 | gulp.start('karma', 'browserify', 'browserify-min', 'e2e'); 158 | }); 159 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Mon May 26 2014 23:07:02 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | 'test/browserified/browserified_tests.js' 19 | ], 20 | 21 | 22 | // list of files to exclude 23 | exclude: [ 24 | ], 25 | 26 | 27 | // preprocess matching files before serving them to the browser 28 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 29 | preprocessors: { 30 | }, 31 | 32 | 33 | // test results reporter to use 34 | // possible values: 'dots', 'progress' 35 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 36 | reporters: ['progress'], 37 | 38 | 39 | // web server port 40 | port: 9876, 41 | 42 | 43 | // enable / disable colors in the output (reporters and logs) 44 | colors: true, 45 | 46 | 47 | // level of logging 48 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 49 | logLevel: config.LOG_INFO, 50 | 51 | 52 | // enable / disable watching file and executing tests whenever any file changes 53 | autoWatch: true, 54 | 55 | 56 | // start these browsers 57 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 58 | browsers: ['Chrome', 'Firefox'], 59 | 60 | 61 | // Continuous Integration mode 62 | // if true, Karma captures browsers, runs the tests and exits 63 | singleRun: false 64 | }); 65 | }; 66 | -------------------------------------------------------------------------------- /karma.conf.js.travis: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Mon May 26 2014 23:07:02 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | 'test/browserified/browserified_tests.js' 19 | ], 20 | 21 | 22 | // list of files to exclude 23 | exclude: [ 24 | ], 25 | 26 | 27 | // preprocess matching files before serving them to the browser 28 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 29 | preprocessors: { 30 | }, 31 | 32 | 33 | // test results reporter to use 34 | // possible values: 'dots', 'progress' 35 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 36 | reporters: ['progress'], 37 | 38 | 39 | // web server port 40 | port: 9876, 41 | 42 | 43 | // enable / disable colors in the output (reporters and logs) 44 | colors: true, 45 | 46 | 47 | // level of logging 48 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 49 | logLevel: config.LOG_INFO, 50 | 51 | 52 | // enable / disable watching file and executing tests whenever any file changes 53 | autoWatch: false, 54 | 55 | 56 | // start these browsers 57 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 58 | browsers: ['Firefox'], 59 | 60 | 61 | // Continuous Integration mode 62 | // if true, Karma captures browsers, runs the tests and exits 63 | singleRun: true 64 | }); 65 | }; 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-browserify-seed", 3 | "version": "0.1.0", 4 | "description": "Yet another example project with Angular, Browserify and Gulp", 5 | "repository": "https://github.com/basti1302/angular-browserify-seed", 6 | "license": "MIT", 7 | "scripts": { 8 | "postinstall": "webdriver-manager update", 9 | "pretest": "webdriver-manager start &", 10 | "test": "gulp" 11 | }, 12 | "dependencies": { 13 | "angular": "^1.4.7", 14 | "angular-route": "^1.4.7", 15 | "es5-shim": "^4.3.1", 16 | "jquery": "^2.1.1" 17 | }, 18 | "devDependencies": { 19 | "browserify": "^12.0.1", 20 | "browserify-shim": "^3.8.2", 21 | "chai": "^3.4.1", 22 | "del": "^2.1.0", 23 | "glob": "^6.0.1", 24 | "gulp": "^3.9.0", 25 | "gulp-connect": "^2.0.5", 26 | "gulp-eslint": "^1.1.0", 27 | "gulp-load-plugins": "^1.1.0", 28 | "gulp-mocha": "^2.2.0", 29 | "gulp-ng-annotate": "^1.1.0", 30 | "gulp-protractor": "1.0.0", 31 | "gulp-streamify": "1.0.2", 32 | "gulp-uglify": "^1.5.1", 33 | "karma": "^0.13.15", 34 | "karma-chai": "^0.1.0", 35 | "karma-chrome-launcher": "^0.2.1", 36 | "karma-firefox-launcher": "^0.1.3", 37 | "karma-mocha": "^0.2.1", 38 | "karma-sinon": "^1.0.3", 39 | "mocha": "^2.3.4", 40 | "protractor": "^2.5.1", 41 | "sinon": "^1.9.1", 42 | "sinon-chai": "^2.5.0", 43 | "vinyl-paths": "^2.1.0", 44 | "vinyl-source-stream": "^1.1.0" 45 | }, 46 | "browser": { 47 | "es5-sham": "./node_modules/es5-shim/es5-sham.min.js", 48 | "es5-shim": "./node_modules/es5-shim/es5-shim.min.js" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | 3 | chromeOnly: true, 4 | chromeDriver: './node_modules/protractor/selenium/chromedriver', 5 | 6 | capabilities: { 7 | 'browserName': 'chrome' 8 | }, 9 | 10 | specs: ['test/e2e/**/*_spec.js'], 11 | 12 | rootElement: '.content', 13 | 14 | jasmineNodeOpts: { 15 | showColors: true, 16 | defaultTimeoutInterval: 30000 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /protractor.conf.js.travis: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | 3 | seleniumAddress: 'http://0.0.0.0:4444/wd/hub', 4 | 5 | capabilities: { 6 | 'browserName': 'phantomjs' 7 | }, 8 | 9 | specs: ['test/e2e/**/*_spec.js'], 10 | 11 | rootElement: '.content', 12 | 13 | jasmineNodeOpts: { 14 | showColors: true, 15 | defaultTimeoutInterval: 30000 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | UNMAINTAINED 2 | ============ 3 | 4 | *DISCLAIMER: THIS REPOSITORY IS UNMAINTAINED!* 5 | 6 | It's up for grabs. If you are interested and want to take it over, open an issue to get into contact. 7 | 8 | AngularJS + Browserify Project Template 9 | ======================================= 10 | 11 | [![Build Status](https://travis-ci.org/basti1302/angular-browserify.png?branch=master)](https://travis-ci.org/angular-browserify/traverson) 12 | 13 | This is a small example/seed project for using AngularJS with Browserify. It demonstrates how to structure code by using CommonJS modules together with AngularJS' dependency injection mechanism. 14 | 15 | An accompanying blog post can be found at . 16 | 17 | Build 18 | ----- 19 | 20 | This project comes with a `gulpfile` that includes: 21 | 22 | * running ESlint to lint JavaScript sources, 23 | * running unit tests via Mocha, 24 | * processing sources with Browserify (to create a non-minfied Browserify bundle), 25 | * ngAnnotate & uglify (to create an ngAnnotate-processed and minified Browserify bundle), 26 | * end-to-end tests with Protractor, 27 | * a static asset server (gulp-connect) and 28 | * live reload support. 29 | 30 | ### Useful gulp tasks 31 | 32 | The 33 | * `gulp fast`: 34 | * linting 35 | * unit tests 36 | * browserification 37 | * no minification, does not start server 38 | * `gulp watch` 39 | * starts server with live reload enabled 40 | * lints, unit tests, browserifies and live-reloads changes in browser 41 | * no minification 42 | * `gulp`: 43 | * linting 44 | * unit tests 45 | * browserification 46 | * minification and browserification of minified sources 47 | * start server for e2e tests 48 | * run Protractor End-to-end tests 49 | * stop server immediately when e2e tests have finished 50 | 51 | At development time, you should usually just have `gulp watch` running in the background all the time. Access the app via http://localhost:8080/. Whenever you change a source file and save it, the browserify bundle is recreated and your browser automatically reloads the changes. Use `gulp` (without a specific task) before releases. 52 | -------------------------------------------------------------------------------- /test/browserified/.gitignore: -------------------------------------------------------------------------------- 1 | browserified_tests.js 2 | -------------------------------------------------------------------------------- /test/browserified/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Browserify Tests Demo 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/e2e/delete_todo_spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TodoPage = require('./pages/todo_page'); 4 | 5 | describe('The todo app (deleting a todo)', function() { 6 | 7 | var todoPage; 8 | 9 | beforeEach(function() { 10 | todoPage = new TodoPage(); 11 | todoPage.open(); 12 | // see comment in test/e2e/list_todo_spec.js 13 | browser.ignoreSynchronization = true; 14 | }); 15 | 16 | it('should delete a todo', function() { 17 | todoPage.sidebarItem(2).click(); 18 | todoPage.del(); 19 | expect(todoPage.sidebarItems().count()).toEqual(3); 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /test/e2e/edit_todo_spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TodoPage = require('./pages/todo_page'); 4 | 5 | describe('The todo app (editing)', function() { 6 | 7 | var todoPage; 8 | 9 | beforeEach(function() { 10 | todoPage = new TodoPage(); 11 | todoPage.open(); 12 | // see comment in test/e2e/list_todo_spec.js 13 | browser.ignoreSynchronization = true; 14 | }); 15 | 16 | it('should be intially not in edit-mode', function() { 17 | todoPage.isInDisplayMode(); 18 | }); 19 | 20 | it('should switch to edit-mode', function() { 21 | todoPage.edit(); 22 | todoPage.isInEditMode(); 23 | }); 24 | 25 | it('should edit and cancel', function() { 26 | todoPage.sidebarItem(1).click(); 27 | todoPage.edit(); 28 | todoPage.setTitle('changed title'); 29 | todoPage.setText('changed text'); 30 | todoPage.cancel(); 31 | todoPage.isInDisplayMode(); 32 | expect(todoPage.title.getText()).toEqual('Write blog post'); 33 | expect(todoPage.text.getText()).toEqual('Write a blog post about how to ' + 34 | 'integrate AngularJS and Browserify for http://angularjs.de/'); 35 | expect(todoPage.sidebarItem(1).getText()).toEqual('Write blog post'); 36 | }); 37 | 38 | it('should edit and save', function() { 39 | todoPage.sidebarItem(1).click(); 40 | todoPage.edit(); 41 | todoPage.setTitle('changed title'); 42 | todoPage.setText('changed text'); 43 | todoPage.save(); 44 | todoPage.isInDisplayMode(); 45 | expect(todoPage.title.getText()).toEqual('changed title'); 46 | expect(todoPage.text.getText()).toEqual('changed text'); 47 | expect(todoPage.sidebarItem(1).getText()).toEqual('changed title'); 48 | }); 49 | 50 | }); 51 | -------------------------------------------------------------------------------- /test/e2e/list_todo_spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TodoPage = require('./pages/todo_page'); 4 | 5 | describe('The todo app', function() { 6 | 7 | var todoPage; 8 | 9 | beforeEach(function() { 10 | todoPage = new TodoPage(); 11 | todoPage.open(); 12 | 13 | // Um, this is not good. Not sure why it is needed :-( 14 | // Without it, we get an "Error while waiting for Protractor to sync with 15 | // the page: {}". There are several issues on GitHub describing that but 16 | // no solution, only workarounds like setting ignoreSynchronization = true 17 | // or waiting a bit at the start of the test. 18 | browser.ignoreSynchronization = true; 19 | }); 20 | 21 | it('should list several todos items', function() { 22 | expect(todoPage.sidebarItem(0).getText()).toEqual('Buy milk'); 23 | expect(todoPage.sidebarItem(1).getText()).toEqual('Write blog post'); 24 | expect(todoPage.sidebarItem(2).getText()).toEqual( 25 | 'Finish talk proposal'); 26 | expect(todoPage.sidebarItem(3).getText()).toEqual('World Domination'); 27 | }); 28 | 29 | it('should show details for the first todo item', function() { 30 | expect(todoPage.title.getText()).toEqual('Buy milk'); 31 | expect(todoPage.text.getText()).toEqual('We are out of milk and coffee ' + 32 | 'without milk is just unbearable.'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/e2e/new_todo_spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TodoPage = require('./pages/todo_page'); 4 | 5 | describe('The todo app (creating a new todo)', function() { 6 | 7 | var todoPage; 8 | 9 | beforeEach(function() { 10 | todoPage = new TodoPage(); 11 | todoPage.open(); 12 | // see comment in test/e2e/list_todo_spec.js 13 | browser.ignoreSynchronization = true; 14 | }); 15 | 16 | it('should switch to edit-mode when creating a new todo', function() { 17 | todoPage.createNew(); 18 | todoPage.isInEditMode(); 19 | }); 20 | 21 | it('should start with an empty todo', function() { 22 | todoPage.createNew(); 23 | expect(todoPage.titleInput.getText()).toEqual(''); 24 | expect(todoPage.textInput.getText()).toEqual(''); 25 | }); 26 | 27 | it('should create a new todo and cancel', function() { 28 | todoPage.createNew(); 29 | todoPage.setTitle('new title'); 30 | todoPage.setText('new text'); 31 | todoPage.cancel(); 32 | todoPage.isInDisplayMode(); 33 | expect(todoPage.sidebarItems().count()).toEqual(4); 34 | todoPage.doesNotContainText('new title'); 35 | todoPage.doesNotContainText('new text'); 36 | }); 37 | 38 | it('should create a new todo and save', function() { 39 | todoPage.createNew(); 40 | todoPage.setTitle('new title'); 41 | todoPage.setText('new text'); 42 | todoPage.save(); 43 | todoPage.isInDisplayMode(); 44 | expect(todoPage.sidebarItems().count()).toEqual(5); 45 | expect(todoPage.sidebarItem(4).getText()).toEqual('new title'); 46 | expect(todoPage.title.getText()).toEqual('new title'); 47 | expect(todoPage.text.getText()).toEqual('new text'); 48 | }); 49 | 50 | }); 51 | -------------------------------------------------------------------------------- /test/e2e/pages/todo_page.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* 4 | * Page object for the todo page. 5 | */ 6 | var TodoPage = function() { 7 | 8 | var driver = browser.driver; 9 | 10 | this.title = element(by.css('.current-item')); 11 | this.dueDate = element(by.binding('todo.due')); 12 | this.text = element(by.binding('todo.text')); 13 | 14 | this.titleInput = element(by.model('todo.title')); 15 | this.textInput = element(by.model('todo.text')); 16 | 17 | var sidebarItemsLocator = by.repeater('todo in getTodos()'); 18 | 19 | this.editButton = element(by.buttonText('Edit')); 20 | this.newButton = element(by.buttonText('New')); 21 | this.deleteButton = element(by.buttonText('Delete')); 22 | this.cancelButton = element(by.buttonText('Cancel')); 23 | this.saveButton = element(by.buttonText('Save')); 24 | 25 | this.open = function() { 26 | browser.get('http://127.0.0.1:8080/#/todos'); 27 | }; 28 | 29 | this.sidebarItems = function() { 30 | return element.all(sidebarItemsLocator); 31 | }; 32 | 33 | this.sidebarItem = function(index) { 34 | return element(sidebarItemsLocator.row(index).column('title')); 35 | }; 36 | 37 | this.setTitle = function(title) { 38 | enter(this.titleInput, title); 39 | }; 40 | 41 | this.setText = function(text) { 42 | enter(this.textInput, text); 43 | }; 44 | 45 | this.edit = function() { 46 | this.editButton.click(); 47 | }; 48 | 49 | this.createNew = function() { 50 | this.newButton.click(); 51 | }; 52 | 53 | this.del = function() { 54 | this.deleteButton.click(); 55 | }; 56 | 57 | this.cancel = function() { 58 | this.cancelButton.click(); 59 | }; 60 | 61 | this.save = function() { 62 | this.saveButton.click(); 63 | }; 64 | 65 | this.isInDisplayMode = function() { 66 | expect(this.title.isDisplayed()).toEqual(true); 67 | expect(this.titleInput.isDisplayed()).toEqual(false); 68 | expect(this.text.isDisplayed()).toEqual(true); 69 | expect(this.textInput.isDisplayed()).toEqual(false); 70 | expect(this.editButton.isDisplayed()).toEqual(true); 71 | expect(this.newButton.isDisplayed()).toEqual(true); 72 | expect(this.deleteButton.isDisplayed()).toEqual(true); 73 | expect(this.cancelButton.isDisplayed()).toEqual(false); 74 | expect(this.saveButton.isDisplayed()).toEqual(false); 75 | }; 76 | 77 | this.isInEditMode = function() { 78 | expect(this.title.isDisplayed()).toEqual(false); 79 | expect(this.titleInput.isDisplayed()).toEqual(true); 80 | expect(this.text.isDisplayed()).toEqual(false); 81 | expect(this.textInput.isDisplayed()).toEqual(true); 82 | expect(this.editButton.isDisplayed()).toEqual(false); 83 | expect(this.newButton.isDisplayed()).toEqual(false); 84 | expect(this.deleteButton.isDisplayed()).toEqual(false); 85 | expect(this.cancelButton.isDisplayed()).toEqual(true); 86 | expect(this.saveButton.isDisplayed()).toEqual(true); 87 | }; 88 | 89 | this.containsText = function(text) { 90 | checkText(text, function(result) { 91 | expect(result).toBe(true); 92 | }); 93 | }; 94 | 95 | this.doesNotContainText = function(text) { 96 | checkText(text, function(result) { 97 | expect(result).toBe(false); 98 | }); 99 | }; 100 | 101 | function checkText(text, fn) { 102 | driver 103 | .isElementPresent({ 104 | xpath: '//*[contains(text(), \'' + text + '\')]' 105 | }).then(fn); 106 | } 107 | }; 108 | 109 | function enter(field, text) { 110 | field.clear(); 111 | field.sendKeys(text); 112 | } 113 | 114 | module.exports = TodoPage; 115 | -------------------------------------------------------------------------------- /test/e2e/select_todo_spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var TodoPage = require('./pages/todo_page'); 4 | 5 | describe('The todo app', function() { 6 | 7 | var todoPage; 8 | 9 | beforeEach(function() { 10 | todoPage = new TodoPage(); 11 | todoPage.open(); 12 | // see comment in test/e2e/list_todo_spec.js 13 | browser.ignoreSynchronization = true; 14 | }); 15 | 16 | it('should select a different todo from the sidebar', function() { 17 | todoPage.sidebarItem(1).click(); 18 | expect(todoPage.title.getText()).toEqual('Write blog post'); 19 | expect(todoPage.text.getText()).toEqual('Write a blog post about how to ' + 20 | 'integrate AngularJS and Browserify for http://angularjs.de/'); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --recursive 2 | --reporter spec 3 | -------------------------------------------------------------------------------- /test/unit/controller/edit_todo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai') 4 | , expect = chai.expect 5 | , sinon = require('sinon') 6 | , sinonChai = require('sinon-chai'); 7 | 8 | chai.use(sinonChai); 9 | 10 | var EditTodoCtrlModule = require('../../../app/js/controller/edit_todo.js'); 11 | 12 | describe('The EditTodoCtrl\'s', function() { 13 | 14 | var todo; 15 | var $scope; 16 | var TodoService; 17 | 18 | beforeEach(function() { 19 | todo = { 20 | title: 'Todo', 21 | due: '2015-02-13', 22 | text: 'Do it', 23 | }; 24 | 25 | $scope = { 26 | $parent: { 27 | todo: todo 28 | } 29 | }; 30 | 31 | TodoService = { 32 | getTodos: sinon.stub().returns([{}]), 33 | create: sinon.spy(), 34 | insert: sinon.spy(), 35 | remove: sinon.spy(), 36 | }; 37 | 38 | EditTodoCtrlModule($scope, TodoService); 39 | }); 40 | 41 | describe('create workflow', function() { 42 | 43 | it('should create an new todo', function() { 44 | $scope.create(); 45 | expect(TodoService.create).to.have.been.calledOnce; 46 | expect($scope.editMode).to.be.true; 47 | }); 48 | 49 | it('should save a new todo', function() { 50 | $scope.create(); 51 | $scope.save(); 52 | expect(TodoService.insert).to.have.been.calledOnce; 53 | expect($scope.editMode).to.be.false; 54 | }); 55 | 56 | it('should cancel the creation of a new todo', function() { 57 | $scope.create(); 58 | $scope.cancel(); 59 | expect(TodoService.insert).to.not.have.been.called; 60 | expect($scope.editMode).to.be.false; 61 | }); 62 | }); 63 | 64 | describe('edit workflow', function() { 65 | 66 | it('should edit a todo', function() { 67 | $scope.edit(); 68 | expect($scope.editMode).to.be.true; 69 | }); 70 | 71 | it('should save an edited todo', function() { 72 | $scope.edit(); 73 | $scope.save(); 74 | expect(TodoService.insert).to.not.have.been.called; 75 | expect($scope.editMode).to.be.false; 76 | }); 77 | 78 | it('should cancel the editing of an existing todo', function() { 79 | $scope.edit(); 80 | $scope.$parent.todo.title = 'changed'; 81 | $scope.cancel(); 82 | expect(TodoService.insert).to.not.have.been.called; 83 | expect($scope.$parent.todo.title).to.equal('Todo'); 84 | expect($scope.editMode).to.be.false; 85 | }); 86 | }); 87 | 88 | it('should remove a todo item', function() { 89 | var t = $scope.$parent.todo; 90 | $scope.remove(); 91 | expect(TodoService.remove).to.have.been.calledWith(t); 92 | }); 93 | 94 | }); 95 | -------------------------------------------------------------------------------- /test/unit/controller/todo_list.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai') 4 | , expect = chai.expect; 5 | 6 | var TodoListCtrlModule = require('../../../app/js/controller/todo_list.js'); 7 | 8 | describe('The TodoListCtrl', function() { 9 | 10 | var todo; 11 | var $scope; 12 | 13 | beforeEach(function() { 14 | todo = { 15 | title: 'Todo', 16 | due: '2015-02-13', 17 | text: 'Do it', 18 | }; 19 | 20 | $scope = { 21 | $parent: { 22 | todo: todo 23 | } 24 | }; 25 | 26 | var TodoService = { 27 | getTodos: function() {}, 28 | }; 29 | 30 | TodoListCtrlModule($scope, TodoService); 31 | }); 32 | 33 | it('should highlight the active todo item', function() { 34 | var styles = $scope.getCssClass(todo); 35 | expect(styles).to.be.instanceof(Array); 36 | expect(styles.length).to.equal(1); 37 | expect(styles[0]).to.equal('sidebar-item-active'); 38 | }); 39 | 40 | it('should not highlight an inactive todo item', function() { 41 | var styles = $scope.getCssClass({}); 42 | expect(styles).to.be.instanceof(Array); 43 | expect(styles.length).to.equal(1); 44 | expect(styles[0]).to.equal('sidebar-item-inactive'); 45 | }); 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /test/unit/service/imprint.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai') 4 | , expect = chai.expect; 5 | 6 | var ImprintServiceModule = require('../../../app/js/service/imprint.js'); 7 | 8 | describe('The ImprintService', function() { 9 | 10 | var ImprintService; 11 | 12 | beforeEach(function() { 13 | ImprintService = new ImprintServiceModule(); 14 | }); 15 | 16 | it('should provide the imprint text', function() { 17 | var text = ImprintService.getText(); 18 | expect(text.length).to.be.above(30); 19 | }); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /test/unit/service/todos.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var chai = require('chai') 4 | , expect = chai.expect; 5 | 6 | var TodoServiceModule = require('../../../app/js/service/todos.js'); 7 | 8 | describe('The TodoService', function() { 9 | 10 | var TodoService; 11 | 12 | beforeEach(function() { 13 | TodoService = new TodoServiceModule(); 14 | }); 15 | 16 | it('should have some todos initially', function() { 17 | var todos = TodoService.getTodos(); 18 | expect(todos.length).to.equal(4); 19 | expect(todos[0].title).to.equal('Buy milk'); 20 | }); 21 | 22 | it('should create a todo', function() { 23 | var todo = TodoService.create(); 24 | expect(todo.title).to.exist; 25 | expect(todo.title).to.be.equal(''); 26 | expect(todo.due).to.exist; 27 | expect(todo.text).to.exist; 28 | expect(todo.text).to.exist; 29 | }); 30 | 31 | it('should insert a todo', function() { 32 | TodoService.insert({ title: 'test' }); 33 | var todos = TodoService.getTodos(); 34 | expect(todos.length).to.equal(5); 35 | expect(todos[4].title).to.equal('test'); 36 | }); 37 | 38 | it('should remove a todo, based on object identity', function() { 39 | TodoService.remove(TodoService.getTodos()[2]); 40 | var todos = TodoService.getTodos(); 41 | expect(todos.length).to.equal(3); 42 | expect(todos[1].title).to.equal('Write blog post'); 43 | expect(todos[2].title).to.equal('World Domination'); 44 | }); 45 | 46 | }); 47 | --------------------------------------------------------------------------------