diff --git a/README.md b/README.md index cb43ba6..e7519d2 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,10 @@ This element represents the child button(s) of the menu and can only "live" insi ```html ``` - +...if you want show custom image in button use `image` attribute: +```html + +``` **NOTE**: If you are adding more than the default number of buttons supported by the provided CSS (currently 4) you will need to compile your own CSS beforehand to support your requirements. It's easy, here's an [example](https://github.com/nobitagit/ng-material-floating-button/issues/28#issuecomment-96980288). ##### TemplateUrl diff --git a/README.md~ b/README.md~ new file mode 100644 index 0000000..cb43ba6 --- /dev/null +++ b/README.md~ @@ -0,0 +1,291 @@ +ng-material-floating-button +======================== + +Material design floating action button implemented as an Angularjs directive. +~~Shamelessly~~ inspired by action buttons from Google Inbox, Evernote and Path. + +Made to be fast and easy to customise. It works out of the box with no other dependency apart from Angular, but plays nicely with the [Angular Material](https://material.angularjs.org) bundle, for which it has dedicated templates. + +## Demo +Head over to the project [homepage](http://nobitagit.github.io/ng-material-floating-button/) to see it in action as a standalone component, check the [Angular Material integration](http://nobitagit.github.io/ng-material-floating-button/angular-material.html) or just take a look at this awesome gif: + + + +**Other versions** +- [Vanilla html](https://github.com/nobitagit/material-floating-button) (original, upstream version of the component) +- [React component](https://github.com/nobitagit/react-material-floating-button) + +## How to use + +Download/clone the repo or use your favorite package manager: +``` +npm i ng-material-floating-button --save +``` +or: + +``` +bower install ng-mfb --save +``` + +Then (optionally) run `npm install` to have access to the configured Grunt tasks. + +Look in the `demo` folder for usage examples and head to the original component [docs](https://github.com/nobitagit/material-floating-button#how-to-use) to see how to customise the styles of the menu. + +If you are **upgrading** check the changelog before doing so in order to prevent breaking changes to bite you. + +### Basic setup +Download the whole repo or clone it, then reference the directive css file (here is `mfb/src/mfb.css`)in your ``: + +```html + +``` +Place a reference to the directive before the closing `` tag or anywhere after your angular script tag. + +```html + +``` +Make sure you reference the Mfb module as a dependecy to your app or module like so: +```js +var app = angular.module('your-app', ['ng-mfb']); +``` +Finally, place the correct html structure in your template. As a first example, assuming your example is using [Ionicons](http://ionicons.com/) as icon font: + +```html + +``` +This example shows the two basic components of the directive, a unique `mfb-menu` element which serves as a wrapper to a variable number of child buttons, defined by the `mfb-button` attribute. +This above code will output a basic button menu on the bottom right corner of the screen with a single menu item. Hardly amazing, so let's see how to customise it. + +**NOTE**: if you want to change the CSS make you sure you understand how it's supposed to be done. Please read [here](#custom-css) and [here](https://github.com/nobitagit/ng-material-floating-button/tree/master/mfb). + +### Element attributes +A number of attributes can be passed to the elements from the template in order to customise both behavior and appearance. + +####`` element +This can be defined as an attribute or an element. So this is valid: +```html + +``` +...and this is valid too: +```html + +``` +##### TemplateUrl +Optional attribute definining the template for the main button. If no template is specified it will fallback to the default `ng-mfb-menu-default.tpl.html`. If you are using [Angular Material](https://material.angularjs.org) in your app you can pass the predefined template for the Angular Material bundle which is `ng-mfb-menu-md.tpl.html`. + +Example: +```html + +``` + +By no means you are tied to the default templates, though. See [customising templates](#custom-tpls). + +##### Main Action +Defines a main action that will get fired when the main button is clicked. Works best with `toggling-method=hover` to put a main action on the base button. + +Example: +```html + +``` + +##### Position +Defines in which corner of the screen the component should be displayed. + +value | explanation +--- | --- +`tl` | top-left corner +`tr` | top-right corner +`br` | bottom-right corner +`bl` | bottom-left corner + +Example: +```html + +``` +##### Toggling method +Defines how the user will open the menu. Two values are possible: + +value | explanation +--- | --- +`hover` | hover to open the menu +`click` | click or tap to open the menu + +Example: + +```html + +``` + +**NOTE**: Using `hover` will prevent user browsing on modbile/touch devices to properly interact with the menu. The directive provides a fallback for this case. + +If you want the menu to work on hover but need support for touch devices you first need to include Modernizr to detect touch support. If you are alreay using it in your project just make sure that the touch detection is enabled. + +If you're not using Modernizr already, just include the tiny (<3KB) provided `modernizr.touch.js` script (look in the `mfb/src/lib/` folder) in your `` or get the latest version of this very script right from [here](http://modernizr.com/download/#-touch-teststyles-prefixes). Note that this is a custom build and will only detect for touch support, it's not the full library. + +##### Menu state +You can programmatically open/close the menu leveraging this attribute at any time after compilation, without any clicking required by the user, or listen to the current state of the menu. + +value | explanation +--- | --- +`open` | menu is... open (surprise, surprise) +`closed` | menu is...(hold tight) ... closed + +Example: + +```html + +``` +```js +// in your controller +$scope.myVar = 'closed'; +``` +NB: currently this value is only updated if using `click` toggling. + +##### Effect +Defines the effect that is performed when the menu opens up to show its child buttons. + +value | +--- | +`zoomin` | +`slidein` | +`slidein-spring` | +`fountain` | + +Test them [here](http://nobitagit.github.io/ng-material-floating-button/). + +Example: +```html + +``` +##### Label +The text that is displayed when hovering the main button. +Example: +```html + +``` + +##### Active-icon +The icon that will be displayed by default on the main button. +Example: +```html + +``` +##### Resting-icon +The icon that will be displayed on the main button when hovering/interacting with the menu. +Example: +```html + +``` +#### `` element +This element represents the child button(s) of the menu and can only "live" inside a wrapper `` element. Like its parent, it can be defined both as an attribute and as an element. So this is valid: +```html + +``` +...and this is valid too: +```html + +``` + +**NOTE**: If you are adding more than the default number of buttons supported by the provided CSS (currently 4) you will need to compile your own CSS beforehand to support your requirements. It's easy, here's an [example](https://github.com/nobitagit/ng-material-floating-button/issues/28#issuecomment-96980288). + +##### TemplateUrl +Optional attribute definining the template for the child buttons. If no template is specified it will fallback to the default `ng-mfb-button-default.tpl.html`. If you are using [Angular Material](https://material.angularjs.org) in your app you can pass the predefined template for the Angular Material bundle which is `ng-mfb-button-md.tpl.html`. + +Example: +```html + +``` + +Here again customising the template is surely possible, see how [here](#custom-tpls). + +##### Icon +Pass the class of the icon font character that is associated to the menu item: +Example: +```html + +``` +##### Label +The text that is displayed when hovering the button. +Example: +```html + +``` + +##### Custom attributes +Due to the nature of the component you'll probably want to associate some actions or use other angular directives such as ng-repeat on the buttons. As these attributes will be copied over to the generated html structure you can simply attach them to the ``. A couple of examples, here using ui-router: +```html + + +``` +And here leveraging a basic ng-repeat with buttons defined via js: +```js +// in your controller... +$scope.buttons = [{ + label: 'a link text', + icon: 'ion-paper-airplane' +},{ + label: 'another link', + icon: 'ion-plus' +},{ + label: 'a third link', + icon: 'ion-paperclip' +}; +``` +```html + + + +``` + +#### `mfb-button-close` attribute + +When using the toggling method click ```
    ``` only the main button toggles the menu. If you want your secondary buttons to close the menu as well you can use the ```mfb-button-close``` attribute on your ```mfb-button```. + +That way if your ```mfb-button``` opens a modal or something else that loses focus, your menu will close. + +```html + +``` + + +### Customising templates +Custom templates can be passed as a attributes to the directive. Just pass either the url of your own template or the ID of the script containing your template. Refer to the default templates provided to have a working base to build upon. + + +### More customisations +The component have plenty more customisations available and they are all handled by the CSS. The CSS and its SCSS source files are found in the `mfb/` folder (which is actually a subtree that pulls from [this repo](https://github.com/nobitagit/material-floating-button)). + +For a thorough overview of what and how to customise the look of the component through css make sure you read [these docs](https://github.com/nobitagit/ng-material-floating-button/tree/master/mfb), especially if you plan to keep your copy in sync with this repo by pulling in changes in the future. + +## Unit tests +To run the tests you need Jasmine and Karma runner. They can be run from the console with either `grunt karma` or `karma start test/karma.conf.js` commands. + +## Contributing and issues +Contributions are very welcome, as well as opening issues if you find any bugs. +If an issue or pull request is **not** specifically related to the Angularjs version (i.e. it's a layout/css bug/feature) please open it on the original component [repo](https://github.com/nobitagit/material-floating-button) rather than here. + +## Todos +- [x] add "click to open" functionality and option +- [x] add to bower +- [x] add to npm + +## Credits +Thanks to these [contributors](https://github.com/nobitagit/ng-material-floating-button/graphs/contributors). +Demo icons are courtesy of [Ionicons](ionicons.com) diff --git a/src/mfb-directive.js b/src/mfb-directive.js index d7f73c4..8b32dcf 100644 --- a/src/mfb-directive.js +++ b/src/mfb-directive.js @@ -45,6 +45,7 @@ ' ' + ' ' + ' ' + + ' ' + ' ' + '' ); @@ -196,7 +197,8 @@ replace: true, scope: { icon: '@', - label: '@' + label: '@', + image: '@' }, templateUrl: function(elem, attrs) { return attrs.templateUrl || 'ng-mfb-button-default.tpl.html'; @@ -205,3 +207,4 @@ }]); })(window, angular); + diff --git a/src/mfb-directive.js~ b/src/mfb-directive.js~ new file mode 100644 index 0000000..d7f73c4 --- /dev/null +++ b/src/mfb-directive.js~ @@ -0,0 +1,207 @@ +;(function(window, angular, undefined) { + + 'use strict'; + + var mfb = angular.module('ng-mfb', []); + + mfb.run(['$templateCache', function($templateCache) { + $templateCache.put('ng-mfb-menu-default.tpl.html', + '' + ); + + $templateCache.put('ng-mfb-menu-md.tpl.html', + '' + ); + + $templateCache.put('ng-mfb-button-default.tpl.html', + '
  • ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
  • ' + ); + + $templateCache.put('ng-mfb-button-md.tpl.html', + '
  • ' + + ' ' + + ' ' + + //' ' + + ' ' + + ' ' + + ' ' + + '
  • ' + ); + }]); + + mfb.directive('mfbButtonClose', function() { + return { + restrict: 'A', + require: '^mfbMenu', + link: function($scope, $element, $attrs, mfbMenuController) { + $element.bind('click', function() { + mfbMenuController.close(); + }); + }, + }; + + }); + + mfb.directive('mfbMenu', ['$timeout', function($timeout) { + return { + restrict: 'EA', + transclude: true, + replace: true, + scope: { + position: '@', + effect: '@', + label: '@', + resting: '@restingIcon', + active: '@activeIcon', + mainAction: '&', + menuState: '=?', + togglingMethod: '@' + }, + templateUrl: function(elem, attrs) { + return attrs.templateUrl || 'ng-mfb-menu-default.tpl.html'; + }, + controller: ['$scope', '$attrs', function($scope, $attrs) { + var openState = 'open', + closedState = 'closed'; + + // Attached toggle, open and close to the controller to give other + // directive access + this.toggle = toggle; + this.close = close; + this.open = open; + + $scope.clicked = clicked; + $scope.hovered = hovered; + + /** + * Set the state to user-defined value. Fallback to closed if no + * value is passed from the outside. + */ + if (!$scope.menuState) { + $scope.menuState = closedState; + } + + /** + * If on touch device AND 'hover' method is selected: + * wait for the digest to perform and then change hover to click. + */ + if (_isTouchDevice() && _isHoverActive()) { + $timeout(useClick); + } + + $attrs.$observe('menuState', function() { + $scope.currentState = $scope.menuState; + }); + + function clicked() { + // If there is a main action, let's fire it + if ($scope.mainAction) { + $scope.mainAction(); + } + + if (!_isHoverActive()) { + toggle(); + } + }; + + function hovered() { + if (_isHoverActive()) { + //toggle(); + } + }; + + /** + * Invert the current state of the menu. + */ + function toggle() { + if ($scope.menuState === openState) { + close(); + } else { + open(); + } + } + + function open() { + $scope.menuState = openState; + } + + function close() { + $scope.menuState = closedState; + } + + /** + * Check if we're on a touch-enabled device. + * Requires Modernizr to run, otherwise simply returns false + */ + function _isTouchDevice() { + return window.Modernizr && Modernizr.touch; + } + + function _isHoverActive() { + return $scope.togglingMethod === 'hover'; + } + + /** + * Convert the toggling method to 'click'. + * This is used when 'hover' is selected by the user + * but a touch device is enabled. + */ + function useClick() { + $scope.$apply(function() { + $scope.togglingMethod = 'click'; + }); + } + }] + }; + }]); + + mfb.directive('mfbButton', [function() { + return { + require: '^mfbMenu', + restrict: 'EA', + transclude: true, + replace: true, + scope: { + icon: '@', + label: '@' + }, + templateUrl: function(elem, attrs) { + return attrs.templateUrl || 'ng-mfb-button-default.tpl.html'; + } + }; + }]); + +})(window, angular);