<commit_before>import 'babel-polyfill';
import Nightmare from 'nightmare';
import {expect} from 'chai';

const baseurl = process.env.TARGET_URL || "http://localhost:8080";

const option = {
  show: true,
  waitTimeout: 10000,
};

const shortWait = 100;
const mediumWait = 2000;
const longWait = 5000;

describe('e2etest', () => {
  let nightmare;

  before(async () => {
    nightmare = new Nightmare(option);
    await nightmare
    .goto(`${baseurl}/initialize`)
    ;
  });
  after(async () => {
    await nightmare.end();
  });
  beforeEach(async () => {
    await nightmare
    .goto(`${baseurl}/logout`)
    await nightmare.wait(shortWait)
    ;
  });

  it('トップページが継ぎ足しできる', async () => {
    await nightmare
    .goto(`${baseurl}/`)
    .wait(shortWait)
    .scrollTo(100000, 0) // 一番下まで
    .wait(shortWait)
    .click('#isu-post-more-btn')
    .wait(longWait)
    ;

    const postLen1 = await nightmare.evaluate(() => {
      return document.querySelectorAll('.isu-post').length;
    });
    expect(39).to.equal(postLen1);

    await nightmare
    .scrollTo(100000, 0) // 一番下まで
    .wait(shortWait)
    .click('#isu-post-more-btn')
    .wait(longWait)
    ;

    const postLen2 = await nightmare.evaluate(() => {
      return document.querySelectorAll('.isu-post').length;
    });
    expect(58).to.equal(postLen2);
  });

  it('画像を投稿できる', async () => {
    await nightmare
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'mary')
    .type('input[name=password]', 'marymary')
    .click('input[type=submit]')
    .wait(longWait)
    .type('textarea[name=body]', 'あいうえお かきくけこ さしすせそ')
    .wait(shortWait)
    ;

    const urlAfterPost = await nightmare.evaluate(() => {
      const form = document.querySelector('.isu-submit form');
      const formData = new FormData(form);
      // 10x10の赤い正方形のgif
      const b64 = 'R0lGODdhBQAFAPAAAP8AAAAAACwAAAAABQAFAAACBISPqVgAOw==';

      // data URIをblobに変える方法: http://stackoverflow.com/a/11954337
      const binary = atob(b64);
      const array = [];
      for (let i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
      }
      const blob = new Blob([new Uint8Array(array)], {type: 'image/gif'});

      // formDataにblobを指定してXHRで送信することでファイルアップロードできる
      formData.append('file', blob, 'square.gif');
      //formData.append('body', 'あいうえお かきくけこ さしすせそ');

      // FormDataはXHRで送信するしかないので、送信後にリダイレクト先URLにlocation.hrefで遷移する
      const xhr = new XMLHttpRequest();
      xhr.open("POST", form.getAttribute('action'));
      xhr.onload = function() {
        location.href = xhr.responseURL;
      };
      xhr.send(formData);
    })
    .wait(mediumWait)
    .url()
    ;

    // 単体ページにリダイレクトされる
    expect(urlAfterPost).to.match(/\/posts\/(\d+)/);

    const id = RegExp.$1;

    // トップページにも反映される
    const postExists = await nightmare
    .goto(`${baseurl}/`)
    .wait(longWait)
    .exists('#pid_' + id)
    ;

    expect(postExists).to.be.true;
  });

  it('コメントできる', async () => {
    await nightmare
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'mary')
    .type('input[name=password]', 'marymary')
    .click('input[type=submit]')
    .wait(longWait)
    ;

    const [id, commentCount] = await nightmare.evaluate(() => {
      return [document.querySelector('.isu-post').id, document.querySelector('.isu-post-comment-count b').textContent];
    });

    const urlAfterComment = await nightmare
    .scrollTo(300, 0) // コメント欄が見えるまで
    .type('.isu-comment-form input[name=comment]', 'あいうえお かきくけこ')
    .click('.isu-comment-form input[type=submit]')
    .wait(mediumWait)
    .url()
    ;
    expect(urlAfterComment).to.equal(`${baseurl}/posts/${id}`);

    const commentCount2 = await nightmare.evaluate(() => {
      return document.querySelector('.isu-post-comment-count b').textContent;
    });
    expect(commentCount2).to.equal(+commentCount + 1 + '');
  });

  it('banできる', async () => {
    await nightmare
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'mary') // adminユーザー
    .type('input[name=password]', 'marymary')
    .click('input[type=submit]')
    .wait(shortWait)
    .goto(`${baseurl}/admin/banned`)
    .wait(shortWait)
    ;

    const name = await nightmare.evaluate(() => {
      return document.querySelector('input[name="uid[]"]').getAttribute('data-account-name');
    });

    const titleBeforeBan = await nightmare
    .goto(`${baseurl}/@${name}`)
    .title()
    ;
    expect(titleBeforeBan).to.equal('Iscogram'); // banされる前は普通に見れてる

    await nightmare
    .goto(`${baseurl}/admin/banned`)
    .wait(shortWait)
    .check('input[name="uid[]"]')
    .scrollTo(100000, 0) // 一番下まで
    .wait(shortWait)
    .click('input[type="submit"]')
    .wait(shortWait)
    ;

    const titleAfterBan = await nightmare
    .goto(`${baseurl}/@${name}`)
    .title()
    ;
    expect(titleAfterBan).to.equal('') // ステータスコードをチェックする方法が無いのでとりあえず
  });

  it('新規登録、ログアウト、ログインできる', async () => {
    const urlAfterLogin = await nightmare
    .goto(`${baseurl}/register`)
    .wait(mediumWait)
    .type('input[name=account_name]', 'catatsuy')
    .type('input[name=password]', 'catatsuy')
    .click('input[type=submit]')
    .wait(longWait)
    .goto(`${baseurl}/logout`)
    .wait(shortWait)
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'catatsuy')
    .type('input[name=password]', 'catatsuy')
    .click('input[type=submit]')
    .wait(longWait)
    .url()
    ;
    expect(urlAfterLogin).to.equal(`${baseurl}/`);

    const name = await nightmare.evaluate(() => {
      return document.querySelector('.isu-account-name a').textContent;
    });
    expect('catatsuyさん').to.equal(name);
  });
});
<commit_msg>不要なコードが残ってた<commit_after>import 'babel-polyfill';
import Nightmare from 'nightmare';
import {expect} from 'chai';

const baseurl = process.env.TARGET_URL || "http://localhost:8080";

const option = {
  show: true,
  waitTimeout: 10000,
};

const shortWait = 100;
const mediumWait = 2000;
const longWait = 5000;

describe('e2etest', () => {
  let nightmare;

  before(async () => {
    nightmare = new Nightmare(option);
    await nightmare
    .goto(`${baseurl}/initialize`)
    ;
  });
  after(async () => {
    await nightmare.end();
  });
  beforeEach(async () => {
    await nightmare
    .goto(`${baseurl}/logout`)
    await nightmare.wait(shortWait)
    ;
  });

  it('トップページが継ぎ足しできる', async () => {
    await nightmare
    .goto(`${baseurl}/`)
    .wait(shortWait)
    .scrollTo(100000, 0) // 一番下まで
    .wait(shortWait)
    .click('#isu-post-more-btn')
    .wait(longWait)
    ;

    const postLen1 = await nightmare.evaluate(() => {
      return document.querySelectorAll('.isu-post').length;
    });
    expect(39).to.equal(postLen1);

    await nightmare
    .scrollTo(100000, 0) // 一番下まで
    .wait(shortWait)
    .click('#isu-post-more-btn')
    .wait(longWait)
    ;

    const postLen2 = await nightmare.evaluate(() => {
      return document.querySelectorAll('.isu-post').length;
    });
    expect(58).to.equal(postLen2);
  });

  it('画像を投稿できる', async () => {
    await nightmare
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'mary')
    .type('input[name=password]', 'marymary')
    .click('input[type=submit]')
    .wait(longWait)
    .type('textarea[name=body]', 'あいうえお かきくけこ さしすせそ')
    .wait(shortWait)
    ;

    const urlAfterPost = await nightmare.evaluate(() => {
      const form = document.querySelector('.isu-submit form');
      const formData = new FormData(form);
      // 10x10の赤い正方形のgif
      const b64 = 'R0lGODdhBQAFAPAAAP8AAAAAACwAAAAABQAFAAACBISPqVgAOw==';

      // data URIをblobに変える方法: http://stackoverflow.com/a/11954337
      const binary = atob(b64);
      const array = [];
      for (let i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
      }
      const blob = new Blob([new Uint8Array(array)], {type: 'image/gif'});

      // formDataにblobを指定してXHRで送信することでファイルアップロードできる
      formData.append('file', blob, 'square.gif');

      // FormDataはXHRで送信するしかないので、送信後にリダイレクト先URLにlocation.hrefで遷移する
      const xhr = new XMLHttpRequest();
      xhr.open("POST", form.getAttribute('action'));
      xhr.onload = function() {
        location.href = xhr.responseURL;
      };
      xhr.send(formData);
    })
    .wait(mediumWait)
    .url()
    ;

    // 単体ページにリダイレクトされる
    expect(urlAfterPost).to.match(/\/posts\/(\d+)/);

    const id = RegExp.$1;

    // トップページにも反映される
    const postExists = await nightmare
    .goto(`${baseurl}/`)
    .wait(longWait)
    .exists('#pid_' + id)
    ;

    expect(postExists).to.be.true;
  });

  it('コメントできる', async () => {
    await nightmare
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'mary')
    .type('input[name=password]', 'marymary')
    .click('input[type=submit]')
    .wait(longWait)
    ;

    const [id, commentCount] = await nightmare.evaluate(() => {
      return [document.querySelector('.isu-post').id, document.querySelector('.isu-post-comment-count b').textContent];
    });

    const urlAfterComment = await nightmare
    .scrollTo(300, 0) // コメント欄が見えるまで
    .type('.isu-comment-form input[name=comment]', 'あいうえお かきくけこ')
    .click('.isu-comment-form input[type=submit]')
    .wait(mediumWait)
    .url()
    ;
    expect(urlAfterComment).to.equal(`${baseurl}/posts/${id}`);

    const commentCount2 = await nightmare.evaluate(() => {
      return document.querySelector('.isu-post-comment-count b').textContent;
    });
    expect(commentCount2).to.equal(+commentCount + 1 + '');
  });

  it('banできる', async () => {
    await nightmare
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'mary') // adminユーザー
    .type('input[name=password]', 'marymary')
    .click('input[type=submit]')
    .wait(shortWait)
    .goto(`${baseurl}/admin/banned`)
    .wait(shortWait)
    ;

    const name = await nightmare.evaluate(() => {
      return document.querySelector('input[name="uid[]"]').getAttribute('data-account-name');
    });

    const titleBeforeBan = await nightmare
    .goto(`${baseurl}/@${name}`)
    .title()
    ;
    expect(titleBeforeBan).to.equal('Iscogram'); // banされる前は普通に見れてる

    await nightmare
    .goto(`${baseurl}/admin/banned`)
    .wait(shortWait)
    .check('input[name="uid[]"]')
    .scrollTo(100000, 0) // 一番下まで
    .wait(shortWait)
    .click('input[type="submit"]')
    .wait(shortWait)
    ;

    const titleAfterBan = await nightmare
    .goto(`${baseurl}/@${name}`)
    .title()
    ;
    expect(titleAfterBan).to.equal('') // ステータスコードをチェックする方法が無いのでとりあえず
  });

  it('新規登録、ログアウト、ログインできる', async () => {
    const urlAfterLogin = await nightmare
    .goto(`${baseurl}/register`)
    .wait(mediumWait)
    .type('input[name=account_name]', 'catatsuy')
    .type('input[name=password]', 'catatsuy')
    .click('input[type=submit]')
    .wait(longWait)
    .goto(`${baseurl}/logout`)
    .wait(shortWait)
    .goto(`${baseurl}/login`)
    .type('input[name=account_name]', 'catatsuy')
    .type('input[name=password]', 'catatsuy')
    .click('input[type=submit]')
    .wait(longWait)
    .url()
    ;
    expect(urlAfterLogin).to.equal(`${baseurl}/`);

    const name = await nightmare.evaluate(() => {
      return document.querySelector('.isu-account-name a').textContent;
    });
    expect('catatsuyさん').to.equal(name);
  });
});
<|endoftext|>


<commit_before>/*
 * Developed by Radu Puspana
 * Date August 2017
 * Version 1.0
 */

// module that handles the budget data using the module pattern
// IFEE creates a new scope. IFEE creates a closure for the vars/functions/objects
var budgetController = (function() {

    // private Expense constructor
    var prvExpense = function(id, description, value) {
       this.id = id;
       this.description = description;
       this.value = value;
    };

    // private Income constructor
    var prvIncome = function(id, description, value) {
        this.id = id;
        this.description = description;
        this.value = value;
    };

})();

// UI module manipulates the UI of the app
var uiController = (function() {

    // private object containing the class names used in index.html and style.css
    var prvDOMstrings = {
        inputType: ".add__type",
        inputDescription: ".add__description",
        inputValue: ".add__value",
        inputButton: ".add__btn"};

    return {
        // public method to retrieve and return all three field values as strings from the UI
        pblGetInput: function() {

            // return an object with all three fields values as strings from the UI
            return {
                // return "inc" or "exp" from the transaction type list
                type: document.querySelector(prvDOMstrings.inputType).value,

                // return the transaction description as string
                description: document.querySelector(prvDOMstrings.inputDescription).value,

                // return the transaction value as a string
                value: document.querySelector(prvDOMstrings.inputValue).value
            };
        },

        // public method for returning the object containing the class names in the index.html and style.css
        pblGetDOMstrings: function() {
            return prvDOMstrings;
        }
    }

})();

// App controller for communicating between the budgetController and the UIconroller
var controller = (function(budgetCtrl, UIctrl) {

    // private function to place the event listeners and the HTML tags' classes
    var prvSetupEventListeners = function() {

        // object containing the class names in the index.html and style.css
        var DOMstrings = uiController.pblGetDOMstrings();

        // register click event for the button with the tick sign
        document.querySelector(DOMstrings.inputButton).addEventListener("click", prvCtrlAddItem, false);

        // register Enter keypress event for the global object. Used only for the ENTER key
        document.getElementById("enterSum").addEventListener("keypress", function(event) {

            // use event.which to assure comptatibility with IE 9..11, Edge 14, UC Browser for Android 11.4
            // code 13 is returned when the "ENTER" key is pressed
            if (event.key === "Enter" || event.which === 13) { prvCtrlAddItem(); }

        }, false);
    };

    // private function for :
    // - retrieving all three user input field values
    var prvCtrlAddItem = function() {

        // get the field input data(expense or income)
        var userInput = uiController.pblGetInput();
        console.log(userInput);

        // add the item to the budget controller
        // add the new item to the UI
        // update the budget taking into account the expense/budget just entered
        // display the newly calculated budget on the UI
        console.log("You pressed enter and an item will be added to one of the tables and the budget will be updated")
    };

    return {
        initialiseVarsAndEvents: function() {
            console.log("App has started.");
            prvSetupEventListeners();
        }
    }

})(budgetController, uiController);

// Global execution scope
controller.initialiseVarsAndEvents();
<commit_msg>Modify comment of budgetController, add prvData vartiable to store all the incomes,expenses entered by the user, total value of income, total value of expenses<commit_after>/*
 * Developed by Radu Puspana
 * Date August 2017
 * Version 1.0
 */

// module that handles the budget data using the module pattern
// this controller keeps track of all the income, expenses, the budget itself, and
// also the percentage of how much an income/expense represents of the total budget
var budgetController = (function() {

    // private Expense constructor
    var prvExpense = function(id, description, value) {
       this.id = id;
       this.description = description;
       this.value = value;
    };

    // private Income constructor
    var prvIncome = function(id, description, value) {
        this.id = id;
        this.description = description;
        this.value = value;
    };

    // object for storing instances of prvExpense, prvIncome, totalExpenses, totalIncomes
    // every expense entered in the UI will map to an instance of prvExpense
    // every income entered in the UI will map to an instance of prvIncome
    var prvData = {
        allItems: {
            expenses: [],
            incomes: []
        },
        totals: {
            totalExpenses: 0,
            totalIncomes: 0
        }
    };

})();

// UI module manipulates the UI of the app
var uiController = (function() {

    // private object containing the class names used in index.html and style.css
    var prvDOMstrings = {
        inputType: ".add__type",
        inputDescription: ".add__description",
        inputValue: ".add__value",
        inputButton: ".add__btn"};

    return {
        // public method to retrieve and return all three field values as strings from the UI
        pblGetInput: function() {

            // return an object with all three fields values as strings from the UI
            return {
                // return "inc" or "exp" from the transaction type list
                type: document.querySelector(prvDOMstrings.inputType).value,

                // return the transaction description as string
                description: document.querySelector(prvDOMstrings.inputDescription).value,

                // return the transaction value as a string
                value: document.querySelector(prvDOMstrings.inputValue).value
            };
        },

        // public method for returning the object containing the class names in the index.html and style.css
        pblGetDOMstrings: function() {
            return prvDOMstrings;
        }
    }

})();

// App controller for communicating between the budgetController and the UIconroller
var controller = (function(budgetCtrl, UIctrl) {

    // private function to place the event listeners and the HTML tags' classes
    var prvSetupEventListeners = function() {

        // object containing the class names in the index.html and style.css
        var DOMstrings = uiController.pblGetDOMstrings();

        // register click event for the button with the tick sign
        document.querySelector(DOMstrings.inputButton).addEventListener("click", prvCtrlAddItem, false);

        // register Enter keypress event for the global object. Used only for the ENTER key
        document.getElementById("enterSum").addEventListener("keypress", function(event) {

            // use event.which to assure comptatibility with IE 9..11, Edge 14, UC Browser for Android 11.4
            // code 13 is returned when the "ENTER" key is pressed
            if (event.key === "Enter" || event.which === 13) { prvCtrlAddItem(); }

        }, false);
    };

    // private function for :
    // - retrieving all three user input field values
    var prvCtrlAddItem = function() {

        // get the field input data(expense or income)
        var userInput = uiController.pblGetInput();
        console.log(userInput);

        // add the item to the budget controller
        // add the new item to the UI
        // update the budget taking into account the expense/budget just entered
        // display the newly calculated budget on the UI
        console.log("You pressed enter and an item will be added to one of the tables and the budget will be updated")
    };

    return {
        initialiseVarsAndEvents: function() {
            console.log("App has started.");
            prvSetupEventListeners();
        }
    }

})(budgetController, uiController);

// Global execution scope
controller.initialiseVarsAndEvents();
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var zdoHelper = {},
    zdoReqRspMap,
    zdoIndSuffix;

zdoReqRspMap = {
    nwkAddrReq:         { ind: 'nwkAddrRsp',        apiType: 'concat',  suffix: [ 'ieeeaddr', 'startindex' ]        },
    ieeeAddrReq:        { ind: 'ieeeAddrRsp',       apiType: 'concat',  suffix: [ 'shortaddr' ]                     }, // 'startindex' mismatch
    nodeDescReq:        { ind: 'nodeDescRsp',       apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    powerDescReq:       { ind: 'powerDescRsp',      apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    simpleDescReq:      { ind: 'simpleDescRsp',     apiType: 'generic', suffix: [ 'nwkaddrofinterest', 'endpoint' ] },
    activeEpReq:        { ind: 'activeEpRsp',       apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    matchDescReq:       { ind: 'matchDescRsp',      apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    complexDescReq:     { ind: 'complexDescRsp',    apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    userDescReq:        { ind: 'userDescRsp',       apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    userDescSet:        { ind: 'userDescConf',      apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    serverDiscReq:      { ind: 'serverDiscRsp',     apiType: 'special', suffix: []                                  },
    endDeviceBindReq:   { ind: 'endDeviceBindRsp',  apiType: 'generic', suffix: [ 'dstaddr' ]                       }, // address 16bit mode unsupported
    bindReq:            { ind: 'bindRsp',           apiType: 'special', suffix: [ 'dstaddr' ]                       },
    unbindReq:          { ind: 'unbindRsp',         apiType: 'generic', suffix: [ 'dstaddr' ]                       },
    nwkDiscoveryReq:    { ind: 'nwkDiscoveryCnf',   apiType: 'generic', suffix: []                                  },
    joinReq:            { ind: 'joinCnf',           apiType: 'generic', suffix: []                                  },
    mgmtNwkDiscReq:     { ind: 'mgmtNwkDiscRsp',    apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtLqiReq:         { ind: 'mgmtLqiRsp',        apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtRtgReq:         { ind: 'mgmtRtgRsp',        apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtBindReq:        { ind: 'mgmtBindRsp',       apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtLeaveReq:       { ind: 'mgmtLeaveRsp',      apiType: 'generic', suffix: [ 'dstaddr' ]                       },
    mgmtDirectJoinReq:  { ind: 'mgmtDirectJoinRsp', apiType: 'generic', suffix: [ 'dstaddr' ]                       },
    mgmtPermitJoinReq:  { ind: 'mgmtPermitJoinRsp', apiType: 'special', suffix: [ 'dstaddr' ]                       },
    mgmtNwkUpdateReq:   null,
    endDeviceAnnce:     null,
    msgCbRegister:      null,
    msgCbRemove:        null,
    startupFromApp:     null,
    setLinkKey:         null,
    removeLinkKey:      null,
    getLinkKey:         null,
    secAddLinkKey:      null,
    secEntryLookupExt:  null,
    extRouteDisc:       null,
    extRouteCheck:      null,
    extRemoveGroup:     null,
    extRemoveAllGroup:  null,
    extFindGroup:       null,
    extAddGroup:        null,
    extCountAllGroups:  null,
    extRxIdle:          null,
    extUpdateNwkKey:    null,
    extSwitchNwkKey:    null,
    extNwkInfo:         null,
    extSecApsRemoveReq: null,
    extFindAllGroupsEndpoint: null,
    forceConcentratorChange:  null,
    extSetParams:             null,
    endDeviceTimeoutReq:      null,
    sendData:                 null,
    nwkAddrOfInterestReq:     null
};

zdoIndSuffix = {
    nwkAddrRsp:        [ 'ieeeaddr', 'startindex' ],
    ieeeAddrRsp:       [ 'nwkaddr' ],  // 'startindex' mismatch
    nodeDescRsp:       [ 'nwkaddr' ],
    powerDescRsp:      [ 'nwkaddr' ],
    simpleDescRsp:     [ 'nwkaddr', 'endpoint' ],
    activeEpRsp:       [ 'nwkaddr' ],
    matchDescRsp:      [ 'nwkaddr' ],
    complexDescRsp:    [ 'nwkaddr' ],
    userDescRsp:       [ 'nwkaddr' ],
    userDescConf:      [ 'nwkaddr' ],
    serverDiscRsp:     null,    // special, listen at controller.on('ZDO:serverDiscRsp')
    endDeviceBindRsp:  [ 'srcaddr' ],
    bindRsp:           [ 'srcaddr' ],
    unbindRsp:         [ 'srcaddr' ],
    nwkDiscoveryCnf:   null,
    joinCnf:           null,
    mgmtNwkDiscRsp:    [ 'srcaddr', 'startindex' ],
    mgmtLqiRsp:        [ 'srcaddr', 'startindex' ],
    mgmtRtgRsp:        [ 'srcaddr', 'startindex' ],
    mgmtBindRsp:       [ 'srcaddr', 'startindex' ],
    mgmtLeaveRsp:      [ 'srcaddr' ],
    mgmtDirectJoinRsp: [ 'srcaddr' ],
    mgmtPermitJoinRsp: [ 'srcaddr' ],
    stateChangeInd:    null,    // very special, tackled in event_bridge._zdoIndicationEventBridge()
    endDeviceAnnceInd: null,
    matchDescRspSent:  null,
    statusErrorRsp:    null,
    srcRtgInd:         null,
    beacon_notify_ind: null,
    leaveInd:          null,
    msgCbIncoming:     null,
    tcDeviceInd:       null,
    permitJoinInd:     null,
    networkStatus:     ['dstaddr']
};

/*************************************************************************************************/
/*** Public APIs                                                                               ***/
/*************************************************************************************************/
zdoHelper.hasAreq = function (reqName) {
    var meta = zdoReqRspMap[reqName];
    return meta ? (!!meta.ind) : false;
};

zdoHelper.getRequestType = function (reqName) {
    var meta = zdoReqRspMap[reqName];
    return meta ? meta.apiType : 'rspless';
};

function generateEvent(indName, meta, valObj){
    if (!meta || (meta.length === 0))
        return;

    let evtName = 'ZDO:' + indName;

    for(const key of meta) {
        if(key === 'srcAddr' || key === 'nwkAddr' || key === 'nwkaddrofinterest' || key === 'dstaddr') evtName += ':' + valObj[key].toString(16)
        else evtName += ':' + valObj[key].toString()
    }

    return evtName
}

zdoHelper.generateEventOfRequest = function (reqName, valObj) {
    var meta = zdoReqRspMap[reqName]

    if (!zdoHelper.hasAreq(reqName))
        return;

    return generateEvent(meta.ind, meta.suffix, valObj)
};

zdoHelper.generateEventOfIndication = function (indName, msgData) {
    return generateEvent(indName, zdoIndSuffix[indName], msgData)
};

zdoHelper.generateDstAddrOfRequest = function(valObj){
    if(valObj.dstaddr) return valObj.dstaddr.toString(16)
    if(valObj.nwkaddrofinterest) return valObj.nwkaddrofinterest.toString(16)
};

module.exports = zdoHelper;
<commit_msg>fix capitalization<commit_after>/* jshint node: true */
'use strict';

var zdoHelper = {},
    zdoReqRspMap,
    zdoIndSuffix;

zdoReqRspMap = {
    nwkAddrReq:         { ind: 'nwkAddrRsp',        apiType: 'concat',  suffix: [ 'ieeeaddr', 'startindex' ]        },
    ieeeAddrReq:        { ind: 'ieeeAddrRsp',       apiType: 'concat',  suffix: [ 'shortaddr' ]                     }, // 'startindex' mismatch
    nodeDescReq:        { ind: 'nodeDescRsp',       apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    powerDescReq:       { ind: 'powerDescRsp',      apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    simpleDescReq:      { ind: 'simpleDescRsp',     apiType: 'generic', suffix: [ 'nwkaddrofinterest', 'endpoint' ] },
    activeEpReq:        { ind: 'activeEpRsp',       apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    matchDescReq:       { ind: 'matchDescRsp',      apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    complexDescReq:     { ind: 'complexDescRsp',    apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    userDescReq:        { ind: 'userDescRsp',       apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    userDescSet:        { ind: 'userDescConf',      apiType: 'generic', suffix: [ 'nwkaddrofinterest' ]             },
    serverDiscReq:      { ind: 'serverDiscRsp',     apiType: 'special', suffix: []                                  },
    endDeviceBindReq:   { ind: 'endDeviceBindRsp',  apiType: 'generic', suffix: [ 'dstaddr' ]                       }, // address 16bit mode unsupported
    bindReq:            { ind: 'bindRsp',           apiType: 'special', suffix: [ 'dstaddr' ]                       },
    unbindReq:          { ind: 'unbindRsp',         apiType: 'generic', suffix: [ 'dstaddr' ]                       },
    nwkDiscoveryReq:    { ind: 'nwkDiscoveryCnf',   apiType: 'generic', suffix: []                                  },
    joinReq:            { ind: 'joinCnf',           apiType: 'generic', suffix: []                                  },
    mgmtNwkDiscReq:     { ind: 'mgmtNwkDiscRsp',    apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtLqiReq:         { ind: 'mgmtLqiRsp',        apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtRtgReq:         { ind: 'mgmtRtgRsp',        apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtBindReq:        { ind: 'mgmtBindRsp',       apiType: 'concat',  suffix: [ 'dstaddr', 'startindex' ]         },
    mgmtLeaveReq:       { ind: 'mgmtLeaveRsp',      apiType: 'generic', suffix: [ 'dstaddr' ]                       },
    mgmtDirectJoinReq:  { ind: 'mgmtDirectJoinRsp', apiType: 'generic', suffix: [ 'dstaddr' ]                       },
    mgmtPermitJoinReq:  { ind: 'mgmtPermitJoinRsp', apiType: 'special', suffix: [ 'dstaddr' ]                       },
    mgmtNwkUpdateReq:   null,
    endDeviceAnnce:     null,
    msgCbRegister:      null,
    msgCbRemove:        null,
    startupFromApp:     null,
    setLinkKey:         null,
    removeLinkKey:      null,
    getLinkKey:         null,
    secAddLinkKey:      null,
    secEntryLookupExt:  null,
    extRouteDisc:       null,
    extRouteCheck:      null,
    extRemoveGroup:     null,
    extRemoveAllGroup:  null,
    extFindGroup:       null,
    extAddGroup:        null,
    extCountAllGroups:  null,
    extRxIdle:          null,
    extUpdateNwkKey:    null,
    extSwitchNwkKey:    null,
    extNwkInfo:         null,
    extSecApsRemoveReq: null,
    extFindAllGroupsEndpoint: null,
    forceConcentratorChange:  null,
    extSetParams:             null,
    endDeviceTimeoutReq:      null,
    sendData:                 null,
    nwkAddrOfInterestReq:     null
};

zdoIndSuffix = {
    nwkAddrRsp:        [ 'ieeeaddr', 'startindex' ],
    ieeeAddrRsp:       [ 'nwkaddr' ],  // 'startindex' mismatch
    nodeDescRsp:       [ 'nwkaddr' ],
    powerDescRsp:      [ 'nwkaddr' ],
    simpleDescRsp:     [ 'nwkaddr', 'endpoint' ],
    activeEpRsp:       [ 'nwkaddr' ],
    matchDescRsp:      [ 'nwkaddr' ],
    complexDescRsp:    [ 'nwkaddr' ],
    userDescRsp:       [ 'nwkaddr' ],
    userDescConf:      [ 'nwkaddr' ],
    serverDiscRsp:     null,    // special, listen at controller.on('ZDO:serverDiscRsp')
    endDeviceBindRsp:  [ 'srcaddr' ],
    bindRsp:           [ 'srcaddr' ],
    unbindRsp:         [ 'srcaddr' ],
    nwkDiscoveryCnf:   null,
    joinCnf:           null,
    mgmtNwkDiscRsp:    [ 'srcaddr', 'startindex' ],
    mgmtLqiRsp:        [ 'srcaddr', 'startindex' ],
    mgmtRtgRsp:        [ 'srcaddr', 'startindex' ],
    mgmtBindRsp:       [ 'srcaddr', 'startindex' ],
    mgmtLeaveRsp:      [ 'srcaddr' ],
    mgmtDirectJoinRsp: [ 'srcaddr' ],
    mgmtPermitJoinRsp: [ 'srcaddr' ],
    stateChangeInd:    null,    // very special, tackled in event_bridge._zdoIndicationEventBridge()
    endDeviceAnnceInd: null,
    matchDescRspSent:  null,
    statusErrorRsp:    null,
    srcRtgInd:         null,
    beacon_notify_ind: null,
    leaveInd:          null,
    msgCbIncoming:     null,
    tcDeviceInd:       null,
    permitJoinInd:     null,
    networkStatus:     ['dstaddr']
};

/*************************************************************************************************/
/*** Public APIs                                                                               ***/
/*************************************************************************************************/
zdoHelper.hasAreq = function (reqName) {
    var meta = zdoReqRspMap[reqName];
    return meta ? (!!meta.ind) : false;
};

zdoHelper.getRequestType = function (reqName) {
    var meta = zdoReqRspMap[reqName];
    return meta ? meta.apiType : 'rspless';
};

function generateEvent(indName, meta, valObj){
    if (!meta || (meta.length === 0))
        return;

    let evtName = 'ZDO:' + indName;

    for(const key of meta) {
        if(key === 'srcaddr' || key === 'nwkaddr' || key === 'nwkaddrofinterest' || key === 'dstaddr') evtName += ':' + valObj[key].toString(16)
        else evtName += ':' + valObj[key].toString()
    }

    return evtName
}

zdoHelper.generateEventOfRequest = function (reqName, valObj) {
    var meta = zdoReqRspMap[reqName]

    if (!zdoHelper.hasAreq(reqName))
        return;

    return generateEvent(meta.ind, meta.suffix, valObj)
};

zdoHelper.generateEventOfIndication = function (indName, msgData) {
    return generateEvent(indName, zdoIndSuffix[indName], msgData)
};

zdoHelper.generateDstAddrOfRequest = function(valObj){
    if(valObj.dstaddr) return valObj.dstaddr.toString(16)
    if(valObj.nwkaddrofinterest) return valObj.nwkaddrofinterest.toString(16)
};

module.exports = zdoHelper;
<|endoftext|>


<commit_before>/*
 * Cookie Calculator : test / units.js
 * copyright (c) 2016 Susisu
 */

"use strict";

let chai   = require("chai"),
    expect = chai.expect;

let units = require("../src/units.js");

describe("Dimension", () => {
    let Dimension = units.Dimension;

    describe(".toString(dim)", () => {
        it("should return \"1\" when dim is non dimensional", () => {
            expect(Dimension.toString({})).to.equal("1");
            expect(Dimension.toString({ [Dimension.AMOUNT]: 0 })).to.equal("1");
            expect(Dimension.toString({
                [Dimension.AMOUNT]     : 0,
                [Dimension.MASS]       : 0,
                [Dimension.LENGTH]     : 0,
                [Dimension.TIME]       : 0,
                [Dimension.TEMPERATURE]: 0,
                [Dimension.CURRENT]    : 0,
                [Dimension.LUMINOUS]   : 0
            })).to.equal("1");
        });

        it("should return a string describing the dimension", () => {
            expect(Dimension.toString({ [Dimension.AMOUNT]     : 1 })).to.equal("N1");
            expect(Dimension.toString({ [Dimension.MASS]       : 1 })).to.equal("M1");
            expect(Dimension.toString({ [Dimension.LENGTH]     : 1 })).to.equal("L1");
            expect(Dimension.toString({ [Dimension.TIME]       : 1 })).to.equal("T1");
            expect(Dimension.toString({ [Dimension.TEMPERATURE]: 1 })).to.equal("Θ1");
            expect(Dimension.toString({ [Dimension.CURRENT]    : 1 })).to.equal("I1");
            expect(Dimension.toString({ [Dimension.LUMINOUS]   : 1 })).to.equal("J1");

            expect(Dimension.toString({
                [Dimension.AMOUNT]     : 1,
                [Dimension.MASS]       : 1,
                [Dimension.LENGTH]     : 1,
                [Dimension.TIME]       : 1,
                [Dimension.TEMPERATURE]: 1,
                [Dimension.CURRENT]    : 1,
                [Dimension.LUMINOUS]   : 1
            })).to.equal("M1L1I1J1N1Θ1T1");

            expect(Dimension.toString({
                [Dimension.MASS]  : 1,
                [Dimension.LENGTH]: 2,
                [Dimension.TIME]  : -2,
            })).to.equal("M1L2T-2");

            expect(Dimension.toString({
                [Dimension.AMOUNT]: 0,
                [Dimension.MASS]  : 1,
                [Dimension.LENGTH]: 2,
                [Dimension.TIME]  : -2,
            })).to.equal("M1L2T-2");

            expect(Dimension.toString({
                [Dimension.AMOUNT]     : 0,
                [Dimension.MASS]       : 1,
                [Dimension.LENGTH]     : 2,
                [Dimension.TIME]       : -2,
                [Dimension.TEMPERATURE]: 0,
                [Dimension.CURRENT]    : 0,
                [Dimension.LUMINOUS]   : 0
            })).to.equal("M1L2T-2");
        });
    });
});
<commit_msg>Delete an unnecessary case<commit_after>/*
 * Cookie Calculator : test / units.js
 * copyright (c) 2016 Susisu
 */

"use strict";

let chai   = require("chai"),
    expect = chai.expect;

let units = require("../src/units.js");

describe("Dimension", () => {
    let Dimension = units.Dimension;

    describe(".toString(dim)", () => {
        it("should return \"1\" when dim is non dimensional", () => {
            expect(Dimension.toString({})).to.equal("1");
            expect(Dimension.toString({ [Dimension.AMOUNT]: 0 })).to.equal("1");
            expect(Dimension.toString({
                [Dimension.AMOUNT]     : 0,
                [Dimension.MASS]       : 0,
                [Dimension.LENGTH]     : 0,
                [Dimension.TIME]       : 0,
                [Dimension.TEMPERATURE]: 0,
                [Dimension.CURRENT]    : 0,
                [Dimension.LUMINOUS]   : 0
            })).to.equal("1");
        });

        it("should return a string describing the dimension", () => {
            expect(Dimension.toString({ [Dimension.AMOUNT]     : 1 })).to.equal("N1");
            expect(Dimension.toString({ [Dimension.MASS]       : 1 })).to.equal("M1");
            expect(Dimension.toString({ [Dimension.LENGTH]     : 1 })).to.equal("L1");
            expect(Dimension.toString({ [Dimension.TIME]       : 1 })).to.equal("T1");
            expect(Dimension.toString({ [Dimension.TEMPERATURE]: 1 })).to.equal("Θ1");
            expect(Dimension.toString({ [Dimension.CURRENT]    : 1 })).to.equal("I1");
            expect(Dimension.toString({ [Dimension.LUMINOUS]   : 1 })).to.equal("J1");

            expect(Dimension.toString({
                [Dimension.AMOUNT]     : 1,
                [Dimension.MASS]       : 1,
                [Dimension.LENGTH]     : 1,
                [Dimension.TIME]       : 1,
                [Dimension.TEMPERATURE]: 1,
                [Dimension.CURRENT]    : 1,
                [Dimension.LUMINOUS]   : 1
            })).to.equal("M1L1I1J1N1Θ1T1");

            expect(Dimension.toString({
                [Dimension.MASS]  : 1,
                [Dimension.LENGTH]: 2,
                [Dimension.TIME]  : -2,
            })).to.equal("M1L2T-2");

            expect(Dimension.toString({
                [Dimension.AMOUNT]     : 0,
                [Dimension.MASS]       : 1,
                [Dimension.LENGTH]     : 2,
                [Dimension.TIME]       : -2,
                [Dimension.TEMPERATURE]: 0,
                [Dimension.CURRENT]    : 0,
                [Dimension.LUMINOUS]   : 0
            })).to.equal("M1L2T-2");
        });
    });
});
<|endoftext|>


<commit_before>$(window).load( function() {
    if (window.location.hash.substring(0, 3) == "#m-") { // Deep Link to Modal
        // remove #m- from hash
        var modalName = window.location.hash.substring(3);
        $('#'+modalName+'-modal').modal('show');
    }
    $('.modal-trigger').click(function () {
    	var modalName = $(this).attr("href").substring(3);
    	$('#'+modalName+'-modal').modal('show');
    	});
});

$(document).ready(function() {
	// Cache the Window object
	$window = $(window);

    $('section[data-type="parallax"]').each(function(){
    	var windowsize = $window.width();
		var $bgobj = $(this); // assigning the object
		if (windowsize > 440) {
			$(window).scroll(function() {
			    var yPos = ($window.scrollTop() / $bgobj.data('speed'));

			    // Put together our final background position
			    var coords = yPos + 'px';

			    // Move the background
			    $bgobj.css({ top: coords });
			});
		}
    });

    $('div[data-type="parallax"]').each(function(){
      var $obj = $(this); // assigning the object

      $(window).scroll(function() {
            var yPos = ($window.scrollTop() / $obj.data('speed'));
            var top = $obj.position().top;

            // Put together our final background position
            var coords = 20 + yPos + '%';

            // Move the background
            $obj.css({ bottom: coords });
        });
    });

    $('[data-toggle="tooltip"]').tooltip();
	// $('.email').tooltip();
	$('[data-toggle="popover"]').popover();

	$('#accordion .collapse').on('shown.bs.collapse', function () {
       $(this).parent().find('.glyphicon-chevron-right').removeClass('glyphicon-chevron-right').addClass('glyphicon-chevron-down');
    });
    $('#accordion .collapse').on('hidden.bs.collapse', function () {
    	$(this).parent().find('.glyphicon-chevron-down').removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right');
    });

	$.ecobasa = {

		// searchbar in top fixed navigation
		searchbar : function() {
			$('#searchbar').hover( function() {
				$(this).addClass('open');
				$(this).addClass('mouseover');
			}, function() {
				if (!$(this).find('input').is(':focus'))
					$(this).removeClass('expanded');
				$(this).removeClass('mouseover');
			});
			$('#searchbar').find('input').blur( function() {
				if(!$(this).parent().hasClass('mouseover'))
					$(this).parent().removeClass('expanded');
			});
			$('#searchbar').click( function() {
				$(this).addClass('open');
			});
		},

		fullcalendar : function() {
			// There are two kinds of calendar in cosinnus: big and small.
			// The .big-calendar fills the content and shows events.
			// Users can add events here.
			// The .small-calendar is for tooltips or small static date chooser.
			// both are based on jQuery fullcalendar. http://arshaw.com/fullcalendar/

			var localeSettings = {
				de: {
					firstDay: 1, // Monday
					buttonText: {
						today: "Heute",
						month: "Monat",
						week: "Woche",
						day: "Tag"
					},
					monthNames: ['Januar','Februar','März','April',
						'Mai','Juni','Juli','August',
						'September','Oktober','November','Dezember'],
					monthNamesShort: ['Jan','Feb','Mär','Apr','Mai',
						'Jun','Jul','Aug','Sept','Okt','Nov','Dez'],
					dayNames: ['Sonntag','Montag','Dienstag',
						'Mittwoch','Donnerstag','Freitag','Samstag'],
					dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
					titleFormat: {
						month: 'MMMM yyyy',
						week: "d.[ MMMM][ yyyy]{ - d. MMMM yyyy}",
						day: 'dddd d. MMMM yyyy'
					},
					columnFormat: {
						month: 'ddd',
						week: 'ddd d',
						day: ''
					},
					axisFormat: 'H:mm',
					timeFormat: {
						'': 'H:mm',
						agenda: 'H:mm{ - H:mm}'
					}
				}
			};
			// LanguageCode injected by backend
			var currentLocaleSettings = localeSettings[LanguageCode];

			if ($('.big-calendar').length)
			$('.big-calendar').fullCalendar($.extend({
				header: {
					left: 'prev,next today',
					center: 'title',
					right: 'month,agendaWeek,agendaDay' // basicDay
				},
				defaultView: 'agendaWeek',

				// cosinnus_calendarEvents is a global var containing the events
				// set by the backend somewhere in the BODY.
				events: cosinnus_calendarEvents,
				select: function(startDate, endDate, allDay, jsEvent, view) {
					$(this.element)
						.closest('.big-calendar')
						.trigger('fullCalendarSelect',[startDate, endDate, allDay, jsEvent, view]);
				},
				eventClick: function(event, jsEvent, view) {
					$(this)
						.closest('.big-calendar')
						.trigger('fullCalendarEventClick',[event, jsEvent, view]);
				},
				selectable: true,
				selectHelper: true
			}, currentLocaleSettings));

			if ($('.small-calendar').length)
			$('.small-calendar').fullCalendar($.extend({
				header: {
					left: 'prev',
					center: 'title',
					right: 'next'
				},
				dayClick: function(date, allDay, jsEvent, view) {
					$(this).trigger('fullCalendarDayClick',[date,jsEvent]);
				},
				viewRender: function(date, cell) {
					// A day has to be rendered because of redraw or something
					$(cell).closest('.small-calendar').trigger('fullCalendarViewRender',[cell]);
				}

			}, currentLocaleSettings));
		},

		calendarBig : function() {
			// The big calendar fills the whole content area and contains the user's events.

			$('.big-calendar')
				.on("fullCalendarSelect", function(event, startDate, endDate, allDay, jsEvent, view) {
					// Dates have been selected. Now the user might want to add an event.
					var startDateDataAttr = startDate.getFullYear() + "-"
						+ ((startDate.getMonth()+1).toString().length === 2
							? (startDate.getMonth()+1)
							: "0" + (startDate.getMonth()+1)) + "-"
						+ (startDate.getDate().toString().length === 2
							? startDate.getDate()
							: "0" + startDate.getDate());

					var endDateDataAttr = endDate.getFullYear() + "-"
						+ ((endDate.getMonth()+1).toString().length === 2
							? (endDate.getMonth()+1)
							: "0" + (endDate.getMonth()+1)) + "-"
						+ (endDate.getDate().toString().length === 2
							? endDate.getDate()
							: "0" + endDate.getDate());

					// allDay is always true as times can not be selected.

					$('#calendarConfirmStartDate').val(startDateDataAttr);
					$('#calendarConfirmEndDate').val(endDateDataAttr);

					if (startDateDataAttr == endDateDataAttr) {
						// Event has one day
						$('#calendarConfirmEventOneday').show();
						$('#calendarConfirmEventMultiday').hide();

						moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
						eventDate = moment(startDateDataAttr);
						var eventDate = moment(eventDate).calendar();
						$('#calendarConfirmEventDate').text(eventDate);

						$('#confirmEventModal').modal('show');
					} else {
						// Event has multiple days
						$('#calendarConfirmEventOneday').hide();
						$('#calendarConfirmEventMultiday').show();

						// There is no time, so use momentShort.
						moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
						startDate = moment(startDateDataAttr);
						var startDate = moment(startDate).calendar();
						$('#calendarConfirmEventStart').text(startDate);

						endDate = moment(endDateDataAttr);
						var endDate = moment(endDate).calendar();
						$('#calendarConfirmEventEnd').text(endDate);

						$('#confirmEventModal').modal('show');
					}
			});

		},

		// When creating or editing an event the user has to select date and time.
		// Clicking one date input shows all calendars on the whole page.
		calendarDayTimeChooser : function() {
			// Hide calendar when clicking outside
			$(document).click(function(event) {
				var thisdaytimechooser = $(event.target).closest('.calendar-date-time-chooser');
				if(thisdaytimechooser.length) {
					// Don't hide any chooser
				} else {
					// hide all
					$('.calendar-date-time-chooser .small-calendar').slideUp();
				}
			});

			$('.calendar-date-time-chooser input.calendar-date-time-chooser-date')
				.click(function() {
				$('.calendar-date-time-chooser .small-calendar').slideDown();
			});

			$('.calendar-date-time-chooser i').click(function() {
				$('.calendar-date-time-chooser .small-calendar').slideDown();
			});

			$('.calendar-date-time-chooser .small-calendar').hide();

			// on every re-drawing of the calendar select the choosen date
			$('.calendar-date-time-chooser .small-calendar')
				.on("fullCalendarViewRender", function(event, cell) {
					// select choosen day

					var date = $(this)
						.closest('.calendar-date-time-chooser')
						.find('.calendar-date-time-chooser-hiddendate')
						.val();
					// "2014-04-28"
					if (date) $(this)
						.find('td[data-date='+date+']')
						.addClass('selected');
				})
				.trigger('fullCalendarViewRender')

				// when clicked on a day: use this!
				.on("fullCalendarDayClick", function(event, date, jsEvent) {
					var dayElement = jsEvent.currentTarget;
					if ($(dayElement).hasClass('fc-other-month')) return;

					var dateDataAttr = date.getFullYear() + "-"
						+ ((date.getMonth()+1).toString().length === 2
							? (date.getMonth()+1)
							: "0" + (date.getMonth()+1)) + "-"
						+ (date.getDate().toString().length === 2
							? date.getDate()
							: "0" + date.getDate());

					// unselect all and re-select later
					$(dayElement).parent().parent().find('td').removeClass('selected');
					$(dayElement).addClass('selected');

					// When date picked, update date in form
					$(this)
						.closest('.calendar-date-time-chooser')
						.find('.calendar-date-time-chooser-hiddendate')
						.val(dateDataAttr);

					// Update INPUT with human readable date
					moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
					var humanDateString = moment(dateDataAttr).calendar();
						$(this)
							.closest('.calendar-date-time-chooser')
							.find('.calendar-date-time-chooser-date')
							.val(humanDateString);
				});

			// Set INPUT with human readable date
			$('.calendar-date-time-chooser').each(function() {
				var dateDataAttr = $(this)
					.find('.calendar-date-time-chooser-hiddendate')
					.val();

				if (dateDataAttr) {
					moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
					var humanDateString = moment(dateDataAttr).calendar();
						$(this)
							.find('.calendar-date-time-chooser-date')
							.val(humanDateString);
				}
			});
		}
	};

	$.ecobasa.fullcalendar();
	$.ecobasa.calendarBig();
	$.ecobasa.calendarDayTimeChooser();
	$.ecobasa.searchbar();
});
<commit_msg>search bar vanish<commit_after>$(window).load( function() {
    if (window.location.hash.substring(0, 3) == "#m-") { // Deep Link to Modal
        // remove #m- from hash
        var modalName = window.location.hash.substring(3);
        $('#'+modalName+'-modal').modal('show');
    }
    $('.modal-trigger').click(function () {
    	var modalName = $(this).attr("href").substring(3);
    	$('#'+modalName+'-modal').modal('show');
    	});
});

$(document).ready(function() {
	// Cache the Window object
	$window = $(window);

    $('section[data-type="parallax"]').each(function(){
    	var windowsize = $window.width();
		var $bgobj = $(this); // assigning the object
		if (windowsize > 440) {
			$(window).scroll(function() {
			    var yPos = ($window.scrollTop() / $bgobj.data('speed'));

			    // Put together our final background position
			    var coords = yPos + 'px';

			    // Move the background
			    $bgobj.css({ top: coords });
			});
		}
    });

    $('div[data-type="parallax"]').each(function(){
      var $obj = $(this); // assigning the object

      $(window).scroll(function() {
            var yPos = ($window.scrollTop() / $obj.data('speed'));
            var top = $obj.position().top;

            // Put together our final background position
            var coords = 20 + yPos + '%';

            // Move the background
            $obj.css({ bottom: coords });
        });
    });

    $('[data-toggle="tooltip"]').tooltip();
	// $('.email').tooltip();
	$('[data-toggle="popover"]').popover();

	$('#accordion .collapse').on('shown.bs.collapse', function () {
       $(this).parent().find('.glyphicon-chevron-right').removeClass('glyphicon-chevron-right').addClass('glyphicon-chevron-down');
    });
    $('#accordion .collapse').on('hidden.bs.collapse', function () {
    	$(this).parent().find('.glyphicon-chevron-down').removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-right');
    });

	$.ecobasa = {

		// searchbar in top fixed navigation
		searchbar : function() {
			$('#searchbar').hover( function() {
				$(this).addClass('open');
				$(this).addClass('mouseover');
				$(this).find('input').focus();
			}, function() {
				if (!$(this).find('input').is(':focus'))
					$(this).removeClass('open');
					$(this).removeClass('mouseover');
			});
			$('#searchbar').find('input').blur( function() {
				if(!$(this).parent().hasClass('mouseover'))
					$(this).parent().removeClass('open');
			});
			$('body').click( function() {
				if(!$('#searchbar').find('input').is(':focus') && $('#searchbar').hasClass('open'))
					$('#searchbar').removeClass('open');
			});
		},

		fullcalendar : function() {
			// There are two kinds of calendar in cosinnus: big and small.
			// The .big-calendar fills the content and shows events.
			// Users can add events here.
			// The .small-calendar is for tooltips or small static date chooser.
			// both are based on jQuery fullcalendar. http://arshaw.com/fullcalendar/

			var localeSettings = {
				de: {
					firstDay: 1, // Monday
					buttonText: {
						today: "Heute",
						month: "Monat",
						week: "Woche",
						day: "Tag"
					},
					monthNames: ['Januar','Februar','März','April',
						'Mai','Juni','Juli','August',
						'September','Oktober','November','Dezember'],
					monthNamesShort: ['Jan','Feb','Mär','Apr','Mai',
						'Jun','Jul','Aug','Sept','Okt','Nov','Dez'],
					dayNames: ['Sonntag','Montag','Dienstag',
						'Mittwoch','Donnerstag','Freitag','Samstag'],
					dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
					titleFormat: {
						month: 'MMMM yyyy',
						week: "d.[ MMMM][ yyyy]{ - d. MMMM yyyy}",
						day: 'dddd d. MMMM yyyy'
					},
					columnFormat: {
						month: 'ddd',
						week: 'ddd d',
						day: ''
					},
					axisFormat: 'H:mm',
					timeFormat: {
						'': 'H:mm',
						agenda: 'H:mm{ - H:mm}'
					}
				}
			};
			// LanguageCode injected by backend
			var currentLocaleSettings = localeSettings[LanguageCode];

			if ($('.big-calendar').length)
			$('.big-calendar').fullCalendar($.extend({
				header: {
					left: 'prev,next today',
					center: 'title',
					right: 'month,agendaWeek,agendaDay' // basicDay
				},
				defaultView: 'agendaWeek',

				// cosinnus_calendarEvents is a global var containing the events
				// set by the backend somewhere in the BODY.
				events: cosinnus_calendarEvents,
				select: function(startDate, endDate, allDay, jsEvent, view) {
					$(this.element)
						.closest('.big-calendar')
						.trigger('fullCalendarSelect',[startDate, endDate, allDay, jsEvent, view]);
				},
				eventClick: function(event, jsEvent, view) {
					$(this)
						.closest('.big-calendar')
						.trigger('fullCalendarEventClick',[event, jsEvent, view]);
				},
				selectable: true,
				selectHelper: true
			}, currentLocaleSettings));

			if ($('.small-calendar').length)
			$('.small-calendar').fullCalendar($.extend({
				header: {
					left: 'prev',
					center: 'title',
					right: 'next'
				},
				dayClick: function(date, allDay, jsEvent, view) {
					$(this).trigger('fullCalendarDayClick',[date,jsEvent]);
				},
				viewRender: function(date, cell) {
					// A day has to be rendered because of redraw or something
					$(cell).closest('.small-calendar').trigger('fullCalendarViewRender',[cell]);
				}

			}, currentLocaleSettings));
		},

		calendarBig : function() {
			// The big calendar fills the whole content area and contains the user's events.

			$('.big-calendar')
				.on("fullCalendarSelect", function(event, startDate, endDate, allDay, jsEvent, view) {
					// Dates have been selected. Now the user might want to add an event.
					var startDateDataAttr = startDate.getFullYear() + "-"
						+ ((startDate.getMonth()+1).toString().length === 2
							? (startDate.getMonth()+1)
							: "0" + (startDate.getMonth()+1)) + "-"
						+ (startDate.getDate().toString().length === 2
							? startDate.getDate()
							: "0" + startDate.getDate());

					var endDateDataAttr = endDate.getFullYear() + "-"
						+ ((endDate.getMonth()+1).toString().length === 2
							? (endDate.getMonth()+1)
							: "0" + (endDate.getMonth()+1)) + "-"
						+ (endDate.getDate().toString().length === 2
							? endDate.getDate()
							: "0" + endDate.getDate());

					// allDay is always true as times can not be selected.

					$('#calendarConfirmStartDate').val(startDateDataAttr);
					$('#calendarConfirmEndDate').val(endDateDataAttr);

					if (startDateDataAttr == endDateDataAttr) {
						// Event has one day
						$('#calendarConfirmEventOneday').show();
						$('#calendarConfirmEventMultiday').hide();

						moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
						eventDate = moment(startDateDataAttr);
						var eventDate = moment(eventDate).calendar();
						$('#calendarConfirmEventDate').text(eventDate);

						$('#confirmEventModal').modal('show');
					} else {
						// Event has multiple days
						$('#calendarConfirmEventOneday').hide();
						$('#calendarConfirmEventMultiday').show();

						// There is no time, so use momentShort.
						moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
						startDate = moment(startDateDataAttr);
						var startDate = moment(startDate).calendar();
						$('#calendarConfirmEventStart').text(startDate);

						endDate = moment(endDateDataAttr);
						var endDate = moment(endDate).calendar();
						$('#calendarConfirmEventEnd').text(endDate);

						$('#confirmEventModal').modal('show');
					}
			});

		},

		// When creating or editing an event the user has to select date and time.
		// Clicking one date input shows all calendars on the whole page.
		calendarDayTimeChooser : function() {
			// Hide calendar when clicking outside
			$(document).click(function(event) {
				var thisdaytimechooser = $(event.target).closest('.calendar-date-time-chooser');
				if(thisdaytimechooser.length) {
					// Don't hide any chooser
				} else {
					// hide all
					$('.calendar-date-time-chooser .small-calendar').slideUp();
				}
			});

			$('.calendar-date-time-chooser input.calendar-date-time-chooser-date')
				.click(function() {
				$('.calendar-date-time-chooser .small-calendar').slideDown();
			});

			$('.calendar-date-time-chooser i').click(function() {
				$('.calendar-date-time-chooser .small-calendar').slideDown();
			});

			$('.calendar-date-time-chooser .small-calendar').hide();

			// on every re-drawing of the calendar select the choosen date
			$('.calendar-date-time-chooser .small-calendar')
				.on("fullCalendarViewRender", function(event, cell) {
					// select choosen day

					var date = $(this)
						.closest('.calendar-date-time-chooser')
						.find('.calendar-date-time-chooser-hiddendate')
						.val();
					// "2014-04-28"
					if (date) $(this)
						.find('td[data-date='+date+']')
						.addClass('selected');
				})
				.trigger('fullCalendarViewRender')

				// when clicked on a day: use this!
				.on("fullCalendarDayClick", function(event, date, jsEvent) {
					var dayElement = jsEvent.currentTarget;
					if ($(dayElement).hasClass('fc-other-month')) return;

					var dateDataAttr = date.getFullYear() + "-"
						+ ((date.getMonth()+1).toString().length === 2
							? (date.getMonth()+1)
							: "0" + (date.getMonth()+1)) + "-"
						+ (date.getDate().toString().length === 2
							? date.getDate()
							: "0" + date.getDate());

					// unselect all and re-select later
					$(dayElement).parent().parent().find('td').removeClass('selected');
					$(dayElement).addClass('selected');

					// When date picked, update date in form
					$(this)
						.closest('.calendar-date-time-chooser')
						.find('.calendar-date-time-chooser-hiddendate')
						.val(dateDataAttr);

					// Update INPUT with human readable date
					moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
					var humanDateString = moment(dateDataAttr).calendar();
						$(this)
							.closest('.calendar-date-time-chooser')
							.find('.calendar-date-time-chooser-date')
							.val(humanDateString);
				});

			// Set INPUT with human readable date
			$('.calendar-date-time-chooser').each(function() {
				var dateDataAttr = $(this)
					.find('.calendar-date-time-chooser-hiddendate')
					.val();

				if (dateDataAttr) {
					moment.lang(moment.lang(),$.cosinnus.momentShort[moment.lang()]);
					var humanDateString = moment(dateDataAttr).calendar();
						$(this)
							.find('.calendar-date-time-chooser-date')
							.val(humanDateString);
				}
			});
		}
	};

	$.ecobasa.fullcalendar();
	$.ecobasa.calendarBig();
	$.ecobasa.calendarDayTimeChooser();
	$.ecobasa.searchbar();
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 *
 * 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.
 */

foam.CLASS({
  package: 'foam.java',
  name: 'Skeleton',

  properties: [
    {
      class: 'Class',
      name: 'of'
    },
    {
      name: 'name',
      expression: function(of) {
        return this.of.name + 'Skeleton';
      }
    },
    {
      name: 'package',
      expression: function(of) {
        return this.of.package;
      }
    },
    {
      name: 'id',
      expression: function(name, package) {
        return package + '.' + name;
      }
    }
  ],

  methods: [
    function buildJavaClass(cls) {
      cls = cls || foam.java.Class.create();

      cls.package = this.package;
      cls.name    = this.name;
      cls.extends = 'foam.box.AbstractSkeleton',

      foam.core.Object.create({
        name: 'delegate',
        javaType: this.of.id
      }).buildJavaClass(cls);

      cls.method({
        type: 'void',
        visibility: 'public',
        name: 'send',
        args: [ { name: 'message', type: 'foam.box.Message' } ],
        body: this.sendMethodCode()
      });

      cls.method({
        type: 'void',
        visibility: 'public',
        name: 'setDelegateObject',
        args: [ { name: 'obj', type: 'Object' } ],
        body: "setDelegate((" + this.of.id + ") obj);"
      });

      return cls;
    }
  ],

  templates: [
    {
      name: 'sendMethodCode',
      template: `if ( ! ( message.getObject() instanceof foam.box.RPCMessage) ) {
      // TODO return an error?
      return;
    }

    foam.box.RPCMessage rpc      = (foam.box.RPCMessage) message.getObject();
    foam.box.Box        replyBox = (foam.box.Box) message.getAttributes().get("replyBox");
    Object              result   = null;

    try {
      switch ( rpc.getName() ) {<%
  var methods = this.of.getOwnAxiomsByClass(foam.core.Method);
  for ( var i = 0 ; i < methods.length ; i++ ) {
    var m = methods[i]; %>
        case "<%= m.name %>":
          <% if ( m.javaReturns && m.javaReturns !== 'void' ) { %>result = <% } %>getDelegate().<%= m.name %>(
          <%
    for ( var j = 0 ; j < m.args.length ; j++ ) {
      if ( m.args[j].javaType == 'foam.core.X' ) {
        %>getMessageX(message)<%
      } else if ( foam.core.AbstractEnum.isSubClass(this.lookup(m.args[j].javaType, true)) ) {
        %><%= m.args[j].javaType%>.forOrdinal(toint(rpc.getArgs() != null && rpc.getArgs().length > <%= j %> ? rpc.getArgs()[<%= j %>] : null))<%
      } else {
        if ( {byte: 1, double: 1, float: 1, int: 1, long: 1, short: 1 }[m.args[j].javaType] ) {
          %>to<%= m.args[j].javaType %><%
        } else {
          %>(<%= m.args[j].javaType %>)<%
        }
        %>(rpc.getArgs() != null && rpc.getArgs().length > <%= j %> ? rpc.getArgs()[<%= j %>] : null)<%
      }
      if ( j != m.args.length - 1 ) { %>,
            <% }
      }
    %>);
        break;
    <%
  }%>
        default: throw new RuntimeException("Method not found: " + rpc.getName());
      }
    } catch (Throwable t) {
      t.printStackTrace();
      message.replyWithException(t);

      return;
    }

    if ( replyBox != null ) {
      foam.box.RPCReturnMessage reply = (foam.box.RPCReturnMessage)getX().create(foam.box.RPCReturnMessage.class);
      if ( result != null ) {
        reply.setData(result);
      }

      foam.box.Message message1 = getX().create(foam.box.Message.class);
      message1.setObject(reply);
      replyBox.send(message1);
    }`
    }
  ]
});
<commit_msg>Removed printing of stack trace from Skeleton<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 *
 * 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.
 */

foam.CLASS({
  package: 'foam.java',
  name: 'Skeleton',

  properties: [
    {
      class: 'Class',
      name: 'of'
    },
    {
      name: 'name',
      expression: function(of) {
        return this.of.name + 'Skeleton';
      }
    },
    {
      name: 'package',
      expression: function(of) {
        return this.of.package;
      }
    },
    {
      name: 'id',
      expression: function(name, package) {
        return package + '.' + name;
      }
    }
  ],

  methods: [
    function buildJavaClass(cls) {
      cls = cls || foam.java.Class.create();

      cls.package = this.package;
      cls.name    = this.name;
      cls.extends = 'foam.box.AbstractSkeleton',

      foam.core.Object.create({
        name: 'delegate',
        javaType: this.of.id
      }).buildJavaClass(cls);

      cls.method({
        type: 'void',
        visibility: 'public',
        name: 'send',
        args: [ { name: 'message', type: 'foam.box.Message' } ],
        body: this.sendMethodCode()
      });

      cls.method({
        type: 'void',
        visibility: 'public',
        name: 'setDelegateObject',
        args: [ { name: 'obj', type: 'Object' } ],
        body: "setDelegate((" + this.of.id + ") obj);"
      });

      return cls;
    }
  ],

  templates: [
    {
      name: 'sendMethodCode',
      template: `if ( ! ( message.getObject() instanceof foam.box.RPCMessage) ) {
      // TODO return an error?
      return;
    }

    foam.box.RPCMessage rpc      = (foam.box.RPCMessage) message.getObject();
    foam.box.Box        replyBox = (foam.box.Box) message.getAttributes().get("replyBox");
    Object              result   = null;

    try {
      switch ( rpc.getName() ) {<%
  var methods = this.of.getOwnAxiomsByClass(foam.core.Method);
  for ( var i = 0 ; i < methods.length ; i++ ) {
    var m = methods[i]; %>
        case "<%= m.name %>":
          <% if ( m.javaReturns && m.javaReturns !== 'void' ) { %>result = <% } %>getDelegate().<%= m.name %>(
          <%
    for ( var j = 0 ; j < m.args.length ; j++ ) {
      if ( m.args[j].javaType == 'foam.core.X' ) {
        %>getMessageX(message)<%
      } else if ( foam.core.AbstractEnum.isSubClass(this.lookup(m.args[j].javaType, true)) ) {
        %><%= m.args[j].javaType%>.forOrdinal(toint(rpc.getArgs() != null && rpc.getArgs().length > <%= j %> ? rpc.getArgs()[<%= j %>] : null))<%
      } else {
        if ( {byte: 1, double: 1, float: 1, int: 1, long: 1, short: 1 }[m.args[j].javaType] ) {
          %>to<%= m.args[j].javaType %><%
        } else {
          %>(<%= m.args[j].javaType %>)<%
        }
        %>(rpc.getArgs() != null && rpc.getArgs().length > <%= j %> ? rpc.getArgs()[<%= j %>] : null)<%
      }
      if ( j != m.args.length - 1 ) { %>,
            <% }
      }
    %>);
        break;
    <%
  }%>
        default: throw new RuntimeException("Method not found: " + rpc.getName());
      }
    } catch (Throwable t) {
      message.replyWithException(t);
      return;
    }

    if ( replyBox != null ) {
      foam.box.RPCReturnMessage reply = (foam.box.RPCReturnMessage)getX().create(foam.box.RPCReturnMessage.class);
      if ( result != null ) {
        reply.setData(result);
      }

      foam.box.Message message1 = getX().create(foam.box.Message.class);
      message1.setObject(reply);
      replyBox.send(message1);
    }`
    }
  ]
});
<|endoftext|>


<commit_before>// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// 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.

/**
 * @fileoverview A class that supports single selection from a dropdown menu,
 * with semantics similar to the native HTML <select>
 * element.
 *
 * @see ../demos/select.html
 */

goog.provide('goog.ui.Select');

goog.require('goog.dom.a11y');
goog.require('goog.dom.a11y.Role');
goog.require('goog.dom.a11y.State');
goog.require('goog.events.EventType');
goog.require('goog.ui.Component.EventType');
goog.require('goog.ui.ControlContent');
goog.require('goog.ui.MenuButton');
goog.require('goog.ui.SelectionModel');
goog.require('goog.ui.registry');

/**
 * A selection control.  Extends {@link goog.ui.MenuButton} by composing a
 * menu with a selection model, and automatically updating the button's caption
 * based on the current selection.
 *
 * @param {goog.ui.ControlContent} caption Default caption or existing DOM
 *     structure to display as the button's caption when nothing is selected.
 * @param {goog.ui.Menu=} opt_menu Menu containing selection options.
 * @param {goog.ui.ButtonRenderer=} opt_renderer Renderer used to render or
 *     decorate the control; defaults to {@link goog.ui.MenuButtonRenderer}.
 * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM hepler, used for
 *     document interaction.
 * @constructor
 * @extends {goog.ui.MenuButton}
 */
goog.ui.Select = function(caption, opt_menu, opt_renderer, opt_domHelper) {
  goog.ui.MenuButton.call(this, caption, opt_menu, opt_renderer, opt_domHelper);
  this.setDefaultCaption(caption);
  this.setPreferredAriaRole(goog.dom.a11y.Role.LISTBOX);
};
goog.inherits(goog.ui.Select, goog.ui.MenuButton);

/**
 * The selection model controlling the items in the menu.
 * @type {goog.ui.SelectionModel}
 * @private
 */
goog.ui.Select.prototype.selectionModel_ = null;

/**
 * Default caption to be shown when no option is selected.
 * @type {goog.ui.ControlContent}
 * @private
 */
goog.ui.Select.prototype.defaultCaption_ = null;

/**
 * Configures the component after its DOM has been rendered, and sets up event
 * handling.  Overrides {@link goog.ui.MenuButton#enterDocument}.
 */
goog.ui.Select.prototype.enterDocument = function() {
  goog.ui.Select.superClass_.enterDocument.call(this);
  this.updateCaption_();
  this.listenToSelectionModelEvents_();
  // Need to set HASPOPUP to false since it's set to true in the parent class.
  goog.dom.a11y.setState(this.getElement(),
      goog.dom.a11y.State.HASPOPUP, 'false');
};

/**
 * Decorates the given element with this control.  Overrides the superclass
 * implementation by initializing the default caption on the select button.
 * @param {Element} element Element to decorate.
 */
goog.ui.Select.prototype.decorateInternal = function(element) {
  goog.ui.Select.superClass_.decorateInternal.call(this, element);
  var caption = this.getCaption();
  if (caption) {
    // Initialize the default caption.
    this.setDefaultCaption(caption);
  } else {
    // There is no default caption; select the first option.
    this.setSelectedIndex(0);
  }
};

/** @override */
goog.ui.Select.prototype.disposeInternal = function() {
  goog.ui.Select.superClass_.disposeInternal.call(this);

  if (this.selectionModel_) {
    this.selectionModel_.dispose();
    this.selectionModel_ = null;
  }

  this.defaultCaption_ = null;
};

/**
 * Handles {@link goog.ui.Component.EventType.ACTION} events dispatched by
 * the menu item clicked by the user.  Updates the selection model, calls
 * the superclass implementation to hide the menu, stops the propagation of
 * the event, and dispatches an ACTION event on behalf of the select control
 * itself.  Overrides {@link goog.ui.MenuButton#handleMenuAction}.
 * @param {goog.events.Event} e Action event to handle.
 */
goog.ui.Select.prototype.handleMenuAction = function(e) {
  this.setSelectedItem(/** @type {goog.ui.MenuItem} */ (e.target));
  goog.ui.Select.superClass_.handleMenuAction.call(this, e);
  e.stopPropagation();
  this.dispatchEvent(goog.ui.Component.EventType.ACTION);
};

/**
 * Handles {@link goog.events.EventType.SELECT} events raised by the
 * selection model when the selection changes.  Updates the contents of the
 * select button.
 * @param {goog.events.Event} e Selection event to handle.
 */
goog.ui.Select.prototype.handleSelectionChange = function(e) {
  var item = this.getSelectedItem();
  goog.ui.Select.superClass_.setValue.call(this, item && item.getValue());
  this.updateCaption_();
};

/**
 * Replaces the menu currently attached to the control (if any) with the given
 * argument, and updates the selection model.  Does nothing if the new menu is
 * the same as the old one.  Overrides {@link goog.ui.MenuButton#setMenu}.
 * @param {goog.ui.Menu} menu New menu to be attached to the menu button.
 * @return {goog.ui.Menu|undefined} Previous menu (undefined if none).
 */
goog.ui.Select.prototype.setMenu = function(menu) {
  // Call superclass implementation to replace the menu.
  var oldMenu = goog.ui.Select.superClass_.setMenu.call(this, menu);

  // Do nothing unless the new menu is different from the current one.
  if (menu != oldMenu) {
    // Clear the old selection model (if any).
    if (this.selectionModel_) {
      this.selectionModel_.clear();
    }

    // Initialize new selection model (unless the new menu is null).
    if (menu) {
      if (this.selectionModel_) {
        menu.forEachChild(function(child, index) {
          this.setCorrectAriaRole_(child);
          this.selectionModel_.addItem(child);
        }, this);
      } else {
        this.createSelectionModel_(menu);
      }
    }
  }

  return oldMenu;
};

/**
 * Returns the default caption to be shown when no option is selected.
 * @return {goog.ui.ControlContent} Default caption.
 */
goog.ui.Select.prototype.getDefaultCaption = function() {
  return this.defaultCaption_;
};

/**
 * Sets the default caption to the given string or DOM structure.
 * @param {goog.ui.ControlContent} caption Default caption to be shown
 *    when no option is selected.
 */
goog.ui.Select.prototype.setDefaultCaption = function(caption) {
  this.defaultCaption_ = caption;
  this.updateCaption_();
};

/**
 * Adds a new menu item at the end of the menu.
 * @param {goog.ui.MenuItem|goog.ui.MenuSeparator} item Menu item to add to the
 *     menu.
 */
goog.ui.Select.prototype.addItem = function(item) {
  this.setCorrectAriaRole_(item);
  goog.ui.Select.superClass_.addItem.call(this, item);

  if (this.selectionModel_) {
    this.selectionModel_.addItem(item);
  } else {
    this.createSelectionModel_(this.getMenu());
  }
};

/**
 * Adds a new menu item at a specific index in the menu.
 * @param {goog.ui.MenuItem|goog.ui.MenuSeparator} item Menu item to add to the
 *     menu.
 * @param {number} index Index at which to insert the menu item.
 */
goog.ui.Select.prototype.addItemAt = function(item, index) {
  this.setCorrectAriaRole_(item);
  goog.ui.Select.superClass_.addItemAt.call(this, item, index);

  if (this.selectionModel_) {
    this.selectionModel_.addItemAt(item, index);
  } else {
    this.createSelectionModel_(this.getMenu());
  }
};

/**
 * Removes an item from the menu and disposes it.
 * @param {goog.ui.MenuItem} item The menu item to remove.
 */
goog.ui.Select.prototype.removeItem = function(item) {
  goog.ui.Select.superClass_.removeItem.call(this, item);
  if (this.selectionModel_) {
    this.selectionModel_.removeItem(item);
  }
};

/**
 * Removes a menu item at a given index in the menu and disposes it.
 * @param {number} index Index of item.
 */
goog.ui.Select.prototype.removeItemAt = function(index) {
  goog.ui.Select.superClass_.removeItemAt.call(this, index);
  if (this.selectionModel_) {
    this.selectionModel_.removeItemAt(index);
  }
};

/**
 * Selects the specified option (assumed to be in the select menu), and
 * deselects the previously selected option, if any.  A null argument clears
 * the selection.
 * @param {goog.ui.MenuItem} item Option to be selected (null to clear
 *     the selection).
 */
goog.ui.Select.prototype.setSelectedItem = function(item) {
  if (this.selectionModel_) {
    this.selectionModel_.setSelectedItem(item);
  }
};

/**
 * Selects the option at the specified index, or clears the selection if the
 * index is out of bounds.
 * @param {number} index Index of the option to be selected.
 */
goog.ui.Select.prototype.setSelectedIndex = function(index) {
  if (this.selectionModel_) {
    this.setSelectedItem(/** @type {goog.ui.MenuItem} */
        (this.selectionModel_.getItemAt(index)));
  }
};

/**
 * Selects the first option found with an associated value equal to the
 * argument, or clears the selection if no such option is found.  A null
 * argument also clears the selection.  Overrides {@link
 * goog.ui.Button#setValue}.
 * @param {*} value Value of the option to be selected (null to clear
 *     the selection).
 */
goog.ui.Select.prototype.setValue = function(value) {
  if (goog.isDefAndNotNull(value) && this.selectionModel_) {
    for (var i = 0, item; item = this.selectionModel_.getItemAt(i); i++) {
      if (item && typeof item.getValue == 'function' &&
          item.getValue() == value) {
        this.setSelectedItem(/** @type {goog.ui.MenuItem} */ (item));
        return;
      }
    }
  }

  this.setSelectedItem(null);
};

/**
 * Returns the currently selected option.
 * @return {goog.ui.MenuItem} The currently selected option (null if none).
 */
goog.ui.Select.prototype.getSelectedItem = function() {
  return this.selectionModel_ ?
      /** @type {goog.ui.MenuItem} */ (this.selectionModel_.getSelectedItem()) :
      null;
};

/**
 * Returns the index of the currently selected option.
 * @return {number} 0-based index of the currently selected option (-1 if none).
 */
goog.ui.Select.prototype.getSelectedIndex = function() {
  return this.selectionModel_ ? this.selectionModel_.getSelectedIndex() : -1;
};

/**
 * @return {goog.ui.SelectionModel} The selection model.
 * @protected
 */
goog.ui.Select.prototype.getSelectionModel = function() {
  return this.selectionModel_;
};

/**
 * Creates a new selection model and sets up an event listener to handle
 * {@link goog.events.EventType.SELECT} events dispatched by it.
 * @param {goog.ui.Component=} opt_component If provided, will add the
 *     component's children as items to the selection model.
 * @private
 */
goog.ui.Select.prototype.createSelectionModel_ = function(opt_component) {
  this.selectionModel_ = new goog.ui.SelectionModel();
  if (opt_component) {
    opt_component.forEachChild(function(child, index) {
      this.setCorrectAriaRole_(child);
      this.selectionModel_.addItem(child);
    }, this);
  }
  this.listenToSelectionModelEvents_();
};

/**
 * Subscribes to events dispatched by the selection model.
 * @private
 */
goog.ui.Select.prototype.listenToSelectionModelEvents_ = function() {
  if (this.selectionModel_) {
    this.getHandler().listen(this.selectionModel_, goog.events.EventType.SELECT,
        this.handleSelectionChange);
  }
};

/**
 * Updates the caption to be shown in the select button.  If no option is
 * selected and a default caption is set, sets the caption to the default
 * caption; otherwise to the empty string.
 * @private
 */
goog.ui.Select.prototype.updateCaption_ = function() {
  var item = this.getSelectedItem();
  this.setContent(item ? item.getCaption() : this.defaultCaption_);
};

/**
 * Sets the correct ARIA role for the menu item or separator.
 * @param {goog.ui.MenuItem|goog.ui.MenuSeparator} item The item to set.
 * @private
 */
goog.ui.Select.prototype.setCorrectAriaRole_ = function(item) {
  item.setPreferredAriaRole(item instanceof goog.ui.MenuItem ?
      goog.dom.a11y.Role.OPTION : goog.dom.a11y.Role.SEPARATOR);
};

/**
 * Opens or closes the menu.  Overrides {@link goog.ui.MenuButton#setOpen} by
 * highlighting the currently selected option on open.
 * @param {boolean} open Whether to open or close the menu.
 * @param {goog.events.Event=} opt_e Mousedown event that caused the menu to
 *     be opened.
 * @override
 */
goog.ui.Select.prototype.setOpen = function(open, opt_e) {
  goog.ui.Select.superClass_.setOpen.call(this, open, opt_e);

  if (this.isOpen()) {
    this.getMenu().setHighlightedIndex(this.getSelectedIndex());
  }
};

// Register a decorator factory function for goog.ui.Selects.
goog.ui.registry.setDecoratorByClassName(
    goog.getCssName('goog-select'), function() {
      // Select defaults to using MenuButtonRenderer, since it shares its L&F.
      return new goog.ui.Select(null);
    });
<commit_msg><commit_after>// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// 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.

/**
 * @fileoverview A class that supports single selection from a dropdown menu,
 * with semantics similar to the native HTML <select>
 * element.
 *
 * @see ../demos/select.html
 */

goog.provide('goog.ui.Select');

goog.require('goog.dom.a11y');
goog.require('goog.dom.a11y.Role');
goog.require('goog.dom.a11y.State');
goog.require('goog.events.EventType');
goog.require('goog.ui.Component.EventType');
goog.require('goog.ui.ControlContent');
goog.require('goog.ui.MenuButton');
goog.require('goog.ui.SelectionModel');
goog.require('goog.ui.registry');

/**
 * A selection control.  Extends {@link goog.ui.MenuButton} by composing a
 * menu with a selection model, and automatically updating the button's caption
 * based on the current selection.
 *
 * @param {goog.ui.ControlContent} caption Default caption or existing DOM
 *     structure to display as the button's caption when nothing is selected.
 * @param {goog.ui.Menu=} opt_menu Menu containing selection options.
 * @param {goog.ui.ButtonRenderer=} opt_renderer Renderer used to render or
 *     decorate the control; defaults to {@link goog.ui.MenuButtonRenderer}.
 * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM hepler, used for
 *     document interaction.
 * @constructor
 * @extends {goog.ui.MenuButton}
 */
goog.ui.Select = function(caption, opt_menu, opt_renderer, opt_domHelper) {
  goog.ui.MenuButton.call(this, caption, opt_menu, opt_renderer, opt_domHelper);
  this.setDefaultCaption(caption);
  this.setPreferredAriaRole(goog.dom.a11y.Role.LISTBOX);
};
goog.inherits(goog.ui.Select, goog.ui.MenuButton);

/**
 * The selection model controlling the items in the menu.
 * @type {goog.ui.SelectionModel}
 * @private
 */
goog.ui.Select.prototype.selectionModel_ = null;

/**
 * Default caption to be shown when no option is selected.
 * @type {goog.ui.ControlContent}
 * @private
 */
goog.ui.Select.prototype.defaultCaption_ = null;

/**
 * Configures the component after its DOM has been rendered, and sets up event
 * handling.  Overrides {@link goog.ui.MenuButton#enterDocument}.
 */
goog.ui.Select.prototype.enterDocument = function() {
  goog.ui.Select.superClass_.enterDocument.call(this);
  this.updateCaption();
  this.listenToSelectionModelEvents_();
  // Need to set HASPOPUP to false since it's set to true in the parent class.
  goog.dom.a11y.setState(this.getElement(),
      goog.dom.a11y.State.HASPOPUP, 'false');
};

/**
 * Decorates the given element with this control.  Overrides the superclass
 * implementation by initializing the default caption on the select button.
 * @param {Element} element Element to decorate.
 */
goog.ui.Select.prototype.decorateInternal = function(element) {
  goog.ui.Select.superClass_.decorateInternal.call(this, element);
  var caption = this.getCaption();
  if (caption) {
    // Initialize the default caption.
    this.setDefaultCaption(caption);
  } else {
    // There is no default caption; select the first option.
    this.setSelectedIndex(0);
  }
};

/** @override */
goog.ui.Select.prototype.disposeInternal = function() {
  goog.ui.Select.superClass_.disposeInternal.call(this);

  if (this.selectionModel_) {
    this.selectionModel_.dispose();
    this.selectionModel_ = null;
  }

  this.defaultCaption_ = null;
};

/**
 * Handles {@link goog.ui.Component.EventType.ACTION} events dispatched by
 * the menu item clicked by the user.  Updates the selection model, calls
 * the superclass implementation to hide the menu, stops the propagation of
 * the event, and dispatches an ACTION event on behalf of the select control
 * itself.  Overrides {@link goog.ui.MenuButton#handleMenuAction}.
 * @param {goog.events.Event} e Action event to handle.
 */
goog.ui.Select.prototype.handleMenuAction = function(e) {
  this.setSelectedItem(/** @type {goog.ui.MenuItem} */ (e.target));
  goog.ui.Select.superClass_.handleMenuAction.call(this, e);
  e.stopPropagation();
  this.dispatchEvent(goog.ui.Component.EventType.ACTION);
};

/**
 * Handles {@link goog.events.EventType.SELECT} events raised by the
 * selection model when the selection changes.  Updates the contents of the
 * select button.
 * @param {goog.events.Event} e Selection event to handle.
 */
goog.ui.Select.prototype.handleSelectionChange = function(e) {
  var item = this.getSelectedItem();
  goog.ui.Select.superClass_.setValue.call(this, item && item.getValue());
  this.updateCaption();
};

/**
 * Replaces the menu currently attached to the control (if any) with the given
 * argument, and updates the selection model.  Does nothing if the new menu is
 * the same as the old one.  Overrides {@link goog.ui.MenuButton#setMenu}.
 * @param {goog.ui.Menu} menu New menu to be attached to the menu button.
 * @return {goog.ui.Menu|undefined} Previous menu (undefined if none).
 */
goog.ui.Select.prototype.setMenu = function(menu) {
  // Call superclass implementation to replace the menu.
  var oldMenu = goog.ui.Select.superClass_.setMenu.call(this, menu);

  // Do nothing unless the new menu is different from the current one.
  if (menu != oldMenu) {
    // Clear the old selection model (if any).
    if (this.selectionModel_) {
      this.selectionModel_.clear();
    }

    // Initialize new selection model (unless the new menu is null).
    if (menu) {
      if (this.selectionModel_) {
        menu.forEachChild(function(child, index) {
          this.setCorrectAriaRole_(child);
          this.selectionModel_.addItem(child);
        }, this);
      } else {
        this.createSelectionModel_(menu);
      }
    }
  }

  return oldMenu;
};

/**
 * Returns the default caption to be shown when no option is selected.
 * @return {goog.ui.ControlContent} Default caption.
 */
goog.ui.Select.prototype.getDefaultCaption = function() {
  return this.defaultCaption_;
};

/**
 * Sets the default caption to the given string or DOM structure.
 * @param {goog.ui.ControlContent} caption Default caption to be shown
 *    when no option is selected.
 */
goog.ui.Select.prototype.setDefaultCaption = function(caption) {
  this.defaultCaption_ = caption;
  this.updateCaption();
};

/**
 * Adds a new menu item at the end of the menu.
 * @param {goog.ui.MenuItem|goog.ui.MenuSeparator} item Menu item to add to the
 *     menu.
 */
goog.ui.Select.prototype.addItem = function(item) {
  this.setCorrectAriaRole_(item);
  goog.ui.Select.superClass_.addItem.call(this, item);

  if (this.selectionModel_) {
    this.selectionModel_.addItem(item);
  } else {
    this.createSelectionModel_(this.getMenu());
  }
};

/**
 * Adds a new menu item at a specific index in the menu.
 * @param {goog.ui.MenuItem|goog.ui.MenuSeparator} item Menu item to add to the
 *     menu.
 * @param {number} index Index at which to insert the menu item.
 */
goog.ui.Select.prototype.addItemAt = function(item, index) {
  this.setCorrectAriaRole_(item);
  goog.ui.Select.superClass_.addItemAt.call(this, item, index);

  if (this.selectionModel_) {
    this.selectionModel_.addItemAt(item, index);
  } else {
    this.createSelectionModel_(this.getMenu());
  }
};

/**
 * Removes an item from the menu and disposes it.
 * @param {goog.ui.MenuItem} item The menu item to remove.
 */
goog.ui.Select.prototype.removeItem = function(item) {
  goog.ui.Select.superClass_.removeItem.call(this, item);
  if (this.selectionModel_) {
    this.selectionModel_.removeItem(item);
  }
};

/**
 * Removes a menu item at a given index in the menu and disposes it.
 * @param {number} index Index of item.
 */
goog.ui.Select.prototype.removeItemAt = function(index) {
  goog.ui.Select.superClass_.removeItemAt.call(this, index);
  if (this.selectionModel_) {
    this.selectionModel_.removeItemAt(index);
  }
};

/**
 * Selects the specified option (assumed to be in the select menu), and
 * deselects the previously selected option, if any.  A null argument clears
 * the selection.
 * @param {goog.ui.MenuItem} item Option to be selected (null to clear
 *     the selection).
 */
goog.ui.Select.prototype.setSelectedItem = function(item) {
  if (this.selectionModel_) {
    this.selectionModel_.setSelectedItem(item);
  }
};

/**
 * Selects the option at the specified index, or clears the selection if the
 * index is out of bounds.
 * @param {number} index Index of the option to be selected.
 */
goog.ui.Select.prototype.setSelectedIndex = function(index) {
  if (this.selectionModel_) {
    this.setSelectedItem(/** @type {goog.ui.MenuItem} */
        (this.selectionModel_.getItemAt(index)));
  }
};

/**
 * Selects the first option found with an associated value equal to the
 * argument, or clears the selection if no such option is found.  A null
 * argument also clears the selection.  Overrides {@link
 * goog.ui.Button#setValue}.
 * @param {*} value Value of the option to be selected (null to clear
 *     the selection).
 */
goog.ui.Select.prototype.setValue = function(value) {
  if (goog.isDefAndNotNull(value) && this.selectionModel_) {
    for (var i = 0, item; item = this.selectionModel_.getItemAt(i); i++) {
      if (item && typeof item.getValue == 'function' &&
          item.getValue() == value) {
        this.setSelectedItem(/** @type {goog.ui.MenuItem} */ (item));
        return;
      }
    }
  }

  this.setSelectedItem(null);
};

/**
 * Returns the currently selected option.
 * @return {goog.ui.MenuItem} The currently selected option (null if none).
 */
goog.ui.Select.prototype.getSelectedItem = function() {
  return this.selectionModel_ ?
      /** @type {goog.ui.MenuItem} */ (this.selectionModel_.getSelectedItem()) :
      null;
};

/**
 * Returns the index of the currently selected option.
 * @return {number} 0-based index of the currently selected option (-1 if none).
 */
goog.ui.Select.prototype.getSelectedIndex = function() {
  return this.selectionModel_ ? this.selectionModel_.getSelectedIndex() : -1;
};

/**
 * @return {goog.ui.SelectionModel} The selection model.
 * @protected
 */
goog.ui.Select.prototype.getSelectionModel = function() {
  return this.selectionModel_;
};

/**
 * Creates a new selection model and sets up an event listener to handle
 * {@link goog.events.EventType.SELECT} events dispatched by it.
 * @param {goog.ui.Component=} opt_component If provided, will add the
 *     component's children as items to the selection model.
 * @private
 */
goog.ui.Select.prototype.createSelectionModel_ = function(opt_component) {
  this.selectionModel_ = new goog.ui.SelectionModel();
  if (opt_component) {
    opt_component.forEachChild(function(child, index) {
      this.setCorrectAriaRole_(child);
      this.selectionModel_.addItem(child);
    }, this);
  }
  this.listenToSelectionModelEvents_();
};

/**
 * Subscribes to events dispatched by the selection model.
 * @private
 */
goog.ui.Select.prototype.listenToSelectionModelEvents_ = function() {
  if (this.selectionModel_) {
    this.getHandler().listen(this.selectionModel_, goog.events.EventType.SELECT,
        this.handleSelectionChange);
  }
};

/**
 * Updates the caption to be shown in the select button.  If no option is
 * selected and a default caption is set, sets the caption to the default
 * caption; otherwise to the empty string.
 * @protected
 */
goog.ui.Select.prototype.updateCaption = function() {
  var item = this.getSelectedItem();
  this.setContent(item ? item.getCaption() : this.defaultCaption_);
};

/**
 * Sets the correct ARIA role for the menu item or separator.
 * @param {goog.ui.MenuItem|goog.ui.MenuSeparator} item The item to set.
 * @private
 */
goog.ui.Select.prototype.setCorrectAriaRole_ = function(item) {
  item.setPreferredAriaRole(item instanceof goog.ui.MenuItem ?
      goog.dom.a11y.Role.OPTION : goog.dom.a11y.Role.SEPARATOR);
};

/**
 * Opens or closes the menu.  Overrides {@link goog.ui.MenuButton#setOpen} by
 * highlighting the currently selected option on open.
 * @param {boolean} open Whether to open or close the menu.
 * @param {goog.events.Event=} opt_e Mousedown event that caused the menu to
 *     be opened.
 * @override
 */
goog.ui.Select.prototype.setOpen = function(open, opt_e) {
  goog.ui.Select.superClass_.setOpen.call(this, open, opt_e);

  if (this.isOpen()) {
    this.getMenu().setHighlightedIndex(this.getSelectedIndex());
  }
};

// Register a decorator factory function for goog.ui.Selects.
goog.ui.registry.setDecoratorByClassName(
    goog.getCssName('goog-select'), function() {
      // Select defaults to using MenuButtonRenderer, since it shares its L&F.
      return new goog.ui.Select(null);
    });
<|endoftext|>