`, and ``.
+$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default;
+$font-family-base: $font-family-sans-serif !default;
+
+$font-size-base: 14px !default;
+$font-size-large: ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-small: ceil(($font-size-base * 0.85)) !default; // ~12px
+
+$font-size-h1: floor(($font-size-base * 2.6)) !default; // ~36px
+$font-size-h2: floor(($font-size-base * 2.15)) !default; // ~30px
+$font-size-h3: ceil(($font-size-base * 1.7)) !default; // ~24px
+$font-size-h4: ceil(($font-size-base * 1.25)) !default; // ~18px
+$font-size-h5: $font-size-base !default;
+$font-size-h6: ceil(($font-size-base * 0.85)) !default; // ~12px
+
+//** Unit-less `line-height` for use in components like buttons.
+$line-height-base: 1.428571429 !default; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+$line-height-computed: floor(($font-size-base * $line-height-base)) !default; // ~20px
+
+//** By default, this inherits from the ``.
+$headings-font-family: inherit !default;
+$headings-font-weight: 500 !default;
+$headings-line-height: 1.1 !default;
+$headings-color: inherit !default;
+
+
+//== Iconography
+//
+//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+//** Load fonts from this directory.
+
+// [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path.
+// [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths.
+$icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
+
+//** File name for all font files.
+$icon-font-name: "glyphicons-halflings-regular" !default;
+//** Element ID within SVG icon file.
+$icon-font-svg-id: "glyphicons_halflingsregular" !default;
+
+
+//== Components
+//
+//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+$padding-base-vertical: 6px !default;
+$padding-base-horizontal: 12px !default;
+
+$padding-large-vertical: 10px !default;
+$padding-large-horizontal: 16px !default;
+
+$padding-small-vertical: 5px !default;
+$padding-small-horizontal: 10px !default;
+
+$padding-xs-vertical: 1px !default;
+$padding-xs-horizontal: 5px !default;
+
+$line-height-large: 1.3333333 !default; // extra decimals for Win 8.1 Chrome
+$line-height-small: 1.5 !default;
+
+$border-radius-base: 4px !default;
+$border-radius-large: 6px !default;
+$border-radius-small: 3px !default;
+
+//** Global color for active items (e.g., navs or dropdowns).
+$component-active-color: #fff !default;
+//** Global background color for active items (e.g., navs or dropdowns).
+$component-active-bg: $brand-primary !default;
+
+//** Width of the `border` for generating carets that indicator dropdowns.
+$caret-width-base: 4px !default;
+//** Carets increase slightly in size for larger components.
+$caret-width-large: 5px !default;
+
+
+//== Tables
+//
+//## Customizes the `.table` component with basic values, each used across all table variations.
+
+//** Padding for ``s and ` `s.
+$table-cell-padding: 8px !default;
+//** Padding for cells in `.table-condensed`.
+$table-condensed-cell-padding: 5px !default;
+
+//** Default background color used for all tables.
+$table-bg: transparent !default;
+//** Background color used for `.table-striped`.
+$table-bg-accent: #f9f9f9 !default;
+//** Background color used for `.table-hover`.
+$table-bg-hover: #f5f5f5 !default;
+$table-bg-active: $table-bg-hover !default;
+
+//** Border color for table and cell borders.
+$table-border-color: #ddd !default;
+
+
+//== Buttons
+//
+//## For each of Bootstrap's buttons, define text, background and border color.
+
+$btn-font-weight: normal !default;
+
+$btn-default-color: #333 !default;
+$btn-default-bg: #fff !default;
+$btn-default-border: #ccc !default;
+
+$btn-primary-color: #fff !default;
+$btn-primary-bg: $brand-primary !default;
+$btn-primary-border: darken($btn-primary-bg, 5%) !default;
+
+$btn-success-color: #fff !default;
+$btn-success-bg: $brand-success !default;
+$btn-success-border: darken($btn-success-bg, 5%) !default;
+
+$btn-info-color: #fff !default;
+$btn-info-bg: $brand-info !default;
+$btn-info-border: darken($btn-info-bg, 5%) !default;
+
+$btn-warning-color: #fff !default;
+$btn-warning-bg: $brand-warning !default;
+$btn-warning-border: darken($btn-warning-bg, 5%) !default;
+
+$btn-danger-color: #fff !default;
+$btn-danger-bg: $brand-danger !default;
+$btn-danger-border: darken($btn-danger-bg, 5%) !default;
+
+$btn-link-disabled-color: $gray-light !default;
+
+// Allows for customizing button radius independently from global border radius
+$btn-border-radius-base: $border-radius-base !default;
+$btn-border-radius-large: $border-radius-large !default;
+$btn-border-radius-small: $border-radius-small !default;
+
+
+//== Forms
+//
+//##
+
+//** ` ` background color
+$input-bg: #fff !default;
+//** ` ` background color
+$input-bg-disabled: $gray-lighter !default;
+
+//** Text color for ` `s
+$input-color: $gray !default;
+//** ` ` border color
+$input-border: #ccc !default;
+
+// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
+//** Default `.form-control` border radius
+// This has no effect on ``s in some browsers, due to the limited stylability of ``s in CSS.
+$input-border-radius: $border-radius-base !default;
+//** Large `.form-control` border radius
+$input-border-radius-large: $border-radius-large !default;
+//** Small `.form-control` border radius
+$input-border-radius-small: $border-radius-small !default;
+
+//** Border color for inputs on focus
+$input-border-focus: #66afe9 !default;
+
+//** Placeholder text color
+$input-color-placeholder: #999 !default;
+
+//** Default `.form-control` height
+$input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
+//** Large `.form-control` height
+$input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
+//** Small `.form-control` height
+$input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
+
+//** `.form-group` margin
+$form-group-margin-bottom: 15px !default;
+
+$legend-color: $gray-dark !default;
+$legend-border-color: #e5e5e5 !default;
+
+//** Background color for textual input addons
+$input-group-addon-bg: $gray-lighter !default;
+//** Border color for textual input addons
+$input-group-addon-border-color: $input-border !default;
+
+//** Disabled cursor for form controls and buttons.
+$cursor-disabled: not-allowed !default;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+$dropdown-bg: #fff !default;
+//** Dropdown menu `border-color`.
+$dropdown-border: rgba(0,0,0,.15) !default;
+//** Dropdown menu `border-color` **for IE8**.
+$dropdown-fallback-border: #ccc !default;
+//** Divider color for between dropdown items.
+$dropdown-divider-bg: #e5e5e5 !default;
+
+//** Dropdown link text color.
+$dropdown-link-color: $gray-dark !default;
+//** Hover color for dropdown links.
+$dropdown-link-hover-color: darken($gray-dark, 5%) !default;
+//** Hover background for dropdown links.
+$dropdown-link-hover-bg: #f5f5f5 !default;
+
+//** Active dropdown menu item text color.
+$dropdown-link-active-color: $component-active-color !default;
+//** Active dropdown menu item background color.
+$dropdown-link-active-bg: $component-active-bg !default;
+
+//** Disabled dropdown menu item background color.
+$dropdown-link-disabled-color: $gray-light !default;
+
+//** Text color for headers within dropdown menus.
+$dropdown-header-color: $gray-light !default;
+
+//** Deprecated `$dropdown-caret-color` as of v3.1.0
+$dropdown-caret-color: #000 !default;
+
+
+//-- Z-index master list
+//
+// Warning: Avoid customizing these values. They're used for a bird's eye view
+// of components dependent on the z-axis and are designed to all work together.
+//
+// Note: These variables are not generated into the Customizer.
+
+$zindex-navbar: 1000 !default;
+$zindex-dropdown: 1000 !default;
+$zindex-popover: 1060 !default;
+$zindex-tooltip: 1070 !default;
+$zindex-navbar-fixed: 1030 !default;
+$zindex-modal-background: 1040 !default;
+$zindex-modal: 1050 !default;
+
+
+//== Media queries breakpoints
+//
+//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// Extra small screen / phone
+//** Deprecated `$screen-xs` as of v3.0.1
+$screen-xs: 480px !default;
+//** Deprecated `$screen-xs-min` as of v3.2.0
+$screen-xs-min: $screen-xs !default;
+//** Deprecated `$screen-phone` as of v3.0.1
+$screen-phone: $screen-xs-min !default;
+
+// Small screen / tablet
+//** Deprecated `$screen-sm` as of v3.0.1
+$screen-sm: 768px !default;
+$screen-sm-min: $screen-sm !default;
+//** Deprecated `$screen-tablet` as of v3.0.1
+$screen-tablet: $screen-sm-min !default;
+
+// Medium screen / desktop
+//** Deprecated `$screen-md` as of v3.0.1
+$screen-md: 992px !default;
+$screen-md-min: $screen-md !default;
+//** Deprecated `$screen-desktop` as of v3.0.1
+$screen-desktop: $screen-md-min !default;
+
+// Large screen / wide desktop
+//** Deprecated `$screen-lg` as of v3.0.1
+$screen-lg: 1200px !default;
+$screen-lg-min: $screen-lg !default;
+//** Deprecated `$screen-lg-desktop` as of v3.0.1
+$screen-lg-desktop: $screen-lg-min !default;
+
+// So media queries don't overlap when required, provide a maximum
+$screen-xs-max: ($screen-sm-min - 1) !default;
+$screen-sm-max: ($screen-md-min - 1) !default;
+$screen-md-max: ($screen-lg-min - 1) !default;
+
+
+//== Grid system
+//
+//## Define your custom responsive grid.
+
+//** Number of columns in the grid.
+$grid-columns: 12 !default;
+//** Padding between columns. Gets divided in half for the left and right.
+$grid-gutter-width: 30px !default;
+// Navbar collapse
+//** Point at which the navbar becomes uncollapsed.
+$grid-float-breakpoint: $screen-sm-min !default;
+//** Point at which the navbar begins collapsing.
+$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
+
+
+//== Container sizes
+//
+//## Define the maximum width of `.container` for different screen sizes.
+
+// Small screen / tablet
+$container-tablet: (720px + $grid-gutter-width) !default;
+//** For `$screen-sm-min` and up.
+$container-sm: $container-tablet !default;
+
+// Medium screen / desktop
+$container-desktop: (940px + $grid-gutter-width) !default;
+//** For `$screen-md-min` and up.
+$container-md: $container-desktop !default;
+
+// Large screen / wide desktop
+$container-large-desktop: (1140px + $grid-gutter-width) !default;
+//** For `$screen-lg-min` and up.
+$container-lg: $container-large-desktop !default;
+
+
+//== Navbar
+//
+//##
+
+// Basics of a navbar
+$navbar-height: 50px !default;
+$navbar-margin-bottom: $line-height-computed !default;
+$navbar-border-radius: $border-radius-base !default;
+$navbar-padding-horizontal: floor(($grid-gutter-width / 2)) !default;
+$navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2) !default;
+$navbar-collapse-max-height: 340px !default;
+
+$navbar-default-color: #777 !default;
+$navbar-default-bg: #f8f8f8 !default;
+$navbar-default-border: darken($navbar-default-bg, 6.5%) !default;
+
+// Navbar links
+$navbar-default-link-color: #777 !default;
+$navbar-default-link-hover-color: #333 !default;
+$navbar-default-link-hover-bg: transparent !default;
+$navbar-default-link-active-color: #555 !default;
+$navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%) !default;
+$navbar-default-link-disabled-color: #ccc !default;
+$navbar-default-link-disabled-bg: transparent !default;
+
+// Navbar brand label
+$navbar-default-brand-color: $navbar-default-link-color !default;
+$navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%) !default;
+$navbar-default-brand-hover-bg: transparent !default;
+
+// Navbar toggle
+$navbar-default-toggle-hover-bg: #ddd !default;
+$navbar-default-toggle-icon-bar-bg: #888 !default;
+$navbar-default-toggle-border-color: #ddd !default;
+
+
+//=== Inverted navbar
+// Reset inverted navbar basics
+$navbar-inverse-color: lighten($gray-light, 15%) !default;
+$navbar-inverse-bg: #222 !default;
+$navbar-inverse-border: darken($navbar-inverse-bg, 10%) !default;
+
+// Inverted navbar links
+$navbar-inverse-link-color: lighten($gray-light, 15%) !default;
+$navbar-inverse-link-hover-color: #fff !default;
+$navbar-inverse-link-hover-bg: transparent !default;
+$navbar-inverse-link-active-color: $navbar-inverse-link-hover-color !default;
+$navbar-inverse-link-active-bg: darken($navbar-inverse-bg, 10%) !default;
+$navbar-inverse-link-disabled-color: #444 !default;
+$navbar-inverse-link-disabled-bg: transparent !default;
+
+// Inverted navbar brand label
+$navbar-inverse-brand-color: $navbar-inverse-link-color !default;
+$navbar-inverse-brand-hover-color: #fff !default;
+$navbar-inverse-brand-hover-bg: transparent !default;
+
+// Inverted navbar toggle
+$navbar-inverse-toggle-hover-bg: #333 !default;
+$navbar-inverse-toggle-icon-bar-bg: #fff !default;
+$navbar-inverse-toggle-border-color: #333 !default;
+
+
+//== Navs
+//
+//##
+
+//=== Shared nav styles
+$nav-link-padding: 10px 15px !default;
+$nav-link-hover-bg: $gray-lighter !default;
+
+$nav-disabled-link-color: $gray-light !default;
+$nav-disabled-link-hover-color: $gray-light !default;
+
+//== Tabs
+$nav-tabs-border-color: #ddd !default;
+
+$nav-tabs-link-hover-border-color: $gray-lighter !default;
+
+$nav-tabs-active-link-hover-bg: $body-bg !default;
+$nav-tabs-active-link-hover-color: $gray !default;
+$nav-tabs-active-link-hover-border-color: #ddd !default;
+
+$nav-tabs-justified-link-border-color: #ddd !default;
+$nav-tabs-justified-active-link-border-color: $body-bg !default;
+
+//== Pills
+$nav-pills-border-radius: $border-radius-base !default;
+$nav-pills-active-link-hover-bg: $component-active-bg !default;
+$nav-pills-active-link-hover-color: $component-active-color !default;
+
+
+//== Pagination
+//
+//##
+
+$pagination-color: $link-color !default;
+$pagination-bg: #fff !default;
+$pagination-border: #ddd !default;
+
+$pagination-hover-color: $link-hover-color !default;
+$pagination-hover-bg: $gray-lighter !default;
+$pagination-hover-border: #ddd !default;
+
+$pagination-active-color: #fff !default;
+$pagination-active-bg: $brand-primary !default;
+$pagination-active-border: $brand-primary !default;
+
+$pagination-disabled-color: $gray-light !default;
+$pagination-disabled-bg: #fff !default;
+$pagination-disabled-border: #ddd !default;
+
+
+//== Pager
+//
+//##
+
+$pager-bg: $pagination-bg !default;
+$pager-border: $pagination-border !default;
+$pager-border-radius: 15px !default;
+
+$pager-hover-bg: $pagination-hover-bg !default;
+
+$pager-active-bg: $pagination-active-bg !default;
+$pager-active-color: $pagination-active-color !default;
+
+$pager-disabled-color: $pagination-disabled-color !default;
+
+
+//== Jumbotron
+//
+//##
+
+$jumbotron-padding: 30px !default;
+$jumbotron-color: inherit !default;
+$jumbotron-bg: $gray-lighter !default;
+$jumbotron-heading-color: inherit !default;
+$jumbotron-font-size: ceil(($font-size-base * 1.5)) !default;
+$jumbotron-heading-font-size: ceil(($font-size-base * 4.5)) !default;
+
+
+//== Form states and alerts
+//
+//## Define colors for form feedback states and, by default, alerts.
+
+$state-success-text: #3c763d !default;
+$state-success-bg: #dff0d8 !default;
+$state-success-border: darken(adjust-hue($state-success-bg, -10), 5%) !default;
+
+$state-info-text: #31708f !default;
+$state-info-bg: #d9edf7 !default;
+$state-info-border: darken(adjust-hue($state-info-bg, -10), 7%) !default;
+
+$state-warning-text: #8a6d3b !default;
+$state-warning-bg: #fcf8e3 !default;
+$state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%) !default;
+
+$state-danger-text: #a94442 !default;
+$state-danger-bg: #f2dede !default;
+$state-danger-border: darken(adjust-hue($state-danger-bg, -10), 5%) !default;
+
+
+//== Tooltips
+//
+//##
+
+//** Tooltip max width
+$tooltip-max-width: 200px !default;
+//** Tooltip text color
+$tooltip-color: #fff !default;
+//** Tooltip background color
+$tooltip-bg: #000 !default;
+$tooltip-opacity: .9 !default;
+
+//** Tooltip arrow width
+$tooltip-arrow-width: 5px !default;
+//** Tooltip arrow color
+$tooltip-arrow-color: $tooltip-bg !default;
+
+
+//== Popovers
+//
+//##
+
+//** Popover body background color
+$popover-bg: #fff !default;
+//** Popover maximum width
+$popover-max-width: 276px !default;
+//** Popover border color
+$popover-border-color: rgba(0,0,0,.2) !default;
+//** Popover fallback border color
+$popover-fallback-border-color: #ccc !default;
+
+//** Popover title background color
+$popover-title-bg: darken($popover-bg, 3%) !default;
+
+//** Popover arrow width
+$popover-arrow-width: 10px !default;
+//** Popover arrow color
+$popover-arrow-color: $popover-bg !default;
+
+//** Popover outer arrow width
+$popover-arrow-outer-width: ($popover-arrow-width + 1) !default;
+//** Popover outer arrow color
+$popover-arrow-outer-color: fade_in($popover-border-color, 0.05) !default;
+//** Popover outer arrow fallback color
+$popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%) !default;
+
+
+//== Labels
+//
+//##
+
+//** Default label background color
+$label-default-bg: $gray-light !default;
+//** Primary label background color
+$label-primary-bg: $brand-primary !default;
+//** Success label background color
+$label-success-bg: $brand-success !default;
+//** Info label background color
+$label-info-bg: $brand-info !default;
+//** Warning label background color
+$label-warning-bg: $brand-warning !default;
+//** Danger label background color
+$label-danger-bg: $brand-danger !default;
+
+//** Default label text color
+$label-color: #fff !default;
+//** Default text color of a linked label
+$label-link-hover-color: #fff !default;
+
+
+//== Modals
+//
+//##
+
+//** Padding applied to the modal body
+$modal-inner-padding: 15px !default;
+
+//** Padding applied to the modal title
+$modal-title-padding: 15px !default;
+//** Modal title line-height
+$modal-title-line-height: $line-height-base !default;
+
+//** Background color of modal content area
+$modal-content-bg: #fff !default;
+//** Modal content border color
+$modal-content-border-color: rgba(0,0,0,.2) !default;
+//** Modal content border color **for IE8**
+$modal-content-fallback-border-color: #999 !default;
+
+//** Modal backdrop background color
+$modal-backdrop-bg: #000 !default;
+//** Modal backdrop opacity
+$modal-backdrop-opacity: .5 !default;
+//** Modal header border color
+$modal-header-border-color: #e5e5e5 !default;
+//** Modal footer border color
+$modal-footer-border-color: $modal-header-border-color !default;
+
+$modal-lg: 900px !default;
+$modal-md: 600px !default;
+$modal-sm: 300px !default;
+
+
+//== Alerts
+//
+//## Define alert colors, border radius, and padding.
+
+$alert-padding: 15px !default;
+$alert-border-radius: $border-radius-base !default;
+$alert-link-font-weight: bold !default;
+
+$alert-success-bg: $state-success-bg !default;
+$alert-success-text: $state-success-text !default;
+$alert-success-border: $state-success-border !default;
+
+$alert-info-bg: $state-info-bg !default;
+$alert-info-text: $state-info-text !default;
+$alert-info-border: $state-info-border !default;
+
+$alert-warning-bg: $state-warning-bg !default;
+$alert-warning-text: $state-warning-text !default;
+$alert-warning-border: $state-warning-border !default;
+
+$alert-danger-bg: $state-danger-bg !default;
+$alert-danger-text: $state-danger-text !default;
+$alert-danger-border: $state-danger-border !default;
+
+
+//== Progress bars
+//
+//##
+
+//** Background color of the whole progress component
+$progress-bg: #f5f5f5 !default;
+//** Progress bar text color
+$progress-bar-color: #fff !default;
+//** Variable for setting rounded corners on progress bar.
+$progress-border-radius: $border-radius-base !default;
+
+//** Default progress bar color
+$progress-bar-bg: $brand-primary !default;
+//** Success progress bar color
+$progress-bar-success-bg: $brand-success !default;
+//** Warning progress bar color
+$progress-bar-warning-bg: $brand-warning !default;
+//** Danger progress bar color
+$progress-bar-danger-bg: $brand-danger !default;
+//** Info progress bar color
+$progress-bar-info-bg: $brand-info !default;
+
+
+//== List group
+//
+//##
+
+//** Background color on `.list-group-item`
+$list-group-bg: #fff !default;
+//** `.list-group-item` border color
+$list-group-border: #ddd !default;
+//** List group border radius
+$list-group-border-radius: $border-radius-base !default;
+
+//** Background color of single list items on hover
+$list-group-hover-bg: #f5f5f5 !default;
+//** Text color of active list items
+$list-group-active-color: $component-active-color !default;
+//** Background color of active list items
+$list-group-active-bg: $component-active-bg !default;
+//** Border color of active list elements
+$list-group-active-border: $list-group-active-bg !default;
+//** Text color for content within active list items
+$list-group-active-text-color: lighten($list-group-active-bg, 40%) !default;
+
+//** Text color of disabled list items
+$list-group-disabled-color: $gray-light !default;
+//** Background color of disabled list items
+$list-group-disabled-bg: $gray-lighter !default;
+//** Text color for content within disabled list items
+$list-group-disabled-text-color: $list-group-disabled-color !default;
+
+$list-group-link-color: #555 !default;
+$list-group-link-hover-color: $list-group-link-color !default;
+$list-group-link-heading-color: #333 !default;
+
+
+//== Panels
+//
+//##
+
+$panel-bg: #fff !default;
+$panel-body-padding: 15px !default;
+$panel-heading-padding: 10px 15px !default;
+$panel-footer-padding: $panel-heading-padding !default;
+$panel-border-radius: $border-radius-base !default;
+
+//** Border color for elements within panels
+$panel-inner-border: #ddd !default;
+$panel-footer-bg: #f5f5f5 !default;
+
+$panel-default-text: $gray-dark !default;
+$panel-default-border: #ddd !default;
+$panel-default-heading-bg: #f5f5f5 !default;
+
+$panel-primary-text: #fff !default;
+$panel-primary-border: $brand-primary !default;
+$panel-primary-heading-bg: $brand-primary !default;
+
+$panel-success-text: $state-success-text !default;
+$panel-success-border: $state-success-border !default;
+$panel-success-heading-bg: $state-success-bg !default;
+
+$panel-info-text: $state-info-text !default;
+$panel-info-border: $state-info-border !default;
+$panel-info-heading-bg: $state-info-bg !default;
+
+$panel-warning-text: $state-warning-text !default;
+$panel-warning-border: $state-warning-border !default;
+$panel-warning-heading-bg: $state-warning-bg !default;
+
+$panel-danger-text: $state-danger-text !default;
+$panel-danger-border: $state-danger-border !default;
+$panel-danger-heading-bg: $state-danger-bg !default;
+
+
+//== Thumbnails
+//
+//##
+
+//** Padding around the thumbnail image
+$thumbnail-padding: 4px !default;
+//** Thumbnail background color
+$thumbnail-bg: $body-bg !default;
+//** Thumbnail border color
+$thumbnail-border: #ddd !default;
+//** Thumbnail border radius
+$thumbnail-border-radius: $border-radius-base !default;
+
+//** Custom text color for thumbnail captions
+$thumbnail-caption-color: $text-color !default;
+//** Padding around the thumbnail caption
+$thumbnail-caption-padding: 9px !default;
+
+
+//== Wells
+//
+//##
+
+$well-bg: #f5f5f5 !default;
+$well-border: darken($well-bg, 7%) !default;
+
+
+//== Badges
+//
+//##
+
+$badge-color: #fff !default;
+//** Linked badge text color on hover
+$badge-link-hover-color: #fff !default;
+$badge-bg: $gray-light !default;
+
+//** Badge text color in active nav link
+$badge-active-color: $link-color !default;
+//** Badge background color in active nav link
+$badge-active-bg: #fff !default;
+
+$badge-font-weight: bold !default;
+$badge-line-height: 1 !default;
+$badge-border-radius: 10px !default;
+
+
+//== Breadcrumbs
+//
+//##
+
+$breadcrumb-padding-vertical: 8px !default;
+$breadcrumb-padding-horizontal: 15px !default;
+//** Breadcrumb background color
+$breadcrumb-bg: #f5f5f5 !default;
+//** Breadcrumb text color
+$breadcrumb-color: #ccc !default;
+//** Text color of current page in the breadcrumb
+$breadcrumb-active-color: $gray-light !default;
+//** Textual separator for between breadcrumb elements
+$breadcrumb-separator: "/" !default;
+
+
+//== Carousel
+//
+//##
+
+$carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6) !default;
+
+$carousel-control-color: #fff !default;
+$carousel-control-width: 15% !default;
+$carousel-control-opacity: .5 !default;
+$carousel-control-font-size: 20px !default;
+
+$carousel-indicator-active-bg: #fff !default;
+$carousel-indicator-border-color: #fff !default;
+
+$carousel-caption-color: #fff !default;
+
+
+//== Close
+//
+//##
+
+$close-font-weight: bold !default;
+$close-color: #000 !default;
+$close-text-shadow: 0 1px 0 #fff !default;
+
+
+//== Code
+//
+//##
+
+$code-color: #c7254e !default;
+$code-bg: #f9f2f4 !default;
+
+$kbd-color: #fff !default;
+$kbd-bg: #333 !default;
+
+$pre-bg: #f5f5f5 !default;
+$pre-color: $gray-dark !default;
+$pre-border-color: #ccc !default;
+$pre-scrollable-max-height: 340px !default;
+
+
+//== Type
+//
+//##
+
+//** Horizontal offset for forms and lists.
+$component-offset-horizontal: 180px !default;
+//** Text muted color
+$text-muted: $gray-light !default;
+//** Abbreviations and acronyms border color
+$abbr-border-color: $gray-light !default;
+//** Headings small color
+$headings-small-color: $gray-light !default;
+//** Blockquote small color
+$blockquote-small-color: $gray-light !default;
+//** Blockquote font size
+$blockquote-font-size: ($font-size-base * 1.25) !default;
+//** Blockquote border color
+$blockquote-border-color: $gray-lighter !default;
+//** Page header border color
+$page-header-border-color: $gray-lighter !default;
+//** Width of horizontal description list titles
+$dl-horizontal-offset: $component-offset-horizontal !default;
+//** Point at which .dl-horizontal becomes horizontal
+$dl-horizontal-breakpoint: $grid-float-breakpoint !default;
+//** Horizontal line color.
+$hr-border: $gray-lighter !default;
diff --git a/app/css/main.scss b/app/css/main.scss
new file mode 100644
index 0000000..3f92e97
--- /dev/null
+++ b/app/css/main.scss
@@ -0,0 +1,64 @@
+@import 'fonts';
+@import 'icons';
+@import 'variables';
+@import 'bootstrap';
+@import 'sprite';
+@import 'type';
+@import 'animations';
+@import 'transformations';
+
+body {
+ padding-top: 70px;
+}
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+ display: none !important;
+}
+
+sprite{
+ display: inline-block;
+ .sprite{
+ display: inline-block;
+ svg{
+ height: inherit;
+ width: inherit;
+ }
+ }
+}
+
+//App Loading
+#app-loading{
+ background-color: $gray-base;
+ height: 100%;
+ left: 0;
+ position: fixed;
+ top: 0;
+ width: 100%;
+ z-index: 10000;
+ span{
+ display: block;
+ left: 50%;
+ position: relative;
+ top: 50%;
+ height: 64px;
+ width: 64px;
+ font-size: 64px;
+ color: #fff;
+ transform: translate(-50%, -50%);
+ &:hover{
+ animation-play-state: paused;
+ }
+ }
+}
+
+p {
+ @include font-size(14px);
+}
+
+.polygons{
+ background: url('../images/polygon.jpg') 50% 50% no-repeat;
+ background-size: cover;
+ height: 300px;
+ width: 300px;
+}
+
diff --git a/app/images/angular.png b/app/images/angular.png
index d1dfc01..a9a2d45 100644
Binary files a/app/images/angular.png and b/app/images/angular.png differ
diff --git a/app/images/browserify.png b/app/images/browserify.png
deleted file mode 100644
index b77ba45..0000000
Binary files a/app/images/browserify.png and /dev/null differ
diff --git a/app/images/favicon/favicon.svg b/app/images/favicon/favicon.svg
new file mode 100644
index 0000000..2c1b4d7
--- /dev/null
+++ b/app/images/favicon/favicon.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/images/gulp.png b/app/images/gulp.png
deleted file mode 100644
index 7994592..0000000
Binary files a/app/images/gulp.png and /dev/null differ
diff --git a/app/images/icons/uEA01-check.svg b/app/images/icons/uEA01-check.svg
new file mode 100644
index 0000000..d72e339
--- /dev/null
+++ b/app/images/icons/uEA01-check.svg
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/images/icons/uEA02-cross.svg b/app/images/icons/uEA02-cross.svg
new file mode 100644
index 0000000..7a22dd5
--- /dev/null
+++ b/app/images/icons/uEA02-cross.svg
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/images/icons/uEA03-pin.svg b/app/images/icons/uEA03-pin.svg
new file mode 100644
index 0000000..d766048
--- /dev/null
+++ b/app/images/icons/uEA03-pin.svg
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/images/icons/uEA04-gear.svg b/app/images/icons/uEA04-gear.svg
new file mode 100644
index 0000000..189660d
--- /dev/null
+++ b/app/images/icons/uEA04-gear.svg
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/images/polygon.jpg b/app/images/polygon.jpg
new file mode 100644
index 0000000..085d38b
Binary files /dev/null and b/app/images/polygon.jpg differ
diff --git a/app/images/sprite/check.svg b/app/images/sprite/check.svg
new file mode 100644
index 0000000..446b167
--- /dev/null
+++ b/app/images/sprite/check.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/app/images/sprite/cross.svg b/app/images/sprite/cross.svg
new file mode 100644
index 0000000..c822313
--- /dev/null
+++ b/app/images/sprite/cross.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
diff --git a/app/images/sprite/pin.svg b/app/images/sprite/pin.svg
new file mode 100644
index 0000000..d368542
--- /dev/null
+++ b/app/images/sprite/pin.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/app/index.html b/app/index.html
index 4e0ed26..5a06a82 100644
--- a/app/index.html
+++ b/app/index.html
@@ -1,19 +1,29 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/js/app.js b/app/js/app.js
new file mode 100644
index 0000000..c120e37
--- /dev/null
+++ b/app/js/app.js
@@ -0,0 +1,58 @@
+import angular from 'angular';
+
+// angular modules
+import constants from './settings/constants';
+import onConfig from './settings/config';
+import onRun from './settings/run';
+import 'angular-sanitize';
+import 'angular-cookies';
+import 'angular-ui-router';
+import 'angular-dynamic-locale';
+import 'angular-translate';
+import 'angular-translate-loader-static-files';
+import 'angular-translate-storage-local';
+import 'angular-translate-storage-cookie';
+import 'angular-translate-handler-log';
+import 'oclazyload';
+import './app_tpl';
+import './filters';
+import './controllers';
+import './services';
+import './directives';
+
+if (constants.mocks === true) {
+ require ('./mocks');
+}
+
+// create and bootstrap application
+const requires = [
+ 'ngSanitize',
+ 'ngCookies',
+ 'tmh.dynamicLocale',
+ 'ui.router',
+ 'pascalprecht.translate',
+ 'app.templates',
+ 'app.filters',
+ 'app.controllers',
+ 'app.services',
+ 'app.directives',
+ 'oc.lazyLoad'
+];
+
+//activate mocks
+if (constants.mocks === true) {
+ requires.push('app.mocks');
+}
+
+// mount on window for testing
+window.app = angular.module('app', requires);
+
+angular.module('app').constant('AppSettings', constants);
+
+angular.module('app').config(onConfig);
+
+angular.module('app').run(onRun);
+
+angular.bootstrap(document, ['app'], {
+ strictDi: true
+});
\ No newline at end of file
diff --git a/app/js/constants.js b/app/js/constants.js
deleted file mode 100644
index e8d80b0..0000000
--- a/app/js/constants.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-const AppSettings = {
- appTitle: 'Example Application',
- apiUrl: '/api/v1'
-};
-
-export default AppSettings;
\ No newline at end of file
diff --git a/app/js/controllers/example.js b/app/js/controllers/example.js
deleted file mode 100644
index d86bdc8..0000000
--- a/app/js/controllers/example.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-function ExampleCtrl() {
-
- // ViewModel
- const vm = this;
-
- vm.title = 'AngularJS, Gulp, and Browserify! Written with keyboards and love!';
- vm.number = 1234;
-
-}
-
-export default {
- name: 'ExampleCtrl',
- fn: ExampleCtrl
-};
diff --git a/app/js/controllers/index.js b/app/js/controllers/index.js
index 4f27bf3..e1d461d 100644
--- a/app/js/controllers/index.js
+++ b/app/js/controllers/index.js
@@ -1,16 +1,25 @@
-'use strict';
-
import angular from 'angular';
-const bulk = require('bulk-require');
+const bulk = require('bulk-require');
const controllersModule = angular.module('app.controllers', []);
-
const controllers = bulk(__dirname, ['./**/!(*index|*.spec).js']);
-Object.keys(controllers).forEach((key) => {
- let item = controllers[key];
+function declare(controllerMap) {
+ Object.keys(controllerMap).forEach((key) => {
+ let item = controllerMap[key];
+
+ if (!item) {
+ return;
+ }
+
+ if (item.fn && typeof item.fn === 'function') {
+ controllersModule.controller(item.name, item.fn);
+ } else {
+ declare(item);
+ }
+ });
+}
- controllersModule.controller(item.name, item.fn);
-});
+declare(controllers);
export default controllersModule;
\ No newline at end of file
diff --git a/app/js/directives/app-loading.js b/app/js/directives/app-loading.js
new file mode 100644
index 0000000..38c78af
--- /dev/null
+++ b/app/js/directives/app-loading.js
@@ -0,0 +1,11 @@
+function AppLoading() {
+ 'ngInject';
+ return {
+ templateUrl: 'directives/app-loading.html'
+ };
+}
+
+export default {
+ name: 'appLoading',
+ fn: AppLoading
+};
diff --git a/app/js/directives/example.js b/app/js/directives/example.js
deleted file mode 100644
index 29890ca..0000000
--- a/app/js/directives/example.js
+++ /dev/null
@@ -1,23 +0,0 @@
-'use strict';
-
-function ExampleDirective() {
-
- return {
- restrict: 'EA',
- templateUrl: 'directives/example.html',
- scope: {
- title: '@',
- message: '@exampleDirective'
- },
- link: (scope, element) => {
- element.on('click', () => {
- window.alert('Element clicked: ' + scope.message);
- });
- }
- };
-}
-
-export default {
- name: 'exampleDirective',
- fn: ExampleDirective
-};
diff --git a/app/js/directives/index.js b/app/js/directives/index.js
index 7d5e26e..2fe305a 100644
--- a/app/js/directives/index.js
+++ b/app/js/directives/index.js
@@ -1,16 +1,25 @@
-'use strict';
-
import angular from 'angular';
-const bulk = require('bulk-require');
+const bulk = require('bulk-require');
const directivesModule = angular.module('app.directives', []);
-
const directives = bulk(__dirname, ['./**/!(*index|*.spec).js']);
-Object.keys(directives).forEach((key) => {
- let item = directives[key];
+function declare(directiveMap) {
+ Object.keys(directiveMap).forEach((key) => {
+ let item = directiveMap[key];
+
+ if (!item) {
+ return;
+ }
+
+ if (item.fn && typeof item.fn === 'function') {
+ directivesModule.directive(item.name, item.fn);
+ } else {
+ declare(item);
+ }
+ });
+}
- directivesModule.directive(item.name, item.fn);
-});
+declare(directives);
export default directivesModule;
\ No newline at end of file
diff --git a/app/js/directives/sprite.js b/app/js/directives/sprite.js
new file mode 100644
index 0000000..d09fda0
--- /dev/null
+++ b/app/js/directives/sprite.js
@@ -0,0 +1,29 @@
+function Sprite($document, $http, $templateCache, $compile, $rootScope) {
+ 'ngInject';
+ var sprites = [];
+ return {
+ restrict: 'E',
+ scope : {
+ symbol: '='
+ },
+ templateUrl: 'directives/sprite.html',
+ link : function (scope, element, attrs) {
+ //var sprite = attrs.sprite;
+ var sprite = 'partials/sprite.html';
+ // if not already loaded
+ if (sprites.indexOf(sprite) < 0) {
+ sprites.push(sprite);
+ $http.get(sprite, {cache: $templateCache}).then(function (response) {
+ var spriteSvg = angular.element(response.data);
+ spriteSvg = $compile(spriteSvg)($rootScope);
+ angular.element($document[0].body).prepend(spriteSvg);
+ });
+ }
+ }
+ };
+}
+
+export default {
+ name: 'sprite',
+ fn: Sprite
+};
diff --git a/app/js/directives/translate-language.js b/app/js/directives/translate-language.js
new file mode 100644
index 0000000..706e613
--- /dev/null
+++ b/app/js/directives/translate-language.js
@@ -0,0 +1,20 @@
+function TranslateLanguage(LocalizationService) {
+ 'ngInject';
+ return {
+ restrict: 'A',
+ replace: true,
+ templateUrl: 'directives/translate-language.html',
+ link: function ($scope) {
+ $scope.languages = LocalizationService.get();
+ $scope.current = LocalizationService.getCurrent();
+ $scope.changeLanguage = function (locale) {
+ $scope.current = LocalizationService.set(locale);
+ };
+ }
+ };
+}
+
+export default {
+ name: 'translateLanguage',
+ fn: TranslateLanguage
+};
diff --git a/app/js/filters/example.js b/app/js/filters/example.js
deleted file mode 100644
index 661bda4..0000000
--- a/app/js/filters/example.js
+++ /dev/null
@@ -1,14 +0,0 @@
-'use strict';
-
-function ExampleFilter() {
-
- return function(input) {
- return input.replace(/keyboard/ig,'leopard');
- };
-
-}
-
-export default {
- name: 'ExampleFilter',
- fn: ExampleFilter
-};
\ No newline at end of file
diff --git a/app/js/filters/index.js b/app/js/filters/index.js
index 627bef0..dececb2 100644
--- a/app/js/filters/index.js
+++ b/app/js/filters/index.js
@@ -1,16 +1,25 @@
-'use strict';
-
import angular from 'angular';
-const bulk = require('bulk-require');
+const bulk = require('bulk-require');
const filtersModule = angular.module('app.filters', []);
-
const filters = bulk(__dirname, ['./**/!(*index|*.spec).js']);
-Object.keys(filters).forEach((key) => {
- let item = filters[key];
+function declare(filterMap) {
+ Object.keys(filterMap).forEach((key) => {
+ let item = filterMap[key];
+
+ if (!item) {
+ return;
+ }
+
+ if (item.fn && typeof item.fn === 'function') {
+ filtersModule.filter(item.name, item.fn);
+ } else {
+ declare(item);
+ }
+ });
+}
- filtersModule.filter(item.name, item.fn);
-});
+declare(filters);
export default filtersModule;
\ No newline at end of file
diff --git a/app/js/filters/trim.js b/app/js/filters/trim.js
new file mode 100644
index 0000000..95357de
--- /dev/null
+++ b/app/js/filters/trim.js
@@ -0,0 +1,14 @@
+function TrimFilter() {
+
+ return function(input, chars) {
+
+ var trim = chars || '\\s';
+
+ return angular.isString(input) ? input.replace(new RegExp('^' + trim + '+|' + trim + '+$', 'g'), '') : input;
+ };
+}
+
+export default {
+ name: 'trim',
+ fn: TrimFilter
+};
\ No newline at end of file
diff --git a/app/js/home.js b/app/js/home.js
new file mode 100644
index 0000000..1951b72
--- /dev/null
+++ b/app/js/home.js
@@ -0,0 +1,9 @@
+import '../modules/home/home_css.js';
+import '../modules/home/home_tpl.js';
+import ctrl from '../modules/home/homeCtrl.js';
+
+var homeModule = angular.module('homeModule', []);
+
+homeModule.controller(ctrl.name, ctrl.fn);
+
+export default homeModule;
\ No newline at end of file
diff --git a/app/js/main.js b/app/js/main.js
deleted file mode 100644
index 64ece7a..0000000
--- a/app/js/main.js
+++ /dev/null
@@ -1,34 +0,0 @@
-'use strict';
-
-import angular from 'angular';
-
-// angular modules
-import 'angular-ui-router';
-import './templates';
-import './filters';
-import './controllers';
-import './services';
-import './directives';
-
-// create and bootstrap application
-const requires = [
- 'ui.router',
- 'templates',
- 'app.filters',
- 'app.controllers',
- 'app.services',
- 'app.directives'
-];
-
-// mount on window for testing
-window.app = angular.module('app', requires);
-
-angular.module('app').constant('AppSettings', require('./constants'));
-
-angular.module('app').config(require('./on_config'));
-
-angular.module('app').run(require('./on_run'));
-
-angular.bootstrap(document, ['app'], {
- strictDi: true
-});
diff --git a/app/js/mocks/index.js b/app/js/mocks/index.js
new file mode 100644
index 0000000..6760105
--- /dev/null
+++ b/app/js/mocks/index.js
@@ -0,0 +1,27 @@
+import angular from 'angular';
+import 'angular-mocks';
+import constants from './../settings/constants';
+
+const bulk = require('bulk-require');
+const mocksModule = angular.module('app.mocks', ['ngMockE2E']);
+const mocks = bulk(__dirname, ['./**/!(*index|*.spec).js']);
+
+function declare(mockMap) {
+ Object.keys(mockMap).forEach((key) => {
+ let item = mockMap[key];
+
+ if (!item) {
+ return;
+ }
+
+ if (item && typeof item === 'function') {
+ mocksModule.run(item);
+ } else {
+ declare(item);
+ }
+ });
+}
+
+declare(mocks);
+
+export default mocksModule;
\ No newline at end of file
diff --git a/app/js/mocks/languages.js b/app/js/mocks/languages.js
new file mode 100644
index 0000000..c613943
--- /dev/null
+++ b/app/js/mocks/languages.js
@@ -0,0 +1,11 @@
+import en_us from '../../resources/translation/en_us.json';
+import es_es from '../../resources/translation/es_es.json';
+
+function LanguagesMocks($httpBackend) {
+ 'ngInject';
+
+ $httpBackend.whenGET('resources/translation/en_us.json').respond(en_us);
+ $httpBackend.whenGET('resources/translation/es_es.json').respond(es_es);
+}
+
+export default LanguagesMocks;
\ No newline at end of file
diff --git a/app/js/mocks/products.js b/app/js/mocks/products.js
new file mode 100644
index 0000000..1beba37
--- /dev/null
+++ b/app/js/mocks/products.js
@@ -0,0 +1,10 @@
+import products from '../../resources/mocks/products.json';
+
+function ProductsMocks($httpBackend) {
+ 'ngInject';
+
+ $httpBackend.whenGET('/api/products').respond(products.list);
+
+}
+
+export default ProductsMocks;
\ No newline at end of file
diff --git a/app/js/on_config.js b/app/js/on_config.js
deleted file mode 100644
index 9befdb7..0000000
--- a/app/js/on_config.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict';
-
-function OnConfig($stateProvider, $locationProvider, $urlRouterProvider) {
- 'ngInject';
-
- $locationProvider.html5Mode(true);
-
- $stateProvider
- .state('Home', {
- url: '/',
- controller: 'ExampleCtrl as home',
- templateUrl: 'home.html',
- title: 'Home'
- });
-
- $urlRouterProvider.otherwise('/');
-
-}
-
-export default OnConfig;
\ No newline at end of file
diff --git a/app/js/on_run.js b/app/js/on_run.js
deleted file mode 100644
index e49dc2f..0000000
--- a/app/js/on_run.js
+++ /dev/null
@@ -1,20 +0,0 @@
-'use strict';
-
-function OnRun($rootScope, AppSettings) {
- 'ngInject';
-
- // change page title based on state
- $rootScope.$on('$stateChangeSuccess', (event, toState) => {
- $rootScope.pageTitle = '';
-
- if ( toState.title ) {
- $rootScope.pageTitle += toState.title;
- $rootScope.pageTitle += ' \u2014 ';
- }
-
- $rootScope.pageTitle += AppSettings.appTitle;
- });
-
-}
-
-export default OnRun;
\ No newline at end of file
diff --git a/app/js/services/example.js b/app/js/services/example.js
deleted file mode 100644
index e388a3c..0000000
--- a/app/js/services/example.js
+++ /dev/null
@@ -1,25 +0,0 @@
-'use strict';
-
-function ExampleService($http) {
- 'ngInject';
-
- const service = {};
-
- service.get = function() {
- return new Promise((resolve, reject) => {
- $http.get('apiPath').success((data) => {
- resolve(data);
- }).error((err, status) => {
- reject(err, status);
- });
- });
- };
-
- return service;
-
-}
-
-export default {
- name: 'ExampleService',
- fn: ExampleService
-};
\ No newline at end of file
diff --git a/app/js/services/index.js b/app/js/services/index.js
index 17f8019..0dc7068 100644
--- a/app/js/services/index.js
+++ b/app/js/services/index.js
@@ -1,16 +1,25 @@
-'use strict';
-
import angular from 'angular';
-const bulk = require('bulk-require');
+const bulk = require('bulk-require');
const servicesModule = angular.module('app.services', []);
-
const services = bulk(__dirname, ['./**/!(*index|*.spec).js']);
-Object.keys(services).forEach((key) => {
- let item = services[key];
+function declare(serviceMap) {
+ Object.keys(serviceMap).forEach((key) => {
+ let item = serviceMap[key];
+
+ if (!item) {
+ return;
+ }
+
+ if (item.fn && typeof item.fn === 'function') {
+ servicesModule.service(item.name, item.fn);
+ } else {
+ declare(item);
+ }
+ });
+}
- servicesModule.service(item.name, item.fn);
-});
+declare(services);
export default servicesModule;
diff --git a/app/js/services/localization.js b/app/js/services/localization.js
new file mode 100644
index 0000000..a595be8
--- /dev/null
+++ b/app/js/services/localization.js
@@ -0,0 +1,64 @@
+function LocalizationService($translate, AppSettings, $rootScope, tmhDynamicLocale, ToolkitService, $timeout, $filter, $state, $log) {
+ 'ngInject';
+
+ var _LOCALIZATIONS = AppSettings.localizations;
+ if (!_LOCALIZATIONS || _LOCALIZATIONS.length === 0) {
+ $log.debug('Localizations are not defined.');
+ }
+
+ var currentLocalization = $translate.proposedLanguage(); // because of async loading
+
+ var validateLocalizations = function (localization) {
+ // var params = {
+ // values: _LOCALIZATIONS,
+ // filter: {code: localization}
+ // };
+ // return ToolkitService.filter(params);
+ return $filter('filter')(_LOCALIZATIONS, {code: localization}, true);
+ };
+
+ // EVENTS
+ $rootScope.$on('$translateChangeSuccess', function (event, data) {
+ document.documentElement.setAttribute('lang', data.language);// sets "lang" attribute to html
+ tmhDynamicLocale.set(data.language.toLowerCase().replace(/_/g, '-'));// load Angular locale
+ });
+
+ $rootScope.$on('$localeChangeSuccess', function () {
+ $timeout(function(){
+ $rootScope.hideLoading = true;
+ $rootScope.pageTitle = $translate.instant($state.current.title);
+ }, 1000);
+ });
+
+ return {
+ set: function (localization) {
+
+ if (!validateLocalizations(localization)) {
+ $log.debug('Localization name "' + localization + '" is invalid.');
+ return;
+ }
+
+ if(currentLocalization !== localization){
+ $rootScope.hideLoading = false;
+ currentLocalization = localization;
+ $translate.use(localization);
+ }
+
+ return currentLocalization;
+ },
+
+ get: function () {
+ return _LOCALIZATIONS;
+ },
+
+ getCurrent: function () {
+ return currentLocalization;
+ }
+ };
+
+}
+
+export default {
+ name: 'LocalizationService',
+ fn: LocalizationService
+};
\ No newline at end of file
diff --git a/app/js/services/toolkit.js b/app/js/services/toolkit.js
new file mode 100644
index 0000000..9401974
--- /dev/null
+++ b/app/js/services/toolkit.js
@@ -0,0 +1,24 @@
+function ToolkitService($filter, $log){
+ 'ngInject';
+
+ const service = {};
+
+ service.filter = function(params) {
+ if(params.values && params.filter){
+ var found = $filter('filter')(params.values, params.filter, true);
+ if(found.length){
+ return true;
+ }
+ }else{
+ $log.debug('Required params are not defined.', params);
+ }
+ };
+
+ return service;
+
+}
+
+export default {
+ name: 'ToolkitService',
+ fn: ToolkitService
+};
\ No newline at end of file
diff --git a/app/js/settings/config.js b/app/js/settings/config.js
new file mode 100644
index 0000000..9c8c9e7
--- /dev/null
+++ b/app/js/settings/config.js
@@ -0,0 +1,66 @@
+function OnConfig($stateProvider, $locationProvider, $urlRouterProvider, $logProvider, $translateProvider, tmhDynamicLocaleProvider, AppSettings) {
+ 'ngInject';
+
+ //Routes
+ $locationProvider.html5Mode({enabled: true, requireBase: false});
+
+ $stateProvider
+ .state('home', {
+ url: '/',
+ title: 'page.home.title',
+ controller: 'homeCtrl as home',
+ templateUrl: 'home.html',
+ resolve: {
+ list_deps: function($ocLazyLoad){
+ return $ocLazyLoad.load({
+ files: ['/js/home.js']
+ });
+ }
+ }
+ })
+
+ .state('styleguide', {
+ url: '/styleguide',
+ title: 'page.styleguide.title',
+ controller: 'styleguideCtrl as styleguide',
+ templateUrl: 'styleguide.html',
+ resolve: {
+ list_deps: function($ocLazyLoad){
+ return $ocLazyLoad.load({
+ files: ['/js/styleguide.js']
+ });
+ }
+ }
+ });
+
+ $urlRouterProvider.otherwise('/');
+
+ //debug logs
+ var cache_buster = '';
+ if(AppSettings.development){
+ $logProvider.debugEnabled(true);
+ }else{
+ $logProvider.debugEnabled(false);
+ cache_buster = '.' + AppSettings.cache_buster;
+ }
+
+ //locale
+ tmhDynamicLocaleProvider.localeLocationPattern('resources/locale/{{locale}}' + cache_buster + '.js');
+
+ //translations
+ //'sanitize' strategy has issues with utf-8 encoding
+ $translateProvider.useSanitizeValueStrategy('sanitizeParameters');
+
+ $translateProvider.useStaticFilesLoader({
+ prefix: 'resources/translation/',// path to translations files
+ suffix: cache_buster + '.json'// suffix, currently- extension of the translations
+ });
+
+ $translateProvider.preferredLanguage(AppSettings.defaultLocalization); // is applied on first load
+ $translateProvider.useLocalStorage(); // saves selected language to localStorage
+
+ $translateProvider.useMissingTranslationHandlerLog();
+
+}
+
+export default OnConfig;
\ No newline at end of file
diff --git a/app/js/settings/run.js b/app/js/settings/run.js
new file mode 100644
index 0000000..34bcf9c
--- /dev/null
+++ b/app/js/settings/run.js
@@ -0,0 +1,31 @@
+function OnRun($rootScope, $translate, AppSettings, $log) {
+ 'ngInject';
+
+ //app settings
+ $rootScope.AppSettings = AppSettings;
+
+ //Print AppSettings in console
+ $log.debug('AppSettings: ', AppSettings);
+
+ //change page based on state
+ $rootScope.$on('$stateChangeSuccess', (event, toState) => {
+
+ //page config
+ $rootScope.page = {
+ state: {
+ name: toState.name
+ }
+ };
+
+ if(toState.title){
+ $rootScope.pageTitle = $translate.instant(toState.title);
+ //$rootScope.pageTitle += ' \u2014 ';
+ }
+
+ //investigate this for jQueryLite
+ //var $html = angular.element(document).find('html');
+
+ });
+}
+
+export default OnRun;
\ No newline at end of file
diff --git a/app/js/styleguide.js b/app/js/styleguide.js
new file mode 100644
index 0000000..18f8b65
--- /dev/null
+++ b/app/js/styleguide.js
@@ -0,0 +1,9 @@
+import '../modules/styleguide/styleguide_css.js';
+import '../modules/styleguide/styleguide_tpl.js';
+import ctrl from '../modules/styleguide/styleguideCtrl.js';
+
+var styleguideModule = angular.module('styleguideModule', []);
+
+styleguideModule.controller(ctrl.name, ctrl.fn);
+
+export default styleguideModule;
\ No newline at end of file
diff --git a/app/modules/home/home.html b/app/modules/home/home.html
new file mode 100644
index 0000000..24a2fc0
--- /dev/null
+++ b/app/modules/home/home.html
@@ -0,0 +1,23 @@
+
+
{{ ' foo ' | trim }}
+
{{ 'foobarfoo' | trim: 'foo' }}
+
+{{ 35 | currency}}
+
+{{ '2016-09-22' | date}}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/modules/home/home.scss b/app/modules/home/home.scss
new file mode 100644
index 0000000..3df05b3
--- /dev/null
+++ b/app/modules/home/home.scss
@@ -0,0 +1,8 @@
+@import '../../css/variables';
+
+body#page-home {
+ #pin{
+ height: 70px;
+ width: 50px;
+ }
+}
\ No newline at end of file
diff --git a/app/modules/home/homeCtrl.js b/app/modules/home/homeCtrl.js
new file mode 100644
index 0000000..4ba7da5
--- /dev/null
+++ b/app/modules/home/homeCtrl.js
@@ -0,0 +1,26 @@
+function homeCtrl($scope, $http, $log) {
+ 'ngInject';
+
+ // ViewModel
+ const vm = this;
+
+ vm.getProducts = function(){
+ $http({
+ method: 'GET',
+ url: '/api/products'
+ })
+ .then(function(response) {
+ if(typeof response.data !== 'string'){
+ vm.products = response.data;
+ }else{
+ $log.debug('Wrong format.');
+ }
+ });
+ };
+
+}
+
+export default {
+ name: 'homeCtrl',
+ fn: homeCtrl
+};
\ No newline at end of file
diff --git a/app/modules/home/homeCtrl_spec.js b/app/modules/home/homeCtrl_spec.js
new file mode 100644
index 0000000..ada01c3
--- /dev/null
+++ b/app/modules/home/homeCtrl_spec.js
@@ -0,0 +1,33 @@
+describe('Home Controller', function() {
+
+ var scope, homeCtrl, $httpBackend;
+
+ beforeEach(function(){
+ angular.mock.module('app');
+ angular.mock.module('homeModule');
+
+ angular.mock.inject(function ($controller, $rootScope, _$httpBackend_) {
+ scope = $rootScope.$new();
+
+ homeCtrl = $controller('homeCtrl', { '$scope': scope});
+
+ $httpBackend = _$httpBackend_;
+
+ var mockLanguageList = {data: 'products'};
+ $httpBackend.whenGET('/api/products').respond(200, mockLanguageList);
+ $httpBackend.whenGET('resources/translation/en_us.json').respond(200, {});
+
+ });
+ });
+
+ it('should exist', function() {
+ expect(homeCtrl).toBeDefined();
+ });
+
+ it('should getProducts', function() {
+ homeCtrl.getProducts();
+ $httpBackend.flush();
+ expect(homeCtrl.products).not.toEqual('products');
+ });
+
+});
\ No newline at end of file
diff --git a/app/modules/styleguide/styleguide.html b/app/modules/styleguide/styleguide.html
new file mode 100644
index 0000000..5071aa8
--- /dev/null
+++ b/app/modules/styleguide/styleguide.html
@@ -0,0 +1,1163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Heading 1
+
Heading 2
+
Heading 3
+
Heading 4
+
Heading 5
+
Heading 6
+
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.
+
+
+
+
+
Example body text
+
Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam id dolor id nibh ultricies vehicula.
+
This line of text is meant to be treated as fine print.
+
The following snippet of text is rendered as bold text .
+
The following snippet of text is rendered as italicized text .
+
An abbreviation of the word attribute is attr .
+
+
+
+
+
+
Emphasis classes
+
Fusce dapibus, tellus ac cursus commodo, tortor mauris nibh.
+
Nullam id dolor id nibh ultricies vehicula ut id elit.
+
Etiam porta sem malesuada magna mollis euismod.
+
Donec ullamcorper nulla non metus auctor fringilla.
+
Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
+
Maecenas sed diam eget risus varius blandit sit amet non magna.
+
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.
+ Someone famous in Source Title
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.
+ Someone famous in Source Title
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+ Column heading
+ Column heading
+ Column heading
+
+
+
+
+ 1
+ Column content
+ Column content
+ Column content
+
+
+ 2
+ Column content
+ Column content
+ Column content
+
+
+ 3
+ Column content
+ Column content
+ Column content
+
+
+ 4
+ Column content
+ Column content
+ Column content
+
+
+ 5
+ Column content
+ Column content
+ Column content
+
+
+ 6
+ Column content
+ Column content
+ Column content
+
+
+ 7
+ Column content
+ Column content
+ Column content
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Tabs
+
+
+
+
+
Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.
+
+
+
Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit.
+
+
+
Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork.
+
+
+
Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Alerts
+
+
+
×
+
Warning!
+
Best check yo self, you're not looking too good. Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et .
+
+
+
+
+
+
+
+
Labels
+
+ Default
+ Primary
+ Success
+ Warning
+ Danger
+ Info
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Basic
+
+
+
Contextual alternatives
+
+
+
Striped
+
+
+
Animated
+
+
+
Stacked
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Jumbotron
+
This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.
+
Learn more
+
+
+
+
+
+
+
+
+
+
+
+
+ 14
+ Cras justo odio
+
+
+ 2
+ Dapibus ac facilisis in
+
+
+ 1
+ Morbi leo risus
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Panel heading
+
+ Panel content
+
+
+
+
+
+
+
+
+
+
+
Panel primary
+
+
+ Panel content
+
+
+
+
+
+
Panel success
+
+
+ Panel content
+
+
+
+
+
+
Panel warning
+
+
+ Panel content
+
+
+
+
+
+
+
+
+
Panel danger
+
+
+ Panel content
+
+
+
+
+
+
Panel info
+
+
+ Panel content
+
+
+
+
+
+
+
+
+
+
+
+ Look, I'm in a well!
+
+
+
+
+
+
+ Look, I'm in a small well!
+
+
+
+
+
+
+ Look, I'm in a large well!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Popovers
+
+ Left
+
+ Top
+
+ Bottom
+
+ Right
+
+
Tooltips
+
+ Left
+
+ Top
+
+ Bottom
+
+ Right
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/modules/styleguide/styleguide.scss b/app/modules/styleguide/styleguide.scss
new file mode 100644
index 0000000..484b5bd
--- /dev/null
+++ b/app/modules/styleguide/styleguide.scss
@@ -0,0 +1,5 @@
+@import '../../css/variables';
+
+body#page-styleguide {
+ background-color: #eee;
+}
\ No newline at end of file
diff --git a/app/modules/styleguide/styleguideCtrl.js b/app/modules/styleguide/styleguideCtrl.js
new file mode 100644
index 0000000..fc74e75
--- /dev/null
+++ b/app/modules/styleguide/styleguideCtrl.js
@@ -0,0 +1,9 @@
+function styleguideCtrl() {
+ 'ngInject';
+
+}
+
+export default {
+ name: 'styleguideCtrl',
+ fn: styleguideCtrl
+};
\ No newline at end of file
diff --git a/app/modules/styleguide/styleguideCtrl_spec.js b/app/modules/styleguide/styleguideCtrl_spec.js
new file mode 100644
index 0000000..f34e375
--- /dev/null
+++ b/app/modules/styleguide/styleguideCtrl_spec.js
@@ -0,0 +1,21 @@
+describe('StyleGuide Controller', function() {
+
+ var scope, styleguideCtrl;
+
+ beforeEach(function(){
+ angular.mock.module('app');
+
+ angular.mock.inject(function ($controller) {
+ scope = {};
+
+ styleguideCtrl = function() {
+ return $controller('StyleGuideCtrl', { '$scope': scope});
+ };
+ });
+ });
+
+ it('should exist', function() {
+ expect(styleguideCtrl).toBeDefined();
+ });
+
+});
\ No newline at end of file
diff --git a/app/resources/locale/en-us.js b/app/resources/locale/en-us.js
new file mode 100644
index 0000000..9a9bfe8
--- /dev/null
+++ b/app/resources/locale/en-us.js
@@ -0,0 +1,128 @@
+'use strict';
+angular.module("ngLocale", [], ["$provide", function($provide) {
+var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
+function getDecimals(n) {
+ n = n + '';
+ var i = n.indexOf('.');
+ return (i == -1) ? 0 : n.length - i - 1;
+}
+
+function getVF(n, opt_precision) {
+ var v = opt_precision;
+
+ if (undefined === v) {
+ v = Math.min(getDecimals(n), 3);
+ }
+
+ var base = Math.pow(10, v);
+ var f = ((n * base) | 0) % base;
+ return {v: v, f: f};
+}
+
+$provide.value("$locale", {
+ "DATETIME_FORMATS": {
+ "AMPMS": [
+ "AM",
+ "PM"
+ ],
+ "DAY": [
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+ ],
+ "ERANAMES": [
+ "Before Christ",
+ "Anno Domini"
+ ],
+ "ERAS": [
+ "BC",
+ "AD"
+ ],
+ "FIRSTDAYOFWEEK": 6,
+ "MONTH": [
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December"
+ ],
+ "SHORTDAY": [
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat"
+ ],
+ "SHORTMONTH": [
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ ],
+ "WEEKENDRANGE": [
+ 5,
+ 6
+ ],
+ "fullDate": "EEEE, MMMM d, y",
+ "longDate": "MMMM d, y",
+ "medium": "MMM d, y h:mm:ss a",
+ "mediumDate": "MMM d, y",
+ "mediumTime": "h:mm:ss a",
+ "short": "M/d/yy h:mm a",
+ "shortDate": "M/d/yy",
+ "shortTime": "h:mm a"
+ },
+ "NUMBER_FORMATS": {
+ "CURRENCY_SYM": "$",
+ "DECIMAL_SEP": ".",
+ "GROUP_SEP": ",",
+ "PATTERNS": [
+ {
+ "gSize": 3,
+ "lgSize": 3,
+ "maxFrac": 3,
+ "minFrac": 0,
+ "minInt": 1,
+ "negPre": "-",
+ "negSuf": "",
+ "posPre": "",
+ "posSuf": ""
+ },
+ {
+ "gSize": 3,
+ "lgSize": 3,
+ "maxFrac": 2,
+ "minFrac": 2,
+ "minInt": 1,
+ "negPre": "-\u00a4",
+ "negSuf": "",
+ "posPre": "\u00a4",
+ "posSuf": ""
+ }
+ ]
+ },
+ "id": "en-us",
+ "pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
+});
+}]);
diff --git a/app/resources/locale/es-es.js b/app/resources/locale/es-es.js
new file mode 100644
index 0000000..9d0eb65
--- /dev/null
+++ b/app/resources/locale/es-es.js
@@ -0,0 +1,110 @@
+'use strict';
+angular.module("ngLocale", [], ["$provide", function($provide) {
+var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
+$provide.value("$locale", {
+ "DATETIME_FORMATS": {
+ "AMPMS": [
+ "a. m.",
+ "p. m."
+ ],
+ "DAY": [
+ "domingo",
+ "lunes",
+ "martes",
+ "mi\u00e9rcoles",
+ "jueves",
+ "viernes",
+ "s\u00e1bado"
+ ],
+ "ERANAMES": [
+ "antes de Cristo",
+ "despu\u00e9s de Cristo"
+ ],
+ "ERAS": [
+ "a. C.",
+ "d. C."
+ ],
+ "FIRSTDAYOFWEEK": 0,
+ "MONTH": [
+ "enero",
+ "febrero",
+ "marzo",
+ "abril",
+ "mayo",
+ "junio",
+ "julio",
+ "agosto",
+ "septiembre",
+ "octubre",
+ "noviembre",
+ "diciembre"
+ ],
+ "SHORTDAY": [
+ "dom.",
+ "lun.",
+ "mar.",
+ "mi\u00e9.",
+ "jue.",
+ "vie.",
+ "s\u00e1b."
+ ],
+ "SHORTMONTH": [
+ "ene.",
+ "feb.",
+ "mar.",
+ "abr.",
+ "may.",
+ "jun.",
+ "jul.",
+ "ago.",
+ "sept.",
+ "oct.",
+ "nov.",
+ "dic."
+ ],
+ "WEEKENDRANGE": [
+ 5,
+ 6
+ ],
+ "fullDate": "EEEE, d 'de' MMMM 'de' y",
+ "longDate": "d 'de' MMMM 'de' y",
+ "medium": "d MMM y H:mm:ss",
+ "mediumDate": "d MMM y",
+ "mediumTime": "H:mm:ss",
+ "short": "d/M/yy H:mm",
+ "shortDate": "d/M/yy",
+ "shortTime": "H:mm"
+ },
+ "NUMBER_FORMATS": {
+ "CURRENCY_SYM": "\u20ac",
+ "DECIMAL_SEP": ",",
+ "GROUP_SEP": ".",
+ "PATTERNS": [
+ {
+ "gSize": 3,
+ "lgSize": 3,
+ "maxFrac": 3,
+ "minFrac": 0,
+ "minInt": 1,
+ "negPre": "-",
+ "negSuf": "",
+ "posPre": "",
+ "posSuf": ""
+ },
+ {
+ "gSize": 3,
+ "lgSize": 3,
+ "maxFrac": 2,
+ "minFrac": 2,
+ "minInt": 1,
+ "negPre": "-",
+ "negSuf": "\u00a0\u00a4",
+ "posPre": "",
+ "posSuf": "\u00a0\u00a4"
+ }
+ ]
+ },
+ "id": "es-es",
+ "pluralCat": function(n, opt_precision) { if (n == 1) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
+});
+}]);
diff --git a/app/resources/mocks/products.json b/app/resources/mocks/products.json
new file mode 100644
index 0000000..3a0ab0b
--- /dev/null
+++ b/app/resources/mocks/products.json
@@ -0,0 +1,22 @@
+{
+ "list": [
+ {
+ "name": "1100"
+ },
+ {
+ "name": "2100"
+ },
+ {
+ "name": "Galaxy S"
+ },
+ {
+ "name": "Galaxy S6"
+ },
+ {
+ "name": "XPeria Z"
+ },
+ {
+ "name": "Optimus"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/resources/translation/en_us.json b/app/resources/translation/en_us.json
new file mode 100644
index 0000000..87093f1
--- /dev/null
+++ b/app/resources/translation/en_us.json
@@ -0,0 +1,12 @@
+{
+ "views.main.Splendid!": "Splendid!",
+ "directives.language-select.Language": "Language",
+ "page": {
+ "home": {
+ "title": "Home"
+ },
+ "styleguide": {
+ "title": "Style Guide"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/resources/translation/es_es.json b/app/resources/translation/es_es.json
new file mode 100644
index 0000000..720b31f
--- /dev/null
+++ b/app/resources/translation/es_es.json
@@ -0,0 +1,12 @@
+{
+ "views.main.Splendid!": "Ben!",
+ "directives.language-select.Language": "Idioma",
+ "page": {
+ "home": {
+ "title": "Inicio"
+ },
+ "styleguide": {
+ "title": "GuÃa de estilo"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/styles/_typography.scss b/app/styles/_typography.scss
deleted file mode 100644
index 8cc7a16..0000000
--- a/app/styles/_typography.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-p {
- margin-bottom: 1em;
-}
-
-.heading {
- margin-bottom: 0.618em;
-
- &.-large {
- font-size: $font-size--lg;
- font-weight: bold;
- line-height: $half-space * 3 / 2;
- }
-
- &.-medium {
- font-size: $font-size--md;
- font-weight: normal;
- line-height: $half-space;
- }
-
- &.-small {
- font-size: $font-size--sm;
- font-weight: bold;
- line-height: $half-space * 2 / 3;
- }
-
- &.-smallest {
- font-size: $font-size--xs;
- font-weight: bold;
- }
-}
-
-h1 {
- @extend .heading.-large;
-}
-
-h2 {
- @extend .heading.-medium;
-}
-
-h3 {
- @extend .heading.-small;
-}
\ No newline at end of file
diff --git a/app/styles/_vars.scss b/app/styles/_vars.scss
deleted file mode 100644
index 486ca82..0000000
--- a/app/styles/_vars.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-// colors
-// #26283B //Ebony Clay
-// #C41E3A //Cardinal
-// #FF4D00 //Vermilion
-// #FEA904 //Yellow Sea
-// #1AB385 //Mountain Meadow
-// #F4F4F4 //Wild Sand
-$font-color--dark: #333;
-$font-color--light: #fff;
-$background--light: #eee;
-$background--dark: #222;
-$blue: #1f8de2;
-$green: #1fe27b;
-$red: #e21f3f;
-
-// spacing
-$full-space: 40px;
-$half-space: 20px;
-
-// font sizing
-$font-size--xs: 10px;
-$font-size--sm: 12px;
-$font-size--md: 16px;
-$font-size--lg: 24px;
-$font-size--xl: 32px;
\ No newline at end of file
diff --git a/app/styles/main.scss b/app/styles/main.scss
deleted file mode 100644
index 4a2d9f9..0000000
--- a/app/styles/main.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-@import 'vars';
-@import 'typography';
-
-body {
- font-family: Helvetica, sans-serif;
- color: $font-color--dark;
- background-color: $background--light;
- padding: $half-space;
-}
\ No newline at end of file
diff --git a/app/templates/directives/app-loading.html b/app/templates/directives/app-loading.html
new file mode 100644
index 0000000..04aa0dd
--- /dev/null
+++ b/app/templates/directives/app-loading.html
@@ -0,0 +1,4 @@
+
diff --git a/app/templates/directives/sprite.html b/app/templates/directives/sprite.html
new file mode 100644
index 0000000..67910a1
--- /dev/null
+++ b/app/templates/directives/sprite.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/templates/directives/translate-language.html b/app/templates/directives/translate-language.html
new file mode 100644
index 0000000..163dff4
--- /dev/null
+++ b/app/templates/directives/translate-language.html
@@ -0,0 +1,4 @@
+
+ {{"directives.language-select.Language" | translate}} :
+
+
diff --git a/app/templates/partials/footer.html b/app/templates/partials/footer.html
new file mode 100644
index 0000000..510ed84
--- /dev/null
+++ b/app/templates/partials/footer.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/templates/partials/header.html b/app/templates/partials/header.html
new file mode 100644
index 0000000..e25cc58
--- /dev/null
+++ b/app/templates/partials/header.html
@@ -0,0 +1,38 @@
+
+
+
\ No newline at end of file
diff --git a/app/templates/partials/sprite.html b/app/templates/partials/sprite.html
new file mode 100644
index 0000000..85625be
--- /dev/null
+++ b/app/templates/partials/sprite.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/views/directives/example.html b/app/views/directives/example.html
deleted file mode 100644
index 0a01f2f..0000000
--- a/app/views/directives/example.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
{{title}}
-
diff --git a/app/views/home.html b/app/views/home.html
deleted file mode 100644
index 4ec1d24..0000000
--- a/app/views/home.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{{ home.title | ExampleFilter }}
-
-Here is a fancy number served up courtesy of Angular: {{ home.number }}
-
-
-
-
diff --git a/gulp/config.js b/gulp/config.js
index 01ef7ec..d510eb1 100644
--- a/gulp/config.js
+++ b/gulp/config.js
@@ -1,78 +1,190 @@
-'use strict';
-
export default {
- browserPort: 3000,
- UIPort: 3001,
-
- sourceDir: './app/',
- buildDir: './build/',
-
- styles: {
- src: 'app/styles/**/*.scss',
- dest: 'build/css',
- prodSourcemap: false,
- sassIncludePaths: []
- },
-
- scripts: {
- src: 'app/js/**/*.js',
- dest: 'build/js'
- },
-
- images: {
- src: 'app/images/**/*',
- dest: 'build/images'
- },
-
- fonts: {
- src: ['app/fonts/**/*'],
- dest: 'build/fonts'
- },
-
- assetExtensions: [
- 'js',
- 'css',
- 'png',
- 'jpe?g',
- 'gif',
- 'svg',
- 'eot',
- 'otf',
- 'ttc',
- 'ttf',
- 'woff2?'
- ],
-
- views: {
- index: 'app/index.html',
- src: 'app/views/**/*.html',
- dest: 'app/js'
- },
-
- gzip: {
- src: 'build/**/*.{html,xml,json,css,js,js.map,css.map}',
- dest: 'build/',
- options: {}
- },
-
- browserify: {
- bundleName: 'main.js',
- prodSourcemap: false
- },
-
- test: {
- karma: 'test/karma.conf.js',
- protractor: 'test/protractor.conf.js'
- },
-
- init: function() {
- this.views.watch = [
- this.views.index,
- this.views.src
- ];
-
- return this;
- }
+ app:{
+ name: 'Boilerplate'
+ },
+
+ browserPort: 3000,
+ UIPort: 3001,
+
+ sourceDir: './app/',
+ buildDir: './build/',
+ tempDir: './temp/',
+
+ environment: {
+ development: {
+ development: true,
+ mocks: false,
+ apiUrl: '/api/v1'
+ },
+ production: {
+ development: false,
+ mocks: false,
+ apiUrl: '/api/v2'
+ }
+ },
+
+ constants: {
+ 'cache_buster': '',
+ 'localizations': [
+ {
+ code: 'es_es',
+ name: 'Español'
+ },
+ {
+ code: 'en_us',
+ name: 'English',
+ locale: '/resources/locale/en-us.js'
+ }
+ ],
+ 'defaultLocalization': 'en_us'
+ },
+
+ favicons: {
+ src: 'app/images/favicon/favicon.svg',
+ dest: 'build/images/favicons/',
+ path: '/images/favicons/',
+ data: 'faviconData.json'
+ },
+
+ styles: {
+ dev: 'app/css/',
+ src: 'app/css/**/*.scss',
+ dest: 'build/css',
+ prodSourcemap: false,
+ autoprefixer: ['last 5 version', '> 0.1%', 'ie 9'],
+ sassIncludePaths: []
+ },
+
+ locale: {
+ src: 'app/resources/locale/*.js',
+ dest: 'build/resources/locale'
+ },
+
+ translation: {
+ src: 'app/resources/translation/*.json',
+ dest: 'build/resources/translation'
+ },
+
+ mocks: {
+ src: 'app/resources/mocks/*.json',
+ dest: 'build/resources/mocks'
+ },
+
+ scripts: {
+ dev: 'app/js/',
+ index: 'app.js',
+ src: 'app/js/**/*.js',
+ dest: 'build/js',
+ files: '**/*.js',
+ jshint: ['app/js/**/*.js', 'app/modules/**/*.js', '!app/modules/**/*_tpl.js', '!app/modules/**/*_spec.js', '!app/modules/**/*_css.js', '!app/js/**/*_tpl.js']
+ },
+
+ ngconstants: {
+ tpl: 'gulp/util/constant.tpl.ejs',
+ name: 'constants.js',
+ dest: 'app/js/settings'
+ },
+
+ iconsfont:{
+ name: 'icons',
+ template: 'gulp/util/iconsfont.css',
+ src: 'app/images/icons/**/*.svg',
+ dest: 'app/fonts'
+ },
+
+ sprite: {
+ src: 'app/images/sprite/**/*.svg',
+ file: 'sprite.svg',
+ path: '../images/',
+ template: 'app/templates/partials/sprite.html',
+ templateDir: 'app/templates/partials/'
+ },
+
+ images: {
+ dir: 'app/images/',
+ src: ['app/images/**/*.png', 'app/images/**/*.jpg', 'app/images/**/*.gif', 'app/images/**/*.svg', '!app/images/sprite/*', '!app/images/icons/*', '!app/images/favicon/*'],
+ dest: 'build/images'
+ },
+
+ fonts: {
+ icons: 'app/fonts/icons*',
+ src: ['app/fonts/*', '!app/fonts/icons*'],
+ dest: 'build/fonts'
+ },
+
+ assetExtensions: [
+ 'js',
+ 'json',
+ 'css',
+ 'png',
+ 'jpe?g',
+ 'gif',
+ 'svg',
+ 'eot',
+ 'otf',
+ 'ttc',
+ 'ttf',
+ 'woff',
+ 'woff2?'
+ ],
+
+ templates: {
+ index: 'app/index.html',
+ src: 'app/templates/**/*.htm*',
+ dest: 'app/js/'
+ },
+
+ modules: {
+ src: 'app/modules/',
+ styles: 'app/modules/**/*.scss',
+ templates: 'app/modules/**/*.htm*',
+ scripts: 'app/modules/**/*.js',
+ tests: '!app/modules/**/*_spec.js'
+ },
+
+ gzip: {
+ src: 'build/**/*.{html,xml,json,css,js,js.map,css.map}',
+ dest: 'build/',
+ options: {}
+ },
+
+ info: {
+ src: 'build/**/*.*'
+ },
+
+ babel: {
+ src: ['app/**/*.js', '!app/resources/**/*.js', '!app/**/*_css.js', '!app/**/*_tpl.js', '!app/**/*_spec.js', '!app/**/index.js'],
+ dest: 'temp_babel'
+ },
+
+ reports: {
+ analysis: {
+ dest: 'reports/analysis',
+ index: 'reports/analysis/index.html'
+ },
+ coverage: {
+ index: 'reports/coverage/*/index.html'
+ }
+ },
+
+ browserify: {
+ bundleName: 'app.js',
+ prodSourcemap: false
+ },
+
+ test: {
+ karma: 'test/karma.conf.js',
+ protractor: 'test/protractor.conf.js'
+ },
+
+ init: function() {
+ this.templates.watch = [
+ this.templates.index,
+ this.templates.src
+ ];
+ return this;
+ }
+
}.init();
diff --git a/gulp/index.js b/gulp/index.js
index 14b4c16..5c7a9fe 100644
--- a/gulp/index.js
+++ b/gulp/index.js
@@ -1,10 +1,21 @@
-'use strict';
-
-import fs from 'fs';
-import onlyScripts from './util/scriptFilter';
+import fs from 'fs';
+import gulp from 'gulp';
+import onlyScripts from './util/scriptFilter';
+import CacheBuster from 'gulp-cachebust';
const tasks = fs.readdirSync('./gulp/tasks/').filter(onlyScripts);
+global.cachebust = new CacheBuster();
+
+// Ensure process ends after all Gulp tasks are finished
+gulp.on('stop', function () {
+ if ( !global.isWatching ) {
+ process.nextTick(function () {
+ process.exit(0);
+ });
+ }
+});
+
tasks.forEach((task) => {
- require('./tasks/' + task);
+ require('./tasks/' + task);
});
\ No newline at end of file
diff --git a/gulp/tasks/analyzeJshint.js b/gulp/tasks/analyzeJshint.js
new file mode 100644
index 0000000..bd5bcbf
--- /dev/null
+++ b/gulp/tasks/analyzeJshint.js
@@ -0,0 +1,9 @@
+import config from '../config';
+import gulp from 'gulp';
+import jshint from 'gulp-jshint';
+
+gulp.task('analyze:Jshint', function() {
+ return gulp.src(config.scripts.jshint)
+ .pipe( jshint() )
+ .pipe( jshint.reporter('jshint-stylish') );
+});
\ No newline at end of file
diff --git a/gulp/tasks/analyzePlato.js b/gulp/tasks/analyzePlato.js
new file mode 100644
index 0000000..5d0fcb1
--- /dev/null
+++ b/gulp/tasks/analyzePlato.js
@@ -0,0 +1,29 @@
+import config from '../config';
+import gulp from 'gulp';
+import plato from 'gulp-plato';
+import babel from 'gulp-babel';
+
+gulp.task('analyze:Plato', function() {
+
+ return gulp.src(
+ config.babel.src
+ )
+ .pipe(
+ babel(
+ {
+ presets: ['es2015']
+ }
+ )
+ )
+ .pipe(
+ gulp.dest(
+ config.babel.dest
+ )
+ )
+ .pipe(
+ plato(
+ config.reports.analysis.dest
+ )
+ );
+
+});
\ No newline at end of file
diff --git a/gulp/tasks/browserSync.js b/gulp/tasks/browserSync.js
deleted file mode 100644
index e908b06..0000000
--- a/gulp/tasks/browserSync.js
+++ /dev/null
@@ -1,35 +0,0 @@
-'use strict';
-
-import config from '../config';
-import url from 'url';
-import browserSync from 'browser-sync';
-import gulp from 'gulp';
-
-gulp.task('browserSync', function() {
-
- const DEFAULT_FILE = 'index.html';
- const ASSET_EXTENSION_REGEX = new RegExp(`\\b(?!\\?)\\.(${config.assetExtensions.join('|')})\\b(?!\\.)`, 'i');
-
- browserSync.init({
- server: {
- baseDir: config.buildDir,
- middleware: function(req, res, next) {
- let fileHref = url.parse(req.url).href;
-
- if ( !ASSET_EXTENSION_REGEX.test(fileHref) ) {
- req.url = '/' + DEFAULT_FILE;
- }
-
- return next();
- }
- },
- port: config.browserPort,
- ui: {
- port: config.UIPort
- },
- ghostMode: {
- links: false
- }
- });
-
-});
diff --git a/gulp/tasks/browserify.js b/gulp/tasks/browserify.js
index 8fcb6d2..c25f60d 100644
--- a/gulp/tasks/browserify.js
+++ b/gulp/tasks/browserify.js
@@ -1,80 +1,83 @@
-'use strict';
+import config from '../config';
+import gulp from 'gulp';
+import gulpif from 'gulp-if';
+import gutil from 'gulp-util';
+import source from 'vinyl-source-stream';
+import sourcemaps from 'gulp-sourcemaps';
+import buffer from 'vinyl-buffer';
+import streamify from 'gulp-streamify';
+import watchify from 'watchify';
+import browserify from 'browserify';
+import babelify from 'babelify';
+import uglify from 'gulp-uglify';
+import handleErrors from '../util/handleErrors';
+import setEnvironment from '../util/setEnvironment';
+import browserSync from 'browser-sync';
+import ngAnnotate from 'browserify-ngannotate';
+import rename from 'gulp-rename';
+import folders from 'gulp-folders';
-import config from '../config';
-import gulp from 'gulp';
-import gulpif from 'gulp-if';
-import gutil from 'gulp-util';
-import source from 'vinyl-source-stream';
-import sourcemaps from 'gulp-sourcemaps';
-import buffer from 'vinyl-buffer';
-import streamify from 'gulp-streamify';
-import watchify from 'watchify';
-import browserify from 'browserify';
-import babelify from 'babelify';
-import uglify from 'gulp-uglify';
-import handleErrors from '../util/handleErrors';
-import browserSync from 'browser-sync';
-import debowerify from 'debowerify';
-import ngAnnotate from 'browserify-ngannotate';
+
+setEnvironment();
function createSourcemap() {
- return !global.isProd || config.browserify.prodSourcemap;
+ return development() || config.browserify.prodSourcemap;
}
-// Based on: http://blog.avisi.nl/2014/04/25/how-to-keep-a-fast-build-with-browserify-and-reactjs/
function buildScript(file) {
-
- let bundler = browserify({
- entries: [config.sourceDir + 'js/' + file],
- debug: createSourcemap(),
- cache: {},
- packageCache: {},
- fullPaths: !global.isProd
- });
-
- if ( !global.isProd ) {
- bundler = watchify(bundler);
-
- bundler.on('update', function() {
- rebundle();
- gutil.log('Rebundle...');
+ let bundler = browserify({
+ entries: [config.sourceDir + 'js/' + file],
+ debug: createSourcemap(),
+ cache: {},
+ packageCache: {},
+ fullPaths: development()
});
- }
- const transforms = [
- { 'name':babelify, 'options': {}},
- { 'name':debowerify, 'options': {}},
- { 'name':ngAnnotate, 'options': {}},
- { 'name':'brfs', 'options': {}},
- { 'name':'bulkify', 'options': {}}
- ];
+ if (development()) {
+ bundler = watchify(bundler);
+ bundler.on('update', function() {
+ rebundle();
+ gutil.log('Rebundle...');
+ });
+ }
- transforms.forEach(function(transform) {
- bundler.transform(transform.name, transform.options);
- });
+ const transforms = [
+ { 'name':babelify, 'options': {}},
+ { 'name':ngAnnotate, 'options': {}},
+ { 'name':'brfs', 'options': {}},
+ { 'name':'bulkify', 'options': {}}
+ ];
- function rebundle() {
- const stream = bundler.bundle();
- const sourceMapLocation = global.isProd ? './' : '';
+ transforms.forEach(function(transform) {
+ bundler.transform(transform.name, transform.options);
+ });
- return stream.on('error', handleErrors)
- .pipe(source(file))
- .pipe(gulpif(createSourcemap(), buffer()))
- .pipe(gulpif(createSourcemap(), sourcemaps.init({ loadMaps: true })))
- .pipe(gulpif(global.isProd, streamify(uglify({
- compress: { drop_console: true }
- }))))
- .pipe(gulpif(createSourcemap(), sourcemaps.write(sourceMapLocation)))
- .pipe(gulp.dest(config.scripts.dest))
- .pipe(browserSync.stream());
- }
+ function rebundle() {
+ const stream = bundler.bundle();
+ const sourceMapLocation = production() ? './' : '';
- return rebundle();
+ return stream.on('error', handleErrors)
+ .pipe( source(file) )
+ .pipe( gulpif(createSourcemap(), buffer()) )
+ .pipe( gulpif(createSourcemap(), sourcemaps.init({ loadMaps: true })) )
+ .pipe( production(streamify(uglify({
+ compress: { drop_console: true }
+ }))) )
+ .pipe( gulpif(createSourcemap(), sourcemaps.write(sourceMapLocation)) )
+ .pipe( rename({dirname: ''}) )
+ .pipe( production(global.cachebust.resources()) )
+ .pipe( gulp.dest(config.scripts.dest) )
+ .pipe( browserSync.stream() );
+ }
-}
+ return rebundle();
-gulp.task('browserify', function() {
+}
- return buildScript('main.js');
+gulp.task('browserify:Modules', folders(config.modules.src, function(module){
+ return buildScript(module + '.js');
+}));
-});
+gulp.task('browserify:Main', function() {
+ return buildScript('app.js');
+});
\ No newline at end of file
diff --git a/gulp/tasks/clean.js b/gulp/tasks/clean.js
deleted file mode 100644
index 0b374ee..0000000
--- a/gulp/tasks/clean.js
+++ /dev/null
@@ -1,11 +0,0 @@
-'use strict';
-
-import config from '../config';
-import gulp from 'gulp';
-import del from 'del';
-
-gulp.task('clean', function() {
-
- return del([config.buildDir]);
-
-});
diff --git a/gulp/tasks/combineSvg.js b/gulp/tasks/combineSvg.js
new file mode 100644
index 0000000..6485d9a
--- /dev/null
+++ b/gulp/tasks/combineSvg.js
@@ -0,0 +1,21 @@
+import config from '../config';
+import gulp from 'gulp';
+import svgstore from 'gulp-svgstore';
+import inject from 'gulp-inject';
+import rename from 'gulp-rename';
+import svgmin from 'gulp-svgmin';
+
+gulp.task('combine:Svg', function () {
+ var svgs = gulp
+ .src(config.sprite.src)
+ .pipe(svgstore({ inlineSvg: true }));
+
+ function fileContents (filePath, file) {
+ return file.contents.toString();
+ }
+
+ return gulp
+ .src(config.sprite.template)
+ .pipe(inject(svgs, { transform: fileContents }))
+ .pipe(gulp.dest(config.sprite.templateDir));
+});
\ No newline at end of file
diff --git a/gulp/tasks/compressFile.js b/gulp/tasks/compressFile.js
new file mode 100644
index 0000000..248723b
--- /dev/null
+++ b/gulp/tasks/compressFile.js
@@ -0,0 +1,12 @@
+import config from '../config';
+import gulp from 'gulp';
+import gzip from 'gulp-gzip';
+
+gulp.task('compress:File', function() {
+
+ // desactivate gzip options
+ // return gulp.src(config.gzip.src)
+ // .pipe(gzip(config.gzip.options))
+ // .pipe(gulp.dest(config.gzip.dest));
+
+});
diff --git a/gulp/tasks/copyFonts.js b/gulp/tasks/copyFonts.js
new file mode 100644
index 0000000..97d88ad
--- /dev/null
+++ b/gulp/tasks/copyFonts.js
@@ -0,0 +1,13 @@
+import config from '../config';
+import changed from 'gulp-changed';
+import gulp from 'gulp';
+import browserSync from 'browser-sync';
+
+gulp.task('copy:Fonts', function() {
+
+ return gulp.src( config.fonts.src )
+ .pipe( changed(config.fonts.dest) ) // Ignore unchanged files
+ .pipe( production(global.cachebust.resources()) )
+ .pipe( gulp.dest(config.fonts.dest) )
+ .pipe( browserSync.stream() );
+});
\ No newline at end of file
diff --git a/gulp/tasks/copyImages.js b/gulp/tasks/copyImages.js
new file mode 100644
index 0000000..992eb0f
--- /dev/null
+++ b/gulp/tasks/copyImages.js
@@ -0,0 +1,19 @@
+import config from '../config';
+import changed from 'gulp-changed';
+import gulp from 'gulp';
+import setEnvironment from '../util/setEnvironment';
+import imagemin from 'gulp-imagemin';
+import browserSync from 'browser-sync';
+
+setEnvironment();
+
+gulp.task('copy:Images', function() {
+
+ return gulp.src(config.images.src)
+ .pipe( changed(config.images.dest) ) // Ignore unchanged files
+ .pipe( production(imagemin()) )
+ .pipe( production(global.cachebust.resources()) )
+ .pipe( gulp.dest(config.images.dest) )
+ .pipe( browserSync.stream() );
+
+});
diff --git a/gulp/tasks/copyLocales.js b/gulp/tasks/copyLocales.js
new file mode 100644
index 0000000..8e1a908
--- /dev/null
+++ b/gulp/tasks/copyLocales.js
@@ -0,0 +1,26 @@
+import config from '../config';
+import gulp from 'gulp';
+import browserSync from 'browser-sync';
+import setEnvironment from '../util/setEnvironment';
+import rename from 'gulp-rename';
+import streamify from 'gulp-streamify';
+import uglify from 'gulp-uglify';
+
+setEnvironment();
+
+// Views task
+gulp.task('copy:Locales', function() {
+
+ var constants = config.constants;
+
+ return gulp.src(config.locale.src)
+ .pipe( production(streamify(uglify({
+ compress: { drop_console: true }
+ }))) )
+ .pipe( production(rename(function (path) {
+ path.basename += '.' + constants.cache_buster;
+ path.extname = '.js'
+ })) )
+ .pipe( gulp.dest(config.locale.dest) )
+ .pipe( browserSync.stream() );
+});
diff --git a/gulp/tasks/copyMainIndex.js b/gulp/tasks/copyMainIndex.js
new file mode 100644
index 0000000..656bb24
--- /dev/null
+++ b/gulp/tasks/copyMainIndex.js
@@ -0,0 +1,19 @@
+import config from '../config';
+import gulp from 'gulp';
+import browserSync from 'browser-sync';
+import htmlhint from 'gulp-htmlhint';
+import htmlmin from 'gulp-htmlmin';
+import realFavicon from 'gulp-real-favicon';
+import fs from 'fs';
+
+//Main app html file
+gulp.task('copy:MainIndex', function() {
+ return gulp.src(config.templates.index)
+ //inject Favicons
+ .pipe(realFavicon.injectFaviconMarkups(JSON.parse(fs.readFileSync(config.favicons.data)).favicon.html_code))
+ .pipe( htmlhint('.htmlhintrc') )
+ .pipe( htmlhint.reporter() )
+ .pipe( production(global.cachebust.references()) )
+ .pipe( production(htmlmin({collapseWhitespace: true})) )
+ .pipe( gulp.dest(config.buildDir) );
+});
\ No newline at end of file
diff --git a/gulp/tasks/copyMocks.js b/gulp/tasks/copyMocks.js
new file mode 100644
index 0000000..e59b245
--- /dev/null
+++ b/gulp/tasks/copyMocks.js
@@ -0,0 +1,16 @@
+import config from '../config';
+import gulp from 'gulp';
+import browserSync from 'browser-sync';
+import gulpif from 'gulp-if';
+import jsonlint from 'gulp-jsonlint';
+
+// Views task
+gulp.task('copy:Mocks', function() {
+
+ return gulp.src(config.mocks.src)
+ .pipe(jsonlint())
+ .pipe(jsonlint.reporter())
+ .pipe(gulp.dest(config.mocks.dest))
+ .pipe(browserSync.stream());
+
+});
diff --git a/gulp/tasks/copyTranslations.js b/gulp/tasks/copyTranslations.js
new file mode 100644
index 0000000..26246dc
--- /dev/null
+++ b/gulp/tasks/copyTranslations.js
@@ -0,0 +1,26 @@
+import config from '../config';
+import gulp from 'gulp';
+import browserSync from 'browser-sync';
+import setEnvironment from '../util/setEnvironment';
+import rename from 'gulp-rename';
+import jsonlint from 'gulp-jsonlint';
+import jsonminify from 'gulp-jsonminify';
+
+setEnvironment();
+
+gulp.task('copy:Translations', function() {
+
+ var constants = config.constants;
+
+ return gulp.src(config.translation.src)
+ .pipe( jsonlint() )
+ .pipe( jsonlint.reporter() )
+ .pipe( production(jsonminify()) )
+ .pipe( production(rename(function (path) {
+ path.basename += '.' + constants.cache_buster;
+ path.extname = '.json'
+ })) )
+ .pipe( gulp.dest(config.translation.dest) )
+ .pipe( browserSync.stream() );
+
+});
diff --git a/gulp/tasks/default.js b/gulp/tasks/default.js
new file mode 100644
index 0000000..1066de3
--- /dev/null
+++ b/gulp/tasks/default.js
@@ -0,0 +1,7 @@
+import config from '../config';
+import gulp from 'gulp';
+import taskListing from 'gulp-task-listing';
+
+gulp.task('show:Tasks', taskListing);
+
+gulp.task('default', ['show:Tasks']);
\ No newline at end of file
diff --git a/gulp/tasks/deleteBuildFiles.js b/gulp/tasks/deleteBuildFiles.js
new file mode 100644
index 0000000..f3cf803
--- /dev/null
+++ b/gulp/tasks/deleteBuildFiles.js
@@ -0,0 +1,8 @@
+import config from '../config';
+import gulp from 'gulp';
+import del from 'del';
+
+gulp.task('delete:Files', function() {
+
+ return del([config.buildDir, config.modules.src + '*_tpl.js', config.modules.src + '*_css.js', config.scripts.dev + '*_tpl.js']);
+});
diff --git a/gulp/tasks/deploy.js b/gulp/tasks/deploy.js
index 3b00367..4885b6f 100644
--- a/gulp/tasks/deploy.js
+++ b/gulp/tasks/deploy.js
@@ -1,9 +1,5 @@
-'use strict';
-
import gulp from 'gulp';
gulp.task('deploy', ['prod'], function() {
-
- // Any deployment logic should go here
-
+ console.log('Any deployment logic should go here');
});
\ No newline at end of file
diff --git a/gulp/tasks/dev.js b/gulp/tasks/dev.js
new file mode 100644
index 0000000..ac7d59f
--- /dev/null
+++ b/gulp/tasks/dev.js
@@ -0,0 +1,47 @@
+import gulp from 'gulp';
+import runSequence from 'run-sequence';
+import environments from 'gulp-environments';
+
+gulp.task('dev', ['delete:Files'], function(cb) {
+
+ cb = cb || function() {};
+
+ global.production = environments.production;
+ global.development = environments.development;
+
+ environments.current(development);
+
+ runSequence(
+ [
+ 'combine:Svg',
+ 'generate:IconFont',
+ 'generate:Favicons'
+ ],
+ [
+ 'copy:Images',
+ 'copy:Fonts',
+ 'inject:IconFont'
+ ],
+ [
+ 'generate:ConstantModule',
+ 'generate:MainStyles',
+ 'generate:ModuleStyles',
+ 'generate:ModuleTemplates',
+ 'generate:MainTemplates'
+ ],
+ [
+ 'browserify:Modules',
+ 'browserify:Main',
+ 'copy:Locales',
+ 'copy:Translations'
+ ],
+ [
+ 'copy:MainIndex'
+ ],
+ [
+ 'watch:Files'
+ ],
+ cb
+ );
+
+});
\ No newline at end of file
diff --git a/gulp/tasks/development.js b/gulp/tasks/development.js
deleted file mode 100644
index a415cb5..0000000
--- a/gulp/tasks/development.js
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict';
-
-import gulp from 'gulp';
-import runSequence from 'run-sequence';
-
-gulp.task('dev', ['clean'], function(cb) {
-
- global.isProd = false;
-
- runSequence(['styles', 'images', 'fonts', 'views', 'browserify'], 'watch', cb);
-
-});
\ No newline at end of file
diff --git a/gulp/tasks/fonts.js b/gulp/tasks/fonts.js
deleted file mode 100644
index 7dcc380..0000000
--- a/gulp/tasks/fonts.js
+++ /dev/null
@@ -1,15 +0,0 @@
-'use strict';
-
-import config from '../config';
-import changed from 'gulp-changed';
-import gulp from 'gulp';
-import browserSync from 'browser-sync';
-
-gulp.task('fonts', function() {
-
- return gulp.src(config.fonts.src)
- .pipe(changed(config.fonts.dest)) // Ignore unchanged files
- .pipe(gulp.dest(config.fonts.dest))
- .pipe(browserSync.stream());
-
-});
diff --git a/gulp/tasks/generateConstantModule.js b/gulp/tasks/generateConstantModule.js
new file mode 100644
index 0000000..06c05d3
--- /dev/null
+++ b/gulp/tasks/generateConstantModule.js
@@ -0,0 +1,38 @@
+import config from '../config';
+import gulp from 'gulp';
+import ngConstant from 'gulp-ng-constant';
+import setEnvironment from '../util/setEnvironment';
+import rename from 'gulp-rename';
+import gulpif from 'gulp-if';
+import replace from 'gulp-replace';
+
+setEnvironment();
+
+gulp.task('generate:ConstantModule', function() {
+
+ if(production()){
+ var environment = 'production';
+ }else{
+ var environment = 'development';
+ }
+
+ var constants = config.constants;
+ if(production()){
+ constants.cache_buster = Math.random().toString(16).slice(2);
+ }
+
+ for (var constant in config.environment[environment]){
+ constants[constant] = config.environment[environment][constant];
+ }
+
+ return ngConstant({
+ constants: constants,
+ templatePath: config.ngconstants.tpl,
+ stream: true
+ })
+ .pipe(gulpif(global.mocks, replace('mocks: false', 'mocks: true')))
+ .pipe(gulpif(!global.mocks, replace('mocks: true', 'mocks: false')))
+ .pipe(rename(config.ngconstants.name))
+ .pipe(gulp.dest(config.ngconstants.dest));
+
+});
\ No newline at end of file
diff --git a/gulp/tasks/generateFavicons.js b/gulp/tasks/generateFavicons.js
new file mode 100644
index 0000000..898815f
--- /dev/null
+++ b/gulp/tasks/generateFavicons.js
@@ -0,0 +1,55 @@
+import config from '../config';
+import gulp from 'gulp';
+import realFavicon from 'gulp-real-favicon';
+
+var runTimestamp = Math.round(Date.now()/1000);
+
+gulp.task('generate:Favicons', function(cb) {
+ realFavicon.generateFavicon({
+ masterPicture: config.favicons.src,
+ dest: config.favicons.dest,
+ iconsPath: config.favicons.path,
+ design: {
+ ios: {
+ pictureAspect: 'backgroundAndMargin',
+ backgroundColor: '#ffffff',
+ margin: '25%',
+ appName: config.app.name
+ },
+ desktopBrowser: {},
+ windows: {
+ pictureAspect: 'noChange',
+ backgroundColor: '#00a300',
+ onConflict: 'override',
+ appName: config.app.name
+ },
+ androidChrome: {
+ pictureAspect: 'shadow',
+ themeColor: '#ffffff',
+ manifest: {
+ name: config.app.name,
+ display: 'browser',
+ orientation: 'notSet',
+ onConflict: 'override',
+ declared: true
+ }
+ },
+ safariPinnedTab: {
+ pictureAspect: 'silhouette',
+ themeColor: '#5bbad5'
+ }
+ },
+ settings: {
+ compression: 2,
+ scalingAlgorithm: 'Spline',
+ errorOnImageTooSmall: false
+ },
+ versioning: {
+ paramName: 'v',
+ paramValue: Math.round(Date.now()/1000)
+ },
+ markupFile: config.favicons.data
+ }, function() {
+ cb();
+ });
+});
diff --git a/gulp/tasks/generateIconFont.js b/gulp/tasks/generateIconFont.js
new file mode 100644
index 0000000..5e3cfe2
--- /dev/null
+++ b/gulp/tasks/generateIconFont.js
@@ -0,0 +1,34 @@
+import config from '../config';
+import changed from 'gulp-changed';
+import rename from 'gulp-rename';
+import gulp from 'gulp';
+import iconfont from 'gulp-iconfont';
+import consolidate from 'gulp-consolidate';
+import browserSync from 'browser-sync';
+
+var runTimestamp = Math.round(Date.now()/1000);
+
+gulp.task('generate:IconFont', function() {
+ return gulp.src(config.iconsfont.src)
+ .pipe( changed(config.iconsfont.dest) ) // Ignore unchanged files
+ .pipe(iconfont({
+ fontName: config.iconsfont.name,
+ normalize: true,
+ appendUnicode: true, // recommended option
+ formats: ['ttf', 'eot', 'woff'], // default, 'woff2' and 'svg' are available
+ timestamp: runTimestamp, // recommended to get consistent builds when watching files
+ }))
+ .on('glyphs', function(glyphs, options) {
+ gulp.src(config.iconsfont.template)
+ .pipe(consolidate('lodash', {
+ glyphs: glyphs,
+ fontName: config.iconsfont.name,
+ fontPath: '../fonts/',
+ className: 'icon'
+ }))
+ .pipe(rename('_icons.scss'))
+ .pipe(gulp.dest('app/css/'));
+ })
+ .pipe(gulp.dest(config.iconsfont.dest))
+ .pipe(browserSync.stream());
+});
diff --git a/gulp/tasks/generateIndexStyles.js b/gulp/tasks/generateIndexStyles.js
new file mode 100644
index 0000000..58c15b7
--- /dev/null
+++ b/gulp/tasks/generateIndexStyles.js
@@ -0,0 +1,42 @@
+import config from '../config';
+import gulp from 'gulp';
+import gulpif from 'gulp-if';
+import sourcemaps from 'gulp-sourcemaps';
+import sass from 'gulp-sass';
+import handleErrors from '../util/handleErrors';
+import setEnvironment from '../util/setEnvironment';
+import browserSync from 'browser-sync';
+import autoprefixer from 'gulp-autoprefixer';
+import uncss from 'gulp-uncss';
+import csso from 'gulp-csso';
+import folders from 'gulp-folders';
+import cssToJs from 'gulp-css-to-js';
+import rename from 'gulp-rename';
+import strip from 'gulp-strip-css-comments';
+
+setEnvironment();
+
+var sass_settings = {
+ sourceComments: development(),
+ outputStyle: production() ? 'compressed' : 'nested',
+ includePaths: config.styles.sassIncludePaths
+};
+
+gulp.task('generate:MainStyles', function () {
+
+ const createSourcemap = development() || config.styles.prodSourcemap;
+
+ return gulp.src(config.styles.src)
+ .pipe( gulpif(createSourcemap, sourcemaps.init()) )
+ .pipe( sass(sass_settings) )
+ .on( 'error', handleErrors )
+ .pipe( production(strip( { 'preserve' : false })) )
+ .pipe( autoprefixer(config.styles.autoprefixer) )
+ .pipe( gulpif(createSourcemap, sourcemaps.write( production() ? './' : null )) )
+ .pipe( production(uncss({ html: [config.templates.src, config.templates.index, config.modules.templates]})) )
+ .pipe( production(csso()) )
+ .pipe( production(global.cachebust.references()) )
+ .pipe( production(global.cachebust.resources()) )
+ .pipe( gulp.dest(config.styles.dest) )
+ .pipe( browserSync.stream() );
+});
diff --git a/gulp/tasks/generateMainTemplates.js b/gulp/tasks/generateMainTemplates.js
new file mode 100644
index 0000000..00671d6
--- /dev/null
+++ b/gulp/tasks/generateMainTemplates.js
@@ -0,0 +1,25 @@
+import config from '../config';
+import gulp from 'gulp';
+import browserSync from 'browser-sync';
+import templateCache from 'gulp-angular-templatecache';
+import folders from 'gulp-folders';
+import htmlhint from 'gulp-htmlhint';
+import htmlmin from 'gulp-htmlmin';
+
+// Views task
+gulp.task('generate:MainTemplates', function() {
+
+ // Process any other view files from app/views
+ return gulp.src(config.templates.src)
+ .pipe(htmlhint('.htmlhintrc'))
+ .pipe(htmlhint.reporter())
+ .pipe( production(htmlmin({collapseWhitespace: true})) )
+ .pipe(templateCache({
+ standalone: true,
+ filename: 'app_tpl.js',
+ module: 'app.templates',
+ moduleSystem: 'Browserify'
+ }))
+ .pipe(gulp.dest(config.templates.dest))
+ .pipe(browserSync.stream());
+});
\ No newline at end of file
diff --git a/gulp/tasks/generateModuleStyles.js b/gulp/tasks/generateModuleStyles.js
new file mode 100644
index 0000000..3339dba
--- /dev/null
+++ b/gulp/tasks/generateModuleStyles.js
@@ -0,0 +1,41 @@
+import config from '../config';
+import gulp from 'gulp';
+import gulpif from 'gulp-if';
+import sourcemaps from 'gulp-sourcemaps';
+import sass from 'gulp-sass';
+import handleErrors from '../util/handleErrors';
+import setEnvironment from '../util/setEnvironment';
+import browserSync from 'browser-sync';
+import autoprefixer from 'gulp-autoprefixer';
+import uncss from 'gulp-uncss';
+import csso from 'gulp-csso';
+import folders from 'gulp-folders';
+import cssToJs from 'gulp-css-to-js';
+import rename from 'gulp-rename';
+import strip from 'gulp-strip-css-comments';
+
+setEnvironment();
+
+var sass_settings = {
+ sourceComments: development(),
+ outputStyle: production() ? 'compressed' : 'nested',
+ includePaths: config.styles.sassIncludePaths
+};
+
+gulp.task('generate:ModuleStyles', folders(config.modules.src, function(module){
+
+ const createSourcemap = development() || config.styles.prodSourcemap;
+
+ return gulp.src( config.modules.src + module + '/*.scss*' )
+ .pipe( gulpif(createSourcemap, sourcemaps.init()) )
+ .pipe( sass(sass_settings) )
+ .on('error', handleErrors)
+ .pipe( autoprefixer(config.styles.autoprefixer) )
+ .pipe( gulpif( createSourcemap, sourcemaps.write( production() ? './' : null )) )
+ .pipe( production(csso()) )
+ .pipe( production(strip( { 'preserve' : false })) )
+ .pipe( cssToJs() )
+ .pipe( rename(module + '_css.js') )
+ .pipe( gulp.dest(config.modules.src + module) )
+ .pipe( browserSync.stream() );
+}));
diff --git a/gulp/tasks/generateModuleTemplates.js b/gulp/tasks/generateModuleTemplates.js
new file mode 100644
index 0000000..830eff5
--- /dev/null
+++ b/gulp/tasks/generateModuleTemplates.js
@@ -0,0 +1,22 @@
+import config from '../config';
+import gulp from 'gulp';
+import browserSync from 'browser-sync';
+import templateCache from 'gulp-angular-templatecache';
+import folders from 'gulp-folders';
+import htmlhint from 'gulp-htmlhint';
+import htmlmin from 'gulp-htmlmin';
+
+gulp.task('generate:ModuleTemplates', folders(config.modules.src, function(module){
+ return gulp.src(config.modules.src + module + '/*.htm*')
+ .pipe(htmlhint('.htmlhintrc'))
+ .pipe(htmlhint.reporter())
+ .pipe( production(htmlmin({collapseWhitespace: true})) )
+ .pipe(templateCache({
+ standalone: true,
+ filename: module + '_tpl.js',
+ module: module + '.templates',
+ moduleSystem: 'Browserify'
+ }))
+ .pipe(gulp.dest(config.modules.src + module))
+ .pipe(browserSync.stream());
+}));
\ No newline at end of file
diff --git a/gulp/tasks/gzip.js b/gulp/tasks/gzip.js
deleted file mode 100644
index 2ebeac7..0000000
--- a/gulp/tasks/gzip.js
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict';
-
-import config from '../config';
-import gulp from 'gulp';
-import gzip from 'gulp-gzip';
-
-gulp.task('gzip', function() {
-
- return gulp.src(config.gzip.src)
- .pipe(gzip(config.gzip.options))
- .pipe(gulp.dest(config.gzip.dest));
-
-});
diff --git a/gulp/tasks/images.js b/gulp/tasks/images.js
deleted file mode 100644
index e423b19..0000000
--- a/gulp/tasks/images.js
+++ /dev/null
@@ -1,18 +0,0 @@
-'use strict';
-
-import config from '../config';
-import changed from 'gulp-changed';
-import gulp from 'gulp';
-import gulpif from 'gulp-if';
-import imagemin from 'gulp-imagemin';
-import browserSync from 'browser-sync';
-
-gulp.task('images', function() {
-
- return gulp.src(config.images.src)
- .pipe(changed(config.images.dest)) // Ignore unchanged files
- .pipe(gulpif(global.isProd, imagemin())) // Optimize
- .pipe(gulp.dest(config.images.dest))
- .pipe(browserSync.stream());
-
-});
diff --git a/gulp/tasks/injectCacheBust.js b/gulp/tasks/injectCacheBust.js
new file mode 100644
index 0000000..05fff6a
--- /dev/null
+++ b/gulp/tasks/injectCacheBust.js
@@ -0,0 +1,13 @@
+import config from '../config';
+import gulp from 'gulp';
+import setEnvironment from '../util/setEnvironment';
+
+setEnvironment();
+
+gulp.task('inject:CacheBust', function() {
+
+ return gulp.src(config.scripts.dest + '/**/*.js')
+ .pipe( production(global.cachebust.references()) )
+ .pipe( gulp.dest(config.scripts.dest) );
+
+});
diff --git a/gulp/tasks/injectIconFont.js b/gulp/tasks/injectIconFont.js
new file mode 100644
index 0000000..5df4f02
--- /dev/null
+++ b/gulp/tasks/injectIconFont.js
@@ -0,0 +1,18 @@
+import config from '../config';
+import changed from 'gulp-changed';
+import gulp from 'gulp';
+import rename from 'gulp-rename';
+import browserSync from 'browser-sync';
+import inlineFonts from 'gulp-inline-fonts';
+
+gulp.task('inject:IconFont', function() {
+ return gulp.src(config.fonts.icons)
+ .pipe(inlineFonts({
+ name: 'icons',
+ style: 'normal',
+ weight: 'normal',
+ formats: ['woff', 'ttf', 'eot']
+ }))
+ .pipe(rename('_fonts.scss'))
+ .pipe(gulp.dest(config.styles.dev));
+});
\ No newline at end of file
diff --git a/gulp/tasks/lint.js b/gulp/tasks/lint.js
deleted file mode 100644
index 5985a6d..0000000
--- a/gulp/tasks/lint.js
+++ /dev/null
@@ -1,11 +0,0 @@
-'use strict';
-
-import config from '../config';
-import gulp from 'gulp';
-import jshint from 'gulp-jshint';
-
-gulp.task('lint', function() {
- return gulp.src([config.scripts.src, '!app/js/templates.js'])
- .pipe(jshint())
- .pipe(jshint.reporter('jshint-stylish'));
-});
\ No newline at end of file
diff --git a/gulp/tasks/mocks.js b/gulp/tasks/mocks.js
new file mode 100644
index 0000000..9e6fbae
--- /dev/null
+++ b/gulp/tasks/mocks.js
@@ -0,0 +1,11 @@
+import config from '../config';
+import gulp from 'gulp';
+import runSequence from 'run-sequence';
+
+gulp.task('mocks', function(cb) {
+
+ global.mocks = true;
+
+ runSequence(['copy:Mocks'], 'dev', cb);
+
+});
\ No newline at end of file
diff --git a/gulp/tasks/openSourceAnalyze.js b/gulp/tasks/openSourceAnalyze.js
new file mode 100644
index 0000000..6c1e400
--- /dev/null
+++ b/gulp/tasks/openSourceAnalyze.js
@@ -0,0 +1,17 @@
+import config from '../config';
+import gulp from 'gulp';
+import open from 'gulp-open';
+import del from 'del';
+
+gulp.task('open:SourceAnalyze', function() {
+
+ del(config.babel.dest);
+
+ return gulp.src(
+ config.reports.analysis.index
+ )
+ .pipe(
+ open()
+ );
+
+});
diff --git a/gulp/tasks/openTestCoverage.js b/gulp/tasks/openTestCoverage.js
new file mode 100644
index 0000000..4ebd38f
--- /dev/null
+++ b/gulp/tasks/openTestCoverage.js
@@ -0,0 +1,15 @@
+import config from '../config';
+import path from 'path';
+import gulp from 'gulp';
+import open from 'gulp-open';
+
+gulp.task('open:TestCoverage', function(cb) {
+
+ return gulp.src(
+ config.reports.coverage.index
+ )
+ .pipe(
+ open()
+ );
+
+});
\ No newline at end of file
diff --git a/gulp/tasks/prod.js b/gulp/tasks/prod.js
new file mode 100644
index 0000000..0ee859f
--- /dev/null
+++ b/gulp/tasks/prod.js
@@ -0,0 +1,52 @@
+import gulp from 'gulp';
+import runSequence from 'run-sequence';
+import evironments from 'gulp-environments';
+
+gulp.task('prod', ['delete:Files'], function(cb) {
+
+ cb = cb || function() {};
+
+ global.production = environments.production;
+ global.development = environments.development;
+
+ environments.current(production);
+
+ runSequence(
+ [
+ 'combine:Svg',
+ 'generate:IconFont',
+ 'generate:Favicons'
+ ],
+ [
+ 'copy:Images',
+ 'copy:Fonts',
+ 'inject:IconFont'
+ ],
+ [
+ 'generate:ConstantModule',
+ 'generate:MainStyles',
+ 'generate:ModuleStyles',
+ 'generate:ModuleTemplates',
+ 'generate:MainTemplates'
+ ],
+ [
+ 'browserify:Modules',
+ 'browserify:Main',
+ 'copy:Locales',
+ 'copy:Translations'
+ ],
+ [
+ 'inject:CacheBust',
+ 'copy:MainIndex'
+ ],
+ [
+ 'show:Info',
+ 'analyze:Plato'
+ ],
+ [
+ 'open:SourceAnalyze'
+ ],
+ cb
+ );
+
+});
diff --git a/gulp/tasks/production.js b/gulp/tasks/production.js
deleted file mode 100644
index 563b8d0..0000000
--- a/gulp/tasks/production.js
+++ /dev/null
@@ -1,14 +0,0 @@
-'use strict';
-
-import gulp from 'gulp';
-import runSequence from 'run-sequence';
-
-gulp.task('prod', ['clean'], function(cb) {
-
- cb = cb || function() {};
-
- global.isProd = true;
-
- runSequence(['styles', 'images', 'fonts', 'views'], 'browserify', 'gzip', cb);
-
-});
diff --git a/gulp/tasks/protractor.js b/gulp/tasks/protractor.js
deleted file mode 100644
index ae9796d..0000000
--- a/gulp/tasks/protractor.js
+++ /dev/null
@@ -1,26 +0,0 @@
-'use strict';
-
-import config from '../config';
-import gulp from 'gulp';
-import {
- protractor,
- webdriver,
- webdriver_update
-} from 'gulp-protractor';
-
-gulp.task('webdriver-update', webdriver_update);
-gulp.task('webdriver', webdriver);
-
-gulp.task('protractor', ['webdriver-update', 'webdriver', 'browserSync'], function(cb = function() {}) {
-
- gulp.src('test/e2e/**/*.js').pipe(protractor({
- configFile: config.test.protractor
- })).on('error', (err) => {
- // Make sure failed tests cause gulp to exit non-zero
- throw err;
- }).on('end', () => {
- process.exit();
- cb();
- });
-
-});
\ No newline at end of file
diff --git a/gulp/tasks/server.js b/gulp/tasks/server.js
new file mode 100644
index 0000000..2c83215
--- /dev/null
+++ b/gulp/tasks/server.js
@@ -0,0 +1,34 @@
+import config from '../config';
+import url from 'url';
+import browserSync from 'browser-sync';
+import gulp from 'gulp';
+
+gulp.task('server', function() {
+
+ const DEFAULT_FILE = 'index.html';
+ const ASSET_EXTENSION_REGEX = new RegExp(`\\b(?!\\?)\\.(${config.assetExtensions.join('|')})\\b(?!\\.)`, 'i');
+
+ browserSync.init({
+ server: {
+ baseDir: config.buildDir,
+ middleware: function(req, res, next) {
+ let fileHref = url.parse(req.url).href;
+
+ if ( !ASSET_EXTENSION_REGEX.test(fileHref) ) {
+ req.url = '/' + DEFAULT_FILE;
+ }
+
+ return next();
+ }
+ },
+ port: config.browserPort,
+ ui: {
+ port: config.UIPort
+ },
+ open: 'ui',
+ ghostMode: {
+ links: false
+ }
+ });
+
+});
diff --git a/gulp/tasks/showInfo.js b/gulp/tasks/showInfo.js
new file mode 100644
index 0000000..e342c35
--- /dev/null
+++ b/gulp/tasks/showInfo.js
@@ -0,0 +1,8 @@
+import config from '../config';
+import gulp from 'gulp';
+import size from 'gulp-filesize';
+
+gulp.task('show:Info', function() {
+ return gulp.src(config.info.src)
+ .pipe(size());
+});
diff --git a/gulp/tasks/styles.js b/gulp/tasks/styles.js
deleted file mode 100644
index 7196cf2..0000000
--- a/gulp/tasks/styles.js
+++ /dev/null
@@ -1,32 +0,0 @@
-'use strict';
-
-import config from '../config';
-import gulp from 'gulp';
-import gulpif from 'gulp-if';
-import sourcemaps from 'gulp-sourcemaps';
-import sass from 'gulp-sass';
-import handleErrors from '../util/handleErrors';
-import browserSync from 'browser-sync';
-import autoprefixer from 'gulp-autoprefixer';
-
-gulp.task('styles', function () {
-
- const createSourcemap = !global.isProd || config.styles.prodSourcemap;
-
- return gulp.src(config.styles.src)
- .pipe(gulpif(createSourcemap, sourcemaps.init()))
- .pipe(sass({
- sourceComments: !global.isProd,
- outputStyle: global.isProd ? 'compressed' : 'nested',
- includePaths: config.styles.sassIncludePaths
- }))
- .on('error', handleErrors)
- .pipe(autoprefixer('last 2 versions', '> 1%', 'ie 8'))
- .pipe(gulpif(
- createSourcemap,
- sourcemaps.write( global.isProd ? './' : null ))
- )
- .pipe(gulp.dest(config.styles.dest))
- .pipe(browserSync.stream());
-
-});
diff --git a/gulp/tasks/test.js b/gulp/tasks/test.js
index b3f49ae..4e55152 100644
--- a/gulp/tasks/test.js
+++ b/gulp/tasks/test.js
@@ -1,10 +1,9 @@
-'use strict';
-
import gulp from 'gulp';
import runSequence from 'run-sequence';
-gulp.task('test', ['browserSync'], function() {
+gulp.task('test', ['server'], function(cb) {
- return runSequence('unit', 'protractor');
+ cb = cb || function() {};
+ return runSequence('test:Unit', 'test:Functional', cb);
});
\ No newline at end of file
diff --git a/gulp/tasks/testFunctional.js b/gulp/tasks/testFunctional.js
new file mode 100644
index 0000000..299327d
--- /dev/null
+++ b/gulp/tasks/testFunctional.js
@@ -0,0 +1,28 @@
+import config from '../config';
+import testServer from '../util/testServer';
+import express from 'express';
+import gulp from 'gulp';
+import {
+ protractor,
+ webdriver
+} from 'gulp-protractor';
+
+gulp.task('launch:Webdriver', webdriver);
+
+gulp.task('test:Functional', ['launch:Webdriver'], function(cb) {
+
+ const testFiles = gulp.src('test/e2e/**/*_spec.js');
+
+ testServer({
+ port: config.browserPort,
+ dir: config.buildDir
+ }).then((server) => {
+ testFiles.pipe(protractor({
+ configFile: config.test.protractor
+ })).on('error', (err) => {
+ // Make sure failed tests cause gulp to exit non-zero
+ throw err;
+ }).on('end', () => server.close(cb));
+ });
+
+});
\ No newline at end of file
diff --git a/gulp/tasks/testUnit.js b/gulp/tasks/testUnit.js
new file mode 100644
index 0000000..e8d6d75
--- /dev/null
+++ b/gulp/tasks/testUnit.js
@@ -0,0 +1,15 @@
+import config from '../config';
+import path from 'path';
+import gulp from 'gulp';
+import {Server} from 'karma';
+
+gulp.task('test:Unit', function(cb) {
+
+ new Server({
+ configFile: path.resolve(__dirname, '../..', config.test.karma),
+ singleRun: true
+ }, cb).start();
+
+ //open:TestCoverage
+
+});
\ No newline at end of file
diff --git a/gulp/tasks/unit.js b/gulp/tasks/unit.js
deleted file mode 100644
index f1a3677..0000000
--- a/gulp/tasks/unit.js
+++ /dev/null
@@ -1,15 +0,0 @@
-'use strict';
-
-import config from '../config';
-import path from 'path';
-import gulp from 'gulp';
-import {Server} from 'karma';
-
-gulp.task('unit', ['views'], function() {
-
- new Server({
- configFile: path.resolve(__dirname, '../..', config.test.karma),
- singleRun: true
- }).start();
-
-});
\ No newline at end of file
diff --git a/gulp/tasks/views.js b/gulp/tasks/views.js
deleted file mode 100644
index 9ff1f2e..0000000
--- a/gulp/tasks/views.js
+++ /dev/null
@@ -1,23 +0,0 @@
-'use strict';
-
-import config from '../config';
-import gulp from 'gulp';
-import browserSync from 'browser-sync';
-import templateCache from 'gulp-angular-templatecache';
-
-// Views task
-gulp.task('views', function() {
-
- // Put our index.html in the dist folder
- gulp.src(config.views.index)
- .pipe(gulp.dest(config.buildDir));
-
- // Process any other view files from app/views
- return gulp.src(config.views.src)
- .pipe(templateCache({
- standalone: true
- }))
- .pipe(gulp.dest(config.views.dest))
- .pipe(browserSync.stream());
-
-});
diff --git a/gulp/tasks/watch.js b/gulp/tasks/watch.js
deleted file mode 100644
index d78bc97..0000000
--- a/gulp/tasks/watch.js
+++ /dev/null
@@ -1,15 +0,0 @@
-'use strict';
-
-import config from '../config';
-import gulp from 'gulp';
-
-gulp.task('watch', ['browserSync'], function() {
-
- // Scripts are automatically watched and rebundled by Watchify inside Browserify task
- gulp.watch(config.scripts.src, ['lint']);
- gulp.watch(config.styles.src, ['styles']);
- gulp.watch(config.images.src, ['images']);
- gulp.watch(config.fonts.src, ['fonts']);
- gulp.watch(config.views.watch, ['views']);
-
-});
\ No newline at end of file
diff --git a/gulp/tasks/watchFiles.js b/gulp/tasks/watchFiles.js
new file mode 100644
index 0000000..d0663f2
--- /dev/null
+++ b/gulp/tasks/watchFiles.js
@@ -0,0 +1,24 @@
+import config from '../config';
+import gulp from 'gulp';
+
+gulp.task('watch:Files', ['server'], function() {
+
+ global.isWatching = true;
+
+ // Scripts are automatically watched and rebundled by Watchify inside Browserify task
+ gulp.watch(config.scripts.src, ['analyze:Jshint']);
+ gulp.watch(config.modules.scripts, ['analyze:Jshint', 'browserify:Modules']);
+ gulp.watch(config.locale.src, ['copy:Locales']);
+ gulp.watch(config.translation.src, ['copy:Translations']);
+ gulp.watch(config.mocks.src, ['copy:Mocks']);
+ gulp.watch(config.styles.src, ['generate:MainStyles']);
+ gulp.watch(config.modules.styles, ['generate:ModuleStyles', 'browserify:Modules']);
+ gulp.watch(config.sprite.src, ['combine:Svg', 'generate:MainTemplates']);
+ gulp.watch(config.images.src, ['copy:Images']);
+ gulp.watch(config.fonts.src, ['copy:Fonts']);
+ gulp.watch(config.iconsfont.src, ['generate:IconFont', 'inject:IconFont']);
+ gulp.watch(config.templates.index, ['copy:MainIndex']);
+ gulp.watch(config.templates.watch, ['generate:MainTemplates']);
+ gulp.watch(config.modules.templates, ['generate:ModuleTemplates']);
+
+});
\ No newline at end of file
diff --git a/gulp/util/bundleLogger.js b/gulp/util/bundleLogger.js
index 0754de6..fa21b44 100644
--- a/gulp/util/bundleLogger.js
+++ b/gulp/util/bundleLogger.js
@@ -1,26 +1,24 @@
-'use strict';
-
/* bundleLogger
* ------------
* Provides gulp style logs to the bundle method in browserify.js
*/
-import gutil from 'gulp-util';
-import prettyHrtime from 'pretty-hrtime';
+import gutil from 'gulp-util';
+import prettyHrtime from 'pretty-hrtime';
var startTime;
export default {
- start() {
- startTime = process.hrtime();
- gutil.log('Running', gutil.colors.green(`'bundle'`) + '...');
- },
+ start() {
+ startTime = process.hrtime();
+ gutil.log('Running', gutil.colors.green(`'bundle'`) + '...');
+ },
- end() {
- var taskTime = process.hrtime(startTime);
- var prettyTime = prettyHrtime(taskTime);
- gutil.log('Finished', gutil.colors.green(`'bundle'`), 'in', gutil.colors.magenta(prettyTime));
- }
+ end() {
+ var taskTime = process.hrtime(startTime);
+ var prettyTime = prettyHrtime(taskTime);
+ gutil.log('Finished', gutil.colors.green(`'bundle'`), 'in', gutil.colors.magenta(prettyTime));
+ }
};
\ No newline at end of file
diff --git a/gulp/util/constant.tpl.ejs b/gulp/util/constant.tpl.ejs
new file mode 100644
index 0000000..d1995f1
--- /dev/null
+++ b/gulp/util/constant.tpl.ejs
@@ -0,0 +1,7 @@
+const AppSettings = {
+<% constants.forEach(function(constant) { %>
+ <%- constant.name %>: <%= constant.value %>,
+<% }) %>
+};
+
+export default AppSettings;
\ No newline at end of file
diff --git a/gulp/util/handleErrors.js b/gulp/util/handleErrors.js
index 77dca45..a426606 100644
--- a/gulp/util/handleErrors.js
+++ b/gulp/util/handleErrors.js
@@ -1,27 +1,25 @@
-'use strict';
-
import notify from 'gulp-notify';
export default function(error) {
- if( !global.isProd ) {
+ if(global.environment == 'development') {
- var args = Array.prototype.slice.call(arguments);
+ var args = Array.prototype.slice.call(arguments);
- // Send error to notification center with gulp-notify
- notify.onError({
- title: 'Compile Error',
- message: '<%= error.message %>'
- }).apply(this, args);
+ // Send error to notification center with gulp-notify
+ notify.onError({
+ title: 'Compile Error',
+ message: '<%= error.message %>'
+ }).apply(this, args);
- // Keep gulp from hanging on this task
- this.emit('end');
+ // Keep gulp from hanging on this task
+ this.emit('end');
- } else {
- // Log the error and stop the process
- // to prevent broken code from building
- console.log(error);
- process.exit(1);
- }
+ } else {
+ // Log the error and stop the process
+ // to prevent broken code from building
+ console.log(error);
+ process.exit(1);
+ }
};
\ No newline at end of file
diff --git a/gulp/util/iconsfont.css b/gulp/util/iconsfont.css
new file mode 100644
index 0000000..4c1a02c
--- /dev/null
+++ b/gulp/util/iconsfont.css
@@ -0,0 +1,25 @@
+.<%= className %> {
+ display: inline-block;
+ font: normal normal normal 14px/1 <%= fontName %>;
+ font-size: inherit;
+ text-rendering: auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.<%= className %>-lg {
+ font-size: 1.3333333333333333em;
+ line-height: 0.75em;
+ vertical-align: -15%;
+}
+.<%= className %>-2x { font-size: 2em; }
+.<%= className %>-3x { font-size: 3em; }
+.<%= className %>-4x { font-size: 4em; }
+.<%= className %>-5x { font-size: 5em; }
+.<%= className %>-fw {
+ width: 1.2857142857142858em;
+ text-align: center;
+}
+
+<% _.each(glyphs, function(glyph) { %>.<%= className %>-<%= glyph.name %>:before { content: "\<%= glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase() %>" }
+<% }); %>
\ No newline at end of file
diff --git a/gulp/util/scriptFilter.js b/gulp/util/scriptFilter.js
index 5ba162c..f3534a3 100644
--- a/gulp/util/scriptFilter.js
+++ b/gulp/util/scriptFilter.js
@@ -1,11 +1,9 @@
-'use strict';
-
import path from 'path';
// Filters out non .js files. Prevents
// accidental inclusion of possible hidden files
export default function(name) {
- return /(\.(js)$)/i.test(path.extname(name));
+ return /(\.(js)$)/i.test(path.extname(name));
};
\ No newline at end of file
diff --git a/gulp/util/setEnvironment.js b/gulp/util/setEnvironment.js
new file mode 100644
index 0000000..441007a
--- /dev/null
+++ b/gulp/util/setEnvironment.js
@@ -0,0 +1,15 @@
+/* setEnvironment
+ * ------------
+ * Set environment if it not defined
+ */
+
+import gulpEnvironments from 'gulp-environments';
+
+global.environments = gulpEnvironments;
+
+export default function() {
+
+ global.production = environments.production;
+ global.development = environments.development;
+
+};
\ No newline at end of file
diff --git a/gulp/util/testServer.js b/gulp/util/testServer.js
new file mode 100644
index 0000000..e4bd23b
--- /dev/null
+++ b/gulp/util/testServer.js
@@ -0,0 +1,13 @@
+import express from 'express';
+
+export default function testServer({port, dir}) {
+
+ const app = express();
+
+ app.use(express.static(dir));
+
+ return new Promise((res, rej) => {
+ const server = app.listen(port, () => res(server));
+ });
+
+}
\ No newline at end of file
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index c6507a0..419fb6d 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -11,6 +11,4 @@
* To add a new task, simply add a new task file to gulp/tasks.
*/
-global.isProd = false;
-
require('./gulp');
\ No newline at end of file
diff --git a/package.json b/package.json
index c005554..1e2d493 100644
--- a/package.json
+++ b/package.json
@@ -1,17 +1,19 @@
{
- "name": "Boneric",
+ "name": "Angularis",
"version": "1.0.0",
"author": "Alex Kryzhanovskyy ",
- "description": "Gay dates site.",
+ "description": "AnbgularJS boilerplate.",
"repository": {
"type": "git",
- "url": "https://bitbucket.org/AlexKryzh/boneric"
+ "url": ""
},
"keywords": [
"express",
"gulp",
"browserify",
+ "bootstrap",
"angular",
+ "restangular",
"sass",
"karma",
"jasmine",
@@ -20,14 +22,28 @@
"private": true,
"license": "UNLICENSED",
"engines": {
- "node": ">=0.12.x"
+ "node": "~4.2.x"
},
- "devDependencies": {
- "angular": "^1.3.15",
- "angular-mocks": "^1.3.15",
+ "dependencies": {
+ "angular": "1.5",
+ "angular-cookies": "1.5",
+ "angular-dynamic-locale": "^0.1.29",
+ "angular-i18n": "1.5",
+ "angular-mocks": "1.5",
+ "angular-sanitize": "1.5",
+ "angular-translate": "^2.8.1",
+ "angular-translate-handler-log": "^2.8.1",
+ "angular-translate-loader-static-files": "^2.8.1",
+ "angular-translate-storage-cookie": "^2.8.1",
+ "angular-translate-storage-local": "^2.8.1",
"angular-ui-router": "^0.2.13",
- "babel-core": "^5.8.25",
- "babelify": "^6.4.0",
+ "bootstrap-sass": "^3.3.6",
+ "oclazyload": "^1.0.9"
+ },
+ "devDependencies": {
+ "babel-core": "^6.4.5",
+ "babel-preset-es2015": "^6.3.13",
+ "babelify": "^7.2.0",
"brfs": "^1.2.0",
"browser-sync": "^2.7.6",
"browserify": "^12.0.0",
@@ -35,35 +51,65 @@
"browserify-ngannotate": "^2.0.0",
"bulk-require": "^0.2.1",
"bulkify": "^1.1.1",
- "debowerify": "^1.3.1",
"del": "^2.1.0",
- "gulp": "^3.8.8",
+ "express": "^4.13.3",
+ "fs": "0.0.2",
+ "gulp": "^3.9.0",
"gulp-angular-templatecache": "^1.3.0",
"gulp-autoprefixer": "^3.1.0",
+ "gulp-babel": "^6.1.2",
+ "gulp-cachebust": "0.0.6",
"gulp-changed": "^1.0.0",
+ "gulp-consolidate": "^0.1.2",
+ "gulp-css-to-js": "0.0.1",
+ "gulp-csso": "^1.0.1",
+ "gulp-environments": "^0.1.1",
+ "gulp-filesize": "0.0.6",
+ "gulp-folders": "^1.1.0",
"gulp-gzip": "^1.2.0",
+ "gulp-htmlhint": "^0.3.1",
+ "gulp-htmlmin": "^1.3.0",
+ "gulp-iconfont": "^5.0.1",
"gulp-if": "^2.0.0",
"gulp-imagemin": "^2.4.0",
+ "gulp-inject": "^3.0.0",
+ "gulp-inline-fonts": "^1.0.1",
"gulp-jshint": "^1.8.3",
+ "gulp-jsonlint": "^1.1.1",
+ "gulp-jsonminify": "^1.0.0",
+ "gulp-ng-constant": "^1.1.0",
"gulp-notify": "^2.0.0",
+ "gulp-open": "^1.0.0",
+ "gulp-plato": "^1.0.2",
"gulp-protractor": "^2.1.0",
+ "gulp-real-favicon": "^0.2.1",
"gulp-rename": "^1.2.0",
+ "gulp-replace": "^0.5.4",
"gulp-sass": "^2.0.4",
"gulp-sourcemaps": "^1.6.0",
"gulp-streamify": "^1.0.2",
+ "gulp-strip-css-comments": "^1.2.0",
+ "gulp-svgmin": "^1.2.2",
+ "gulp-svgstore": "^5.0.5",
+ "gulp-task-listing": "^1.0.1",
"gulp-uglify": "^1.4.2",
+ "gulp-uncss": "^1.0.4",
"gulp-util": "^3.0.1",
"imagemin-pngcrush": "^4.1.0",
+ "install": "^0.4.1",
"isparta": "^4.0.0",
"jshint-stylish": "^2.1.0",
- "karma": "^0.13.14",
+ "karma": "^0.13.19",
"karma-browserify": "^4.4.0",
"karma-chrome-launcher": "^0.2.1",
"karma-coverage": "douglasduteil/karma-coverage#next",
"karma-firefox-launcher": "^0.1.3",
"karma-jasmine": "^0.3.6",
+ "karma-sauce-launcher": "^0.3.0",
+ "merge-stream": "^1.0.0",
+ "path": "^0.12.7",
"pretty-hrtime": "^1.0.1",
- "protractor": "2.5.1",
+ "protractor": "^3.0.0",
"run-sequence": "^1.1.5",
"tiny-lr": "0.0.9",
"uglifyify": "^3.0.1",
@@ -73,8 +119,15 @@
},
"scripts": {
"prestart": "npm install",
- "test": "karma start test/karma.conf.js",
+ "test": "./node_modules/.bin/gulp test",
+ "webdriver-update": "./node_modules/.bin/webdriver-manager update",
+ "postinstall": "npm run webdriver-update",
"preprotractor": "webdriver-manager update",
"protractor": "protractor test/protractor.conf.js"
+ },
+ "babel": {
+ "presets": [
+ "es2015"
+ ]
}
}
diff --git a/test/e2e/example_spec.js b/test/e2e/example_spec.js
deleted file mode 100644
index d68cb4a..0000000
--- a/test/e2e/example_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*global browser, by */
-
-'use strict';
-
-describe('E2E: Example', function() {
-
- beforeEach(function() {
- browser.get('/');
- browser.waitForAngular();
- });
-
- it('should route correctly', function() {
- expect(browser.getLocationAbsUrl()).toMatch('/');
- });
-
- it('should show the number defined in the controller', function() {
- var element = browser.findElement(by.css('.number-example'));
- expect(element.getText()).toEqual('1234');
- });
-
-});
\ No newline at end of file
diff --git a/test/e2e/routes_spec.js b/test/e2e/routes_spec.js
index 3cedaca..818f2fe 100644
--- a/test/e2e/routes_spec.js
+++ b/test/e2e/routes_spec.js
@@ -1,12 +1,15 @@
-/*global browser */
-
'use strict';
describe('E2E: Routes', function() {
- it('should have a working home route', function() {
- browser.get('#/');
- expect(browser.getLocationAbsUrl()).toMatch('/');
- });
+ it('should have a working home route', function() {
+ browser.get('/');
+ expect(browser.getLocationAbsUrl()).toMatch('/');
+ });
+
+ it('should open Style Guide page', function() {
+ element(by.css('#navbar a[ui-sref="styleguide"]')).click();
+ expect(browser.getLocationAbsUrl()).toMatch('/styleguide');
+ });
});
\ No newline at end of file
diff --git a/test/e2e/translations_spec.js b/test/e2e/translations_spec.js
new file mode 100644
index 0000000..3799244
--- /dev/null
+++ b/test/e2e/translations_spec.js
@@ -0,0 +1,16 @@
+'use strict';
+browser.get('/');
+
+describe('E2E: Translations', function() {
+
+ it('Should translate page to Spanish', function() {
+ element(by.css('#translate-language .es_es')).click();
+ expect(element(by.css('#translate-language label')).getText()).toEqual('Idioma');
+ });
+
+ it('Should translate page to English', function() {
+ element(by.css('#translate-language .en_us')).click();
+ expect(element(by.css('#translate-language label')).getText()).toEqual('Language');
+ });
+
+});
\ No newline at end of file
diff --git a/test/karma.conf.js b/test/karma.conf.js
index 41facda..af5fecb 100644
--- a/test/karma.conf.js
+++ b/test/karma.conf.js
@@ -1,53 +1,96 @@
'use strict';
-var istanbul = require('browserify-istanbul');
-var isparta = require('isparta');
+const istanbul = require('browserify-istanbul');
+const isparta = require('isparta');
-module.exports = function(config) {
-
- config.set({
+const karmaBaseConfig = {
basePath: '../',
+ singleRun: true,
frameworks: ['jasmine', 'browserify'],
preprocessors: {
- 'app/js/**/*.js': ['browserify', 'coverage']
+ 'app/@(js|modules)/**/!(*spec|*tpl|*css|index).js': ['browserify', 'coverage']
},
browsers: ['Chrome'],
reporters: ['progress', 'coverage'],
+ coverageReporter: {
+ reporters : [
+ {
+ "type": "text",
+ dir: 'reports/coverage'
+ },
+ {
+ "type": "html",
+ dir: 'reports/coverage'
+ }
+ ]
+ },
+
autoWatch: true,
browserify: {
- debug: true,
- extensions: ['.js'],
- transform: [
- 'babelify',
- 'browserify-ngannotate',
- 'bulkify',
- istanbul({
- instrumenter: isparta,
- ignore: ['**/node_modules/**', '**/test/**']
- })
- ]
+ debug: true,
+ extensions: ['.js'],
+ transform: [
+ 'babelify',
+ 'browserify-ngannotate',
+ 'bulkify',
+ istanbul({
+ instrumenter: isparta,
+ instrumenterConfig: { embedSource: true },
+ ignore: ['**/node_modules/**', '**/test/**', '**/app/js/mocks/**/*.js', '**/*_spec.js', '**/*_tpl.js', '**/*_css.js', '**/index.js', '**/app/js/settings/mocks.js']
+ })
+ ]
},
proxies: {
- '/': 'http://localhost:9876/'
+ '/': 'http://localhost:9876/'
},
urlRoot: '/__karma__/',
files: [
- // app-specific code
- 'app/js/main.js',
+ // app-specific code
+ { pattern: 'app/@(js|modules)/**/!(*tpl|*css|index).js', included: true },
- // 3rd-party resources
- 'node_modules/angular-mocks/angular-mocks.js',
+ // 3rd-party resources
+ { pattern: 'node_modules/angular-mocks/angular-mocks.js', watched: false },
- // test files
- 'test/unit/**/*.js'
+ // test files
+ 'test/unit/**/*.js'
]
- });
+};
+const customLaunchers = {
+ chrome: {
+ base: 'SauceLabs',
+ browserName: 'chrome'
+ }
};
+
+const ciAdditions = {
+ sauceLabs: {
+ testName: 'Karma Unit Tests',
+ startConnect: false,
+ build: process.env.TRAVIS_BUILD_NUMBER,
+ tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
+ },
+ browsers: Object.keys(customLaunchers),
+ customLaunchers: customLaunchers,
+ reporters: ['progress', 'coverage', 'saucelabs']
+};
+
+module.exports = function(config) {
+ const isCI = process.env.CI;
+ config.set(isCI ? Object.assign(karmaBaseConfig, ciAdditions) : karmaBaseConfig);
+
+ // config.set({
+ // coverageReporter: {
+ // instrumenterOptions: {
+ // istanbul: { noCompact: true }
+ // }
+ // }
+ // });
+};
\ No newline at end of file
diff --git a/test/protractor.conf.js b/test/protractor.conf.js
index 0817eef..9462e23 100644
--- a/test/protractor.conf.js
+++ b/test/protractor.conf.js
@@ -6,29 +6,34 @@ var gulpConfig = require('../gulp/config');
exports.config = {
- allScriptsTimeout: 11000,
+ allScriptsTimeout: 11000,
- baseUrl: 'http://localhost:' + gulpConfig.browserPort + '/',
+ baseUrl: 'http://localhost:' + gulpConfig.browserPort + '/',
- directConnect: true,
+ directConnect: true,
- capabilities: {
- browserName: 'chrome',
- version: '',
- platform: 'ANY'
- },
+ capabilities: {
+ browserName: 'chrome',
+ version: '',
+ platform: 'ANY'
+ },
- framework: 'jasmine2',
+ framework: 'jasmine2',
- jasmineNodeOpts: {
- isVerbose: false,
- showColors: true,
- includeStackTrace: true,
- defaultTimeoutInterval: 30000
- },
+ jasmineNodeOpts: {
+ isVerbose: false,
+ showColors: true,
+ includeStackTrace: true,
+ defaultTimeoutInterval: 30000
+ },
- specs: [
- 'e2e/**/*.js'
- ]
+ // The file path to the selenium server jar ()
+ //seleniumServerJar: './node_modules/protractor/selenium/selenium-server-standalone-2.47.1.jar',
+
+ chromeDriver: './../node_modules/protractor/selenium/chromedriver',
+
+ specs: [
+ 'e2e/**/*_spec.js'
+ ]
};
diff --git a/test/unit/app_spec.js b/test/unit/app_spec.js
new file mode 100644
index 0000000..8507766
--- /dev/null
+++ b/test/unit/app_spec.js
@@ -0,0 +1,27 @@
+/*global angular */
+
+'use strict';
+
+// describe('Unit: Constants', function() {
+
+// var constants;
+
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
+
+// // mock the directive
+// angular.mock.inject(function(_AppSettings_) {
+// constants = _AppSettings_;
+// });
+// });
+
+// it('should exist', function() {
+// expect(constants).toBeDefined();
+// });
+
+// it('should have an application name', function() {
+// expect(constants.appTitle).toEqual('Example Application');
+// });
+
+// });
\ No newline at end of file
diff --git a/test/unit/constants_spec.js b/test/unit/constants_spec.js
deleted file mode 100644
index 8fb2a5b..0000000
--- a/test/unit/constants_spec.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*global angular */
-
-'use strict';
-
-describe('Unit: Constants', function() {
-
- var constants;
-
- beforeEach(function() {
- // instantiate the app module
- angular.mock.module('app');
-
- // mock the directive
- angular.mock.inject(function(AppSettings) {
- constants = AppSettings;
- });
- });
-
- it('should exist', function() {
- expect(constants).toBeDefined();
- });
-
- it('should have an application name', function() {
- expect(constants.appTitle).toEqual('Example Application');
- });
-
-});
\ No newline at end of file
diff --git a/test/unit/controllers/example_spec.js b/test/unit/controllers/example_spec.js
index bfbfa54..52def17 100644
--- a/test/unit/controllers/example_spec.js
+++ b/test/unit/controllers/example_spec.js
@@ -1,30 +1,26 @@
-/*global angular */
+// describe('Unit: ExampleCtrl', function() {
-'use strict';
+// var ctrl;
-describe('Unit: ExampleCtrl', function() {
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
- var ctrl;
+// angular.mock.inject(function($controller) {
+// ctrl = $controller('ExampleCtrl');
+// });
+// });
- beforeEach(function() {
- // instantiate the app module
- angular.mock.module('app');
+// it('should exist', function() {
+// expect(ctrl).toBeDefined();
+// });
- angular.mock.inject(function($controller) {
- ctrl = $controller('ExampleCtrl');
- });
- });
+// it('should have a number variable equal to 1234', function() {
+// expect(ctrl.number).toEqual(1234);
+// });
- it('should exist', function() {
- expect(ctrl).toBeDefined();
- });
+// it('should have a title variable equal to \'AngularJS, Gulp, and Browserify!\'', function() {
+// expect(ctrl.title).toEqual('AngularJS, Gulp, and Browserify! Written with keyboards and love!');
+// });
- it('should have a number variable equal to 1234', function() {
- expect(ctrl.number).toEqual(1234);
- });
-
- it('should have a title variable equal to \'AngularJS, Gulp, and Browserify!\'', function() {
- expect(ctrl.title).toEqual('AngularJS, Gulp, and Browserify! Written with keyboards and love!');
- });
-
-});
\ No newline at end of file
+// });
\ No newline at end of file
diff --git a/test/unit/directives/app-loading_spec.js b/test/unit/directives/app-loading_spec.js
new file mode 100644
index 0000000..d3903a4
--- /dev/null
+++ b/test/unit/directives/app-loading_spec.js
@@ -0,0 +1,39 @@
+/*global angular, module, browser*/
+
+'use strict';
+
+// describe('Unit: ExampleDirective', function() {
+
+// var element, scope;
+
+// beforeEach(function() {
+// spyOn(window, 'alert');
+// angular.mock.module('app');
+
+// angular.mock.inject(function($compile, $rootScope) {
+// scope = $rootScope;
+// element = angular.element('Sample Directive
');
+// scope.title = 'A sample title';
+// scope.message = 'It doesn\'t hurt.';
+// $compile(element)(scope);
+// scope.$digest();
+// });
+// });
+
+// it('should bind itself to the element', function() {
+// element.triggerHandler('click');
+// expect(window.alert).toHaveBeenCalledWith('Element clicked: It doesn\'t hurt.');
+// });
+
+// it('should update its bindings', function() {
+// scope.message = 'It hurts a bit.';
+// scope.$digest();
+// element.triggerHandler('click');
+// expect(window.alert).toHaveBeenCalledWith('Element clicked: It hurts a bit.');
+// });
+
+// it('should bind a title property to its template', function() {
+// expect(element.find('h1').text()).toBe('A sample title');
+// });
+
+// });
diff --git a/test/unit/directives/example_spec.js b/test/unit/directives/example_spec.js
deleted file mode 100644
index 8247493..0000000
--- a/test/unit/directives/example_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*global angular, module, browser*/
-
-'use strict';
-
-describe('Unit: ExampleDirective', function() {
-
- var element, scope;
-
- beforeEach(function() {
- spyOn(window, 'alert');
- angular.mock.module('app');
-
- angular.mock.inject(function($compile, $rootScope) {
- scope = $rootScope;
- element = angular.element('Sample Directive
');
- scope.title = 'A sample title';
- scope.message = 'It doesn\'t hurt.';
- $compile(element)(scope);
- scope.$digest();
- });
- });
-
- it('should bind itself to the element', function() {
- element.triggerHandler('click');
- expect(window.alert).toHaveBeenCalledWith('Element clicked: It doesn\'t hurt.');
- });
-
- it('should update its bindings', function() {
- scope.message = 'It hurts a bit.';
- scope.$digest();
- element.triggerHandler('click');
- expect(window.alert).toHaveBeenCalledWith('Element clicked: It hurts a bit.');
- });
-
- it('should bind a title property to its template', function() {
- expect(element.find('h1').text()).toBe('A sample title');
- });
-
-});
diff --git a/test/unit/directives/translate-language_spec.js b/test/unit/directives/translate-language_spec.js
new file mode 100644
index 0000000..d3903a4
--- /dev/null
+++ b/test/unit/directives/translate-language_spec.js
@@ -0,0 +1,39 @@
+/*global angular, module, browser*/
+
+'use strict';
+
+// describe('Unit: ExampleDirective', function() {
+
+// var element, scope;
+
+// beforeEach(function() {
+// spyOn(window, 'alert');
+// angular.mock.module('app');
+
+// angular.mock.inject(function($compile, $rootScope) {
+// scope = $rootScope;
+// element = angular.element('Sample Directive
');
+// scope.title = 'A sample title';
+// scope.message = 'It doesn\'t hurt.';
+// $compile(element)(scope);
+// scope.$digest();
+// });
+// });
+
+// it('should bind itself to the element', function() {
+// element.triggerHandler('click');
+// expect(window.alert).toHaveBeenCalledWith('Element clicked: It doesn\'t hurt.');
+// });
+
+// it('should update its bindings', function() {
+// scope.message = 'It hurts a bit.';
+// scope.$digest();
+// element.triggerHandler('click');
+// expect(window.alert).toHaveBeenCalledWith('Element clicked: It hurts a bit.');
+// });
+
+// it('should bind a title property to its template', function() {
+// expect(element.find('h1').text()).toBe('A sample title');
+// });
+
+// });
diff --git a/test/unit/filters/example_spec.js b/test/unit/filters/example_spec.js
deleted file mode 100644
index d339a0c..0000000
--- a/test/unit/filters/example_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/*global angular */
-
-'use strict';
-
-describe('Unit: ExampleFilter', function() {
-
- var $filter;
-
- beforeEach(function() {
- // instantiate the app module
- angular.mock.module('app');
-
- // mock the filter
- angular.mock.inject(function(_$filter_) {
- $filter = _$filter_;
- });
- });
-
- it('should replace the word "keyboard" with "leopard"', function() {
- var testString = 'computers are operated by keyboards';
- var resultString = $filter('ExampleFilter')(testString);
-
- expect(resultString).toEqual('computers are operated by leopards');
- });
-
-});
\ No newline at end of file
diff --git a/test/unit/filters/trim_spec.js b/test/unit/filters/trim_spec.js
new file mode 100644
index 0000000..436c8ce
--- /dev/null
+++ b/test/unit/filters/trim_spec.js
@@ -0,0 +1,39 @@
+describe('Trim Filter', function() {
+
+ var filter;
+
+ beforeEach(function() {
+ // instantiate the app module
+ angular.mock.module('app');
+ angular.mock.module('app.filters');
+
+ // mock the filter
+ angular.mock.inject(function(_$filter_) {
+ filter = _$filter_;
+ });
+
+ });
+
+ it('should strip whitespace from the beginning and end of a string', function() {
+ expect(filter('trim')(' a ')).toEqual('a');
+ expect(filter('trim')(' foo bar ')).toEqual('foo bar');
+ expect(filter('trim')(' ')).toEqual('');
+ });
+
+ it('should strip specific chars from the beginning and end of a string', function() {
+
+ expect(filter('trim')('__a__', '__')).toEqual('a');
+ expect(filter('trim')('//foo bar//', '//')).toEqual('foo bar');
+ expect(filter('trim')('barfoobar', 'bar')).toEqual('foo');
+ expect(filter('trim')('barfoobar', 'foo')).toEqual('barfoobar');
+
+ });
+
+ it('should get a !string and not touch it', function() {
+ expect(filter('trim')({})).toEqual({});
+ expect(filter('trim')([])).toEqual([]);
+ expect(filter('trim')(1)).toEqual(1);
+ expect(filter('trim')(!1)).toBeFalsy();
+ });
+
+});
\ No newline at end of file
diff --git a/test/unit/locale_spec.js b/test/unit/locale_spec.js
new file mode 100644
index 0000000..8507766
--- /dev/null
+++ b/test/unit/locale_spec.js
@@ -0,0 +1,27 @@
+/*global angular */
+
+'use strict';
+
+// describe('Unit: Constants', function() {
+
+// var constants;
+
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
+
+// // mock the directive
+// angular.mock.inject(function(_AppSettings_) {
+// constants = _AppSettings_;
+// });
+// });
+
+// it('should exist', function() {
+// expect(constants).toBeDefined();
+// });
+
+// it('should have an application name', function() {
+// expect(constants.appTitle).toEqual('Example Application');
+// });
+
+// });
\ No newline at end of file
diff --git a/test/unit/services/example_spec.js b/test/unit/services/example_spec.js
deleted file mode 100644
index fadce16..0000000
--- a/test/unit/services/example_spec.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*global angular */
-
-'use strict';
-
-describe('Unit: ExampleService', function() {
-
- var http, service;
-
- beforeEach(function() {
- // instantiate the app module
- angular.mock.module('app');
-
- // mock the service
- angular.mock.inject(function($httpBackend, ExampleService) {
- http = $httpBackend;
- service = ExampleService;
- });
- });
-
- it('should exist', function() {
- expect(service).toBeDefined();
- });
-
- it('should retrieve data', function(done) {
- http.expect('GET', 'apiPath').respond(201, {data: 1234});
-
- service.get().then(function(result) {
- expect(result).toEqual({data: 1234});
- }, function(error) {
- expect(error).toBeUndefined();
- }).then(done);
-
- http.flush();
- });
-});
diff --git a/test/unit/services/localization_spec.js b/test/unit/services/localization_spec.js
new file mode 100644
index 0000000..4eb0c18
--- /dev/null
+++ b/test/unit/services/localization_spec.js
@@ -0,0 +1,35 @@
+/*global angular */
+
+'use strict';
+
+// describe('Unit: ExampleService', function() {
+
+// var http, service;
+
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
+
+// // mock the service
+// angular.mock.inject(function($httpBackend, ExampleService) {
+// http = $httpBackend;
+// service = ExampleService;
+// });
+// });
+
+// it('should exist', function() {
+// expect(service).toBeDefined();
+// });
+
+// it('should retrieve data', function(done) {
+// http.expect('GET', 'apiPath').respond(201, {data: 1234});
+
+// service.get().then(function(result) {
+// expect(result).toEqual({data: 1234});
+// }, function(error) {
+// expect(error).toBeUndefined();
+// }).then(done);
+
+// http.flush();
+// });
+// });
diff --git a/test/unit/services/toolkit_spec.js b/test/unit/services/toolkit_spec.js
new file mode 100644
index 0000000..4eb0c18
--- /dev/null
+++ b/test/unit/services/toolkit_spec.js
@@ -0,0 +1,35 @@
+/*global angular */
+
+'use strict';
+
+// describe('Unit: ExampleService', function() {
+
+// var http, service;
+
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
+
+// // mock the service
+// angular.mock.inject(function($httpBackend, ExampleService) {
+// http = $httpBackend;
+// service = ExampleService;
+// });
+// });
+
+// it('should exist', function() {
+// expect(service).toBeDefined();
+// });
+
+// it('should retrieve data', function(done) {
+// http.expect('GET', 'apiPath').respond(201, {data: 1234});
+
+// service.get().then(function(result) {
+// expect(result).toEqual({data: 1234});
+// }, function(error) {
+// expect(error).toBeUndefined();
+// }).then(done);
+
+// http.flush();
+// });
+// });
diff --git a/test/unit/settings/config_spec.js b/test/unit/settings/config_spec.js
new file mode 100644
index 0000000..52def17
--- /dev/null
+++ b/test/unit/settings/config_spec.js
@@ -0,0 +1,26 @@
+// describe('Unit: ExampleCtrl', function() {
+
+// var ctrl;
+
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
+
+// angular.mock.inject(function($controller) {
+// ctrl = $controller('ExampleCtrl');
+// });
+// });
+
+// it('should exist', function() {
+// expect(ctrl).toBeDefined();
+// });
+
+// it('should have a number variable equal to 1234', function() {
+// expect(ctrl.number).toEqual(1234);
+// });
+
+// it('should have a title variable equal to \'AngularJS, Gulp, and Browserify!\'', function() {
+// expect(ctrl.title).toEqual('AngularJS, Gulp, and Browserify! Written with keyboards and love!');
+// });
+
+// });
\ No newline at end of file
diff --git a/test/unit/settings/constants_spec.js b/test/unit/settings/constants_spec.js
new file mode 100644
index 0000000..52def17
--- /dev/null
+++ b/test/unit/settings/constants_spec.js
@@ -0,0 +1,26 @@
+// describe('Unit: ExampleCtrl', function() {
+
+// var ctrl;
+
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
+
+// angular.mock.inject(function($controller) {
+// ctrl = $controller('ExampleCtrl');
+// });
+// });
+
+// it('should exist', function() {
+// expect(ctrl).toBeDefined();
+// });
+
+// it('should have a number variable equal to 1234', function() {
+// expect(ctrl.number).toEqual(1234);
+// });
+
+// it('should have a title variable equal to \'AngularJS, Gulp, and Browserify!\'', function() {
+// expect(ctrl.title).toEqual('AngularJS, Gulp, and Browserify! Written with keyboards and love!');
+// });
+
+// });
\ No newline at end of file
diff --git a/test/unit/settings/run_spec.js b/test/unit/settings/run_spec.js
new file mode 100644
index 0000000..647ff47
--- /dev/null
+++ b/test/unit/settings/run_spec.js
@@ -0,0 +1,18 @@
+describe('Settings Run', function() {
+
+ var scope;
+
+ beforeEach(function(){
+ angular.mock.module('app');
+
+ angular.mock.inject(function ($controller, $rootScope, _$httpBackend_) {
+ scope = $rootScope.$new();
+ });
+ });
+
+ it('should change page properties on $routeChangeSuccess', function() {
+ scope.$broadcast('$routeChangeSuccess');
+ console.log(scope.page);
+ });
+
+});
\ No newline at end of file
diff --git a/test/unit/toolkit_spec.js b/test/unit/toolkit_spec.js
new file mode 100644
index 0000000..30b6353
--- /dev/null
+++ b/test/unit/toolkit_spec.js
@@ -0,0 +1,27 @@
+/*global angular */
+
+'use strict';
+
+// describe('Toolkit Service', function() {
+
+// var constants;
+
+// beforeEach(function() {
+// // instantiate the app module
+// angular.mock.module('app');
+
+// // mock the directive
+// angular.mock.inject(function(_AppSettings_) {
+// constants = _AppSettings_;
+// });
+// });
+
+// it('should exist', function() {
+// expect(constants).toBeDefined();
+// });
+
+// it('should have an application name', function() {
+// expect(constants.appTitle).toEqual('Example Application');
+// });
+
+// });
\ No newline at end of file