<commit_before>/* Copyright 2015 Sébastien Maccagnoni-Munch
 *
 * This file is part of AwesomeShop.
 *
 * AwesomeShop is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * AwesomeShop is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with AwesomeShop. If not, see <http://www.gnu.org/licenses/>.
 */

angular.module('dbProducts', ['angularFileUpload', 'slugifier'])
.config(function($stateProvider) {
    $stateProvider
        .state('products', {
            url: '/product',
            templateUrl: 'products',
            controller: 'ProductsCtrl'
        })
        .state('newproduct', {
            url: '/product/new',
            templateUrl: 'product',
            controller: 'ProductCtrl'
        })
        .state('product', {
            url: '/product-{product_type}/:product_id',
            templateUrl: function($stateParams) {
                return 'product-'+$stateParams.product_type;
            },
            controller: 'ProductCtrl'
        })
})
.controller('ProductsCtrl', function($scope, $http) {
    $http.get('/api/product')
        .then(function(response) {
            $scope.products = response.data;
        });
})
.controller('ProductCtrl', function($timeout, $scope, $http, $stateParams, $state, FileUploader, Slug, CONFIG) {
    $scope.langs = CONFIG.languages;
    $scope.sortoptions = {containment:'#photos'};
    $scope.sort_photo = function(from_rank, to_rank) {
        $http.get('/api/product/'+$scope.product.id+'/photo/'+from_rank+'/move/'+to_rank);
    };
    $http.get('/api/category', {params: {'flat':'true'}})
        .then(function(response) {
            $scope.categories = response.data;
        });
    $http.get('/api/product')
        .then(function(response) {
            $scope.products = response.data;
        });
    $http.get('/api/page-doc')
        .then(function(response) {
            $scope.documentations = response.data;
        });
    $http.get('/api/taxrate')
        .then(function(response) {
            $scope.taxrates = response.data;
        })
    function reinit(pid) {
        $scope.uploader = new FileUploader({
            url: '/api/product/'+pid+'/photo',
            autoUpload: true,
            removeAfterUpload: true
        });
        $scope.uploader.onSuccessItem = function(item, response, status, header) {
            $scope.photos.push(response);
        };
    }
    $scope.name_from_id = function(prodid) {
        if ($scope.products) {
            for (i=0; i<$scope.products.length; i++) {
                if ($scope.products[i].id == prodid) {
                    return $scope.products[i].name;
                }
            }
        }
        return prodid;
    }
    $scope.filtered_products = function() {
        var filtered = [];
        if ($scope.products && $scope.product) {
            if ($scope.product.id) {
                for (i=0; i<$scope.products.length; i++) {
                    if ($scope.products[i].id != $scope.product.id && $scope.product.related_products.indexOf($scope.products[i].id) == -1) {
                        filtered.push($scope.products[i])
                    }
                }
            } else {
                filtered = $scope.products;
            }
        }
        return filtered;
    }
    $scope.add_prod = function(prodid) {
        $scope.product.related_products.push(prodid);
        $scope.product.related_products.sort();
        $scope.form.$setDirty();
    }
    $scope.remove_prod = function(prodid) {
        $scope.product.related_products.splice($scope.product.related_products.indexOf(prodid), 1);
        $scope.form.$setDirty();
    }
    $scope.net_price = function() {
        if ($scope.taxrates && $scope.product) {
            for (i=0; i<$scope.taxrates.length; i++) {
                if ($scope.product.tax == $scope.taxrates[i].id) {
                    return parseFloat($scope.product.gross_price) * ( 1 + parseFloat($scope.taxrates[i].rate) );
                }
            }
        }
        return '?';
    }
    $scope.submit = function() {
        if ($scope.product.id) {
            $http.put('/api/product-'+$scope.product.type+'/'+$scope.product.id+'/edit', $scope.product)
                .then(function(response) {
                    $scope.product = response.data;
                    $scope.form.$setPristine();
                });
        } else {
            $http.post('/api/product-'+$scope.product.type, $scope.product)
                .then(function(response) {
                    $scope.product = response.data;
                    $scope.form.$setPristine();
                    reinit($scope.product.id);
                    $state.go('product', {product_id:response.data.id}, {notify:false});
                });
        };
    }
    $scope.delete = function() {
        if ($scope.product.id) {
            $http.delete('/api/product-'+$scope.product.type+'/'+$scope.product.id+'/edit')
                .then(function(response) {
                    $state.go('products');
                });
        } else {
            $state.go('products');
        }
    };
    $scope.slug_from = function(text) {
        $scope.product.slug = Slug.slugify(text);
    };
    $scope.delete_photo = function(filename, index) {
        $http.delete('/api/product/'+$scope.product.id+'/photo/'+filename)
            .then(function() {
                $scope.photos.splice(index, 1);
            })
    }
    if ($stateParams.product_id) {
        $http.get('/api/product-'+$stateParams.product_type+'/'+$stateParams.product_id+'/edit')
            .then(function(response) {
                $scope.product = response.data;
                // angular-sortable-view doesn't seem to work with embedded lists
                $scope.photos = $scope.product.photos;
                $scope.displayable_from_id($scope, 'categories', $scope.product.category)
                $scope.displayable_from_id($scope, 'documentations', $scope.product.documentation)
                reinit($scope.product.id);
            });
    } else {
        $scope.product = {
            related_products: []
        };
    }
});
<commit_msg>Display slug if there is no name in the "related products" list<commit_after>/* Copyright 2015 Sébastien Maccagnoni-Munch
 *
 * This file is part of AwesomeShop.
 *
 * AwesomeShop is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * AwesomeShop is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with AwesomeShop. If not, see <http://www.gnu.org/licenses/>.
 */

angular.module('dbProducts', ['angularFileUpload', 'slugifier'])
.config(function($stateProvider) {
    $stateProvider
        .state('products', {
            url: '/product',
            templateUrl: 'products',
            controller: 'ProductsCtrl'
        })
        .state('newproduct', {
            url: '/product/new',
            templateUrl: 'product',
            controller: 'ProductCtrl'
        })
        .state('product', {
            url: '/product-{product_type}/:product_id',
            templateUrl: function($stateParams) {
                return 'product-'+$stateParams.product_type;
            },
            controller: 'ProductCtrl'
        })
})
.controller('ProductsCtrl', function($scope, $http) {
    $http.get('/api/product')
        .then(function(response) {
            $scope.products = response.data;
        });
})
.controller('ProductCtrl', function($timeout, $scope, $http, $stateParams, $state, FileUploader, Slug, CONFIG) {
    $scope.langs = CONFIG.languages;
    $scope.sortoptions = {containment:'#photos'};
    $scope.sort_photo = function(from_rank, to_rank) {
        $http.get('/api/product/'+$scope.product.id+'/photo/'+from_rank+'/move/'+to_rank);
    };
    $http.get('/api/category', {params: {'flat':'true'}})
        .then(function(response) {
            $scope.categories = response.data;
        });
    $http.get('/api/product')
        .then(function(response) {
            $scope.products = response.data;
        });
    $http.get('/api/page-doc')
        .then(function(response) {
            $scope.documentations = response.data;
        });
    $http.get('/api/taxrate')
        .then(function(response) {
            $scope.taxrates = response.data;
        })
    function reinit(pid) {
        $scope.uploader = new FileUploader({
            url: '/api/product/'+pid+'/photo',
            autoUpload: true,
            removeAfterUpload: true
        });
        $scope.uploader.onSuccessItem = function(item, response, status, header) {
            $scope.photos.push(response);
        };
    }
    $scope.name_from_id = function(prodid) {
        if ($scope.products) {
            for (i=0; i<$scope.products.length; i++) {
                if ($scope.products[i].id == prodid) {
                    return $scope.products[i].name || $scope.products[i].slug;
                }
            }
        }
        return prodid;
    }
    $scope.filtered_products = function() {
        var filtered = [];
        if ($scope.products && $scope.product) {
            if ($scope.product.id) {
                for (i=0; i<$scope.products.length; i++) {
                    if ($scope.products[i].id != $scope.product.id && $scope.product.related_products.indexOf($scope.products[i].id) == -1) {
                        filtered.push($scope.products[i])
                    }
                }
            } else {
                filtered = $scope.products;
            }
        }
        return filtered;
    }
    $scope.add_prod = function(prodid) {
        $scope.product.related_products.push(prodid);
        $scope.product.related_products.sort();
        $scope.form.$setDirty();
    }
    $scope.remove_prod = function(prodid) {
        $scope.product.related_products.splice($scope.product.related_products.indexOf(prodid), 1);
        $scope.form.$setDirty();
    }
    $scope.net_price = function() {
        if ($scope.taxrates && $scope.product) {
            for (i=0; i<$scope.taxrates.length; i++) {
                if ($scope.product.tax == $scope.taxrates[i].id) {
                    return parseFloat($scope.product.gross_price) * ( 1 + parseFloat($scope.taxrates[i].rate) );
                }
            }
        }
        return '?';
    }
    $scope.submit = function() {
        if ($scope.product.id) {
            $http.put('/api/product-'+$scope.product.type+'/'+$scope.product.id+'/edit', $scope.product)
                .then(function(response) {
                    $scope.product = response.data;
                    $scope.form.$setPristine();
                });
        } else {
            $http.post('/api/product-'+$scope.product.type, $scope.product)
                .then(function(response) {
                    $scope.product = response.data;
                    $scope.form.$setPristine();
                    reinit($scope.product.id);
                    $state.go('product', {product_id:response.data.id}, {notify:false});
                });
        };
    }
    $scope.delete = function() {
        if ($scope.product.id) {
            $http.delete('/api/product-'+$scope.product.type+'/'+$scope.product.id+'/edit')
                .then(function(response) {
                    $state.go('products');
                });
        } else {
            $state.go('products');
        }
    };
    $scope.slug_from = function(text) {
        $scope.product.slug = Slug.slugify(text);
    };
    $scope.delete_photo = function(filename, index) {
        $http.delete('/api/product/'+$scope.product.id+'/photo/'+filename)
            .then(function() {
                $scope.photos.splice(index, 1);
            })
    }
    if ($stateParams.product_id) {
        $http.get('/api/product-'+$stateParams.product_type+'/'+$stateParams.product_id+'/edit')
            .then(function(response) {
                $scope.product = response.data;
                // angular-sortable-view doesn't seem to work with embedded lists
                $scope.photos = $scope.product.photos;
                $scope.displayable_from_id($scope, 'categories', $scope.product.category)
                $scope.displayable_from_id($scope, 'documentations', $scope.product.documentation)
                reinit($scope.product.id);
            });
    } else {
        $scope.product = {
            related_products: []
        };
    }
});
<|endoftext|>


<commit_before>import helper from 'tipsi-appium-helper'

helper.extend('openExampleFor', async (exampleName, wait = 60000) => {
  const { driver, idFromAccessId } = helper

  const listId = idFromAccessId('List')

  const examplesNameId = idFromAccessId(exampleName)

  // TODO: add find item with swipe

  await driver.waitForVisible(listId, wait)

  await driver.waitForVisible(examplesNameId, wait).click(examplesNameId)
})
<commit_msg>Implemented back to list action in e2e tests<commit_after>import helper from 'tipsi-appium-helper'

helper.extend('openExampleFor', async (exampleName, wait = 6000) => {
  const { driver, platform, idFromAccessId, idFromXPath } = helper

  const listId = idFromAccessId('List')
  const backId = idFromXPath(`//
    XCUIElementTypeApplication/XCUIElementTypeWindow/
    XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/
    XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/
    XCUIElementTypeOther/XCUIElementTypeOther/XCUIElementTypeOther/
    XCUIElementTypeOther
  `)
  const examplesNameId = idFromAccessId(exampleName)

  // TODO: add find item with swipe

  try {
    await driver.waitForVisible(listId, wait)
  } catch (error) {
    if (platform('android')) {
      await driver.back()
    } else {
      await driver.click(backId)
    }
  }

  await driver.waitForVisible(examplesNameId, wait).click(examplesNameId)
})
<|endoftext|>


<commit_before>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {Component, PropTypes} from 'react';
import Immutable, { List, Map } from 'immutable';
import classNames from 'classnames';
import provide from 'react-redux-provide';
import ConfGlobal from 'conf/local.json';
import selectn from 'selectn';

import PromiseWrapper from 'views/components/Document/PromiseWrapper';

import TextHeader from 'views/components/Document/Typography/text-header';

import ProviderHelpers from 'common/ProviderHelpers';
import PageDialectLearnBase from 'views/pages/explore/dialect/learn/base';
import AlphabetListView from 'views/pages/explore/dialect/learn/alphabet/list-view';

import Paper from 'material-ui/lib/paper';
import FlatButton from 'material-ui/lib/flat-button';
import GridTile from 'material-ui/lib/grid-list/grid-tile';

import Header from 'views/pages/explore/dialect/header';
import ToolbarNavigation from 'views/pages/explore/dialect/learn/base/toolbar-navigation';
import LearningSidebar from 'views/pages/explore/dialect/learn/base/learning-sidebar';

class AlphabetGridTile extends Component {

  constructor(props) {
    super(props)
  }

  render() {
    return <GridTile key={selectn('uid', this.props.tile)} style={{border: '3px solid #e0e0e0', borderRadius: '5px', textAlign: 'center', paddingTop: '15px'}}>
      {selectn('properties.fvcharacter:upper_case_character', this.props.tile)} {selectn('properties.dc:title', this.props.tile)}

      {selectn('contextParameters.character.related_words[0].dc:title', this.props.tile)}

      {selectn('contextParameters.character.related_words[0].fv:definitions[0].translation', this.props.tile) || selectn('contextParameters.character.related_words[0].fv:literal_translation[0].translation', this.props.tile)}
    </GridTile>;
  }
}

/**
* Learn alphabet
*/
@provide
export default class PageDialectLearnAlphabet extends PageDialectLearnBase {

  static defaultProps = {
    print: false
  }

  static propTypes = {
    properties: PropTypes.object.isRequired,
    navigateTo: PropTypes.func.isRequired,
    windowPath: PropTypes.string.isRequired,
    pushWindowPath: PropTypes.func.isRequired,
    splitWindowPath: PropTypes.array.isRequired,
    fetchDocument: PropTypes.func.isRequired,
    computeDocument: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    fetchDialect2: PropTypes.func.isRequired,
    computeDialect2: PropTypes.object.isRequired,
    fetchCharacters: PropTypes.func.isRequired,
    computeCharacters: PropTypes.object.isRequired,
    updateDialect2: PropTypes.func.isRequired,
    fetchPortal: PropTypes.func.isRequired,
    computePortal: PropTypes.object.isRequired,
    updatePortal: PropTypes.func.isRequired,
    routeParams: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    print: PropTypes.bool
  };

  constructor(props, context) {
    super(props, context);
    // Bind methods to 'this'
    ['_onNavigateRequest'].forEach( (method => this[method] = this[method].bind(this)) );
  }

  fetchData(newProps) {
    newProps.fetchDialect2(newProps.routeParams.dialect_path);
    newProps.fetchPortal(newProps.routeParams.dialect_path + '/Portal');

    newProps.fetchDocument(newProps.routeParams.dialect_path + '/Dictionary');

    newProps.fetchCharacters(newProps.routeParams.dialect_path + '/Alphabet', '&sortOrder=asc&sortBy=fvcharacter:alphabet_order');
  }

  _onCharAudioTouchTap(charAudioId) {
	  document.getElementById(charAudioId).play();
  }

  _onNavigateRequest(path) {
    const destination = this.props.navigateTo(path);
    const newPathArray = this.props.splitWindowPath.slice();

    newPathArray.push(destination.path);

    this.props.pushWindowPath('/' + newPathArray.join('/'));
  }

  render() {

    const computeEntities = Immutable.fromJS([{
      'id': this.props.routeParams.dialect_path,
      'entity': this.props.computeDialect2
    }, {
      'id': this.props.routeParams.dialect_path + '/Portal',
      'entity': this.props.computePortal
    }])

    const { updatePortal, updateDialect2, computeLogin } = this.props;

    const computeDocument = ProviderHelpers.getEntry(this.props.computeDocument, this.props.routeParams.dialect_path + '/Dictionary');
    const computeDialect2 = ProviderHelpers.getEntry(this.props.computeDialect2, this.props.routeParams.dialect_path);
    const computePortal = ProviderHelpers.getEntry(this.props.computePortal, this.props.routeParams.dialect_path + '/Portal');

    const computeCharacters = ProviderHelpers.getEntry(this.props.computeCharacters, this.props.routeParams.dialect_path + '/Alphabet');

    const isSection = this.props.routeParams.area === 'sections';

    const alphabetListView = <AlphabetListView pagination={false} routeParams={this.props.routeParams} dialect={selectn('response', computeDialect2)} />;

    if (this.props.print) {
      return <PromiseWrapper renderOnError={true} computeEntities={computeEntities}>

{selectn('response.title', computeDialect2)} Alphabet

                {React.cloneElement(alphabetListView, { gridListView: true, gridViewProps: {style:{overflowY: 'auto', maxHeight: '100%'}}, gridListTile: AlphabetGridTile, dialect: selectn('response', computeDialect2) })}

            </PromiseWrapper>;
    }

    return <PromiseWrapper renderOnError={true} computeEntities={computeEntities}>

                <ToolbarNavigation showStats={this._showStats} routeParams={this.props.routeParams} />

                  <TextHeader title={selectn('response.title', computeDialect2) + " Alphabet"} tag="h1" properties={this.props.properties} appendToTitle={print} />

                  {(() => {

                      const characters = selectn('response.entries', computeCharacters);

                      if (characters && characters.length > 0) {
                          return

                          {selectn('response.entries', computeCharacters).map((char, i) =>
                            <Paper key={char.uid} style={{textAlign: 'center', margin: '5px', padding: '5px 10px', display: 'inline-block'}}>
                              <FlatButton onTouchTap={this._onNavigateRequest.bind(this, char.path.split('/')[char.path.split('/').length-1])} label={char.title} style={{minWidth: 'inherit', textTransform: 'initial'}} />
                              {(char.contextParameters.character.related_audio[0]) ?

                                  <audio id={'charAudio' + char.uid}  src={ConfGlobal.baseURL + char.contextParameters.character.related_audio[0].path} />

                              : ''}
                            </Paper>
                          )}

;
                        }

                    })()}

                <LearningSidebar
                  isSection={isSection}
                  properties={this.props.properties}
                  dialect={{compute: computeDialect2, update: updateDialect2}} />

        </PromiseWrapper>;
  }
}<commit_msg>FV-112: Fixed alphabet index page not loading<commit_after>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {Component, PropTypes} from 'react';
import Immutable, { List, Map } from 'immutable';
import classNames from 'classnames';
import provide from 'react-redux-provide';
import ConfGlobal from 'conf/local.json';
import selectn from 'selectn';

import PromiseWrapper from 'views/components/Document/PromiseWrapper';

import TextHeader from 'views/components/Document/Typography/text-header';

import ProviderHelpers from 'common/ProviderHelpers';
import PageDialectLearnBase from 'views/pages/explore/dialect/learn/base';
import AlphabetListView from 'views/pages/explore/dialect/learn/alphabet/list-view';

import Paper from 'material-ui/lib/paper';
import FlatButton from 'material-ui/lib/flat-button';
import GridTile from 'material-ui/lib/grid-list/grid-tile';

import Header from 'views/pages/explore/dialect/header';
import ToolbarNavigation from 'views/pages/explore/dialect/learn/base/toolbar-navigation';
import LearningSidebar from 'views/pages/explore/dialect/learn/base/learning-sidebar';

class AlphabetGridTile extends Component {

  constructor(props) {
    super(props)
  }

  render() {
    return <GridTile key={selectn('uid', this.props.tile)} style={{border: '3px solid #e0e0e0', borderRadius: '5px', textAlign: 'center', paddingTop: '15px'}}>
      {selectn('properties.fvcharacter:upper_case_character', this.props.tile)} {selectn('properties.dc:title', this.props.tile)}

      {selectn('contextParameters.character.related_words[0].dc:title', this.props.tile)}

      {selectn('contextParameters.character.related_words[0].fv:definitions[0].translation', this.props.tile) || selectn('contextParameters.character.related_words[0].fv:literal_translation[0].translation', this.props.tile)}
    </GridTile>;
  }
}

/**
* Learn alphabet
*/
@provide
export default class PageDialectLearnAlphabet extends PageDialectLearnBase {

  static defaultProps = {
    print: false
  }

  static propTypes = {
    properties: PropTypes.object.isRequired,
    navigateTo: PropTypes.func.isRequired,
    windowPath: PropTypes.string.isRequired,
    pushWindowPath: PropTypes.func.isRequired,
    splitWindowPath: PropTypes.array.isRequired,
    fetchDocument: PropTypes.func.isRequired,
    computeDocument: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    fetchDialect2: PropTypes.func.isRequired,
    computeDialect2: PropTypes.object.isRequired,
    fetchCharacters: PropTypes.func.isRequired,
    computeCharacters: PropTypes.object.isRequired,
    updateDialect2: PropTypes.func.isRequired,
    fetchPortal: PropTypes.func.isRequired,
    computePortal: PropTypes.object.isRequired,
    updatePortal: PropTypes.func.isRequired,
    routeParams: PropTypes.object.isRequired,
    computeLogin: PropTypes.object.isRequired,
    print: PropTypes.bool
  };

  constructor(props, context) {
    super(props, context);
    // Bind methods to 'this'
    ['_onNavigateRequest'].forEach( (method => this[method] = this[method].bind(this)) );
  }

  fetchData(newProps) {
    newProps.fetchDialect2(newProps.routeParams.dialect_path);
    newProps.fetchPortal(newProps.routeParams.dialect_path + '/Portal');

    newProps.fetchDocument(newProps.routeParams.dialect_path + '/Dictionary');

    newProps.fetchCharacters(newProps.routeParams.dialect_path + '/Alphabet', '&sortOrder=asc&sortBy=fvcharacter:alphabet_order');
  }

  _onCharAudioTouchTap(charAudioId) {
	  document.getElementById(charAudioId).play();
  }

  _onNavigateRequest(path) {
    const destination = this.props.navigateTo(path);
    const newPathArray = this.props.splitWindowPath.slice();

    newPathArray.push(destination.path);

    this.props.pushWindowPath('/' + newPathArray.join('/'));
  }

  render() {

    const computeEntities = Immutable.fromJS([{
      'id': this.props.routeParams.dialect_path,
      'entity': this.props.computeDialect2
    }, {
      'id': this.props.routeParams.dialect_path + '/Portal',
      'entity': this.props.computePortal
    }])

    const { updatePortal, updateDialect2, computeLogin } = this.props;

    const computeDocument = ProviderHelpers.getEntry(this.props.computeDocument, this.props.routeParams.dialect_path + '/Dictionary');
    const computeDialect2 = ProviderHelpers.getEntry(this.props.computeDialect2, this.props.routeParams.dialect_path);
    const computePortal = ProviderHelpers.getEntry(this.props.computePortal, this.props.routeParams.dialect_path + '/Portal');

    const computeCharacters = ProviderHelpers.getEntry(this.props.computeCharacters, this.props.routeParams.dialect_path + '/Alphabet');

    const isSection = this.props.routeParams.area === 'sections';

    const alphabetListView = <AlphabetListView pagination={false} routeParams={this.props.routeParams} dialect={selectn('response', computeDialect2)} />;

    if (this.props.print) {
      return <PromiseWrapper renderOnError={true} computeEntities={computeEntities}>

{selectn('response.title', computeDialect2)} Alphabet

                {React.cloneElement(alphabetListView, { gridListView: true, gridViewProps: {style:{overflowY: 'auto', maxHeight: '100%'}}, gridListTile: AlphabetGridTile, dialect: selectn('response', computeDialect2) })}

            </PromiseWrapper>;
    }

    return <PromiseWrapper computeEntities={computeEntities}>

                <ToolbarNavigation showStats={this._showStats} routeParams={this.props.routeParams} />

                  <TextHeader title={selectn('response.title', computeDialect2) + " Alphabet"} tag="h1" properties={this.props.properties} appendToTitle={print} />

                  {(() => {

                      const characters = selectn('response.entries', computeCharacters);

                      if (characters && characters.length > 0) {
                          return

                          {selectn('response.entries', computeCharacters).map((char, i) =>
                            <Paper key={char.uid} style={{textAlign: 'center', margin: '5px', padding: '5px 10px', display: 'inline-block'}}>
                              <FlatButton onTouchTap={this._onNavigateRequest.bind(this, char.path.split('/')[char.path.split('/').length-1])} label={char.title} style={{minWidth: 'inherit', textTransform: 'initial'}} />
                              {(char.contextParameters.character.related_audio[0]) ?

                                  <audio id={'charAudio' + char.uid}  src={ConfGlobal.baseURL + char.contextParameters.character.related_audio[0].path} />

                              : ''}
                            </Paper>
                          )}

;
                        }

                    })()}

                <LearningSidebar
                  isSection={isSection}
                  properties={this.props.properties}
                  dialect={{compute: computeDialect2, update: updateDialect2}} />

        </PromiseWrapper>;
  }
}<|endoftext|>


<commit_before>/*
---

name: Scroller

description: Provides a wrapper for the iScroll scroller.

license: MIT-style license.

authors:
	- Jean-Philippe Dery (jeanphilippe.dery@gmail.com)

requires:
	- Core/Class
	- Core/Class.Extras
	- Class.Mutator.Property

provides:
	- Scroller

...
*/

Moobile.Scroller = new Class( /** @lends Scroller.prototype */ {

	Implements: [
		Events,
		Options,
		Class.Binds
	],

	engine: null,

	options: {
		engine: 'Native'
	},

	initialize: function(content, options) {

		this.setOptions(options);

		// TODO: Add an option to autodetect the proper engine

		var engine = Moobile.Scroller.Engine[this.options.engine];
		if (engine == undefined) {
			throw new Error('The scroller engine ' + engine + ' does not exists');
		}

		this.engine = new engine(content);

		return this;
	},

	scrollTo: function(x, y, time) {
		this.engine.scrollTo(x, y, time);
		return this;
	},

	scrollToElement: function(element, time) {
		this.engine.scrollToElement(element, time);
		return this;
	},

	refresh: function() {
		this.engine.refresh();
		return this;
	},

	getScroll: function() {
		return this.engine.getScroll();
	},

	getContent: function() {
		return this.engine.getContent();
	},

	getWrapper: function() {
		return this.engine.getWrapper();
	},

	destroy: function() {
		this.engine.destroy();
		this.engine = null;
		return this;
	}

});

(function() {

window.addEvent('domready', function(e) {
	document.addEvent('touchmove', function(e) {
		if (!e.target.getParent('.scrollable')) e.preventDefault();
	});
});

})();
<commit_msg>Implemented the scroller engine in the Scroller class<commit_after>/*
---

name: Scroller

description: Provides a wrapper for the iScroll scroller.

license: MIT-style license.

authors:
	- Jean-Philippe Dery (jeanphilippe.dery@gmail.com)

requires:
	- Core/Class
	- Core/Class.Extras
	- Class.Mutator.Property

provides:
	- Scroller

...
*/

/**
 * @name  Scroller
 * @class Provides the class that wraps a scroller engine.
 *
 * @classdesc
 *
 * [TODO: Introduction]
 * [TODO: Events]
 * [TODO: Options]
 *
 * @author  Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
 * @version 0.1
 */
Moobile.Scroller = new Class( /** @lends Scroller.prototype */ {

	Implements: [
		Events,
		Options,
		Class.Binds
	],

	/**
	 * @var    {Scroller.Engine} The engine.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	engine: null,

	/**
	 * @var    {Element} The content element, with variable size.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	content: null,

	/**
	 * @var    {Element} The content wrapper element, with fixed size.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	wrapper: null,

	/**
	 * @var    {Object} The scrolling position at the beginning of a scroll.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	startScroll: null,

	/**
	 * @var    {Object} The scrolling time at the beginning of a scroll.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	startTime: null,

	/**
	 * @var    {Object} The scrolling page at the beginning of a scroll.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	startPage: null,

	/**
	 * @var    {Object} The class options.
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1.0
	 */
	options: {
		engine: ['Native', 'IScroll'],
		momentum: true,
		scrollX: true,
		scrollY: true,
		snapToPage: false,
		snapToPageAt: 35,
		snapToPageDuration: 150,
		snapToPageDelay: 150
	},

	/**
	 * Initializes this scroller.
	 *
	 * This `content` element given to this method will be wrapped with an
	 * other element. Any CSS classes given to the `content` element will be
	 * added to the wrapper element with the `-wrapper` suffix.
	 *
	 * This method also creates a scroller engine that is proper for the
	 * current platform based on the `engine` option.
	 *
	 * @param {Element}	[content] The Element, element id or string.
	 * @param {Object}  [options] The options.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	initialize: function(content, options) {

		this.setOptions(options);

		if (this.options.snapToPage)
			this.options.momentum = false;

		Array.from(this.options.engine).each(function(name) {

			var engine = Moobile.Scroller.Engine[name];
			if (engine == undefined) {
				throw new Error('The scroller engine ' + engine + ' does not exists');
			}

			if (engine.supportsCurrentPlatform &&
				engine.supportsCurrentPlatform.call(this) == false) {
				return;
			}

			var options = {
				momentum: this.options.momentum,
				scrollX: this.options.scrollX,
				scrollY: this.options.scrollY
			};

			this.engine = new engine(content, options);
			this.engine.addEvent('start', this.bound('onStart'));
			this.engine.addEvent('move', this.bound('onMove'));
			this.engine.addEvent('end', this.bound('onEnd'));

		}, this);

		this.wrapper = this.getWrapper();
		this.content = this.getContent();

		var classes = this.content.get('class');
		if (classes) {
			classes.split(' ').each(function(klass) {
				this.wrapper.addClass(klass + '-wrapper');
			}, this);
		}

		this.wrapper.addClass('scroll');

		return this;
	},

	/**
	 * Destroys this scroller.
	 *
	 * This method will destroy the scroller engine. The scrollable content
	 * will not be removed upon destruction as the content wrapper will.
	 *
	 * @return {Scroller} This scroller.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	destroy: function() {

		this.engine.destroy();
		this.engine = null;

		return this;
	},

	/**
	 * Scrolls to a set of coordinates.
	 *
	 * @param {Number} x      The x coordinate.
	 * @param {Number} y      The y coordinate.
	 * @param {Number} [time] The duration of the scroll.
	 *
	 * @return {Scroller} This scroller.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	scrollTo: function(x, y, time) {
		this.engine.scrollTo(x, y, time);
		return this;
	},

	/**
	 * Scrolls to page.
	 *
	 * @param {Number} pageX  The horizontal page number.
	 * @param {Number} pageY  The vertical page number.
	 * @param {Number} [time] The duration of the scroll.
	 *
	 * @return {Scroller} This scroller.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	scrollToPage: function(pageX, pageY, time) {

		pageX = pageX || 0;
		pageY = pageY || 0;

		var size = this.getSize();
		var x = size.x * pageX;
		var y = size.y * pageY;

		this.scrollTo(x, y, time);

		return this;
	},

	/**
	 * Scrolls to an element.
	 *
	 * @param {Element} element The element to scroll to.
	 * @param {Number}  [time]  The duration of the scroll.
	 *
	 * @return {Scroller} This scroller.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	scrollToElement: function(element, time) {
		this.engine.scrollToElement(element, time);
		return this;
	},

	/**
	 * Snaps to the proper page.
	 *
	 * This method will snap to the closest page based on the scroller options.
	 * You should seldom need to call this method as it's called automatically
	 * when the `snapToPage` option is enabled.
	 *
	 * @return {Scroller} This scroller.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	snap: function() {

		var size = this.getSize();
		var scroll = this.getScroll();

		var time = Date.now() - this.startTime;

		var pageX = this.startPage.x;
		var pageY = this.startPage.y;
		var moveX = Math.round((scroll.x - this.startPage.x * size.x) / size.x * 100);
		var moveY = Math.round((scroll.y - this.startPage.y * size.y) / size.y * 100);

		var dirX = moveX >= 0 ? 1 : -1;
		var dirY = moveY >= 0 ? 1 : -1;

		if (Math.abs(this.startScroll.x - scroll.x) < 10) dirX = 0;
		if (Math.abs(this.startScroll.y - scroll.y) < 10) dirY = 0;

		if (Math.abs(moveX) >= this.options.snapToPageAt || time <= this.options.snapToPageDelay) pageX += dirX;
		if (Math.abs(moveY) >= this.options.snapToPageAt || time <= this.options.snapToPageDelay) pageY += dirY;

		this.scrollToPage(pageX, pageY, this.options.snapToPageDuration);

		return this;
	},

	/**
	 * Refreshes this scroller.
	 *
	 * What this method exacly does is based on this scroller engine
	 * implementation of the `refresh` method.
	 *
	 * @return {Scroller} This scroller.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	refresh: function() {
		this.engine.refresh();
		return this;
	},

	/**
	 * Returns the size.
	 *
	 * This method will return the wrapper's size as an object with two keys,
	 * `x` which indicates the width and `y` which indicates the height.
	 *
	 * @return {Object} The size.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getSize: function() {
		return this.engine.getSize();
	},

	/**
	 * Returns the current scroll position.
	 *
	 * This method will return the current scroll position as an object
	 * with two keys, `x` which indicates the horizontal scroll and `y` which
	 * indicates the vertical scroll of this entity.
	 *
	 * @return {Object} The scroll position.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getScroll: function() {
		return this.engine.getScroll();
	},

	/**
	 * Returns size including the scrolling area.
	 *
	 * This method will return the content's size as an object with two keys,
	 * `x` which indicates the width and `y` which indicates the height.
	 *
	 * @return {Object} The size including the scrolling area.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getScrollSize: function() {
		return this.engine.getScrollSize();
	},

	/**
	 * Returns the current page.
	 *
	 * This method will return the current page as an object with two keys,
	 * `x` which indicates horizontal page and `y` which indicates the vertical
	 * page.
	 *
	 * @return {Object} This scroller's current page.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getPage: function() {
		return {
			x: Math.floor(this.getScroll().x / this.getSize().x),
			y: Math.floor(this.getScroll().y / this.getSize().y)
		};
	},

	/**
	 * Returns the content element.
	 *
	 * @return {Element} The content element.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getContent: function() {
		return this.engine.getContent();
	},

	/**
	 * Returns the wrapper element.
	 *
	 * @return {Element} The wrapper element.
	 *
	 * @author Jean-Philippe Dery (jeanphilippe.dery@gmail.com)
	 * @since  0.1
	 */
	getWrapper: function() {
		return this.engine.getWrapper();
	},

	onStart: function() {
		this.startScroll = this.getScroll();
		this.startPage = this.getPage();
		this.startTime = Date.now();
		this.fireEvent('start');
	},

	onMove: function() {
		this.fireEvent('move');
	},

	onEnd: function() {

		if (this.options.snapToPage)
			this.snap();

		this.startScroll = null;
		this.startPage = null;
		this.startTime = null;

		this.fireEvent('end');
	}
});

(function() {

window.addEvent('domready', function(e) {

	var pos = null;

	document.addEvent('touchstart', function(e) {
		pos = e.client;
	});

	document.addEvent('touchmove', function(e) {

		if (e.target.getParent('.scroll') == null) {
			e.preventDefault();
		} else {

			//
			// TODO
			// This part has to be improved, right now only a pure horizontal
			// move will allow the whole thing to move
			//

			//if (Math.abs(e.client.y - pos.y) > Math.abs(e.client.x - pos.x))
			//	e.preventDefault();
		}
	});
});

})();
<|endoftext|>


<commit_before>"use strict";

var parentWidth = 320;
var parentHeight = 480;
var aspect = parentWidth / parentHeight;

var scalingExample = {
    box: {
        id: "scaleBox",
        className: "box",
        // Specify a layoutWidth and layoutHeight. This means that the box will
        // use a transform to get its correct width and height from the constraint
        // solver and will have these values as it's DOM Layout dimensions. We do
        // this because updating a transform is faster than causing a DOM relayout.
        layoutWidth: parentWidth,
        layoutHeight: parentHeight
    },
    constraints: [
        // Scale is initially 0.45
        "scale == 0.45",
        // Define some aliases for width, height and horizontal center.
        "width == scaleBox.right - scaleBox.left",
        "height == scaleBox.bottom - scaleBox.top",
        "centerX == scaleBox.left + width * 0.5",
        // We want the aspect ratio preserved, so width == height * aspect
        "width == height * " + aspect,
        // Relate the height and the scale. We define a scale of 1.0 to be the parent height.
        "height == scale * " + parentHeight,
        // Pin the bottom of the box to the bottom of the parent.
        "scaleBox.bottom == " + parentHeight,
        // Center the box horizontally.
        "centerX == " + (parentWidth / 2)
    ],
    motionConstraints: [
        // Constrain the scale with springs. We could constrain the top or something else
        // and backtracking would ensure that we got the same effect.
        { lhs: "scale", op: ">=", rhs: 0.45 },
        { lhs: "scale", op: "<=", rhs: 1 }
    ],
    manipulators: [
        // Dragging in "y" should move the top of the scaleBox.
        { box: "scaleBox", y: "scaleBox.top", x: "centerX" }
    ]
};

function makeScalingExample(parentElement) {
    Slalom.Serialization.assemble(scalingExample, parentElement);
}

makeScalingExample(document.getElementById('scaling-example'));

<commit_msg>Scaling example: play with extra constraints in horizontal.<commit_after>"use strict";

var parentWidth = 320;
var parentHeight = 480;
var aspect = parentWidth / parentHeight;

var scalingExample = {
    box: {
        id: "scaleBox",
        className: "box",
        // Specify a layoutWidth and layoutHeight. This means that the box will
        // use a transform to get its correct width and height from the constraint
        // solver and will have these values as it's DOM Layout dimensions. We do
        // this because updating a transform is faster than causing a DOM relayout.
        layoutWidth: parentWidth,
        layoutHeight: parentHeight
    },
    constraints: [
        // Scale is initially 0.45
        "scale == 0.45",
        // Define some aliases for width, height and horizontal center.
        "width == scaleBox.right - scaleBox.left",
        "height == scaleBox.bottom - scaleBox.top",
        "centerX == scaleBox.left + width * 0.5",
        // We want the aspect ratio preserved, so width == height * aspect
        "width == height * " + aspect,
        // Relate the height and the scale. We define a scale of 1.0 to be the parent height.
        "height == scale * " + parentHeight,
        // Pin the bottom of the box to the bottom of the parent.
        "scaleBox.bottom == " + parentHeight,
        // Center the box horizontally.
        "centerX == " + (parentWidth / 2) + " !weak"
    ],
    motionConstraints: [
        // Constrain the scale with springs. We could constrain the top or something else
        // and backtracking would ensure that we got the same effect.
        [ "scale", ">=", 0.45 ],
        [ "scale", "<=", 1 ],
        // Keep the photo on the screen, too.
        [ "scaleBox.left", ">=", 0, { overdragCoefficient: 0 } ],
        [ "scaleBox.right", "<=", parentWidth, { overdragCoefficient: 0 } ]
    ],
    manipulators: [
        // Dragging in "y" should move the top of the scaleBox.
        { box: "scaleBox", y: "scaleBox.top", x: "centerX" }
    ]
};

function makeScalingExample(parentElement) {
    Slalom.Serialization.assemble(scalingExample, parentElement);
}

makeScalingExample(document.getElementById('scaling-example'));

<|endoftext|>


<commit_before>(function($){
  // these CSS properties will be copied from every test field
  // to their respective twin
  var mimics = [
    'font-family',
    'font-size',
    'font-weight',
    'font-style',
    'font-variant',
    'line-height',
    'letter-spacing',
    'word-spacing',
    'text-indent',
    'text-transform',
    'padding-top',
    'padding-right',
    'padding-bottom',
    'padding-left',
    // copying border width because innerHeight() and innerWidth
    // do return the length including the border width,
    // at least for textareas and inputs
    'border-top-width',
    'border-bottom-width',
  ];

  $.fn.rubber = function() {
    return this.each(function(){
      var nodeName = this.nodeName.toLowerCase(),
        $text = $(this),
        type = $text.attr('type'),

      // check that this is an input element
      if(nodeName) !== 'input')
        return true;

      // only allow text and password types
      if(type != 'text' && type != 'password' && type != 'undefined')
        return true;

      var maxWidth = parseInt($text.css('max-width'), 10),
        css_add = {
          minWidth: $text.width(),
          // default max-width of the parent element's width,
          // so it doesn't interfere with the layout.
          maxWidth: maxWidth > 0 ? maxWidth : ($text.parent().width()-$text.position().left-$text.outerWidth()+$text.innerWidth())
        },

        starting_css = 'display:none',
        update = function(){
          // copy text from text field to $twin, add the longest character to the end
          $twin.text($text.val() + 'W ');
          // update width of text field if it differ's from twin's width
          if($text.width() != $twin.width())
            $text.width($twin.width());
        },

        $twin = $('
').appendTo('body');

      // copy each of the css properties from text field to twin
      $.each(mimics, function(){
        $twin.css(this.toString(), $text.css(this.toString()));
      });

      // add custom css properties from text field to twin
      $.each(css_add, function(i, val){
        $twin.css(i, val);
      });

      // only update when textarea is typed or pasted on
      // input doesn't work on IE
      $text.bind('keypress keyup input', function(){
        update();
      });

      // update once when page is loaded in case text field has text in it
      update();
    });
  }
})(jQuery);
<commit_msg>fixed a few errors<commit_after>(function($){
  // these CSS properties will be copied from every test field
  // to their respective twin
  var mimics = [
    'font-family',
    'font-size',
    'font-weight',
    'font-style',
    'font-variant',
    'line-height',
    'letter-spacing',
    'word-spacing',
    'text-indent',
    'text-transform',
    'padding-top',
    'padding-right',
    'padding-bottom',
    'padding-left',
    // copying border width because innerHeight() and innerWidth
    // do return the length including the border width,
    // at least for textareas and inputs
    'border-top-width',
    'border-bottom-width',
  ];

  $.fn.rubber = function() {
    return this.each(function(){
      var nodeName = this.nodeName.toLowerCase(),
        $text = $(this),
        type = $text.attr('type');

      // check that this is an input element
      if(nodeName !== 'input')
        return true;

      // only allow text and password types
      if(type != 'text' && type != 'password' && type != 'undefined')
        return true;

      var maxWidth = parseInt($text.css('max-width'), 10),
        css_add = {
          minWidth: $text.width(),
          // default max-width of the parent element's width,
          // so it doesn't interfere with the layout.
          maxWidth: maxWidth > 0 ? maxWidth : ($text.parent().width()-$text.position().left-$text.outerWidth()+$text.innerWidth())
        },

        starting_css = 'display:none',
        update = function(){
          // copy text from text field to $twin, add the longest character to the end
          $twin.text($text.val() + 'W ');
          // update width of text field if it differ's from twin's width
          if($text.width() != $twin.width())
            $text.width($twin.width());
        },

        $twin = $('
').appendTo('body');

      // copy each of the css properties from text field to twin
      $.each(mimics, function(){
        $twin.css(this.toString(), $text.css(this.toString()));
      });

      // add custom css properties from text field to twin
      $.each(css_add, function(i, val){
        $twin.css(i, val);
      });

      // only update when textarea is typed or pasted on
      // input doesn't work on IE
      $text.bind('keypress keyup input', function(){
        update();
      });

      // update once when page is loaded in case text field has text in it
      update();
    });
  }
})(jQuery);
<|endoftext|>


<commit_before>Application.Services.factory("measurements", measurementsService);

function measurementsService() {
    var self = this;
    self.activeTemplate = {};
    self.measurements = [
        {
            name: "Composition",
            description: "Composition of sample",
            category: "scalar",
            fn: Composition
        },
        {
            name: "Area Fraction",
            description: "",
            category: "scalar",
            fn: AreaFraction
        },
        {
            name: "Volume Fraction",
            description: "",
            category: "scalar",
            fn: VolumeFraction
        },
        {
            name: "Dislocation Density",
            description: "",
            category: "scalar",
            fn: DislocationDensity
        },
        {
            name: "Length",
            description: "",
            category: "scalar",
            fn: Length
        },
        {
            name: "Width",
            description: "",
            category: "scalar",
            fn: Width
        },
        {
            name: "Height",
            description: "",
            category: "scalar",
            fn: Height
        },
        {
            name: "Density",
            description: "",
            category: "scalar",
            fn: Density
        },
        {
            name: "Volume",
            description: "",
            category: "scalar",
            fn: Volume
        },
        {
            name: "Young's Modulus",
            description: "",
            category: "scalar",
            fn: YoungsModulus
        },
        {
            name: "Tensile Yield Strength",
            description: "",
            category: "scalar",
            fn: TensileYieldStrength
        },
        {
            name: "Ultimate Tensile Strength",
            description: "",
            category: "scalar",
            fn: UltimateTensileStrength
        },
        {
            name: "Strain To Fracture",
            description: "",
            category: "scalar",
            fn: StrainToFracture
        },
        {
            name: "Space Group",
            description: "",
            category: "scalar",
            fn: SpaceGroup
        },
        {
            name: "Point Group",
            description: "",
            category: "scalar",
            fn: PointGroup
        },
        {
            name: "Crystal System",
            description: "",
            category: "scalar",
            fn: CrystalSystem
        },
        {
            name: "Band Gap",
            description: "",
            category: "scalar",
            fn: BandGap
        },
        //{
        //    name: "Fatigue Life",
        //    description: "",
        //    category: "pairs",
        //    fn: FatigueLife
        //},
        //{
        //    name: "Crack Growth",
        //    description: "",
        //    category: "pairs",
        //    fn: CrackGrowth
        //},
        {
            name: "Particle Size Distribution",
            description: "",
            category: "chart",
            fn: ParticleSizeDistribution
        },
        {
            name: "Particle Shape Distribution",
            description: "",
            category: "chart",
            fn: ParticleShapeDistribution
        },
        {
            name: "Grain Size Distribution",
            description: "",
            category: "chart",
            fn: GrainSizeDistribution
        },
        {
            name: "Grain Orientation Distribution",
            description: "",
            category: "chart",
            fn: GrainOrientationDistribution
        },
        {
            name: "Stress Strain",
            description: "",
            category: "chart",
            fn: StressStrain
        },
        {
            name: "Stress Displacement",
            description: "",
            category: "chart",
            fn: StressDisplacement
        }
    ];

    return {
        templates: function() {
            return self.measurements;
        },

        newInstance: function(m) {
            return new m.fn();
        }
    };
}

;<commit_msg>Add attribute to properties.<commit_after>Application.Services.factory("measurements", measurementsService);

function measurementsService() {
    var self = this;
    self.activeTemplate = {};
    self.measurements = [
        {
            name: "Composition",
            attribute: "composition",
            description: "Composition of sample",
            category: "scalar",
            fn: Composition
        },
        {
            name: "Area Fraction",
            attribute: "area_fraction",
            description: "",
            category: "scalar",
            fn: AreaFraction
        },
        {
            name: "Volume Fraction",
            attribute: "volume_fraction",
            description: "",
            category: "scalar",
            fn: VolumeFraction
        },
        {
            name: "Dislocation Density",
            attribute: "dislocation_density",
            description: "",
            category: "scalar",
            fn: DislocationDensity
        },
        {
            name: "Length",
            attribute: "length",
            description: "",
            category: "scalar",
            fn: Length
        },
        {
            name: "Width",
            attribute: "width",
            description: "",
            category: "scalar",
            fn: Width
        },
        {
            name: "Height",
            attribute: "height",
            description: "",
            category: "scalar",
            fn: Height
        },
        {
            name: "Density",
            attribute: "density",
            description: "",
            category: "scalar",
            fn: Density
        },
        {
            name: "Volume",
            attribute: "volume",
            description: "",
            category: "scalar",
            fn: Volume
        },
        {
            name: "Young's Modulus",
            attribute: "youngs_modulus",
            description: "",
            category: "scalar",
            fn: YoungsModulus
        },
        {
            name: "Tensile Yield Strength",
            attribute: "tensile_yield_strength",
            description: "",
            category: "scalar",
            fn: TensileYieldStrength
        },
        {
            name: "Ultimate Tensile Strength",
            attribute: "ultimate_tensile_strength",
            description: "",
            category: "scalar",
            fn: UltimateTensileStrength
        },
        {
            name: "Strain To Fracture",
            attribute: "strain_to_fracture",
            description: "",
            category: "scalar",
            fn: StrainToFracture
        },
        {
            name: "Space Group",
            attribute: "space_group",
            description: "",
            category: "scalar",
            fn: SpaceGroup
        },
        {
            name: "Point Group",
            attribute: "point_group",
            description: "",
            category: "scalar",
            fn: PointGroup
        },
        {
            name: "Crystal System",
            attribute: "crystal_system",
            description: "",
            category: "scalar",
            fn: CrystalSystem
        },
        {
            name: "Band Gap",
            attribute: "band_gap",
            description: "",
            category: "scalar",
            fn: BandGap
        },
        //{
        //    name: "Fatigue Life",
        //    attribute: "fatigue_life",
        //    description: "",
        //    category: "pairs",
        //    fn: FatigueLife
        //},
        //{
        //    name: "Crack Growth",
        //    attribute: "crack_growth",
        //    description: "",
        //    category: "pairs",
        //    fn: CrackGrowth
        //},
        {
            name: "Particle Size Distribution",
            attribute: "particle_size_distribution",
            description: "",
            category: "chart",
            fn: ParticleSizeDistribution
        },
        {
            name: "Particle Shape Distribution",
            attribute: "particle_shape_distribution",
            description: "",
            category: "chart",
            fn: ParticleShapeDistribution
        },
        {
            name: "Grain Size Distribution",
            attribute: "grain_size_distribution",
            description: "",
            category: "chart",
            fn: GrainSizeDistribution
        },
        {
            name: "Grain Orientation Distribution",
            attribute: "grain_orientation_distribution",
            description: "",
            category: "chart",
            fn: GrainOrientationDistribution
        },
        {
            name: "Stress Strain",
            attribute: "stress_strain",
            description: "",
            category: "chart",
            fn: StressStrain
        },
        {
            name: "Stress Displacement",
            attribute: "stress_displacement",
            description: "",
            category: "chart",
            fn: StressDisplacement
        }
        //{
        //    name: "Phases Present",
        //    attribute: "phases_present",
        //    description: "",
        //    category: "list",
        //    fn: PhasesPresent
        //}
    ];

    return {
        templates: function() {
            return self.measurements;
        },

        newInstance: function(m) {
            return new m.fn();
        }
    };
}

;<|endoftext|>


<commit_before>
/**
 * UI Selector Class
 * @class UI.Selector
 * @extends {UI.Component}
 * @type {Class}
 */
define([
	'UI/Selector/Border',
	'UI/Selector/Menu',
	'UI/Selector/Resizer',
	'UI/Selector/Overlay',
	'UI/Selector/Mask'
], function(
	Border,
	Menu,
	Resizer,
	Overlay,
	Mask
) {

	var exports = new Class({

		Implements: [Events, Options],

		options: {
			container: document.body,
			scope: document.body,
			target: document.body,
			trigger: 'click',

			clss: 'ui-selector',
			prefix: 'pages',
			zIndex: 1100,
			wrapper: {
				tagName: 'div',
				clss: 'ui-selector'
			},

			components: [],
			toolbar: false,
			menu: false,
			border: {
				size: 1,
				display:'none'
			},
			resizer: true,
			overlay: false,
			cookie: {
				duration: 365,
				path: '/'
			},
			usefx: false,
			enable : true,
			timerOnHide: 0,
			onCatch: {},
			onDisable: {},
			onEnable: {},
			positionning: 'relative'
		},

		initialize: function(options){
			//_log.debug('UI.Selector.initilize()');
			this.setOptions(options);

			this.selectors = [];

			this.container = this.options.container;

			var scope = this.options.scope || this.container;
			var target = this.options.target;

			this.name = this.options.prefix+'-'+this.options.name;
			this.size = {};

			this.timer = null;

			//_log.debug('UI.Selector.init(scope,target)',this.name);

			this._initElement(this.options.components);
			this._initEvents(scope,target);

			//_log.debug('shoud hide this');

			this.hideNow();
		},

		update: function(){

			var scope = this.options.scope;
			var target = this.options.target;

			this._initEvents(scope,target);
		},

		_initEvents: function(scope,target) {
			//_log.debug('UI.Selector._initEvents(scope,target)',typeOf(scope),target);
			var delay = 20;
			var self = this;

			//_log.debug('UI.Selector._initEvents(scope,target)',typeOf(scope),target);

			var delegation = self.options.trigger+':relay('+target+')';

			scope.addEvent(delegation, function(ev, el) {
				self.reach(el)
			});

			/*var list = scope.querySelectorAll( target );

			//_log.debug(list);

			new Array()

			Array.each(list, function(el) {
				//_log.debug('UI.Selector.target',el,self.options.trigger);
				el.store('selector', self);
				el.addEvent(self.options.trigger, function(){
					self.reach(el);
				});

				el.addEvents({
					mouseenter: function(e) {
						//e.stop();
						clearTimeout(self.timer);
					},
					mouseover: function(e) {
						//self.reach(el);
						//e.stop();
						clearTimeout(self.timer);
					}
				});
			});*/

			/*pages.addEvent('resize', function() {
				self.reach(self.el);
			});*/
		},

		attachElement: function(el) {
			//_log.debug('UI.Selector._initEvents(scope,target)',scope,target);
			var delay = 20;
			var self = this;

			//_log.debug('UI.Selector._setEventsElement',el,self.options.trigger);

			el.addEvent(self.options.trigger, function(){
				self.reach(el);
			});

			el.addEvents({
				mouseenter: function(e) {
					//e.stop();
					clearTimeout(self.timer);
				},
				mouseover: function(e) {
					//self.reach(el);
					//e.stop();
					clearTimeout(self.timer);
				}
			});

			/*pages.addEvent('resize', function() {
				self.reach(self.el);
			});*/
		},

		_initElement: function(components){
			var self = this;

			this.wrapper = new Element('div', {
				'class': this.options.wrapper.clss,
				zIndex: this.options.zIndex
			}).set('data-selector', this.options.name)
			.inject(this.options.container, 'top');

			components.each(function(name){
				//_log.debug('Selector _initElement',name);
				self.options[name].content = self.options.container;
				var build = 'build'+name.capitalize();
				if (!self.options[name].usefx)
					self.options[name].usefx = self.options.usefx;

				self.selectors.push(self[build](self.options[name]));
			});

			if (this.isEnable()) this.enable();
			else this.disable();

			return this.wrapper;
		},

		buildComponent: function() {

		},

		buildBorder: function(options){
			var self = this;
			//_log.debug();

			options.positionning = this.options.positionning;

			this.border = new Border(this.wrapper, options);

			this.addEvents({
				show: function(){ self.border.show(); },
				hide: function(){ self.border.hide(); },
				reach: function(el){ self.border.reach(el); },
				repos: function(el){ self.border.reach(el); },
				highlight: function(color){	self.border.highlight(color); }
			});
		},

		buildMask: function(opts){
			var self = this;

			opts.positionning = this.options.positionning;

			opts.scope = this.options.scope;

			this.mask = new Mask(this.wrapper, opts);

			this.mask.addEvent('click', function(ev) {
				self.fireEvent('click', ev);
			});

			this.addEvents({
				show: function(){ self.mask.show(); },
				hide: function(){ self.mask.hide(); },
				reach: function(el){	self.mask.reach(el); },
				repos: function(el){	self.mask.reach(el); },
				highlight: function(color){	self.mask.highlight(color); }
			});
		},

		buildResizer: function(options){
			var self = this;

			this.resizer = new Resizer(this.wrapper, options).addEvents({
				mouseleave: function() {
					self.hide();
				},
				mouseenter: function() {
					clearTimeout(self.timer);
				}
			});

			this.addEvents({
				show: function(el){ self.resizer.show(); },
				hide: function(el){	self.resizer.hide(); },
				reach: function(el){ self.resizer.reach(el); },
				repos: function(el){ self.resizer.reach(el); }
			});
		},

		buildMenu: function(options){
			//_log.debug('buildMenu', this.options.name, options);

			var self = this,
				left = null,
				right = null;

			// _log.debug( this.wrapper, options);

			options.positionning = this.options.positionning;

			this.menu = new Menu( this.wrapper, options);

			if (this.options.timerOnHide) {
				this.menu.element.addEvents({
					mouseleave: function() {
						self.hide();
					},
					mouseenter: function() {
						clearTimeout(self.timer);
					}
				});
			}

			this.addEvents({
				show: function(){ self.menu.element.show(); },
				hide: function(){	self.menu.element.hide(); },
				reach: function(el) { self.menu.reach(el);	},
				repos: function(el) { self.menu.reach(el); },
				highlight: function(color){	self.menu.element.highlight(color); }
			});
		},

		buildStatus: function(options){
			//_log.debug('buildMenu', this.options.name, options);

			var self = this,
				left = null,
				right = null;

			//_log.debug( this.wrapper);

			this.status = new Status( this.wrapper, options);

			if (this.options.timerOnHide) {
				this.status.element.addEvents({
					mouseleave: function() {
						self.hide();
					},
					mouseenter: function() {
						clearTimeout(self.timer);
					}
				});
			}

			this.addEvents({
				show: function(){ self.status.element.show(); },
				hide: function(){	self.status.element.hide(); },
				reach: function(el) { self.status.reach(el); },
				repos: function(el) { self.status.reach(el); },
				highlight: function(color){	self.status.element.highlight(color); }
			});
		},

		_initOverlay: function(){
			var self = this;

			this.overlay = new Overlay({
				container: this.options.container
			}).addEvents({
				click: function() {
					self.fireEvent('click', self.el);
				},
				dblclick: function() {
					self.fireEvent('dblclick',self.el);
				}
			});

			if (this.options.timerOnHide) {
				this.overlay.element.addEvents({
					mouseleave: function() {
						clearTimeout(self.timer);
						self.hide();
					},
					mouseenter: function() {
						//_log.debug('enteroverlay');
						clearTimeout(self.timer);
					}

				});
			}

			this.addEvents({
				show: function(el){ self.overlay.show(); },
				hide: function(el){	self.overlay.hide(); },
				reach: function(el){ self.overlay.reach(el); },
				repos: function(el){ self.overlay.reach(el); },
				highlight: function(color){	self.overlay.highlight(color); }
			});
		},

		reach: function(el){
			if (el) {
				this.el = el;
			} else if (this.el) {
				el = this.el;
			} else { return; }

			//_log.debug('reach',el);

			if (this.isEnable) {
				this.show();
				this.fireEvent('reach',el);
			}
		},

		repos: function(el){
			if (el) {
				this.el = el;
			} else if (this.el) {
				el = this.el;
			} else { return; }

			if (this.isEnable) {
				this.show();
				this.fireEvent('repos',el);
			}
		},

		set: function(name,value,name){
			//_log.debug(name,value,name);

			if (name)
				self[name][name](value);
			else
			this.selectors.each(function(name) {
				self[name][name](value);
			});

			return this;
		},

		/*

				Note: Should be cool if we can also add and remove selectors

		*/
		add: function(type) {

		},

		remove: function(type) {

		},

		hide: function(){
			clearTimeout(this.timer);
			this.timer = (function() {
				this.fireEvent('hide');
			}).delay(this.options.timerOnHide,this);
		},

		hideNow: function(){
			clearTimeout(this.timer);
			this.fireEvent('hide');
		},

		show: function(){
			clearTimeout(this.timer);
			if (this.isEnable)
				this.fireEvent('show');
		},

		highlight: function(color){
			if (this.isEnable)
				this.fireEvent('highlight',color);
		},

		enable: function(selector) {
			//_log.debug('enable', this.options.name);

			this.isEnable = true;
			Cookie.write(this.name, '1', this.options.cookie);
			//this.show();
		},

		disable: function(selector) {
			//_log.debug('disable', this.options.name);

			this.isEnable = false;
			Cookie.write(this.name, '0', this.options.cookie);
			this.hideNow();
		},

		isEnable: function() {
			if (Cookie.read(this.name) === '1') return true;
				else return false;
		},

		toggle: function(){
			if (Cookie.read(this.name) === '1') this.disable();
			else this.enable();
		}
	});

	return exports;
});

<commit_msg>documentation + fix syntax errors<commit_after>/**
 * UI Selector Class
 * @class UI.Selector
 */
define([
	'UI/Selector/Border',
	'UI/Selector/Menu',
	'UI/Selector/Resizer',
	'UI/Selector/Overlay',
	'UI/Selector/Mask'
], function(
	Border,
	Menu,
	Resizer,
	Overlay,
	Mask
) {

	var exports = new Class({

		Implements: [Events, Options],

		options: {
			container: document.body,
			scope: document.body,
			target: document.body,
			trigger: 'click',

			clss: 'ui-selector',
			prefix: 'pages',
			zIndex: 1100,
			wrapper: {
				tagName: 'div',
				clss: 'ui-selector'
			},

			components: [],
			toolbar: false,
			menu: false,
			border: {
				size: 1,
				display: 'none'
			},
			resizer: true,
			overlay: false,
			cookie: {
				duration: 365,
				path: '/'
			},
			usefx: false,
			enable: true,
			timerOnHide: 0,
			onCatch: {},
			onDisable: {},
			onEnable: {},
			positionning: 'relative'
		},

		/**
		 * initialize
		 * @param  {Object} options
		 * @return {void}
		 */
		initialize: function(options) {
			//_log.debug('UI.Selector.initilize()');
			this.setOptions(options);

			this.selectors = [];

			this.container = this.options.container;

			var scope = this.options.scope || this.container;
			var target = this.options.target;

			this.name = this.options.prefix + '-' + this.options.name;
			this.size = {};

			this.timer = null;

			//_log.debug('UI.Selector.init(scope,target)',this.name);

			this._initElement(this.options.components);
			this._initEvents(scope, target);

			//_log.debug('shoud hide this');

			this.hideNow();
		},

		update: function() {

			var scope = this.options.scope;
			var target = this.options.target;

			this._initEvents(scope, target);
		},

		_initEvents: function(scope, target) {
			//_log.debug('UI.Selector._initEvents(scope,target)',typeOf(scope),target);
			//var delay = 20;
			var self = this;

			//_log.debug('UI.Selector._initEvents(scope,target)',typeOf(scope),target);

			var delegation = self.options.trigger + ':relay(' + target + ')';

			scope.addEvent(delegation, function(ev, el) {
				self.reach(el);
			});

			/*var list = scope.querySelectorAll( target );

			//_log.debug(list);

			new Array()

			Array.each(list, function(el) {
				//_log.debug('UI.Selector.target',el,self.options.trigger);
				el.store('selector', self);
				el.addEvent(self.options.trigger, function(){
					self.reach(el);
				});

				el.addEvents({
					mouseenter: function(e) {
						//e.stop();
						clearTimeout(self.timer);
					},
					mouseover: function(e) {
						//self.reach(el);
						//e.stop();
						clearTimeout(self.timer);
					}
				});
			});*/

			/*pages.addEvent('resize', function() {
				self.reach(self.el);
			});*/
		},

		attachElement: function(el) {
			//_log.debug('UI.Selector._initEvents(scope,target)',scope,target);
			//var delay = 20;
			var self = this;

			//_log.debug('UI.Selector._setEventsElement',el,self.options.trigger);

			el.addEvent(self.options.trigger, function() {
				self.reach(el);
			});

			el.addEvents({
				mouseenter: function(e) {
					//e.stop();
					clearTimeout(self.timer);
				},
				mouseover: function(e) {
					//self.reach(el);
					//e.stop();
					clearTimeout(self.timer);
				}
			});

			/*pages.addEvent('resize', function() {
				self.reach(self.el);
			});*/
		},

		_initElement: function(components) {
			var self = this;

			this.wrapper = new Element('div', {
					'class': this.options.wrapper.clss,
					zIndex: this.options.zIndex
				}).set('data-selector', this.options.name)
				.inject(this.options.container, 'top');

			components.each(function(name) {
				//_log.debug('Selector _initElement',name);
				self.options[name].content = self.options.container;
				var build = 'build' + name.capitalize();
				if (!self.options[name].usefx) {
					self.options[name].usefx = self.options.usefx;
				}

				self.selectors.push(self[build](self.options[name]));
			});

			if (this.isEnable()) {
				this.enable();
			} else {
				this.disable();
			}

			return this.wrapper;
		},

		buildComponent: function() {

		},

		buildBorder: function(options) {
			var self = this;
			//_log.debug();

			options.positionning = this.options.positionning;

			this.border = new Border(this.wrapper, options);

			this.addEvents({
				show: function() {
					self.border.show();
				},
				hide: function() {
					self.border.hide();
				},
				reach: function(el) {
					self.border.reach(el);
				},
				repos: function(el) {
					self.border.reach(el);
				},
				highlight: function(color) {
					self.border.highlight(color);
				}
			});
		},

		buildMask: function(opts) {
			var self = this;

			opts.positionning = this.options.positionning;

			opts.scope = this.options.scope;

			this.mask = new Mask(this.wrapper, opts);

			this.mask.addEvent('click', function(ev) {
				self.fireEvent('click', ev);
			});

			this.addEvents({
				show: function() {
					self.mask.show();
				},
				hide: function() {
					self.mask.hide();
				},
				reach: function(el) {
					self.mask.reach(el);
				},
				repos: function(el) {
					self.mask.reach(el);
				},
				highlight: function(color) {
					self.mask.highlight(color);
				}
			});
		},

		buildResizer: function(options) {
			var self = this;

			this.resizer = new Resizer(this.wrapper, options).addEvents({
				mouseleave: function() {
					self.hide();
				},
				mouseenter: function() {
					clearTimeout(self.timer);
				}
			});

			this.addEvents({
				show: function(el) {
					self.resizer.show();
				},
				hide: function(el) {
					self.resizer.hide();
				},
				reach: function(el) {
					self.resizer.reach(el);
				},
				repos: function(el) {
					self.resizer.reach(el);
				}
			});
		},

		buildMenu: function(options) {
			//_log.debug('buildMenu', this.options.name, options);

			var self = this;
			//var left = null;
			//var right = null;

			// _log.debug( this.wrapper, options);

			options.positionning = this.options.positionning;

			this.menu = new Menu(this.wrapper, options);

			if (this.options.timerOnHide) {
				this.menu.element.addEvents({
					mouseleave: function() {
						self.hide();
					},
					mouseenter: function() {
						clearTimeout(self.timer);
					}
				});
			}

			this.addEvents({
				show: function() {
					self.menu.element.show();
				},
				hide: function() {
					self.menu.element.hide();
				},
				reach: function(el) {
					self.menu.reach(el);
				},
				repos: function(el) {
					self.menu.reach(el);
				},
				highlight: function(color) {
					self.menu.element.highlight(color);
				}
			});
		},

		buildStatus: function(options) {
			//_log.debug('buildMenu', this.options.name, options);

			var self = this;
			//var left = null;
			//var right = null;

			//_log.debug( this.wrapper);

			this.status = new Status(this.wrapper, options);

			if (this.options.timerOnHide) {
				this.status.element.addEvents({
					mouseleave: function() {
						self.hide();
					},
					mouseenter: function() {
						clearTimeout(self.timer);
					}
				});
			}

			this.addEvents({
				show: function() {
					self.status.element.show();
				},
				hide: function() {
					self.status.element.hide();
				},
				reach: function(el) {
					self.status.reach(el);
				},
				repos: function(el) {
					self.status.reach(el);
				},
				highlight: function(color) {
					self.status.element.highlight(color);
				}
			});
		},

		_initOverlay: function() {
			var self = this;

			this.overlay = new Overlay({
				container: this.options.container
			}).addEvents({
				click: function() {
					self.fireEvent('click', self.el);
				},
				dblclick: function() {
					self.fireEvent('dblclick', self.el);
				}
			});

			if (this.options.timerOnHide) {
				this.overlay.element.addEvents({
					mouseleave: function() {
						clearTimeout(self.timer);
						self.hide();
					},
					mouseenter: function() {
						//_log.debug('enteroverlay');
						clearTimeout(self.timer);
					}

				});
			}

			this.addEvents({
				show: function(el) {
					self.overlay.show();
				},
				hide: function(el) {
					self.overlay.hide();
				},
				reach: function(el) {
					self.overlay.reach(el);
				},
				repos: function(el) {
					self.overlay.reach(el);
				},
				highlight: function(color) {
					self.overlay.highlight(color);
				}
			});
		},

		reach: function(el) {
			if (el) {
				this.el = el;
			} else if (this.el) {
				el = this.el;
			} else {
				return;
			}

			//_log.debug('reach',el);

			if (this.isEnable) {
				this.show();
				this.fireEvent('reach', el);
			}
		},

		repos: function(el) {
			if (el) {
				this.el = el;
			} else if (this.el) {
				el = this.el;
			} else {
				return;
			}

			if (this.isEnable) {
				this.show();
				this.fireEvent('repos', el);
			}
		},

		set: function(name, value, name) {
			//_log.debug(name, value, name);

			var self = this;

			if (name) {
				this[name][name](value);
			} else {
				this.selectors.each(function(name) {
					self[name][name](value);
				});
			}

			return this;
		},

		/*

				Note: Should be cool if we can also add and remove selectors

		*/
		add: function(type) {

		},

		remove: function(type) {

		},

		hide: function() {
			clearTimeout(this.timer);
			this.timer = (function() {
				this.fireEvent('hide');
			}).delay(this.options.timerOnHide, this);
		},

		hideNow: function() {
			clearTimeout(this.timer);
			this.fireEvent('hide');
		},

		show: function() {
			clearTimeout(this.timer);
			if (this.isEnable) {
				this.fireEvent('show');
			}
		},

		highlight: function(color) {
			if (this.isEnable) {
				this.fireEvent('highlight', color);
			}
		},

		enable: function(selector) {
			//_log.debug('enable', this.options.name);

			this.isEnable = true;
			Cookie.write(this.name, '1', this.options.cookie);
			//this.show();
		},

		disable: function(selector) {
			//_log.debug('disable', this.options.name);

			this.isEnable = false;
			Cookie.write(this.name, '0', this.options.cookie);
			this.hideNow();
		},

		isEnable: function() {
			if (Cookie.read(this.name) === '1') {
				return true;
			} else {
				return false;
			}
		},

		toggle: function() {
			if (Cookie.read(this.name) === '1') {
				this.disable();
			} else {
				this.enable();
			}
		}

	});

	return exports;

});
<|endoftext|>


<commit_before>/*
	Class: UI.Context
		Create a context menu

	Extends:
		<UI.Menu>

	Arguments:
		options

	Options:
		contexts - (array) An array containing contexts definition. A context definition is an object composed of following keys :
			a name key, who is the context name,
			a target key, who define on wich elements the context menu will be attached. It could be a CSS3 target as well.
			a menu key, who is a menu list as defined in <UI.Menu>.

	Discussion:
		We must still add methods to set dynamically new contexts, ...

	Example:
		(start code)
		var context = new UI.Context({
			contexts : [
				{
					name : 'workspace',
					target	: '.app-workspace',
					menu		: [
						{ text: 'Workspace menu'},
						{ text		: 'separator' },
						{
							text: 'Hello world...',
							action	: function(){ alert('Hello world!') }
						}
						{ text		: 'viewSource'},
						{ text		: 'separator' },
						{ text		: 'deleteCategory'}
					]
				},
				{
					name: 'pageinfo',
					target: '[id^=pageinfo]',
					menu: [
						{
							text: 'editCategory',
							action: function(){ this.test('dorpdown') }.bind(this)
						},
						{ text: 'editCategoryApparence'}
					]
				}
			]
		});
		(end)

	Implied global:
		UI,ui,
		$,
		Class,Event,	Window,
		document

*/

UI.Context = new Class({

	Extends: UI.Menu,

	name: 'context',

	options:{
		name: 'context',
		scope: $(document.body),
		container: $(document.body),
		trigger: 'contextmenu'
	},

	/*
	Constructor: initialize
		Construtor

	Arguments:
		options - (object) options

	See also:
		<UI.Menu::initialize>
		<UI.Element::initialize>
	*/

	initialize: function(options){
		this.parent(options);

		//console.log('initparent() context ok', this.element, $(document.body));
		this.element.inject(this.options.container);

		this._initContext();
	},

	/*
	Function: _initElement
		private function

		Call UI.Component _initElement, then create a menu wrapper

	Return:
		(void)

	See also:
		<UI.Component::_initElement>
	*/
	_initElement: function(){
		var self = this,
			opts = this.options;

		//console.log('UI.MEnu._initElement()', opts);

		this.element = new Element('div', {
			'class': 'ui-context',
			zIndex: opts.zIndex,
			display: 'none'
		});

		this.element.addClass('context-'+opts.name);

		if (opts.klss)
			this.element.addClass(opts.klss);

		if (opts.type)
			this.element.addClass('type-'+opts.type);

		this._initHead(opts.head);

		this.content = new Element('ul', {
			'class': 'menu-list'
		}).inject(this.element);

		this.addEvents({
			show: function() {
				self.content.getStyle('display', 'block');
			},
			hide: function() {
				self.content.getStyle('display', 'none');
			}
		});

		this.element.addEvent('click', function(e){
			e.stop();
		});

		this.element.hide();
	},
	/*
	Method: addContexts
		Attach context to elements (provided by contexts.target)

	Arguments:
		contexts - (array) an array containing contexts definition. See above in class' options for more details

	Return:
		this
	*/

	_initContext: function(){
		var self = this;
			opts = this.options;
			scope = opts.scope || $(document.body);

		scope.getElements(opts.target).each(function(el) {
			//console.log(el);
			self.addTarget(el);
		});

		// self.element.addEvent('contextmenu', function(e){
		// 	e.stop();
		// });

		return this;
	},

	addList: function() {

	},

	addTarget: function(el) {
		var self = this;

		el.addEvent(self.options.trigger, function(e){
			e.stop();
			e.preventDefault();

			self.target = e.target;

			//console.log(e.target);

			//.hide(0);
			//self.buildMenu(context.menu);
			self.show(e);
		});
	},

	removeList: function() {

	},

	_initEvents: function() {
		this.parent();

		this.addEvents({
			show: function(){
				ui.menu.hideAll();
			}
		});

	},

	/*
	Method: removeContexts
		Remove context to elements (defined by target)

	Arguments:
		target - (string) target defining elements where context will be detached

	Return:
		this
	*/

	removeContexts: function(){
		//console.log('removeContext',this.options.scope);
		this.els.each(function(el) {
			el.removeEvents('contextmenu');
		});

		/*this.options.contexts.each(function(context){
			this.options.scope.getElements(context.target).each(function(el){
				//console.log(context.target,el);
				el.removeEvents('contextmenu');
			},this);
		},this);*/

		return this;
	},

	/*
	Method: setPosition
		private function

		Overwrite the setPosition method of UI.Menu to use mouse coordinates to set menu location

	Arguments:
		x - (integer) X mouse's coordinates
		y - (integer) Y mouse's coordinates

	Return:
		(void)

	See also:
		<UI.Menu::setPosition>

	*/

	setPosition: function(x,y){
		if ((x === null) || (y === null)) {
			return;
		}

		var coor = this.element.getCoordinates();
		var top = y - 30;
		var left = x + this.options.container.getScrollLeft();

		if ((x + coor.width) > this.options.container.getWidth()) { left =  left - coor.width; }
		if ((y + coor.height) > this.options.container.getHeight()) {
			//console.log('top', top);
			top =  top; // - coor.height;
		}

		this.element.setStyles({
			'top' : top,
			'left' : left
		});
	},

	/*
		Method: show
			private function

			Hide

		Arguments:
			e - (event) Event who provide cursor's position

		Return:
			this

		See also:
			<UI.Menu::show>
			<UI.Element::show>
	*/
	hide: function(){
		clearTimeout(this.timer);
		this.timer = (function() {
			this.close();
		}).delay(this.options.timerOnHide,this);
	},

	hideNow: function() {
		this.element.hide();
	},

	/*
		Method: show
			private function

			Overwrite the show method of UI.Menu to use mouse coordinates

		Arguments:
			e - (event) Event who provide cursor's position

		Return:
			this

		See also:
			<UI.Menu::show>
			<UI.Element::show>
	*/

	show: function(e){
		this.fireEvent('show', e.target);

		this.element.show();
		var coord = this.content.getCoordinates();
		this.setSize(coord.width, coord.height);
		this.setPosition(e.client.x,e.client.y);

		return this;
	}
});
<commit_msg>Migrate Website from Menu to Toolbar + split mnml.toolbar.view<commit_after>/*
	Class: UI.Context
		Create a context menu

	Extends:
		<UI.Menu>

	Arguments:
		options

	Options:
		contexts - (array) An array containing contexts definition. A context definition is an object composed of following keys :
			a name key, who is the context name,
			a target key, who define on wich elements the context menu will be attached. It could be a CSS3 target as well.
			a menu key, who is a menu list as defined in <UI.Menu>.

	Discussion:
		We must still add methods to set dynamically new contexts, ...

	Example:
		(start code)
		var context = new UI.Context({
			contexts : [
				{
					name : 'workspace',
					target	: '.app-workspace',
					menu		: [
						{ text: 'Workspace menu'},
						{ text		: 'separator' },
						{
							text: 'Hello world...',
							action	: function(){ alert('Hello world!') }
						}
						{ text		: 'viewSource'},
						{ text		: 'separator' },
						{ text		: 'deleteCategory'}
					]
				},
				{
					name: 'pageinfo',
					target: '[id^=pageinfo]',
					menu: [
						{
							text: 'editCategory',
							action: function(){ this.test('dorpdown') }.bind(this)
						},
						{ text: 'editCategoryApparence'}
					]
				}
			]
		});
		(end)

	Implied global:
		UI,ui,
		$,
		Class,Event,	Window,
		document

*/

UI.Context = new Class({

	Extends: UI.Menu,

	name: 'context',

	options:{
		name: 'context',
		scope: $(document.body),
		container: $(document.body),
		trigger: 'contextmenu'
	},

	/*
	Constructor: initialize
		Construtor

	Arguments:
		options - (object) options

	See also:
		<UI.Menu::initialize>
		<UI.Element::initialize>
	*/

	initialize: function(options){
		this.parent(options);

		//console.log('initparent() context ok', this.element, $(document.body));
		this.element.inject(this.options.container);

		this._initContext();
	},

	/*
	Function: _initElement
		private function

		Call UI.Component _initElement, then create a menu wrapper

	Return:
		(void)

	See also:
		<UI.Component::_initElement>
	*/
	_initElement: function(){
		var self = this,
			opts = this.options;

		//console.log('UI.MEnu._initElement()', opts);

		this.element = new Element('div', {
			'class': 'ui-context',
			zIndex: opts.zIndex,
			display: 'none'
		});

		this.element.addClass('context-'+opts.name);

		if (opts.klss)
			this.element.addClass(opts.klss);

		if (opts.type)
			this.element.addClass('type-'+opts.type);

		this._initHead(opts.head);

		this.content = new Element('ul', {
			'class': 'menu-list'
		}).inject(this.element);

		this.addEvents({
			show: function() {
				self.content.getStyle('display', 'block');
			},
			hide: function() {
				self.content.getStyle('display', 'none');
			}
		});

		this.element.addEvent('click', function(e){
			e.stop();
		});

		this.element.hide();
	},
	/*
	Method: addContexts
		Attach context to elements (provided by contexts.target)

	Arguments:
		contexts - (array) an array containing contexts definition. See above in class' options for more details

	Return:
		this
	*/

	_initContext: function(){
		var self = this;
			opts = this.options;
			scope = opts.scope || $(document.body);

		scope.getElements(opts.target).each(function(el) {
			//console.log(el);
			self.addTarget(el);
		});

		// self.element.addEvent('contextmenu', function(e){
		// 	e.stop();
		// });

		return this;
	},

	addList: function() {

	},

	addTarget: function(el) {
		var self = this;

		el.addEvent(self.options.trigger, function(e){
			e.stop();
			e.preventDefault();

			self.target = e.target;

			//console.log(e.target);

			//.hide(0);
			//self.buildMenu(context.menu);
			self.show(e);
		});
	},

	removeList: function() {

	},

	_initEvents: function() {
		this.parent();

		this.addEvents({
			show: function(){
				ui.menu.hideAll();
			}
		});

	},

	/*
	Method: removeContexts
		Remove context to elements (defined by target)

	Arguments:
		target - (string) target defining elements where context will be detached

	Return:
		this
	*/

	removeContexts: function(){
		//console.log('removeContext',this.options.scope);
		this.els.each(function(el) {
			el.removeEvents('contextmenu');
		});

		/*this.options.contexts.each(function(context){
			this.options.scope.getElements(context.target).each(function(el){
				//console.log(context.target,el);
				el.removeEvents('contextmenu');
			},this);
		},this);*/

		return this;
	},

	/*
	Method: setPosition
		private function

		Overwrite the setPosition method of UI.Menu to use mouse coordinates to set menu location

	Arguments:
		x - (integer) X mouse's coordinates
		y - (integer) Y mouse's coordinates

	Return:
		(void)

	See also:
		<UI.Menu::setPosition>

	*/

	setPosition: function(x,y){
		if ((x === null) || (y === null)) {
			return;
		}

		var ctop = this.options.container.getPosition().y;

		var coor = this.element.getCoordinates();
		var top = y - ctop;
		var left = x + this.options.container.getScrollLeft();

		if ((x + coor.width) > this.options.container.getWidth()) { left =  left - coor.width; }
		if ((y + coor.height) > this.options.container.getHeight()) {
			//console.log('top', top);
			top =  top; // - coor.height;
		}

		this.element.setStyles({
			'top' : top,
			'left' : left
		});
	},

	/*
		Method: show
			private function

			Hide

		Arguments:
			e - (event) Event who provide cursor's position

		Return:
			this

		See also:
			<UI.Menu::show>
			<UI.Element::show>
	*/
	hide: function(){
		clearTimeout(this.timer);
		this.timer = (function() {
			this.close();
		}).delay(this.options.timerOnHide,this);
	},

	hideNow: function() {
		this.element.hide();
	},

	/*
		Method: show
			private function

			Overwrite the show method of UI.Menu to use mouse coordinates

		Arguments:
			e - (event) Event who provide cursor's position

		Return:
			this

		See also:
			<UI.Menu::show>
			<UI.Element::show>
	*/

	show: function(e){
		this.fireEvent('show', e.target);

		this.element.show();
		var coord = this.content.getCoordinates();
		//this.setSize(coord.width, coord.height);
		this.setPosition(e.client.x,e.client.y);

		return this;
	}
});
<|endoftext|>