├── blog
├── .gitattributes
├── public
├── admin
│ ├── code
│ │ ├── import
│ │ │ ├── import.styl
│ │ │ ├── import.js
│ │ │ └── import.controller.spec.js
│ │ ├── analytics
│ │ │ ├── analytics.styl
│ │ │ ├── analytics.js
│ │ │ ├── analytics.controller.spec.js
│ │ │ └── google-analytics-embed-customizations.js
│ │ ├── components
│ │ │ ├── camel-to-human
│ │ │ │ ├── camel-to-human.filter.js
│ │ │ │ └── camel-to-human.filter.spec.js
│ │ │ ├── date-picker
│ │ │ │ └── date-picker.directive.js
│ │ │ ├── mdl
│ │ │ │ └── mdl.directive.js
│ │ │ └── dialog
│ │ │ │ └── dialog.directive.js
│ │ ├── media
│ │ │ ├── media.styl
│ │ │ ├── media.js
│ │ │ ├── media.controller.spec.js
│ │ │ ├── media.jade
│ │ │ └── media.controller.js
│ │ ├── pages
│ │ │ ├── pages.js
│ │ │ ├── pages.styl
│ │ │ └── pages.controller.spec.js
│ │ ├── themes
│ │ │ ├── themes.js
│ │ │ ├── themes.controller.spec.js
│ │ │ └── themes.styl
│ │ ├── comments
│ │ │ ├── comments.js
│ │ │ ├── comments.controller.spec.js
│ │ │ └── comments.styl
│ │ ├── extensions
│ │ │ ├── extensions.js
│ │ │ ├── extensions.controller.spec.js
│ │ │ └── extensions.styl
│ │ ├── users
│ │ │ ├── users.js
│ │ │ └── users.controller.spec.js
│ │ ├── cms
│ │ │ ├── cms.js
│ │ │ ├── cms.controller.spec.js
│ │ │ └── cms.jade
│ │ └── account
│ │ │ ├── settings
│ │ │ ├── settings.controller.js
│ │ │ └── settings.jade
│ │ │ ├── account.js
│ │ │ └── login
│ │ │ └── login.styl
│ └── fonts
│ │ ├── FontAwesome.otf
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ └── fontawesome-webfont.woff2
├── app
│ ├── components
│ │ ├── mb-link
│ │ │ ├── mb-link.styl
│ │ │ └── mb-link.directive.js
│ │ ├── mb-choose-link
│ │ │ ├── mb-choose-link.styl
│ │ │ ├── mb-edit-link.service.js
│ │ │ ├── mb-edit-link.controller.js
│ │ │ └── mb-choose-link.directive.js
│ │ ├── mb-list-area
│ │ │ ├── mb-list-area.directive.spec.js
│ │ │ ├── mb-list-area.styl
│ │ │ ├── mb-list-area.jade
│ │ │ └── mb-list-area-directive.js
│ │ ├── mb-choose-icon
│ │ │ ├── mb-choose-icon.styl
│ │ │ └── mb-edit-icon.service.js
│ │ ├── meanbase-editable
│ │ │ ├── icons.png
│ │ │ ├── icons-2x.png
│ │ │ └── meanbase-editable.directive.spec.js
│ │ ├── mb-choose-image
│ │ │ └── mb-choose-image.styl
│ │ ├── mb-find-images-modal
│ │ │ ├── mb-find-images-modal.styl
│ │ │ ├── mb-find-image.modal.jade
│ │ │ ├── mb-find-images-modal.directive.spec.js
│ │ │ ├── mb-find-images-modal.directive.js
│ │ │ └── mb-find-image.service.js
│ │ ├── mb-list-selector
│ │ │ ├── mb-list-selector.jade
│ │ │ ├── mb-list-selector.styl
│ │ │ └── mb-list.modal.jade
│ │ ├── mb-edit-link
│ │ │ ├── mb-edit-link.styl
│ │ │ └── mb-edit-link.directive.js
│ │ ├── main
│ │ │ ├── main.jade
│ │ │ └── main.controller.spec.js
│ │ ├── mb-list-remove
│ │ │ ├── mb-list-remove.styl
│ │ │ └── mb-list-remove.directive.js
│ │ ├── mb-extension-edit
│ │ │ ├── mb-extension-edit.styl
│ │ │ ├── mb-extension-edit.directive.js
│ │ │ └── mb-extension-edit.modal.jade
│ │ ├── mb-edit-menu
│ │ │ ├── mb-edit-menu.styl
│ │ │ ├── mb-edit-menu.directive.js
│ │ │ └── mb-edit-menu.service.js
│ │ ├── mb-dynamic-html
│ │ │ ├── mb-dynamic-html.directive.js
│ │ │ └── mb-dynamic-html.directive.spec.js
│ │ ├── cms.headbar
│ │ │ ├── choose-link.modal.jade
│ │ │ └── editmodal.modal.jade
│ │ ├── mb-init-list
│ │ │ └── init-list.directive.js
│ │ ├── mb-recaptcha
│ │ │ └── mb-recaptcha.directive.js
│ │ ├── mb-icon
│ │ │ └── mb-icon.directive.js
│ │ ├── mb-grid-item
│ │ │ └── mb-grid-item.styl
│ │ ├── mb-add-menu-item
│ │ │ ├── mb-add-menu-item.service.js
│ │ │ ├── mb-add-menu-item.directive.js
│ │ │ └── mb-add-menu-item.controller.js
│ │ ├── mb-list-add
│ │ │ ├── mb-list-add.styl
│ │ │ └── mb-list-add.directive.js
│ │ └── mb-text
│ │ │ └── mb-text.styl
│ ├── robots.txt
│ ├── fonts
│ │ ├── FontAwesome.otf
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ └── fontawesome-webfont.woff2
│ └── app.styl
├── extensions
│ ├── mb-search
│ │ ├── search-form.styl
│ │ ├── mb-search-box-extension.html
│ │ ├── screenshot.png
│ │ ├── index.js
│ │ ├── search-form.html
│ │ └── search-form.directive.js
│ ├── md-selling-point-list
│ │ ├── selling-point-extension.html
│ │ ├── selling-point-list.styl
│ │ ├── index.js
│ │ ├── toggle-type.modal.html
│ │ ├── selling-point-list.directive.js
│ │ └── selling-point-list.html
│ ├── mb-subscribe
│ │ ├── index.js
│ │ └── subscribe-form-extension.jade
│ ├── md-bullet-point-list
│ │ ├── index.js
│ │ └── bullet-point-list-extension.html
│ └── .gitignore
├── themes
│ ├── meanbase-demo
│ │ ├── templates
│ │ │ ├── blog
│ │ │ │ ├── blog.styl
│ │ │ │ └── blog-screenshot.png
│ │ │ ├── archive
│ │ │ │ ├── archive.styl
│ │ │ │ ├── archive-screenshot.png
│ │ │ │ └── archive.controller.js
│ │ │ └── home
│ │ │ │ └── home-screenshot.png
│ │ ├── img
│ │ │ ├── dog.png
│ │ │ ├── ipad.png
│ │ │ ├── phones.png
│ │ │ ├── banner-bg.jpg
│ │ │ └── intro-bg.jpg
│ │ ├── screenshot.png
│ │ ├── theme.json
│ │ ├── index.js
│ │ ├── LICENSE
│ │ └── README.md
│ └── .gitignore
├── shared
│ ├── sortable
│ │ ├── sortable.jade
│ │ ├── sortable.directive.spec.js
│ │ ├── sortable.styl
│ │ └── sortable.directive.js
│ ├── missing
│ │ ├── missing.controller.js
│ │ ├── missing.js
│ │ ├── missing.jade
│ │ ├── missing.controller.spec.js
│ │ └── missing.styl
│ ├── taglist
│ │ ├── taglist.jade
│ │ ├── taglist.directive.spec.js
│ │ ├── taglist.styl
│ │ └── taglist.directive.js
│ ├── validate
│ │ ├── validate.jade
│ │ ├── validate.styl
│ │ └── validate.directive.spec.js
│ ├── htmlToPlainText
│ │ └── htmlToPlainText.filter.js
│ ├── api
│ │ ├── api.service.spec.js
│ │ └── api.service.js
│ ├── helpers
│ │ └── helpers.service.spec.js
│ ├── endpoints
│ │ └── endpoints.service.spec.js
│ ├── fallback-src
│ │ ├── fallback-src.directive.js
│ │ └── fallback-src.directive.spec.js
│ ├── ng-enter
│ │ ├── ng-enter.directive.js
│ │ └── ng-enter.directive.spec.js
│ ├── mongoose-error
│ │ └── mongoose-error.directive.js
│ ├── doubleClick
│ │ ├── doubleClick.directive.spec.js
│ │ └── doubleClick.directive.js
│ ├── mb-animate
│ │ ├── mb-animate.directive.spec.js
│ │ └── mb-animate.directive.js
│ ├── image-selector
│ │ └── image-selector.directive.spec.js
│ └── feathers
│ │ └── feathers.service.js
└── assets
│ └── .gitignore
├── meanbase-logo.png
├── Meanbase-Sidebar.png
├── data
└── .gitignore
├── Meanbase-Frontend.png
├── export
├── export
│ └── .gitignore
├── import
│ └── .gitignore
└── .gitignore
├── Meanbase-Themes-Page.png
├── meanbase-screenshot.png
├── .babelrc
├── .travis.yml
├── .dockerignore
├── src
├── hooks
│ ├── recaptcha.js
│ ├── owner-or-restrict-changes.js
│ ├── allow-upsert.js
│ ├── is-enabled.js
│ ├── if-password-then-hash.js
│ ├── has-permission.js
│ ├── delete-custom-data.js
│ ├── permission-or-restrict-changes.js
│ ├── is-target-enabled.js
│ ├── attach-permissions.js
│ ├── send-verification-email.js
│ ├── has-permission-or-restrict.js
│ └── filter-by-permission-or-restrict.js
├── middleware
│ ├── not-found-handler.js
│ ├── index.js
│ └── logger.js
├── index.js
├── services
│ ├── menus
│ │ ├── hooks
│ │ │ ├── object-to-array.js
│ │ │ └── array-to-object.js
│ │ └── index.js
│ ├── comments
│ │ ├── hooks
│ │ │ ├── prepend-slash.js
│ │ │ ├── is-approved.js
│ │ │ └── are-comments-permitted.js
│ │ ├── index.js
│ │ └── comments-model.js
│ ├── subscribe
│ │ └── hooks
│ │ │ └── index.js
│ ├── settings
│ │ ├── hooks
│ │ │ └── recompile-index.js
│ │ ├── index.js
│ │ └── settings-model.js
│ ├── email
│ │ ├── hooks
│ │ │ └── index.js
│ │ └── index.js
│ ├── ban
│ │ ├── index.js
│ │ └── ban-model.js
│ ├── wordpress-import
│ │ ├── index.js
│ │ ├── hooks
│ │ │ ├── index.js
│ │ │ └── convert-xml-to-json.js
│ │ ├── wordpress-import.service.js
│ │ └── unzip.js
│ ├── user
│ │ └── index.js
│ ├── pages
│ │ ├── index.js
│ │ └── hooks
│ │ │ ├── convert-for-incoming.js
│ │ │ └── notify-subscribers.js
│ ├── roles
│ │ ├── index.js
│ │ └── hooks
│ │ │ └── index.js
│ ├── authentication
│ │ └── hooks
│ │ │ └── index.js
│ ├── custom
│ │ ├── index.js
│ │ └── custom-model.js
│ ├── images
│ │ ├── index.js
│ │ ├── images-model.js
│ │ └── hooks
│ │ │ └── index.js
│ ├── themes
│ │ └── index.js
│ ├── staging
│ │ ├── index.js
│ │ ├── staging-model.js
│ │ └── hooks
│ │ │ └── index.js
│ ├── theme-uploads
│ │ ├── index.js
│ │ ├── theme-uploads.service.js
│ │ └── hooks
│ │ │ └── index.js
│ ├── extensions
│ │ ├── index.js
│ │ └── extensions-model.js
│ ├── import-export
│ │ └── hooks
│ │ │ └── index.js
│ ├── image-uploads
│ │ ├── image-uploads.service.js
│ │ └── hooks
│ │ │ └── index.js
│ ├── extension-uploads
│ │ ├── index.js
│ │ ├── extension-uploads.service.js
│ │ └── hooks
│ │ │ └── index.js
│ └── shared-content
│ │ ├── index.js
│ │ ├── shared-content-model.js
│ │ └── hooks
│ │ └── index.js
├── components
│ ├── patterns
│ │ └── index.js
│ ├── settings
│ │ └── index.js
│ └── seed
│ │ └── seed
│ │ ├── user.js
│ │ ├── menus.js
│ │ ├── comments.js
│ │ ├── extensions.js
│ │ └── themes.js
├── routes.js
└── app.js
├── test
├── services
│ ├── ban
│ │ └── index.test.js
│ ├── email
│ │ └── index.test.js
│ ├── menus
│ │ └── index.test.js
│ ├── pages
│ │ └── index.test.js
│ ├── roles
│ │ └── index.test.js
│ ├── user
│ │ └── index.test.js
│ ├── custom
│ │ └── index.test.js
│ ├── images
│ │ └── index.test.js
│ ├── themes
│ │ └── index.test.js
│ ├── comments
│ │ └── index.test.js
│ ├── settings
│ │ └── index.test.js
│ ├── extension
│ │ └── index.test.js
│ ├── extensions
│ │ └── index.test.js
│ ├── subscribe
│ │ └── index.test.js
│ ├── import-export
│ │ └── index.test.js
│ └── shared-content
│ │ └── index.test.js
└── app.test.js
├── nginx
├── Dockerfile
└── nginx.conf
├── docker-compose.dev.yml
├── nginx-prerender
├── Dockerfile
└── nginx.conf
├── update.sh
├── e2e
└── main
│ ├── main.po.js
│ └── main.spec.js
├── meanbase.dev.env
├── .editorconfig
├── Dockerfile.dev
├── gulp
├── document.js
├── test.js
├── admin
│ └── bower.js
└── app
│ └── bower.js
├── .gitignore
├── Dockerfile
├── views
└── admin.html
├── .yo-rc.json
└── docker-compose.yml
/blog:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
--------------------------------------------------------------------------------
/public/admin/code/import/import.styl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/app/components/mb-link/mb-link.styl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/extensions/mb-search/search-form.styl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/templates/blog/blog.styl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/app/components/mb-choose-link/mb-choose-link.styl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/templates/archive/archive.styl:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/app/components/mb-list-area/mb-list-area.directive.spec.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/app/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org
2 |
3 | User-agent: *
4 |
--------------------------------------------------------------------------------
/public/shared/sortable/sortable.jade:
--------------------------------------------------------------------------------
1 | div this is the sortable directive
--------------------------------------------------------------------------------
/public/extensions/mb-search/mb-search-box-extension.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/meanbase-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/meanbase-logo.png
--------------------------------------------------------------------------------
/Meanbase-Sidebar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/Meanbase-Sidebar.png
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 |
4 | # But not these files...
5 | !.gitignore
6 |
--------------------------------------------------------------------------------
/Meanbase-Frontend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/Meanbase-Frontend.png
--------------------------------------------------------------------------------
/export/export/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 | # But not these files...
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/export/import/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 | # But not these files...
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/Meanbase-Themes-Page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/Meanbase-Themes-Page.png
--------------------------------------------------------------------------------
/meanbase-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/meanbase-screenshot.png
--------------------------------------------------------------------------------
/public/assets/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
5 |
--------------------------------------------------------------------------------
/export/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 | # But not these files...
4 | !.gitignore
5 | !export/
6 | !import/
7 |
--------------------------------------------------------------------------------
/public/extensions/md-selling-point-list/selling-point-extension.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2017"],
3 | "plugins": ["transform-async-to-generator", "angularjs-annotate"]
4 | }
5 |
--------------------------------------------------------------------------------
/public/app/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/app/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/public/admin/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/admin/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/public/admin/code/analytics/analytics.styl:
--------------------------------------------------------------------------------
1 | #meanbase-analytics
2 | padding-top 1em
3 |
4 | button
5 | margin-top 0.5em
6 |
--------------------------------------------------------------------------------
/public/app/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/app/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/public/app/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/app/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/img/dog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/img/dog.png
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/img/ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/img/ipad.png
--------------------------------------------------------------------------------
/public/admin/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/admin/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/public/admin/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/admin/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/public/app/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/app/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/public/app/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/app/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/public/extensions/mb-search/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/extensions/mb-search/screenshot.png
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/img/phones.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/img/phones.png
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/screenshot.png
--------------------------------------------------------------------------------
/public/admin/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/admin/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/public/admin/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/admin/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/public/themes/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 |
4 | # But not these files...
5 | !.gitignore
6 | !meanbase-demo/**
7 | !meanbase-demo
8 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/img/banner-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/img/banner-bg.jpg
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/img/intro-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/img/intro-bg.jpg
--------------------------------------------------------------------------------
/public/app/components/mb-choose-icon/mb-choose-icon.styl:
--------------------------------------------------------------------------------
1 | .select-images-button
2 | margin-top 1em
3 |
4 | .inEditMode choose-icon
5 | cursor pointer
6 |
--------------------------------------------------------------------------------
/public/app/components/meanbase-editable/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/app/components/meanbase-editable/icons.png
--------------------------------------------------------------------------------
/public/shared/missing/missing.controller.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | angular.module('meanbaseApp')
4 | .controller('MissingCtrl', function ($scope) {
5 |
6 | });
7 |
--------------------------------------------------------------------------------
/public/shared/taglist/taglist.jade:
--------------------------------------------------------------------------------
1 | .tag-list
2 | span.tag(ng-repeat="tag in tags" ng-click="deleteTag(tag)") {{tag}}
3 | span.remove
4 | input(type="Text")
--------------------------------------------------------------------------------
/public/shared/validate/validate.jade:
--------------------------------------------------------------------------------
1 | div
2 | ng-transclude
3 | div.help-block.required This field is required.
4 | div.help-block.error {{errorMessage}}
--------------------------------------------------------------------------------
/public/app/components/mb-choose-image/mb-choose-image.styl:
--------------------------------------------------------------------------------
1 | .select-images-button
2 | margin-top 1em
3 |
4 | .inEditMode choose-image
5 | cursor pointer
6 |
--------------------------------------------------------------------------------
/public/app/components/meanbase-editable/icons-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/app/components/meanbase-editable/icons-2x.png
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '0.10'
4 | - '0.11'
5 | before_script:
6 | - npm install -g bower grunt-cli
7 | - bower install
8 | services: mongodb
--------------------------------------------------------------------------------
/public/app/components/mb-find-images-modal/mb-find-images-modal.styl:
--------------------------------------------------------------------------------
1 | .disable-click {
2 | pointer-events: none;
3 | }
4 |
5 | .enable-click {
6 | pointer-events: auto;
7 | }
8 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/templates/blog/blog-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/templates/blog/blog-screenshot.png
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/templates/home/home-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/templates/home/home-screenshot.png
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 |
4 | # But not these files...
5 | !.gitignore
6 | !.dockerignore
7 | !package.json
8 | !gulpfile.js
9 | !webpack.config.js
10 | !dist
11 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/templates/archive/archive-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codingfriend1/meanbase/HEAD/public/themes/meanbase-demo/templates/archive/archive-screenshot.png
--------------------------------------------------------------------------------
/public/app/components/mb-list-selector/mb-list-selector.jade:
--------------------------------------------------------------------------------
1 | .btn.btn-success.btn-block(ng-click="openModal()" ng-if="$root.editMode").mb-list-selector-btn
2 | i.fa.fa-plus.fa-lg
3 | //- span Add-ons
4 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/theme.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Jon Paul",
3 | "email": "codingfriend1@gmail.com",
4 | "title": "Meanbase Demo",
5 | "description": "A theme to demo meanbase functionality"
6 | }
--------------------------------------------------------------------------------
/src/hooks/recaptcha.js:
--------------------------------------------------------------------------------
1 | export default (options) => {
2 | return async (hook) => {
3 | try {
4 | Promise.resolve(hook);
5 | } catch(err) {
6 | Promise.reject(err);
7 | }
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/public/extensions/mb-subscribe/index.js:
--------------------------------------------------------------------------------
1 | // inject jade
2 | import "./subscribe-form-extension.jade";
3 | // end inject jade
4 |
5 | // inject js
6 | // end inject js
7 |
8 | // inject stylus
9 | // end inject stylus
10 |
--------------------------------------------------------------------------------
/src/hooks/owner-or-restrict-changes.js:
--------------------------------------------------------------------------------
1 | import errors from 'feathers-errors';
2 |
3 | export default options => {
4 | return hook => {
5 | if (!hook.params.provider) { return hook; }
6 |
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/public/shared/htmlToPlainText/htmlToPlainText.filter.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp').
2 | filter('htmlToPlainText', function() {
3 | return function(text) {
4 | return text ? String(text).replace(/<[^>]+>/gm, '') : '';
5 | };
6 | }
7 | );
8 |
--------------------------------------------------------------------------------
/src/middleware/not-found-handler.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const errors = require('feathers-errors');
4 |
5 | module.exports = function() {
6 | return function(req, res, next) {
7 | next(new errors.NotFound('Page not found'));
8 | };
9 | };
10 |
--------------------------------------------------------------------------------
/public/extensions/md-bullet-point-list/index.js:
--------------------------------------------------------------------------------
1 | // inject jade
2 | import "./bullet-point-list-extension.html";
3 | // end inject jade
4 |
5 | // inject js
6 | // end inject js
7 |
8 | // inject stylus
9 | // end inject stylus
10 |
11 | // It works
12 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const app = require('./app');
4 | const port = app.get('port');
5 | const server = app.listen(port);
6 |
7 | server.on('listening', () =>
8 | console.log(`Feathers application started on ${app.get('host')}:${port}`)
9 | );
10 |
--------------------------------------------------------------------------------
/src/hooks/allow-upsert.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | import errors from 'feathers-errors'
4 |
5 | export default options => {
6 | return hook => {
7 | if(hook.params) {
8 | hook.params = Object.assign({}, hook.params, {mongoose: {upsert: true} })
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/services/ban/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('ban service', function() {
7 | it('registered the bans service', () => {
8 | assert.ok(app.service('bans'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/email/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('email service', function() {
7 | it('registered the emails service', () => {
8 | assert.ok(app.service('emails'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/menus/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('menus service', function() {
7 | it('registered the menus service', () => {
8 | assert.ok(app.service('menus'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/pages/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('pages service', function() {
7 | it('registered the pages service', () => {
8 | assert.ok(app.service('pages'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/roles/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('roles service', function() {
7 | it('registered the roles service', () => {
8 | assert.ok(app.service('roles'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/user/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('user service', function() {
7 | it('registered the users service', () => {
8 | assert.ok(app.service('users'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/custom/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('custom service', function() {
7 | it('registered the customs service', () => {
8 | assert.ok(app.service('customs'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/images/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('images service', function() {
7 | it('registered the images service', () => {
8 | assert.ok(app.service('images'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/themes/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('themes service', function() {
7 | it('registered the themes service', () => {
8 | assert.ok(app.service('themes'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/templates/archive/archive.controller.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .controller('archiveCtrl', function ($scope, endpoints, api) {
3 | api.pages.find({ template: {$in: ['article', 'blog']} }).then(function(response) {
4 | $scope.posts = response;
5 | });
6 | });
7 |
--------------------------------------------------------------------------------
/test/services/comments/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('comments service', function() {
7 | it('registered the comments service', () => {
8 | assert.ok(app.service('comments'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/settings/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('settings service', function() {
7 | it('registered the settings service', () => {
8 | assert.ok(app.service('settings'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/extension/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('extension service', function() {
7 | it('registered the extensions service', () => {
8 | assert.ok(app.service('extensions'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/extensions/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('extensions service', function() {
7 | it('registered the extensions service', () => {
8 | assert.ok(app.service('extensions'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/test/services/subscribe/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('subscribe service', function() {
7 | it('registered the subscribes service', () => {
8 | assert.ok(app.service('subscribes'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/public/shared/missing/missing.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | angular.module('meanbaseApp')
4 | .config(function ($stateProvider) {
5 | $stateProvider
6 | .state('main.missing', {
7 | url: '/missing',
8 | templateUrl: require('./missing.jade'),
9 | controller: 'MissingCtrl'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/nginx/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx
2 |
3 | RUN rm -f /etc/nginx/nginx.conf
4 | COPY ./nginx.conf /etc/nginx/
5 |
6 | RUN rm -rf /etc/nginx/conf.d/*
7 | WORKDIR /etc/nginx/conf.d/
8 | COPY ./conf.d/ /etc/nginx/conf.d/
9 |
10 | RUN ln -sf /dev/stdout /var/log/nginx/access.log
11 | RUN ln -sf /dev/stderr /var/log/nginx/error.log
12 |
--------------------------------------------------------------------------------
/public/extensions/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything
2 | *
3 | # But not these files...
4 | !.gitignore
5 | !md-bullet-point-list/**
6 | !md-bullet-point-list
7 |
8 | !md-selling-point-list/**
9 | !md-selling-point-list
10 |
11 | !mb-search/**
12 | !mb-search
13 |
14 | !mb-subscribe/**
15 | !mb-subscribe
16 |
17 | .DS_Store
18 |
--------------------------------------------------------------------------------
/public/shared/missing/missing.jade:
--------------------------------------------------------------------------------
1 | .container.meanbase-404
2 | h1
3 | | Not found
4 | span :(
5 | p Sorry, but the page you were trying to view does not exist.
6 | p It looks like this was the result of either:
7 | ul
8 | li a mistyped address
9 | li an out-of-date link
10 | .text-center
11 | a(href="/") Home
12 |
--------------------------------------------------------------------------------
/test/services/import-export/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('import-export service', function() {
7 | it('registered the import-exports service', () => {
8 | assert.ok(app.service('import-exports'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/docker-compose.dev.yml:
--------------------------------------------------------------------------------
1 | db:
2 | image: mongo
3 | ports:
4 | - "27017"
5 | - "37017"
6 | command: --smallfiles
7 | web:
8 | build: .
9 | dockerfile: Dockerfile.dev
10 | ports:
11 | - "3030:3030"
12 | env_file:
13 | - meanbase.dev.env
14 | links:
15 | - db:db
16 | volumes:
17 | - .:/var/www
18 |
--------------------------------------------------------------------------------
/nginx-prerender/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx
2 |
3 | RUN rm -f /etc/nginx/nginx.conf
4 | COPY ./nginx.conf /etc/nginx/
5 |
6 | RUN rm -rf /etc/nginx/conf.d/*
7 | WORKDIR /etc/nginx/conf.d/
8 | COPY ./conf.d/ /etc/nginx/conf.d/
9 |
10 | RUN ln -sf /dev/stdout /var/log/nginx/access.log
11 | RUN ln -sf /dev/stderr /var/log/nginx/error.log
12 |
--------------------------------------------------------------------------------
/test/services/shared-content/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const app = require('../../../src/app');
5 |
6 | describe('shared-content service', function() {
7 | it('registered the shared-contents service', () => {
8 | assert.ok(app.service('shared-contents'));
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/public/admin/code/components/camel-to-human/camel-to-human.filter.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .filter('camelToHuman', function() {
3 | return function(input) {
4 | return input.charAt(0).toLowerCase() + input.substr(1).replace(/[A-Z]/g, function(x) {
5 | return ' ' + x.toLowerCase();
6 | });
7 | }
8 | });
9 |
--------------------------------------------------------------------------------
/public/admin/code/media/media.styl:
--------------------------------------------------------------------------------
1 | #meanbase-cms
2 | .drop-zone
3 | padding 1em
4 | background-color CLOUDS
5 | border 2px dashed CONCRETE
6 | p
7 | margin-bottom 0
8 | padding 0
9 |
10 | .progress
11 | margin-top 0.5em
12 | margin-bottom 0
13 | .nv-file-over
14 | background-color SILVER
15 | border-color CLOUDS
--------------------------------------------------------------------------------
/public/app/components/mb-edit-link/mb-edit-link.styl:
--------------------------------------------------------------------------------
1 | .mb-edit-link-btn
2 | position: absolute
3 | top: -20px
4 | right: 30px
5 | padding-top: 2px
6 | padding-left: 2px
7 | width: 35px
8 | height: 30px
9 | border-radius: 3px
10 | background-color: #95A5A6
11 | color: #ECF0F1
12 | cursor: pointer
13 | z-index: 2
14 |
--------------------------------------------------------------------------------
/public/app/components/main/main.jade:
--------------------------------------------------------------------------------
1 | .meanbase-front#mb-meanbase-front(ng-class="{loggedIn: isLoggedIn}")
2 | include ../cms.headbar/cms.headbar.jade
3 | div(ui-view="" ng-class="{'fixed-header-stopper': isLoggedIn}")#main-view
4 | div.mb-loading-screen.text-center
5 | h1
6 | i.fa.fa-spinner.fa-spin
7 | span| Loading Template
8 |
--------------------------------------------------------------------------------
/public/extensions/mb-search/index.js:
--------------------------------------------------------------------------------
1 | // inject jade
2 | import "./mb-search-box-extension.html";
3 | import "./search-form.html";
4 | // end inject jade
5 |
6 | // inject js
7 | import "./search-form.directive.js";
8 | // end inject js
9 |
10 | // inject stylus
11 | import "./search-form.styl";
12 | // end inject stylus
13 |
14 | // It works
15 |
--------------------------------------------------------------------------------
/public/shared/validate/validate.styl:
--------------------------------------------------------------------------------
1 | .has-error
2 | .help-block.error
3 | display block
4 | padding 6px
5 | .help-block.required
6 | display none
7 |
8 | .has-warning
9 | .help-block.required
10 | display block
11 | padding 6px
12 | .help-block.error
13 | display none
14 |
15 | .has-success
16 | .help-block
17 | display none
18 | padding 6px
--------------------------------------------------------------------------------
/public/admin/code/media/media.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.media', {
5 | url: '/media',
6 | templateUrl: require('./media.jade'),
7 | controller: 'MediaCtrl',
8 | hasPermission: 'manageMedia',
9 | icon: 'images'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/public/app/components/mb-list-remove/mb-list-remove.styl:
--------------------------------------------------------------------------------
1 | .remove-from-list-btn {
2 | position: absolute;
3 | top: -20px;
4 | right: -10px;
5 | padding-top: 2px;
6 | padding-left: 2px;
7 | width: 35px;
8 | height: 30px;
9 | border-radius: 3px;
10 | background-color: #E74C3C;
11 | color: #ECF0F1;
12 | cursor: pointer;
13 | z-index: 2;
14 | }
15 |
--------------------------------------------------------------------------------
/public/extensions/md-selling-point-list/selling-point-list.styl:
--------------------------------------------------------------------------------
1 | .md-toggle-type {
2 | position: absolute;
3 | top: -20px;
4 | right: 32px;
5 | padding-top: 5px;
6 | padding-left: 10px;
7 | width: 35px;
8 | height: 30px;
9 | border-radius: 3px;
10 | background-color: #95A5A6;
11 | color: #ECF0F1;
12 | cursor: pointer;
13 | z-index: 2;
14 | }
15 |
--------------------------------------------------------------------------------
/public/admin/code/pages/pages.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.pages', {
5 | url: '/pages',
6 | templateUrl: require('./pages.jade'),
7 | controller: 'PagesCtrl',
8 | hasPermission: 'editContent',
9 | icon: 'web_asset'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/public/app/components/mb-extension-edit/mb-extension-edit.styl:
--------------------------------------------------------------------------------
1 | .mb-edit-extension-btn {
2 | position: absolute;
3 | top: -20px;
4 | right: 0px;
5 | padding-top: 1px;
6 | padding-left: 7px;
7 | width: 35px;
8 | height: 30px;
9 | border-radius: 3px;
10 | background-color: #95A5A6;
11 | color: #ECF0F1;
12 | cursor: pointer;
13 | z-index: 2;
14 | }
15 |
--------------------------------------------------------------------------------
/src/services/menus/hooks/object-to-array.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import { objectOfArraysToArrayOfObjects } from '../../../components/utility';
3 |
4 | export default options => {
5 | return hook => {
6 |
7 | if (!hook.params.provider) { return hook; }
8 |
9 | hook.data = objectOfArraysToArrayOfObjects(hook.data);
10 | return hook;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/hooks/is-enabled.js:
--------------------------------------------------------------------------------
1 | export default (options) => {
2 | return hook => {
3 | if (!hook.params.provider) { return hook; }
4 | if(!hook.params.user) {
5 | throw new Error('Cannot check enabled of a non-existant user.');
6 | } else if(!hook.params.user.enabled) {
7 | throw new Error('Your account must be enabled to do that.');
8 | }
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/public/admin/code/themes/themes.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.themes', {
5 | url: '/themes',
6 | templateUrl: require('./themes.jade'),
7 | controller: 'ThemesCtrl',
8 | hasPermission: 'changeSiteSettings',
9 | icon: 'settings'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/public/admin/code/import/import.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.import', {
5 | url: '/import',
6 | templateUrl: require('./import.jade'),
7 | controller: 'ImportCtrl',
8 | hasPermission: "importExportData",
9 | icon: 'file_download'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/src/hooks/if-password-then-hash.js:
--------------------------------------------------------------------------------
1 | import errors from 'feathers-errors';
2 | const auth = require('feathers-authentication').hooks;
3 | export default options => {
4 | return hook => {
5 | if (!hook.params.provider) { return hook; }
6 |
7 | if(hook.data.password) {
8 | return auth.hashPassword()(hook);
9 | } else {
10 | return hook;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/public/admin/code/comments/comments.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.comments', {
5 | url: '/comments',
6 | templateUrl: require('./comments.jade'),
7 | controller: 'CommentsCtrl',
8 | hasPermission: 'moderateComments',
9 | icon: 'comment'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/public/admin/code/analytics/analytics.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.analytics', {
5 | url: '/analytics',
6 | templateUrl: require('./analytics.jade'),
7 | controller: 'AnalyticsCtrl',
8 | hasPermission: "viewAnalytics",
9 | icon: 'show_chart'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/public/app/components/mb-edit-menu/mb-edit-menu.styl:
--------------------------------------------------------------------------------
1 | .mb-edit-menu-btn
2 | // position: absolute
3 | display inline-block
4 | padding-top: 2px
5 | padding-left: 5px
6 | width: 22px
7 | height: 22px
8 | border-radius: 10em
9 | background-color: #95A5A6
10 | color: #ECF0F1
11 | cursor: pointer
12 | position absolute
13 | top 0
14 | right 0
15 | i
16 | color #ECF0F1
17 |
--------------------------------------------------------------------------------
/public/extensions/md-selling-point-list/index.js:
--------------------------------------------------------------------------------
1 | // inject jade
2 | import "./selling-point-extension.html";
3 | import "./selling-point-list.html";
4 | import "./toggle-type.modal.html";
5 | // end inject jade
6 |
7 | // inject js
8 | import "./selling-point-list.directive.js";
9 | // end inject js
10 |
11 | // inject stylus
12 | import "./selling-point-list.styl";
13 | // end inject stylus
14 |
--------------------------------------------------------------------------------
/public/shared/api/api.service.spec.js:
--------------------------------------------------------------------------------
1 | describe('Service: api', function () {
2 |
3 | // load the service's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | // instantiate service
7 | var api;
8 | beforeEach(inject(function (_api_) {
9 | api = _api_;
10 | }));
11 |
12 | it('should do something', function () {
13 | expect(!!api).toBe(true);
14 | });
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/public/admin/code/extensions/extensions.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.extensions', {
5 | url: '/extensions',
6 | templateUrl: require('./extensions.jade'),
7 | controller: 'ExtensionsCtrl',
8 | hasPermission: 'manageExtensions',
9 | icon: 'input'
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/public/admin/code/users/users.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.users', {
5 | url: '/users',
6 | templateUrl: require('./users.jade'),
7 | controller: 'UsersCtrl',
8 | controllerAs:'stateCtrl',
9 | hasPermission: 'manageUsers',
10 | icon: 'people'
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/public/app/components/mb-dynamic-html/mb-dynamic-html.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp').directive('mbDynamicHtml', function ($compile) {
2 | return {
3 | restrict: 'A',
4 | link: function (scope, element, attrs) {
5 | scope.$watch(attrs.mbDynamicHtml, function(html) {
6 | element.prepend(html);
7 | $compile(element.contents())(scope);
8 | })
9 | }
10 | };
11 | });
12 |
--------------------------------------------------------------------------------
/public/extensions/mb-subscribe/subscribe-form-extension.jade:
--------------------------------------------------------------------------------
1 | .well
2 | .input-group
3 | input#email.btn.btn-lg(type='email', placeholder='Your Email', required='true' ng-model="subscribeEmail")
4 | button.btn.btn-info.btn-lg(ng-click="subscribeEmail? $root.subscribe(subscribeEmail): null") Subscribe
5 | //- button.btn.btn-info.btn-lg(ng-click="subscribeEmail? $root.unsubscribe(subscribeEmail): null") Subscribe
6 |
--------------------------------------------------------------------------------
/public/shared/helpers/helpers.service.spec.js:
--------------------------------------------------------------------------------
1 | describe('Service: helpers', function () {
2 |
3 | // load the service's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | // instantiate service
7 | var helpers;
8 | beforeEach(inject(function (_helpers_) {
9 | helpers = _helpers_;
10 | }));
11 |
12 | it('should do something', function () {
13 | expect(!!helpers).toBe(true);
14 | });
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/src/services/comments/hooks/prepend-slash.js:
--------------------------------------------------------------------------------
1 | module.exports = options => {
2 | return (hook) => {
3 | if(hook.data && hook.data.url && hook.data.url.charAt(0) !== '/') {
4 | hook.data.url = '/' + hook.data.url;
5 | }
6 |
7 | if(hook.params.query && hook.params.query.url && hook.params.query.url.charAt(0) !== '/') {
8 | hook.params.query.url = '/' + hook.params.query.url;
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/patterns/index.js:
--------------------------------------------------------------------------------
1 | exports.isTitle = /^[A-Za-z0-9@:?&=.\/ _\-]*$/;
2 |
3 | exports.isURI = /(((http|https|ftp):\/\/([\w-\d]+\.)+[\w-\d]+){0,1}((\/|#)[\w~,;\-\.\/?%&+#=]*))/;
4 |
5 | exports.isFilePath = /^[0-9A-Za-z \/*_.\\\-]*$/;
6 |
7 | exports.isCSSClass = /^[A-Za-z0-9_ \-*]*$/;
8 |
9 | exports.isAnchorTarget = /^[_blank|_self|_parent|_top]*$/;
10 |
11 | exports.isText = /.*/;
12 |
13 | exports.isHTML = /.*/;
14 |
--------------------------------------------------------------------------------
/public/shared/endpoints/endpoints.service.spec.js:
--------------------------------------------------------------------------------
1 | describe('Service: endpoints', function () {
2 |
3 | // load the service's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | // instantiate service
7 | var endpoints;
8 | beforeEach(inject(function (_endpoints_) {
9 | endpoints = _endpoints_;
10 | }));
11 |
12 | it('should do something', function () {
13 | expect(!!endpoints).toBe(true);
14 | });
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/src/components/settings/index.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const express = require('express');
3 |
4 | module.exports = function() {
5 | const app = this;
6 |
7 | app.set('view engine', 'jade');
8 | app.use( express.static(app.get('clientPath')) );
9 |
10 | if(process.env.NODE_ENV !== 'production') {
11 | app.set('mongodb', process.env.DATABASE_URL || "mongodb://localhost:27017/meanbase-dev");
12 | }
13 |
14 | };
15 |
--------------------------------------------------------------------------------
/src/services/comments/hooks/is-approved.js:
--------------------------------------------------------------------------------
1 | module.exports = options => {
2 | return async hook => {
3 | let autoAccept;
4 | if(hook.data) {
5 | autoAccept = await hook.app.service('settings').find({query: {name: 'auto-accept-comments'}});
6 | } else {
7 | return Promise.resolve(hook);
8 | }
9 |
10 | if(autoAccept.length > 0) {
11 | hook.data.approved = autoAccept[0].value;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/public/admin/code/cms/cms.js:
--------------------------------------------------------------------------------
1 | // ### Parent route for backend.
2 | // - All routes for the admin interface have cms/ as their prefix
3 | angular.module('meanbaseApp')
4 | .config(function ($stateProvider) {
5 | $stateProvider
6 | .state('cms', {
7 | url: '/cms',
8 | templateUrl: require('./cms.jade'),
9 | controller: 'cmsCtrl',
10 | controllerAs: 'cms',
11 | authenticate: true
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/public/admin/code/components/date-picker/date-picker.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp').directive('datePicker', function($window) {
2 | return {
3 | restrict: 'A',
4 | scope: {
5 | options: '='
6 | },
7 | link: function(scope, element, attrs) {
8 | var options = Object.assign({
9 | time: false
10 | }, scope.options)
11 | element.bootstrapMaterialDatePicker(options);
12 | }
13 | };
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/update.sh:
--------------------------------------------------------------------------------
1 | # Stop server
2 | sudo nginx -s quit; pm2 stop all; sudo mongo 127.0.0.1/admin --eval "db.shutdownServer()";
3 |
4 | # Grab Updates
5 | git pull
6 | npm install
7 | sudo bower install --allow-root --config.interactive=false
8 | gulp build
9 | gulp injectBuild
10 | gulp build-themes
11 |
12 | export NODE_ENV=production
13 | # Start server
14 | sudo mongod --smallfiles --fork --logpath /var/log/mongodb.log; pm2 start dist/server/app.js; sudo nginx
15 |
--------------------------------------------------------------------------------
/public/shared/fallback-src/fallback-src.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('fallbackSrc', function () {
3 | return {
4 | template: '
',
5 | restrict: 'EA',
6 | link: function (scope, element, attrs) {
7 | if(attrs.fallbackSrc) {
8 | element.bind('error', function() {
9 | angular.element(this).attr("src", attrs.fallbackSrc);
10 | });
11 | }
12 | }
13 | };
14 | });
15 |
--------------------------------------------------------------------------------
/public/shared/ng-enter/ng-enter.directive.js:
--------------------------------------------------------------------------------
1 |
2 | angular.module('meanbaseApp')
3 | .directive('ngEnter', function () {
4 | return function (scope, element, attrs) {
5 | element.bind("keydown keypress", function (event) {
6 | if(event.which === 13) {
7 | scope.$apply(function (){
8 | scope.$eval(attrs.ngEnter);
9 | });
10 |
11 | event.preventDefault();
12 | }
13 | });
14 | };
15 | });
16 |
--------------------------------------------------------------------------------
/src/components/seed/seed/user.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(app) {
3 |
4 | // let email = process.env.ADMIN_EMAIL
5 | // let pass = process.env.ADMIN_PASS
6 | // let name = process.env.ADMIN_NAME
7 | // if(email && pass && name) {
8 | // let admin = {
9 | // "email": email,
10 | // "password": pass,
11 | // "name": name,
12 | // "role": "admin"
13 | // }
14 | // return admin;
15 | // }
16 |
17 | return undefined
18 | };
19 |
--------------------------------------------------------------------------------
/e2e/main/main.po.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file uses the Page Object pattern to define the main page for tests
3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ
4 | */
5 |
6 | 'use strict';
7 |
8 | var MainPage = function() {
9 | this.heroEl = element(by.css('.hero-unit'));
10 | this.h1El = this.heroEl.element(by.css('h1'));
11 | this.imgEl = this.heroEl.element(by.css('img'));
12 | };
13 |
14 | module.exports = new MainPage();
15 |
16 |
--------------------------------------------------------------------------------
/public/app/components/mb-list-area/mb-list-area.styl:
--------------------------------------------------------------------------------
1 | .mb-drag-to-room
2 | margin 0 0.5em 0.75em
3 | padding 1.5em 1em 0.5em
4 | background-color CLOUDS
5 | border 2px dashed SILVER
6 |
7 | .mb-drag-handle
8 | position: absolute
9 | top: -20px
10 | right: 32px
11 | padding-top: 5px
12 | padding-left: 10px
13 | width: 35px
14 | height: 30px
15 | border-radius: 3px
16 | background-color: #95A5A6
17 | color: #ECF0F1
18 | cursor move
19 | i
20 | cursor move
21 |
--------------------------------------------------------------------------------
/src/hooks/has-permission.js:
--------------------------------------------------------------------------------
1 | export default permissionName => {
2 | return hook => {
3 | if (!hook.params.provider) { return hook; }
4 | if(!hook.params.user) {
5 | throw new Error('Cannot check permissions of a non-existant user.');
6 | } else if (hook.params.user.permissions.indexOf(permissionName) === -1 && hook.params.user.permissions.indexOf('allPrivilages') === -1) {
7 | throw new Error('You must be a(n) ' + permissionName + ' to do that.');
8 | }
9 | };
10 | };
11 |
--------------------------------------------------------------------------------
/meanbase.dev.env:
--------------------------------------------------------------------------------
1 | NODE_ENV=developement
2 | DATABASE_URL=mongodb://db/meanbase-dev
3 | DATABASE_NAME=meanbase-dev
4 | RESET_SEED=false
5 | SEED=true
6 |
7 | # DOMAIN=your-domain.com
8 | # EMAIL_USER=your-gmail-username
9 | # EMAIL_PASS=your-gmail-password
10 | # EMAIL=your-gmail-email
11 | # MAILGUN_API_KEY=api-key
12 | # MAILGUN_DOMAIN=your-domain-name.com
13 | # MAILGUN_SUBSCRIPTION_EMAIL=the-mailing-list-email@your-service.com
14 | # ACCOUNT_EMAIL=the-from-email-for-your-mailing-list@your-service.com
15 |
--------------------------------------------------------------------------------
/public/admin/code/components/mdl/mdl.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp').directive('mdl', function($timeout) {
2 | return {
3 | restrict: 'A',
4 | compile: function() {
5 | return {
6 | post: function (scope, element) {
7 | // var el = element.get(0);
8 | var el = element;
9 | $timeout(function() {
10 | componentHandler.upgradeAllRegistered();
11 | }, 0, false);
12 | }
13 | };
14 | },
15 | };
16 | })
17 |
--------------------------------------------------------------------------------
/public/shared/mongoose-error/mongoose-error.directive.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | * Removes server error when user updates input
5 | */
6 | angular.module('meanbaseApp')
7 | .directive('mongooseError', function () {
8 | return {
9 | restrict: 'A',
10 | require: 'ngModel',
11 | link: function(scope, element, attrs, ngModel) {
12 | element.on('keydown', function() {
13 | return ngModel.$setValidity('mongoose', true);
14 | });
15 | }
16 | };
17 | });
18 |
--------------------------------------------------------------------------------
/src/middleware/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const handler = require('feathers-errors/handler');
4 | const notFound = require('./not-found-handler');
5 | const logger = require('./logger');
6 |
7 | module.exports = function() {
8 | // Add your custom middleware here. Remember, that
9 | // just like Express the order matters, so error
10 | // handling middleware should go last.
11 | const app = this;
12 |
13 | app.use(notFound());
14 | app.use(logger(app));
15 | app.use(handler());
16 | };
17 |
--------------------------------------------------------------------------------
/e2e/main/main.spec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | describe('Main View', function() {
4 | var page;
5 |
6 | beforeEach(function() {
7 | browser.get('/');
8 | page = require('./main.po');
9 | });
10 |
11 | it('should include jumbotron with correct data', function() {
12 | expect(page.h1El.getText()).toBe('\'Allo, \'Allo!');
13 | expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/);
14 | expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman');
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/services/subscribe/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const globalHooks = require('../../../hooks');
4 | const hooks = require('feathers-hooks');
5 |
6 |
7 | exports.before = {
8 | all: [],
9 | find: [],
10 | get: [],
11 | create: [
12 | hooks.disable('external')
13 | ],
14 | update: [],
15 | patch: [],
16 | remove: []
17 | };
18 |
19 | exports.after = {
20 | all: [],
21 | find: [],
22 | get: [],
23 | create: [],
24 | update: [],
25 | patch: [],
26 | remove: []
27 | };
28 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/public/app/components/mb-list-area/mb-list-area.jade:
--------------------------------------------------------------------------------
1 | div(ng-sortable="sortableLists" ng-class="{'mb-drag-to-room': $root.editMode && page.lists[areaName].length === 0}")
2 | div(ng-repeat="listItem in page.lists[areaName]" mb-dynamic-html="listItem.html" class="relative" ng-class="{'mb-draggable': $root.editMode}")
3 | //- mb-list-remove(list="page.lists[areaName]" item="listItem")
4 | //- div.mb-drag-handle(ng-if="$root.editMode")
5 | //- i.fa.fa-arrows
6 | mb-extension-edit(item="listItem")
7 | div(mb-list-selector="{{areaName}}")
8 |
--------------------------------------------------------------------------------
/public/admin/code/pages/pages.styl:
--------------------------------------------------------------------------------
1 | #meanbase-cms
2 | .mb-list-explanation
3 | position: relative
4 | padding 16px
5 | label
6 | display inline-block
7 |
8 | .mb-publish-label
9 | position: absolute
10 | right 40px
11 | .margin-top
12 | margin-top 1em
13 | .panel-group
14 | .panel
15 | overflow initial
16 | .commment-author
17 | padding-left 0.75em
18 | .date-field
19 | margin-bottom 0
20 | #moderate-comments
21 | .form-group
22 | .btn
23 | margin-right 0.5em
24 | margin-bottom 0.5em
25 |
--------------------------------------------------------------------------------
/public/admin/code/media/media.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: MediaCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var MediaCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | MediaCtrl = $controller('MediaCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/public/admin/code/users/users.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: UsersCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var UsersCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | UsersCtrl = $controller('UsersCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/public/admin/code/import/import.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: ImportCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var ImportCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | ImportCtrl = $controller('ImportCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/public/admin/code/themes/themes.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: ThemesCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var ThemesCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | ThemesCtrl = $controller('ThemesCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/public/admin/code/pages/pages.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: CommentsCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var CommentsCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | CommentsCtrl = $controller('CommentsCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/public/admin/code/comments/comments.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: CommentsCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var CommentsCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | CommentsCtrl = $controller('CommentsCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/public/admin/code/analytics/analytics.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: AnalyticsCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var AnalyticsCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | AnalyticsCtrl = $controller('AnalyticsCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/public/shared/missing/missing.controller.spec.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | describe('Controller: MissingCtrl', function () {
4 |
5 | // load the controller's module
6 | beforeEach(module('meanbaseApp'));
7 |
8 | var MissingCtrl, scope;
9 |
10 | // Initialize the controller and a mock scope
11 | beforeEach(inject(function ($controller, $rootScope) {
12 | scope = $rootScope.$new();
13 | MissingCtrl = $controller('MissingCtrl', {
14 | $scope: scope
15 | });
16 | }));
17 |
18 | it('should ...', function () {
19 | expect(1).toEqual(1);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/public/themes/meanbase-demo/index.js:
--------------------------------------------------------------------------------
1 | // inject jade
2 | import "./templates/blog/blog-template.html";
3 | import "./templates/archive/archive-template.html";
4 | import "./templates/home/home-template.html";
5 | // end inject jade
6 |
7 | // inject js
8 | import "./templates/archive/archive.controller.js";
9 | // end inject js
10 |
11 | // inject stylus
12 | import "./templates/archive/archive.styl";
13 | import "./templates/blog/blog.styl";
14 | import "./templates/blog/clean-blog.styl";
15 | import "./css/landing-page.css";
16 | // end inject stylus
17 |
18 | // it works
19 |
--------------------------------------------------------------------------------
/src/services/settings/hooks/recompile-index.js:
--------------------------------------------------------------------------------
1 |
2 | import compileIndex from '../../../components/compile-index';
3 | var contains = ['clientID', 'appID', 'verificationID', 'recaptchaClientKey', 'recaptchaKey'];
4 |
5 | module.exports = options => {
6 | const contains = options || ['clientID', 'appID', 'verificationID', 'recaptchaClientKey', 'recaptchaKey'];
7 | return hook => {
8 | if(hook.params.query && contains.indexOf(hook.params.query.name) > -1) {
9 | console.log('recompiling html views');
10 | compileIndex.call(hook.app);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/public/admin/code/cms/cms.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: CmsCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var CmsCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | CmsCtrl = $controller('CmsCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect('app').toEqual('test');
18 | expect(1).toEqual(1);
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/public/admin/code/extensions/extensions.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: ExtensionsCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var ExtensionsCtrl, scope;
7 |
8 | // Initialize the controller and a mock scope
9 | beforeEach(inject(function ($controller, $rootScope) {
10 | scope = $rootScope.$new();
11 | ExtensionsCtrl = $controller('ExtensionsCtrl', {
12 | $scope: scope
13 | });
14 | }));
15 |
16 | it('should ...', function () {
17 | expect(1).toEqual(1);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/Dockerfile.dev:
--------------------------------------------------------------------------------
1 | ############################################################
2 | # Dockerfile to build Meanbase
3 | # Based on Ubuntu
4 | ############################################################
5 |
6 | FROM codingfriend/meanbase
7 |
8 |
9 | ################## ESTABLISH DIRECTORIES ######################
10 | RUN rm -rf /var/www/
11 | WORKDIR /var/www/
12 | COPY ./package.json /var/www/
13 | RUN npm install
14 | COPY . /var/www/
15 | ################## END DIRECTORIES ######################
16 |
17 | # Expose the default port
18 | EXPOSE 3030
19 | VOLUME /var/www
20 |
21 | CMD ["npm", "start"]
22 |
--------------------------------------------------------------------------------
/gulp/document.js:
--------------------------------------------------------------------------------
1 | module.exports = function (gulp, plugins) {
2 | gulp.task('clear-docs', function () {
3 | return plugins.del('documentation/**');
4 | });
5 |
6 | gulp.task('document', ['clear-docs'], function(done) {
7 | // gulp.src([
8 | // 'client/{app, components}/**/*.js',
9 | // 'README.md',
10 | // 'server/**.js'
11 | // ])
12 | plugins.run("docker -i client/ --exclude bower_components,*spec.js,*.styl,*.jade,extensions,assets,themes,tasks,e2e,dist,.tmp,Gruntfile.js,gulpfile.js,karma.conf.js -o documentation -u -n --ignore_hidden").exec('', done);
13 | });
14 | };
--------------------------------------------------------------------------------
/public/shared/ng-enter/ng-enter.directive.spec.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | describe('Directive: ngEnter', function () {
4 |
5 | // load the directive's module
6 | beforeEach(module('meanbaseApp'));
7 |
8 | var element,
9 | scope;
10 |
11 | beforeEach(inject(function ($rootScope) {
12 | scope = $rootScope.$new();
13 | }));
14 |
15 | it('should make hidden element visible', inject(function ($compile) {
16 | element = angular.element('');
17 | element = $compile(element)(scope);
18 | expect(element.text()).toBe('this is the ngEnter directive');
19 | }));
20 | });
21 |
--------------------------------------------------------------------------------
/public/shared/doubleClick/doubleClick.directive.spec.js:
--------------------------------------------------------------------------------
1 | describe('Directive: doubleClick', function () {
2 |
3 | // load the directive's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var element,
7 | scope;
8 |
9 | beforeEach(inject(function ($rootScope) {
10 | scope = $rootScope.$new();
11 | }));
12 |
13 | it('should make hidden element visible', inject(function ($compile) {
14 | element = angular.element('');
15 | element = $compile(element)(scope);
16 | expect(element.text()).toBe('this is the doubleClick directive');
17 | }));
18 | });
19 |
--------------------------------------------------------------------------------
/public/shared/fallback-src/fallback-src.directive.spec.js:
--------------------------------------------------------------------------------
1 | describe('Directive: fallbackSrc', function () {
2 |
3 | // load the directive's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var element,
7 | scope;
8 |
9 | beforeEach(inject(function ($rootScope) {
10 | scope = $rootScope.$new();
11 | }));
12 |
13 | it('should make hidden element visible', inject(function ($compile) {
14 | element = angular.element('');
15 | element = $compile(element)(scope);
16 | expect(element.text()).toBe('this is the fallbackSrc directive');
17 | }));
18 | });
19 |
--------------------------------------------------------------------------------
/public/shared/mb-animate/mb-animate.directive.spec.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | describe('Directive: mb-animate', function () {
4 |
5 | // load the directive's module
6 | beforeEach(module('meanbaseApp'));
7 |
8 | var element,
9 | scope;
10 |
11 | beforeEach(inject(function ($rootScope) {
12 | scope = $rootScope.$new();
13 | }));
14 |
15 | it('should make hidden element visible', inject(function ($compile) {
16 | element = angular.element('');
17 | element = $compile(element)(scope);
18 | expect(element.text()).toBe('this is the mb-animate directive');
19 | }));
20 | });
21 |
--------------------------------------------------------------------------------
/public/admin/code/components/camel-to-human/camel-to-human.filter.spec.js:
--------------------------------------------------------------------------------
1 | describe('Filter: camelToHuman', function () {
2 |
3 | // load the filter's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | // initialize a new instance of the filter before each test
7 | var camelToHuman;
8 | beforeEach(inject(function ($filter) {
9 | camelToHuman = $filter('camelToHuman');
10 | }));
11 |
12 | it('should return the input prefixed with "camelToHuman filter:"', function () {
13 | var text = 'angularjs';
14 | expect(camelToHuman(text)).toBe('camelToHuman filter: ' + text);
15 | });
16 |
17 | });
18 |
--------------------------------------------------------------------------------
/src/services/menus/hooks/array-to-object.js:
--------------------------------------------------------------------------------
1 | export default options => {
2 | return hook => {
3 |
4 | if(!hook.params.provider && !hook.params.forceCall) { return hook; }
5 |
6 | if(hook.result && Array.isArray(hook.result) && hook.result.length > 0) {
7 | let allMenus = [].concat(hook.result), menus = {}, i = 0;
8 | while(i < allMenus.length) {
9 | if(menus[allMenus[i].group] === undefined) {
10 | menus[allMenus[i].group] = [];
11 | }
12 | menus[allMenus[i].group].push(allMenus[i]);
13 | i++;
14 | }
15 | hook.result = menus;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/public/app/components/mb-dynamic-html/mb-dynamic-html.directive.spec.js:
--------------------------------------------------------------------------------
1 | describe('Directive: dynamicHtml', function () {
2 |
3 | // load the directive's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var element,
7 | scope;
8 |
9 | beforeEach(inject(function ($rootScope) {
10 | scope = $rootScope.$new();
11 | }));
12 |
13 | it('should make hidden element visible', inject(function ($compile) {
14 | element = angular.element('');
15 | element = $compile(element)(scope);
16 | expect(element.text()).toBe('this is the dynamicHtml directive');
17 | }));
18 | });
19 |
--------------------------------------------------------------------------------
/public/extensions/mb-search/search-form.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
Pages with "{{searchString}}"
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/middleware/logger.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const winston = require('winston');
4 |
5 | module.exports = function(app) {
6 | // Add a logger to our app object for convenience
7 | app.logger = winston;
8 |
9 | return function(error, req, res, next) {
10 | if (error) {
11 | const message = `${error.code ? `(${error.code}) ` : '' }Route: ${req.url} - ${error.message}`;
12 |
13 | if (error.code === 404) {
14 | winston.info(message);
15 | }
16 | else {
17 | winston.error(message);
18 | winston.info(error.stack);
19 | }
20 | }
21 |
22 | next(error);
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/public/app/components/mb-find-images-modal/mb-find-image.modal.jade:
--------------------------------------------------------------------------------
1 | #findImage-modal.extensiondata-selector
2 | .modal-header
3 | button.close(ng-click="$dismiss()")
4 | span(aria-hidden="true") ×
5 | span.sr-only Close
6 | h4.modal-title {{instructions}}
7 | .modal-body
8 | mb-image-selector(api="imageSelectorApi" mb-image-selector-config="config")
9 | .modal-footer
10 | p.double-tap-instructions Double tap to enlarge photos
11 | div.choose-close-buttons
12 | button.btn.btn-success(type='button' ng-click="chooseImages()") Choose
13 | button.btn.btn-default(type='button' ng-click="$dismiss()") Close
14 |
--------------------------------------------------------------------------------
/public/app/components/mb-list-area/mb-list-area-directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('mbListArea', function ($rootScope) {
3 | return {
4 | templateUrl: require('./mb-list-area.jade'),
5 | restrict: 'A',
6 | scope: true,
7 | link: function (scope, element, attrs) {
8 | if(attrs.mbListArea) {
9 | scope.areaName = attrs.mbListArea || 'list1';
10 | if(!$rootScope.page.lists[scope.areaName]) {
11 | $rootScope.page.lists[scope.areaName] = [];
12 | }
13 |
14 | if(!$rootScope.currentUser) { return false }
15 | }
16 | }
17 | };
18 | });
19 |
--------------------------------------------------------------------------------
/public/app/components/meanbase-editable/meanbase-editable.directive.spec.js:
--------------------------------------------------------------------------------
1 | describe('Directive: meanbase-editable', function () {
2 |
3 | // load the directive's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var element,
7 | scope;
8 |
9 | beforeEach(inject(function ($rootScope) {
10 | scope = $rootScope.$new();
11 | }));
12 |
13 | it('should make hidden element visible', inject(function ($compile) {
14 | element = angular.element('');
15 | element = $compile(element)(scope);
16 | expect(element.text()).toBe('this is the meanbase-editable directive');
17 | }));
18 | });
19 |
--------------------------------------------------------------------------------
/public/app/components/cms.headbar/choose-link.modal.jade:
--------------------------------------------------------------------------------
1 | .modal-header
2 | button.close(type='button' ng-click="cancel()")
3 | span(aria-hidden='true') ×
4 | span.sr-only Close
5 | h4.modal-title Choose your page link name
6 | .modal-body
7 | .form-group
8 | label Link Title
9 | .input-group
10 | span.input-group-addon /
11 | input.form-control(type='text' ng-model="url" autofocus ng-enter="choose(url)")
12 | span.glyphicon.glyphicon-ok.form-control-feedback
13 | .modal-footer
14 | button.btn.btn-default(type='button' ng-click="cancel()") Close
15 | button.btn.btn-success(type='button' ng-click="choose(url)") Choose
16 |
--------------------------------------------------------------------------------
/public/app/components/mb-edit-menu/mb-edit-menu.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('mbEditMenu', function ($rootScope, endpoints, $timeout, editMenuModal) {
3 | return {
4 | template: '',
5 | restrict: 'EA',
6 | link: function (scope, element, attrs) {
7 | scope.item = scope.$eval(attrs.item)
8 |
9 | element.bind('click', function(event) {
10 | scope.item = scope.$eval(attrs.item)
11 | editMenuModal.open(event, scope.item)
12 | })
13 | }
14 | }
15 |
16 | })
17 |
--------------------------------------------------------------------------------
/src/services/email/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const globalHooks = require('../../../hooks');
4 | const hooks = require('feathers-hooks');
5 | const auth = require('feathers-authentication').hooks;
6 |
7 | exports.before = {
8 | all: [
9 | hooks.disable('external')
10 | // auth.verifyToken(),
11 | // auth.populateUser(),
12 | // auth.restrictToAuthenticated()
13 | ],
14 | find: [],
15 | get: [],
16 | create: [],
17 | update: [],
18 | patch: [],
19 | remove: []
20 | };
21 |
22 | exports.after = {
23 | all: [],
24 | find: [],
25 | get: [],
26 | create: [],
27 | update: [],
28 | patch: [],
29 | remove: []
30 | };
31 |
--------------------------------------------------------------------------------
/public/shared/taglist/taglist.directive.spec.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | describe('Directive: taglist', function () {
4 |
5 | // load the directive's module and view
6 | beforeEach(module('meanbaseApp'));
7 | beforeEach(module('components/taglist/taglist.html'));
8 |
9 | var element, scope;
10 |
11 | beforeEach(inject(function ($rootScope) {
12 | scope = $rootScope.$new();
13 | }));
14 |
15 | it('should make hidden element visible', inject(function ($compile) {
16 | element = angular.element('');
17 | element = $compile(element)(scope);
18 | scope.$apply();
19 | expect(element.text()).toBe('this is the taglist directive');
20 | }));
21 | });
22 |
--------------------------------------------------------------------------------
/public/shared/validate/validate.directive.spec.js:
--------------------------------------------------------------------------------
1 |
2 | describe('Directive: validate', function () {
3 |
4 | // load the directive's module and view
5 | beforeEach(module('meanbaseApp'));
6 | beforeEach(module('components/validate/validate.html'));
7 |
8 | var element, scope;
9 |
10 | beforeEach(inject(function ($rootScope) {
11 | scope = $rootScope.$new();
12 | }));
13 |
14 | it('should make hidden element visible', inject(function ($compile) {
15 | element = angular.element('');
16 | element = $compile(element)(scope);
17 | scope.$apply();
18 | expect(element.text()).toBe('this is the validate directive');
19 | }));
20 | });
21 |
--------------------------------------------------------------------------------
/public/shared/sortable/sortable.directive.spec.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | describe('Directive: sortable', function () {
4 |
5 | // load the directive's module and view
6 | beforeEach(module('meanbaseApp'));
7 | beforeEach(module('components/sortable/sortable.html'));
8 |
9 | var element, scope;
10 |
11 | beforeEach(inject(function ($rootScope) {
12 | scope = $rootScope.$new();
13 | }));
14 |
15 | it('should make hidden element visible', inject(function ($compile) {
16 | element = angular.element('');
17 | element = $compile(element)(scope);
18 | scope.$apply();
19 | expect(element.text()).toBe('this is the sortable directive');
20 | }));
21 | });
22 |
--------------------------------------------------------------------------------
/src/services/ban/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const ban = require('./ban-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: ban,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/bans', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const banService = app.service('/bans');
20 |
21 | // Set up our before hooks
22 | banService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | banService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/wordpress-import/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import WordpressImportService from './wordpress-import.service';
4 | const hooks = require('./hooks');
5 | import unzip from './unzip';
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | app.use('/wordpress-import',
11 | unzip,
12 | new WordpressImportService()
13 | );
14 |
15 | // Get our initialize service to that we can bind hooks
16 | const wordpressImportService = app.service('/wordpress-import');
17 | //
18 | // // Set up our before hooks
19 | wordpressImportService.before(hooks.before);
20 | //
21 | // // Set up our after hooks
22 | wordpressImportService.after(hooks.after);
23 | };
24 |
--------------------------------------------------------------------------------
/src/services/user/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const user = require('./user-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: user,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/users', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const userService = app.service('/users');
20 |
21 | // Set up our before hooks
22 | userService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | userService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/menus/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const menus = require('./menus-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: menus,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/menus', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const menusService = app.service('/menus');
20 |
21 | // Set up our before hooks
22 | menusService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | menusService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/pages/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const pages = require('./pages-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: pages,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/pages', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const pagesService = app.service('/pages');
20 |
21 | // Set up our before hooks
22 | pagesService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | pagesService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/roles/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const roles = require('./roles-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: roles,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/roles', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const rolesService = app.service('/roles');
20 |
21 | // Set up our before hooks
22 | rolesService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | rolesService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/authentication/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const globalHooks = require('../../../hooks');
4 | const hooks = require('feathers-hooks');
5 | const auth = require('feathers-authentication').hooks;
6 |
7 | const permissionName = 'manageUsers';
8 |
9 | exports.before = {
10 | all: [],
11 | find: [
12 |
13 | ],
14 | get: [
15 |
16 | ],
17 | create: [
18 | globalHooks.isTargetEnabled(),
19 | ],
20 | update: [
21 |
22 | ],
23 | patch: [
24 |
25 | ],
26 | remove: [
27 |
28 | ]
29 | };
30 |
31 | exports.after = {
32 | all: [
33 | ],
34 | find: [
35 | ],
36 | get: [
37 | ],
38 | create: [
39 | ],
40 | update: [],
41 | patch: [],
42 | remove: []
43 | };
44 |
--------------------------------------------------------------------------------
/src/services/custom/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const custom = require('./custom-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: custom,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/custom', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const customService = app.service('/custom');
20 |
21 | // Set up our before hooks
22 | customService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | customService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/images/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const images = require('./images-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: images,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/images', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const imagesService = app.service('/images');
20 |
21 | // Set up our before hooks
22 | imagesService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | imagesService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/themes/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const themes = require('./themes-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: themes,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/themes', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const themesService = app.service('/themes');
20 |
21 | // Set up our before hooks
22 | themesService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | themesService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/staging/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const staging = require('./staging-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: staging,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/staging', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const stagingService = app.service('/staging');
20 |
21 | // Set up our before hooks
22 | stagingService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | stagingService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/public/shared/image-selector/image-selector.directive.spec.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | describe('Directive: imageSelector', function () {
4 |
5 | // load the directive's module and view
6 | beforeEach(module('meanbaseApp'));
7 | beforeEach(module('components/image-selector/image-selector.html'));
8 |
9 | var element, scope;
10 |
11 | beforeEach(inject(function ($rootScope) {
12 | scope = $rootScope.$new();
13 | }));
14 |
15 | it('should make hidden element visible', inject(function ($compile) {
16 | element = angular.element('');
17 | element = $compile(element)(scope);
18 | scope.$apply();
19 | expect(element.text()).toBe('this is the imageSelector directive');
20 | }));
21 | });
22 |
--------------------------------------------------------------------------------
/src/hooks/delete-custom-data.js:
--------------------------------------------------------------------------------
1 | import errors from 'feathers-errors'
2 |
3 | export default type => {
4 | return hook => {
5 | if (!hook.params.provider) { return hook; }
6 |
7 | if(!hook.result) { return hook; }
8 |
9 | let results = hook.result;
10 | if(!Array.isArray(hook.result)) {
11 | results = [hook.result];
12 | }
13 |
14 | for (var i = 0; i < results.length; i++) {
15 | if(type === 'theme') {
16 | hook.app.service('custom').remove(null, { query: {belongsTo: results[i].title} });
17 | } else if (type === 'extension') {
18 | hook.app.service('custom').remove(null, { query: {belongsTo: results[i].name} });
19 | }
20 | }
21 | return hook;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/services/settings/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const settings = require('./settings-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: settings,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/settings', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const settingsService = app.service('/settings');
20 |
21 | // Set up our before hooks
22 | settingsService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | settingsService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/theme-uploads/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import ThemeUploadsService from './theme-uploads.service';
4 | const hooks = require('./hooks');
5 | import unzip from '../../hooks/unzip'
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | app.use('/theme-uploads',
11 | unzip({folderPathProperty: 'themesPath', setProperty: 'themeUrl'}),
12 | new ThemeUploadsService()
13 | );
14 |
15 | // Get our initialize service to that we can bind hooks
16 | const themeUploadsService = app.service('/theme-uploads');
17 | //
18 | // // Set up our before hooks
19 | themeUploadsService.before(hooks.before);
20 | //
21 | // // Set up our after hooks
22 | themeUploadsService.after(hooks.after);
23 | };
24 |
--------------------------------------------------------------------------------
/public/admin/code/media/media.jade:
--------------------------------------------------------------------------------
1 | .mdl-grid
2 | .mdl-cell.mdl-cell--12-col
3 | div.drop-zone(nv-file-drop="uploader" nv-file-over multiple uploader="uploader").text-center.form-inline
4 | p Drop files here to upload or
5 | .form-group.text-center
6 | input#file.form-control(type='file' nv-file-select multiple uploader="uploader" style="display: none")
7 | label.mdl-button.mdl-js-button.mdl-button--fab.mdl-button--colored.file-upload-btn(for="file")
8 | i.material-icons add
9 | .progress
10 | .progress-bar(role="progressbar" ng-style="{ 'width': uploader.progress + '%' }")
11 | .mdl-grid
12 | .mdl-cell.mdl-cell--12-col
13 | mb-image-selector(mb-image-selector-config="imageSelectorConfig")
14 |
--------------------------------------------------------------------------------
/public/app/components/mb-choose-link/mb-edit-link.service.js:
--------------------------------------------------------------------------------
1 | (() => {
2 |
3 | @mbService()
4 |
5 | class linkModal {
6 |
7 | constructor($rootScope, $modal) {
8 | this.$rootScope = $rootScope
9 | this.$modal = $modal
10 | }
11 |
12 | @autobind
13 | open(belongsTo, property) {
14 | if(!belongsTo || !property) { return false }
15 | var modalInstance = this.$modal.open({
16 | templateUrl: require('./mb-edit-link.modal.jade'),
17 | controller: require('./mb-edit-link.controller.js'),
18 | size: 'md',
19 | resolve: {
20 | link: function() {
21 | return belongsTo[property]
22 | },
23 | }
24 | })
25 | }
26 | }
27 |
28 | })()
29 |
--------------------------------------------------------------------------------
/public/app/components/mb-find-images-modal/mb-find-images-modal.directive.spec.js:
--------------------------------------------------------------------------------
1 | describe('Directive: findImagesModal', function () {
2 |
3 | // load the directive's module and view
4 | beforeEach(module('meanbaseApp'));
5 | beforeEach(module('components/find-images-modal/find-images-modal.html'));
6 |
7 | var element, scope;
8 |
9 | beforeEach(inject(function ($rootScope) {
10 | scope = $rootScope.$new();
11 | }));
12 |
13 | it('should make hidden element visible', inject(function ($compile) {
14 | element = angular.element('');
15 | element = $compile(element)(scope);
16 | scope.$apply();
17 | expect(element.text()).toBe('this is the findImagesModal directive');
18 | }));
19 | });
20 |
--------------------------------------------------------------------------------
/src/services/extensions/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const extensions = require('./extensions-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: extensions,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/extensions', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const extensionsService = app.service('/extensions');
20 |
21 | // Set up our before hooks
22 | extensionsService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | extensionsService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/import-export/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const globalHooks = require('../../../hooks');
4 | const hooks = require('feathers-hooks');
5 | const auth = require('feathers-authentication').hooks;
6 |
7 | exports.before = {
8 | all: [
9 | auth.verifyToken(),
10 | auth.populateUser(),
11 | auth.restrictToAuthenticated(),
12 | globalHooks.attachPermissions(),
13 | globalHooks.isEnabled(),
14 | globalHooks.hasPermission('importExportData')
15 | ],
16 | find: [],
17 | get: [],
18 | create: [
19 | ],
20 | update: [],
21 | patch: [],
22 | remove: []
23 | };
24 |
25 | exports.after = {
26 | all: [],
27 | find: [],
28 | get: [],
29 | create: [],
30 | update: [],
31 | patch: [],
32 | remove: []
33 | };
34 |
--------------------------------------------------------------------------------
/public/extensions/mb-search/search-form.directive.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This directive uses the slug passed in to get the appropriate images and display them in a slider
4 |
5 | angular.module('extensions')
6 | .directive('searchForm', function (endpoints, $rootScope, helpers, api) {
7 | return {
8 | templateUrl: require('./search-form.html'),
9 | restrict: 'EA',
10 | link: function (scope, element, attrs) {
11 | scope.searchString = '';
12 | scope.search = function() {
13 | api.pages.find({ $text: { $search: scope.searchString} }).then(function(response) {
14 | scope.results = !_.isEmpty(response)? response: [{url: '', title: 'No results'}];
15 | });
16 | };
17 | }
18 | };
19 | });
20 |
--------------------------------------------------------------------------------
/public/shared/sortable/sortable.styl:
--------------------------------------------------------------------------------
1 | .wobble
2 | -webkit-animation wiggle 0.4s ease infinite
3 | animation wiggle 0.4s ease infinite
4 | @-webkit-keyframes wiggle
5 | 0%
6 | -webkit-transform rotateZ(4deg)
7 | 50%
8 | -webkit-transform rotateZ(-4deg)
9 | 100%
10 | -webkit-transform rotateZ(4deg)
11 | @-moz-keyframes wiggle
12 | 0%
13 | -moz-transform rotateZ(4deg)
14 | 50%
15 | -moz-transform rotateZ(-4deg)
16 | 100%
17 | -moz-transform rotateZ(4deg)
18 | @-o-keyframes wiggle
19 | 0%
20 | -o-transform rotateZ(4deg)
21 | 50%
22 | -o-transform rotateZ(-4deg)
23 | 100%
24 | -o-transform rotateZ(4deg)
25 | @keyframes wiggle
26 | 0%
27 | transform rotateZ(4deg)
28 | 50%
29 | transform rotateZ(-4deg)
30 | 100%
31 | transform rotateZ(4deg)
--------------------------------------------------------------------------------
/src/hooks/permission-or-restrict-changes.js:
--------------------------------------------------------------------------------
1 | import errors from 'feathers-errors';
2 |
3 | export default (permissionName, options) => {
4 | return (hook) => {
5 | if (!hook.params.provider) { return hook; }
6 |
7 | if(!hook.params.user || (hook.params.user.permissions.indexOf(permissionName) === -1 && hook.params.user.permissions.indexOf('allPrivilages') === -1) ) {
8 | for (var i = 0; i < options.restrictOn.length; i++) {
9 | if(hook.data[options.restrictOn[i]] !== undefined && hook.data[options.restrictOn[i]] !== null) {
10 | return Promise.reject(new errors.Forbidden('You are not permitted to update the ' + options.restrictOn[i] + ' field.'));
11 | }
12 | }
13 | return Promise.resolve(hook);
14 | }
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/src/services/staging/staging-model.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // staging-model.js - A mongoose model
4 | //
5 | // See http://mongoosejs.com/docs/models.html
6 | // for more of what you can do here.
7 |
8 | const mongoose = require('mongoose');
9 | const Schema = mongoose.Schema;
10 |
11 | const stagingSchema = new Schema({
12 | belongsTo: { type: String, required: false, trim: true, default: '' },
13 | key: { type: String, required: true},
14 | data: Schema.Types.Mixed,
15 | createdAt: { type: Date, 'default': Date.now },
16 | updatedAt: { type: Date, 'default': Date.now }
17 | });
18 |
19 | stagingSchema.index({belongsTo: 1, key: 1}, {unique: true});
20 |
21 | const stagingModel = mongoose.model('staging', stagingSchema);
22 |
23 | module.exports = stagingModel;
24 |
--------------------------------------------------------------------------------
/src/services/image-uploads/image-uploads.service.js:
--------------------------------------------------------------------------------
1 |
2 | export default class ImageUploadService {
3 |
4 | setup(app) {
5 | this.app = app;
6 | }
7 |
8 | create(data, params) {
9 | return new Promise((resolve, reject) => {
10 | const destination = params.file.destination.replace(this.app.get('clientPath'), '');
11 |
12 | data = {
13 | url: destination,
14 | filename: params.file.filename,
15 | galleries: data.galleries? [data.galleries]: []
16 | };
17 |
18 | this.app.service('images').create(data).then(function(found) {
19 | resolve(found);
20 | }).catch(function(err) {
21 | console.log("error uploading image", err);
22 | reject(err);
23 | });
24 | });
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/services/extension-uploads/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import ExtensionUploadsService from './extension-uploads.service';
4 | const hooks = require('./hooks');
5 | import unzip from '../../hooks/unzip'
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | app.use('/extension-uploads',
11 | unzip({folderPathProperty: 'extensionsPath', setProperty: 'extensionUrl'}),
12 | new ExtensionUploadsService()
13 | );
14 |
15 | // Get our initialize service to that we can bind hooks
16 | const extensionUploadsService = app.service('/extension-uploads');
17 | //
18 | // // Set up our before hooks
19 | extensionUploadsService.before(hooks.before);
20 | //
21 | // // Set up our after hooks
22 | extensionUploadsService.after(hooks.after);
23 | };
24 |
--------------------------------------------------------------------------------
/src/services/theme-uploads/theme-uploads.service.js:
--------------------------------------------------------------------------------
1 | import feathersErrors from 'feathers-errors'
2 | import _ from 'lodash'
3 |
4 | export default class ImageUploadService {
5 |
6 | setup(app) {
7 | this.app = app;
8 | }
9 |
10 | create(data, params) {
11 | return new Promise((resolve, reject) => {
12 | if(data && !_.isEmpty(data)) {
13 | this.app.service('themes').create(data).then(function(found) {
14 | return resolve(found);
15 | }).catch(function(err) {
16 | console.log("error uploading theme", err);
17 | return reject(err);
18 | });
19 | } else {
20 | return reject(new feathersErrors.Unprocessable('The theme did not have a valid theme content.'));
21 | }
22 | });
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/public/admin/code/account/settings/settings.controller.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .controller('SettingsCtrl', function ($scope, Auth, toastr) {
3 | $scope.errors = {};
4 |
5 | $scope.changePassword = function(form) {
6 | $scope.submitted = true;
7 | if(form.$valid) {
8 | Auth.changePassword( $scope.user.oldPassword, $scope.user.newPassword )
9 | .then( function() {
10 | toastr.success('Successfully changed password');
11 | $scope.message = 'Password successfully changed.';
12 | })
13 | .catch( function() {
14 | form.password.$setValidity('mongoose', false);
15 | $scope.errors.other = 'Incorrect password';
16 | $scope.message = '';
17 | });
18 | }
19 | };
20 | });
21 |
--------------------------------------------------------------------------------
/src/services/shared-content/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const sharedContent = require('./shared-content-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: sharedContent,
12 | lean: true
13 | };
14 |
15 | // Initialize our service with any options it requires
16 | app.use('/shared-content', service(options));
17 |
18 | // Get our initialize service to that we can bind hooks
19 | const sharedContentService = app.service('/shared-content');
20 |
21 | // Set up our before hooks
22 | sharedContentService.before(hooks.before);
23 |
24 | // Set up our after hooks
25 | sharedContentService.after(hooks.after);
26 | };
27 |
--------------------------------------------------------------------------------
/src/services/staging/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const globalHooks = require('../../../hooks');
4 | const hooks = require('feathers-hooks');
5 | const auth = require('feathers-authentication').hooks;
6 |
7 | exports.before = {
8 | all: [
9 | auth.verifyToken(),
10 | auth.populateUser(),
11 | auth.restrictToAuthenticated(),
12 | globalHooks.attachPermissions(),
13 | globalHooks.isEnabled(),
14 | globalHooks.hasPermission('editContent'),
15 | ],
16 | find: [],
17 | get: [],
18 | create: [],
19 | update: [],
20 | patch: [
21 | globalHooks.allowUpsert()
22 | ],
23 | remove: []
24 | };
25 |
26 | exports.after = {
27 | all: [],
28 | find: [],
29 | get: [],
30 | create: [],
31 | update: [],
32 | patch: [],
33 | remove: []
34 | };
35 |
--------------------------------------------------------------------------------
/public/app/components/mb-init-list/init-list.directive.js:
--------------------------------------------------------------------------------
1 |
2 | angular.module('meanbaseApp')
3 | .directive('mbInitList', function ($rootScope, $timeout) {
4 | return {
5 | restrict: 'A',
6 | scope: {
7 | mbInitList: '='
8 | },
9 | link: function (scope, element, attrs) {
10 | function checkForEmpty() {
11 | if(!scope.mbInitList) {
12 | scope.mbInitList = {
13 | items: []
14 | };
15 | }
16 |
17 | if(!scope.mbInitList.items) {
18 | scope.mbInitList.items = [];
19 | }
20 | }
21 |
22 | checkForEmpty()
23 |
24 | scope.$onRootScope('cms.updateView', function() {
25 | checkForEmpty()
26 | })
27 | }
28 | };
29 | });
30 |
--------------------------------------------------------------------------------
/src/services/ban/ban-model.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // ban-model.js - A mongoose model
4 | //
5 | // See http://mongoosejs.com/docs/models.html
6 | // for more of what you can do here.
7 |
8 | const mongoose = require('mongoose');
9 | const Schema = mongoose.Schema;
10 | const patterns = require('../../components/patterns');
11 | const validators = require('mongoose-validators');
12 |
13 | const banSchema = new Schema({
14 | email: {
15 | type: String,
16 | lowercase: true,
17 | unique: true,
18 | validate: validators.isEmail({skipEmpty:true})
19 | },
20 | ip: {
21 | type: String,
22 | trim: true,
23 | validate: validators.isIP({skipEmpty: true})
24 | }
25 | });
26 |
27 | const banModel = mongoose.model('ban', banSchema);
28 |
29 | module.exports = banModel;
30 |
--------------------------------------------------------------------------------
/src/services/comments/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const service = require('feathers-mongoose');
4 | const comments = require('./comments-model');
5 | const hooks = require('./hooks');
6 |
7 | module.exports = function() {
8 | const app = this;
9 |
10 | const options = {
11 | Model: comments,
12 | lean: true,
13 | paginate: {
14 | default: 30
15 | }
16 | };
17 |
18 | // Initialize our service with any options it requires
19 | app.use('/comments', service(options));
20 |
21 | // Get our initialize service to that we can bind hooks
22 | const commentsService = app.service('/comments');
23 |
24 | // Set up our before hooks
25 | commentsService.before(hooks.before);
26 |
27 | // Set up our after hooks
28 | commentsService.after(hooks.after);
29 | };
30 |
--------------------------------------------------------------------------------
/src/services/email/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const hooks = require('./hooks');
4 |
5 | import Mailer from 'feathers-mailer'
6 | import smtpTransport from 'nodemailer-smtp-transport'
7 |
8 | module.exports = function(){
9 | const app = this;
10 |
11 | // Initialize our service with any options it requires
12 | app.use('/emails', Mailer(smtpTransport({
13 | service: 'gmail',
14 | auth: {
15 | user: process.env.EMAIL_USER,
16 | pass: process.env.EMAIL_PASS
17 | }
18 | })));
19 |
20 | // Get our initialize service to that we can bind hooks
21 | const emailService = app.service('/emails');
22 |
23 | // Set up our before hooks
24 | emailService.before(hooks.before);
25 |
26 | // Set up our after hooks
27 | emailService.after(hooks.after);
28 | };
29 |
--------------------------------------------------------------------------------
/src/services/theme-uploads/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import examineTheme from './examine-theme';
4 |
5 | const globalHooks = require('../../../hooks');
6 | const hooks = require('feathers-hooks');
7 | const auth = require('feathers-authentication').hooks;
8 |
9 | const permissionName = 'changeSiteSettings';
10 |
11 | exports.before = {
12 | create: [
13 | auth.verifyToken(),
14 | auth.populateUser(),
15 | auth.restrictToAuthenticated(),
16 | globalHooks.attachPermissions(),
17 | globalHooks.isEnabled(),
18 | globalHooks.hasPermission(permissionName),
19 | examineTheme()
20 | ]
21 | };
22 |
23 | exports.after = {
24 | all: [],
25 | find: [],
26 | get: [],
27 | create: [
28 |
29 | ],
30 | update: [],
31 | patch: [],
32 | remove: []
33 | };
34 |
--------------------------------------------------------------------------------
/public/app/components/mb-recaptcha/mb-recaptcha.directive.js:
--------------------------------------------------------------------------------
1 | // Handles starting up and shutting down the inline text editors and syncing up changes with the model when edits are saved
2 | angular.module('meanbaseApp')
3 | .directive('mbRecaptcha', function ($sanitize, $rootScope) {
4 | return {
5 | restrict: 'E',
6 | template: '',
7 | scope: {
8 | field: '=ngModel'
9 | },
10 | link: function (scope, element, attrs, ctrl) {
11 | scope.recaptchaClientKey = window.meanbaseGlobals.recaptchaClientKey;
12 |
13 | scope.setResponse = function(response) {
14 | scope.field = response;
15 | }
16 | }
17 | };
18 | });
19 |
--------------------------------------------------------------------------------
/public/admin/code/account/account.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .config(function ($stateProvider) {
3 | $stateProvider
4 | .state('cms.account', {
5 | url: '/account',
6 | templateUrl: require('./login/login.jade'),
7 | controller: 'LoginCtrl',
8 | icon: 'assignment_ind'
9 | })
10 | .state('cms.accountVerify', {
11 | url: '/account/:action/:token',
12 | templateUrl: require('./login/login.jade'),
13 | controller: 'LoginCtrl',
14 | hide: true,
15 | })
16 | .state('cms.my-settings', {
17 | url: '/my-settings',
18 | templateUrl: require('./settings/settings.jade'),
19 | controller: 'SettingsCtrl',
20 | authenticate: true,
21 | icon: 'verified_user'
22 | })
23 | });
24 |
--------------------------------------------------------------------------------
/src/services/extension-uploads/extension-uploads.service.js:
--------------------------------------------------------------------------------
1 | import feathersErrors from 'feathers-errors'
2 | import _ from 'lodash'
3 |
4 | export default class ImageUploadService {
5 |
6 | setup(app) {
7 | this.app = app;
8 | }
9 |
10 | create(data, params) {
11 | return new Promise((resolve, reject) => {
12 | if(data && !_.isEmpty(data)) {
13 | this.app.service('extensions').create(data).then(function(found) {
14 | return resolve(found);
15 | }).catch(function(err) {
16 | console.log("error uploading theme", err);
17 | return reject(err);
18 | });
19 | } else {
20 | return reject(new feathersErrors.Unprocessable('The extension did not have a valid extension content.'));
21 | }
22 |
23 | });
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/services/extension-uploads/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import examineExtension from './examine-extension';
4 |
5 | const globalHooks = require('../../../hooks');
6 | const hooks = require('feathers-hooks');
7 | const auth = require('feathers-authentication').hooks;
8 |
9 | const permissionName = 'changeSiteSettings';
10 |
11 | exports.before = {
12 | create: [
13 | auth.verifyToken(),
14 | auth.populateUser(),
15 | auth.restrictToAuthenticated(),
16 | globalHooks.attachPermissions(),
17 | globalHooks.isEnabled(),
18 | globalHooks.hasPermission(permissionName),
19 | examineExtension()
20 | ]
21 | };
22 |
23 | exports.after = {
24 | all: [],
25 | find: [],
26 | get: [],
27 | create: [
28 |
29 | ],
30 | update: [],
31 | patch: [],
32 | remove: []
33 | };
34 |
--------------------------------------------------------------------------------
/src/services/image-uploads/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import resize from './resize';
4 |
5 | const globalHooks = require('../../../hooks');
6 | const hooks = require('feathers-hooks');
7 | const auth = require('feathers-authentication').hooks;
8 | const dauria = require('dauria');
9 |
10 | const permissionName = 'manageMedia';
11 |
12 | exports.before = {
13 | create: [
14 | auth.verifyToken(),
15 | auth.populateUser(),
16 | auth.restrictToAuthenticated(),
17 | globalHooks.attachPermissions(),
18 | globalHooks.isEnabled(),
19 | globalHooks.hasPermission(permissionName),
20 | resize()
21 | ]
22 | };
23 |
24 | exports.after = {
25 | all: [],
26 | find: [],
27 | get: [],
28 | create: [
29 |
30 | ],
31 | update: [],
32 | patch: [],
33 | remove: []
34 | };
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | public/admin/bower_components
4 | public/admin/*.png
5 | public/app/*.png
6 | public/app/*.svg
7 | public/admin/public/fonts
8 | public/app/public/fonts
9 | public/app/bower_components
10 | public/admin/bundle.js
11 | public/admin/index.html
12 | public/admin/bundle.js.map
13 | public/admin/bower.js
14 | public/app/bower.js
15 | public/app/index.html
16 | public/app/bundle.js
17 | public/app/bundle.js.map
18 | public/themes/*/theme.min.js
19 | public/themes/*/theme.min.js.map
20 | public/old-app/
21 | public/old-app/**
22 | server/logs/debug.log
23 | .vscode
24 | .tmp
25 | old-server
26 | .idea
27 | bower_components
28 | documentation
29 | dist
30 | !gulp/build/dist.js
31 | /server/config/local.env.js
32 | __MACOSX
33 | code-documentation
34 | meanbase.env
35 | environment.env
36 |
--------------------------------------------------------------------------------
/public/app/components/mb-icon/mb-icon.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('mbIcon', function ($rootScope, endpoints, $compile) {
3 | return {
4 | template: '',
5 | restrict: 'E',
6 | scope: true,
7 | replace: true,
8 | link: function (scope, element, attrs) {
9 | scope.belongsTo = scope.$parent.$eval(attrs.belongsTo);
10 |
11 | if(!scope.belongsTo) { scope.belongsTo = {}; }
12 | scope.property = attrs.property;
13 |
14 | if(scope.belongsTo[scope.property].classes === 'fa fa-pencil fa-lg example') {
15 | scope.belongsTo[scope.property].classes = '';
16 | }
17 | }
18 | }
19 | });
20 |
--------------------------------------------------------------------------------
/src/services/settings/settings-model.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // settings-model.js - A mongoose model
4 | //
5 | // See http://mongoosejs.com/docs/models.html
6 | // for more of what you can do here.
7 |
8 | const mongoose = require('mongoose');
9 | const Schema = mongoose.Schema;
10 | const patterns = require('../../components/patterns');
11 | const validators = require('mongoose-validators');
12 |
13 | const settingsSchema = new Schema({
14 | name: {
15 | type: String,
16 | trim: true,
17 | required: true,
18 | unique: true,
19 | validate: validators.matches(patterns.isTitle)
20 | },
21 | value: {
22 | type: Schema.Types.Mixed,
23 | required: true
24 | }
25 | });
26 |
27 | const settingsModel = mongoose.model('settings', settingsSchema);
28 |
29 | module.exports = settingsModel;
30 |
--------------------------------------------------------------------------------
/public/app/components/mb-edit-link/mb-edit-link.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('mbEditLink', function ($rootScope, endpoints, $timeout) {
3 | return {
4 | template: '
',
5 | restrict: 'EA',
6 | link: function (scope, element, attrs) {
7 |
8 | if(!$rootScope.isLoggedIn) { return false }
9 |
10 | element.bind('click', function(event) {
11 | scope.belongsTo = scope.$eval(attrs.belongsTo)
12 | if(!scope.belongsTo) { scope.belongsTo = {} }
13 | if(!scope.belongsTo[attrs.property]) { scope.belongsTo[attrs.property] = {} }
14 | scope.openLinkModal(scope.belongsTo, attrs.property)
15 | })
16 | }
17 | }
18 |
19 | })
20 |
--------------------------------------------------------------------------------
/public/admin/code/components/dialog/dialog.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('dialogOpen', function ($rootScope, $timeout) {
3 | return {
4 | restrict: 'A',
5 | scope: {
6 | dialogOpen:'='
7 | },
8 | link: function (scope, element, attrs) {
9 | var el = element.get(0);
10 |
11 | // dialogPolyfill.registerDialog(el);
12 |
13 | // scope.$watch('dialogOpen', function(value, oldValue) {
14 | // if(value) {
15 | // $timeout(function() {
16 | // el.showModal();
17 | // });
18 | // } else if(value !== undefined) {
19 | // $timeout(function() {
20 | // el.close();
21 | // });
22 | // }
23 | // });
24 | } //link
25 | }; //return
26 | });
27 |
--------------------------------------------------------------------------------
/public/app/components/mb-grid-item/mb-grid-item.styl:
--------------------------------------------------------------------------------
1 | .inEditMode [mb-grid-item]
2 | position relative
3 | box-shadow 2px 2px 2px 1px rgba(0, 0, 0, 0.2)
4 |
5 | // .inEditMode [mb-grid-item] .ui-resizable-handlebefore
6 | // content "\f0dc"
7 |
8 | .inEditMode [mb-grid-item] .ui-resizable-handle
9 | position absolute
10 | font normal normal normal 20px/1 FontAwesome
11 | color black
12 | display block
13 | background-color transparent
14 | left 100%
15 | top 50%
16 | width 12px
17 | height 100%
18 | // -webkit-transform translate(-50%, -50%) rotate(90deg)
19 | // transform translate(-50%, -50%) rotate(90deg)
20 | // -ms-transform translate(-50%, -50%) rotate(90deg)
21 |
22 | -webkit-transform translate(-50%, -50%)
23 | transform translate(-50%, -50%)
24 | -ms-transform translate(-50%, -50%)
25 | cursor col-resize
26 |
--------------------------------------------------------------------------------
/public/app/components/main/main.controller.spec.js:
--------------------------------------------------------------------------------
1 | describe('Controller: MainCtrl', function () {
2 |
3 | // load the controller's module
4 | beforeEach(module('meanbaseApp'));
5 |
6 | var MainCtrl,
7 | scope,
8 | $httpBackend;
9 |
10 | // Initialize the controller and a mock scope
11 | beforeEach(inject(function (_$httpBackend_, $controller, $rootScope) {
12 | $httpBackend = _$httpBackend_;
13 | $httpBackend.expectGET('/api/things')
14 | .respond(['HTML5 Boilerplate', 'AngularJS', 'Karma', 'Express']);
15 |
16 | scope = $rootScope.$new();
17 | MainCtrl = $controller('MainCtrl', {
18 | $scope: scope
19 | });
20 | }));
21 |
22 | it('should attach a list of things to the scope', function () {
23 | $httpBackend.flush();
24 | expect(scope.awesomeThings.length).toBe(4);
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/public/app/components/mb-add-menu-item/mb-add-menu-item.service.js:
--------------------------------------------------------------------------------
1 | (() => {
2 |
3 | @mbService()
4 |
5 | class addMenuModal {
6 |
7 | constructor($rootScope, $modal) {
8 | this.$rootScope = $rootScope
9 | this.$modal = $modal
10 | }
11 |
12 | @autobind
13 | open(belongsTo, property) {
14 | if(!belongsTo || !property || !belongsTo[property]) { return false }
15 |
16 | var modalInstance = this.$modal.open({
17 | templateUrl: require('./mb-add-menu-item.modal.jade'),
18 | controller: require('./mb-add-menu-item.controller.js'),
19 | size: 'md',
20 | resolve: {
21 | property: function() {
22 | return property
23 | },
24 | menu: function() {
25 | return belongsTo
26 | }
27 | }
28 | })
29 | }
30 | }
31 |
32 | })()
33 |
--------------------------------------------------------------------------------
/public/app/components/mb-extension-edit/mb-extension-edit.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('mbExtensionEdit', function ($rootScope, endpoints, $timeout, $modal, editExtensionModal) {
3 | return {
4 | template: '
',
5 | restrict: 'EA',
6 | scope: true,
7 | link: function (scope, element, attrs) {
8 |
9 | if(!$rootScope.isLoggedIn) { return false; }
10 |
11 | var item = scope.$parent.$eval(attrs.item);
12 |
13 | element.bind('click', function() {
14 | console.log('click modal');
15 | editExtensionModal.open(item)
16 | });
17 |
18 | // scope.$on('$destroy', function() {
19 | // element.unbind('click')
20 | // })
21 | }
22 | }
23 |
24 | });
25 |
--------------------------------------------------------------------------------
/src/hooks/is-target-enabled.js:
--------------------------------------------------------------------------------
1 | import errors from 'feathers-errors';
2 |
3 | export default (options) => {
4 | return async hook => {
5 |
6 | if(!hook.params.provider) { return Promise.resolve(hook); }
7 |
8 | if(!hook.data.email) {
9 | return Promise.resolve(hook);
10 | }
11 |
12 | try {
13 | const found = await hook.app.service('users').find({query: {email: hook.data.email}});
14 | if(found.length > 0) {
15 | if(found[0].enabled) {
16 | return Promise.resolve(hook);
17 | } else {
18 | return Promise.reject(new errors.Forbidden('This user is not enabled'));
19 | }
20 | } else {
21 | return Promise.reject(new errors.Forbidden('Could not find this user.'));
22 | }
23 | } catch(err) {
24 | console.log('Checking user enabled error', err);
25 | }
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/services/wordpress-import/hooks/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import importWordpress from './import-wordpress';
4 | import convertXmlToJson from './convert-xml-to-json'
5 |
6 | const globalHooks = require('../../../hooks');
7 | const hooks = require('feathers-hooks');
8 | const auth = require('feathers-authentication').hooks;
9 |
10 | const permissionName = 'manageContent';
11 |
12 | exports.before = {
13 | create: [
14 | auth.verifyToken(),
15 | auth.populateUser(),
16 | auth.restrictToAuthenticated(),
17 | globalHooks.attachPermissions(),
18 | globalHooks.isEnabled(),
19 | globalHooks.hasPermission(permissionName),
20 | convertXmlToJson(),
21 | importWordpress()
22 | ]
23 | };
24 |
25 | exports.after = {
26 | all: [],
27 | find: [],
28 | get: [],
29 | create: [],
30 | update: [],
31 | patch: [],
32 | remove: []
33 | };
34 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ############################################################
2 | # Dockerfile to build Meanbase
3 | # Based on Ubuntu
4 | ############################################################
5 |
6 | FROM codingfriend/meanbase
7 |
8 | RUN npm install --global npm-install-que
9 |
10 | ################## ESTABLISH DIRECTORIES ######################
11 | RUN rm -rf /var/www/
12 | WORKDIR /var/www/
13 | # COPY dist/package.json /var/www/
14 | ENV NODE_ENV=production
15 | # RUN npm-install-que --production
16 | # RUN npm config set jobs 1
17 | # RUN npm install feathers express passport prerender-node
18 | # RUN npm install
19 | COPY dist/ /var/www/
20 | ################## END DIRECTORIES ######################
21 |
22 | # Expose the default port
23 | EXPOSE 8080
24 | VOLUME /var/www
25 |
26 | # CMD ["pm2", "start", "src", "--no-daemon"]
27 | CMD ["pm2", "start", "src", "--no-daemon"]
28 |
--------------------------------------------------------------------------------
/public/admin/code/account/login/login.styl:
--------------------------------------------------------------------------------
1 | // Social buttons
2 | // --------------------------------------------------
3 |
4 | .btn-facebook
5 | color: #fff;
6 | background-color: #3B5998;
7 | border-color: #133783;
8 |
9 | .btn-twitter
10 | color: #fff;
11 | background-color: #2daddc;
12 | border-color: #0271bf;
13 |
14 | .btn-google-plus
15 | color: #fff;
16 | background-color: #dd4b39;
17 | border-color: #c53727;
18 |
19 | .btn-github
20 | color: #fff;
21 | background-color: #fafafa;
22 | border-color: #ccc;
23 |
24 | .margin-center
25 | margin 2em auto
26 |
27 | .mdl-color--primary
28 | background-color #34495e !important
29 | color #ECF0F1
30 |
31 | #meanbase-cms
32 | .mdl-card__supporting-text
33 | margin auto
34 |
35 | .btn-inverse:not(.btn-link):not(.btn-flat)
36 | background-color #34495e
37 | color #ECF0F1
38 |
--------------------------------------------------------------------------------
/src/components/seed/seed/menus.js:
--------------------------------------------------------------------------------
1 | var home = {
2 | "title": "Home",
3 | "url": "/",
4 | "position": 0,
5 | "group": "main"
6 | };
7 |
8 | var tutorial = {
9 | "title": "Tutorial",
10 | "url": "/tutorial",
11 | "position": 0
12 | };
13 |
14 | var login = {
15 | "title": "Login",
16 | "url": "/login",
17 | "group": "rightHand",
18 | "position": 1
19 | };
20 |
21 | var youtubeDemo = {
22 | "title": "Youtube Demo",
23 | "url": "https://www.youtube.com/watch?v=tteztXru4eA&feature=youtu.be",
24 | "group": "sidebar",
25 | "position": 0
26 | };
27 |
28 | var article = {
29 | "title": "Why a CMS?",
30 | "url": "/why-cms",
31 | "group": "main",
32 | "position": 2
33 | };
34 |
35 | var login = {
36 | "title": "Login",
37 | "url": "/cms",
38 | "published": true,
39 | "target": "_self",
40 | "position": 4,
41 | "group": "main",
42 | };
43 |
44 | module.exports = [login];
45 |
--------------------------------------------------------------------------------
/src/services/custom/custom-model.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // custom-model.js - A mongoose model
4 | //
5 | // See http://mongoosejs.com/docs/models.html
6 | // for more of what you can do here.
7 |
8 | const mongoose = require('mongoose');
9 | const Schema = mongoose.Schema;
10 |
11 | const customSchema = new Schema({
12 | belongsTo: {
13 | type: String,
14 | required: true
15 | },
16 | key: {
17 | type: String,
18 | required: true
19 | },
20 | enabled: {
21 | type: Boolean,
22 | default: false
23 | },
24 | value: Schema.Types.Mixed,
25 | permission: {
26 | type: String
27 | },
28 | createdAt: { type: Date, 'default': Date.now },
29 | updatedAt: { type: Date, 'default': Date.now }
30 | });
31 |
32 | customSchema.index({belongsTo: 1, key: 1}, {unique: true});
33 |
34 | const customModel = mongoose.model('custom', customSchema);
35 |
36 | module.exports = customModel;
37 |
--------------------------------------------------------------------------------
/src/services/wordpress-import/wordpress-import.service.js:
--------------------------------------------------------------------------------
1 | import feathersErrors from 'feathers-errors'
2 | import _ from 'lodash'
3 |
4 | export default class ImageUploadService {
5 |
6 | setup(app) {
7 | this.app = app;
8 | }
9 |
10 | create(data, params) {
11 | return new Promise((resolve, reject) => {
12 | return resolve([]);
13 | // if(data && !_.isEmpty(data)) {
14 | // // this.app.service('themes').create(data).then(function(found) {
15 | // // return resolve(found);
16 | // // }).catch(function(err) {
17 | // // console.log("error uploading theme", err);
18 | // // return reject(err);
19 | // // });
20 | // return resolve([]);
21 | // } else {
22 | // return reject(new feathersErrors.Unprocessable('The import did not have a valid import content.'));
23 | // }
24 |
25 | });
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/seed/seed/comments.js:
--------------------------------------------------------------------------------
1 | var firstComment = {
2 | "author": "Admin",
3 | "url": "/why-cms",
4 | "content": "Comments can be added to articles.",
5 | "email": "admin@admin.com",
6 | "ip": "172.31.255.255",
7 | "approved": true,
8 | "likes": 2
9 | };
10 |
11 | var secondComment = {
12 | "author": "test",
13 | "url": "/why-cms",
14 | "content": "I can approve or reject comments",
15 | "email": "test@test.com",
16 | "ip": "172.97.114.255",
17 | "approved": false,
18 | "likes": 0
19 | };
20 |
21 | var thirdComment = {
22 | "email": "codingfriend@meanbase.com",
23 | "content": "You can manage comments on your site by approving or rejecting them. Google Recaptcha protects you from spam.",
24 | "url": "/why-cms",
25 | "approved": true,
26 | "date": "2016-08-28T02:05:02.842Z",
27 | "author": "Coding Friend",
28 | }
29 |
30 | module.exports = [firstComment, secondComment, thirdComment];
31 |
--------------------------------------------------------------------------------
/gulp/test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @overview Handles unit tests
3 | * gulp test
4 | * Runs jasmine karma unit tests client side
5 | * @author Jon Paul Miles
6 | */
7 |
8 | var karma = require('karma').server;
9 |
10 | module.exports = function (gulp, plugins, config) {
11 | // Unit Tests
12 | gulp.task('karma', function() {
13 | return gulp.src('../karma.conf.js')
14 | .pipe(plugins.inject(gulp.src(plugins.mainBowerFiles('**/*.js'), {read: false}), {
15 | starttag: 'files: [',
16 | endtag: "'client/bower_components/angular-mocks/angular-mocks.js'",
17 | addRootSlash: false,
18 | transform: function (filepath, file, i, length) {
19 | return '"' + filepath + '",';;
20 | }
21 | }))
22 | .pipe(gulp.dest('./'));
23 | });
24 |
25 | gulp.task('test', ['karma'], function (done) {
26 | karma.start({
27 | configFile: __dirname + '/../karma.conf.js'
28 | }, done);
29 | });
30 | };
--------------------------------------------------------------------------------
/public/app/components/mb-find-images-modal/mb-find-images-modal.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('mbFindImagesModal', function ($rootScope, $timeout, imageModal) {
3 | return {
4 | restrict: 'EA',
5 | scope: true,
6 | link: function (scope, element, attrs) {
7 | if(!$rootScope.isLoggedIn) { return false; }
8 |
9 | var config = scope.findImagesConfig;
10 |
11 | element.bind('click', function openModal(event) {
12 | event.stopPropagation()
13 | if(!$rootScope.editMode) { return false; }
14 |
15 | if (event.target !== this && !$(event.target).is('[mb-src]') && !$(event.target).is('img')) { return };
16 |
17 | imageModal.open(config, function(selectedImages) {
18 | $rootScope.$emit('cms.choseImages', {gallerySlug: config.gallerySlug, images: selectedImages});
19 | })
20 | });
21 | }
22 | };
23 | });
24 |
--------------------------------------------------------------------------------
/public/shared/feathers/feathers.service.js:
--------------------------------------------------------------------------------
1 | const feathers = require('feathers/client')
2 | const socketio = require('feathers-socketio/client');
3 | const hooks = require('feathers-hooks');
4 | const io = require('socket.io-client');
5 | const localstorage = require('feathers-localstorage');
6 | const authentication = require('feathers-authentication/client');
7 | const rest = require('feathers-rest/client');
8 |
9 | angular.module('meanbaseApp').factory('feathers', function() {
10 | // const socket = io(window.location.origin);
11 |
12 | window.app = feathers()
13 | .configure(hooks())
14 | .configure(rest(window.location.origin).jquery(jQuery))
15 | // .configure(socketio(socket))
16 | // .configure(rest(window.location.origin).fetch(window.fetch.bind(window)))
17 | .configure(authentication({ storage: window.localStorage, localEndpoint: '/api/auth/local', tokenEndpoint: '/api/auth/token' }));
18 |
19 | return app;
20 | });
21 |
--------------------------------------------------------------------------------
/src/services/shared-content/shared-content-model.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // shared-content-model.js - A mongoose model
4 | //
5 | // See http://mongoosejs.com/docs/models.html
6 | // for more of what you can do here.
7 |
8 | const mongoose = require('mongoose');
9 | const Schema = mongoose.Schema;
10 | const patterns = require('../../components/patterns');
11 | const validators = require('mongoose-validators');
12 |
13 | const sharedContentSchema = new Schema({
14 | contentName: {
15 | type: String,
16 | unique: true,
17 | required: true,
18 | validate: validators.matches(patterns.isTitle)
19 | },
20 | data: Schema.Types.Mixed,
21 | config: Schema.Types.Mixed,
22 | type: {
23 | type: String,
24 | required: true,
25 | validate: validators.matches(patterns.isTitle)
26 | }
27 | });
28 |
29 | const sharedContentModel = mongoose.model('shared-content', sharedContentSchema);
30 |
31 | module.exports = sharedContentModel;
32 |
--------------------------------------------------------------------------------
/src/services/pages/hooks/convert-for-incoming.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import {objectOfArraysToArrayOfObjects, objectToArray} from '../../../components/utility';
3 |
4 | export default function(options) {
5 | return (hook) => {
6 | if (!hook.params.provider || !hook.data) { return hook; }
7 |
8 | if(hook.data.title) {
9 | hook.params.titleWasChanged = true;
10 | } else {
11 | hook.params.titleWasChanged = false;
12 | }
13 |
14 | if(typeof hook.data.url === 'string' && hook.data.url.charAt(0) !== '/') {
15 | hook.data.url = '/' + hook.data.url;
16 | }
17 |
18 | if(hook.data.extensions) {
19 | hook.data.extensions = objectOfArraysToArrayOfObjects(hook.data.extensions);
20 | }
21 |
22 | if(hook.data.images) {
23 | // hook.data.images = objectToArray(hook.data.images);
24 | hook.data.images = objectToArray(hook.data.images);
25 | }
26 |
27 | return hook;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/public/app/components/mb-add-menu-item/mb-add-menu-item.directive.js:
--------------------------------------------------------------------------------
1 | angular.module('meanbaseApp')
2 | .directive('mbAddMenuItem', function ($rootScope, endpoints, $timeout, addMenuModal) {
3 | return {
4 | template: ' Add Link',
5 | restrict: 'A',
6 | link: function (scope, element, attrs) {
7 |
8 | element.bind('click', function(event) {
9 | let group = scope.$parent.$eval(attrs.mbAddMenuItem)
10 |
11 | if(!group) {
12 | if(!$rootScope.menus[attrs.mbAddMenuItem]) {
13 | $rootScope.menus[attrs.mbAddMenuItem] = []
14 | }
15 | group = attrs.mbAddMenuItem
16 | addMenuModal.open($rootScope.menus, group)
17 | } else {
18 | addMenuModal.open(group, attrs.property)
19 | }
20 |
21 |
22 |
23 | });
24 | }
25 | }
26 |
27 | });
28 |
--------------------------------------------------------------------------------
/public/extensions/md-selling-point-list/toggle-type.modal.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
19 |
20 |
--------------------------------------------------------------------------------
/src/components/seed/seed/extensions.js:
--------------------------------------------------------------------------------
1 | const searchFolders = require('../../search-folders');
2 |
3 | module.exports = async function() {
4 |
5 | const app = this;
6 |
7 | console.log('checking for extensions...');
8 |
9 | const extensionjsons = await searchFolders.retrieveExtensions.call(this);
10 |
11 | // We are putting this on the global so that when the client/index.html is compiled it will include the extension links
12 | if(!global.meanbaseGlobals) { global.meanbaseGlobals = {}; }
13 | global.meanbaseGlobals.extensions = extensionjsons;
14 |
15 | if(extensionjsons.length === 0) {
16 | console.log('no extensions found');
17 | return false;
18 | }
19 |
20 | try {
21 | await app.service('extensions').remove(null, {query: {}});
22 | await app.service('extensions').create(extensionjsons);
23 | console.log('extensions initialized');
24 | } catch (err) {
25 | console.log('Initializing extensions error: ', err);
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/public/app/components/mb-list-add/mb-list-add.styl:
--------------------------------------------------------------------------------
1 | // .add-to-list-btn {
2 | // position: absolute;
3 | // top: -20px;
4 | // right: -10px;
5 | // padding-top: 5px;
6 | // padding-left: 10px;
7 | // width: 35px;
8 | // height: 30px;
9 | // border-radius: 3px;
10 | // background-color: #2ECC71;
11 | // color: #ECF0F1;
12 | // cursor: pointer;
13 | // z-index: 2;
14 | // }
15 |
16 | .add-to-list-btn
17 | box-sizing: border-box
18 | background-color: white
19 | // border-radius: 100px
20 | padding 1em 1.2em 0.9em
21 | position relative
22 | cursor pointer
23 | text-align: center
24 | color grey
25 |
26 | i
27 | color grey
28 | font-size: 1.5em
29 | // position: absolute
30 | // top 50%
31 | // left 50%
32 | // -webkit-transform: translate(-50%, -50%)
33 | // transform: translate(-50%, -50%)
34 | // font-size: 2.5em
35 | // color grey
36 |
37 | .add-to-list-btn:hover
38 | color #2ECC71
39 | i
40 | color #2ECC71
41 |
--------------------------------------------------------------------------------
/public/shared/missing/missing.styl:
--------------------------------------------------------------------------------
1 | .meanbase-404
2 | padding 30px 10px
3 | font-size 20px
4 | line-height 1.4
5 | color #737373
6 | background #f0f0f0
7 | -webkit-text-size-adjust 100%
8 | -ms-text-size-adjust 100%
9 | input
10 | font-family "Helvetica Neue", Helvetica, Arial, sans-serif
11 |
12 | -moz-selection
13 | background #b3d4fc
14 | text-shadow none
15 |
16 | selection
17 | background #b3d4fc
18 | text-shadow none
19 |
20 | max-width 500px
21 | _width 500px
22 | padding 30px 20px 50px
23 | border 1px solid #b3b3b3
24 | border-radius 4px
25 | margin 4em auto
26 | box-shadow 0 1px 10px #a7a7a7, inset 0 1px 0 #fff
27 | background #fcfcfc
28 |
29 | h1
30 | margin 0 10px
31 | font-size 50px
32 | text-align center
33 |
34 | h1 span
35 | color #bbb
36 |
37 | h3
38 | margin 1.5em 0 0.5em
39 |
40 | p
41 | margin 1em 0
42 |
43 | ul
44 | padding 0 0 0 40px
45 | margin 1em 0
46 |
47 | .container
48 | max-width 380px
49 | _width 380px
50 | margin 0 auto
51 |
--------------------------------------------------------------------------------
/views/admin.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |