<commit_before>Ext.namespace('Vps.Component');
Vps.Component.Pages = Ext.extend(Ext.Panel, {
    initComponent : function()
    {
        this.actions = {};
        this.componentConfigs = {};

        this.pageButtonMenu = new Ext.menu.Menu({
            items    : [
                '-',
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome'),
                this.getAction('preview')
            ]
        });
        this.pageButton = new Ext.Toolbar.Button({
            cls     : 'x-btn-text-icon bmenu',
            text    : trlVps('Page'),
            menu    : this.pageButtonMenu,
            icon    : '/assets/silkicons/page.png',
            disabled: true
        });

        this.treePanel = new Vps.Auto.TreePanel({
            controllerUrl: '/admin/component/pages',
            title       : trlVps('Seitenbaum'),
            region      : 'west',
            split       : true,
            width       : 300,
            collapsible : true,
            minSize     : 200,
            maxSize     : 600,
            autoScroll: true,
            tbar: []
        });

        var tbar = this.treePanel.getTopToolbar();
        tbar.add(this.pageButton);

        tbar.add('-');
        tbar.add(trlVps('Search: '));

        var filter = new Vps.Auto.Filter.Text({name: 'text', 'paramName': 'query'});
        filter.on('filter', function(f, params) {
            this.applyBaseParams(params);
            this.reload();
        }, this.treePanel);
        filter.getToolbarItem().each(function(i) {
            tbar.add(i);
        });

        tbar.add('->');
        tbar.add(this.treePanel.getAction('reload'));

        this.treePanel.onMoved = function (response) {
            this.tree.getRootNode().reload();
        };

        this.contentTabPanel = new Ext.TabPanel({
            region      : 'center'
        });
        this.contentTabPanel.on('render', function() {
            this.contentTabPanel.strip.setHeight(24);
        }, this);

        this.layout = 'border';
        this.items = [this.treePanel, this.contentTabPanel];

        Vps.Component.Pages.superclass.initComponent.call(this);

        this.treePanel.on('loaded', this.onTreePanelLoaded, this);
        this.setupEditform();

        this.editActions = {};
    },
    setupEditform : function ()
    {
       this.editDialog = new Vps.Auto.Form.Window({
            width: 400,
            height: 400,
            controllerUrl: ' '
        });
        this.editDialog.on('datachange', function(test) {
            this.treePanel.tree.root.reload();
        }, this);
    },

    onTreePanelLoaded : function(tree)
    {
        tree.loader.on('load', function(tree, node, response) {
            var result = Ext.decode(response.responseText);
            Ext.applyIf(this.componentConfigs, result.componentConfigs);
        }, this);

        this.contextMenu = new Ext.menu.Menu({
             items: [
                '-',
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome'),
                this.getAction('preview')
            ]
        });

        tree.on('click', this.treeSelectionchange, this);
        tree.on('contextmenu', function (node) {
            node.select();
            this.treeSelectionchange(node);
            this.contextMenu.show(node.ui.getAnchor());
        }, this);

        tree.on('dblclick', function (o, e) {
            var i = this.contextMenu.items.first();
            if (i) {
                i.handler.call(i.scope, i, e);
            }
        }, this);

    },

    treeSelectionchange : function (node) {
        if (!node) return;
        var data = node.attributes;

        this.editDialog.getAutoForm().editControllerUrl = data.editControllerUrl;
        this.editDialog.getAutoForm().addControllerUrl = data.addControllerUrl;

        if (data.disabled) {
            this.pageButton.disable();
        } else {
            this.pageButton.enable();
        }

        for (var action in data.actions) {
            if (data.actions[action]) {
                this.getAction(action).enable();
            } else {
                this.getAction(action).disable();
            }
        }

        this.contextMenu.items.each(function(i) {
            if (i.initialConfig.actionKey) {
                this.contextMenu.remove(i);
            }
        }, this);
        this.pageButtonMenu.items.each(function(i) {
            if (i.initialConfig.actionKey) {
                this.pageButtonMenu.remove(i);
            }
        }, this);
        var actionsAdded = 0;
        data.editComponents.each(function(editComponent) {
            var actionKey = editComponent.componentClass+'-'+editComponent.type;
            if (!this.editActions[actionKey]) {
                this.editActions[actionKey] = new Ext.Action({
                    text    : this.componentConfigs[actionKey].title,
                    handler : function (o, e) {
                        var node = this.treePanel.tree.getSelectionModel().getSelectedNode();
                        node.attributes.editComponents.each(function(editComponent) {
                            if (editComponent.componentClass+'-'+editComponent.type == o.actionKey) {
                                this.loadComponent({
                                    id: editComponent.componentId,
                                    componentClass: editComponent.componentClass,
                                    type: editComponent.type,
                                    text: node.text,
                                    icon: node.attributes.bIcon,
                                    editComponents: node.attributes.editComponents,
                                    pageId: node.attributes.id
                                });
                                return false;
                            }
                        }, this);
                    },
                    icon    : this.componentConfigs[actionKey].icon,
                    cls     : 'x-btn-text-icon',
                    scope   : this,
                    actionKey: actionKey
                });
            }
            this.editActions[actionKey].setDisabled(data.disabled);
            this.contextMenu.insert(actionsAdded, new Ext.menu.Item(this.editActions[actionKey]));
            this.pageButtonMenu.insert(actionsAdded, new Ext.menu.Item(this.editActions[actionKey]));
            actionsAdded++;
        }, this);
    },

    loadComponent: function(data)
    {
        var panel = this.contentTabPanel.getItem('page'+data.pageId);
        if (!panel) {
            panel = this.createComponentPanel(data);
            this.contentTabPanel.add(panel);
        }
        this.contentTabPanel.setActiveTab(panel);

        panel.applyBaseParams({
            id: data.id
        });
        panel.mainComponentText = data.text;
        panel.mainComponentIcon = data.icon;
        panel.load({
            componentClass: data.componentClass,
            type: data.type,
            editComponents: data.editComponents
        });
    },

    createComponentPanel: function(data)
    {
        var panel = new Vps.Component.ComponentPanel({
            id          : 'page'+data.pageId,
            title       : data.text,
            closable    : true,
            autoLoad    : false,
            componentConfigs : this.componentConfigs
        });
        return panel;
    },

    getAction : function(type)
    {
        if (this.actions[type]) return this.actions[type];

        if (type == 'properties') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Page properties'),
                handler : function () {
                    var form = this.editDialog.getAutoForm();
                    form.controllerUrl = form.editControllerUrl;
                    if (form.formPanel) {
                        form.remove(form.formPanel, true);
                        this.editDialog.getAutoForm().formPanel = null;
                    }
                    var node = this.treePanel.tree.selModel.selNode;
                    this.editDialog.getAutoForm().setBaseParams({
                        componentId: node.attributes.editControllerComponentId
                    });
                    this.editDialog.showEdit(node.id);
                },
                icon    : '/assets/silkicons/page_gear.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'add') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Add new child page'),
                handler : function () {
            		var form = this.editDialog.getAutoForm();
                    form.controllerUrl = form.addControllerUrl;
	                if (form.formPanel) {
	                    form.remove(form.formPanel, true);
	                    this.editDialog.getAutoForm().formPanel = null;
	                }
                    var node = this.treePanel.tree.selModel.selNode;
                    this.editDialog.getAutoForm().setBaseParams({
                        componentId: node.attributes.editControllerComponentId,
                        parent_id: node.id
                    });
                    this.editDialog.showAdd();
                },
                icon    : '/assets/silkicons/page_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'delete') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Delete page'),
                handler : function() {
                    this.treePanel.onDelete();
                },
                icon    : '/assets/silkicons/page_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'visible') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Show / hide page'),
                handler : function() {
                    this.treePanel.onVisible();
                },
                icon    : '/assets/fx_invisible/silkicons/page.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'makeHome') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Use as homepage'),
                handler : function (o, e) {
                    Ext.Msg.show({
                        title: trlVps('Use as homepage'),
                        msg: trlVps('Attention! You are about to set the selected page as the homepage of your website. This may affect the entire website. Do you wish to proceed?'),
                        buttons: Ext.Msg.YESNO,
                        icon: Ext.MessageBox.WARNING,
                        fn: function(btn, text) {
                            if (btn == 'yes') {
                                Ext.Ajax.request({
                                    url: '/admin/component/pages/json-make-home',
                                    success: function(r) {
                                        response = Ext.decode(r.responseText);
                                        var oldhome = this.treePanel.tree.getNodeById(response.oldhome);
                                        oldhome.attributes.visible = response.oldhomeVisible;
                                        this.treePanel.setVisible(oldhome);
                                        oldhome.ui.iconNode.style.backgroundImage = 'url(/assets/silkicons/page.png)';
                                        var home = this.treePanel.tree.getNodeById(response.home);
                                        home.ui.iconNode.style.backgroundImage = 'url(/assets/silkicons/application_home.png)';
                                    },
                                    params: {id: this.treePanel.tree.getSelectionModel().getSelectedNode().id },
                                    scope: this
                                });
                            }
                        },
                        scope: this
                    });
                },
                icon    : '/assets/silkicons/application_home.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'expand') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Expand here'),
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().expand(true); },
                icon    : '/assets/silkicons/bullet_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'collapse') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Collapse here'),
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().collapse(true); },
                icon    : '/assets/silkicons/bullet_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'preview') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Open preview'),
                handler : function () {
                    window.open('/admin/component/pages/open-preview?page_id='+
                                this.treePanel.getSelectedId());
                },
                icon    : '/assets/silkicons/page_white_magnify.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else {
            throw 'unknown action-type: ' + type;
        }
        return this.actions[type];
    }

});

Ext.reg('vps.component.pages', Vps.Component.Pages);
<commit_msg>PagesController: editComponents-Bug bei mehreren gleichen ComponentClasses auf einer Seite<commit_after>Ext.namespace('Vps.Component');
Vps.Component.Pages = Ext.extend(Ext.Panel, {
    initComponent : function()
    {
        this.actions = {};
        this.componentConfigs = {};

        this.pageButtonMenu = new Ext.menu.Menu({
            items    : [
                '-',
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome'),
                this.getAction('preview')
            ]
        });
        this.pageButton = new Ext.Toolbar.Button({
            cls     : 'x-btn-text-icon bmenu',
            text    : trlVps('Page'),
            menu    : this.pageButtonMenu,
            icon    : '/assets/silkicons/page.png',
            disabled: true
        });

        this.treePanel = new Vps.Auto.TreePanel({
            controllerUrl: '/admin/component/pages',
            title       : trlVps('Seitenbaum'),
            region      : 'west',
            split       : true,
            width       : 300,
            collapsible : true,
            minSize     : 200,
            maxSize     : 600,
            autoScroll: true,
            tbar: []
        });

        var tbar = this.treePanel.getTopToolbar();
        tbar.add(this.pageButton);

        tbar.add('-');
        tbar.add(trlVps('Search: '));

        var filter = new Vps.Auto.Filter.Text({name: 'text', 'paramName': 'query'});
        filter.on('filter', function(f, params) {
            this.applyBaseParams(params);
            this.reload();
        }, this.treePanel);
        filter.getToolbarItem().each(function(i) {
            tbar.add(i);
        });

        tbar.add('->');
        tbar.add(this.treePanel.getAction('reload'));

        this.treePanel.onMoved = function (response) {
            this.tree.getRootNode().reload();
        };

        this.contentTabPanel = new Ext.TabPanel({
            region      : 'center'
        });
        this.contentTabPanel.on('render', function() {
            this.contentTabPanel.strip.setHeight(24);
        }, this);

        this.layout = 'border';
        this.items = [this.treePanel, this.contentTabPanel];

        Vps.Component.Pages.superclass.initComponent.call(this);

        this.treePanel.on('loaded', this.onTreePanelLoaded, this);
        this.setupEditform();

        this.editActions = {};
    },
    setupEditform : function ()
    {
       this.editDialog = new Vps.Auto.Form.Window({
            width: 400,
            height: 400,
            controllerUrl: ' '
        });
        this.editDialog.on('datachange', function(test) {
            this.treePanel.tree.root.reload();
        }, this);
    },

    onTreePanelLoaded : function(tree)
    {
        tree.loader.on('load', function(tree, node, response) {
            var result = Ext.decode(response.responseText);
            Ext.applyIf(this.componentConfigs, result.componentConfigs);
        }, this);

        this.contextMenu = new Ext.menu.Menu({
             items: [
                '-',
                this.getAction('properties'),
                this.getAction('add'),
                this.getAction('delete'),
                this.getAction('visible'),
                this.getAction('makeHome'),
                this.getAction('preview')
            ]
        });

        tree.on('click', this.treeSelectionchange, this);
        tree.on('contextmenu', function (node) {
            node.select();
            this.treeSelectionchange(node);
            this.contextMenu.show(node.ui.getAnchor());
        }, this);

        tree.on('dblclick', function (o, e) {
            var i = this.contextMenu.items.first();
            if (i) {
                i.handler.call(i.scope, i, e);
            }
        }, this);

    },

    treeSelectionchange : function (node) {
        if (!node) return;
        var data = node.attributes;

        this.editDialog.getAutoForm().editControllerUrl = data.editControllerUrl;
        this.editDialog.getAutoForm().addControllerUrl = data.addControllerUrl;

        if (data.disabled) {
            this.pageButton.disable();
        } else {
            this.pageButton.enable();
        }

        for (var action in data.actions) {
            if (data.actions[action]) {
                this.getAction(action).enable();
            } else {
                this.getAction(action).disable();
            }
        }

        this.contextMenu.items.each(function(i) {
            if (i.initialConfig.actionKey) {
                this.contextMenu.remove(i);
            }
        }, this);
        this.pageButtonMenu.items.each(function(i) {
            if (i.initialConfig.actionKey) {
                this.pageButtonMenu.remove(i);
            }
        }, this);
        var actionsAdded = 0;
        data.editComponents.each(function(editComponent) {
        	var editKey = editComponent.componentId;
            var actionKey = editComponent.componentClass+'-'+editComponent.type;
            if (!this.editActions[editKey]) {
                this.editActions[editKey] = new Ext.Action({
                    text    : this.componentConfigs[actionKey].title,
                    handler : function (o, e) {
                        var node = this.treePanel.tree.getSelectionModel().getSelectedNode();
                        node.attributes.editComponents.each(function(editComponent) {
                        	if (editComponent.componentId == o.editKey) {
                                this.loadComponent({
                                    id: editComponent.componentId,
                                    componentClass: editComponent.componentClass,
                                    type: editComponent.type,
                                    text: node.text,
                                    icon: node.attributes.bIcon,
                                    editComponents: node.attributes.editComponents,
                                    pageId: node.attributes.id
                                });
                                return false;
                            }
                        }, this);
                    },
                    icon    : this.componentConfigs[actionKey].icon,
                    cls     : 'x-btn-text-icon',
                    scope   : this,
                    actionKey: actionKey,
                    editKey: editKey
                });
            }
            this.editActions[editKey].setDisabled(data.disabled);
            this.contextMenu.insert(actionsAdded, new Ext.menu.Item(this.editActions[editKey]));
            this.pageButtonMenu.insert(actionsAdded, new Ext.menu.Item(this.editActions[editKey]));
            actionsAdded++;
        }, this);
    },

    loadComponent: function(data)
    {
        var panel = this.contentTabPanel.getItem('page'+data.pageId);
        if (!panel) {
            panel = this.createComponentPanel(data);
            this.contentTabPanel.add(panel);
        }
        this.contentTabPanel.setActiveTab(panel);

        panel.applyBaseParams({
            id: data.id
        });
        panel.mainComponentText = data.text;
        panel.mainComponentIcon = data.icon;
        panel.load({
            componentClass: data.componentClass,
            type: data.type,
            editComponents: data.editComponents
        });
    },

    createComponentPanel: function(data)
    {
        var panel = new Vps.Component.ComponentPanel({
            id          : 'page'+data.pageId,
            title       : data.text,
            closable    : true,
            autoLoad    : false,
            componentConfigs : this.componentConfigs
        });
        return panel;
    },

    getAction : function(type)
    {
        if (this.actions[type]) return this.actions[type];

        if (type == 'properties') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Page properties'),
                handler : function () {
                    var form = this.editDialog.getAutoForm();
                    form.controllerUrl = form.editControllerUrl;
                    if (form.formPanel) {
                        form.remove(form.formPanel, true);
                        this.editDialog.getAutoForm().formPanel = null;
                    }
                    var node = this.treePanel.tree.selModel.selNode;
                    this.editDialog.getAutoForm().setBaseParams({
                        componentId: node.attributes.editControllerComponentId
                    });
                    this.editDialog.showEdit(node.id);
                },
                icon    : '/assets/silkicons/page_gear.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'add') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Add new child page'),
                handler : function () {
            		var form = this.editDialog.getAutoForm();
                    form.controllerUrl = form.addControllerUrl;
	                if (form.formPanel) {
	                    form.remove(form.formPanel, true);
	                    this.editDialog.getAutoForm().formPanel = null;
	                }
                    var node = this.treePanel.tree.selModel.selNode;
                    this.editDialog.getAutoForm().setBaseParams({
                        componentId: node.attributes.editControllerComponentId,
                        parent_id: node.id
                    });
                    this.editDialog.showAdd();
                },
                icon    : '/assets/silkicons/page_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'delete') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Delete page'),
                handler : function() {
                    this.treePanel.onDelete();
                },
                icon    : '/assets/silkicons/page_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'visible') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Show / hide page'),
                handler : function() {
                    this.treePanel.onVisible();
                },
                icon    : '/assets/fx_invisible/silkicons/page.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'makeHome') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Use as homepage'),
                handler : function (o, e) {
                    Ext.Msg.show({
                        title: trlVps('Use as homepage'),
                        msg: trlVps('Attention! You are about to set the selected page as the homepage of your website. This may affect the entire website. Do you wish to proceed?'),
                        buttons: Ext.Msg.YESNO,
                        icon: Ext.MessageBox.WARNING,
                        fn: function(btn, text) {
                            if (btn == 'yes') {
                                Ext.Ajax.request({
                                    url: '/admin/component/pages/json-make-home',
                                    success: function(r) {
                                        response = Ext.decode(r.responseText);
                                        var oldhome = this.treePanel.tree.getNodeById(response.oldhome);
                                        oldhome.attributes.visible = response.oldhomeVisible;
                                        this.treePanel.setVisible(oldhome);
                                        oldhome.ui.iconNode.style.backgroundImage = 'url(/assets/silkicons/page.png)';
                                        var home = this.treePanel.tree.getNodeById(response.home);
                                        home.ui.iconNode.style.backgroundImage = 'url(/assets/silkicons/application_home.png)';
                                    },
                                    params: {id: this.treePanel.tree.getSelectionModel().getSelectedNode().id },
                                    scope: this
                                });
                            }
                        },
                        scope: this
                    });
                },
                icon    : '/assets/silkicons/application_home.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'expand') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Expand here'),
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().expand(true); },
                icon    : '/assets/silkicons/bullet_add.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'collapse') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Collapse here'),
                handler : function () { this.treePanel.tree.getSelectionModel().getSelectedNode().collapse(true); },
                icon    : '/assets/silkicons/bullet_delete.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else if (type == 'preview') {
            this.actions[type] = new Ext.Action({
                text    : trlVps('Open preview'),
                handler : function () {
                    window.open('/admin/component/pages/open-preview?page_id='+
                                this.treePanel.getSelectedId());
                },
                icon    : '/assets/silkicons/page_white_magnify.png',
                cls     : 'x-btn-text-icon',
                scope   : this
            });
        } else {
            throw 'unknown action-type: ' + type;
        }
        return this.actions[type];
    }

});

Ext.reg('vps.component.pages', Vps.Component.Pages);
<|endoftext|>


<commit_before>ds.register_dashboard_item('dashboard_definition', {

  constructor: function(data) {
    "use strict"

    var self = limivorous.observable()
                         .property('queries', {init: {}})
                         .property('options', {init: {}})
                         .extend(ds.models.item, {item_type: 'dashboard_definition'})
                         .extend(ds.models.container)
                         .build()

    if (data && data.queries) {
      // For now the on-the-wire query map is string/string. Eventually
      // it will be come string/object as we move thresholds into the
      // queries instead of presentations.
      for (var key in data.queries) {
        var query = data.queries[key]
        self.queries[key] = typeof(query) === 'string'
                          ? ds.models.data.Query({name: key, targets: query})
                          : ds.models.data.Query(query)
      }
    }
    ds.models.item.init(self, data)
    ds.models.container.init(self, data)

    /**
     * Operations
     */

    self.summarize = function() {
      var counts = {}
      self.visit(function(item) {
        if (typeof(counts[item.item_type]) === 'undefined') {
          counts[item.item_type] = 1
        } else {
          counts[item.item_type] = counts[item.item_type] + 1
        }
      })
      return counts
    }

    self.render_templates = function(context) {
      for (var key in self.queries) {
        self.queries[key].render_templates(context)
      }
      return self
    }

    self.load_all = function(options_) {
      self.options = options_ || self.options
      for (var key in self.queries) {
        self.queries[key].load(self.options)
      }
      return self
    }

    self.add_query = function(query) {
      self.queries[query.name] = query
      query.options = self.options
      return self
    }

    /**
     * Rename a query and update any references to it.
     */
    self.rename_query = function(old_name, new_name) {
      var query = self.queries[old_name]
      if (!query)
        return self
      var updated = []
      self.visit(function(item) {
        if (item.query && (item.query.name == old_name)) {
          item.query = new_name
          updated.push(item)
        }
      })
      query.name = new_name
      self.add_query(query)
      delete self.queries[old_name]
      return updated
    }

    self.toJSON = function() {
      var q = {}
      for (var key in self.queries) {
        q[key] = self.queries[key].toJSON()
      }
      return ds.models.container.json(self, ds.models.item.json(self, {queries: q}))
    }

    return self
  },

  template: ds.templates.models.definition

})
<commit_msg>Fix handling of array value targets<commit_after>ds.register_dashboard_item('dashboard_definition', {

  constructor: function(data) {
    "use strict"

    var self = limivorous.observable()
                         .property('queries', {init: {}})
                         .property('options', {init: {}})
                         .extend(ds.models.item, {item_type: 'dashboard_definition'})
                         .extend(ds.models.container)
                         .build()

    if (data && data.queries) {
      // For now the on-the-wire query map is string/string. Eventually
      // it will be come string/object as we move thresholds into the
      // queries instead of presentations.
      for (var key in data.queries) {
        var query = data.queries[key]
        self.queries[key] = (typeof(query) === 'string' || query instanceof Array)
                          ? ds.models.data.Query({name: key, targets: query})
                          : ds.models.data.Query(query)
      }
    }
    ds.models.item.init(self, data)
    ds.models.container.init(self, data)

    /**
     * Operations
     */

    self.summarize = function() {
      var counts = {}
      self.visit(function(item) {
        if (typeof(counts[item.item_type]) === 'undefined') {
          counts[item.item_type] = 1
        } else {
          counts[item.item_type] = counts[item.item_type] + 1
        }
      })
      return counts
    }

    self.render_templates = function(context) {
      for (var key in self.queries) {
        self.queries[key].render_templates(context)
      }
      return self
    }

    self.load_all = function(options_) {
      self.options = options_ || self.options
      for (var key in self.queries) {
        self.queries[key].load(self.options)
      }
      return self
    }

    self.add_query = function(query) {
      self.queries[query.name] = query
      query.options = self.options
      return self
    }

    /**
     * Rename a query and update any references to it.
     */
    self.rename_query = function(old_name, new_name) {
      var query = self.queries[old_name]
      if (!query)
        return self
      var updated = []
      self.visit(function(item) {
        if (item.query && (item.query.name == old_name)) {
          item.query = new_name
          updated.push(item)
        }
      })
      query.name = new_name
      self.add_query(query)
      delete self.queries[old_name]
      return updated
    }

    self.toJSON = function() {
      var q = {}
      for (var key in self.queries) {
        q[key] = self.queries[key].toJSON()
      }
      return ds.models.container.json(self, ds.models.item.json(self, {queries: q}))
    }

    return self
  },

  template: ds.templates.models.definition

})
<|endoftext|>


<commit_before>/* eslint-disable no-console */

const tag = document.createElement('script');
tag.src = 'https://local.gruveo.com/embed-api/';
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

let embed;
// eslint-disable-next-line no-unused-vars
function onGruveoEmbedAPIReady() {
  embed = new Gruveo.Embed('myembed', {
    responsive: true,
    embedParams: Object.assign({
      color: '63b2de',
      chromeless: true,
      branding: false,
    }/* NOTE for old security use this: , securityParams */)
  });

  embed
    .on('ready', handleEmbedReady)
    .on('stateChange', handleEmbedStateChange)
    .on('requestToSignApiAuthToken', handleEmbedRequestToSignApiAuthToken)
    .on('hangup', () => console.info('Received "hangup".'))
    .on('busy', () => console.info('Received "busy".'))
    .on('error', (error) => console.error(`Received error "${error}".`))
    ;
}

function handleEmbedReady(e) {
  console.info('Ready.');
  document.getElementById('form').addEventListener('submit', (e) => {
    // Generate a random code and start a video call on that code.
    const code = document.getElementById('code-input').value || Gruveo.Embed.generateRandomCode();
    console.info(`Calling code "${code}".`);
    embed.call(code, true);
    e.preventDefault();
  });
  document.getElementById('end-btn').addEventListener('click', () => {
    console.info('Ending call.');
    embed.end();
  });
  document.getElementById('audio-chk').addEventListener('change', (e) => {
    console.info('Toggling audio.');
    embed.toggleAudio(e.target.checked);
  });
  document.getElementById('video-chk').addEventListener('change', (e) => {
    console.info('Toggling video.');
    embed.toggleVideo(e.target.checked);
  });
  document.getElementById('roomLock-chk').addEventListener('change', (e) => {
    console.info('Toggling room lock.');
    embed.toggleRoomLock(e.target.checked);
  });
  document.getElementById('switchCamera-btn').addEventListener('click', () => {
    console.info('Switching camera.');
    embed.switchCamera();
  });
}

function handleEmbedStateChange(e) {
  console.info(`State set to "${e.state}".`);
  if (e.state === 'ready') {
    console.info(`Call duration was ${e.callDuration} s.`);
  }
}

function handleEmbedRequestToSignApiAuthToken(token) {
  console.info(`Signing API Auth token "${token}".`);
  fetch('/signer', {
    method: 'POST',
    body: token
  })
    .then((res) => {
      if (res.status === 200) {
        return res;
      }
      throw new Error(`Unexpected server respnse status code "${res.status}".`);
    })
    .then(res => res.text())
    .then((signature) => {
      console.info(`API Auth token signature is "${signature}".`);
      embed.authorize(securityParams.clientId, signature);
    })
    .catch(err => {
      console.error(`Error signing API Auth token: ${err.message}`);
      console.info('Ending call.');
      embed.end();
    });
}
<commit_msg>added support for roomLock event<commit_after>/* eslint-disable no-console */

const tag = document.createElement('script');
tag.src = 'https://local.gruveo.com/embed-api/';
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

// eslint-disable-next-line no-unused-vars
function onGruveoEmbedAPIReady() {
  const embed = new Gruveo.Embed('myembed', {
    responsive: true,
    embedParams: Object.assign({
      color: '63b2de',
      chromeless: true,
      branding: false,
    }/* NOTE for old security use this: , securityParams */)
  });

  const roomLockCheckbox = document.getElementById('roomLock-chk');

  // attach event handlers
  embed
    .on('ready', () => {
      console.info('Ready.');
    })
    .on('stateChange', ({ state, callDuration }) => {
      console.info(`State set to "${state}".`);
      if (state === 'ready') {
        console.info(`Call duration was ${callDuration} s.`);
      }
    })
    .on('requestToSignApiAuthToken', ({ token }) => {
      console.info(`Signing API Auth token "${token}".`);
      fetch('/signer', {
        method: 'POST',
        body: token
      })
        .then((res) => {
          if (res.status === 200) {
            return res;
          }
          throw new Error(`Unexpected server respnse status code "${res.status}".`);
        })
        .then(res => res.text())
        .then((signature) => {
          console.info(`API Auth token signature is "${signature}".`);
          embed.authorize(securityParams.clientId, signature);
        })
        .catch(err => {
          console.error(`Error signing API Auth token: ${err.message}`);
          console.info('Ending call.');
          embed.end();
        });
    })
    .on('hangup', () => {
      console.info('Received "hangup".');
    })
    .on('busy', () => {
      console.info('Received "busy".');
    })
    .on('error', ({ error }) => {
      console.error(`Received error "${error}".`);
    })
    .on('roomLock', ({ locked }) => {
      console.info(`Received roomLock "${locked}".`, locked);
      roomLockCheckbox.checked = locked;
    })
    ;

  document.getElementById('form').addEventListener('submit', (e) => {
    // Generate a random code and start a video call on that code.
    const code = document.getElementById('code-input').value || Gruveo.Embed.generateRandomCode();
    console.info(`Calling code "${code}".`);
    embed.call(code, true);
    e.preventDefault();
  });
  document.getElementById('end-btn').addEventListener('click', () => {
    console.info('Ending call.');
    embed.end();
  });
  document.getElementById('audio-chk').addEventListener('change', (e) => {
    console.info('Toggling audio.');
    embed.toggleAudio(e.target.checked);
  });
  document.getElementById('video-chk').addEventListener('change', (e) => {
    console.info('Toggling video.');
    embed.toggleVideo(e.target.checked);
  });
  roomLockCheckbox.addEventListener('change', (e) => {
    console.info('Toggling room lock.');
    embed.toggleRoomLock(e.target.checked);
  });
  document.getElementById('switchCamera-btn').addEventListener('click', () => {
    console.info('Switching camera.');
    embed.switchCamera();
  });

}
<|endoftext|>


<commit_before>(function($) {

    /**
     * @class ZoomifyTileSource
     * @classdesc A tilesource implementation for the zoomify format.
     *
     * A description of the format can be found here:
     * https://ecommons.cornell.edu/bitstream/handle/1813/5410/Introducing_Zoomify_Image.pdf
     *
     * There are two ways of creating a zoomify tilesource for openseadragon
     *
     * 1) Supplying all necessary information in the tilesource object. A minimal example object for this method looks like this:
     *
     * {
     *      type: "zoomifytileservice",
     *      width: 1000,
     *      height: 1000,
     *      tilesUrl: "/test/data/zoomify/"
     * }
     *
     * The tileSize is set to 256 (the usual Zoomify default) when it is not defined. The tileUrl must the path to the image _directory_.
     *
     * 2) Loading image metadata from xml file: (CURRENTLY NOT SUPPORTED)
     *
     * When creating zoomify formatted images one "xml" like file with name ImageProperties.xml
     * will be created as well. Here is an example of such a file:
     *
     * <IMAGE_PROPERTIES WIDTH="1000" HEIGHT="1000" NUMTILES="21" NUMIMAGES="1" VERSION="1.8" TILESIZE="256" />
     *
     * To use this xml file as metadata source you must supply the path to the ImageProperties.xml file and leave out all other parameters:
     * As stated above, this method of loading a zoomify tilesource is currently not supported
     *
     * {
     *      type: "zoomifytileservice",
     *      tilesUrl: "/test/data/zoomify/ImageProperties.xml"
     * }

    *
    * @memberof OpenSeadragon
     * @extends OpenSeadragon.TileSource
     * @param {Number} width - the pixel width of the image.
     * @param {Number} height
     * @param {Number} tileSize
     * @param {String} tilesUrl
     */
    $.ZoomifyTileSource = function(options) {
        if(options.tileSize === undefined){
            options.tileSize = 256;
        }

        var currentImageSize = {
            x: options.width,
            y: options.height
        };
        options.imageSizes = [{
            x: options.width,
            y: options.height
        }];
        options.gridSize = [this._getGridSize(options.width, options.height, options.tileSize)];

        while (parseInt(currentImageSize.x, 10) > options.tileSize || parseInt(currentImageSize.y, 10) > options.tileSize) {
            currentImageSize.x = Math.floor(currentImageSize.x / 2);
            currentImageSize.y = Math.floor(currentImageSize.y / 2);
            options.imageSizes.push({
                x: currentImageSize.x,
                y: currentImageSize.y
            });
            options.gridSize.push(this._getGridSize(currentImageSize.x, currentImageSize.y, options.tileSize));
        }
        options.imageSizes.reverse();
        options.gridSize.reverse();
        options.minLevel = 0;
        options.maxLevel = options.gridSize.length - 1;

        OpenSeadragon.TileSource.apply(this, [options]);
    };

    $.extend($.ZoomifyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ZoomifyTileSource.prototype */ {

        //private
        _getGridSize: function(width, height, tileSize) {
            return {
                x: Math.ceil(width / tileSize),
                y: Math.ceil(height / tileSize)
            };
        },

        //private
        _calculateAbsoluteTileNumber: function(level, x, y) {
            var num = 0;
            var size = {};

            //Sum up all tiles below the level we want the number of tiles
            for (var z = 0; z < level; z++) {
                size = this.gridSize[z];
                num += size.x * size.y;
            }
            //Add the tiles of the level
            size = this.gridSize[level];
            num += size.x * y + x;
            return num;
        },

        /**
         * Determine if the data and/or url imply the image service is supported by
         * this tile source.
         * @function
         * @param {Object|Array} data
         * @param {String} optional - url
         */
        supports: function(data, url) {
            return (data.type && "zoomifytileservice" === data.type);
        },

        /**
         *
         * @function
         * @param {Object} data - the raw configuration
         * @param {String} url - the url the data was retrieved from if any.
         * @return {Object} options - A dictionary of keyword arguments sufficient
         *      to configure this tile sources constructor.
         */
        configure: function(data, url) {
            return data;
        },

        /**
         * @function
         * @param {Number} level
         * @param {Number} x
         * @param {Number} y
         */
        getTileUrl: function(level, x, y) {
            //console.log(level);
            var result = 0;
            var num = this._calculateAbsoluteTileNumber(level, x, y);
            result = Math.floor(num / 256);
            return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.jpg';

        }
    });

}(OpenSeadragon));

<commit_msg>revised tileSize check as suggested by @msalsbery<commit_after>(function($) {

    /**
     * @class ZoomifyTileSource
     * @classdesc A tilesource implementation for the zoomify format.
     *
     * A description of the format can be found here:
     * https://ecommons.cornell.edu/bitstream/handle/1813/5410/Introducing_Zoomify_Image.pdf
     *
     * There are two ways of creating a zoomify tilesource for openseadragon
     *
     * 1) Supplying all necessary information in the tilesource object. A minimal example object for this method looks like this:
     *
     * {
     *      type: "zoomifytileservice",
     *      width: 1000,
     *      height: 1000,
     *      tilesUrl: "/test/data/zoomify/"
     * }
     *
     * The tileSize is set to 256 (the usual Zoomify default) when it is not defined. The tileUrl must the path to the image _directory_.
     *
     * 2) Loading image metadata from xml file: (CURRENTLY NOT SUPPORTED)
     *
     * When creating zoomify formatted images one "xml" like file with name ImageProperties.xml
     * will be created as well. Here is an example of such a file:
     *
     * <IMAGE_PROPERTIES WIDTH="1000" HEIGHT="1000" NUMTILES="21" NUMIMAGES="1" VERSION="1.8" TILESIZE="256" />
     *
     * To use this xml file as metadata source you must supply the path to the ImageProperties.xml file and leave out all other parameters:
     * As stated above, this method of loading a zoomify tilesource is currently not supported
     *
     * {
     *      type: "zoomifytileservice",
     *      tilesUrl: "/test/data/zoomify/ImageProperties.xml"
     * }

    *
    * @memberof OpenSeadragon
     * @extends OpenSeadragon.TileSource
     * @param {Number} width - the pixel width of the image.
     * @param {Number} height
     * @param {Number} tileSize
     * @param {String} tilesUrl
     */
    $.ZoomifyTileSource = function(options) {
        if(typeof options.tileSize === 'undefined'){
            options.tileSize = 256;
        }

        var currentImageSize = {
            x: options.width,
            y: options.height
        };
        options.imageSizes = [{
            x: options.width,
            y: options.height
        }];
        options.gridSize = [this._getGridSize(options.width, options.height, options.tileSize)];

        while (parseInt(currentImageSize.x, 10) > options.tileSize || parseInt(currentImageSize.y, 10) > options.tileSize) {
            currentImageSize.x = Math.floor(currentImageSize.x / 2);
            currentImageSize.y = Math.floor(currentImageSize.y / 2);
            options.imageSizes.push({
                x: currentImageSize.x,
                y: currentImageSize.y
            });
            options.gridSize.push(this._getGridSize(currentImageSize.x, currentImageSize.y, options.tileSize));
        }
        options.imageSizes.reverse();
        options.gridSize.reverse();
        options.minLevel = 0;
        options.maxLevel = options.gridSize.length - 1;

        OpenSeadragon.TileSource.apply(this, [options]);
    };

    $.extend($.ZoomifyTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.ZoomifyTileSource.prototype */ {

        //private
        _getGridSize: function(width, height, tileSize) {
            return {
                x: Math.ceil(width / tileSize),
                y: Math.ceil(height / tileSize)
            };
        },

        //private
        _calculateAbsoluteTileNumber: function(level, x, y) {
            var num = 0;
            var size = {};

            //Sum up all tiles below the level we want the number of tiles
            for (var z = 0; z < level; z++) {
                size = this.gridSize[z];
                num += size.x * size.y;
            }
            //Add the tiles of the level
            size = this.gridSize[level];
            num += size.x * y + x;
            return num;
        },

        /**
         * Determine if the data and/or url imply the image service is supported by
         * this tile source.
         * @function
         * @param {Object|Array} data
         * @param {String} optional - url
         */
        supports: function(data, url) {
            return (data.type && "zoomifytileservice" === data.type);
        },

        /**
         *
         * @function
         * @param {Object} data - the raw configuration
         * @param {String} url - the url the data was retrieved from if any.
         * @return {Object} options - A dictionary of keyword arguments sufficient
         *      to configure this tile sources constructor.
         */
        configure: function(data, url) {
            return data;
        },

        /**
         * @function
         * @param {Number} level
         * @param {Number} x
         * @param {Number} y
         */
        getTileUrl: function(level, x, y) {
            //console.log(level);
            var result = 0;
            var num = this._calculateAbsoluteTileNumber(level, x, y);
            result = Math.floor(num / 256);
            return this.tilesUrl + 'TileGroup' + result + '/' + level + '-' + x + '-' + y + '.jpg';

        }
    });

}(OpenSeadragon));

<|endoftext|>


<commit_before>/**
 * @license
 * Vissense <http://vissense.com/>
 * Copyright 2014 tbk <theborakompanioni+vissense@gmail.com>
 * Available under MIT license <http://opensource.org/licenses/MIT>
 */

 /**
 * detects visibility changes of an element.
 *
 * example:
 * var elem = document.getElementById('myElement');
 * var visobj = VisSense(eleme):
 * var vismon = visobj.monitor();
 *
 * vismon.onVisibilityChange(function() { ... });
 * vismon.onVisibilityPercentageChange(function() { ... });
 * vismon.onVisible(function() { ... });
 * vismon.onFullyVisible(function() { ... });
 * vismon.onHidden(function() { ... });
 *
 *
 * hasVisibilityChanged() // => true
 * hasVisibilityPercentageChanged // => true
 *
 * fireIfVisibilityChanged(function() { ... });
 * fireIfVisibilityPercentageChanged(function() { ... });
 *
 */
;(function(window, Math, VisSense, VisSenseUtils) {
  'use strict';
    /** Used as a safe reference for `undefined` in pre ES5 environments */
    var undefined;

    /** Used as a reference to the global object */
    var root = (typeof window === 'object' && window) || this;

    var states =  {
        HIDDEN: 0,
        VISIBLE: 1,
        FULLY_VISIBLE: 2
    };

    var updateTriggerEvents = ['readystatechange', 'scroll', 'resize'];

    /*--------------------------------------------------------------------------*/

    var VisState = (function() {
        var STATES = {
            HIDDEN: 0,
            VISIBLE: 1,
            FULLY_VISIBLE: 2
        };

        function VisState(state) {
            this.isVisible = function() {
                return state ===  STATES.VISIBLE || this.isFullyVisible();
            };
            this.isFullyVisible = function() {
                return state ===  STATES.FULLY_VISIBLE;
            };
            this.isHidden = function() {
                return state ===  STATES.HIDDEN;
            };
            this.state = function() {
                return state;
            };
        }

        function withPrevious(visstate, prev) {
            if(!!prev) {
                // disable getting previous state from prev
                prev.prev = VisSenseUtils.noop;
            }

            visstate.wasVisible = function() {
                return !!prev && prev.isVisible();
            };
            visstate.wasFullyVisible = function() {
                return !!prev && prev.isFullyVisible();
            };
            visstate.wasHidden = function() {
                return !!prev && prev.isHidden();
            };
            visstate.hasVisibilityChanged = function() {
                return !prev || visstate.state() !== prev.state();
            };
            visstate.prev = function() {
                return prev;
            };
            return visstate;
        }

        function withPercentage(visstate, percentage) {
            visstate.hasVisibilityPercentageChanged = function() {
                return !this.prev() || percentage !== this.prev().percentage();
            };
            visstate.percentage = function() {
                return percentage;
            };
            return visstate;
        }

        function state(status, percentage, prev) {
            return withPrevious(withPercentage(new VisState(status), percentage), prev);
        }

        var exports = {};

        exports.state = state;

        exports.hidden = function(percentage, prev) {
            return state(STATES.HIDDEN, percentage, prev || null);
        };

        exports.visible = function(percentage, prev) {
            return state(STATES.VISIBLE, percentage, prev || null);
        };
        exports.fullyvisible = function(percentage, prev) {
            return state(STATES.FULLY_VISIBLE, percentage, prev || null);
        };

        return exports;
    }());

    function nextState(visobj, visstate) {
        var percentage = visobj.getVisibilityPercentage();
        if(visobj.isHidden()) {
            return VisState.hidden(percentage, visstate);
        } else if (visobj.isFullyVisible()) {
             return VisState.fullyvisible(percentage, visstate);
        } else if (visobj.isVisible()) {
          return VisState.visible(percentage, visstate);
        }
        throw new Error('IllegalState');
    };

    /*--------------------------------------------------------------------------*/

    function fireListeners(listeners, context) {
        for(var i in listeners) {
            listeners[i].call(context || root);
        }
    }
    /*--------------------------------------------------------------------------*/

    function VisMon(visobj, config) {
        var self = this;

        var lastListenerId = -1;
        var _private = {
          status: null,
          listeners: []
        };

        // read-only access to VisSense instance
        self.visobj = function() {
            return visobj;
        };

        /**
        * read-only access to status
        */
        self.status = function(prop) {
            return _private.status;
        };

        self.getVisibilityPercentage = function() {
            return self.status().percentage();
        }
        /**
        * read-only access to status
        */
        self.prev = function(prop) {
            return self.status().prev();
        };

        // Adds a listener.
        //
        // var id = visobj.monitor().register(function() {
        //   doSomething();
        // });
        self.register = function(callback) {
            lastListenerId += 1;
            _private.listeners[lastListenerId] = callback;
            return lastListenerId;
        };

        /**
        * expose update method
        */
        VisMon.prototype.update = _update;

        (function init() {
            // react on tab changes
            VisSenseUtils.onPageVisibilityChange(_update);

            for(var i in updateTriggerEvents) {
                VisSenseUtils.addEvent(root, updateTriggerEvents[i], _update);
            }

            _update();
            // reschedule update immediately
            VisSenseUtils.defer(_update);
        }());

        function _update() {
            _private.status = nextState(visobj, _private.status);

            // notify listeners
            fireListeners(_private.listeners, self);
        }
    }

    VisSense.monitor = function monitor(visobj, config) {
        return new VisMon(visobj, config);
    };

    VisSense.prototype.monitor = function(config) {
        return VisSense.monitor(this, config);
    };

    /**
    * Returns a function that invokes callback only
    * if the visibility state changes.
    *
    * shorthand for
    * if(visobj.hasVisibilityChanged()) {
    *   callback();
    * }
    * visobj.fireIfVisibilityChanged(callback)
    */
    VisMon.prototype.fireIfVisibilityChanged = function(callback) {
        var self = this;
        return VisSenseUtils.fireIf(function() {
            return self.status().hasVisibilityChanged();
        }, callback);
    };

    /**
    * Returns a function that invokes callback only
    * if visibility rate changes.
    * This does not occur when element is hidden but may
    * be called multiple times if element is in state
    * `VISIBLE` and (depending on the config) `FULLY_VISIBLE`
    */
    VisMon.prototype.fireIfVisibilityPercentageChanged = function(callback) {
        var self = this;
        return VisSenseUtils.fireIf(function() {
            return self.status().hasVisibilityPercentageChanged();
        }, callback);
    };

    /**
    * Fires when visibility state changes
    */
    VisMon.prototype.onVisibilityChange = function (callback) {
        return this.register(this.fireIfVisibilityChanged(callback));
    };

    /**
    * Fires when visibility percentage changes
    */
    VisMon.prototype.onVisibilityPercentageChange = function (callback) {
        return this.register(this.fireIfVisibilityPercentageChanged(callback));
    };

    /**
    * Fires when visibility changes and and state transits from:
    * HIDDEN => VISIBLE
    * HIDDEN => FULLY_VISIBLE
    * Fires NOT when state transits from:
    * VISIBLE => FULLY_VISIBLE or
    * FULLY_VISIBLE => VISIBLE
    *
    * VisSense(document.getElementById('example1')).monitor().onVisible(function() {
    *   Animations.startAnimation();
    * });
    */
    VisMon.prototype.onVisible = function (callback) {
        var self = this;

        var fireIfVisible =  VisSenseUtils.fireIf(function() {
            return self.status().isVisible();
        }, callback);

        // only fire when coming from state hidden or no previous state is present
        var handler = this.fireIfVisibilityChanged(VisSenseUtils.fireIf(function() {
            return !self.status().prev() || self.status().wasHidden();
        }, fireIfVisible));
        return this.register(handler);
    };

    /**
    * Fires when visibility changes and element becomes fully visible
    */
    VisMon.prototype.onFullyVisible = function (callback) {
        var self = this;
        var fireIfFullyVisible =  VisSenseUtils.fireIf(function() {
            return self.status().isFullyVisible();
        }, callback);

        var handler = this.fireIfVisibilityChanged(fireIfFullyVisible);
        return this.register(handler);
    };

    /**
    * Fires when visibility changes and element becomes hidden
    */
    VisMon.prototype.onHidden = function (callback) {
        var self = this;

        var fireIfHidden =  VisSenseUtils.fireIf(function() {
            return self.status().isHidden();
        }, callback);

        var handler = this.fireIfVisibilityChanged(fireIfHidden);
        return this.register(handler);
    };

    VisMon.prototype.on = function(eventName, handler) {
        var emitEvents = {
            'hidden' : this.onHidden,
            'visible' : this.onVisible,
            'fullyvisible' : this.onFullyVisible,
            'percentagechange' : this.onVisibilityPercentageChange,
            'visibilitychange' : this.onVisibilityChange
        };
        if(!emitEvents[eventName]) {
            throw new Error("VisMon: Event '"+ eventName +"' is not supported");
        }
        return emitEvents[eventName](handler);
    };

}.call(this, this, this.Math, this.VisSense, this.VisSenseUtils));<commit_msg>trigger update on mousemove over element<commit_after>/**
 * @license
 * Vissense <http://vissense.com/>
 * Copyright 2014 tbk <theborakompanioni+vissense@gmail.com>
 * Available under MIT license <http://opensource.org/licenses/MIT>
 */

 /**
 * detects visibility changes of an element.
 *
 * example:
 * var elem = document.getElementById('myElement');
 * var visobj = VisSense(eleme):
 * var vismon = visobj.monitor();
 *
 * vismon.onVisibilityChange(function() { ... });
 * vismon.onVisibilityPercentageChange(function() { ... });
 * vismon.onVisible(function() { ... });
 * vismon.onFullyVisible(function() { ... });
 * vismon.onHidden(function() { ... });
 *
 *
 * hasVisibilityChanged() // => true
 * hasVisibilityPercentageChanged // => true
 *
 * fireIfVisibilityChanged(function() { ... });
 * fireIfVisibilityPercentageChanged(function() { ... });
 *
 */
;(function(window, Math, VisSense, VisSenseUtils) {
  'use strict';
    /** Used as a safe reference for `undefined` in pre ES5 environments */
    var undefined;

    /** Used as a reference to the global object */
    var root = (typeof window === 'object' && window) || this;

    var states =  {
        HIDDEN: 0,
        VISIBLE: 1,
        FULLY_VISIBLE: 2
    };

    var updateTriggerEvents = ['readystatechange', 'scroll', 'resize'];

    /*--------------------------------------------------------------------------*/

    var VisState = (function() {
        var STATES = {
            HIDDEN: 0,
            VISIBLE: 1,
            FULLY_VISIBLE: 2
        };

        function VisState(state) {
            this.isVisible = function() {
                return state ===  STATES.VISIBLE || this.isFullyVisible();
            };
            this.isFullyVisible = function() {
                return state ===  STATES.FULLY_VISIBLE;
            };
            this.isHidden = function() {
                return state ===  STATES.HIDDEN;
            };
            this.state = function() {
                return state;
            };
        }

        function withPrevious(visstate, prev) {
            if(!!prev) {
                // disable getting previous state from prev
                prev.prev = VisSenseUtils.noop;
            }

            visstate.wasVisible = function() {
                return !!prev && prev.isVisible();
            };
            visstate.wasFullyVisible = function() {
                return !!prev && prev.isFullyVisible();
            };
            visstate.wasHidden = function() {
                return !!prev && prev.isHidden();
            };
            visstate.hasVisibilityChanged = function() {
                return !prev || visstate.state() !== prev.state();
            };
            visstate.prev = function() {
                return prev;
            };
            return visstate;
        }

        function withPercentage(visstate, percentage) {
            visstate.hasVisibilityPercentageChanged = function() {
                return !this.prev() || percentage !== this.prev().percentage();
            };
            visstate.percentage = function() {
                return percentage;
            };
            return visstate;
        }

        function state(status, percentage, prev) {
            return withPrevious(withPercentage(new VisState(status), percentage), prev);
        }

        var exports = {};

        exports.state = state;

        exports.hidden = function(percentage, prev) {
            return state(STATES.HIDDEN, percentage, prev || null);
        };

        exports.visible = function(percentage, prev) {
            return state(STATES.VISIBLE, percentage, prev || null);
        };
        exports.fullyvisible = function(percentage, prev) {
            return state(STATES.FULLY_VISIBLE, percentage, prev || null);
        };

        return exports;
    }());

    function nextState(visobj, visstate) {
        var percentage = visobj.getVisibilityPercentage();
        if(visobj.isHidden()) {
            return VisState.hidden(percentage, visstate);
        } else if (visobj.isFullyVisible()) {
             return VisState.fullyvisible(percentage, visstate);
        } else if (visobj.isVisible()) {
          return VisState.visible(percentage, visstate);
        }
        throw new Error('IllegalState');
    };

    /*--------------------------------------------------------------------------*/

    function fireListeners(listeners, context) {
        for(var i in listeners) {
            listeners[i].call(context || root);
        }
    }
    /*--------------------------------------------------------------------------*/

    function VisMon(visobj, config) {
        var self = this;

        var lastListenerId = -1;
        var _private = {
          status: null,
          listeners: []
        };

        // read-only access to VisSense instance
        self.visobj = function() {
            return visobj;
        };

        /**
        * read-only access to status
        */
        self.status = function(prop) {
            return _private.status;
        };

        self.getVisibilityPercentage = function() {
            return self.status().percentage();
        }
        /**
        * read-only access to status
        */
        self.prev = function(prop) {
            return self.status().prev();
        };

        // Adds a listener.
        //
        // var id = visobj.monitor().register(function() {
        //   doSomething();
        // });
        self.register = function(callback) {
            lastListenerId += 1;
            _private.listeners[lastListenerId] = callback;
            return lastListenerId;
        };

        /**
        * expose update method
        */
        VisMon.prototype.update = _update;

        (function init() {
            // react on tab changes
            VisSenseUtils.onPageVisibilityChange(_update);

            for(var i in updateTriggerEvents) {
                VisSenseUtils.addEvent(root, updateTriggerEvents[i], _update);
            }

            // triggers update if mouse moves over element
            // this is important if the element is draggable
            VisSenseUtils.addEvent(visobj._element, 'mousemove', _update);

            _update();
            // reschedule update immediately
            VisSenseUtils.defer(_update);
        }());

        function _update() {
            _private.status = nextState(visobj, _private.status);

            // notify listeners
            fireListeners(_private.listeners, self);
        }
    }

    VisSense.monitor = function monitor(visobj, config) {
        return new VisMon(visobj, config);
    };

    VisSense.prototype.monitor = function(config) {
        return VisSense.monitor(this, config);
    };

    /**
    * Returns a function that invokes callback only
    * if the visibility state changes.
    *
    * shorthand for
    * if(visobj.hasVisibilityChanged()) {
    *   callback();
    * }
    * visobj.fireIfVisibilityChanged(callback)
    */
    VisMon.prototype.fireIfVisibilityChanged = function(callback) {
        var self = this;
        return VisSenseUtils.fireIf(function() {
            return self.status().hasVisibilityChanged();
        }, callback);
    };

    /**
    * Returns a function that invokes callback only
    * if visibility rate changes.
    * This does not occur when element is hidden but may
    * be called multiple times if element is in state
    * `VISIBLE` and (depending on the config) `FULLY_VISIBLE`
    */
    VisMon.prototype.fireIfVisibilityPercentageChanged = function(callback) {
        var self = this;
        return VisSenseUtils.fireIf(function() {
            return self.status().hasVisibilityPercentageChanged();
        }, callback);
    };

    /**
    * Fires when visibility state changes
    */
    VisMon.prototype.onVisibilityChange = function (callback) {
        return this.register(this.fireIfVisibilityChanged(callback));
    };

    /**
    * Fires when visibility percentage changes
    */
    VisMon.prototype.onVisibilityPercentageChange = function (callback) {
        return this.register(this.fireIfVisibilityPercentageChanged(callback));
    };

    /**
    * Fires when visibility changes and and state transits from:
    * HIDDEN => VISIBLE
    * HIDDEN => FULLY_VISIBLE
    * Fires NOT when state transits from:
    * VISIBLE => FULLY_VISIBLE or
    * FULLY_VISIBLE => VISIBLE
    *
    * VisSense(document.getElementById('example1')).monitor().onVisible(function() {
    *   Animations.startAnimation();
    * });
    */
    VisMon.prototype.onVisible = function (callback) {
        var self = this;

        var fireIfVisible =  VisSenseUtils.fireIf(function() {
            return self.status().isVisible();
        }, callback);

        // only fire when coming from state hidden or no previous state is present
        var handler = this.fireIfVisibilityChanged(VisSenseUtils.fireIf(function() {
            return !self.status().prev() || self.status().wasHidden();
        }, fireIfVisible));
        return this.register(handler);
    };

    /**
    * Fires when visibility changes and element becomes fully visible
    */
    VisMon.prototype.onFullyVisible = function (callback) {
        var self = this;
        var fireIfFullyVisible =  VisSenseUtils.fireIf(function() {
            return self.status().isFullyVisible();
        }, callback);

        var handler = this.fireIfVisibilityChanged(fireIfFullyVisible);
        return this.register(handler);
    };

    /**
    * Fires when visibility changes and element becomes hidden
    */
    VisMon.prototype.onHidden = function (callback) {
        var self = this;

        var fireIfHidden =  VisSenseUtils.fireIf(function() {
            return self.status().isHidden();
        }, callback);

        var handler = this.fireIfVisibilityChanged(fireIfHidden);
        return this.register(handler);
    };

    VisMon.prototype.on = function(eventName, handler) {
        var emitEvents = {
            'hidden' : this.onHidden,
            'visible' : this.onVisible,
            'fullyvisible' : this.onFullyVisible,
            'percentagechange' : this.onVisibilityPercentageChange,
            'visibilitychange' : this.onVisibilityChange
        };
        if(!emitEvents[eventName]) {
            throw new Error("VisMon: Event '"+ eventName +"' is not supported");
        }
        return emitEvents[eventName](handler);
    };

}.call(this, this, this.Math, this.VisSense, this.VisSenseUtils));<|endoftext|>


<commit_before>/*
    PP - Phenopolis's JavaScript module

    Define a global PP (acronym for Phenopolis) object containing all
    PP associated methods:
*/

// define global PP object
var PP;
if (!PP) {
  PP = {};
}

// PP module
(function() {
  PP.equalizeAboutBoxes = function() {
    PP.equalSizeDiv('.collection');
    $(window).resize(function() {
      $('.collection').css('height', 'auto');
      PP.equalSizeDiv('.collection');
    });
  };

  PP.equalSizeDiv = function(div) {
    if ($(div).length === 0) return;
    var maxHeight = 0;
    $(div).each(function() {
      if ($(this).height() > maxHeight) { maxHeight = $(this).height(); }
    });
    $(div).css('height', maxHeight);
  };

  PP.initLogin = function() {
    PP.openLoginModelOnClick('#enter_login_btn');

    // Submit form upon clicking the login button in the modal
    $('#login_btn').on('click', function() {
      PP.submitLogin();
    });

    // submit form upon pressing enter in the login form
    $('#login_form input').keydown(function(e) {
      if (e.keyCode == 13) PP.submitLogin();
    });

    // Automatically login when selecting the demo login button
    $('#demo_login_btn, #parallax_demo_login_btn').on('click', function() {
      $('#name').val('demo');
      $('#password').val('demo123');
      PP.submitLogin();
    });

    $('#register_btn').on('click', function() {
      PP.showRegistrationForm();
    });

    $('#submit_register_btn').on('click', function() {
      PP.submitRegisterForm();
    });
  };

  // TODO: Replace with JQuery.validate
  // show Login Model
  PP.submitLogin = function() {
    $('#auth_modal').modal({ dismissible: false, endingTop: '20%' });
    $('#auth_modal').modal('open');

    $.ajax({
      type: 'POST',
      url: '/login',
      data: $('#login_form').serialize(),
      dataType: 'json',
      timeout: 120000,
      success: function(data) {
        window.location.href = '/search';
      },
      error: function(data, msg) {
        $('#auth_modal').modal('close');
        $("#username, #password").addClass("invalid");
        $("#username, #password").prop("aria-invalid", "true");
        $('#login_form_error_msg').show();
      }
    });
  };

  //
  PP.showRegistrationForm = function() {
    $('#login_content').hide();
    $('#register_btn').hide();
    $('#login_btn').hide();
    $('#demo_login_btn').hide();

    $('#register_content').show();
    $('#enter_login_btn').show();
    $('#submit_register_btn').show();
  };

  //
  PP.showLoginForm = function() {
    $('#login_content').show();
    $('#register_btn').show();
    $('#login_btn').show();
    $('#demo_login_btn').show();

    $('#register_content').hide();
    $('#enter_login_btn').hide();
    $('#submit_register_btn').hide();
  };

  //
  PP.openLoginModelOnClick = function(id) {
    $(id).on('click', function() {
      PP.showLoginForm();
    });
  };

  //
  PP.submitRegisterForm = function() {
    $.ajax({
      type: 'POST',
      url: '/register',
      data: $('#login_form').serialize(),
      dataType: 'json',
      timeout: 120000,
      success: function(data) {
        $('#registration_successful').show();
      },
      error: function(data, msg) {
        console.log(data);
        console.log(msg);
      }
    });
  };
}());
// End of PP module
<commit_msg>submit register form<commit_after>/*
    PP - Phenopolis's JavaScript module

    Define a global PP (acronym for Phenopolis) object containing all
    PP associated methods:
*/

// define global PP object
var PP;
if (!PP) {
  PP = {};
}

// PP module
(function() {
  PP.equalizeAboutBoxes = function() {
    PP.equalSizeDiv('.collection');
    $(window).resize(function() {
      $('.collection').css('height', 'auto');
      PP.equalSizeDiv('.collection');
    });
  };

  PP.equalSizeDiv = function(div) {
    if ($(div).length === 0) return;
    var maxHeight = 0;
    $(div).each(function() {
      if ($(this).height() > maxHeight) { maxHeight = $(this).height(); }
    });
    $(div).css('height', maxHeight);
  };

  PP.initLogin = function() {
    PP.openLoginModelOnClick('#enter_login_btn');

    // Submit form upon clicking the login button in the modal
    $('#login_btn').on('click', function() {
      PP.submitLogin();
    });

    // submit form upon pressing enter in the login form
    $('#login_form input').keydown(function(e) {
      if (e.keyCode == 13) PP.submitLogin();
    });

    // Automatically login when selecting the demo login button
    $('#demo_login_btn, #parallax_demo_login_btn').on('click', function() {
      $('#name').val('demo');
      $('#password').val('demo123');
      PP.submitLogin();
    });

    $('#register_btn').on('click', function() {
      PP.showRegistrationForm();
    });

    $('#submit_register_btn').on('click', function() {
      PP.submitRegisterForm();
    });
  };

  // TODO: Replace with JQuery.validate
  // show Login Model
  PP.submitLogin = function() {
    $('#auth_modal').modal({ dismissible: false, endingTop: '20%' });
    $('#auth_modal').modal('open');

    $.ajax({
      type: 'POST',
      url: '/login',
      data: $('#login_form').serialize(),
      dataType: 'json',
      timeout: 120000,
      success: function(data) {
        window.location.href = '/search';
      },
      error: function(data, msg) {
        $('#auth_modal').modal('close');
        $("#username, #password").addClass("invalid");
        $("#username, #password").prop("aria-invalid", "true");
        $('#login_form_error_msg').show();
      }
    });
  };

  //
  PP.showRegistrationForm = function() {
    $('#login_content').hide();
    $('#register_btn').hide();
    $('#login_btn').hide();
    $('#demo_login_btn').hide();

    $('#register_content').show();
    $('#enter_login_btn').show();
    $('#submit_register_btn').show();
  };

  //
  PP.showLoginForm = function() {
    $('#login_content').show();
    $('#register_btn').show();
    $('#login_btn').show();
    $('#demo_login_btn').show();

    $('#register_content').hide();
    $('#enter_login_btn').hide();
    $('#submit_register_btn').hide();
  };

  //
  PP.openLoginModelOnClick = function(id) {
    $(id).on('click', function() {
      PP.showLoginForm();
    });
  };

  //
  PP.submitRegisterForm = function() {
    $.ajax({
      type: 'POST',
      url: '/register',
      data: $('#register_form').serialize(),
      dataType: 'json',
      timeout: 120000,
      success: function(data) {
        $('#registration_successful').show();
      },
      error: function(data, msg) {
        console.log(data);
        console.log(msg);
      }
    });
  };
}());
// End of PP module
<|endoftext|>