<commit_before>/**
* This file is part of taolin project (http://taolin.fbk.eu)
* Copyright (C) 2008, 2009 FBK Foundation, (http://www.fbk.eu)
* Authors: SoNet Group (see AUTHORS.txt)
*
* Taolin is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation version 3 of the License.
*
* Taolin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Taolin. If not, see <http://www.gnu.org/licenses/>.
*
*/

/**
  * Ext.ux.fbk.sonet.BuddyList Extension Class
  *
  * @author  Davide Setti
  * @version 1.0
  * @class Ext.ux.fbk.sonet.BuddyList
  *
This widget show the user connected to the jabber server

*/

var fancyPresenceDict = {
    dnd: 'do not disturb'
};

var roster = {
  // Online buddies
  online: [],
  // Full roster
  roster: [],
  setPresence: function (jid, presence, status, type) {
    var fm = Ext.util.Format;
    //console.log('setPresence');
    if ((type !== 'unavailable') && (!this.roster.length)){
        //console.log('storing');
        var b = new Buddy(jid, '', '', '', presence, status, type);
        return;
    }

    // this is a dirty way to put ME inside the buddylist
    // the problem is that ME is not sent in the roster, but only as presence/status
    if (jid == jabber.myJid){
        try {
            for (var i=0, x; x = this.roster[i++];) {
                if (x.jid == jid)
                    throw "JidAlreadyPresentException";
            }
            for (var i=0, x; x = this.online[i++];) {
                if (x.jid == jid)
                    throw "JidAlreadyPresentException";
            }
            // if we're here, Me is not present in roster.roster or roster.online
            var b = new Buddy(jid, '', '', 'Me', presence, status, type);
            this.roster.push(b);
        } catch (e) {}
    }

    // If the buddy comes online, move them to 'online'
    if (type != 'unavailable') {
      for (var i=0, x; x = this.roster[i++];) {
        if (x.jid == jid) {
          this.online.push(x);
          this.roster.remove(x);
          break;
        }
      }
    }
    var sBulletPresence = (type === 'unavailable') ? 'unavailable' : presence
        ,sStyleBg = 'url(js/portal/shared/icons/fam/'+ hBullets[sBulletPresence] +') left no-repeat';

    //TODO: THIS IS REALLY SLOW! TAKES ~0.05s ON A CORE2DUO AND FF3.6
    var sCssClass = 'user-' + (jid.split('@'))[0];
    // IE wants DIV, FF div... and the others? It's better to try to get both instead of using Ext.isIE
    var rule = 'body .'+ sCssClass;

    if (!Ext.util.CSS.updateRule(rule, 'background', sStyleBg)) { // if no cssClass has been found, create it
        var s = rule +" {\n}";
        Ext.util.CSS.createStyleSheet(s, rule);
        Ext.util.CSS.refreshCache();

        // now we need to get the class, so we can change its style
        Ext.util.CSS.updateRule(rule, 'background', sStyleBg);
    }

    var online = this.online;
    for (var i=online.length-1, buddy, fancyPresence; i>=0; --i) {
        buddy = online[i];
        if (buddy.jid === jid) {
            fancyPresence = presence;
            if (presence in fancyPresenceDict)
                fancyPresence = fancyPresenceDict[presence];

            Ext.apply(buddy, {
                presence: presence
                ,fancyPresence: fancyPresence
                ,status: fm.htmlEncode(status)
                ,fancyStatus: fm.htmlEncode(status).smilize().urlize()
                ,type: type
            });

            // If the buddy goes offline, remove from online list
            if (type === 'unavailable') {
                online.remove(buddy);
                this.roster.push(buddy);
            }
            break;
      }
    }
    rosterStore.load();
  },
  clear: function () {
    this.online = [];
    this.roster = [];
    rosterStore.load();
  }
};

rosterStore = new Ext.data.GroupingStore({
  id: 'rosterStore',
  proxy: new Ext.data.MemoryProxy(roster),
  reader: new Ext.data.JsonReader({
    root: 'online'
    },[
      {name: 'jid'},
      {name: 'subscription'},
      {name: 'name'},
      {name: 'group'},
      {name: 'presence'},
      {name: 'status'},
      {name: 'fancyStatus'},
      {name: 'fancyPresence'}
  ]),
  sortInfo: {field: 'jid', direction: "ASC"},
  groupField: 'group'
});
/*
rosterStore.on('loadexception', function(proxy, store, response, e) {
    console.log('loadexception: ' + e.message);
});
*/

BuddyList = function(conf, panel_conf) {
    Ext.apply(this, panel_conf);

    this.conf = conf;

    BuddyList.superclass.constructor.call(this, {
        id:'buddylist',
        collapsible: true,
        autoHeight: true,
        header: false,
        buddyTpl: new Ext.XTemplate(
            '

'
                ,''
                    ,'
{jid}'
                        ,'<tpl if="presence">'
                            ,'{fancyPresence}'
                        ,'</tpl>'
                    ,'
'
                    ,'<tpl if="status">'
                        ,'
'
                            ,'{fancyStatus}'
                        ,'
'
                    ,'</tpl>'
                ,'	'
                ,'<tpl if="showPhoto">'
                ,''
                    ,''
                ,'	'
                ,'</tpl>'
            ,'

'
            ,{
                compiled: true
                ,disableFormats: true
            }
        ),
        listeners: {
            resize : {
                fn: function(panel, panelWidth, panelHeight){
                    var gp = this.gridPanel;
                    gp.setWidth(panelWidth);
                },
                scope: this
            }
        },
        items: [
            new Ext.grid.GridPanel({
              store: rosterStore,
              autoHeight: true,
              draggable: false,
              hideHeaders: true,
              parent: this,
              columns: [{
                id: 'jid',
                dataIndex: 'jid',
                buddyList: this,
                myIndex: 0,
                renderer: function (value, p, record) {
                    var data = $.extend(record.data, {showPhoto: this.buddyList.conf.showPhoto});
                    return this.buddyList.buddyTpl.applyTemplate(data);
                }},
                {dataIndex: 'group', hidden: true},
                {dataIndex: 'presence', hidden: true},
                {dataIndex: 'subscription', hidden: true},
                {dataIndex: 'status', hidden: true},
                {dataIndex: 'fancyStatus', hidden: true}
              ],
              view: new Ext.grid.GroupingView({
                forceFit: true,
                scrollOffset:2,
                showGroupName: false,
                rowSelectorDepth: 12,
                groupTextTpl: '{text} ({values.rs.length:plural("Buddy", "Buddies")})',
                deferEmptyText: false,
                emptyText: 'Loading...'
              }),
              cls: 'blist-grid',
              listeners: {
                rowclick: function() {
                    var buddy = this.getSelectionModel().getSelected().data;
                    if(jabber.myJid != buddy.jid)
                        jabberui.createNewChatWindow(buddy.jid);
                    getIdFromJidNode(buddy.jid);
                },
                resize : {
                    fn: function(panel, panelWidth, panelHeight){
                        var presence = Ext.getCmp('presence')
                            ,status = Ext.getCmp('status')
                            ,width = panelWidth - (presence.width + 20); // Status's width
                        if(width) // Check wether "width" is not NaN but a real number
                            status.setWidth(width);
                    },
                    scope: this
                }
              },
              tbar: [new Ext.ux.IconCombo({
                  id: 'presence',
                  //name: 'presence',
                  width: 100,
                  listWidth: 130,
                  store: new Ext.data.SimpleStore({
                    fields: ['presence', 'readablePresence', 'iconClass'],
                    data: [
                      ['', 'Available', 'buddyliststate']
                      ,['away', 'Away', 'buddyliststateaway']
                      ,['dnd', 'Do not disturb', 'buddyliststatednd']
                      ,['invisible', 'Invisible', 'buddyliststateinvisible']
                      //,['chat', 'Chatty']
                      //,['unavailable', 'Offline']
                    ]
                  }),
                  panel: this,
                  value:get(conf, 'presence', ''),
                  displayField: 'readablePresence',
                  valueField: 'presence',
                  iconClsField: 'iconClass',
                  mode: 'local',
                  forceSelection: true,
                  triggerAction: 'all',
                  editable: false,
                  listeners: {
                    render: function (combo) {
                        combo.initFlags();
                        //combo.setValue(combo.store.collect('presence', true)[0]);
                    },
                    select: function (combo) {
                      var status = Ext.getCmp('status').getValue()
                        ,presence = combo.getValue()
                        ,type;

                      //store in DB
                      this.panel.setPref('presence', presence);

                      //this XEP isn't very linear...
                      if (presence == 'invisible') {
                        presence = '';
                        type = 'invisible';
                      }

                      jabber.setPresence(combo.getValue(), status, type);
                    }
                  }
                }), ' ',
                new Ext.form.ComboBox({
                  id: 'status'
                  ,emptyText: 'Set status message'
                  ,store: new Ext.data.SimpleStore({
                    fields: ['status']
                    ,data: [[conf.status]] // TODO: Change this in an array
                  })
                  ,displayField: 'status'
                  ,value: conf.status
                  ,panel: this
                  ,mode: 'local'
                  ,width: 145
                  ,queryDelay: 500
                  ,hideLabel: true
                  ,triggerAction: 'all'
                  ,cls:'buddylist-status-field'
                  ,focusClass:'buddylist-status-focus'
                  ,recordType:Ext.data.Record.create(['status'])
                  ,loseFocus: function () {
                     Ext.getCmp('presence').focus();
                     this.fireEvent("blur", this);
                  }
                  //,enableKeyEvents:true
                  // this should go into listeners.keyup, but there are problems in Ext 2.2
                  ,onKeyUp: function (e) {
                      this.collapse();
                      if (e.getKey() == Ext.EventObject.ENTER) {
                        var status = Ext.getCmp('status')
                            ,sPresence = Ext.getCmp('presence').getValue()
                            ,sStatus = status.getEl().dom.value;

                        rec = new status.recordType({status: sStatus});
                        Ext.getCmp('status').store.add(rec);

                        //store in DB
                        this.panel.setPref('status', sStatus, reloadTimeline);

                        //change jabber status
                        jabber.setPresence(sPresence, sStatus);
                        this.loseFocus();
                      }
                      e.stopEvent();
                  }
                  ,listeners: {
                    blur: function (t) {
                        if(!Ext.isOpera && t.focusClass){ // don't touch in Opera
                            t.el.removeClass(t.focusClass);
                        }
                    }
                    ,select: function (combo, record, index) { //change status from drop down menu
                        var presence = Ext.getCmp('presence').getValue()
                            ,status = record.get('status');

                        //store in DB
                        combo.panel.setPref('status', status, reloadTimeline);

                        //change jabber status
                        jabber.setPresence(presence, status);
                    }
                    ,render: function(t){

                        var presence, status, type
                            ,cPresence = Ext.getCmp('presence');

                        if (cPresence.value == 'invisible'){
                            presence = '';
                            type = 'invisible';
                        } else {
                            presence = cPresence.value;
                        }

                        status = t.value ? t.value : '';

                        jabberui.init(presence, status, type);
                    }
                    ,beforedestroy: function(t){
                        jabber.quit();
                    }
                  }
                })]
            })]
    });

    var gp = this.items.first();
    this.gridPanel = gp;
    gp.store.on('load', function() {
        if (this.view) {
            Ext.getCmp('buddylist').gridPanel.view.emptyText = 'Nobody online or there has been problems connecting to the server.

Click here to try again. If you changed your password recently, please logout and login again with the new password.';
        }
    }, gp);
};

Ext.extend(BuddyList, Ext.Panel);

//Ext.reg('buddylist', BuddyList);
<commit_msg>remove not needed check<commit_after>/**
* This file is part of taolin project (http://taolin.fbk.eu)
* Copyright (C) 2008, 2009 FBK Foundation, (http://www.fbk.eu)
* Authors: SoNet Group (see AUTHORS.txt)
*
* Taolin is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation version 3 of the License.
*
* Taolin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Taolin. If not, see <http://www.gnu.org/licenses/>.
*
*/

/**
  * Ext.ux.fbk.sonet.BuddyList Extension Class
  *
  * @author  Davide Setti
  * @version 1.0
  * @class Ext.ux.fbk.sonet.BuddyList
  *
This widget show the user connected to the jabber server

*/

var fancyPresenceDict = {
    dnd: 'do not disturb'
};

var roster = {
  // Online buddies
  online: [],
  // Full roster
  roster: [],
  setPresence: function (jid, presence, status, type) {
    var fm = Ext.util.Format;
    if (!this.roster.length){
        return;
    }

    // this is a dirty way to put ME inside the buddylist
    // the problem is that ME is not sent in the roster, but only as presence/status
    if (jid == jabber.myJid){
        try {
            for (var i=0, x; x = this.roster[i++];) {
                if (x.jid == jid)
                    throw "JidAlreadyPresentException";
            }
            for (var i=0, x; x = this.online[i++];) {
                if (x.jid == jid)
                    throw "JidAlreadyPresentException";
            }
            // if we're here, Me is not present in roster.roster or roster.online
            var b = new Buddy(jid, '', '', 'Me', presence, status, type);
            this.roster.push(b);
        } catch (e) {}
    }

    // If the buddy comes online, move them to 'online'
    if (type != 'unavailable') {
      for (var i=0, x; x = this.roster[i++];) {
        if (x.jid == jid) {
          this.online.push(x);
          this.roster.remove(x);
          break;
        }
      }
    }
    var sBulletPresence = (type === 'unavailable') ? 'unavailable' : presence
        ,sStyleBg = 'url(js/portal/shared/icons/fam/'+ hBullets[sBulletPresence] +') left no-repeat';

    //TODO: THIS IS REALLY SLOW! TAKES ~0.05s ON A CORE2DUO AND FF3.6
    var sCssClass = 'user-' + (jid.split('@'))[0];
    // IE wants DIV, FF div... and the others? It's better to try to get both instead of using Ext.isIE
    var rule = 'body .'+ sCssClass;

    if (!Ext.util.CSS.updateRule(rule, 'background', sStyleBg)) { // if no cssClass has been found, create it
        var s = rule +" {\n}";
        Ext.util.CSS.createStyleSheet(s, rule);
        Ext.util.CSS.refreshCache();

        // now we need to get the class, so we can change its style
        Ext.util.CSS.updateRule(rule, 'background', sStyleBg);
    }

    var online = this.online;
    for (var i=online.length-1, buddy, fancyPresence; i>=0; --i) {
        buddy = online[i];
        if (buddy.jid === jid) {
            fancyPresence = presence;
            if (presence in fancyPresenceDict)
                fancyPresence = fancyPresenceDict[presence];

            Ext.apply(buddy, {
                presence: presence
                ,fancyPresence: fancyPresence
                ,status: fm.htmlEncode(status)
                ,fancyStatus: fm.htmlEncode(status).smilize().urlize()
                ,type: type
            });

            // If the buddy goes offline, remove from online list
            if (type === 'unavailable') {
                online.remove(buddy);
                this.roster.push(buddy);
            }
            break;
      }
    }
    rosterStore.load();
  },
  clear: function () {
    this.online = [];
    this.roster = [];
    rosterStore.load();
  }
};

rosterStore = new Ext.data.GroupingStore({
  id: 'rosterStore',
  proxy: new Ext.data.MemoryProxy(roster),
  reader: new Ext.data.JsonReader({
    root: 'online'
    },[
      {name: 'jid'},
      {name: 'subscription'},
      {name: 'name'},
      {name: 'group'},
      {name: 'presence'},
      {name: 'status'},
      {name: 'fancyStatus'},
      {name: 'fancyPresence'}
  ]),
  sortInfo: {field: 'jid', direction: "ASC"},
  groupField: 'group'
});
/*
rosterStore.on('loadexception', function(proxy, store, response, e) {
    console.log('loadexception: ' + e.message);
});
*/

BuddyList = function(conf, panel_conf) {
    Ext.apply(this, panel_conf);

    this.conf = conf;

    BuddyList.superclass.constructor.call(this, {
        id:'buddylist',
        collapsible: true,
        autoHeight: true,
        header: false,
        buddyTpl: new Ext.XTemplate(
            '

'
                ,''
                    ,'
{jid}'
                        ,'<tpl if="presence">'
                            ,'{fancyPresence}'
                        ,'</tpl>'
                    ,'
'
                    ,'<tpl if="status">'
                        ,'
'
                            ,'{fancyStatus}'
                        ,'
'
                    ,'</tpl>'
                ,'	'
                ,'<tpl if="showPhoto">'
                ,''
                    ,''
                ,'	'
                ,'</tpl>'
            ,'

'
            ,{
                compiled: true
                ,disableFormats: true
            }
        ),
        listeners: {
            resize : {
                fn: function(panel, panelWidth, panelHeight){
                    var gp = this.gridPanel;
                    gp.setWidth(panelWidth);
                },
                scope: this
            }
        },
        items: [
            new Ext.grid.GridPanel({
              store: rosterStore,
              autoHeight: true,
              draggable: false,
              hideHeaders: true,
              parent: this,
              columns: [{
                id: 'jid',
                dataIndex: 'jid',
                buddyList: this,
                myIndex: 0,
                renderer: function (value, p, record) {
                    var data = $.extend(record.data, {showPhoto: this.buddyList.conf.showPhoto});
                    return this.buddyList.buddyTpl.applyTemplate(data);
                }},
                {dataIndex: 'group', hidden: true},
                {dataIndex: 'presence', hidden: true},
                {dataIndex: 'subscription', hidden: true},
                {dataIndex: 'status', hidden: true},
                {dataIndex: 'fancyStatus', hidden: true}
              ],
              view: new Ext.grid.GroupingView({
                forceFit: true,
                scrollOffset:2,
                showGroupName: false,
                rowSelectorDepth: 12,
                groupTextTpl: '{text} ({values.rs.length:plural("Buddy", "Buddies")})',
                deferEmptyText: false,
                emptyText: 'Loading...'
              }),
              cls: 'blist-grid',
              listeners: {
                rowclick: function() {
                    var buddy = this.getSelectionModel().getSelected().data;
                    if(jabber.myJid != buddy.jid)
                        jabberui.createNewChatWindow(buddy.jid);
                    getIdFromJidNode(buddy.jid);
                },
                resize : {
                    fn: function(panel, panelWidth, panelHeight){
                        var presence = Ext.getCmp('presence')
                            ,status = Ext.getCmp('status')
                            ,width = panelWidth - (presence.width + 20); // Status's width
                        if(width) // Check wether "width" is not NaN but a real number
                            status.setWidth(width);
                    },
                    scope: this
                }
              },
              tbar: [new Ext.ux.IconCombo({
                  id: 'presence',
                  //name: 'presence',
                  width: 100,
                  listWidth: 130,
                  store: new Ext.data.SimpleStore({
                    fields: ['presence', 'readablePresence', 'iconClass'],
                    data: [
                      ['', 'Available', 'buddyliststate']
                      ,['away', 'Away', 'buddyliststateaway']
                      ,['dnd', 'Do not disturb', 'buddyliststatednd']
                      ,['invisible', 'Invisible', 'buddyliststateinvisible']
                      //,['chat', 'Chatty']
                      //,['unavailable', 'Offline']
                    ]
                  }),
                  panel: this,
                  value:get(conf, 'presence', ''),
                  displayField: 'readablePresence',
                  valueField: 'presence',
                  iconClsField: 'iconClass',
                  mode: 'local',
                  forceSelection: true,
                  triggerAction: 'all',
                  editable: false,
                  listeners: {
                    render: function (combo) {
                        combo.initFlags();
                        //combo.setValue(combo.store.collect('presence', true)[0]);
                    },
                    select: function (combo) {
                      var status = Ext.getCmp('status').getValue()
                        ,presence = combo.getValue()
                        ,type;

                      //store in DB
                      this.panel.setPref('presence', presence);

                      //this XEP isn't very linear...
                      if (presence == 'invisible') {
                        presence = '';
                        type = 'invisible';
                      }

                      jabber.setPresence(combo.getValue(), status, type);
                    }
                  }
                }), ' ',
                new Ext.form.ComboBox({
                  id: 'status'
                  ,emptyText: 'Set status message'
                  ,store: new Ext.data.SimpleStore({
                    fields: ['status']
                    ,data: [[conf.status]] // TODO: Change this in an array
                  })
                  ,displayField: 'status'
                  ,value: conf.status
                  ,panel: this
                  ,mode: 'local'
                  ,width: 145
                  ,queryDelay: 500
                  ,hideLabel: true
                  ,triggerAction: 'all'
                  ,cls:'buddylist-status-field'
                  ,focusClass:'buddylist-status-focus'
                  ,recordType:Ext.data.Record.create(['status'])
                  ,loseFocus: function () {
                     Ext.getCmp('presence').focus();
                     this.fireEvent("blur", this);
                  }
                  //,enableKeyEvents:true
                  // this should go into listeners.keyup, but there are problems in Ext 2.2
                  ,onKeyUp: function (e) {
                      this.collapse();
                      if (e.getKey() == Ext.EventObject.ENTER) {
                        var status = Ext.getCmp('status')
                            ,sPresence = Ext.getCmp('presence').getValue()
                            ,sStatus = status.getEl().dom.value;

                        rec = new status.recordType({status: sStatus});
                        Ext.getCmp('status').store.add(rec);

                        //store in DB
                        this.panel.setPref('status', sStatus, reloadTimeline);

                        //change jabber status
                        jabber.setPresence(sPresence, sStatus);
                        this.loseFocus();
                      }
                      e.stopEvent();
                  }
                  ,listeners: {
                    blur: function (t) {
                        if(!Ext.isOpera && t.focusClass){ // don't touch in Opera
                            t.el.removeClass(t.focusClass);
                        }
                    }
                    ,select: function (combo, record, index) { //change status from drop down menu
                        var presence = Ext.getCmp('presence').getValue()
                            ,status = record.get('status');

                        //store in DB
                        combo.panel.setPref('status', status, reloadTimeline);

                        //change jabber status
                        jabber.setPresence(presence, status);
                    }
                    ,render: function(t){

                        var presence, status, type
                            ,cPresence = Ext.getCmp('presence');

                        if (cPresence.value == 'invisible'){
                            presence = '';
                            type = 'invisible';
                        } else {
                            presence = cPresence.value;
                        }

                        status = t.value ? t.value : '';

                        jabberui.init(presence, status, type);
                    }
                    ,beforedestroy: function(t){
                        jabber.quit();
                    }
                  }
                })]
            })]
    });

    var gp = this.items.first();
    this.gridPanel = gp;
    gp.store.on('load', function() {
        if (this.view) {
            Ext.getCmp('buddylist').gridPanel.view.emptyText = 'Nobody online or there has been problems connecting to the server.

Click here to try again. If you changed your password recently, please logout and login again with the new password.';
        }
    }, gp);
};

Ext.extend(BuddyList, Ext.Panel);

//Ext.reg('buddylist', BuddyList);
<|endoftext|>


<commit_before>/**
 * Created by Wayne on 16/3/16.
 */

'use strict';

var tender = require('../controllers/tender'),
  driverFilter = require('../../../libraries/filters/driver'),
  tenderPayment = require('../controllers/tender_payment');

module.exports = function (app) {
  app.route('/tender/driver/getWechatPayToken').post(driverFilter.requireDriver,tenderPayment.getWechatPayToken);
  app.route('/tender/driver/test_notifiy_url').get(tenderPayment.test_notifiy_url);
};
<commit_msg>Update for test<commit_after>/**
 * Created by Wayne on 16/3/16.
 */

'use strict';

var tender = require('../controllers/tender'),
  driverFilter = require('../../../libraries/filters/driver'),
  tenderPayment = require('../controllers/tender_payment');

module.exports = function (app) {
  app.route('/tender/driver/getWechatPayToken').post(driverFilter.requireDriver, tenderPayment.getWechatPayToken);
  app.route('/tender/driver/test_notifiy_url').get(tenderPayment.test_notifiy_url);
  app.route('/tender/driver/test_notifiy_url').post(tenderPayment.test_notifiy_url);
};
<|endoftext|>


<commit_before>const R = require('ramda');
const BigNumber = require('bignumber.js');

const BrehonContract = artifacts.require('./BrehonContract.sol');
const defaults = require('../config/deployment_settings.js').defaults;

const contractHelpers = require('../lib/contractHelpers.js');

const startContract = contractHelpers.startContract;
const fastForwardTime = contractHelpers.fastForwardTime;
const raiseDispute = contractHelpers.raiseDispute;
const assertError = contractHelpers.assertError;
const assertNoError = contractHelpers.assertNoError;
const assertNoErrorWithMsg = assertNoError(false, 'No Exception must be thrown');
const vAssertNoErrorWithMsg = assertNoError(true, 'No Exception must be thrown');
const StagesEnum = contractHelpers.StagesEnum;
const startContractAndRaiseDispute = contractHelpers.startContractAndRaiseDispute;
const verifyEvent = contractHelpers.verifyEvent;
const getMinimumContractAmt = contractHelpers.getMinimumContractAmt;
const getSplitForPrimaryBrehon = contractHelpers.getPercentageSplit(defaults, 0);

/**
 * Spec:
 * + Must use verifyEvent method
 * + Error verification should happen via assertError
 * - Must check for all stages
 **/

contract('BrehonContract claimFunds should only be allowed at one of the conflict resolved stages', (accounts) => {
  it('by preventing it from being called at Negotiation stage', () => {
    let brehonContract;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(function claimFunds() {
        return brehonContract.claimFunds(
            {from: defaults.partyB_addr}
        );
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered during the Negotiation state'));
  });
});

contract('BrehonContract claimFunds should only be allowed at one of the conflict resolved stages', (accounts) => {
  it('by preventing it from being called at Execution stage', () => {
    var brehonContract;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContract(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults)
        }], defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function claimFunds() {
        return brehonContract.claimFunds(
            {from: defaults.partyB_addr}
        );
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered during the Execution state'));
  });
});

contract('BrehonContract should allow partyA to be able to withdraw funds', (accounts) => {
  const settlement = {
    'partyA': getSplitForPrimaryBrehon(60),
    'partyB': getSplitForPrimaryBrehon(40)
  };
  const sufficientTime = 60 * 60 * 24 * 5;
  it('after appealPeriod', () => {
    let brehonContract,
      startingBalance;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults)
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          {from: defaults.primaryBrehon_addr}
        );
      })
      .then(() => {
        startingBalance = web3.eth.getBalance(defaults.partyA_addr);
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, sufficientTime))
      .catch(assertNoErrorWithMsg)
      .then(function claimFunds() {
        return brehonContract.claimFunds(
            {from: defaults.partyA_addr}
        );
      })
      .then((result) => {
        const newBalance = web3.eth.getBalance(defaults.partyA_addr);
        const tx = web3.eth.getTransaction(result.tx)
        const block = web3.eth.getBlock(tx.blockNumber);
        const gasPaid = new BigNumber(block.gasUsed).mul(tx.gasPrice);
        assert.isTrue(startingBalance.minus(gasPaid).plus(settlement.partyA).eq(newBalance));
      })
      .catch(assertNoErrorWithMsg);
  });
});

contract('BrehonContract should not allow partyA to be able to withdraw funds', (accounts) => {
  const settlement = {
    'partyA': getSplitForPrimaryBrehon(60),
    'partyB': getSplitForPrimaryBrehon(40)
  };
  const insufficientTime = 60 * 60 * 24 * 2;
  it('before appealPeriod', () => {
    let brehonContract,
      startingBalance;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults)
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          {from: defaults.primaryBrehon_addr}
        );
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, insufficientTime))
      .then(function claimFunds() {
        return brehonContract.claimFunds(
            {from: defaults.partyA_addr}
        );
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered before the appealPeriod was over'));
  });
});

contract('BrehonContract should allow partyB to be able to withdraw funds', (accounts) => {
  const settlement = {
    'partyA': getSplitForPrimaryBrehon(60),
    'partyB': getSplitForPrimaryBrehon(40)
  };
  const sufficientTime = 60 * 60 * 24 * 5;
  it('after appealPeriod', () => {
    let brehonContract,
      startingBalance;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults)
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          {from: defaults.primaryBrehon_addr}
        );
      })
      .then(() => {
        startingBalance = web3.eth.getBalance(defaults.partyB_addr);
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, sufficientTime))
      .catch(assertNoErrorWithMsg)
      .then(function claimFunds() {
        return brehonContract.claimFunds(
            {from: defaults.partyB_addr}
        );
      })
      .then((result) => {
        const newBalance = web3.eth.getBalance(defaults.partyB_addr);
        const tx = web3.eth.getTransaction(result.tx)
        const block = web3.eth.getBlock(tx.blockNumber);
        const gasPaid = new BigNumber(block.gasUsed).mul(tx.gasPrice);
        assert.isTrue(startingBalance.minus(gasPaid).plus(settlement.partyB).eq(newBalance));
      })
      .catch(assertNoErrorWithMsg);
  });
});

contract('BrehonContract should not allow partyB to be able to withdraw funds', (accounts) => {
  const settlement = {
    'partyA': getSplitForPrimaryBrehon(60),
    'partyB': getSplitForPrimaryBrehon(40)
  };
  const insufficientTime = 60 * 60 * 24 * 2;
  it('before appealPeriod', () => {
    let brehonContract,
      startingBalance;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults)
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          {from: defaults.primaryBrehon_addr}
        );
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, insufficientTime))
      .then(function claimFunds() {
        return brehonContract.claimFunds(
            {from: defaults.partyB_addr}
        );
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered before the appealPeriod was over'));
  });
});
<commit_msg>- Eslint cleanup + added a method to test claiming of funds after a settlement is reached - placeholder for now<commit_after>const BigNumber = require('bignumber.js');

const BrehonContract = artifacts.require('./BrehonContract.sol');
const defaults = require('../config/deployment_settings.js').defaults;

const contractHelpers = require('../lib/contractHelpers.js');

const startContract = contractHelpers.startContract;
const fastForwardTime = contractHelpers.fastForwardTime;
const assertError = contractHelpers.assertError;
const assertNoError = contractHelpers.assertNoError;
const assertNoErrorWithMsg = assertNoError(false, 'No Exception must be thrown');
const StagesEnum = contractHelpers.StagesEnum;
const startContractAndRaiseDispute = contractHelpers.startContractAndRaiseDispute;
const verifyEvent = contractHelpers.verifyEvent;
const getMinimumContractAmt = contractHelpers.getMinimumContractAmt;
const getSplitForPrimaryBrehon = contractHelpers.getPercentageSplit(defaults, 0);

/**
 * Spec:
 * + Must use verifyEvent method
 * + Error verification should happen via assertError
 * - Must check for all stages
 **/

contract('BrehonContract claimFunds should only be allowed at one of the conflict resolved stages', () => {
  it('by preventing it from being called at Negotiation stage', () => {
    let brehonContract;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(function claimFunds() {
        return brehonContract.claimFunds({ from: defaults.partyB_addr });
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered during the Negotiation state'));
  });
});

contract('BrehonContract claimFunds should only be allowed at one of the conflict resolved stages', () => {
  it('by preventing it from being called at Execution stage', () => {
    let brehonContract;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContract(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults),
        }], defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function claimFunds() {
        return brehonContract.claimFunds({ from: defaults.partyB_addr });
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered during the Execution state'));
  });
});

contract('BrehonContract should allow partyA to be able to withdraw funds', () => {
  const settlement = {
    partyA: getSplitForPrimaryBrehon(60),
    partyB: getSplitForPrimaryBrehon(40),
  };
  const sufficientTime = 60 * 60 * 24 * 5;
  it('after appealPeriod', () => {
    let brehonContract;
    let startingBalance;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults),
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          { from: defaults.primaryBrehon_addr });
      })
      .then(() => {
        startingBalance = web3.eth.getBalance(defaults.partyA_addr);
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, sufficientTime))
      .catch(assertNoErrorWithMsg)
      .then(function claimFunds() {
        return brehonContract.claimFunds({ from: defaults.partyA_addr });
      })
      .then((result) => {
        const newBalance = web3.eth.getBalance(defaults.partyA_addr);
        const tx = web3.eth.getTransaction(result.tx);
        const block = web3.eth.getBlock(tx.blockNumber);
        const gasPaid = new BigNumber(block.gasUsed).mul(tx.gasPrice);
        assert.isTrue(startingBalance.minus(gasPaid).plus(settlement.partyA).eq(newBalance));
      })
      .catch(assertNoErrorWithMsg);
  });
});

contract('BrehonContract should not allow partyA to be able to withdraw funds', () => {
  const settlement = {
    partyA: getSplitForPrimaryBrehon(60),
    partyB: getSplitForPrimaryBrehon(40),
  };
  const insufficientTime = 60 * 60 * 24 * 2;
  it('before appealPeriod', () => {
    let brehonContract;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults),
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          { from: defaults.primaryBrehon_addr });
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, insufficientTime))
      .then(function claimFunds() {
        return brehonContract.claimFunds({ from: defaults.partyA_addr });
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered before the appealPeriod was over'));
  });
});

contract('BrehonContract should allow partyB to be able to withdraw funds', () => {
  const settlement = {
    partyA: getSplitForPrimaryBrehon(60),
    partyB: getSplitForPrimaryBrehon(40),
  };
  const sufficientTime = 60 * 60 * 24 * 5;
  it('after appealPeriod', () => {
    let brehonContract;
    let startingBalance;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults),
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          { from: defaults.primaryBrehon_addr });
      })
      .then(() => {
        startingBalance = web3.eth.getBalance(defaults.partyB_addr);
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, sufficientTime))
      .catch(assertNoErrorWithMsg)
      .then(function claimFunds() {
        return brehonContract.claimFunds({ from: defaults.partyB_addr });
      })
      .then((result) => {
        const newBalance = web3.eth.getBalance(defaults.partyB_addr);
        const tx = web3.eth.getTransaction(result.tx);
        const block = web3.eth.getBlock(tx.blockNumber);
        const gasPaid = new BigNumber(block.gasUsed).mul(tx.gasPrice);
        assert.isTrue(startingBalance.minus(gasPaid).plus(settlement.partyB).eq(newBalance));
      })
      .catch(assertNoErrorWithMsg);
  });
});

contract('BrehonContract should not allow partyB to be able to withdraw funds', () => {
  const settlement = {
    partyA: getSplitForPrimaryBrehon(60),
    partyB: getSplitForPrimaryBrehon(40),
  };
  const insufficientTime = 60 * 60 * 24 * 2;
  it('before appealPeriod', () => {
    let brehonContract;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContractAndRaiseDispute(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults),
        }], defaults.partyA_addr, defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function adjudicate() {
        return brehonContract.adjudicate(
          settlement.partyA,
          settlement.partyB,
          { from: defaults.primaryBrehon_addr });
      })
      .catch(assertNoErrorWithMsg)
      .then(fastForwardTime(web3, insufficientTime))
      .then(function claimFunds() {
        return brehonContract.claimFunds({ from: defaults.partyB_addr });
      })
      .catch(assertError('Exception was not thrown when claimFunds was triggered before the appealPeriod was over'));
  });
});

contract('BrehonContract should allow partyA to withdraw funds after a settlement', () => {
  const settlement = {
    partyA: getSplitForPrimaryBrehon(60),
    partyB: getSplitForPrimaryBrehon(40),
  };
  it('at Execution stage', () => {
    let brehonContract;
    return BrehonContract.deployed()
      .then(function captureReference(instance) {
        brehonContract = instance;
        return instance;
      })
      .then(startContract(
        [{
          addr: defaults.partyA_addr,
          value: getMinimumContractAmt(defaults),
        }], defaults.partyA_addr))
      .catch(assertNoErrorWithMsg)
      .then(function proposeSettlement() {
        return brehonContract.proposeSettlement(
          settlement.partyA,
          settlement.partyB,
          { from: defaults.partyB_addr });
      })
      .catch(assertNoErrorWithMsg)
      .then(function acceptSettlement() {
        return brehonContract.acceptSettlement(
          settlement.partyA,
          settlement.partyB,
          { from: defaults.partyA_addr });
      })
      .then(verifyEvent('DisputeResolved', {
        _awardPartyA: settlement.partyA,
        _awardPartyB: settlement.partyB,
      }))
      .then(function verifyAwards() {
        return brehonContract.getActiveJudgmentByParty.call(defaults.partyA_addr,
          { from: defaults.partyA_addr }).then((award) => {
            assert.equal(award.valueOf(), settlement.partyA.valueOf(), 'acceptSettlement did not correctly set the award');
          });
      })
      .then(function verifyAwards() {
        return brehonContract.getActiveJudgmentByParty.call(defaults.partyB_addr,
          { from: defaults.partyB_addr }).then((award) => {
            assert.equal(award.valueOf(), settlement.partyB.valueOf(), 'acceptSettlement did not correctly set the award');
          });
      })
      .then(function verifyDisputeResolution() {
        return brehonContract.stage.call().then((stage) => {
          assert.equal(stage, StagesEnum.Completed, 'acceptSettlement not correctly changed the state');
        });
      })
      .catch(function handleException(err) {
        console.error(err);
        assert.isNull(err, 'Exception was thrown when partyA tried to accept settlement');
      });
  });
});
<|endoftext|>


<commit_before>module.exports = function (config) {
  return {

    basePath: '../..',

    frameworks: ['mocha'],

    // list of files / patterns to load in the browser
    files: [
      'test/browser-test-config/browser-tests.test.js'
    ],

    preprocessors: {
      '**/*.js': ['webpack']
    },

    captureTimeout: 210000,
    browserDisconnectTolerance: 3, // this one helps
    browserDisconnectTimeout: 210000,
    browserNoActivityTimeout: 210000,

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity,

    webpack: {
      // don't use esm
      mode: 'development',

      resolve: {
        // unless we disallow .mjs files here the tests fail
        // due to decimal.mjs being imported.
        extensions: ['.js', '.json'],
        // same as above, disallow 'module' field to prevent
        // decimal.mjs from breaking tests.
        mainFields: ['browser', 'main']
      },

      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: 'babel-loader'
          }
        ]
      }
    }

  }
}
<commit_msg>chore: update karma config<commit_after>module.exports = function (config) {
  return {

    basePath: '../..',

    frameworks: ['mocha', 'webpack'],

    // list of files / patterns to load in the browser
    files: [
      'test/browser-test-config/browser-tests.test.js'
    ],

    plugins: [
      'karma-webpack',
      'karma-mocha',
      'karma-mocha-reporter',
      'karma-firefox-launcher'
    ],

    preprocessors: {
      '**/*.js': ['webpack']
    },

    captureTimeout: 210000,
    browserDisconnectTolerance: 3, // this one helps
    browserDisconnectTimeout: 210000,
    browserNoActivityTimeout: 210000,

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity,

    webpack: {
      // don't use esm
      mode: 'development',

      resolve: {
        // unless we disallow .mjs files here the tests fail
        // due to decimal.mjs being imported.
        extensions: ['.js', '.json'],
        // same as above, disallow 'module' field to prevent
        // decimal.mjs from breaking tests.
        mainFields: ['browser', 'main']
      },

      module: {
        rules: [
          {
            test: /\.js$/,
            exclude: /node_modules/,
            use: 'babel-loader'
          }
        ]
      }
    }

  }
}
<|endoftext|>


<commit_before>define([
    'dojo/_base/declare',
    'dojo/_base/lang',
    'dojo/has',
    'dojo/_base/array',
    'dojo/date/locale',
    'dojo/number',

    'dojo/store/Memory',
    'dgrid/Grid', // http://dojofoundation.org/packages/dgrid/
    'dgrid/Selection',
    'dgrid/Keyboard',
    'dgrid/extensions/ColumnHider',
    'dgrid/extensions/ColumnReorder',
    'dgrid/extensions/ColumnResizer',
    'dgrid/extensions/Pagination'
], function (
    declare,
    lang,
    has,
    array,
    locale,
    number,

    Memory,
    Grid,
    Selection,
    Keyboard,
    ColumnHider,
    ColumnReorder,
    ColumnResizer,
    Pagination
) {

    return declare(null, {

        gridOptions: {},

        defaultGridOptions: {

            minWidth: 70,

            // no columns, use fields from Query's returned features
            columns: [],

            // no sort
            sort: [],

            // Allow the user to use column sets in grid
            columnSet: false,

            // Allow the user to hide columns in grid
            columnHide: true,

            // Allow the user to reorder columns in grid
            columnReorder: true,

            // Allow the user to resize columns in grid
            columnResize: true,

            // Use pagination on the results grid
            pagination: true,

            paginationOptions: {
                rowsPerPage: 100,
                previousNextArrows: true,
                firstLastArrows: true,
                pagingLinks: 2,
                pagingTextBox: true,
                pageSizeOptions: [10, 25, 50, 100, 250, 500, 1000],
                showLoadingMessage: true
            }
        },

        getGridConfiguration: function (options) {
            this.gridOptions = this.mixinDeep(lang.clone(this.defaultGridOptions), options);
        },

        createGrid: function () {
            if (!this.grid) {
                var gridOptions = {
                    cellNavigation: false,
                    showHeader: true,
                    showFooter: true,
                    adjustLastColumn: true,
                    store: new Memory(),
                    columns: [],
                    sort: []
                };

                var options = this.gridOptions || {};

                // grid and mixins
                var req = [Grid, Keyboard];
                if (this.featureOptions.selected !== false) {
                    req.push(Selection);
                    gridOptions.selectionMode = has('touch') ? 'toggle' : 'extended';
                    gridOptions.allowFeatureSelectionAll = true;
                }

                if (options.pagination !== false) {
                    req.push(Pagination);
                    lang.mixin(gridOptions, options.paginationOptions);
                }

                // grid extensions
                if (options.columnHide !== false) {
                    req.push(ColumnHider);
                }
                if (options.columnReorder !== false) {
                    req.push(ColumnReorder);
                }
                if (options.columnResize !== false) {
                    req.push(ColumnResizer);
                }

                var AttributeGrid = declare(req);
                this.grid = new AttributeGrid(gridOptions, this.attributesTableGridDijit.domNode);
                this.grid.startup();

                if (this.featureOptions.selected) {
                    this.grid.on('dgrid-select', lang.hitch(this, 'selectFeaturesFromGrid'));
                    this.grid.on('dgrid-deselect', lang.hitch(this, 'selectFeaturesFromGrid'));
                }
            }

        },

        populateGrid: function (options) {
            var results = options;
            if (options.results) {
                results = options.results;
            }

            var delim = '', linkField = this.linkField;
            var filteredFields = array.filter(results.fields, function (field) {
                return (field.name === linkField);
            });
            if (filteredFields.length >0) {
                if (filteredFields[0].type === 'esriFieldTypeString') {
                    delim = '\'';
                }
            }

            var features = this.getFeaturesFromResults();
            var rows = [];
            array.forEach(features, lang.hitch(this, function (feature) {
                // relationship query
                if (feature.relatedRecords) {
                    rows = rows.concat(this.getRelatedRecords(feature));

                // spatial or table query
                } else if (feature.attributes) {
                    rows = rows.concat(this.getRecordFromFeature(feature));
                }
            }));

            if (this.toolbarOptions.zoom.show) {
                this.zoomToFeatureGraphics();
            }

            this.getColumnsAndSort(results, options);

            if (rows && rows.length > 0) {
                this.grid.set('store', new Memory({
                    idProperty: this.idProperty,
                    data: rows
                }));
            }

            this.grid.refresh();
            this.setToolbarButtons();

        },

        getRecordFromFeature: function (feature) {
            var rows = [], delim = '';
            var lq =  null;
            if (this.hasLinkedQuery()) {
                lq = this.linkedQuery;
            }

            var showFeatures = this.featureOptions.features;
            if (!lq || lq.type !== 'table') {
                var row = feature.attributes;
                // add reference to the feature if there is geometry
                if (showFeatures && feature.geometry) {
                    row.feature = lang.clone(feature);
                }
                if (lq && lq.linkIDs) {
                    lq.linkIDs.push(delim + feature.attributes[this.linkField] + delim);
                }
                rows.push(row);

                if (showFeatures && feature.geometry) {
                    this.addFeatureGraphic(feature);
                }
            }
            return rows;
        },

        getRelatedRecords: function (feature) {
            var rows = [], delim = '', objectID = feature.objectId;
            var lq =  null;
            if (this.hasLinkedQuery()) {
                lq = this.linkedQuery;
            }

            var showFeatures = this.featureOptions.features;
            // multiple related records for a feature
            array.forEach(feature.relatedRecords, lang.hitch(this, function (record) {
                if (record.attributes) {
                    var row = record.attributes;
                    row.RelatedObjectID = objectID;
                    rows.push(row);
                }
                if (lq && lq.linkIDs) {
                    lq.linkIDs.push(delim + feature.attributes[this.linkField] + delim);
                }
                if (showFeatures && record.geometry) {
                    this.addFeatureGraphic(feature);
                }
            }));
            return rows;
        },

        getColumnsAndSort: function (results, options) {
            // reset the columns?
            if (options.columns) {
                this.gridOptions.columns = options.columns;
            }

            // reset the sort?
            if (options.sort) {
                this.gridOptions.sort = options.sort;
            }

            // set the columns
            var columns = lang.clone(this.gridOptions.columns) || [];
            // no columns? get them from the fields
            if (!columns || columns.length < 1) {
                columns = this.buildColumns(results);
            }

            if (columns) {
                this.setColumnStyles(columns);
                this.grid.set('columns', columns);
            } else if (this.gridOptions.subRows) {
                this.grid.set('subRows', this.gridOptions.subRows);
            }

            // set the sort
            var sort = this.gridOptions.sort || [];
            // no sort? use the first column
            if (sort.length < 1 && columns && columns.length > 0) {
                sort = [
                    {
                        attribute: columns[0].field,
                        descending: false
                    }
                ];
            }
            this.grid.set('sort', sort);
        },

        buildColumns: function (results) {
            function formatDateTime (value) {
                var date = new Date(value);
                return locale.format(date, {
                    formatLength: 'short'
                });
            }
            function formatNumber (value) {
                return number.format(value);
            }
            function formatSingleDouble (value) {
                return number.format(value, {
                    places: 3
                });
            }

            var excludedFields = ['objectid', 'esri_oid', 'shape', 'shape.len', 'shape.area', 'shape.starea()', 'shape.stlength()', 'st_area(shape)', 'st_length(shape)'];
            var columns = [], col, nameLC = null;
            if (results.fields) {
                array.forEach(results.fields, function (field) {
                    nameLC = field.name.toLowerCase();
                    if (array.indexOf(excludedFields, nameLC) < 0) {
                        col = {
                            id: field.name,
                            field: field.name,
                            label: field.alias,
                            style: 'white-space:nowrap;overflow:hidden;text-overflow:ellipsis;',
                            width: 100
                        };
                        switch (field.type) {
                            case 'esriFieldTypeString':
                                col.width = 150;
                                break;
                            case 'esriFieldTypeSmallInteger':
                            case 'esriFieldTypeInteger':
                                col.formatter = formatNumber;
                                col.style += 'text-align:right;';
                                break;
                            case 'esriFieldTypeSingle':
                            case 'esriFieldTypeDouble':
                                col.formatter = formatSingleDouble;
                                col.style += 'text-align:right;';
                                break;
                            case 'esriFieldTypeDate':
                                col.width = 150;
                                col.formatter = formatDateTime;
                                break;
                        }
                        columns.push(col);
                    }
                });
            } else if (this.getFeatureCount() > 0) {
                var feature = this.features[0];
                if (feature) {
                    var attributes = feature.attributes;
                    for (var key in attributes) {
                        if (attributes.hasOwnProperty(key)) {
                            columns.push({
                                id: key,
                                field: key,
                                label: key,
                                width: 100
                            });
                        }
                    }
                }
            }
            return columns;
        },

        setColumnStyles: function (columns) {
            //style the grid columns from the config object
            var gr = this.grid;
            array.forEach(columns, function (column) {
                if (column.style) {
                    gr.styleColumn(column.id, column.style);
                }
            });
        },

        selectFeaturesFromGrid: function () {
            var selection = this.grid.get('selection'),
                feature = null;

            this.selectedFeatures = [];
            this.selectedGraphics.clear();

            for (var key in selection) {
                if (selection.hasOwnProperty(key) && selection[key] === true) {
                    feature = this.getFeatureFromStore(key);
                    if (feature && feature.geometry) {
                        this.addSelectedGraphic(feature);
                    }
                }
            }
            this.doneSelectingFeatures(true);
        },

        getFeatureFromStore: function (key) {
            var store = this.grid.get('store'),
                rec = null,
                feature = null;
            rec = store.get(key);
            if (rec) {
                feature = rec.feature;
            }
            return feature;

        },

        clearGrid: function () {
            if (this.grid) {
                if (this.grid.clearSelection) {
                    this.grid.clearSelection();
                }
                this.grid.set('columns', []);
                this.grid.set('store', new Memory());
                this.grid.refresh();
            }
            this.setToolbarButtons();
        }

    });
});
<commit_msg>Add configuration for inheriting a sort order from query results.<commit_after>define([
    'dojo/_base/declare',
    'dojo/_base/lang',
    'dojo/has',
    'dojo/_base/array',
    'dojo/date/locale',
    'dojo/number',

    'dojo/store/Memory',
    'dgrid/Grid', // http://dojofoundation.org/packages/dgrid/
    'dgrid/Selection',
    'dgrid/Keyboard',
    'dgrid/extensions/ColumnHider',
    'dgrid/extensions/ColumnReorder',
    'dgrid/extensions/ColumnResizer',
    'dgrid/extensions/Pagination'
], function (
    declare,
    lang,
    has,
    array,
    locale,
    number,

    Memory,
    Grid,
    Selection,
    Keyboard,
    ColumnHider,
    ColumnReorder,
    ColumnResizer,
    Pagination
) {

    return declare(null, {

        gridOptions: {},

        defaultGridOptions: {

            minWidth: 70,

            // no columns, use fields from Query's returned features
            columns: [],

            // no sort
            sort: [],

            // Allow the user to use column sets in grid
            columnSet: false,

            // Allow the user to hide columns in grid
            columnHide: true,

            // Allow the user to reorder columns in grid
            columnReorder: true,

            // Allow the user to resize columns in grid
            columnResize: true,

            // Use pagination on the results grid
            pagination: true,

            paginationOptions: {
                rowsPerPage: 100,
                previousNextArrows: true,
                firstLastArrows: true,
                pagingLinks: 2,
                pagingTextBox: true,
                pageSizeOptions: [10, 25, 50, 100, 250, 500, 1000],
                showLoadingMessage: true
            }
        },

        getGridConfiguration: function (options) {
            this.gridOptions = this.mixinDeep(lang.clone(this.defaultGridOptions), options);
        },

        createGrid: function () {
            if (!this.grid) {
                var gridOptions = {
                    cellNavigation: false,
                    showHeader: true,
                    showFooter: true,
                    adjustLastColumn: true,
                    store: new Memory(),
                    columns: [],
                    sort: []
                };

                var options = this.gridOptions || {};

                // grid and mixins
                var req = [Grid, Keyboard];
                if (this.featureOptions.selected !== false) {
                    req.push(Selection);
                    gridOptions.selectionMode = has('touch') ? 'toggle' : 'extended';
                    gridOptions.allowFeatureSelectionAll = true;
                }

                if (options.pagination !== false) {
                    req.push(Pagination);
                    lang.mixin(gridOptions, options.paginationOptions);
                }

                // grid extensions
                if (options.columnHide !== false) {
                    req.push(ColumnHider);
                }
                if (options.columnReorder !== false) {
                    req.push(ColumnReorder);
                }
                if (options.columnResize !== false) {
                    req.push(ColumnResizer);
                }

                var AttributeGrid = declare(req);
                this.grid = new AttributeGrid(gridOptions, this.attributesTableGridDijit.domNode);
                this.grid.startup();

                if (this.featureOptions.selected) {
                    this.grid.on('dgrid-select', lang.hitch(this, 'selectFeaturesFromGrid'));
                    this.grid.on('dgrid-deselect', lang.hitch(this, 'selectFeaturesFromGrid'));
                }
            }

        },

        populateGrid: function (options) {
            var results = options;
            if (options.results) {
                results = options.results;
            }

            var delim = '', linkField = this.linkField;
            var filteredFields = array.filter(results.fields, function (field) {
                return (field.name === linkField);
            });
            if (filteredFields.length >0) {
                if (filteredFields[0].type === 'esriFieldTypeString') {
                    delim = '\'';
                }
            }

            var features = this.getFeaturesFromResults();
            var rows = [];
            array.forEach(features, lang.hitch(this, function (feature) {
                // relationship query
                if (feature.relatedRecords) {
                    rows = rows.concat(this.getRelatedRecords(feature));

                // spatial or table query
                } else if (feature.attributes) {
                    rows = rows.concat(this.getRecordFromFeature(feature));
                }
            }));

            if (this.toolbarOptions.zoom.show) {
                this.zoomToFeatureGraphics();
            }

            this.getColumnsAndSort(results, options);

            if (rows && rows.length > 0) {
                this.grid.set('store', new Memory({
                    idProperty: this.idProperty,
                    data: rows
                }));
            }

            this.grid.refresh();
            this.setToolbarButtons();

        },

        getRecordFromFeature: function (feature) {
            var rows = [], delim = '';
            var lq =  null;
            if (this.hasLinkedQuery()) {
                lq = this.linkedQuery;
            }

            var showFeatures = this.featureOptions.features;
            if (!lq || lq.type !== 'table') {
                var row = feature.attributes;
                // add reference to the feature if there is geometry
                if (showFeatures && feature.geometry) {
                    row.feature = lang.clone(feature);
                }
                if (lq && lq.linkIDs) {
                    lq.linkIDs.push(delim + feature.attributes[this.linkField] + delim);
                }
                rows.push(row);

                if (showFeatures && feature.geometry) {
                    this.addFeatureGraphic(feature);
                }
            }
            return rows;
        },

        getRelatedRecords: function (feature) {
            var rows = [], delim = '', objectID = feature.objectId;
            var lq =  null;
            if (this.hasLinkedQuery()) {
                lq = this.linkedQuery;
            }

            var showFeatures = this.featureOptions.features;
            // multiple related records for a feature
            array.forEach(feature.relatedRecords, lang.hitch(this, function (record) {
                if (record.attributes) {
                    var row = record.attributes;
                    row.RelatedObjectID = objectID;
                    rows.push(row);
                }
                if (lq && lq.linkIDs) {
                    lq.linkIDs.push(delim + feature.attributes[this.linkField] + delim);
                }
                if (showFeatures && record.geometry) {
                    this.addFeatureGraphic(feature);
                }
            }));
            return rows;
        },

        getColumnsAndSort: function (results, options) {
            // reset the columns?
            if (options.columns) {
                this.gridOptions.columns = options.columns;
            }

            // reset the sort?
            if (options.sort) {
                this.gridOptions.sort = options.sort;
            }

            // set the columns
            var columns = lang.clone(this.gridOptions.columns) || [];
            // no columns? get them from the fields
            if (!columns || columns.length < 1) {
                columns = this.buildColumns(results);
            }

            if (columns) {
                this.setColumnStyles(columns);
                this.grid.set('columns', columns);
            } else if (this.gridOptions.subRows) {
                this.grid.set('subRows', this.gridOptions.subRows);
            }

            // set the sort
            var sort = this.gridOptions.sort || [];
            // sort === 'inherit'? use query result order
            if (typeof sort === 'string' && sort.toLowerCase() === 'inherit'){
                return;
            }
            // no sort? use the first column
            if (sort.length < 1 && columns && columns.length > 0) {
                sort = [
                    {
                        attribute: columns[0].field,
                        descending: false
                    }
                ];
            }
            this.grid.set('sort', sort);
        },

        buildColumns: function (results) {
            function formatDateTime (value) {
                var date = new Date(value);
                return locale.format(date, {
                    formatLength: 'short'
                });
            }
            function formatNumber (value) {
                return number.format(value);
            }
            function formatSingleDouble (value) {
                return number.format(value, {
                    places: 3
                });
            }

            var excludedFields = ['objectid', 'esri_oid', 'shape', 'shape.len', 'shape.area', 'shape.starea()', 'shape.stlength()', 'st_area(shape)', 'st_length(shape)'];
            var columns = [], col, nameLC = null;
            if (results.fields) {
                array.forEach(results.fields, function (field) {
                    nameLC = field.name.toLowerCase();
                    if (array.indexOf(excludedFields, nameLC) < 0) {
                        col = {
                            id: field.name,
                            field: field.name,
                            label: field.alias,
                            style: 'white-space:nowrap;overflow:hidden;text-overflow:ellipsis;',
                            width: 100
                        };
                        switch (field.type) {
                            case 'esriFieldTypeString':
                                col.width = 150;
                                break;
                            case 'esriFieldTypeSmallInteger':
                            case 'esriFieldTypeInteger':
                                col.formatter = formatNumber;
                                col.style += 'text-align:right;';
                                break;
                            case 'esriFieldTypeSingle':
                            case 'esriFieldTypeDouble':
                                col.formatter = formatSingleDouble;
                                col.style += 'text-align:right;';
                                break;
                            case 'esriFieldTypeDate':
                                col.width = 150;
                                col.formatter = formatDateTime;
                                break;
                        }
                        columns.push(col);
                    }
                });
            } else if (this.getFeatureCount() > 0) {
                var feature = this.features[0];
                if (feature) {
                    var attributes = feature.attributes;
                    for (var key in attributes) {
                        if (attributes.hasOwnProperty(key)) {
                            columns.push({
                                id: key,
                                field: key,
                                label: key,
                                width: 100
                            });
                        }
                    }
                }
            }
            return columns;
        },

        setColumnStyles: function (columns) {
            //style the grid columns from the config object
            var gr = this.grid;
            array.forEach(columns, function (column) {
                if (column.style) {
                    gr.styleColumn(column.id, column.style);
                }
            });
        },

        selectFeaturesFromGrid: function () {
            var selection = this.grid.get('selection'),
                feature = null;

            this.selectedFeatures = [];
            this.selectedGraphics.clear();

            for (var key in selection) {
                if (selection.hasOwnProperty(key) && selection[key] === true) {
                    feature = this.getFeatureFromStore(key);
                    if (feature && feature.geometry) {
                        this.addSelectedGraphic(feature);
                    }
                }
            }
            this.doneSelectingFeatures(true);
        },

        getFeatureFromStore: function (key) {
            var store = this.grid.get('store'),
                rec = null,
                feature = null;
            rec = store.get(key);
            if (rec) {
                feature = rec.feature;
            }
            return feature;

        },

        clearGrid: function () {
            if (this.grid) {
                if (this.grid.clearSelection) {
                    this.grid.clearSelection();
                }
                this.grid.set('columns', []);
                this.grid.set('store', new Memory());
                this.grid.refresh();
            }
            this.setToolbarButtons();
        }

    });
});
<|endoftext|>


<commit_before>var TouchstartBtn = require('../../lib/index').Touchstart,
    expect = require('expect.js');

describe('TouchstartButton', function () {
    it('must be an function', function () {
        expect(TouchstartBtn).to.be.an('function');
    });

    describe('instance', function () {
        it.skip('should raise an Error when calling .bind() if already binded', function () {

        });
        it.skip('should raise an Error when calling .unbind() if unbinded', function () {

        });
        it.skip('is active until the returned promise of the callback is resolved', function () {

        });
        it.skip('can not be activated if already activated', function () {

        });
        it.skip('should delay 1000 ms the execution of the callback if delay option set to 1000', function () {

        });
    });
});

<commit_msg>default/touchstart test<commit_after>var TouchstartBtn = require('../../lib/index').Touchstart,
    Q = require('q'),
    expect = require('expect.js');

describe('TouchstartButton', function () {
    it('must be an function', function () {
        expect(TouchstartBtn).to.be.an('function');
    });

    describe('instance', function () {
        it('should raise an Error when calling .bind() if already binded', function () {
            var btn = new TouchstartBtn({
                    el : document.createElement('div'),
                    f : function () { }
                });
            btn.bind();
            expect(function () { btn.bind(); }).to.throwException("Can't bind an already binded button.");
        });
        it('should raise an Error when calling .unbind() if unbinded', function () {
            var btn = new TouchstartBtn({
                    el : document.createElement('div'),
                    f : function () { }
                });
            expect(function () { btn.unbind(); }).to.throwException("Can't unbind a unbinded button.");
        });
        it('can not be activated if already activated', function (done) {
            var i = 0,
                btn = new TouchstartBtn({
                    el : document.createElement('div'),
                    f : function () { i = i+1; return Q.delay(200); }
                });
            btn.bind();
            // first fake activation
            btn.onTouchstart({});
            setTimeout(function () {
                // second activation while the first is not done
                btn.onTouchstart({});
            },100);
            setTimeout(function () {
                expect(i).to.be(1);
                done();
            },300);
        });
        it('should delay 1000 ms the execution of the callback if delay option set to 1000', function (done) {
            this.timeout(1500);

            var flag = false,
                btn = new TouchstartBtn({
                    el : document.createElement('div'),
                    f : function () { flag = true; },
                    delay : 1000
                });
            btn.bind();
            // fake activation
            btn.onTouchstart({});
            setTimeout(function () {
                expect(flag).to.be(false);
            },500);
            setTimeout(function () {
                expect(flag).to.be(true);
                done();
            },1100);
        });
        it('should add the `.active` css class on the underlying DOM element when active', function (done) {
            var btn = new TouchstartBtn({
                el : document.createElement('div'),
                f : function () { return Q.delay(200); }
            });

            btn.bind();
            // fake activation
            btn.onTouchstart({});

            setTimeout(function () {
                expect(btn.el.classList.contains('active')).to.be(true);
                done();
            },100);
        });
        it('should remove the `.active` css class on the underlying DOM element when callback ended', function (done) {
            var btn = new TouchstartBtn({
                el : document.createElement('div'),
                f : function () { return Q.delay(100); }
            });

            btn.bind();
            // fake activation
            btn.onTouchstart({});

            setTimeout(function () {
                expect(btn.el.classList.contains('active')).to.be(false);
                done();
            },200);
        });
    });
});

<|endoftext|>


<commit_before>// (C) Copyright 2015 Martin Dougiamas
//
// 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.

angular.module('mm.core')

/**
 * Directive to create select multiple form item.
 *
 * @module mm.core
 * @ngdoc directive
 * @name mmMultipleSelect
 * @description
 * Based on http://codepen.io/jdnichollsc/pen/qOrqqK?editors=001 and http://codepen.io/adexerivera/pen/oYKZoK?editors=1000
 *
 * Example usage:
 *     <mm-multiple-select title="{{title}}" options="categories" key-property="id" value-property="name"
 *     selected-property="selected"></mm-multiple-select>
 *
 * Parameters accepted:
 *
 * @param {String} title                            Title and label of the selector.
 * @param {Array}  options                          Options to be used in the selector. Each option must have a key and a value
 *                                                      property. Additionally selected property can be defined.
 * @param {String} [keyProperty="key"]              Name of the key property of the option to be sent to the server.
 * @param {String} [valueProperty="value"]          Name of the value property of the option to be shown, human readable.
 * @param {String} [selectedProperty="selected"]    Name of the selected property that indicates if the option is selected.
 */
.directive('mmMultipleSelect', function($ionicModal, $translate) {
    return {
        restrict: 'E',
        priority: 100,
        scope: {
            title: '@',
            options: '='
        },
        templateUrl: 'core/templates/multipleselect.html',
        link: function(scope, element, attrs) {

            var keyProperty = attrs.keyProperty || "key",
                valueProperty = attrs.valueProperty || "value",
                selectedProperty = attrs.selectedProperty || "selected",
                strSeparator = $translate.instant('mm.core.elementseparator') + " ";

            scope.optionsRender = [];
            scope.selectedOptions = "";

            element.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();

                if (!scope.modal) {
                    $ionicModal.fromTemplateUrl('core/templates/multipleselectpopover.html', {
                        scope: scope,
                        animation: 'slide-in-up'
                    }).then(function(m) {
                        scope.modal = m;
                        scope.optionsRender = scope.options.map(function(option) {
                            return {
                                key: option[keyProperty],
                                value: option[valueProperty],
                                selected: option[selectedProperty] || false
                            };
                        });

                        scope.modal.show();
                    });
                } else {
                    scope.modal.show();
                }
            });

            scope.saveOptions = function() {
                var selected = [];
                angular.forEach(scope.optionsRender, function (tempOption){
                    for (var j = 0; j < scope.options.length; j++) {
                        var option = scope.options[j];
                        if (option[keyProperty] == tempOption.key) {
                            option[selectedProperty] = tempOption.selected;
                            if (tempOption.selected) {
                                selected.push(tempOption.value);
                            }
                            return;
                        }
                    }
                });
                scope.selectedOptions = selected.join(strSeparator);

                scope.closeModal();
            };

            scope.closeModal = function(){
                scope.modal.hide();
            };

            scope.$on('$destroy', function () {
                if (scope.modal){
                    scope.modal.remove();
                }
            });
        }
    };
});
<commit_msg>MOBILE-1966 multipleselect: Load selected options<commit_after>// (C) Copyright 2015 Martin Dougiamas
//
// 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.

angular.module('mm.core')

/**
 * Directive to create select multiple form item.
 *
 * @module mm.core
 * @ngdoc directive
 * @name mmMultipleSelect
 * @description
 * Based on http://codepen.io/jdnichollsc/pen/qOrqqK?editors=001 and http://codepen.io/adexerivera/pen/oYKZoK?editors=1000
 *
 * Example usage:
 *     <mm-multiple-select title="{{title}}" options="categories" key-property="id" value-property="name"
 *     selected-property="selected"></mm-multiple-select>
 *
 * Parameters accepted:
 *
 * @param {String} title                            Title and label of the selector.
 * @param {Array}  options                          Options to be used in the selector. Each option must have a key and a value
 *                                                      property. Additionally selected property can be defined.
 * @param {String} [keyProperty="key"]              Name of the key property of the option to be sent to the server.
 * @param {String} [valueProperty="value"]          Name of the value property of the option to be shown, human readable.
 * @param {String} [selectedProperty="selected"]    Name of the selected property that indicates if the option is selected.
 */
.directive('mmMultipleSelect', function($ionicModal, $translate) {
    return {
        restrict: 'E',
        priority: 100,
        scope: {
            title: '@',
            options: '='
        },
        templateUrl: 'core/templates/multipleselect.html',
        link: function(scope, element, attrs) {

            var keyProperty = attrs.keyProperty || "key",
                valueProperty = attrs.valueProperty || "value",
                selectedProperty = attrs.selectedProperty || "selected",
                strSeparator = $translate.instant('mm.core.elementseparator') + " ";

            scope.optionsRender = [];
            scope.selectedOptions = getSelectedOptionsText();

            element.on('click', function(e) {
                e.preventDefault();
                e.stopPropagation();

                if (!scope.modal) {
                    $ionicModal.fromTemplateUrl('core/templates/multipleselectpopover.html', {
                        scope: scope,
                        animation: 'slide-in-up'
                    }).then(function(m) {
                        scope.modal = m;
                        scope.optionsRender = scope.options.map(function(option) {
                            return {
                                key: option[keyProperty],
                                value: option[valueProperty],
                                selected: option[selectedProperty] || false
                            };
                        });

                        scope.modal.show();
                    });
                } else {
                    scope.modal.show();
                }
            });

            scope.saveOptions = function() {
                angular.forEach(scope.optionsRender, function (tempOption){
                    for (var j = 0; j < scope.options.length; j++) {
                        var option = scope.options[j];
                        if (option[keyProperty] == tempOption.key) {
                            option[selectedProperty] = tempOption.selected;
                            return;
                        }
                    }
                });
                scope.selectedOptions = getSelectedOptionsText();

                scope.closeModal();
            };

            // Get string for selected options to be shown.
            function getSelectedOptionsText() {
                var selected = scope.options.filter(function(option) {
                    return !!option[selectedProperty];
                }).map(function(option) {
                    return option[valueProperty];
                });

                return selected.join(strSeparator);
            }

            scope.closeModal = function(){
                scope.modal.hide();
            };

            scope.$on('$destroy', function () {
                if (scope.modal){
                    scope.modal.remove();
                }
            });
        }
    };
});
<|endoftext|>