Skip to content

Releases: mcasimir/mobile-angular-ui

v1.3.3

07 Sep 18:53
Compare
Choose a tag to compare

Fixes

  • Fix overlay page include quotes in ./demo

v1.3.2

04 Sep 19:42
Compare
Choose a tag to compare

Fixes

  • added fontawesome.woff2 to bower json (bdafc03)
  • bolder default font-weight (c21438b, 0a8030c)
  • fixes active links not working (15564fb)
  • fixes touch-move-default broken with scrollable (60a807c)

All the changes

v1.3.1

28 Aug 15:11
Compare
Choose a tag to compare

Fixes

  • removed webdriver postinstall hook (2a43565)

See all the commits

v1.3.0

27 Aug 17:22
Compare
Choose a tag to compare

Features

  • added ui-shared-state and deprecated ui-state so it does not clash with ui-router (9ad2f57)
  • activeLinks module supports html5Mode (d3cbbbf)
  • updated fastclick to version 1.0.6 (03060e2)
  • updated font-awesome to version 4.6.3 (9f7424c)

Fixes

  • Implemented workaround for jQuery event normalization (a3bb0e7)
  • scrollTo behavior when scrollableHeader is present (54b0e41)

All commits

1.2.0-beta.5

16 Dec 20:28
Compare
Choose a tag to compare
1.2.0-beta.5 Pre-release
Pre-release

Migrating to Mobile Angular UI 1.2

All of the functionalities are now separed in 3 modules: core, components and gestures.

Core UI functionalities

Core UI Functionalities are those any HTML UI built on Angular could use. They are not Mobile-specific nor depending on anything else that Angular itself, and you could use them with any css framework.

YieldTo/ContentFor

They are the same that 1.1 beside to be prefixed with ui- so use: ui-yield-to and ui-content-for.

Toggle/Toggleable to SharedState and ui-*

Toggle has been rewritten from scratch for 1.2. In place of that there is a new service with it's own isolated context.

It is called SharedState. It will act as a BUS between UI elements to share UI related state that is automatically disposed when all scopes requiring it are destroyed.

eg.

SharedState.initialize(requiringScope, 'myId');
SharedState.toggle('myId');

Using SharedState directives is very close to attach an ng-init in root element and interact through expression and ng-click, but it has handy features to avoid polluting controllers/scopes with ui-related stuffs.

SharedState methods are exposed through ui- directives. So you should never use it directly in your controller, and you can spare them to hold application logic.

Example: Tabs

<div class="tabs" ui-state="activeTab">

  <ul class="nav nav-tabs">
    <li ui-class="{'active': activeTab == 1)}">
      <a ui-set="{'activeTab': 1}">Tab 1</a>
    </li>
    <li ui-class="{'active': activeTab == 2)}">
      <a ui-set="{'activeTab': 2}">Tab 2</a>
    </li>
    <li ui-class="{'active': activeTab == 3)}">
      <a ui-set="{'activeTab': 3}">Tab 3</a>
    </li>
  </ul>

  <div ui-if="activeTab == 1">
    Tab 1
  </div>

  <div ui-if="activeTab == 2">
    Tab 2
  </div>

  <div ui-if="activeTab == 3">
    Tab 3
  </div>

</div>

NOTE: ui-toggle/set/turnOn/turnOff responds to click/tap without stopping propagation so you can use them along with ng-click too. You can also change events to respond to with ui-triggers attribute.

Any SharedState method is exposed through Ui object in $rootScope. So you could always do ng-click="Ui.turnOn('myVar')".

Since SharedState is a service you can initialize/set statuses through controllers too:

app.controller('myController', function($scope, SharedState){
  SharedState.initialize($scope, "activeTab", 3);
});

As well as you can use ui-default for that:

<div class="tabs" ui-state="activeTab" ui-default="thisIsAnExpression(5 + 1 - 2)"></div>

Outer Clicks

ui-outer-click and ui-outer-click-if are directives that allow to specifiy a behaviour when click/tap events happen outside an element. This can be easily used to implement eg. close on outer click feature for a dropdown.

  <div class="btn-group pull-right">
    <a ui-turn-on='myDropdown' class='btn'>
      <i class="fa fa-ellipsis-v"></i>
    </a>
    <ul 
      class="dropdown-menu"

      ui-state="myDropdown"
      ui-if="myDropdown"

      ui-outer-click="ui.turnOff('myDropdown')"
      ui-outer-click-if="ui.active('myDropdown')"

      ui-turn-off="myDropdown">

      <li><a>Action</a></li>
      <li><a>Another action</a></li>
      <li><a>Something else here</a></li>
      <li class="divider"></li>
      <li><a>Separated link</a></li>
    </ul>
  </div>

New Experimental Features

$swipe

A drop in replacement for ngTouch's $swipe. It is free from other ngTouch features that does not play or duplicates fastclicks behaviour.

$drag

$drag Service wraps $swipe to extend its behavior moving target element through css transform according to the $swipe coords thus creating a drag effect.

$drag interface is very close to $swipe:

app.controller('MyController', function($drag, $element){
  var unbindDrag = $drag.bind($element, {
   // drag callbacks
   // - rect is the current result of getBoundingClientRect() for bound element
   // - cancelFn issue a "touchcancel" on element
   // - resetFn restore the initial transform
   // - undoFn undoes the current movement
   // - swipeCoords are the coordinates exposed by the underlying $swipe service
   start: function(rect, cancelFn, resetFn, swipeCoords){},
   move: function(rect, cancelFn, resetFn, swipeCoords){},
   end: function(rect, undoFn, resetFn, swipeCoords) {};
   cancel: function(rect, resetFn){},

   // constraints for the movement
   // you can use a "static" object of the form:
   // {top: .., lelf: .., bottom: .., rigth: ..}
   // or pass a function that is called on each movement 
   // and return it in a dynamic way.
   // This is useful if you have to constraint drag movement while bounduaries are
   // changing over time.

   constraint: function(){ return {top: y1, left: x1, bottom: y2, right: x2}; }, // or just {top: y1, left: x1, bottom: y2, right: x2}

   // instantiates the Trasform according to touch movement (defaults to `t.translate(dx, dy);`)
   // dx, dy are the distances of movement for x and y axis after constraints are applyied
   transform: function(transform, dx, dy, currSwipeX, currSwipeY, startSwipeX, startSwipeY) {},

   // changes the Transform before is applied to element (useful to add something like easing or accelleration)
   adaptTransform: function(transform, dx, dy, currSwipeX, currSwipeY, startSwipeX, startSwipeY) {}

  });

  // This is automatically called when element is disposed so it is not necessary
  // that you call this manually but if you have to detatch $drag service before
  // this you could just call:
  unbindDrag();
});

Main differences with $swipe are:

  • bound elements will move following swipe direction automatically
  • coords param take into account css transform so you can easily detect collision with other elements.
  • start, move, end callback receive a cancel funcion that can be used to cancel the motion and reset
    the transform.
  • you can configure the transform behavior passing a transform function to options.
  • you can constraint the motion through the constraint option (setting relative movement limits)

Example 1. Drag to dismiss

app.directive('dragToDismiss', function($drag, $parse, $timeout){
  return {
    restrict: 'A',
    compile: function(elem, attrs) {
      var dismissFn = $parse(attrs.dragToDismiss);
      return function(scope, elem, attrs){
        var dismiss = false;

        $drag.bind(elem, {
          constraint: {
            minX: 0, 
            minY: 0, 
            maxY: 0 
          },
          move: function(c) {
            if( c.left >= c.width / 4) {
              dismiss = true;
              elem.addClass('dismiss');
            } else {
              dismiss = false;
              elem.removeClass('dismiss');
            }
          },
          cancel: function(){
            elem.removeClass('dismiss');
          },
          end: function(c, undo, reset) {
            if (dismiss) {
              elem.addClass('dismitted');
              $timeout(function() { 
                scope.$apply(function() {
                  dismissFn(scope);  
                });
              }, 400);
            } else {
              reset();
            }
          }
        });
      };
    }
  };
});

Example 2. Touch enabled "deck of cards" carousel directive

app.directive('carousel', function(){
  return {
    restrict: 'C',
    scope: {},
    controller: function($scope) {
      this.itemCount = 0;
      this.activeItem = null;

      this.addItem = function(){
        var newId = this.itemCount++;
        this.activeItem = this.itemCount == 1 ? newId : this.activeItem;
        return newId;
      };

      this.next = function(){
        this.activeItem = this.activeItem || 0;
        this.activeItem = this.activeItem == this.itemCount - 1 ? 0 : this.activeItem + 1;
      };

      this.prev = function(){
        this.activeItem = this.activeItem || 0;
        this.activeItem = this.activeItem === 0 ? this.itemCount - 1 : this.activeItem - 1;
      };
    }
  };
});

app.directive('carouselItem', function($drag) {
  return {
    restrict: 'C',
    require: '^carousel',
    scope: {},
    transclude: true,
    template: '<div class="item"><div ng-transclude></div></div>',
    link: function(scope, elem, attrs, carousel) {
      scope.carousel = carousel;
      var id = carousel.addItem();

      var zIndex = function(){
        var res = 0;
        if (id == carousel.activeItem){
          res = 2000;
        } else if (carousel.activeItem < id) {
          res = 2000 - (id - carousel.activeItem);
        } else {
          res = 2000 - (carousel.itemCount - 1 - carousel.activeItem + id);
        }
        return res;
      };

      scope.$watch(function(){
        return carousel.activeItem;
      }, function(n, o){
        elem[0].style['z-index']=zIndex();
      });


      $drag.bind(elem, {
        constraint: { minY: 0, maxY: 0 },
        adaptTransform: function(t, dx, dy, x, y, x0, y0) {
          var maxAngle = 15;
          var velocity = 0.02;
          var r = t.getRotation();
          var newRot = r + Math.round(dx * velocity);
          newRot = Math.min(newRot, maxAngle);
          newRot = Math.max(newRot, -maxAngle);
          t.rotate(-r);
          t.rotate(newRot);
        },
        move: function(c){
          if(c.left >= c.width / 4 || c.left <= -(c.width / 4)) {
            elem.addClass('dismiss');  
          } else {
            elem.removeClass('dismiss');  
          }          
        },
        cancel: function(){
          elem.removeClass('dismiss');
        },
        end: function(c, undo, reset) {
          elem.removeClass('dismiss');
          if(c.left >= c.width / 4) {
            scope.$apply(function() {
              carousel.next();
            });
          } else if (c.left <= -(c.width / 4)) {
            scope.$apply(function() {
              carousel.next();
      ...
Read more

1.1.0-beta.21

23 May 09:01
Compare
Choose a tag to compare
1.1.0-beta.21 Pre-release
Pre-release

Fixes #53: Android devices bad rendering box model with %-based translate3d. Switched to fixed sidebars width and media-queries.