<commit_before>'use strict';

var currentTabIndex = 0;
var currentTypeFilterIndex = 0;

// angular.module('adRep.view2', ['ngRoute','ui.calendar', 'ui.bootstrap'])
angular.module('adRep.view2', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/view2', {
    templateUrl: 'view2/view2.html',
    controller: 'AdsListController'
  });
}])

//.controller('AdsListController', ['$scope', '$location', '$timeout', function($scope, $location, $timeout, $compile, uiCalendarConfig) {
.controller('AdsListController', ['$scope', '$location', '$timeout', function($scope, $location, $timeout) {

    var contentTypeList = [];
    var channelTypeList = [];
    var dataList = [];
    var cShowDataList = [];

    var cYear = new Date().getFullYear();
    var cMonth = new Date().getMonth() + 1;
    var cDay = new Date().getDate();
    var today = cYear + '-' + cMonth + '-' + cDay;

    var scMonth = cMonth > 9 ? "" + cMonth : "0" + cMonth;
    var scDay = cDay > 9 ? "" + cDay : "0" + cDay;
    var showToday = "2017-09-10"//cYear + '-' + scMonth + '-' + scDay;
    console.log("today = " + showToday);

    var gSelectDate = showToday;
    resetFilterItems();
    setCurrentShowData();
    setShowData();

    $scope.$on('$viewContentLoaded', function() {
        console.log("page onload");
        setFilterSelectView();
        //$("#demo1").value = today + "";
    });

    var calendar = new LCalendar();
    var onDateChanged = function () {
        var dateInput = document.getElementById("demo1");
        var sDate = dateInput.value;
        dateInput.blur();
        console.log("select date = " + sDate);

        if (gSelectDate == sDate)
            return;

        gSelectDate = sDate;
        // currentTypeFilterIndex++;
        // if (currentTypeFilterIndex > 2){
        //     currentTypeFilterIndex = 0;
        // }
        currentTypeFilterIndex = 0;
        currentTabIndex = 0;

        console.log("reset show date");
        resetFilterItems();
        setShowData();
    };

    function pushItemToArray(array, item){
        if (array == null || item == null)
            return;

        var isSame = false;
        for (var m = 0; m < array.length; m++){
            var aItem = array[m];
            if (aItem.label == item.label){
                isSame = true;
                break;
            }
        }

        if (isSame == false)
            array.push(item);
    }

    function resetFilterItems() {

        var currentDateDatas = [];
        for (var i = 0; i < fullTestDataHW.length; i++){
            var item = fullTestDataHW[i];
            if (item.date == gSelectDate){
                currentDateDatas = item.listData;
            }
        }

        contentTypeList = [];
        channelTypeList = [];
        dataList = [];

        for (var j = 0; j < currentDateDatas.length; j++){
            var dItem = currentDateDatas[j];
            var ctItem = {"label": dItem.theme};
            var chItem = {"label": dItem.platform};
            pushItemToArray(contentTypeList, ctItem);
            pushItemToArray(channelTypeList, chItem);
            //contentTypeList.push(dItem.theme);
            //channelTypeList.push(dItem.platform);
        }
        console.log("contentTypeList length = " + contentTypeList.length);
        console.log("channelTypeList length = " + channelTypeList.length);
        dataList = currentDateDatas;
    };

    function setCurrentShowData() {
        if (currentTabIndex == 0){
            cShowDataList = dataList;
        } else if (currentTabIndex == 1){
            cShowDataList = [];
            var filterItem = contentTypeList[currentTypeFilterIndex];
            for (var m = 0; m < dataList.length; m++){
                var item = dataList[m];
                if (item.theme == filterItem.label){
                    cShowDataList.push(item);
                }
            }
        } else if (currentTabIndex == 2){
            cShowDataList = [];
            var filterItem = channelTypeList[currentTypeFilterIndex];
            for (var m = 0; m < dataList.length; m++){
                var item = dataList[m];
                if (item.platform == filterItem.label){
                    cShowDataList.push(item);
                }
            }
        }
    };

    calendar.init({
        'trigger': '#demo1', //标签id
        'type': 'date', //date 调出日期选择 datetime 调出日期时间选择 time 调出时间选择 ym 调出年月选择,
        'minDate': '2000-1-1', //最小日期
        'maxDate': today, //最大日期
        'defaultDate': showToday,
        'onSelectDate': onDateChanged
    });

    // var date = new Date();
    // var d = date.getDate();
    // var m = date.getMonth();
    // var y = date.getFullYear();
    //
    //
    //
    // /* event source that contains custom events on the scope */
    // $scope.events = [
    //     {title: 'All Day Event',start: new Date(y, m, 1)},
    //     {title: 'Long Event',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
    //     {id: 999,title: 'Repeating Event',start: new Date(y, m, d - 3, 16, 0),allDay: false},
    //     {id: 999,title: 'Repeating Event',start: new Date(y, m, d + 4, 16, 0),allDay: false},
    //     {title: 'Birthday Party',start: new Date(y, m, d + 1, 19, 0),end: new Date(y, m, d + 1, 22, 30),allDay: false},
    //     {title: 'Click for Google',start: new Date(y, m, 28),end: new Date(y, m, 29),url: 'http://google.com/'},
    //     {title:'zql',start:new Date(y,m,3)}
    // ];
    //
    // /* config object */
    // $scope.uiConfig = {
    //     calendar:{
    //         height: 450,
    //         editable: false,
    //         header:{
    //             left: '',
    //             center: 'title',
    //             right: 'today prev,next'
    //         }
    //     }
    // };
    //
    // /* event sources array*/
    // $scope.eventSources = [$scope.events];

    // $scope.filterTypeLabel = fullTestData[0].typeName;
    // $scope.filterTypeList = fullTestData[0].listData;
    // $scope.adsRecords = fullTestData[0].listData[0].data;

    // setTimeout(function () {
    //     $scope.$apply(function () {
    //         console.log("reset test data ");
    //         $scope.filterTypeLabel = fullTestData[1].typeName;
    //         $scope.filterTypeList = fullTestData[1].listData;
    //         $scope.adsRecords = fullTestData[1].listData[0].data;
    //     });
    // }, 5000);

  $scope.onTypeChanged = function (index) {
      console.log("foot index " + index);

      if (index <= 2 && index >= 0){
          console.log("data update ");
          currentTabIndex = index;
          currentTypeFilterIndex = 0;
          setFilterSelectView();
          setCurrentShowData();
          setShowData();
      }
  };

    $scope.filterTypeChenged = function(){

        var changeitem = $scope.selectedFilterItems;
        console.log(" filter val : " + changeitem);
        for (var i = 0; i < $scope.filterTypeList.length; i++){
            var listItem = $scope.filterTypeList[i].label;
            if (listItem === changeitem){
                currentTypeFilterIndex = i;
                console.log(" filter index : " + currentTypeFilterIndex);
            }
        }
        setCurrentShowData();
        setShowData();
    };

  //   $scope.filterClick = function (index) {
  //     console.log(" filter index : " + index);
  //     currentTypeFilterIndex = index;
  //     setShowData();
  // };

  $scope.adsListClick = function (index) {
      //currentAd = adsReporterData[index];
      console.log("$scope.filterTypeLabel = " + $scope.filterTypeLabel);
      console.log($scope.filterTypeList);
      console.log($scope.adsRecords);

      currentAd = $scope.adsRecords[index];
      console.log("click : " + index);
      console.log(currentAd);
      $location.path('/ad_detail');
  };

  $scope.userLogout = function () {
      $location.path('/view1');
  };

  function setFilterSelectView(){
      if (currentTabIndex == 0){
          document.getElementById("demo1").style.display = "block";
          document.getElementById("selectDropDown").style.display = "none";
          // $("#demo1").style.display = "block";
          // $("#selectDropDown").style.display = "none";
      } else {
          document.getElementById("demo1").style.display = "none";
          document.getElementById("selectDropDown").style.display = "block";
          // $("#demo1").style.display = "none";
          // $("#selectDropDown").style.display = "block";
      }
  }

  function setShowData() {
      $scope.adsTypesData = fullTestData;
      if (currentTabIndex >= 0 && currentTabIndex <= 2){
          $scope.filterTypeLabel = fullTestData[currentTabIndex].typeName;

          // $scope.filterTypeList = fullTestData[currentTabIndex].listData;
          // $scope.adsRecords = fullTestData[currentTabIndex].listData[currentTypeFilterIndex].data;
          // $scope.selectedFilterItems = fullTestData[currentTabIndex].listData[currentTypeFilterIndex].label;

          if (currentTabIndex == 1) {
              $scope.filterTypeList = contentTypeList;
              $scope.selectedFilterItems = contentTypeList[0].label;
          } else {
              $scope.filterTypeList = channelTypeList;
              $scope.selectedFilterItems = channelTypeList[0].label;
          }
          $scope.adsRecords = cShowDataList;

          for(var m = 0; m < $scope.adsTypesData.length; m++){
              if (m == currentTabIndex){
                  $scope.adsTypesData[m].isSel = true;
              } else {
                  $scope.adsTypesData[m].isSel = false;
              }
              console.log("isSel : " + m + " = " + $scope.adsTypesData[m].isSel);
          }
      }
  }
}]);<commit_msg>测试数据格式修改<commit_after>'use strict';

var currentTabIndex = 0;
var currentTypeFilterIndex = 0;

// angular.module('adRep.view2', ['ngRoute','ui.calendar', 'ui.bootstrap'])
angular.module('adRep.view2', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/view2', {
    templateUrl: 'view2/view2.html',
    controller: 'AdsListController'
  });
}])

//.controller('AdsListController', ['$scope', '$location', '$timeout', function($scope, $location, $timeout, $compile, uiCalendarConfig) {
.controller('AdsListController', ['$scope', '$location', '$timeout', function($scope, $location, $timeout) {

    var contentTypeList = [];
    var channelTypeList = [];
    var dataList = [];
    var cShowDataList = [];

    var cYear = new Date().getFullYear();
    var cMonth = new Date().getMonth() + 1;
    var cDay = new Date().getDate();
    var today = cYear + '-' + cMonth + '-' + cDay;

    var scMonth = cMonth > 9 ? "" + cMonth : "0" + cMonth;
    var scDay = cDay > 9 ? "" + cDay : "0" + cDay;
    var showToday = "2017-09-10"; //cYear + '-' + scMonth + '-' + scDay; //
    console.log("today = " + showToday);

    var gSelectDate = showToday;
    resetFilterItems();
    setCurrentShowData();
    setShowData();

    $scope.$on('$viewContentLoaded', function() {
        console.log("page onload");
        setFilterSelectView();
        //$("#demo1").value = today + "";
    });

    var calendar = new LCalendar();
    var onDateChanged = function () {
        var dateInput = document.getElementById("demo1");
        var sDate = dateInput.value;
        dateInput.blur();
        console.log("select date = " + sDate);

        if (gSelectDate == sDate)
            return;

        gSelectDate = sDate;
        // currentTypeFilterIndex++;
        // if (currentTypeFilterIndex > 2){
        //     currentTypeFilterIndex = 0;
        // }
        currentTypeFilterIndex = 0;
        currentTabIndex = 0;

        console.log("reset show date");
        resetFilterItems();
        setCurrentShowData();
        setShowData();
    };

    function pushItemToArray(array, item){
        if (array == null || item == null)
            return;

        var isSame = false;
        for (var m = 0; m < array.length; m++){
            var aItem = array[m];
            if (aItem.label == item.label){
                isSame = true;
                break;
            }
        }

        if (isSame == false)
            array.push(item);
    }

    function resetFilterItems() {

        var currentDateDatas = [];
        for (var i = 0; i < fullTestDataHW.length; i++){
            var item = fullTestDataHW[i];
            if (item.date == gSelectDate){
                currentDateDatas = item.listData;
            }
        }

        contentTypeList = [];
        channelTypeList = [];
        dataList = [];

        for (var j = 0; j < currentDateDatas.length; j++){
            var dItem = currentDateDatas[j];
            var ctItem = {"label": dItem.theme};
            var chItem = {"label": dItem.platform};
            pushItemToArray(contentTypeList, ctItem);
            pushItemToArray(channelTypeList, chItem);
            //contentTypeList.push(dItem.theme);
            //channelTypeList.push(dItem.platform);
        }
        console.log("contentTypeList length = " + contentTypeList.length);
        console.log("channelTypeList length = " + channelTypeList.length);
        dataList = currentDateDatas;
    };

    function setCurrentShowData() {
        cShowDataList.splice(0,cShowDataList.length);
        if (currentTabIndex == 0){
            //cShowDataList = dataList;
            for (var m = 0; m < dataList.length; m++){
                var item = dataList[m];
                cShowDataList.push(item);
            }
        } else if (currentTabIndex == 1){
            cShowDataList = [];
            var filterItem = contentTypeList[currentTypeFilterIndex];
            for (var m = 0; m < dataList.length; m++){
                var item = dataList[m];
                if (item.theme == filterItem.label){
                    cShowDataList.push(item);
                }
            }
        } else if (currentTabIndex == 2){
            cShowDataList = [];
            var filterItem = channelTypeList[currentTypeFilterIndex];
            for (var m = 0; m < dataList.length; m++){
                var item = dataList[m];
                if (item.platform == filterItem.label){
                    cShowDataList.push(item);
                }
            }
        }
    };

    calendar.init({
        'trigger': '#demo1', //标签id
        'type': 'date', //date 调出日期选择 datetime 调出日期时间选择 time 调出时间选择 ym 调出年月选择,
        'minDate': '2000-1-1', //最小日期
        'maxDate': today, //最大日期
        'defaultDate': showToday,
        'onSelectDate': onDateChanged
    });

    // var date = new Date();
    // var d = date.getDate();
    // var m = date.getMonth();
    // var y = date.getFullYear();
    //
    //
    //
    // /* event source that contains custom events on the scope */
    // $scope.events = [
    //     {title: 'All Day Event',start: new Date(y, m, 1)},
    //     {title: 'Long Event',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
    //     {id: 999,title: 'Repeating Event',start: new Date(y, m, d - 3, 16, 0),allDay: false},
    //     {id: 999,title: 'Repeating Event',start: new Date(y, m, d + 4, 16, 0),allDay: false},
    //     {title: 'Birthday Party',start: new Date(y, m, d + 1, 19, 0),end: new Date(y, m, d + 1, 22, 30),allDay: false},
    //     {title: 'Click for Google',start: new Date(y, m, 28),end: new Date(y, m, 29),url: 'http://google.com/'},
    //     {title:'zql',start:new Date(y,m,3)}
    // ];
    //
    // /* config object */
    // $scope.uiConfig = {
    //     calendar:{
    //         height: 450,
    //         editable: false,
    //         header:{
    //             left: '',
    //             center: 'title',
    //             right: 'today prev,next'
    //         }
    //     }
    // };
    //
    // /* event sources array*/
    // $scope.eventSources = [$scope.events];

    // $scope.filterTypeLabel = fullTestData[0].typeName;
    // $scope.filterTypeList = fullTestData[0].listData;
    // $scope.adsRecords = fullTestData[0].listData[0].data;

    // setTimeout(function () {
    //     $scope.$apply(function () {
    //         console.log("reset test data ");
    //         $scope.filterTypeLabel = fullTestData[1].typeName;
    //         $scope.filterTypeList = fullTestData[1].listData;
    //         $scope.adsRecords = fullTestData[1].listData[0].data;
    //     });
    // }, 5000);

  $scope.onTypeChanged = function (index) {
      console.log("foot index " + index);

      if (index <= 2 && index >= 0){
          console.log("data update ");
          currentTabIndex = index;
          currentTypeFilterIndex = 0;
          setFilterSelectView();
          setCurrentShowData();
          setShowData();
      }
  };

    $scope.filterTypeChenged = function(){

        var changeitem = $scope.selectedFilterItems;
        console.log(" filter val : " + changeitem);
        for (var i = 0; i < $scope.filterTypeList.length; i++){
            var listItem = $scope.filterTypeList[i].label;
            if (listItem === changeitem){
                currentTypeFilterIndex = i;
                console.log(" filter index : " + currentTypeFilterIndex);
            }
        }
        setCurrentShowData();
        setShowData();
    };

  //   $scope.filterClick = function (index) {
  //     console.log(" filter index : " + index);
  //     currentTypeFilterIndex = index;
  //     setShowData();
  // };

  $scope.adsListClick = function (index) {
      //currentAd = adsReporterData[index];
      console.log("$scope.filterTypeLabel = " + $scope.filterTypeLabel);
      console.log($scope.filterTypeList);
      console.log($scope.adsRecords);

      currentAd = $scope.adsRecords[index];
      console.log("click : " + index);
      console.log(currentAd);
      $location.path('/ad_detail');
  };

  $scope.userLogout = function () {
      $location.path('/view1');
  };

  function setFilterSelectView(){
      if (currentTabIndex == 0){
          document.getElementById("demo1").style.display = "block";
          document.getElementById("selectDropDown").style.display = "none";
          // $("#demo1").style.display = "block";
          // $("#selectDropDown").style.display = "none";
      } else {
          document.getElementById("demo1").style.display = "none";
          document.getElementById("selectDropDown").style.display = "block";
          // $("#demo1").style.display = "none";
          // $("#selectDropDown").style.display = "block";
      }
  }

  function setShowData() {
      $scope.adsTypesData = fullTestData;
      if (currentTabIndex >= 0 && currentTabIndex <= 2){
          $scope.filterTypeLabel = fullTestData[currentTabIndex].typeName;

          // $scope.filterTypeList = fullTestData[currentTabIndex].listData;
          // $scope.adsRecords = fullTestData[currentTabIndex].listData[currentTypeFilterIndex].data;
          // $scope.selectedFilterItems = fullTestData[currentTabIndex].listData[currentTypeFilterIndex].label;

          if (currentTabIndex == 1) {
              $scope.filterTypeList = contentTypeList;
              if (contentTypeList.length >= 1)
                  $scope.selectedFilterItems = contentTypeList[0].label;
          } else if (currentTabIndex == 2) {
              $scope.filterTypeList = channelTypeList;
              if (channelTypeList.length >= 1)
                  $scope.selectedFilterItems = channelTypeList[0].label;
          } else {
              $scope.filterTypeList = [];
              $scope.selectedFilterItems = " ";
          }
          $scope.adsRecords = cShowDataList;

          for(var m = 0; m < $scope.adsTypesData.length; m++){
              if (m == currentTabIndex){
                  $scope.adsTypesData[m].isSel = true;
              } else {
                  $scope.adsTypesData[m].isSel = false;
              }
              console.log("isSel : " + m + " = " + $scope.adsTypesData[m].isSel);
          }

          $scope.$applyAsync();
      }
  }
}]);<|endoftext|>


<commit_before>// -------------------------------------------------------------------------- \\
// File: MenuView.js                                                          \\
// Module: ControlViews                                                       \\
// Requires: Core, Foundation, DOM, View                                      \\
// Author: Neil Jenkins                                                       \\
// License: © 2010–2013 FastMail Pty Ltd. All rights reserved.                \\
// -------------------------------------------------------------------------- \\

"use strict";

( function ( NS ) {

// A menu option must have:
// filter( pattern ): RegExp -> Boolean
// isFocussed: Boolean
// isHidden: Boolean
// isDisabled: Boolean

var MenuController = NS.Class({

    Extends: NS.Object,

    options: [],

    // --- Focus ---

    canSelect: function ( option ) {
        return !option.get( 'isHidden' ) && !option.get( 'isDisabled' );
    },

    focussedOption: null,

    getAdjacentOption: function ( step ) {
        var options = this.get( 'options' ),
            l = options.get( 'length' ),
            i = options.indexOf( this.get( 'focussedOption' ) ),
            current;

        if ( i < 0 && step < 0 ) {
            i = l;
        }
        current = i.mod( l );

        do {
            i = ( i + step ).mod( l );
        } while ( l &&
            !this.canSelect( options.getObjectAt( i ) ) && i !== current );

        return options.getObjectAt( i );
    },

    focusPrevious: function ( event ) {
        if ( event ) { event.preventDefault(); }
        return this.focusOption( this.getAdjacentOption( -1 ) );
    },

    focusNext: function ( event ) {
        if ( event ) { event.preventDefault(); }
        return this.focusOption( this.getAdjacentOption( 1 ) );
    },

    focusOption: function ( option ) {
        var current = this.get( 'focussedOption' );
        if ( current !== option ) {
            if ( current ) {
                current.set( 'isFocussed', false );
            }
            if ( option ) {
                if ( !this.canSelect( option ) ) {
                    option = null;
                } else {
                    option.set( 'isFocussed', true );
                }
            }
            this.set( 'focussedOption', option );
        }
        return this;
    },

    blurOption: function ( option ) {
        if ( this.get( 'focussedOption' ) === option ) {
            this.focusOption( null );
        }
        return this;
    },

    selectFocussed: function ( event ) {
        if ( event ) { event.preventDefault(); }
        var focussedOption = this.get( 'focussedOption' );
        if ( focussedOption && this.canSelect( focussedOption ) ) {
            focussedOption.activate( this );
        }
        return this;
    },

    // --- Filter ---

    filter: '',

    filterDidChange: function () {
        var value = this.get( 'filter' ).escapeRegExp(),
            pattern = value ? new RegExp( '(?:^|\\W)' + value, 'i' ) : null,
            options = this.get( 'options' ),
            l = options.get( 'length' ),
            focussedOption = this.get( 'focussedOption' );

        while ( l-- ) {
            options.getObjectAt( l ).filter( pattern );
        }
        if ( !focussedOption || !this.canSelect( focussedOption ) ) {
            this.focusOption( null ).focusNext();
        }
    }.observes( 'filter' ),

    // --- Keyboard support ---

    keyBindings: {
        esc: 'onEscape',
        enter: 'selectFocussed',
        up: 'focusPrevious',
        down: 'focusNext',
        left: 'closeIfSub',
        right: 'activateIfMenu'
    },

    triggerKeyBinding: function ( event ) {
        var key = NS.DOMEvent.lookupKey( event ),
            bindings = this.get( 'keyBindings' );
        if ( bindings[ key ] ) {
            event.stopPropagation();
            this[ bindings[ key ] ]( event, key );
        }
    }.on( 'keydown' ),

    onEscape: function ( event ) {
        event.preventDefault();
        var filter = this.get( 'filter' );
        if ( filter ) {
            this.set( 'filter', '' );
        } else {
            this.get( 'view' ).hide();
        }
    },

    closeIfSub: function () {
        var view = this.get( 'view' ),
            popOverView;
        if ( !view.get( 'showFilter' ) &&
                ( popOverView = view.getParent( NS.PopOverView ) ) &&
                  popOverView.get( 'parentPopOverView' ) ) {
            view.hide();
        }
    },

    activateIfMenu: function () {
        var focussedOption = this.get( 'focussedOption' );
        if ( focussedOption &&
                focussedOption.get( 'button' ) instanceof NS.MenuButtonView ) {
            this.selectFocussed();
        }
    }
});

var MenuOptionView = NS.Class({

    Extends: NS.View,

    isHidden: false,
    isDisabled: function () {
        return this.getFromPath( 'button.isDisabled' );
    }.property( 'button.isDisabled' ),
    isFocussed: false,
    isFocussable: function () {
        return !this.get( 'isHidden' ) && !this.get( 'isDisabled' );
    }.property( 'isHidden', 'isDisabled' ),

    layerTag: 'li',

    className: function () {
        return 'MenuOptionView' +
            ( this.get( 'isFocussed' ) ? ' focussed' : '' ) +
            ( this.get( 'isHidden' ) ? ' hidden' : '' );
    }.property( 'isFocussed', 'isHidden' ),

    init: function ( view, controller ) {
        this.childViews = [ view ];
        this.button = view;
        this.controller = controller;
        MenuOptionView.parent.init.call( this );
    },

    scrollIntoView: function () {
        if ( this.get( 'isFocussed' ) ) {
            var scrollView = this.getParent( NS.ScrollView );
            if ( scrollView ) {
                var scrollHeight = scrollView.get( 'pxHeight' ),
                    scrollTop = scrollView.get( 'scrollTop' ),
                    top = this.getPositionRelativeTo( scrollView ).top,
                    height = this.get( 'pxHeight' );

                if ( top < scrollTop ) {
                    scrollView.scrollTo( 0, top - ( height >> 1 ), true );
                } else if ( top + height > scrollTop + scrollHeight ) {
                    scrollView.scrollTo( 0,
                        top + height - scrollHeight + ( height >> 1 ), true );
                }
            }
        }
    }.observes( 'isFocussed' ),

    _focusTimeout: null,

    takeFocus: function () {
        if ( this.get( 'isInDocument' ) ) {
            this.get( 'controller' ).focusOption( this )
                .activateIfMenu();
        }
    },

    mouseMove: function () {
        if ( !this.get( 'isFocussed' ) && !this._focusTimeout ) {
            var popOverView = this.getParent( NS.PopOverView );
            if ( popOverView && popOverView.hasSubView() ) {
                this._focusTimeout = NS.RunLoop.invokeAfterDelay(
                    this.takeFocus, 75, this );
            } else {
                this.takeFocus();
            }
        }
    }.on( 'mousemove' ),

    mouseOut: function () {
        if ( this._focusTimeout ) {
            NS.RunLoop.cancel( this._focusTimeout );
            this._focusTimeout = null;
        }
        if ( !this.get( 'button' ).get( 'isActive' ) ) {
            this.get( 'controller' ).blurOption( this );
        }
    }.on( 'mouseout' ),

    filter: function ( pattern ) {
        var label = this.get( 'button' ).get( 'label' );
        this.set( 'isHidden', !!pattern && !pattern.test( label ) );
    },

    activate: function () {
        var button = this.get( 'button' );
        if ( button.activate ) { button.activate(); }
    }
});

var MenuView = NS.Class({

    Extends: NS.View,

    className: 'MenuView',

    showFilter: false,
    closeOnActivate: true,

    didCreateLayer: function ( layer ) {
        MenuView.parent.didCreateLayer.call( this, layer );
        layer.addEventListener( 'mousemove', this, false );
        layer.addEventListener( 'mouseout', this, false );
    },

    willDestroyLayer: function ( layer ) {
        layer.removeEventListener( 'mouseout', this, false );
        layer.removeEventListener( 'mousemove', this, false );
        MenuView.parent.willDestroyLayer.call( this, layer );
    },

    didEnterDocument: function () {
        MenuView.parent.didEnterDocument.call( this );
        var scrollView = this._scrollView,
            delta, controller, input;
        if ( scrollView && !this.getParent( NS.ScrollView ) ) {
            delta = this.get( 'layer' ).getBoundingClientRect().bottom -
                this.getParent( NS.RootView ).get( 'pxHeight' );
            // Must redraw immediately so size is correct when PopOverView
            // checks if it is positioned off screen.
            scrollView.set( 'layout', {
                maxHeight: scrollView.get( 'pxHeight' ) - delta - 10
            }).redraw();
        }

        if ( this.get( 'showFilter' ) ) {
            controller = this.get( 'controller' );
            input = this._input;
            if ( !controller.get( 'focussedOption' ) ) {
                controller.focusNext();
            }
            NS.RunLoop.invokeInNextEventLoop( function () {
                input.focus().set( 'selection', {
                    start: 0,
                    end: input.get( 'value' ).length
                });
            });
        }
        return this;
    },

    didLeaveDocument: function () {
        var controller = this.get( 'controller' );
        if ( this.get( 'showFilter' ) ) {
            controller.set( 'filter', '' );
        } else {
            controller.focusOption( null );
        }
        return MenuView.parent.didLeaveDocument.call( this );
    },

    mayHaveResized: function () {
        this.parentViewDidResize();
    }.queue( 'after' ).observes( 'controller.filter' ),

    nextEventTarget: function () {
        return this.get( 'controller' );
    }.property( 'controller' ),

    controller: function () {
        return new MenuController({
            view: this
        });
    }.property(),

    ItemView: MenuOptionView,

    draw: function ( layer, Element, el ) {
        var controller = this.get( 'controller' ),
            MenuOptionView = this.get( 'ItemView' ),
            optionViews = this.get( 'options' ).map( function ( view ) {
                return new MenuOptionView( view, controller );
            });
        controller.set( 'options', optionViews );
        return [
            this.get( 'showFilter' ) ? el( 'div', [
                this._input = new NS.TextView({
                    blurOnEscape: false,
                    type: 'text filter',
                    value: NS.bindTwoWay( 'filter', this.get( 'controller' ) )
                })
            ]) : null,
            this._scrollView = new NS.ScrollView({
                positioning: 'relative',
                layout: {},
                layerTag: 'ul',
                childViews: optionViews
            })
        ];
    },

    hide: function () {
        var parent = this.get( 'parentView' );
        if ( parent ) {
            NS.RunLoop.invokeInNextEventLoop( parent.hide, parent );
        }
    },

    hideAll: function () {
        if ( this.get( 'closeOnActivate' ) ) {
            var popOverView = this.getParent( NS.PopOverView ) ||
                    this.get( 'parentView' ),
                parent;
            if ( popOverView ) {
                while ( parent = popOverView.get( 'parentPopOverView' ) ) {
                    popOverView = parent;
                }
                NS.RunLoop.invokeInNextEventLoop(
                    popOverView.hide, popOverView );
            }
        }
    }.on( 'button:activate' ),

    fireShortcut: function ( event ) {
        if ( !this.get( 'showFilter' ) ) {
            var key = NS.DOMEvent.lookupKey( event ),
                handler = NS.ViewEventsController
                            .kbShortcuts.getHandlerForKey( key ),
                parent, object, method;
            if ( handler ) {
                parent = object = handler[0];
                method = handler[1];
                // Check object is child view of the menu; we want to ignore any
                // other keyboard shortcuts.
                if ( object instanceof NS.View ) {
                    while ( parent && parent !== this ) {
                        parent = parent.get( 'parentView' );
                    }
                    if ( parent ) {
                        object[ method ]( event );
                        event.preventDefault();
                    }
                }
            }
        }
    }.on( 'keypress' )
});

NS.MenuController = MenuController;
NS.MenuOptionView = MenuOptionView;
NS.MenuView = MenuView;

}( this.O ) );
<commit_msg>Restrict length of MenuView inside ScrollView.<commit_after>// -------------------------------------------------------------------------- \\
// File: MenuView.js                                                          \\
// Module: ControlViews                                                       \\
// Requires: Core, Foundation, DOM, View                                      \\
// Author: Neil Jenkins                                                       \\
// License: © 2010–2013 FastMail Pty Ltd. All rights reserved.                \\
// -------------------------------------------------------------------------- \\

"use strict";

( function ( NS ) {

// A menu option must have:
// filter( pattern ): RegExp -> Boolean
// isFocussed: Boolean
// isHidden: Boolean
// isDisabled: Boolean

var MenuController = NS.Class({

    Extends: NS.Object,

    options: [],

    // --- Focus ---

    canSelect: function ( option ) {
        return !option.get( 'isHidden' ) && !option.get( 'isDisabled' );
    },

    focussedOption: null,

    getAdjacentOption: function ( step ) {
        var options = this.get( 'options' ),
            l = options.get( 'length' ),
            i = options.indexOf( this.get( 'focussedOption' ) ),
            current;

        if ( i < 0 && step < 0 ) {
            i = l;
        }
        current = i.mod( l );

        do {
            i = ( i + step ).mod( l );
        } while ( l &&
            !this.canSelect( options.getObjectAt( i ) ) && i !== current );

        return options.getObjectAt( i );
    },

    focusPrevious: function ( event ) {
        if ( event ) { event.preventDefault(); }
        return this.focusOption( this.getAdjacentOption( -1 ) );
    },

    focusNext: function ( event ) {
        if ( event ) { event.preventDefault(); }
        return this.focusOption( this.getAdjacentOption( 1 ) );
    },

    focusOption: function ( option ) {
        var current = this.get( 'focussedOption' );
        if ( current !== option ) {
            if ( current ) {
                current.set( 'isFocussed', false );
            }
            if ( option ) {
                if ( !this.canSelect( option ) ) {
                    option = null;
                } else {
                    option.set( 'isFocussed', true );
                }
            }
            this.set( 'focussedOption', option );
        }
        return this;
    },

    blurOption: function ( option ) {
        if ( this.get( 'focussedOption' ) === option ) {
            this.focusOption( null );
        }
        return this;
    },

    selectFocussed: function ( event ) {
        if ( event ) { event.preventDefault(); }
        var focussedOption = this.get( 'focussedOption' );
        if ( focussedOption && this.canSelect( focussedOption ) ) {
            focussedOption.activate( this );
        }
        return this;
    },

    // --- Filter ---

    filter: '',

    filterDidChange: function () {
        var value = this.get( 'filter' ).escapeRegExp(),
            pattern = value ? new RegExp( '(?:^|\\W)' + value, 'i' ) : null,
            options = this.get( 'options' ),
            l = options.get( 'length' ),
            focussedOption = this.get( 'focussedOption' );

        while ( l-- ) {
            options.getObjectAt( l ).filter( pattern );
        }
        if ( !focussedOption || !this.canSelect( focussedOption ) ) {
            this.focusOption( null ).focusNext();
        }
    }.observes( 'filter' ),

    // --- Keyboard support ---

    keyBindings: {
        esc: 'onEscape',
        enter: 'selectFocussed',
        up: 'focusPrevious',
        down: 'focusNext',
        left: 'closeIfSub',
        right: 'activateIfMenu'
    },

    triggerKeyBinding: function ( event ) {
        var key = NS.DOMEvent.lookupKey( event ),
            bindings = this.get( 'keyBindings' );
        if ( bindings[ key ] ) {
            event.stopPropagation();
            this[ bindings[ key ] ]( event, key );
        }
    }.on( 'keydown' ),

    onEscape: function ( event ) {
        event.preventDefault();
        var filter = this.get( 'filter' );
        if ( filter ) {
            this.set( 'filter', '' );
        } else {
            this.get( 'view' ).hide();
        }
    },

    closeIfSub: function () {
        var view = this.get( 'view' ),
            popOverView;
        if ( !view.get( 'showFilter' ) &&
                ( popOverView = view.getParent( NS.PopOverView ) ) &&
                  popOverView.get( 'parentPopOverView' ) ) {
            view.hide();
        }
    },

    activateIfMenu: function () {
        var focussedOption = this.get( 'focussedOption' );
        if ( focussedOption &&
                focussedOption.get( 'button' ) instanceof NS.MenuButtonView ) {
            this.selectFocussed();
        }
    }
});

var MenuOptionView = NS.Class({

    Extends: NS.View,

    isHidden: false,
    isDisabled: function () {
        return this.getFromPath( 'button.isDisabled' );
    }.property( 'button.isDisabled' ),
    isFocussed: false,
    isFocussable: function () {
        return !this.get( 'isHidden' ) && !this.get( 'isDisabled' );
    }.property( 'isHidden', 'isDisabled' ),

    layerTag: 'li',

    className: function () {
        return 'MenuOptionView' +
            ( this.get( 'isFocussed' ) ? ' focussed' : '' ) +
            ( this.get( 'isHidden' ) ? ' hidden' : '' );
    }.property( 'isFocussed', 'isHidden' ),

    init: function ( view, controller ) {
        this.childViews = [ view ];
        this.button = view;
        this.controller = controller;
        MenuOptionView.parent.init.call( this );
    },

    scrollIntoView: function () {
        if ( this.get( 'isFocussed' ) ) {
            var scrollView = this.getParent( NS.ScrollView );
            if ( scrollView ) {
                var scrollHeight = scrollView.get( 'pxHeight' ),
                    scrollTop = scrollView.get( 'scrollTop' ),
                    top = this.getPositionRelativeTo( scrollView ).top,
                    height = this.get( 'pxHeight' );

                if ( top < scrollTop ) {
                    scrollView.scrollTo( 0, top - ( height >> 1 ), true );
                } else if ( top + height > scrollTop + scrollHeight ) {
                    scrollView.scrollTo( 0,
                        top + height - scrollHeight + ( height >> 1 ), true );
                }
            }
        }
    }.observes( 'isFocussed' ),

    _focusTimeout: null,

    takeFocus: function () {
        if ( this.get( 'isInDocument' ) ) {
            this.get( 'controller' ).focusOption( this )
                .activateIfMenu();
        }
    },

    mouseMove: function () {
        if ( !this.get( 'isFocussed' ) && !this._focusTimeout ) {
            var popOverView = this.getParent( NS.PopOverView );
            if ( popOverView && popOverView.hasSubView() ) {
                this._focusTimeout = NS.RunLoop.invokeAfterDelay(
                    this.takeFocus, 75, this );
            } else {
                this.takeFocus();
            }
        }
    }.on( 'mousemove' ),

    mouseOut: function () {
        if ( this._focusTimeout ) {
            NS.RunLoop.cancel( this._focusTimeout );
            this._focusTimeout = null;
        }
        if ( !this.get( 'button' ).get( 'isActive' ) ) {
            this.get( 'controller' ).blurOption( this );
        }
    }.on( 'mouseout' ),

    filter: function ( pattern ) {
        var label = this.get( 'button' ).get( 'label' );
        this.set( 'isHidden', !!pattern && !pattern.test( label ) );
    },

    activate: function () {
        var button = this.get( 'button' );
        if ( button.activate ) { button.activate(); }
    }
});

var MenuView = NS.Class({

    Extends: NS.View,

    className: 'MenuView',

    showFilter: false,
    closeOnActivate: true,

    didCreateLayer: function ( layer ) {
        MenuView.parent.didCreateLayer.call( this, layer );
        layer.addEventListener( 'mousemove', this, false );
        layer.addEventListener( 'mouseout', this, false );
    },

    willDestroyLayer: function ( layer ) {
        layer.removeEventListener( 'mouseout', this, false );
        layer.removeEventListener( 'mousemove', this, false );
        MenuView.parent.willDestroyLayer.call( this, layer );
    },

    didEnterDocument: function () {
        MenuView.parent.didEnterDocument.call( this );
        var scrollView = this._scrollView,
            windowHeight, delta, controller, input;
        if ( scrollView ) {
            windowHeight = ( this.getParent( NS.ScrollView ) ||
                this.getParent( NS.RootView ) ).get( 'pxHeight' );
            delta = this.get( 'layer' ).getBoundingClientRect().bottom -
                windowHeight;
            // Must redraw immediately so size is correct when PopOverView
            // checks if it is positioned off screen.
            scrollView.set( 'layout', {
                maxHeight: Math.max(
                    scrollView.get( 'pxHeight' ) - delta - 10,
                    windowHeight / 2
                )
            }).redraw();
        }

        if ( this.get( 'showFilter' ) ) {
            controller = this.get( 'controller' );
            input = this._input;
            if ( !controller.get( 'focussedOption' ) ) {
                controller.focusNext();
            }
            NS.RunLoop.invokeInNextEventLoop( function () {
                input.focus().set( 'selection', {
                    start: 0,
                    end: input.get( 'value' ).length
                });
            });
        }
        return this;
    },

    didLeaveDocument: function () {
        var controller = this.get( 'controller' );
        if ( this.get( 'showFilter' ) ) {
            controller.set( 'filter', '' );
        } else {
            controller.focusOption( null );
        }
        return MenuView.parent.didLeaveDocument.call( this );
    },

    mayHaveResized: function () {
        this.parentViewDidResize();
    }.queue( 'after' ).observes( 'controller.filter' ),

    nextEventTarget: function () {
        return this.get( 'controller' );
    }.property( 'controller' ),

    controller: function () {
        return new MenuController({
            view: this
        });
    }.property(),

    ItemView: MenuOptionView,

    draw: function ( layer, Element, el ) {
        var controller = this.get( 'controller' ),
            MenuOptionView = this.get( 'ItemView' ),
            optionViews = this.get( 'options' ).map( function ( view ) {
                return new MenuOptionView( view, controller );
            });
        controller.set( 'options', optionViews );
        return [
            this.get( 'showFilter' ) ? el( 'div', [
                this._input = new NS.TextView({
                    blurOnEscape: false,
                    type: 'text filter',
                    value: NS.bindTwoWay( 'filter', this.get( 'controller' ) )
                })
            ]) : null,
            this._scrollView = new NS.ScrollView({
                positioning: 'relative',
                layout: {},
                layerTag: 'ul',
                childViews: optionViews
            })
        ];
    },

    hide: function () {
        var parent = this.get( 'parentView' );
        if ( parent ) {
            NS.RunLoop.invokeInNextEventLoop( parent.hide, parent );
        }
    },

    hideAll: function () {
        if ( this.get( 'closeOnActivate' ) ) {
            var popOverView = this.getParent( NS.PopOverView ) ||
                    this.get( 'parentView' ),
                parent;
            if ( popOverView ) {
                while ( parent = popOverView.get( 'parentPopOverView' ) ) {
                    popOverView = parent;
                }
                NS.RunLoop.invokeInNextEventLoop(
                    popOverView.hide, popOverView );
            }
        }
    }.on( 'button:activate' ),

    fireShortcut: function ( event ) {
        if ( !this.get( 'showFilter' ) ) {
            var key = NS.DOMEvent.lookupKey( event ),
                handler = NS.ViewEventsController
                            .kbShortcuts.getHandlerForKey( key ),
                parent, object, method;
            if ( handler ) {
                parent = object = handler[0];
                method = handler[1];
                // Check object is child view of the menu; we want to ignore any
                // other keyboard shortcuts.
                if ( object instanceof NS.View ) {
                    while ( parent && parent !== this ) {
                        parent = parent.get( 'parentView' );
                    }
                    if ( parent ) {
                        object[ method ]( event );
                        event.preventDefault();
                    }
                }
            }
        }
    }.on( 'keypress' )
});

NS.MenuController = MenuController;
NS.MenuOptionView = MenuOptionView;
NS.MenuView = MenuView;

}( this.O ) );
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------- \\
// File: TextView.js                                                          \\
// Module: ControlViews                                                       \\
// Requires: Core, Foundation, DOM, View, AbstractControlView.js              \\
// Author: Neil Jenkins                                                       \\
// License: © 2010–2013 FastMail Pty Ltd. All rights reserved.                \\
// -------------------------------------------------------------------------- \\

/*global document */

"use strict";

( function ( NS, undefined ) {

var nativePlaceholder = 'placeholder' in document.createElement( 'input' );

/**
    Class: O.TextView

    Extends: O.AbstractControlView

    A text input control. The `value` property is two-way bindable, representing
    the input text.
*/
var TextView = NS.Class({

    Extends: NS.AbstractControlView,

    init: function ( mixin ) {
        TextView.parent.init.call( this, mixin );
        this._settingFromInput = false;
    },

    /**
        Property: O.TextView#isMultiline
        Type: Boolean
        Default: false

        If set to true, the text field will accept line breaks.

        This property *must not* be changed after the view has been rendered.
    */
    isMultiline: false,

    /**
        Property: O.TextView#isExpanding
        Type: Boolean
        Default: false

        If <#isMultiline> is set to true, setting <#isExpanding> to true will
        make it automatically expand vertically to fit its contents, rather than
        show a scrollbar.

        This property *must not* be changed after the view has been rendered.
    */
    isExpanding: false,

    /**
        Property: O.TextView#isValid
        Type: Boolean
        Default: true

        If false, an `invalid' class will be added to the view's class name.
    */
    isValid: true,

    /**
        Property: O.TextView#isHighlighted
        Type: Boolean
        Default: false

        If true, a `highlight` class will be added to the view's class name.
        This is a styling hook for highlighting the view, e.g. if it fails
        validation.
    */
    isHighlighted: false,

    /**
        Property: O.TextView#isFocussed
        Type: Boolean

        Represents whether the view currently has focus or not.
    */
    isFocussed: false,

    /**
        Property: O.TextView#inputType
        Type: String
        Default: "text"

        The type property for the <input> DOM node (e.g. "password", "tel" etc.)

        This property *must not* be changed after the view has been rendered.
    */
    inputType: 'text',

    /**
        Property: O.TextView#placeholder
        Type: String
        Default: ''

        Placeholder text to be displayed in the text input when it is empty.
    */
    placeholder: '',

    /**
        Property: O.TextView#value
        Type: String
        Default: ''

        The value currently input in the text field.
    */
    value: '',

    /**
        Property: O.TextView#inputAttributes
        Type: Object

        Extra attributes to add to the text view. Examples include:

        - maxLength: Number
        - autocomplete: 'on' or 'off'
        - autocapitalize: 'on' or 'off'
        - autocorrect: 'on' or 'off'
        - pattern: String (regexp)
    */
    inputAttributes: {
        autocomplete: 'off'
    },

    /**
        Property: O.TextView#selection
        Type: Object

        When used as a getter, this will return an object with two properties:

        start - {Number} The number of characters offset from the beginning of
                the text that the selection starts.
        end   - {Number} The number of characters offset from the beginning of
                the text that the selection ends.

        Note, if there is no selection, the start and end values will be the
        same, and give the position of the cursor.

        When used as a setter, you can give it an object as described above to
        set the selection, or if you just want to give it a cursor position, you
        can pass a number instead.

        Note, this property is *not observable* and cannot be used to monitor
        changes in selection/cursor position.

    */
    selection: function ( selection ) {
        var control = this._domControl,
            isNumber = ( typeof selection === 'number' ),
            start = selection ? isNumber ?
                    selection : selection.start : 0,
            end = selection ? isNumber ?
                    selection : selection.end || start : start;
        if ( selection !== undefined ) {
            // Ensure any value changes have been drawn.
            this.redraw();
            // Firefox will throw an error if the control is not actually in the
            // document when trying to set the selection. There might be other
            // situations where it does so as well, so just using a try/catch to
            // guard against all.
            try {
                control.setSelectionRange( start, end );
            } catch ( error ) {}
        } else {
            // Firefox sometimes throws an error if you try to read the
            // selection. Again, probably if the control is not actually in the
            // document.
            try {
                start = control.selectionStart;
                end = control.selectionEnd;
            } catch ( error ) {}
        }
        return selection || {
            start: start,
            end: end
        };
    }.property().nocache(),

    /**
        Property: O.TextView#blurOnEscape
        Type: Boolean
        Default: true

        If true, if the user is focussed in the text view and hits the escape
        key, the focus will be removed.
    */
    blurOnEscape: true,

    // --- Render ---

    /**
        Property: O.TextView#allowTextSelection
        Type: Boolean
        Default: true

        Overrides default in <O.View#allowTextSelection>.
    */
    allowTextSelection: true,

    /**
        Property: O.TextView#type
        Type: String

        The type of the text view, as determined by the <#isMultiline> and
        <#isExpanding> properties. Will be one of `'expanding'`, `'multiline'`
        or `'text'`. Will be added to the view's class name.
    */
    type: function () {
        return this.get( 'isMultiline' ) ?
            this.get( 'isExpanding' ) ? 'expanding' : 'multiline' : 'text';
    }.property(),

    /**
        Property: O.TextView#className
        Type: String

        Overrides default in <O.View#className>. Will have the class `TextView`,
        and the class given in the <#type> property, along with the following
        other class names dependent on state:

        highlight - The <#isHighlighted> property is true.
        focussed  - The <#isFocussed> property is true.
        invalid   - The <#isValid> property is false.
        disabled  - The <#isDisabled> property is true.
    */
    className: function () {
        return 'TextView ' + this.get( 'type' ) +
            ( this.get( 'isHighlighted' ) ? ' highlight' : '' ) +
            ( this.get( 'isFocussed' ) ? ' focussed' : '' ) +
            ( this.get( 'isValid' ) ? '' : ' invalid' ) +
            ( this.get( 'isDisabled' ) ? ' disabled' : '' );
    }.property( 'type', 'isHighlighted',
        'isFocussed', 'isValid', 'isDisabled' ),

    /**
        Method: O.TextView#draw

        Overridden to draw view. See <O.View#draw>.
    */
    draw: function ( layer, Element, el ) {
        var value = this.get( 'value' ),
            placeholder = this.get( 'placeholder' ),
            control = this._domControl = el(
                this.get( 'isMultiline' ) ? 'textarea' : 'input', {
                    id: this.get( 'id' ) + '-input',
                    name: this.get( 'name' ),
                    type: this.get( 'inputType' ),
                    disabled: this.get( 'isDisabled' ),
                    tabIndex: this.get( 'tabIndex' ),
                    value: value
                });

        this.redrawInputAttributes();

        if ( placeholder ) {
            if ( nativePlaceholder ) {
                control.placeholder = placeholder;
            } else if ( !value ) {
                control.className = 'placeholder';
                control.value = placeholder;
                this._placeholderShowing = true;
            }
        }

        layer.title = this.get( 'tooltip' );

        return [
            this._domLabel = el( 'span', [ this.get( 'label' ) ] ),
            this.get( 'isExpanding' ) ? el( 'pre', [
                this._mirror = el( 'span', {
                    text: NS.bind( 'value', this )
                }),
                el( 'br' )
            ]) : null,
            control
        ];
    },

    // --- Keep render in sync with state ---

    /**
        Method: O.TextView#textNeedsRedraw

        Calls <O.View#propertyNeedsRedraw> for extra properties requiring
        redraw.
    */
    textNeedsRedraw: function ( self, property, oldValue ) {
        var isValue = ( property === 'value' );
        if ( !isValue || !this._settingFromInput ) {
            this.propertyNeedsRedraw( self, property, oldValue );
        }
        if ( isValue && this.get( 'isExpanding' ) ) {
            NS.RunLoop.queueFn( 'after', this.parentViewDidResize, this );
        }
    }.observes( 'value', 'placeholder', 'inputAttributes' ),

    /**
        Method: O.TextView#redrawValue

        Updates the content of the `<textarea>` or `<input>` to match the
        <#value> property.
    */
    redrawValue: function () {
        var value = this.get( 'value' );
        this._domControl.value = value;
        // Ensure placeholder is updated.
        if ( !this.get( 'isFocussed' ) ) {
            this._onBlur();
        }
    },

    /**
        Method: O.TextView#redrawPlaceholder

        Updates the placeholder text in the DOM when the <#placeholder> property
        changes.
    */
    redrawPlaceholder: function () {
        var placeholder = this.get( 'placeholder' ),
            control = this._domControl;
        if ( nativePlaceholder ) {
            control.placeholder = placeholder;
        } else if ( this._placeholderShowing ) {
            control.value = placeholder;
        }
    },

    /**
        Method: O.TextView#redrawInputAttributes

        Updates any other properties of the `<input>` element.
    */
    redrawInputAttributes: function () {
        var inputAttributes = this.get( 'inputAttributes' ),
            control = this._domControl,
            property;
        for ( property in inputAttributes ) {
            control.set( property, inputAttributes[ property ] );
        }
    },

    // --- Activate ---

    /**
        Method: O.TextView#activate

        Overridden to focus the text view. See <O.AbstractControlView#activate>.
    */
    activate: function () {
        this.focus();
    },

    // --- Scrolling and focus ---

    savedSelection: null,

    /**
        Method: O.TextView#didEnterDocument

        Overridden to restore scroll position and selection. See
        <O.View#didEnterDocument>.
    */
    didEnterDocument: function () {
        TextView.parent.didEnterDocument.call( this );
        // Restore scroll positions:
        if ( this.get( 'isMultiline' ) ) {
            var control = this._domControl,
                left = this.get( 'scrollLeft' ),
                top = this.get( 'scrollTop' );
            if ( left ) { control.scrollLeft = left; }
            if ( top ) { control.scrollTop = top; }
            control.addEventListener( 'scroll', this, false );
        }
        var selection = this.get( 'savedSelection' );
        if ( selection ) {
            this.set( 'selection', selection ).focus();
        }
        return this;
    },

    /**
        Method: O.TextView#willLeaveDocument

        Overridden to save scroll position and selection. See
        <O.View#willLeaveDocument>.
    */
    willLeaveDocument: function () {
        // If focussed, save cursor position
        if ( this.get( 'isFocussed' ) ) {
            this.set( 'savedSelection', this.get( 'selection' ) );
            this.blur();
        }
        // Stop listening for scrolls:
        if ( this.get( 'isMultiline' ) ) {
            this._domControl.removeEventListener( 'scroll', this, false );
        }
        return TextView.parent.willLeaveDocument.call( this );
    },

    /**
        Method (private): O.TextView#_syncBackScrolls

        Sets the <O.View#scrollLeft> and <O.View#scrollTop> properties whenever
        the user scrolls the textarea.

        Parameters:
            event - {Event} The scroll event.
    */
    _syncBackScrolls: function ( event ) {
        var control = this._domControl,
            left = control.scrollLeft,
            top = control.scrollTop;

        this.beginPropertyChanges()
            .set( 'scrollLeft', left )
            .set( 'scrollTop', top )
        .endPropertyChanges();

        event.stopPropagation();
    }.on( 'scroll' ),

    // --- Keep state in sync with render ---

    /**
        Method: O.TextView#syncBackValue

        Updates the <#value> property when the user interacts with the textarea.

        Parameters:
            event - {Event} The input event.
    */
    syncBackValue: function () {
        this._settingFromInput = true;
        this.set( 'value', this._domControl.value );
        this._settingFromInput = false;
    }.on( 'input' ),

    /**
        Method (private): O.TextView#_onFocus

        Updates the <#isFocussed> property and removes the placholder text for
        browsers that don't support this natively.

        Parameters:
            event - {Event} The focus event.
    */
    _onFocus: function () {
        if ( this._placeholderShowing ) {
            var control = this._domControl;
            control.className = '';
            control.value = '';
            this._placeholderShowing = false;
        }
        this.set( 'isFocussed', true );
    }.on( 'focus' ),

    /**
        Method (private): O.TextView#_onBlur

        Updates the <#isFocussed> property and adds the placholder text for
        browsers that don't support this natively.

        Parameters:
            event - {Event} The blur event.
    */
    _onBlur: function () {
        this.set( 'isFocussed', false );
        if ( !nativePlaceholder ) {
            var placeholder = this.get( 'placeholder' );
            if ( placeholder && !this.get( 'value' ) ) {
                var control = this._domControl;
                control.className = 'placeholder';
                control.value = placeholder;
                this._placeholderShowing = true;
            }
        }
    }.on( 'blur' ),

    /**
        Method (private): O.TextView#_onKeypress

        Stop IE automatically focussing the nearest button when the user hits
        enter in single line text inputs.

        Parameters:
            event - {Event} The keypress event.
    */
    _onKeypress: function ( event ) {
        var key = ( event.keyCode || event.which );
        // If key == enter, IE will automatically focus the nearest button
        // (presumably as though it were submitting the form). Stop this.
        if ( key === 13 && !this.get( 'isMultiline' ) ) {
            event.preventDefault();
        }
    }.on( 'keypress' ),

    /**
        Method (private): O.TextView#_blurOnEsc

        Blur the text area when the user hits escape, provided the
        <#blurOnEscape> property is set to `true`.

        Parameters:
            event - {Event} The keydown event.
    */
    _blurOnEsc: function ( event ) {
        var key = ( event.keyCode || event.which );
        // If key == esc, we want to blur. Not all browsers do this
        // automatically.
        if ( key === 27 && this.get( 'blurOnEscape' ) ) {
            this.blur();
        }
    }.on( 'keydown' )
});

if ( 8 <= NS.UA.msie && NS.UA.msie <= 9 ) {
    TextView.implement({
        _ieSyncBackValue: function ( event ) {
            var key = event.type === 'cut' ?
                'delete' : NS.DOMEvent.lookupKey( event );
            // IE9 fails to fire the input event on deletion of content.
            // IE8 fails to fire the propertychange event on deletion
            // and also if only a single character input (at least after a
            // deletion)
            if ( NS.UA.msie === 8 || key === 'backspace' || key === 'delete' ) {
                this.fire( 'input' );
            }
        }.on( 'keyup', 'cut' )
    });
}

NS.TextView = TextView;

}( this.O ) );
<commit_msg>Fix IE8 placeholder text gets set as TextView#value.<commit_after>// -------------------------------------------------------------------------- \\
// File: TextView.js                                                          \\
// Module: ControlViews                                                       \\
// Requires: Core, Foundation, DOM, View, AbstractControlView.js              \\
// Author: Neil Jenkins                                                       \\
// License: © 2010–2013 FastMail Pty Ltd. All rights reserved.                \\
// -------------------------------------------------------------------------- \\

/*global document */

"use strict";

( function ( NS, undefined ) {

var nativePlaceholder = 'placeholder' in document.createElement( 'input' );

/**
    Class: O.TextView

    Extends: O.AbstractControlView

    A text input control. The `value` property is two-way bindable, representing
    the input text.
*/
var TextView = NS.Class({

    Extends: NS.AbstractControlView,

    init: function ( mixin ) {
        TextView.parent.init.call( this, mixin );
        this._settingFromInput = false;
    },

    /**
        Property: O.TextView#isMultiline
        Type: Boolean
        Default: false

        If set to true, the text field will accept line breaks.

        This property *must not* be changed after the view has been rendered.
    */
    isMultiline: false,

    /**
        Property: O.TextView#isExpanding
        Type: Boolean
        Default: false

        If <#isMultiline> is set to true, setting <#isExpanding> to true will
        make it automatically expand vertically to fit its contents, rather than
        show a scrollbar.

        This property *must not* be changed after the view has been rendered.
    */
    isExpanding: false,

    /**
        Property: O.TextView#isValid
        Type: Boolean
        Default: true

        If false, an `invalid' class will be added to the view's class name.
    */
    isValid: true,

    /**
        Property: O.TextView#isHighlighted
        Type: Boolean
        Default: false

        If true, a `highlight` class will be added to the view's class name.
        This is a styling hook for highlighting the view, e.g. if it fails
        validation.
    */
    isHighlighted: false,

    /**
        Property: O.TextView#isFocussed
        Type: Boolean

        Represents whether the view currently has focus or not.
    */
    isFocussed: false,

    /**
        Property: O.TextView#inputType
        Type: String
        Default: "text"

        The type property for the <input> DOM node (e.g. "password", "tel" etc.)

        This property *must not* be changed after the view has been rendered.
    */
    inputType: 'text',

    /**
        Property: O.TextView#placeholder
        Type: String
        Default: ''

        Placeholder text to be displayed in the text input when it is empty.
    */
    placeholder: '',

    /**
        Property: O.TextView#value
        Type: String
        Default: ''

        The value currently input in the text field.
    */
    value: '',

    /**
        Property: O.TextView#inputAttributes
        Type: Object

        Extra attributes to add to the text view. Examples include:

        - maxLength: Number
        - autocomplete: 'on' or 'off'
        - autocapitalize: 'on' or 'off'
        - autocorrect: 'on' or 'off'
        - pattern: String (regexp)
    */
    inputAttributes: {
        autocomplete: 'off'
    },

    /**
        Property: O.TextView#selection
        Type: Object

        When used as a getter, this will return an object with two properties:

        start - {Number} The number of characters offset from the beginning of
                the text that the selection starts.
        end   - {Number} The number of characters offset from the beginning of
                the text that the selection ends.

        Note, if there is no selection, the start and end values will be the
        same, and give the position of the cursor.

        When used as a setter, you can give it an object as described above to
        set the selection, or if you just want to give it a cursor position, you
        can pass a number instead.

        Note, this property is *not observable* and cannot be used to monitor
        changes in selection/cursor position.

    */
    selection: function ( selection ) {
        var control = this._domControl,
            isNumber = ( typeof selection === 'number' ),
            start = selection ? isNumber ?
                    selection : selection.start : 0,
            end = selection ? isNumber ?
                    selection : selection.end || start : start;
        if ( selection !== undefined ) {
            // Ensure any value changes have been drawn.
            this.redraw();
            // Firefox will throw an error if the control is not actually in the
            // document when trying to set the selection. There might be other
            // situations where it does so as well, so just using a try/catch to
            // guard against all.
            try {
                control.setSelectionRange( start, end );
            } catch ( error ) {}
        } else {
            // Firefox sometimes throws an error if you try to read the
            // selection. Again, probably if the control is not actually in the
            // document.
            try {
                start = control.selectionStart;
                end = control.selectionEnd;
            } catch ( error ) {}
        }
        return selection || {
            start: start,
            end: end
        };
    }.property().nocache(),

    /**
        Property: O.TextView#blurOnEscape
        Type: Boolean
        Default: true

        If true, if the user is focussed in the text view and hits the escape
        key, the focus will be removed.
    */
    blurOnEscape: true,

    // --- Render ---

    /**
        Property: O.TextView#allowTextSelection
        Type: Boolean
        Default: true

        Overrides default in <O.View#allowTextSelection>.
    */
    allowTextSelection: true,

    /**
        Property: O.TextView#type
        Type: String

        The type of the text view, as determined by the <#isMultiline> and
        <#isExpanding> properties. Will be one of `'expanding'`, `'multiline'`
        or `'text'`. Will be added to the view's class name.
    */
    type: function () {
        return this.get( 'isMultiline' ) ?
            this.get( 'isExpanding' ) ? 'expanding' : 'multiline' : 'text';
    }.property(),

    /**
        Property: O.TextView#className
        Type: String

        Overrides default in <O.View#className>. Will have the class `TextView`,
        and the class given in the <#type> property, along with the following
        other class names dependent on state:

        highlight - The <#isHighlighted> property is true.
        focussed  - The <#isFocussed> property is true.
        invalid   - The <#isValid> property is false.
        disabled  - The <#isDisabled> property is true.
    */
    className: function () {
        return 'TextView ' + this.get( 'type' ) +
            ( this.get( 'isHighlighted' ) ? ' highlight' : '' ) +
            ( this.get( 'isFocussed' ) ? ' focussed' : '' ) +
            ( this.get( 'isValid' ) ? '' : ' invalid' ) +
            ( this.get( 'isDisabled' ) ? ' disabled' : '' );
    }.property( 'type', 'isHighlighted',
        'isFocussed', 'isValid', 'isDisabled' ),

    /**
        Method: O.TextView#draw

        Overridden to draw view. See <O.View#draw>.
    */
    draw: function ( layer, Element, el ) {
        var value = this.get( 'value' ),
            placeholder = this.get( 'placeholder' ),
            control = this._domControl = el(
                this.get( 'isMultiline' ) ? 'textarea' : 'input', {
                    id: this.get( 'id' ) + '-input',
                    name: this.get( 'name' ),
                    type: this.get( 'inputType' ),
                    disabled: this.get( 'isDisabled' ),
                    tabIndex: this.get( 'tabIndex' ),
                    value: value
                });

        this.redrawInputAttributes();

        if ( placeholder ) {
            if ( nativePlaceholder ) {
                control.placeholder = placeholder;
            } else if ( !value ) {
                this._placeholderShowing = true;
                control.className = 'placeholder';
                control.value = placeholder;
            }
        }

        layer.title = this.get( 'tooltip' );

        return [
            this._domLabel = el( 'span', [ this.get( 'label' ) ] ),
            this.get( 'isExpanding' ) ? el( 'pre', [
                this._mirror = el( 'span', {
                    text: NS.bind( 'value', this )
                }),
                el( 'br' )
            ]) : null,
            control
        ];
    },

    // --- Keep render in sync with state ---

    /**
        Method: O.TextView#textNeedsRedraw

        Calls <O.View#propertyNeedsRedraw> for extra properties requiring
        redraw.
    */
    textNeedsRedraw: function ( self, property, oldValue ) {
        var isValue = ( property === 'value' );
        if ( !isValue || !this._settingFromInput ) {
            this.propertyNeedsRedraw( self, property, oldValue );
        }
        if ( isValue && this.get( 'isExpanding' ) ) {
            NS.RunLoop.queueFn( 'after', this.parentViewDidResize, this );
        }
    }.observes( 'value', 'placeholder', 'inputAttributes' ),

    /**
        Method: O.TextView#redrawValue

        Updates the content of the `<textarea>` or `<input>` to match the
        <#value> property.
    */
    redrawValue: function () {
        var value = this.get( 'value' );
        this._domControl.value = value;
        // Ensure placeholder is updated.
        if ( !this.get( 'isFocussed' ) ) {
            this._onBlur();
        }
    },

    /**
        Method: O.TextView#redrawPlaceholder

        Updates the placeholder text in the DOM when the <#placeholder> property
        changes.
    */
    redrawPlaceholder: function () {
        var placeholder = this.get( 'placeholder' ),
            control = this._domControl;
        if ( nativePlaceholder ) {
            control.placeholder = placeholder;
        } else if ( this._placeholderShowing ) {
            control.value = placeholder;
        }
    },

    /**
        Method: O.TextView#redrawInputAttributes

        Updates any other properties of the `<input>` element.
    */
    redrawInputAttributes: function () {
        var inputAttributes = this.get( 'inputAttributes' ),
            control = this._domControl,
            property;
        for ( property in inputAttributes ) {
            control.set( property, inputAttributes[ property ] );
        }
    },

    // --- Activate ---

    /**
        Method: O.TextView#activate

        Overridden to focus the text view. See <O.AbstractControlView#activate>.
    */
    activate: function () {
        this.focus();
    },

    // --- Scrolling and focus ---

    savedSelection: null,

    /**
        Method: O.TextView#didEnterDocument

        Overridden to restore scroll position and selection. See
        <O.View#didEnterDocument>.
    */
    didEnterDocument: function () {
        TextView.parent.didEnterDocument.call( this );
        // Restore scroll positions:
        if ( this.get( 'isMultiline' ) ) {
            var control = this._domControl,
                left = this.get( 'scrollLeft' ),
                top = this.get( 'scrollTop' );
            if ( left ) { control.scrollLeft = left; }
            if ( top ) { control.scrollTop = top; }
            control.addEventListener( 'scroll', this, false );
        }
        var selection = this.get( 'savedSelection' );
        if ( selection ) {
            this.set( 'selection', selection ).focus();
        }
        return this;
    },

    /**
        Method: O.TextView#willLeaveDocument

        Overridden to save scroll position and selection. See
        <O.View#willLeaveDocument>.
    */
    willLeaveDocument: function () {
        // If focussed, save cursor position
        if ( this.get( 'isFocussed' ) ) {
            this.set( 'savedSelection', this.get( 'selection' ) );
            this.blur();
        }
        // Stop listening for scrolls:
        if ( this.get( 'isMultiline' ) ) {
            this._domControl.removeEventListener( 'scroll', this, false );
        }
        return TextView.parent.willLeaveDocument.call( this );
    },

    /**
        Method (private): O.TextView#_syncBackScrolls

        Sets the <O.View#scrollLeft> and <O.View#scrollTop> properties whenever
        the user scrolls the textarea.

        Parameters:
            event - {Event} The scroll event.
    */
    _syncBackScrolls: function ( event ) {
        var control = this._domControl,
            left = control.scrollLeft,
            top = control.scrollTop;

        this.beginPropertyChanges()
            .set( 'scrollLeft', left )
            .set( 'scrollTop', top )
        .endPropertyChanges();

        event.stopPropagation();
    }.on( 'scroll' ),

    // --- Keep state in sync with render ---

    /**
        Method: O.TextView#syncBackValue

        Updates the <#value> property when the user interacts with the textarea.

        Parameters:
            event - {Event} The input event.
    */
    syncBackValue: function () {
        this._settingFromInput = true;
        if ( nativePlaceholder || !this._placeholderShowing ) {
            this.set( 'value', this._domControl.value );
        }
        this._settingFromInput = false;
    }.on( 'input' ),

    /**
        Method (private): O.TextView#_onFocus

        Updates the <#isFocussed> property and removes the placholder text for
        browsers that don't support this natively.

        Parameters:
            event - {Event} The focus event.
    */
    _onFocus: function () {
        if ( this._placeholderShowing ) {
            this._placeholderShowing = false;
            var control = this._domControl;
            control.className = '';
            control.value = '';
        }
        this.set( 'isFocussed', true );
    }.on( 'focus' ),

    /**
        Method (private): O.TextView#_onBlur

        Updates the <#isFocussed> property and adds the placholder text for
        browsers that don't support this natively.

        Parameters:
            event - {Event} The blur event.
    */
    _onBlur: function () {
        this.set( 'isFocussed', false );
        if ( !nativePlaceholder ) {
            var placeholder = this.get( 'placeholder' );
            if ( placeholder && !this.get( 'value' ) ) {
                this._placeholderShowing = true;
                var control = this._domControl;
                control.className = 'placeholder';
                control.value = placeholder;
            }
        }
    }.on( 'blur' ),

    /**
        Method (private): O.TextView#_onKeypress

        Stop IE automatically focussing the nearest button when the user hits
        enter in single line text inputs.

        Parameters:
            event - {Event} The keypress event.
    */
    _onKeypress: function ( event ) {
        var key = ( event.keyCode || event.which );
        // If key == enter, IE will automatically focus the nearest button
        // (presumably as though it were submitting the form). Stop this.
        if ( key === 13 && !this.get( 'isMultiline' ) ) {
            event.preventDefault();
        }
    }.on( 'keypress' ),

    /**
        Method (private): O.TextView#_blurOnEsc

        Blur the text area when the user hits escape, provided the
        <#blurOnEscape> property is set to `true`.

        Parameters:
            event - {Event} The keydown event.
    */
    _blurOnEsc: function ( event ) {
        var key = ( event.keyCode || event.which );
        // If key == esc, we want to blur. Not all browsers do this
        // automatically.
        if ( key === 27 && this.get( 'blurOnEscape' ) ) {
            this.blur();
        }
    }.on( 'keydown' )
});

if ( 8 <= NS.UA.msie && NS.UA.msie <= 9 ) {
    TextView.implement({
        _ieSyncBackValue: function ( event ) {
            var key = event.type === 'cut' ?
                'delete' : NS.DOMEvent.lookupKey( event );
            // IE9 fails to fire the input event on deletion of content.
            // IE8 fails to fire the propertychange event on deletion
            // and also if only a single character input (at least after a
            // deletion)
            if ( NS.UA.msie === 8 || key === 'backspace' || key === 'delete' ) {
                this.fire( 'input' );
            }
        }.on( 'keyup', 'cut' )
    });
}

NS.TextView = TextView;

}( this.O ) );
<|endoftext|>


<commit_before>if ('Accelerometer' in window && 'Gyroscope' in window) {
  //document.getElementById('moApi').innerHTML = 'Generic Sensor API';

  let accelerometer = new Accelerometer();
  accelerometer.addEventListener('reading', e => MaccelerationHandler(accelerometer, 'moAccel'));
  accelerometer.start();

  let accelerometerWithGravity = new Accelerometer({includeGravity: true});
  accelerometerWithGravity.addEventListener('reading', e => MaccelerationHandler(accelerometerWithGravity, 'moAccelGrav'));
  accelerometerWithGravity.start();

  let gyroscope = new Gyroscope();
  gyroscope.addEventListener('reading', e => rotationHandler({
    alpha: gyroscope.x,
    beta: gyroscope.y,
    gamma: gyroscope.z
  }));
  gyroscope.start();

  intervalHandler('Not available in Generic Sensor API');

} else if ('DeviceMotionEvent' in window) {
  //document.getElementById('alert').style.display = 'none';
  //document.getElementById('moApi').innerHTML = 'Device Motion API';

  window.addEventListener('devicemotion', function (eventData) {
    accelerationHandler(eventData.acceleration, 'moAccel');
    accelerationHandler(eventData.accelerationIncludingGravity, 'moAccelGrav');
    rotationHandler(eventData.rotationRate);
    intervalHandler(eventData.interval);
  }, false);
} else {
  //document.getElementById('alert').style.display = 'none';
  //document.getElementById('moApi').innerHTML = 'No Accelerometer & Gyroscope API available';
}

function accelerationHandler(acceleration, targetId) {
  var info, xyz = "[X, Y, Z]";

  info = xyz.replace("X", acceleration.x && acceleration.x.toFixed(3));
  info = info.replace("Y", acceleration.y && acceleration.y.toFixed(3));
  info = info.replace("Z", acceleration.z && acceleration.z.toFixed(3));
  //document.getElementById(targetId).innerHTML = info;
}

function MaccelerationHandler(acceleration, targetId) {
  var info, xyz = "[X, Y, Z]";

  info = xyz.replace("X", acceleration.x && acceleration.x.toFixed(3));
  info = info.replace("Y", acceleration.y && acceleration.y.toFixed(3));
  info = info.replace("Z", acceleration.z && acceleration.z.toFixed(3));

  var zz = (acceleration.z && acceleration.z.toFixed(3));

  if(zz>10) {
    document.body.style.backgroundColor = "red";
  }
  //document.getElementById(targetId).innerHTML = info;
}

function rotationHandler(rotation) {
  var info, xyz = "[X, Y, Z]";

  info = xyz.replace("X", rotation.alpha && rotation.alpha.toFixed(3));
  info = info.replace("Y", rotation.beta && rotation.beta.toFixed(3));
  info = info.replace("Z", rotation.gamma && rotation.gamma.toFixed(3));
  //document.getElementById("moRotation").innerHTML = info;
}

function intervalHandler(interval) {
  //document.getElementById("moInterval").innerHTML = interval;
}

if (location.href.indexOf('debug') !== -1) {
  //document.getElementById('alert').style.display = 'none';
}<commit_msg>Update index.js<commit_after>if ('Accelerometer' in window && 'Gyroscope' in window) {
  //document.getElementById('moApi').innerHTML = 'Generic Sensor API';

  let accelerometer = new Accelerometer();
  accelerometer.addEventListener('reading', e => MaccelerationHandler(accelerometer, 'moAccel'));
  accelerometer.start();

  let accelerometerWithGravity = new Accelerometer({includeGravity: true});
  accelerometerWithGravity.addEventListener('reading', e => MaccelerationHandler(accelerometerWithGravity, 'moAccelGrav'));
  accelerometerWithGravity.start();

  let gyroscope = new Gyroscope();
  gyroscope.addEventListener('reading', e => rotationHandler({
    alpha: gyroscope.x,
    beta: gyroscope.y,
    gamma: gyroscope.z
  }));
  gyroscope.start();

  intervalHandler('Not available in Generic Sensor API');

} else if ('DeviceMotionEvent' in window) {
  //document.getElementById('alert').style.display = 'none';
  //document.getElementById('moApi').innerHTML = 'Device Motion API';

  window.addEventListener('devicemotion', function (eventData) {
    accelerationHandler(eventData.acceleration, 'moAccel');
    MaccelerationHandler(eventData.accelerationIncludingGravity, 'moAccelGrav');
    rotationHandler(eventData.rotationRate);
    intervalHandler(eventData.interval);
  }, false);
} else {
  //document.getElementById('alert').style.display = 'none';
  //document.getElementById('moApi').innerHTML = 'No Accelerometer & Gyroscope API available';
}

function accelerationHandler(acceleration, targetId) {
  var info, xyz = "[X, Y, Z]";

  info = xyz.replace("X", acceleration.x && acceleration.x.toFixed(3));
  info = info.replace("Y", acceleration.y && acceleration.y.toFixed(3));
  info = info.replace("Z", acceleration.z && acceleration.z.toFixed(3));
  //document.getElementById(targetId).innerHTML = info;
}

function MaccelerationHandler(acceleration, targetId) {
  var info, xyz = "[X, Y, Z]";

  var zz = (acceleration.z && acceleration.z.toFixed(3));

  if (zz>9.8) {
    document.body.style.backgroundColor = "red";
  }
}

function rotationHandler(rotation) {
  var info, xyz = "[X, Y, Z]";

  //info = xyz.replace("X", rotation.alpha && rotation.alpha.toFixed(3));
  //info = info.replace("Y", rotation.beta && rotation.beta.toFixed(3));
  //info = info.replace("Z", rotation.gamma && rotation.gamma.toFixed(3));

  var xx = (rotation.alpha && rotation.alpha.toFixed(3));
  var yy = (rotation.beta && rotation.beta.toFixed(3));
  var zz = (rotation.gamma && rotation.gamma.toFixed(3));

  var mean = (((xx)^2) + ((yy)^2) + ((zz)^2))*(1/2);
  //document.getElementById("mean").innerHTML = mean;
  //document.getElementById("moRotation").innerHTML = info;

}

function intervalHandler(interval) {
  //document.getElementById("moInterval").innerHTML = interval;
}

if (location.href.indexOf('debug') !== -1) {
  //document.getElementById('alert').style.display = 'none';
}
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import {VBox, HBox, Spacer} from "appy-comps";
import DragAction from "./DragAction";
import RemoteDB from "./RemoteDB";
import Transition from 'react-transition-group/Transition';

const duration = 250;

const defaultStyle = {
    transition: `opacity ${duration}ms ease-in-out`,
};

const transitionStyles = {
    entering: { opacity: 0 },
    entered:  { opacity: 1 },
    exiting:  { opacity: 1 },
    exited:   { opacity: 0 }
};

const Fade = ({ in: inProp, children, onDone }) => (
    <Transition in={inProp} timeout={0}  appear  addEndListener={node =>  node.addEventListener('transitionend', onDone,false)}>
        {(state) => (

                {children}

        )}
    </Transition>
);
export default class FakeWindow extends Component {
    constructor(props) {
        super(props);

        this.db = new RemoteDB("fakewindow");
        this.db.connect();
        this.state = {
            down: false,
            action: null,
            open:true,
        };
        this.moveHandler = (action) => {
            const a = this.props.app;
            this.props.onMove(a, a.x+action.delta.x, a.y + action.delta.y);
        };
        this.resizeHandler = (action) => {
            const a = this.props.app;
            this.props.onResize(a, a.w+action.delta.x, a.h + action.delta.y);
        };
        this.mouseDown = (e) => {
            this.db.sendMessage({
                type: 'command',
                target: 'system',
                command: "raise",
                appid: this.props.appid,
            });
            this.setState({action: new DragAction(e, this.moveHandler)});
        };
        this.resizeDown = (e) => this.setState({action: new DragAction(e, this.resizeHandler)});
        this.fadeWindow = () => {
            this.setState({open:false});
        };
        this.closeWindow = (node,done) => {
            if(this.state.open) return;
            this.db.sendMessage({
                type: 'command',
                target: 'system',
                command: "close",
                appid: this.props.appid,
            });
        };

        //handler for resize messages
        this.db.listenMessages((msg) => {
            if (msg.type !== 'command') return;
            if (msg.command !== 'resize') return;
            if (msg.appid !== this.props.appid) return;
            if (msg.width) this.props.onResize(this.props.app, msg.width, this.props.app.h);
            if (msg.height) this.props.onResize(this.props.app, this.props.app.w, msg.height);
        });
    }

    render() {
        const style = {
            top: this.props.app.y,
            left: this.props.app.x,
            width: this.props.app.w,
            height: this.props.app.h,
        };

        return(
            <Fade in={this.state.open} onDone={this.closeWindow}>
                <VBox className="window" style={style}>
                    <HBox onMouseDown={this.mouseDown} style={{userSelect: 'none', cursor: 'move'}} className="header">
                        {this.props.title}
                        <Spacer/>
                        <button className="fa fa-close" onClick={this.fadeWindow}/>
                    </HBox>
                    <VBox grow scroll>
                        {this.props.children}
                    </VBox>
                    <HBox className="footer">
                        <Spacer/>
                        <button className="fa fa-arrows-alt"
                                style={{
                                    cursor: 'nwse-resize'
                                }}
                                onMouseDown={this.resizeDown}/>
                    </HBox>
                </VBox>
            </Fade>
        )
    }
}<commit_msg>add scale as well as opacity<commit_after>import React, {Component} from 'react';
import {VBox, HBox, Spacer} from "appy-comps";
import DragAction from "./DragAction";
import RemoteDB from "./RemoteDB";
import Transition from 'react-transition-group/Transition';

const duration = 250;

const defaultStyle = {
    transition: `transform ${duration}ms ease-in-out, opacity ${duration}ms ease-in-out`,

};

const transitionStyles = {
    entering: { opacity: 0, transform: 'scale(1.3)' },
    entered:  { opacity: 1, transform: 'scale(1)'},
    exiting:  { opacity: 1, transform: 'scale(1)'},
    exited:   { opacity: 0, transform: 'scale(1.3)'}
};

const Fade = ({ in: inProp, children, onDone }) => (
    <Transition in={inProp} timeout={0}  appear  addEndListener={node =>  node.addEventListener('transitionend', onDone,false)}>
        {(state) => (

                {children}

        )}
    </Transition>
);
export default class FakeWindow extends Component {
    constructor(props) {
        super(props);

        this.db = new RemoteDB("fakewindow");
        this.db.connect();
        this.state = {
            down: false,
            action: null,
            open:true,
        };
        this.moveHandler = (action) => {
            const a = this.props.app;
            this.props.onMove(a, a.x+action.delta.x, a.y + action.delta.y);
        };
        this.resizeHandler = (action) => {
            const a = this.props.app;
            this.props.onResize(a, a.w+action.delta.x, a.h + action.delta.y);
        };
        this.mouseDown = (e) => {
            this.db.sendMessage({
                type: 'command',
                target: 'system',
                command: "raise",
                appid: this.props.appid,
            });
            this.setState({action: new DragAction(e, this.moveHandler)});
        };
        this.resizeDown = (e) => this.setState({action: new DragAction(e, this.resizeHandler)});
        this.fadeWindow = () => {
            this.setState({open:false});
        };
        this.closeWindow = (node,done) => {
            if(this.state.open) return;
            this.db.sendMessage({
                type: 'command',
                target: 'system',
                command: "close",
                appid: this.props.appid,
            });
        };

        //handler for resize messages
        this.db.listenMessages((msg) => {
            if (msg.type !== 'command') return;
            if (msg.command !== 'resize') return;
            if (msg.appid !== this.props.appid) return;
            if (msg.width) this.props.onResize(this.props.app, msg.width, this.props.app.h);
            if (msg.height) this.props.onResize(this.props.app, this.props.app.w, msg.height);
        });
    }

    render() {
        const style = {
            top: this.props.app.y,
            left: this.props.app.x,
            width: this.props.app.w,
            height: this.props.app.h,
        };

        return(
            <Transition in={this.state.open} timeout={0} appear addEndListener={node => node.addEventListener('transitionend', this.closeWindow, false)}>
                {(state) => (
                <VBox className="window" style={{
                    ...style,
                    ...defaultStyle,
                    ...transitionStyles[state]
                }}>
                    <HBox onMouseDown={this.mouseDown} style={{userSelect: 'none', cursor: 'move'}} className="header">
                        {this.props.title}
                        <Spacer/>
                        <button className="fa fa-close" onClick={this.fadeWindow}/>
                    </HBox>
                    <VBox grow scroll>
                        {this.props.children}
                    </VBox>
                    <HBox className="footer">
                        <Spacer/>
                        <button className="fa fa-arrows-alt"
                                style={{
                                    cursor: 'nwse-resize'
                                }}
                                onMouseDown={this.resizeDown}/>
                    </HBox>
                </VBox>
                    )}
            </Transition>
        )
    }

    componentWillReceiveProps(newProps) {
    }
}<|endoftext|>


<commit_before>// @flow
import * as React from 'react'
import type {FilterType} from './types'
import {SingleToggleSection} from './section-toggle'
import {ListSection} from './section-list'
import {PickerSection} from './section-picker'

type FilterSectionPropsType = {
	filter: FilterType,
	onChange: (filter: FilterType) => any,
}

export function FilterSection({filter, onChange}: FilterSectionPropsType) {
	if (filter.type === 'toggle') {
		return <SingleToggleSection filter={filter} onChange={onChange} />
	}

	if (filter.type === 'list') {
		if (!filter.spec.options.length) {
			return null
		}

		return <ListSection filter={filter} onChange={onChange} />
	}

	if (filter.type === 'picker') {
		if (filter.spec.options.length < 2) {
			return null
		}

		return <PickerSection filter={filter} onChange={onChange} />
	}

	return null
}
<commit_msg>make filter list section scrollable<commit_after>// @flow
import * as React from 'react'
import {ScrollView} from 'react-native'
import type {FilterType} from './types'
import {SingleToggleSection} from './section-toggle'
import {ListSection} from './section-list'
import {PickerSection} from './section-picker'

type FilterSectionPropsType = {
	filter: FilterType,
	onChange: (filter: FilterType) => any,
}

export function FilterSection({filter, onChange}: FilterSectionPropsType) {
	if (filter.type === 'toggle') {
		return <SingleToggleSection filter={filter} onChange={onChange} />
	}

	if (filter.type === 'list') {
		if (!filter.spec.options.length) {
			return null
		}

		return (
			<ScrollView>
				<ListSection filter={filter} onChange={onChange} />
			</ScrollView>
		)
	}

	if (filter.type === 'picker') {
		if (filter.spec.options.length < 2) {
			return null
		}

		return <PickerSection filter={filter} onChange={onChange} />
	}

	return null
}
<|endoftext|>


<commit_before><commit_msg>More typo fixes<commit_after><|endoftext|>


<commit_before>import _ from 'lodash';
// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { PropTypes } from 'react';
import AddressList from '@folio/stripes-components/lib/structures/AddressFieldGroup/AddressList';
import Select from '@folio/stripes-components/lib/Select';

import Autocomplete from '../Autocomplete';
import { countriesOptions } from '../../data/countries';
import { addressTypeOptions } from '../../data/addressTypes';
import { toListAddresses, toUserAddresses } from './converters';

const addressFields = {
  country: { component: Autocomplete, props: { dataOptions: countriesOptions } },
  addressType: { component: Select, props: { dataOptions: addressTypeOptions } },
};

console.log(addressFields);

class UserAddresses extends React.Component {
  static propTypes = {
    addresses: PropTypes.arrayOf(PropTypes.object),
    onUpdate: PropTypes.func,
  };

  constructor(props) {
    super(props);
    this.onAddressUpdate = this.onAddressUpdate.bind(this);
    this.state = (props.addresses) ?
      { addresses: toListAddresses(props.addresses) } : {};
  }

  onAddressUpdate(addr) {
    this.addAddress(addr);
    this.props.onUpdate(toUserAddresses(this.state.addresses));
  }

  addAddress(addr) {
    const addresses = this.state.addresses;
    let index = 0;

    /* eslint-disable no-param-reassign */
    addr.id = addr.id || _.uniqueId();

    if (addresses.length) {
      index = _.findIndex(addresses, a => a.id === addr.id);
      if (index === -1) index = addresses.length;
    }

    addresses[index] = addr;
    this.setState({ addresses });
  }

  render() {
    if (!this.state.addresses) return (<div />);

    return (<AddressList
      onUpdate={this.onAddressUpdate}
      onCreate={this.onAddressUpdate}
      fieldComponents={addressFields}
      addresses={this.state.addresses}
      canEdit
      canDelete
    />);
  }
}

export default UserAddresses;
<commit_msg>cleanup<commit_after>import _ from 'lodash';
// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { PropTypes } from 'react';
import AddressList from '@folio/stripes-components/lib/structures/AddressFieldGroup/AddressList';
import Select from '@folio/stripes-components/lib/Select';

import Autocomplete from '../Autocomplete';
import { countriesOptions } from '../../data/countries';
import { addressTypeOptions } from '../../data/addressTypes';
import { toListAddresses, toUserAddresses } from './converters';

const addressFields = {
  country: { component: Autocomplete, props: { dataOptions: countriesOptions } },
  addressType: { component: Select, props: { dataOptions: addressTypeOptions } },
};

class UserAddresses extends React.Component {
  static propTypes = {
    addresses: PropTypes.arrayOf(PropTypes.object),
    onUpdate: PropTypes.func,
  };

  constructor(props) {
    super(props);
    this.onAddressUpdate = this.onAddressUpdate.bind(this);
    this.state = (props.addresses) ?
      { addresses: toListAddresses(props.addresses) } : {};
  }

  onAddressUpdate(addr) {
    this.addAddress(addr);
    this.props.onUpdate(toUserAddresses(this.state.addresses));
  }

  addAddress(addr) {
    const addresses = this.state.addresses;
    let index = 0;

    /* eslint-disable no-param-reassign */
    addr.id = addr.id || _.uniqueId();

    if (addresses.length) {
      index = _.findIndex(addresses, a => a.id === addr.id);
      if (index === -1) index = addresses.length;
    }

    addresses[index] = addr;
    this.setState({ addresses });
  }

  render() {
    if (!this.state.addresses) return (<div />);

    return (<AddressList
      onUpdate={this.onAddressUpdate}
      onCreate={this.onAddressUpdate}
      fieldComponents={addressFields}
      addresses={this.state.addresses}
      canEdit
      canDelete
    />);
  }
}

export default UserAddresses;
<|endoftext|>