<commit_before>/*
 * The MIT License
 *
 * Copyright (c) 2014 Petar Petrov
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

angular.module('pbg', ['ionic', 'pbg.controllers', 'pbg.services'])

.constant('NSOURCES', {
  NEWS: {
    name: 'news',
    storeName: 'news20',
    url: 'http://localhost/news.rss?'
    // url: 'http://www.government.bg/cgi-bin/e-cms/rss.pl?'
  },
  EVENTS: {
    name: 'events',
    storeName: 'events20',
    url: 'http://localhost/events.rss?'
    // url: 'http://www.government.bg/cgi-bin/e-cms/rss.pl?ch=0003&'
  },
  DECISIONS: {
    name: 'decisions',
    storeName: 'decisions20',
    url: 'http://www.government.bg/cgi-bin/e-cms/rss.pl?ch=0004&'
  }
})

.run(function($ionicPlatform) {

  // init local storage
  storage.init();
  // init date-time lib
  moment.lang('bg');

  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }
  });
})

.config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

    // setup an abstract state for the tabs directive
    .state('tab', {
      url: "/tab",
      abstract: true,
      templateUrl: "templates/tabs.html"
    })

    // Each tab has its own nav history stack:

    .state('tab.about', {
      url: '/about',
      views: {
        'tab-about': {
          templateUrl: 'templates/tab-about.html',
          controller: 'AboutCtrl'
        }
      }
    })

    .state('tab.news', {
      url: '/news',
      views: {
        'tab-news': {
          templateUrl: 'templates/tab-news.html',
          controller: 'NewsCtrl'
        }
      }
    })
    .state('tab.news-detail', {
      url: '/news/:id',
      views: {
        'tab-news': {
          templateUrl: 'templates/news-detail.html',
          controller: 'NewsDetailCtrl'
        }
      }
    })

    .state('tab.events', {
      url: '/events',
      views: {
        'tab-events': {
          templateUrl: 'templates/tab-news.html',
          controller: 'EventsCtrl'
        }
      }
    })
    .state('tab.events-detail', {
      url: '/events/:id',
      views: {
        'tab-events': {
          templateUrl: 'templates/news-detail.html',
          controller: 'EventsDetailCtrl'
        }
      }
    })

    .state('tab.decisions', {
      url: '/decisions',
      views: {
        'tab-decisions': {
          templateUrl: 'templates/tab-news.html',
          controller: 'DecisionsCtrl'
        }
      }
    })
    .state('tab.decisions-detail', {
      url: '/decisions/:id',
      views: {
        'tab-decisions': {
          templateUrl: 'templates/news-detail.html',
          controller: 'DecisionsDetailCtrl'
        }
      }
    })

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/news');

});

<commit_msg>Fix rss news urls<commit_after>/*
 * The MIT License
 *
 * Copyright (c) 2014 Petar Petrov
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

angular.module('pbg', ['ionic', 'pbg.controllers', 'pbg.services'])

.constant('NSOURCES', {
  NEWS: {
    name: 'news',
    storeName: 'news20',
    // url: 'http://localhost/news.rss?'
    url: 'http://www.government.bg/cgi-bin/e-cms/rss.pl?'
  },
  EVENTS: {
    name: 'events',
    storeName: 'events20',
    // url: 'http://localhost/events.rss?'
    url: 'http://www.government.bg/cgi-bin/e-cms/rss.pl?ch=0003&'
  },
  DECISIONS: {
    name: 'decisions',
    storeName: 'decisions20',
    url: 'http://www.government.bg/cgi-bin/e-cms/rss.pl?ch=0004&'
  }
})

.run(function($ionicPlatform) {

  // init local storage
  storage.init();
  // init date-time lib
  moment.lang('bg');

  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }
  });
})

.config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

    // setup an abstract state for the tabs directive
    .state('tab', {
      url: "/tab",
      abstract: true,
      templateUrl: "templates/tabs.html"
    })

    // Each tab has its own nav history stack:

    .state('tab.about', {
      url: '/about',
      views: {
        'tab-about': {
          templateUrl: 'templates/tab-about.html',
          controller: 'AboutCtrl'
        }
      }
    })

    .state('tab.news', {
      url: '/news',
      views: {
        'tab-news': {
          templateUrl: 'templates/tab-news.html',
          controller: 'NewsCtrl'
        }
      }
    })
    .state('tab.news-detail', {
      url: '/news/:id',
      views: {
        'tab-news': {
          templateUrl: 'templates/news-detail.html',
          controller: 'NewsDetailCtrl'
        }
      }
    })

    .state('tab.events', {
      url: '/events',
      views: {
        'tab-events': {
          templateUrl: 'templates/tab-news.html',
          controller: 'EventsCtrl'
        }
      }
    })
    .state('tab.events-detail', {
      url: '/events/:id',
      views: {
        'tab-events': {
          templateUrl: 'templates/news-detail.html',
          controller: 'EventsDetailCtrl'
        }
      }
    })

    .state('tab.decisions', {
      url: '/decisions',
      views: {
        'tab-decisions': {
          templateUrl: 'templates/tab-news.html',
          controller: 'DecisionsCtrl'
        }
      }
    })
    .state('tab.decisions-detail', {
      url: '/decisions/:id',
      views: {
        'tab-decisions': {
          templateUrl: 'templates/news-detail.html',
          controller: 'DecisionsDetailCtrl'
        }
      }
    })

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/news');

});

<|endoftext|>


<commit_before>import React from 'react'
import { Text } from '@hackclub/design-system'

const ErrorPage = ({
  message = 'Something terrible has happened',
  ...props
}) => (
  <Text color="error" py={3} align="center" {...props}>
    🚨 {message} 🚨

    Please let us know about this by emailing us at{' '}
    bug@hackclub.com
  </Text>
)

export default ErrorPage
<commit_msg>Fix ErrorPage error<commit_after>import React from 'react'
import { Text } from '@hackclub/design-system'

const alarm = (

    🚨

)

const ErrorPage = ({
  message = 'Something terrible has happened',
  ...props
}) => (
  <Text color="error" py={3} align="center" {...props}>
    {alarm} {message} {alarm}

    Please let us know about this by emailing us at{' '}
    bug@hackclub.com
  </Text>
)

export default ErrorPage
<|endoftext|>


<commit_before>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, mount } from 'enzyme';
import chai from 'chai';
import Form from './Form';

const expect = chai.expect;

/* eslint-disable no-unused-vars */
const debug = (component) => {
    console.info('------------------------------------------------------------');
    console.info(component.debug());
    console.info('------------------------------------------------------------');
};
/* eslint-enable no-unused-vars */

/* *****************************************************************************
the Form component
    should be a form element
    should be a form.form-inline element when inline=true
    should be a form.form-horizontal element when horizontal=true
*/
describe('the Form component', () => {

    it('should be a form element', () => {
        const component = shallow(<Form>a child</Form>);

        expect(component.is('div')).to.equal(true);
        expect(component.is('div.form-inline')).to.equal(false);
        expect(component.is('div.form-horizontal')).to.equal(false);
    });

    it('should be a form.form-inline element', () => {
        const component = shallow(<Form inline>a child</Form>);

        expect(component.is('div.form-inline')).to.equal(true);
        expect(component.is('div.form-horizontal')).to.equal(false);
    });

    it('should be a form.form-horizontal element', () => {
        const component = shallow(<Form horizontal>a child</Form>);

        expect(component.is('div.form-inline')).to.equal(false);
        expect(component.is('div.form-horizontal')).to.equal(true);
    });

});

/* *****************************************************************************
the Form component
    should not show the alert message if initialized with a mix of valid & invalid values
    should not show the alert message if initialized with all valid values
    should not show the alert message if initialized with all invalid values
    should show an alert with a single error message when one child is blurred (1 invalid child)
    should show an alert with a single error message when one child is blurred (2 invalid children)
*/
describe('the Form component', () => {

    it('should not show the alert message if initialized with a mix of valid ' +
        '& invalid values', () => {
        const label = 'my label';

        const invalid = '';

        const valid = 'triceratops';

        const component = mount(
            <Form>
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={valid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);
    });

    it('should not show the alert message if initialized with all valid values', () => {
        const label = 'my label';

        const valid = 'triceratops';

        const component = mount(
            <Form>
                <Form.TextInput required value={valid} />
                <Form.TextInput required value={valid} />
                <Form.TextInput required value={valid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);
    });

    it('should not show the alert message if initialized with all invalid values', () => {
        const label = 'my label';

        const invalid = '';

        const component = mount(
            <Form>
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);
    });

    it('should show an alert with a single error message when one child is ' +
        'blurred (1 invalid child)', () => {
        const label = 'my label';

        const descriptionForValid = 'this should not appear';
        const descriptionForInvalid = 'should see this';

        const initialValue = 'this is valid';

        const newValue = '';

        const component = mount(
            <Form>
                <Form.TextInput
                    required
                    id="1"
                    description={descriptionForValid}
                    value={initialValue}
                />
                <Form.TextInput
                    required
                    id="2"
                    description={descriptionForInvalid}
                    value={initialValue}
                />
                <Form.TextInput
                    required
                    id="3"
                    description={descriptionForValid}
                    value={initialValue}
                />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);

        component.find('input[id="2"]').simulate('change', {
            target: { value: newValue }
        });

        component.find('input[id="2"]').simulate('blur');

        expect(component.find('Alert')).to.have.length(1);
        expect(component.find('Alert').text()).to.not.contain(descriptionForValid);
        expect(component.find('Alert').text()).to.contain(descriptionForInvalid);
    });

    it('should show an alert with a single error message when one child is ' +
        'blurred (2 invalid children)', () => {
        const label = 'my label';

        const descriptionForValid = 'this should not appear';
        const descriptionForInvalid = 'should see this';

        const valid = 'this is valid';
        const invalid = '';

        const newValue = '';

        const component = mount(
            <Form>
                <Form.TextInput required name="textinput-1" description={descriptionForValid} value={valid} />
                <Form.TextInput required name="textinput-2" description={descriptionForInvalid} value={valid} />
                <Form.TextInput required name="textinput-3" description={descriptionForValid} value={invalid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);

        component.find('input[name="textinput-2"]').simulate('change', {
            target: { value: newValue }
        });

        component.find('input[name="textinput-2"]').simulate('blur');

        expect(component.find('Alert')).to.have.length(1);
        expect(component.find('Alert').text()).to.not.contain(descriptionForValid);
        expect(component.find('Alert').text()).to.contain(descriptionForInvalid);
    });

});
<commit_msg>updated spec to use name prop instead of id<commit_after>// the eslint "no-unused-expressions" rule is triggered by the `expect`
// assertions in the tests. So, in order to avoid problems with eslint, I'm
// disabling that rule in this file
//
/* eslint-disable no-unused-expressions */

import React from 'react';
import { shallow, mount } from 'enzyme';
import chai from 'chai';
import Form from './Form';

const expect = chai.expect;

/* eslint-disable no-unused-vars */
const debug = (component) => {
    console.info('------------------------------------------------------------');
    console.info(component.debug());
    console.info('------------------------------------------------------------');
};
/* eslint-enable no-unused-vars */

/* *****************************************************************************
the Form component
    should be a form element
    should be a form.form-inline element when inline=true
    should be a form.form-horizontal element when horizontal=true
*/
describe('the Form component', () => {

    it('should be a form element', () => {
        const component = shallow(<Form>a child</Form>);

        expect(component.is('div')).to.equal(true);
        expect(component.is('div.form-inline')).to.equal(false);
        expect(component.is('div.form-horizontal')).to.equal(false);
    });

    it('should be a form.form-inline element', () => {
        const component = shallow(<Form inline>a child</Form>);

        expect(component.is('div.form-inline')).to.equal(true);
        expect(component.is('div.form-horizontal')).to.equal(false);
    });

    it('should be a form.form-horizontal element', () => {
        const component = shallow(<Form horizontal>a child</Form>);

        expect(component.is('div.form-inline')).to.equal(false);
        expect(component.is('div.form-horizontal')).to.equal(true);
    });

});

/* *****************************************************************************
the Form component
    should not show the alert message if initialized with a mix of valid & invalid values
    should not show the alert message if initialized with all valid values
    should not show the alert message if initialized with all invalid values
    should show an alert with a single error message when one child is blurred (1 invalid child)
    should show an alert with a single error message when one child is blurred (2 invalid children)
*/
describe('the Form component', () => {

    it('should not show the alert message if initialized with a mix of valid ' +
        '& invalid values', () => {
        const label = 'my label';

        const invalid = '';

        const valid = 'triceratops';

        const component = mount(
            <Form>
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={valid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);
    });

    it('should not show the alert message if initialized with all valid values', () => {
        const label = 'my label';

        const valid = 'triceratops';

        const component = mount(
            <Form>
                <Form.TextInput required value={valid} />
                <Form.TextInput required value={valid} />
                <Form.TextInput required value={valid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);
    });

    it('should not show the alert message if initialized with all invalid values', () => {
        const label = 'my label';

        const invalid = '';

        const component = mount(
            <Form>
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.TextInput required value={invalid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);
    });

    it('should show an alert with a single error message when one child is ' +
        'blurred (1 invalid child)', () => {
        const label = 'my label';

        const descriptionForValid = 'this should not appear';
        const descriptionForInvalid = 'should see this';

        const initialValue = 'this is valid';

        const newValue = '';

        const component = mount(
            <Form>
                <Form.TextInput
                    required
                    name="textinput-1"
                    description={descriptionForValid}
                    value={initialValue}
                />
                <Form.TextInput
                    required
                    name="textinput-2"
                    description={descriptionForInvalid}
                    value={initialValue}
                />
                <Form.TextInput
                    required
                    name="textinput-3"
                    description={descriptionForValid}
                    value={initialValue}
                />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);

        component.find('input[name="textinput-2"]').simulate('change', {
            target: { value: newValue }
        });

        component.find('input[name="textinput-2"]').simulate('blur');

        expect(component.find('Alert')).to.have.length(1);
        expect(component.find('Alert').text()).to.not.contain(descriptionForValid);
        expect(component.find('Alert').text()).to.contain(descriptionForInvalid);
    });

    it('should show an alert with a single error message when one child is ' +
        'blurred (2 invalid children)', () => {
        const label = 'my label';

        const descriptionForValid = 'this should not appear';
        const descriptionForInvalid = 'should see this';

        const valid = 'this is valid';
        const invalid = '';

        const newValue = '';

        const component = mount(
            <Form>
                <Form.TextInput required name="textinput-1" description={descriptionForValid} value={valid} />
                <Form.TextInput required name="textinput-2" description={descriptionForInvalid} value={valid} />
                <Form.TextInput required name="textinput-3" description={descriptionForValid} value={invalid} />
                <Form.SubmitButton label={label} />
            </Form>
        );

        expect(component.find('Alert')).to.have.length(0);

        component.find('input[name="textinput-2"]').simulate('change', {
            target: { value: newValue }
        });

        component.find('input[name="textinput-2"]').simulate('blur');

        expect(component.find('Alert')).to.have.length(1);
        expect(component.find('Alert').text()).to.not.contain(descriptionForValid);
        expect(component.find('Alert').text()).to.contain(descriptionForInvalid);
    });

});
<|endoftext|>


<commit_before>import HypertyDiscovery from 'service-framework/src/hyperty-discovery/HypertyDiscovery'
import URI from 'urijs'
import Syncher from 'service-framework/src/syncher/Syncher'
import SyncObject from 'service-framework/src/syncher/SyncObject'
import GroupChat from './GroupChat'

class Communication extends SyncObject{
    constructor(name){
        super()

        this.startingTime = Date.now()
        this.lastModified = Date.now()
        this.status = "pending"
        this.resources = []
        this.children = []
        this.name = name
    }
}

let GroupChatHyperty = {
    _getHyFor (participants){
        return Promise.all(participants.map((p) => {
            return this.hypertyDiscoveryService.discoverHypertyPerUser(p.email, p.domain)
                .then((user)=>user.hypertyURL)
        }))
    },

    _createSyncher (name, hyperties){
        return this.syncher.create(this.objectDescURL, hyperties, new Communication(name))
    },

    create (name, participants) {
        return this._getHyFor(participants)
            .then((hyperties)=>this._createSyncher(name, hyperties))
            .then((dataObjectReporter) => {
                dataObjectReporter.onSubscription((event)=>event.accept())
                return GroupChat(dataObjectReporter)
            })
    },

    onInvite (callback) {
        return this.syncher.onNotification((event) =>{
            this.syncher.subscribe(this.objectDescURL, event.url)
                .then((dataObject) => {
                    return callback(GroupChat(dataObject))
                })
        })
    }
}

let groupChatFactory = function(hypertyURL, bus, config){
    let syncher = new Syncher(hypertyURL, bus, config);
    let hypertyDiscovery = new HypertyDiscovery(hypertyURL, bus)
    let uri = new URI(hypertyURL)

    return Object.assign(Object.create(GroupChatHyperty), {

            'syncher': syncher,
            'hypertyDiscoveryService': hypertyDiscovery,
            'objectDescURL': 'hyperty-catalogue://' + uri.hostname() + '/.well-known/dataschemas/CommunicationDataSchema'
        })
}

export default function activate(hypertyURL, bus, config){
    return {
        name: 'Group Chat Hyperty',
        instance: groupChatFactory(hypertyURL, bus, config)
    }
}
<commit_msg>Resolve hyperty by user, descriptor and time<commit_after>import HypertyDiscovery from 'service-framework/dist/HypertyDiscovery'
import URI from 'urijs'
import { Syncher } from 'service-framework/dist/Syncher'
import GroupChat from './GroupChat'

class Communication {
    constructor(name){
        this.startingTime = Date.now()
        this.lastModified = Date.now()
        this.status = "pending"
        this.resources = []
        this.children = []
        this.name = name
    }
}

let GroupChatHyperty = {
    _getHyFor (participants){
        return Promise.all(participants.map((p) => {
            return this.hypertyDiscoveryService.discoverHypertiesPerUser(p.email, p.domain)
                .then((hyperties)=>{
                    return Object.keys(hyperties)
                        .map((key)=>{return {key:key, descriptor:hyperties[key].descriptor, lastModified:hyperties[key].lastModified}})
                        .filter((desc)=>desc.descriptor.endsWith('GroupChatHyperty'))
                        .sort((a,b)=>(new Date(a.lastModified)<new Date(b.lastModified))?1:-1)
                        .shift().key
                })
        }))
    },

    _createSyncher (name, hyperties){
        return this.syncher.create(this.objectDescURL, hyperties, new Communication(name))
    },

    create (name, participants) {
        return this._getHyFor(participants)
            .then((hyperties)=>this._createSyncher(name, hyperties))
            .then((dataObjectReporter) => {
                dataObjectReporter.onSubscription((event)=>event.accept())
                return GroupChat(dataObjectReporter)
            })
    },

    onInvite (callback) {
        return this.syncher.onNotification((event) =>{
            this.syncher.subscribe(this.objectDescURL, event.url)
                .then((dataObject) => {
                    return callback(GroupChat(dataObject))
                })
        })
    }
}

let groupChatFactory = function(hypertyURL, bus, config){
    let syncher = new Syncher(hypertyURL, bus, config);
    let hypertyDiscovery = new HypertyDiscovery(hypertyURL, bus)
    let uri = new URI(hypertyURL)

    return Object.assign(Object.create(GroupChatHyperty), {
            'syncher': syncher,
            'hypertyDiscoveryService': hypertyDiscovery,
            'objectDescURL': 'hyperty-catalogue://' + uri.hostname() + '/.well-known/dataschemas/CommunicationDataSchema',
        })
}

export default function activate(hypertyURL, bus, config){
    return {
        name: 'Group Chat Hyperty',
        instance: groupChatFactory(hypertyURL, bus, config)
    }
}
<|endoftext|>


<commit_before>$(function onReady() { readPort(); fetchTemperatureReadings(); });

function writePort(val) {
	$.get("/writePort", {value : val}, function(data) { $("#status").text(data); })
		.fail(function() { $("#status").text("Failed to write port!"); });
}

function readPort() {
	$.get("/readPort", {}, function(data) { $("#status").text(data); })
		.fail(function() { $("#status").text("Failed to read port!"); });
}

function fetchTemperatureReadings() {
	$.get("/readTemp", {}, function(data) {
		ul = $("#readings");
		ul.html("");
		ul.appendTo("body");
		$(data).each(function (index, item) {
			ul.append($(document.createElement("li"))
				.text(item["name"] + ": " + item["celsius"] + "C"));
		});
	});
}
<commit_msg>Set status correctly in main.js<commit_after>$(function onReady() { readPort(); fetchTemperatureReadings(); });

function writePort(val) {
	$.get("/writePort", {value : val}, function(data) { $("#status").text(data["status"]); })
		.fail(function() { $("#status").text("Failed to write port!"); });
}

function readPort() {
	$.get("/readPort", {}, function(data) { $("#status").text(data["status"]); })
		.fail(function() { $("#status").text("Failed to read port!"); });
}

function fetchTemperatureReadings() {
	$.get("/readTemp", {}, function(data) {
		ul = $("#readings");
		ul.html("");
		ul.appendTo("body");
		$(data).each(function (index, item) {
			ul.append($(document.createElement("li"))
				.text(item["name"] + ": " + item["celsius"] + "C"));
		});
	});
}
<|endoftext|>


<commit_before>'use strict';

var assert = require('assert'),
	indigo = require('../../indigo'),
	rest = require('../../libs/rest'),
	params = {'param1':1, 'param2': 2};

describe('Testing REST API\'s', function () {

	before(function (done) {
		indigo.start(__appDir + '/examples/firststep/config/app.json');
		done();
	});

	after(function(done) {
		indigo.close(done);
	});

	it('should verify rest properties', function(done) {
		assert.equal(indigo.service.host, 'localhost');
		assert.equal(indigo.service.port, '8787');
		done();
	});

	it('should test GET', function(done) {
		indigo.service.get('/firststep/REST', null, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'GET');
			done();
		});
	});

	it('should test POST', function(done) {
		indigo.service.post('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'POST');
			done();
		});
	});

	it('should test PUT', function(done) {
		indigo.service.put('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'PUT');
			done();
		});
	});

	it('should test DELETE', function(done) {
		indigo.service.delete('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'DELETE');
			done();
		});
	});

	it('should test PATCH', function(done) {
		indigo.service.patch('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'PATCH');
			done();
		});
	});

	it('should test error 404', function(done) {
		indigo.service.init({
				host:'localhost',
				port:80
			}).get('/firststep/REST', params, function(err, result, req, res) {
				assert.equal(res.statusCode, 404);
				done();
		});
	});

	it('should test ECONNRESET error', function(done) {
		indigo.service.init({
				host:'localhost',
				port:8787,
				secure:true
			}).get('/firststep/REST', params, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNRESET');
				done();
		});
	});

	it('should get ECONNREFUSED error', function(done) {
		indigo.service.init({
				host:'localhost',
				port: 8765,
				secure: true
			}).get('/firststep/REST', params, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNREFUSED');
				done();
		});
	});

	it('should get ECONNREFUSED calling request function', function(done) {
		rest().init({
				host:'localhost',
				port: 8123
			}).request('GET', '/firststep/REST', null, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNREFUSED');
				done();
		});
	});

	it('should get ECONNRESET calling request function', function(done) {
		rest().init({
				host:'localhost',
				port: 8787
			}).request('GET', '/firststep/REST', null, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNRESET');
				done();
		});
	});

	it('should test parsing error', function(done) {
		indigo.service.get('/firststep/TEST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err.message, 'Unexpected token H');
			assert.equal(result, 'HELLO WORLD!');
			done();
		});
	});
});
 <commit_msg>Fixed uinttest on Linux OS<commit_after>'use strict';

var assert = require('assert'),
	indigo = require('../../indigo'),
	rest = require('../../libs/rest'),
	params = {'param1':1, 'param2': 2};

describe('Testing REST API\'s', function () {

	before(function (done) {
		indigo.start(__appDir + '/examples/firststep/config/app.json');
		done();
	});

	after(function(done) {
		indigo.close(done);
	});

	it('should verify rest properties', function(done) {
		assert.equal(indigo.service.host, 'localhost');
		assert.equal(indigo.service.port, '8787');
		done();
	});

	it('should test GET', function(done) {
		indigo.service.get('/firststep/REST', null, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'GET');
			done();
		});
	});

	it('should test POST', function(done) {
		indigo.service.post('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'POST');
			done();
		});
	});

	it('should test PUT', function(done) {
		indigo.service.put('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'PUT');
			done();
		});
	});

	it('should test DELETE', function(done) {
		indigo.service.delete('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'DELETE');
			done();
		});
	});

	it('should test PATCH', function(done) {
		indigo.service.patch('/firststep/REST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err, null, 'no errors');
			assert.equal(result.method, 'PATCH');
			done();
		});
	});

	it('should test error', function(done) {
		indigo.service.init({
				host:'localhost',
				port:80
			}).get('/firststep/REST', params, function(err, result, req, res) {
				assert.notEqual(res.statusCode, 200);
				done();
		});
	});

	it('should test ECONNRESET error', function(done) {
		indigo.service.init({
				host:'localhost',
				port:8787,
				secure:true
			}).get('/firststep/REST', params, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNRESET');
				done();
		});
	});

	it('should get ECONNREFUSED error', function(done) {
		indigo.service.init({
				host:'localhost',
				port: 8765,
				secure: true
			}).get('/firststep/REST', params, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNREFUSED');
				done();
		});
	});

	it('should get ECONNREFUSED calling request function', function(done) {
		rest().init({
				host:'localhost',
				port: 8123
			}).request('GET', '/firststep/REST', null, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNREFUSED');
				done();
		});
	});

	it('should get ECONNRESET calling request function', function(done) {
		rest().init({
				host:'localhost',
				port: 8787
			}).request('GET', '/firststep/REST', null, function(err, result, req, res) {
				assert.equal(res.statusCode, 500);
				assert.equal(err.code, 'ECONNRESET');
				done();
		});
	});

	it('should test parsing error', function(done) {
		indigo.service.get('/firststep/TEST', params, function(err, result, req, res) {
			assert.equal(res.statusCode, 200);
			assert.equal(err.message, 'Unexpected token H');
			assert.equal(result, 'HELLO WORLD!');
			done();
		});
	});
});
 <|endoftext|>


<commit_before>/*
 * Copyright 2016 Lime - HighTech Solutions s.r.o.
 *
 * 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 from "react";
import {connect} from "react-redux";
// Actions
import {authenticate, init} from "../actions/tokenActions";
// Components
// i18n
import {FormattedMessage} from "react-intl";

const stompClient = require('../websocket-client');

/**
 * Operation component displays the operation data to the user.
 */
@connect((store) => {
    return {
        context: store.dispatching.context
    }
})
export default class Token extends React.Component {

    constructor() {
        super();
        this.update = this.update.bind(this);
        this.init = this.init.bind(this);
        this.onRegister = this.onRegister.bind(this);
        this.onAuthorize = this.onAuthorize.bind(this);
        this.setAuthorizedByWebSocket = this.setAuthorizedByWebSocket.bind(this);
        this.isAuthorizedByWebSocket = this.isAuthorizedByWebSocket.bind(this);
        this.state = {authorizedByWebSocket: false};
    }

    componentWillMount() {
        this.init();
        this.update();
    }

    init() {
        this.props.dispatch(init());
    }

    update() {
        const update = this.update;
        const isAuthorizedByWebSocket = this.isAuthorizedByWebSocket;
        this.props.dispatch(authenticate(function (b) {
            if (b) {
                setTimeout(function () {
                    if (!isAuthorizedByWebSocket()) {
                        update();
                    }
                }, 3000);
            }
        }));
    }

    setAuthorizedByWebSocket() {
        this.setState({authorizedByWebSocket: true});
    }

    isAuthorizedByWebSocket() {
        return this.state.authorizedByWebSocket;
    }

    onRegister() {
        console.log('WebSocket has been registered.');
    }

    onAuthorize() {
        const setAuthorizedByWebSocket = this.setAuthorizedByWebSocket;
        console.log('Authorization received from WebSocket.');
        this.props.dispatch(authenticate(function (b) {
            if (!b) {
                setAuthorizedByWebSocket();
            }
        }));
    }

    componentWillReceiveProps(props) {
        const webSocketId = props.context.webSocketId;
        if (webSocketId != null) {
            stompClient.register([
                {route: '/user/topic/registration', callback: this.onRegister},
                {route: '/user/topic/authorization', callback: this.onAuthorize}
            ], webSocketId);
        }
    }

    render() {
        return (

                    <FormattedMessage id="message.token.confirm"/>

                    <FormattedMessage id="message.token.offline"/>

                    <FormattedMessage id="message.token.offline.link"/>

        )
    }
}<commit_msg>Fix #58: Authorization notification using WebSockets vs. regular authentication in mtoken step Potential race condition in the authenticate() method calls is handled<commit_after>/*
 * Copyright 2016 Lime - HighTech Solutions s.r.o.
 *
 * 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 from "react";
import {connect} from "react-redux";
// Actions
import {authenticate, init} from "../actions/tokenActions";
// Components
// i18n
import {FormattedMessage} from "react-intl";

const stompClient = require('../websocket-client');

/**
 * Operation component displays the operation data to the user.
 */
@connect((store) => {
    return {
        context: store.dispatching.context
    }
})
export default class Token extends React.Component {

    constructor() {
        super();
        this.update = this.update.bind(this);
        this.init = this.init.bind(this);
        this.onRegister = this.onRegister.bind(this);
        this.onAuthorize = this.onAuthorize.bind(this);
        this.setAuthorizationByWebSocketInProgress = this.setAuthorizationByWebSocketInProgress.bind(this);
        this.isAuthorizationByWebSocketInProgress = this.isAuthorizationByWebSocketInProgress.bind(this);
        this.setAuthorizedByWebSocket = this.setAuthorizedByWebSocket.bind(this);
        this.isAuthorizedByWebSocket = this.isAuthorizedByWebSocket.bind(this);
        this.state = {authorizationByWebSocketInProgress: false, authorizedByWebSocket: false};
    }

    componentWillMount() {
        this.init();
        this.update();
    }

    init() {
        this.props.dispatch(init());
    }

    update() {
        const update = this.update;
        const isAuthorizationByWebSocketInProgress = this.isAuthorizationByWebSocketInProgress;
        const isAuthorizedByWebSocket = this.isAuthorizedByWebSocket;
        if (!isAuthorizedByWebSocket()) {
            // Authorization by WebSockets wasn't completed, we need to keep calling update() every 3s.
            if (isAuthorizationByWebSocketInProgress()) {
                // If the WebSocket authorization is in progress, calling authenticate() method is temporarily paused,
                // however update() method is called in 3s to check for possible change of state in case WebSocket
                // authenticate() method fails (in this case the 3s polling will be resumed).
                setTimeout(function () {
                    update();
                }, 3000);
            } else {
                // Otherwise keep trying to authenticate every 3s using polling. This is a fallback mechanism in case
                // authorization by WebSockets fails completely (e.g. network issues).
                this.props.dispatch(authenticate(function (b) {
                    if (b) {
                        setTimeout(function () {
                            update();
                        }, 3000);
                    }
                }));
            }
        }
    }

    setAuthorizedByWebSocket(authorized) {
        this.setState({authorizedByWebSocket: authorized});
    }

    isAuthorizedByWebSocket() {
        return this.state.authorizedByWebSocket;
    }

    setAuthorizationByWebSocketInProgress(inProgress) {
        this.setState({authorizationByWebSocketInProgress: inProgress});
    }

    isAuthorizationByWebSocketInProgress() {
        return this.state.authorizationByWebSocketInProgress;
    }

    onRegister() {
        console.log('WebSocket has been registered.');
    }

    onAuthorize() {
        const setAuthorizedByWebSocket = this.setAuthorizedByWebSocket;
        const setAuthorizationByWebSocketInProgress = this.setAuthorizationByWebSocketInProgress;
        // WebSocket authorization is marked as in progress so that regular 3s polling does not call the authenticate() method.
        // This mechanism avoids calling authenticate() methods twice at the same time in the rather rare case of a race condition.
        setAuthorizationByWebSocketInProgress(true);
        console.log('Authorization received from WebSocket.');
        this.props.dispatch(authenticate(function (b) {
            if (!b) {
                setAuthorizedByWebSocket(true);
            }
            // End of attempt to authorize by WebSockets - 3s polling can be resumed in case authorization is not done yet.
            setAuthorizationByWebSocketInProgress(false);
        }));
    }

    componentWillReceiveProps(props) {
        const webSocketId = props.context.webSocketId;
        if (webSocketId != null) {
            stompClient.register([
                {route: '/user/topic/registration', callback: this.onRegister},
                {route: '/user/topic/authorization', callback: this.onAuthorize}
            ], webSocketId);
        }
    }

    render() {
        return (

                    <FormattedMessage id="message.token.confirm"/>

                    <FormattedMessage id="message.token.offline"/>

                    <FormattedMessage id="message.token.offline.link"/>

        )
    }
}<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// NodeLevel Template
////////////////////////////////////////////////////////////////////////////////

/*
 * Copyright 2015 Concept
 *
 * 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.
 */

// -- Helpers ------------------------------------------------------------------

/**
* NodeLevel: deleteNode
* parameter: _id (node collection id)
* description: recursively deletes all children
* from a node in a post-order manner
*/
deleteNode = function(prevNode, template) {

  if(typeof prevNode === "string")
    prevNode = GV.collections.Nodes.findOne({ _id: prevNode });

  var nodeId = prevNode._id;
  var fileId = prevNode.fileId;

  var nodes = GV.collections.Nodes.find({parent: nodeId}).fetch();

  nodes.forEach(function(node) {
    deleteNode(node);
  });

  // Remove the tab
  GV.tabs.removeTab(nodeId);

  // Remove the node
  GV.collections.Nodes.remove({ _id: nodeId }, function(error) {

    if(fileId) {
      GV.collections.Files.remove({ _id: fileId }, function(error) {

        // Remove the reference from the document
        GV.collections.Documents.update({
          _id: Session.get('mainDocument')
        },
        {
          $pull: {
            children: nodeId,
            fileIds: fileId
          }
        }, function(error) {
          if(error) {
            Notifications.warn('Feil', error.message);
          }

          // update positions
          if(template)
            updatePositions(template);
        });
      });
    } else {
      // Remove the reference from the document
      GV.collections.Documents.update({
        _id: Session.get('mainDocument')
      },
      {
        $pull: {
          children: nodeId
        }
      }, function(error) {
        if(error) {
          Notifications.warn('Feil', error.message);
        }

        // update positions
        if(template)
          updatePositions(template);
      });
    }
  });
};

getSection = function(prevSection, prevNodePos) {
  // var label = "";

  // if(this.level > 0) {
  //   if(node.prevSection) {
  //     label = label + node.prevSection + ".";
  //   }

  // }
  // label = label + "" + (prevNodePos + 1);
  if(prevSection)
    return prevSection + "." + (prevNodePos + 1);
  else
    prevNodePos + 1;

};

insertNodeOfType = function(data, type, t) {
  if(data && data._id) {

    var node = {
      parent: data._id,
      level: data.level + 1,
      sectionLabel: generateSectionLabel(data.sectionLabel, data.position),
      userId: data.userId,
      lastChanged: new Date(),
      position: -1,
      nodeType: type
    };

    GV.collections.Nodes.insert(node, function(error, nodeId) {
      if(!error) {
        GV.collections.Documents.update({
          _id: Session.get('mainDocument')
        },
        {
          $addToSet: {
            children: nodeId
          }
        });

        GV.collections.Nodes.update({ _id: data._id }, { $set: { collapsed: false } });

        Router.current().subscribe('nodeById', nodeId, {
          onReady: function () {
            Meteor.defer(function() {
              updatePositions(t.parentNode);

              $('li.node span').removeClass('selected');
              $("li.root li.node").find("[data-id='" + nodeId + "']").find("> span").addClass('selected');

              GV.tabs.setDummyTab(nodeId);
              Session.set('nodeInFocus', nodeId);
            });
          },
          onError: function () { console.log("onError", arguments); }
        });
      }
    });
  }
};

// -- Template helpers ---------------------------------------------------------

Template.NodeLevel.helpers({

  /**
   * Returns true if the node has been collapsed, and the children should be hidden.
   */
  isCollapsed: function() {
    return this.collapsed || this.collapsed;
  },

  /**
   * Returns true if the node has children.
   */
  hasChildren: function() {
    if(Session.get("showMediaNodes")) {
      return GV.collections.Nodes.find({ parent: this._id }).count() > 0;
    } else {
      return GV.collections.Nodes.find({ parent: this._id, nodeType: "chapter" }).count() > 0;
    }
  },

  /**
   * Returns the children of the current node.
   */
  children: function() {
    if(Session.get("showMediaNodes")) {
      return GV.collections.Nodes.find({ parent: this._id }, { sort: { nodeType: 1, position: 1  }}).map(function(node, index) {
        node.node_index = index;
        return node;
      });
    } else {
      return GV.collections.Nodes.find({ parent: this._id, nodeType: "chapter" }, { sort: { position: 1  }}).map(function(node, index) {
        node.node_index = index;
        return node;
      });
    }
  },

  getContext: function(options) {

    var context = _.extend(this, {
      prevSection: getSection(options.hash.prevSection, this.node_index)
    });

    return context;
  },
  /**
   * Returns a combined section label by merging the parents label and the node
   * position value. This is the readable structure notation.
   */
  // getSectionLabel: function() {
  //   var label = "";

  //   if(this.sectionLabel)
  //     label = label + this.sectionLabel;

  //   if(this.position >= 0) {

  //     if(this.level == 0)
  //       label = label + (this.position + 1);
  //     else
  //       label = label + "." + (this.position + 1);
  //   }

  //   return label;
  // },

  getSectionLabel: function() {
    return this.prevSection;
    // if(this.prevSection)
    //   return this.prevSection + "." + (this.node_index + 1);
    // else
    //   return this.node_index + 1;
  },

  /**
   * Returns true if this node should have a drop zone beneath itself.
   */
  hasBottomSlot: function() {
    return this.node_index == (GV.collections.Nodes.find({ parent: this.parent }).count() - 1);
  }

});

// -- Template on render -------------------------------------------------------

Template.NodeLevel.rendered = function() {

  var self = this;

  $('.tree li.node.root li.node.chapter span').contextMenu('right-click-menu-chapter-node', {
    bindings: {

      // Add node button
      'add-chapter-node': function(t) {
        var elData = UI.getData(t);

        insertNodeOfType(elData, "chapter", t);
      },

      // Add node button
      'add-media-node': function(t) {
        var elData = UI.getData(t);

        insertNodeOfType(elData, "media", t);
      },

      // Delete button
      'delete-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          var confirmationPrompt = {
            title: "Bekreftelse på slettingen",
            message: 'Er du sikker på at du vil slette referansen? NB: Vil slette alle underkategorier til referansen!',
            buttons: {
              cancel: {
                label: "Nei"
              },
              confirm: {
                label: "Ja",
                callback: function(result) {
                  if(result) {

                    deleteNode(elData, t.parentNode.parentNode.parentNode);

                    // Set the main document in focus
                    Session.set('nodeInFocus', Session.get('mainDocument'));

                    Notifications.success('Sletting fullført', 'Referansen ble slettet fra systemet.');
                  }
                }
              }
            }
          }
          bootbox.dialog(confirmationPrompt);
        }
      },

      // Edit button
      'edit-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          GV.tabs.addTab(elData._id);
          Session.set('nodeInFocus', elData._id);
        }
      }

    }
  });

$('.tree li.node.root li.node.media-node span').contextMenu('right-click-menu-media-node', {
    bindings: {

      // Delete button
      'delete-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          var confirmationPrompt = {
            title: "Bekreftelse på slettingen",
            message: 'Er du sikker på at du vil slette referansen? NB: Vil slette alle underkategorier til referansen!',
            buttons: {
              cancel: {
                label: "Nei"
              },
              confirm: {
                label: "Ja",
                callback: function(result) {
                  if(result) {

                    deleteNode(elData, t.parentNode.parentNode.parentNode);

                    // Set the main document in focus
                    Session.set('nodeInFocus', Session.get('mainDocument'));

                    Notifications.success('Sletting fullført', 'Referansen ble slettet fra systemet.');
                  }
                }
              }
            }
          }
          bootbox.dialog(confirmationPrompt);
        }
      },

      // Edit button
      'edit-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          GV.tabs.addTab(elData._id);
          Session.set('nodeInFocus', elData._id);
        }
      }

    }
  });
};
<commit_msg>Generalize node creation some what more.<commit_after>////////////////////////////////////////////////////////////////////////////////
// NodeLevel Template
////////////////////////////////////////////////////////////////////////////////

/*
 * Copyright 2015 Concept
 *
 * 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.
 */

// -- Helpers ------------------------------------------------------------------

/**
* NodeLevel: deleteNode
* parameter: _id (node collection id)
* description: recursively deletes all children
* from a node in a post-order manner
*/
deleteNode = function(prevNode, template) {

  if(typeof prevNode === "string")
    prevNode = GV.collections.Nodes.findOne({ _id: prevNode });

  var nodeId = prevNode._id;
  var fileId = prevNode.fileId;

  var nodes = GV.collections.Nodes.find({parent: nodeId}).fetch();

  nodes.forEach(function(node) {
    deleteNode(node);
  });

  // Remove the tab
  GV.tabs.removeTab(nodeId);

  // Remove the node
  GV.collections.Nodes.remove({ _id: nodeId }, function(error) {

    if(fileId) {
      GV.collections.Files.remove({ _id: fileId }, function(error) {

        // Remove the reference from the document
        GV.collections.Documents.update({
          _id: Session.get('mainDocument')
        },
        {
          $pull: {
            children: nodeId,
            fileIds: fileId
          }
        }, function(error) {
          if(error) {
            Notifications.warn('Feil', error.message);
          }

          // update positions
          if(template)
            updatePositions(template);
        });
      });
    } else {
      // Remove the reference from the document
      GV.collections.Documents.update({
        _id: Session.get('mainDocument')
      },
      {
        $pull: {
          children: nodeId
        }
      }, function(error) {
        if(error) {
          Notifications.warn('Feil', error.message);
        }

        // update positions
        if(template)
          updatePositions(template);
      });
    }
  });
};

getSection = function(prevSection, prevNodePos) {
  // var label = "";

  // if(this.level > 0) {
  //   if(node.prevSection) {
  //     label = label + node.prevSection + ".";
  //   }

  // }
  // label = label + "" + (prevNodePos + 1);
  if(prevSection)
    return prevSection + "." + (prevNodePos + 1);
  else
    prevNodePos + 1;

};

insertNodeOfType = function(data, type, t) {
  if(data && data._id) {

    var node = {
      parent: data._id,
      level: data.level + 1 || 0,
      sectionLabel: generateSectionLabel(data.sectionLabel, data.position),
      userId: data.userId,
      lastChanged: new Date(),
      position: -1,
      nodeType: type
    };

    GV.collections.Nodes.insert(node, function(error, nodeId) {
      if(!error) {
        GV.collections.Documents.update({
          _id: Session.get('mainDocument')
        },
        {
          $addToSet: {
            children: nodeId
          }
        });

        GV.collections.Nodes.update({ _id: data._id }, { $set: { collapsed: false } });

        Router.current().subscribe('nodeById', nodeId, {
          onReady: function () {
            Meteor.defer(function() {
              if(t)
                updatePositions(t.parentNode);

              $('li.node span').removeClass('selected');
              var el  = $("li.root li.node").find("[data-id='" + nodeId + "']").find("> span");

              if(el & el.length)
                el.addClass('selected');

              GV.tabs.setDummyTab(nodeId);
              Session.set('nodeInFocus', nodeId);

            });
          },
          onError: function () { console.log("onError", arguments); }
        });
      }
    });
  }
};

// -- Template helpers ---------------------------------------------------------

Template.NodeLevel.helpers({

  /**
   * Returns true if the node has been collapsed, and the children should be hidden.
   */
  isCollapsed: function() {
    return this.collapsed || this.collapsed;
  },

  /**
   * Returns true if the node has children.
   */
  hasChildren: function() {
    if(Session.get("showMediaNodes")) {
      return GV.collections.Nodes.find({ parent: this._id }).count() > 0;
    } else {
      return GV.collections.Nodes.find({ parent: this._id, nodeType: "chapter" }).count() > 0;
    }
  },

  /**
   * Returns the children of the current node.
   */
  children: function() {
    if(Session.get("showMediaNodes")) {
      return GV.collections.Nodes.find({ parent: this._id }, { sort: { nodeType: 1, position: 1  }}).map(function(node, index) {
        node.node_index = index;
        return node;
      });
    } else {
      return GV.collections.Nodes.find({ parent: this._id, nodeType: "chapter" }, { sort: { position: 1  }}).map(function(node, index) {
        node.node_index = index;
        return node;
      });
    }
  },

  getContext: function(options) {

    var context = _.extend(this, {
      prevSection: getSection(options.hash.prevSection, this.node_index)
    });

    return context;
  },
  /**
   * Returns a combined section label by merging the parents label and the node
   * position value. This is the readable structure notation.
   */
  // getSectionLabel: function() {
  //   var label = "";

  //   if(this.sectionLabel)
  //     label = label + this.sectionLabel;

  //   if(this.position >= 0) {

  //     if(this.level == 0)
  //       label = label + (this.position + 1);
  //     else
  //       label = label + "." + (this.position + 1);
  //   }

  //   return label;
  // },

  getSectionLabel: function() {
    return this.prevSection;
    // if(this.prevSection)
    //   return this.prevSection + "." + (this.node_index + 1);
    // else
    //   return this.node_index + 1;
  },

  /**
   * Returns true if this node should have a drop zone beneath itself.
   */
  hasBottomSlot: function() {
    return this.node_index == (GV.collections.Nodes.find({ parent: this.parent }).count() - 1);
  }

});

// -- Template on render -------------------------------------------------------

Template.NodeLevel.rendered = function() {

  var self = this;

  $('.tree li.node.root li.node.chapter span').contextMenu('right-click-menu-chapter-node', {
    bindings: {

      // Add node button
      'add-chapter-node': function(t) {
        var elData = UI.getData(t);

        insertNodeOfType(elData, "chapter", t);
      },

      // Add node button
      'add-media-node': function(t) {
        var elData = UI.getData(t);

        insertNodeOfType(elData, "media", t);
      },

      // Delete button
      'delete-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          var confirmationPrompt = {
            title: "Bekreftelse på slettingen",
            message: 'Er du sikker på at du vil slette referansen? NB: Vil slette alle underkategorier til referansen!',
            buttons: {
              cancel: {
                label: "Nei"
              },
              confirm: {
                label: "Ja",
                callback: function(result) {
                  if(result) {

                    deleteNode(elData, t.parentNode.parentNode.parentNode);

                    // Set the main document in focus
                    Session.set('nodeInFocus', Session.get('mainDocument'));

                    Notifications.success('Sletting fullført', 'Referansen ble slettet fra systemet.');
                  }
                }
              }
            }
          }
          bootbox.dialog(confirmationPrompt);
        }
      },

      // Edit button
      'edit-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          GV.tabs.addTab(elData._id);
          Session.set('nodeInFocus', elData._id);
        }
      }

    }
  });

$('.tree li.node.root li.node.media-node span').contextMenu('right-click-menu-media-node', {
    bindings: {

      // Delete button
      'delete-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          var confirmationPrompt = {
            title: "Bekreftelse på slettingen",
            message: 'Er du sikker på at du vil slette referansen? NB: Vil slette alle underkategorier til referansen!',
            buttons: {
              cancel: {
                label: "Nei"
              },
              confirm: {
                label: "Ja",
                callback: function(result) {
                  if(result) {

                    deleteNode(elData, t.parentNode.parentNode.parentNode);

                    // Set the main document in focus
                    Session.set('nodeInFocus', Session.get('mainDocument'));

                    Notifications.success('Sletting fullført', 'Referansen ble slettet fra systemet.');
                  }
                }
              }
            }
          }
          bootbox.dialog(confirmationPrompt);
        }
      },

      // Edit button
      'edit-node': function(t) {
        var elData = UI.getData(t);

        if(elData && elData._id) {
          GV.tabs.addTab(elData._id);
          Session.set('nodeInFocus', elData._id);
        }
      }

    }
  });
};
<|endoftext|>


<commit_before>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers','chart.js','ngCordova'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }
  });
})

.config(function($stateProvider, $urlRouterProvider,$httpProvider) {
  $stateProvider

    .state('app', {
    url: '/app',
    abstract: true,
    templateUrl: 'templates/side-menu-left.html'
    // controller: 'AppCtrl'
  })
  .state('app.overview', {
      url: "/overview",
      views: {
        'menuContent' :{
          templateUrl: "templates/overview.html"
        }
      }
    })
  .state('app.arm', {
      url: "/arm",
      views: {
        'menuContent' :{
          templateUrl: "/templates/arm.html"
        }
      }
    })
  .state('app.camera', {
      url: "/camera",
      views: {
        'menuContent' :{
          templateUrl: "templates/camera.html"
        }
      }
    })
    .state('app.dashboard', {
      url: "/dashboard",
      views: {
        'menuContent' :{
          templateUrl: "templates/dashboard.html"
        }
      }
    })
  .state('app.addNode', {
      url: "/add-node",
      views: {
        'menuContent' :{
          templateUrl: "templates/add-node.html"
        }
      }
    })
  .state('app.dashboard.home', {
      url: "/home",
      views: {
        'home-tab' :{
          templateUrl: "templates/home.html"
        }
      }
    })
  .state('app.dashboard.favorites', {
      url: "/favorites",
      views: {
        'favorites-tab' :{
          templateUrl: "templates/favorites.html"
        }
      }
    })
  .state('app.dashboard.settings', {
      url: "/settings",
      views: {
        'settings-tab' :{
          templateUrl: "templates/settings.html"
        }
      }
    })

  .state('app.nodeType', {
      url: "/nodeType",
      views: {
        'menuContent' :{
          templateUrl: "templates/nodeType.html"
        }
      }
    })
	.state('app.node', {
      url: "/node",
      views: {
        'menuContent' :{
          templateUrl: "templates/node-single.html"
        }
      }
    })
  .state('app.usersetting', {
      url: "/usersetting",
      views: {
        'menuContent' :{
          templateUrl: "templates/usersetting.html"
        }
      }
    })
  .state('app.userinfo', {
      url: "/userinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/userinfo.html"
        }
      }
    })

  .state('app.subusers', {
      url: "/subusers",
      views: {
        'menuContent' :{
          templateUrl: "templates/subusers.html"
        }
      }
    })
  .state('app.subuserinfo', {
      url: "/subuserinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/subuserinfo.html"
        }
      }
    })
  .state('app.settings', {
      url: "/settings",
      views: {
        'menuContent' :{
          templateUrl: "templates/settings.html"
        }
      }
    })
  .state('app.devicemanage', {
      url: "/devicemanage",
      views: {
        'menuContent' :{
          templateUrl: "templates/devicemanage.html"
        }
      }
    })
  .state('app.deviceinfo', {
      url: "/deviceinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/deviceinfo.html"
        }
      }
    })
  .state('app.devicenetwork', {
      url: "/devicenetwork",
      views: {
        'menuContent' :{
          templateUrl: "templates/devicenetwork.html"
        }
      }
    })
  .state('app.notifies', {
      url: "/notifies",
      views: {
        'menuContent' :{
          templateUrl: "templates/notifies.html"
        }
      }
    })
  .state('app.alarm', {
      url: "/alarm",
      views: {
        'menuContent' :{
          templateUrl: "templates/alarm.html"
        }
      }
    })
  .state('app.purchaseinfo', {
      url: "/purchaseinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/purchaseinfo.html"
        }
      }
    })
  .state('app.battery', {
      url: '/battery',
      views: {
        'menuContent': {
          templateUrl: 'templates/battery.html'
        }
      }
    })
  .state('app.manustack', {
      url: '/manustack',
      views: {
        'menuContent': {
          templateUrl: 'templates/manustack.html'
        }
      }
    })
  .state('app.vib', {
    url: '/vib',
    views: {
        'menuContent': {
             templateUrl: 'templates/vib.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })

  .state('app.changepassword', {
    url: '/changepassword',
    views: {
        'menuContent': {
             templateUrl: 'templates/changepassword.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })

  .state('app.version', {
    url: '/version',
    views: {
        'menuContent': {
             templateUrl: 'templates/version.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })
  .state('app.help', {
    url: '/help',
    views: {
        'menuContent': {
             templateUrl: 'templates/help.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })
    .state('app.login', {
    url: '/login',
    views: {
        'menuContent': {
             templateUrl: 'templates/login.html',
        }
      }
    })
    .state('app.register', {
    url: '/register',
    views: {
        'menuContent': {
             templateUrl: 'templates/register.html',
        }
      }
    })
  ;
  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/app/overview');
  $httpProvider.defaults.headers.post['Content-Type'] = 'text/plain;charset=UTF-8';
});
<commit_msg>debug<commit_after>// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.controllers' is found in controllers.js
angular.module('starter', ['ionic', 'starter.controllers','chart.js','ngCordova'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
      cordova.plugins.Keyboard.disableScroll(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleDefault();
    }
  });
})

.config(function($stateProvider, $urlRouterProvider,$httpProvider) {
  $stateProvider

    .state('app', {
    url: '/app',
    abstract: true,
    templateUrl: 'templates/side-menu-left.html'
    // controller: 'AppCtrl'
  })
  .state('app.overview', {
      url: "/overview",
      views: {
        'menuContent' :{
          templateUrl: "templates/overview.html"
        }
      }
    })
  .state('app.arm', {
      url: "/arm",
      views: {
        'menuContent' :{
          templateUrl: "templates/arm.html"
        }
      }
    })
  .state('app.camera', {
      url: "/camera",
      views: {
        'menuContent' :{
          templateUrl: "templates/camera.html"
        }
      }
    })
    .state('app.dashboard', {
      url: "/dashboard",
      views: {
        'menuContent' :{
          templateUrl: "templates/dashboard.html"
        }
      }
    })
  .state('app.addNode', {
      url: "/add-node",
      views: {
        'menuContent' :{
          templateUrl: "templates/add-node.html"
        }
      }
    })
  .state('app.dashboard.home', {
      url: "/home",
      views: {
        'home-tab' :{
          templateUrl: "templates/home.html"
        }
      }
    })
  .state('app.dashboard.favorites', {
      url: "/favorites",
      views: {
        'favorites-tab' :{
          templateUrl: "templates/favorites.html"
        }
      }
    })
  .state('app.dashboard.settings', {
      url: "/settings",
      views: {
        'settings-tab' :{
          templateUrl: "templates/settings.html"
        }
      }
    })

  .state('app.nodeType', {
      url: "/nodeType",
      views: {
        'menuContent' :{
          templateUrl: "templates/nodeType.html"
        }
      }
    })
	.state('app.node', {
      url: "/node",
      views: {
        'menuContent' :{
          templateUrl: "templates/node-single.html"
        }
      }
    })
  .state('app.usersetting', {
      url: "/usersetting",
      views: {
        'menuContent' :{
          templateUrl: "templates/usersetting.html"
        }
      }
    })
  .state('app.userinfo', {
      url: "/userinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/userinfo.html"
        }
      }
    })

  .state('app.subusers', {
      url: "/subusers",
      views: {
        'menuContent' :{
          templateUrl: "templates/subusers.html"
        }
      }
    })
  .state('app.subuserinfo', {
      url: "/subuserinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/subuserinfo.html"
        }
      }
    })
  .state('app.settings', {
      url: "/settings",
      views: {
        'menuContent' :{
          templateUrl: "templates/settings.html"
        }
      }
    })
  .state('app.devicemanage', {
      url: "/devicemanage",
      views: {
        'menuContent' :{
          templateUrl: "templates/devicemanage.html"
        }
      }
    })
  .state('app.deviceinfo', {
      url: "/deviceinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/deviceinfo.html"
        }
      }
    })
  .state('app.devicenetwork', {
      url: "/devicenetwork",
      views: {
        'menuContent' :{
          templateUrl: "templates/devicenetwork.html"
        }
      }
    })
  .state('app.notifies', {
      url: "/notifies",
      views: {
        'menuContent' :{
          templateUrl: "templates/notifies.html"
        }
      }
    })
  .state('app.alarm', {
      url: "/alarm",
      views: {
        'menuContent' :{
          templateUrl: "templates/alarm.html"
        }
      }
    })
  .state('app.purchaseinfo', {
      url: "/purchaseinfo",
      views: {
        'menuContent' :{
          templateUrl: "templates/purchaseinfo.html"
        }
      }
    })
  .state('app.battery', {
      url: '/battery',
      views: {
        'menuContent': {
          templateUrl: 'templates/battery.html'
        }
      }
    })
  .state('app.manustack', {
      url: '/manustack',
      views: {
        'menuContent': {
          templateUrl: 'templates/manustack.html'
        }
      }
    })
  .state('app.vib', {
    url: '/vib',
    views: {
        'menuContent': {
             templateUrl: 'templates/vib.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })

  .state('app.changepassword', {
    url: '/changepassword',
    views: {
        'menuContent': {
             templateUrl: 'templates/changepassword.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })

  .state('app.version', {
    url: '/version',
    views: {
        'menuContent': {
             templateUrl: 'templates/version.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })
  .state('app.help', {
    url: '/help',
    views: {
        'menuContent': {
             templateUrl: 'templates/help.html',
             //绑定controller
             //controller: 'VibrationCtrl'
        }
      }
    })
    .state('app.login', {
    url: '/login',
    views: {
        'menuContent': {
             templateUrl: 'templates/login.html',
        }
      }
    })
    .state('app.register', {
    url: '/register',
    views: {
        'menuContent': {
             templateUrl: 'templates/register.html',
        }
      }
    })
  ;
  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/app/overview');
  $httpProvider.defaults.headers.post['Content-Type'] = 'text/plain;charset=UTF-8';
});
<|endoftext|>


<commit_before>/**
 * $Id$
 */
Ext.namespace('Gemma');

/**
 * need to set geneId as config
 */
Gemma.GeneDetails =  Ext.extend(Ext.Panel, {

	padding:10,
	defaults:{
		border:false,
		flex:0
	},
	layoutConfig:{
		align:'stretch'
	},
	layout:'vbox',
	renderHomologues: function(homologues, mainGeneSymbol){
		var homologueStr = '';
		var j, homologue;
		for (j = 0; j < homologues.length; j++) {
			homologue = homologues[j];
				homologueStr += "" +
				homologue.officialSymbol +
				" [" +
				homologue.taxonCommonName +
				"]   ";
		}
		if(homologueStr === ''){
			homologueStr = "No homologues defined";
		}
		return homologueStr;
	},

	renderGeneSets:function(geneSets){
		var geneSetLinks = [];
		for (var i = 0; i < geneSets.length; i++) {
			if (geneSets[i] && geneSets[i].name && geneSets[i].id) {
				geneSetLinks.push('' + geneSets[i].name + '');
			}
		}
		if(geneSetLinks.length === 0){
			geneSetLinks.push('Not currently a member of any gene group');
		}
		return geneSetLinks;
	},

	/**
	 *
	 * @param geneDetails
	 * @returns {String}
	 */
	renderMultifunctionality : function(geneDetails) {
		if (geneDetails.multifunctionalityRank) {
			return geneDetails.numGoTerms + " GO Terms; Overall multifunctionality " + geneDetails.multifunctionalityRank.toFixed(2);
		} else {
			return "[ Not available ]";
		}
	},

	/**
	 *
	 * @param geneDetails
	 * @returns {String}
	 */
	renderPhenotypes : function(geneDetails) {
		if (geneDetails.phenotypes && geneDetails.phenotypes.length > 0) {
			var i = 0;
			var text = '';
			var limit = Math.min(3,geneDetails.phenotypes.length);
			for(i = 0; i < limit ; i++){
				text += ''+geneDetails.phenotypes[i].value+'';
				if( (i+1) !== limit){
					text += ', ';
				}
			}
			if(limit < geneDetails.phenotypes.length){
				text += ', '+ (geneDetails.phenotypes.length-limit) +' more';
			}
			text += "";
			return text;
		} else {
			return "[ None ]";
		}
	},

	changeTab:function( tabName ){
		this.fireEvent('changeTab', tabName);
	},
	/**
	 *
	 * @param ncbiId
	 * @param count
	 * @returns {String}
	 */
	renderAssociatedExperiments : function(ncbiId, count) {
		return ''+count+'';
	},

	renderNodeDegree : function(geneDetails) {
		if (geneDetails.nodeDegreeRank) {
			return geneDetails.nodeDegreeRank.toFixed(2);
		} else {
			return "[ Not available ]";
		}
	},
	initComponent: function(){
		Gemma.GeneDetails.superclass.initComponent.call(this);

		this.on('render', function(){
			if (!this.loadMask && this.getEl()) {
				this.loadMask = new Ext.LoadMask(this.getEl(), {
					msg: Gemma.StatusText.Loading.generic,
					msgCls: 'absolute-position-loading-mask ext-el-mask-msg x-mask-loading'
				});
			}
			this.loadMask.show();

			GeneController.loadGeneDetails(this.geneId, function(geneDetails){

			this.loadMask.hide();
				this.add([
				{
						html: '
' + geneDetails.name + '
' +
						geneDetails.officialName +
						'

'
					}, {
						layout: 'form',
						defaults: {
							border: false
						},
						items: [{
							fieldLabel: 'Taxon',
							html: geneDetails.taxonCommonName
						}, {
							fieldLabel: 'Aliases',
							html: geneDetails.aliases.join(', ')
						}, {
							fieldLabel: 'NCBI ID',
							html: geneDetails.ncbiId + ' '
						}, {
							fieldLabel: 'Homologues',
							html: this.renderHomologues(geneDetails.homologues, geneDetails.name)
						}, {
							fieldLabel: 'Gene Groups',
							html: this.renderGeneSets(geneDetails.geneSets).join(', ')
						}, {
							fieldLabel: 'Studies' + ' ' +
							' ',
							html: this.renderAssociatedExperiments( geneDetails.ncbiId, geneDetails.associatedExperimentCount )
						}, {
							fieldLabel: 'Multifunc.' + ' ' +
							' ',
							html: this.renderMultifunctionality( geneDetails )
						}, {
							fieldLabel: 'Hub score' + ' ' +
							' ',
							html: this.renderNodeDegree( geneDetails )
						}, {
							fieldLabel: 'Phenotypes' + ' ' +
							' ',
							html: this.renderPhenotypes( geneDetails )
						}, {
							fieldLabel: 'Probes' + ' ' +
								' ',
							html: geneDetails.compositeSequenceCount +
								' ' +
								' '
						}, {
							fieldLabel: 'Notes',
							html: geneDetails.description
						}]
					}]);
				this.doLayout();
			}.createDelegate(this));
		});
	}
});<commit_msg>gene details tab content was cut off in Win FF<commit_after>/**
 * $Id$
 */
Ext.namespace('Gemma');

/**
 * need to set geneId as config
 */
Gemma.GeneDetails =  Ext.extend(Ext.Panel, {

	padding:10,
	defaults:{
		border:false,
		flex:0
	},
	layoutConfig:{
		align:'stretch'
	},
	layout:'vbox',
	renderHomologues: function(homologues, mainGeneSymbol){
		var homologueStr = '';
		var j, homologue;
		for (j = 0; j < homologues.length; j++) {
			homologue = homologues[j];
				homologueStr += "" +
				homologue.officialSymbol +
				" [" +
				homologue.taxonCommonName +
				"]   ";
		}
		if(homologueStr === ''){
			homologueStr = "No homologues defined";
		}
		return homologueStr;
	},

	renderGeneSets:function(geneSets){
		var geneSetLinks = [];
		for (var i = 0; i < geneSets.length; i++) {
			if (geneSets[i] && geneSets[i].name && geneSets[i].id) {
				geneSetLinks.push('' + geneSets[i].name + '');
			}
		}
		if(geneSetLinks.length === 0){
			geneSetLinks.push('Not currently a member of any gene group');
		}
		return geneSetLinks;
	},

	/**
	 *
	 * @param geneDetails
	 * @returns {String}
	 */
	renderMultifunctionality : function(geneDetails) {
		if (geneDetails.multifunctionalityRank) {
			return geneDetails.numGoTerms + " GO Terms; Overall multifunctionality " + geneDetails.multifunctionalityRank.toFixed(2);
		} else {
			return "[ Not available ]";
		}
	},

	/**
	 *
	 * @param geneDetails
	 * @returns {String}
	 */
	renderPhenotypes : function(geneDetails) {
		if (geneDetails.phenotypes && geneDetails.phenotypes.length > 0) {
			var i = 0;
			var text = '';
			var limit = Math.min(3,geneDetails.phenotypes.length);
			for(i = 0; i < limit ; i++){
				text += ''+geneDetails.phenotypes[i].value+'';
				if( (i+1) !== limit){
					text += ', ';
				}
			}
			if(limit < geneDetails.phenotypes.length){
				text += ', '+ (geneDetails.phenotypes.length-limit) +' more';
			}
			text += "";
			return text;
		} else {
			return "[ None ]";
		}
	},

	changeTab:function( tabName ){
		this.fireEvent('changeTab', tabName);
	},
	/**
	 *
	 * @param ncbiId
	 * @param count
	 * @returns {String}
	 */
	renderAssociatedExperiments : function(ncbiId, count) {
		return ''+count+'';
	},

	renderNodeDegree : function(geneDetails) {
		if (geneDetails.nodeDegreeRank) {
			return geneDetails.nodeDegreeRank.toFixed(2);
		} else {
			return "[ Not available ]";
		}
	},
	initComponent: function(){
		Gemma.GeneDetails.superclass.initComponent.call(this);

		// need to do this on render so we can show a load mask
		this.on('afterrender', function(){
			if (!this.loadMask && this.getEl()) {
				this.loadMask = new Ext.LoadMask(this.getEl(), {
					msg: Gemma.StatusText.Loading.generic,
					msgCls: 'absolute-position-loading-mask ext-el-mask-msg x-mask-loading'
				});
			}
			this.loadMask.show();

			GeneController.loadGeneDetails(this.geneId, function(geneDetails){

				this.loadMask.hide();
				this.add([
				{
						html: '
' + geneDetails.name + '
' +
						geneDetails.officialName +
						'

'
					}, {
						layout: 'form',
						defaults: {
							border: false
						},
						items: [{
							fieldLabel: 'Taxon',
							html: geneDetails.taxonCommonName
						}, {
							fieldLabel: 'Aliases',
							html: geneDetails.aliases.join(', ')
						}, {
							fieldLabel: 'NCBI ID',
							html: geneDetails.ncbiId + ' '
						}, {
							fieldLabel: 'Homologues',
							html: this.renderHomologues(geneDetails.homologues, geneDetails.name)
						}, {
							fieldLabel: 'Gene Groups',
							html: this.renderGeneSets(geneDetails.geneSets).join(', ')
						}, {
							fieldLabel: 'Studies' + ' ' +
							' ',
							html: this.renderAssociatedExperiments( geneDetails.ncbiId, geneDetails.associatedExperimentCount )
						}, {
							fieldLabel: 'Multifunc.' + ' ' +
							' ',
							html: this.renderMultifunctionality( geneDetails )
						}, {
							fieldLabel: 'Hub score' + ' ' +
							' ',
							html: this.renderNodeDegree( geneDetails )
						}, {
							fieldLabel: 'Phenotypes' + ' ' +
							' ',
							html: this.renderPhenotypes( geneDetails )
						}, {
							fieldLabel: 'Probes' + ' ' +
								' ',
							html: geneDetails.compositeSequenceCount +
								' ' +
								' '
						}, {
							fieldLabel: 'Notes',
							html: geneDetails.description
						}]
					}]);
				this.syncSize();
			}.createDelegate(this));
		});
	}
});<|endoftext|>


<commit_before>'use strict';

var CustomError    = require('es5-ext/lib/Error/custom')
  , d              = require('es5-ext/lib/Object/descriptor')
  , extend         = require('es5-ext/lib/Object/extend')
  , forEach        = require('es5-ext/lib/Object/for-each')
  , startsWith     = require('es5-ext/lib/String/prototype/starts-with')
  , makeElement    = require('dom-ext/lib/Document/prototype/make-element')
  , castAttribute  = require('dom-ext/lib/Element/prototype/cast-attribute')
  , replaceContent = require('dom-ext/lib/Element/prototype/replace-content')
  , getId          = require('dom-ext/lib/HTMLElement/prototype/get-id')
  , SetCollection  = require('set-collection')
  , dbProto        = require('dbjs/lib/_proto')
  , Db             = require('../')
  , DOMComposite   = require('../_composite')
  , htmlAttributes = require('../_html-attributes')

  , map = Array.prototype.map
  , getRel = function (name) { return this.get(name); }
  , Base = Db.Base
  , Fieldset, renderRow, renderRowSpan;

renderRow = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('th', el('label', { for: id }, options.label, options.label ? ':' : '')),
		// input
		el('td', input,
			// required mark
			el('span', { class: 'required-status' }, '*'),
			// validation status mark
			el('span', { class: 'validation-status' }, '✓'),
			// error message
			el('span', { class: 'error-message error-message-' +
				input._name.replace(/[:#]/g, '-') }),
			// hint
			options.hint && el('p', { 'class': 'hint' }, options.hint)));
};

renderRowSpan = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('td', { colspan: 2 },
			el('p', el('label', { for: id }, options.label ? ':' : '')),
			// input
			el('div', input,
				// required mark
				el('span', { class: 'required-status' }, '*'),
				// validation status mark
				el('span', { class: 'validation-status' }, '✓'),
				// error message
				el('span', { class: 'error-message error-message-' +
					input._name.replace(/[:#]/g, '-') }),
				// hint
				options.hint && el('p', { 'class': 'hint' }, options.hint))));
};

module.exports = Fieldset = function (document, list/*, options*/) {
	var options = Object(arguments[2]);

	this.document = document;
	this.list = list;
	this.items = {};
	this.options = Object(options.control);
	this.customOptions = Object(options.controls);
	this.prepend = options.prepend;
	this.append = options.append;

	if (list.liveMap) {
		this.list = list.liveMap(this.renderItem, this);
		this.list.on('change', this.reload);
	} else {
		this.list = list.map(this.renderItem, this);
	}

	this.render();
	forEach(options, function (value, name) {
		if (!htmlAttributes[name] && !startsWith.call(name, 'data-')) return;
		castAttribute.call(this.dom, name, value);
	}, this);
	this.dom.classList.add('dbjs');

	this.reload();
};
Object.defineProperty(Fieldset, 'renderRow', d(renderRow));

Object.defineProperties(Fieldset.prototype, extend({
	render: d(function () {
		var el = makeElement.bind(this.document);
		this.dom = el('fieldset', el('table',
			this.domItems = el('tbody')));
	}),
	renderItem: d(function (rel) {
		var options = this.getOptions(rel);
		if (options.render == null) options.render = renderRow;
		else if (options.render === 'span') options.render = renderRowSpan;
		return (this.items[rel._id_] =
			rel.toDOMInputComponent(this.document, options));
	}),
	toDOM: d(function () { return this.dom; }),
	getOptions: d(DOMComposite.prototype.getOptions)
}, d.binder({
	reload: d(function () {
		replaceContent.call(this.domItems, this.prepend, this.list, this.append);
	})
})));

Object.defineProperty(Base, 'DOMFieldset', d(Fieldset));

Object.defineProperty(dbProto, 'toDOMFieldset',
	d(function (document/*, options*/) {
		var options = Object(arguments[1]), data, list, include, controlOpts
		  , setup, byOrder;

		if (options.names != null) {
			data = options.names._isSet_ ? options.names.values : options.names;
			data = new SetCollection(map.call(data, getRel, this));
		} else {
			data = this.getProperties(options.tag);
		}

		if (options.include) {
			if (options.include._type_ === 'relation') {
				include = new SetCollection();
				include.add(options.include);
			} else if (!options.include._isSet_) {
				include = new SetCollection(options.include);
			} else {
				include = options.include;
			}
			include.forEach(function (rel) {
				if (!rel || (rel._type_ !== 'relation')) {
					throw new CustomError("Include item must be a relation",
						'INVALID_RELATION');
				}
			});
			data = data.union(include);
		}

		controlOpts = Object(options.controls);

		byOrder = function (a, b) {
			var aOpts = controlOpts[a._id_] || controlOpts[a.name]
			  , bOpts = controlOpts[b._id_] || controlOpts[b.name];
			a = (aOpts && !isNaN(aOpts.order)) ? aOpts.order : a.order;
			b = (bOpts && !isNaN(bOpts.order)) ? bOpts.order : b.order;
			return a - b;
		};

		if (data.list) {
			list = data.list(byOrder);
			list.forEach(setup = function (rel) {
				var opts = controlOpts[rel._id_] || controlOpts[rel.name];
				if (opts && !isNaN(opts.order)) return;
				rel._order.on('change', list._sort);
			});
			data.on('add', function (rel) {
				setup(rel);
				list._sort();
			});
			data.on('delete', function (rel) {
				var opts = controlOpts[rel._id_] || controlOpts[rel.name];
				if (opts && !isNaN(opts.order)) return;
				rel._order.off('change', list._sort);
			});
		} else {
			list = data.values.sort(byOrder);
		}

		return new Base.DOMFieldset(document, list, options);
	}));
<commit_msg>Optional DOM for required and validation statuses<commit_after>'use strict';

var CustomError    = require('es5-ext/lib/Error/custom')
  , d              = require('es5-ext/lib/Object/descriptor')
  , extend         = require('es5-ext/lib/Object/extend')
  , forEach        = require('es5-ext/lib/Object/for-each')
  , startsWith     = require('es5-ext/lib/String/prototype/starts-with')
  , makeElement    = require('dom-ext/lib/Document/prototype/make-element')
  , castAttribute  = require('dom-ext/lib/Element/prototype/cast-attribute')
  , replaceContent = require('dom-ext/lib/Element/prototype/replace-content')
  , getId          = require('dom-ext/lib/HTMLElement/prototype/get-id')
  , SetCollection  = require('set-collection')
  , dbProto        = require('dbjs/lib/_proto')
  , Db             = require('../')
  , DOMComposite   = require('../_composite')
  , htmlAttributes = require('../_html-attributes')

  , map = Array.prototype.map
  , getRel = function (name) { return this.get(name); }
  , Base = Db.Base
  , Fieldset, renderRow, renderRowSpan;

renderRow = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('th', el('label', { for: id }, options.label, options.label ? ':' : '')),
		// input
		el('td', input,
			// required mark
			(options.requiredStatus !== false) ?
					el('span', { class: 'required-status' }, '*') : null,
			// validation status mark
			(options.validationStatus !== false) ?
					el('span', { class: 'validation-status' }, '✓') : null,
			// error message
			el('span', { class: 'error-message error-message-' +
				input._name.replace(/[:#]/g, '-') }),
			// hint
			options.hint && el('p', { 'class': 'hint' }, options.hint)));
};

renderRowSpan = function (input, options) {
	var el = makeElement.bind(input.document)
	  , id = getId.call(input.control || input.dom);
	return el('tr',
		// label
		el('td', { colspan: 2 },
			el('p', el('label', { for: id }, options.label ? ':' : '')),
			// input
			el('div', input,
				// required mark
				el('span', { class: 'required-status' }, '*'),
				// validation status mark
				el('span', { class: 'validation-status' }, '✓'),
				// error message
				el('span', { class: 'error-message error-message-' +
					input._name.replace(/[:#]/g, '-') }),
				// hint
				options.hint && el('p', { 'class': 'hint' }, options.hint))));
};

module.exports = Fieldset = function (document, list/*, options*/) {
	var options = Object(arguments[2]);

	this.document = document;
	this.list = list;
	this.items = {};
	this.options = Object(options.control);
	this.customOptions = Object(options.controls);
	this.prepend = options.prepend;
	this.append = options.append;

	if (list.liveMap) {
		this.list = list.liveMap(this.renderItem, this);
		this.list.on('change', this.reload);
	} else {
		this.list = list.map(this.renderItem, this);
	}

	this.render();
	forEach(options, function (value, name) {
		if (!htmlAttributes[name] && !startsWith.call(name, 'data-')) return;
		castAttribute.call(this.dom, name, value);
	}, this);
	this.dom.classList.add('dbjs');

	this.reload();
};
Object.defineProperty(Fieldset, 'renderRow', d(renderRow));

Object.defineProperties(Fieldset.prototype, extend({
	render: d(function () {
		var el = makeElement.bind(this.document);
		this.dom = el('fieldset', el('table',
			this.domItems = el('tbody')));
	}),
	renderItem: d(function (rel) {
		var options = this.getOptions(rel);
		if (options.render == null) options.render = renderRow;
		else if (options.render === 'span') options.render = renderRowSpan;
		return (this.items[rel._id_] =
			rel.toDOMInputComponent(this.document, options));
	}),
	toDOM: d(function () { return this.dom; }),
	getOptions: d(DOMComposite.prototype.getOptions)
}, d.binder({
	reload: d(function () {
		replaceContent.call(this.domItems, this.prepend, this.list, this.append);
	})
})));

Object.defineProperty(Base, 'DOMFieldset', d(Fieldset));

Object.defineProperty(dbProto, 'toDOMFieldset',
	d(function (document/*, options*/) {
		var options = Object(arguments[1]), data, list, include, controlOpts
		  , setup, byOrder;

		if (options.names != null) {
			data = options.names._isSet_ ? options.names.values : options.names;
			data = new SetCollection(map.call(data, getRel, this));
		} else {
			data = this.getProperties(options.tag);
		}

		if (options.include) {
			if (options.include._type_ === 'relation') {
				include = new SetCollection();
				include.add(options.include);
			} else if (!options.include._isSet_) {
				include = new SetCollection(options.include);
			} else {
				include = options.include;
			}
			include.forEach(function (rel) {
				if (!rel || (rel._type_ !== 'relation')) {
					throw new CustomError("Include item must be a relation",
						'INVALID_RELATION');
				}
			});
			data = data.union(include);
		}

		controlOpts = Object(options.controls);

		byOrder = function (a, b) {
			var aOpts = controlOpts[a._id_] || controlOpts[a.name]
			  , bOpts = controlOpts[b._id_] || controlOpts[b.name];
			a = (aOpts && !isNaN(aOpts.order)) ? aOpts.order : a.order;
			b = (bOpts && !isNaN(bOpts.order)) ? bOpts.order : b.order;
			return a - b;
		};

		if (data.list) {
			list = data.list(byOrder);
			list.forEach(setup = function (rel) {
				var opts = controlOpts[rel._id_] || controlOpts[rel.name];
				if (opts && !isNaN(opts.order)) return;
				rel._order.on('change', list._sort);
			});
			data.on('add', function (rel) {
				setup(rel);
				list._sort();
			});
			data.on('delete', function (rel) {
				var opts = controlOpts[rel._id_] || controlOpts[rel.name];
				if (opts && !isNaN(opts.order)) return;
				rel._order.off('change', list._sort);
			});
		} else {
			list = data.values.sort(byOrder);
		}

		return new Base.DOMFieldset(document, list, options);
	}));
<|endoftext|>