<commit_before>//
// Annotation study results view
//

// Model for a feature
isic.models.FeatureModel = Backbone.Model.extend({
    name: function () {
        return this.get('name');
    }
});

// Model for a feature image
isic.models.FeatureImageModel = Backbone.Model.extend({
});

// Model for a global feature result
isic.models.GlobalFeatureResultModel = Backbone.Model.extend({
});

// Collection of feature models
isic.collections.FeatureCollection = Backbone.Collection.extend({
    model: isic.models.FeatureModel,

    // Update collection from an array of features of the form:
    // { 'id': id, 'name': [name1, name2, ...] }
    update: function (features) {
        var models = _.map(features, function (feature) {
            var featureId = feature['id'];
            var featureNames = feature['name'];
            var model = new isic.models.FeatureModel({
                id: featureId,
                name: featureNames.join(', ')
            });
            return model;
        });
        this.reset(models);
    }
});

// Base view for a collection of models in a select tag
isic.views.StudyResultsSelectView = isic.View.extend({
    events: {
        'change': 'modelChanged'
    },

    initialize: function (options) {
        this.title = options.title;
        this.selectId = 'isic-study-results-select-view-select-' +
            isic.views.StudyResultsSelectView._count;
        this.getName = options.getName || this._defaultGetName;
        this.listenTo(this.collection, 'reset', this.render);

        this.render();

        ++isic.views.StudyResultsSelectView._count;
    },

    modelChanged: function () {
        this.trigger('changed', this._element().val());
    },

    setEnabled: function (val) {
        if (val) {
            this._element().removeAttr('disabled');
        } else {
            this._element().attr('disabled', 'disabled');
        }
    },

    update: function () {
        this.render();
        this._element().selectedIndex = 0;
        this.setEnabled(true);
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsSelectView({
            title: this.title,
            selectId: this.selectId,
            getName: this.getName,
            models: this.collection.models
        }));

        return this;
    },

    _element: function () {
        return this.$('select');
    },

    _defaultGetName: function (model) {
        return model.name();
    }
}, {
    // Class properties
    _count: 0
});

// Collection of global feature result models
isic.collections.GlobalFeatureResultCollection = Backbone.Collection.extend({
    model: isic.models.GlobalFeatureResultModel,

    // Update collection from annotation object and feature list
    update: function (annotations, features) {
        var models = _.map(features, function (feature) {
            var featureId = feature['id'];
            var featureNames = feature['name'];
            var model = new isic.models.GlobalFeatureResultModel({
                id: featureId,
                name: featureNames.join(', ')
            });
            if (annotations) {
                var featureOptions = _.indexBy(feature['options'], 'id');
                var resultId = annotations[featureId];
                var resultName = featureOptions[resultId]['name'];
                model.set('resultId', resultId);
                model.set('resultName', resultName);
            }
            return model;
        });
        this.reset(models);
    }
});

// View for a global feature table
isic.views.StudyResultsGlobalFeaturesTableView = isic.View.extend({
    initialize: function (settings) {
        this.listenTo(this.collection, 'reset', this.render);
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsGlobalFeaturesTable({
            features: this.collection.models
        }));
    }
});

// View for the annotation results of global features in a featureset
isic.views.StudyResultsGlobalFeaturesView = isic.View.extend({
    initialize: function (settings) {
        this.annotation = settings.annotation;
        this.featureset = settings.featureset;

        this.results = new isic.collections.GlobalFeatureResultCollection();
        this.listenTo(this.featureset, 'change', this.render);
        this.listenTo(this.featureset, 'change', this.updateResults);
        this.listenTo(this.annotation, 'change', this.updateResults);

        this.tableView = new isic.views.StudyResultsGlobalFeaturesTableView({
            collection: this.results,
            parentView: this
        });

        this.updateResults();
        this.render();
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsGlobalFeaturesPage({
            title: 'Global Features',
            hasFeatureset: !_.isUndefined(this.featureset.id),
            hasGlobalFeatures: !_.isEmpty(this.featureset.get('image_features')),
            featureset: this.featureset
        }));

        this.tableView.setElement(
            this.$('#isic-study-results-global-features-table')).render();

        return this;
    },

    updateResults: function () {
        this.results.update(
            this.annotation.get('annotations'),
            this.featureset.get('image_features')
        );
    }
});

// View for a local feature image defined by an annotation and local feature
isic.views.StudyResultsFeatureImageView = isic.View.extend({
    initialize: function (settings) {
        this.listenTo(this.model, 'change', this.render);
    },

    render: function () {
        var featureId = this.model.get('featureId');
        var annotationId = this.model.get('annotationId');
        var imageUrl = null;
        if (featureId && annotationId) {
            imageUrl = [girder.apiRoot, 'annotation', annotationId, 'image', featureId].join('/');
        }

        this.$el.html(isic.templates.studyResultsFeatureImagePage({
            imageUrl: imageUrl
        }));
    }
});

// View to allow selecting a local feature from a featureset and to display an
// image showing the annotation for the feature
isic.views.StudyResultsLocalFeaturesView = isic.View.extend({
    initialize: function (settings) {
        this.annotation = settings.annotation;
        this.featureset = settings.featureset;
        this.features = new isic.collections.FeatureCollection();

        this.featureImageModel = new isic.models.FeatureImageModel();

        this.listenTo(this.featureset, 'change', this.render);
        this.listenTo(this.featureset, 'change', this.updateFeatureCollection);
        this.listenTo(this.annotation, 'change', this.updateFeatureImageModel);

        this.selectFeatureView = new isic.views.StudyResultsSelectView({
            title: 'Feature',
            collection: this.features,
            parentView: this
        });

        this.imageView = new isic.views.StudyResultsFeatureImageView({
            model: this.featureImageModel,
            parentView: this
        });

        this.listenTo(this.selectFeatureView, 'changed', this.featureChanged);
    },

    featureChanged: function (featureId) {
        this.featureId = featureId;
        this.updateFeatureImageModel();
    },

    updateFeatureImageModel: function () {
        this.featureImageModel.set({
            featureId: this.featureId,
            annotationId: this.annotation.id
        });
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsLocalFeaturesPage({
            title: 'Local Features',
            hasFeatureset: !_.isUndefined(this.featureset.id),
            hasLocalFeatures: !_.isEmpty(this.featureset.get('region_features')),
            featureset: this.featureset
        }));

        this.selectFeatureView.setElement(
            this.$('#isic-study-results-select-local-feature-container')).render();
        this.imageView.setElement(
            this.$('#isic-study-results-local-features-image-container')).render();

        return this;
    },

    updateFeatureCollection: function () {
        delete this.featureId;

        this.features.update(this.featureset.get('region_features'));
    }
});

// View for an image
isic.views.StudyResultsImageView = isic.View.extend({
    initialize: function (settings) {
        this.listenTo(this.model, 'change', this.render);
    },

    render: function () {
        var imageUrl = this.model.id ? this.model.downloadUrl({contentDisposition: 'inline'}) : null;

        this.$el.html(isic.templates.studyResultsImagePage({
            imageUrl: imageUrl
        }));
    }
});

// View for the results of an annotation study
isic.views.StudyResultsView = isic.View.extend({
    initialize: function (settings) {
        this.studies = new isic.collections.StudyCollection();
        this.studies.pageLimit = Number.MAX_SAFE_INTEGER;

        this.images = new isic.collections.ImageCollection();
        this.images.pageLimit = Number.MAX_SAFE_INTEGER;

        this.users = new girder.collections.UserCollection();
        this.users.pageLimit = Number.MAX_SAFE_INTEGER;

        this.image = new isic.models.ImageModel();
        this.user = new girder.models.UserModel();
        this.featureset = new isic.models.FeaturesetModel();
        this.annotation = new isic.models.AnnotationModel();

        this.selectStudyView = new isic.views.StudyResultsSelectView({
            title: 'Study',
            collection: this.studies,
            parentView: this
        });

        this.selectImageView = new isic.views.StudyResultsSelectView({
            title: 'Image',
            collection: this.images,
            parentView: this
        });

        this.selectUserView = new isic.views.StudyResultsSelectView({
            title: 'User',
            getName: function (model) {
                return model.get('login');
            },
            collection: this.users,
            parentView: this
        });

        this.globalFeaturesView = new isic.views.StudyResultsGlobalFeaturesView({
            annotation: this.annotation,
            featureset: this.featureset,
            parentView: this
        });

        this.localFeaturesView = new isic.views.StudyResultsLocalFeaturesView({
            annotation: this.annotation,
            featureset: this.featureset,
            parentView: this
        });

        this.imageView = new isic.views.StudyResultsImageView({
            model: this.image,
            parentView: this
        });

        this.studies.fetch();

        this.listenTo(this.selectStudyView, 'changed', this.studyChanged);
        this.listenTo(this.selectImageView, 'changed', this.imageChanged);
        this.listenTo(this.selectUserView, 'changed', this.userChanged);

        this.render();
    },

    studyChanged: function (studyId) {
        this.images.reset();
        this.users.reset();

        this.image.clear();
        this.user.clear();

        this.selectImageView.setEnabled(false);
        this.selectUserView.setEnabled(false);

        this.annotation.clear();
        this.featureset.clear();

        // Fetch selected study
        this.study = new isic.models.StudyModel({
            _id: studyId
        }).once('g:fetched', function () {
            // Populate images collection
            var imageModels = _.map(this.study.get('images'), function (image) {
                return new isic.models.ImageModel(image);
            });
            this.images.reset(imageModels);

            // Populate users collection
            var userModels = _.map(this.study.get('users'), function (user) {
                return new girder.models.UserModel(user);
            });
            this.users.reset(userModels);

            // Fetch featureset
            var featureset = new isic.models.FeaturesetModel(this.study.get('featureset'));
            featureset.once('g:fetched', function () {
                this.featureset.set(featureset.attributes);
            }, this).fetch();
        }, this).fetch();
    },

    imageChanged: function (imageId) {
        this.image.set('_id', imageId);
        this.annotation.clear();
        this.fetchAnnotation();
    },

    userChanged: function (userId) {
        this.user.set('_id', userId);
        this.annotation.clear();
        this.fetchAnnotation();
    },

    fetchAnnotation: function () {
        if (!this.image.id ||
            !this.user.id) {
            return;
        }

        var annotations = new isic.collections.AnnotationCollection();
        annotations.once('g:changed', function () {
            if (!annotations.isEmpty()) {
                // Fetch annotation detail
                this.annotation.set(annotations.first().attributes).fetch();
            }
        }, this).fetch({
            studyId: this.study.id,
            userId: this.user.id,
            imageId: this.image.id
        });
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsPage({
            title: 'Annotation Study Results'
        }));

        this.selectStudyView.setElement(
            this.$('#isic-study-results-select-study-container')).render();
        this.selectImageView.setElement(
            this.$('#isic-study-results-select-image-container')).render();
        this.selectUserView.setElement(
            this.$('#isic-study-results-select-user-container')).render();
        this.globalFeaturesView.setElement(
            this.$('#isic-study-results-global-features-container')).render();
        this.localFeaturesView.setElement(
            this.$('#isic-study-results-local-features-container')).render();
        this.imageView.setElement(
            this.$('#isic-study-results-image-container')).render();

        return this;
    }
});

isic.router.route('studyResults', 'studyResults', function (id) {
    girder.events.trigger('g:navigateTo', isic.views.StudyResultsView);
});
<commit_msg>study results page: Generate select element ids with _.uniqueId()<commit_after>//
// Annotation study results view
//

// Model for a feature
isic.models.FeatureModel = Backbone.Model.extend({
    name: function () {
        return this.get('name');
    }
});

// Model for a feature image
isic.models.FeatureImageModel = Backbone.Model.extend({
});

// Model for a global feature result
isic.models.GlobalFeatureResultModel = Backbone.Model.extend({
});

// Collection of feature models
isic.collections.FeatureCollection = Backbone.Collection.extend({
    model: isic.models.FeatureModel,

    // Update collection from an array of features of the form:
    // { 'id': id, 'name': [name1, name2, ...] }
    update: function (features) {
        var models = _.map(features, function (feature) {
            var featureId = feature['id'];
            var featureNames = feature['name'];
            var model = new isic.models.FeatureModel({
                id: featureId,
                name: featureNames.join(', ')
            });
            return model;
        });
        this.reset(models);
    }
});

// Base view for a collection of models in a select tag
isic.views.StudyResultsSelectView = isic.View.extend({
    events: {
        'change': 'modelChanged'
    },

    initialize: function (options) {
        this.title = options.title;
        this.selectId = _.uniqueId('isic-study-results-select-view-select-');
        this.getName = options.getName || this._defaultGetName;
        this.listenTo(this.collection, 'reset', this.render);

        this.render();
    },

    modelChanged: function () {
        this.trigger('changed', this._element().val());
    },

    setEnabled: function (val) {
        if (val) {
            this._element().removeAttr('disabled');
        } else {
            this._element().attr('disabled', 'disabled');
        }
    },

    update: function () {
        this.render();
        this._element().selectedIndex = 0;
        this.setEnabled(true);
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsSelectView({
            title: this.title,
            selectId: this.selectId,
            getName: this.getName,
            models: this.collection.models
        }));

        return this;
    },

    _element: function () {
        return this.$('select');
    },

    _defaultGetName: function (model) {
        return model.name();
    }
});

// Collection of global feature result models
isic.collections.GlobalFeatureResultCollection = Backbone.Collection.extend({
    model: isic.models.GlobalFeatureResultModel,

    // Update collection from annotation object and feature list
    update: function (annotations, features) {
        var models = _.map(features, function (feature) {
            var featureId = feature['id'];
            var featureNames = feature['name'];
            var model = new isic.models.GlobalFeatureResultModel({
                id: featureId,
                name: featureNames.join(', ')
            });
            if (annotations) {
                var featureOptions = _.indexBy(feature['options'], 'id');
                var resultId = annotations[featureId];
                var resultName = featureOptions[resultId]['name'];
                model.set('resultId', resultId);
                model.set('resultName', resultName);
            }
            return model;
        });
        this.reset(models);
    }
});

// View for a global feature table
isic.views.StudyResultsGlobalFeaturesTableView = isic.View.extend({
    initialize: function (settings) {
        this.listenTo(this.collection, 'reset', this.render);
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsGlobalFeaturesTable({
            features: this.collection.models
        }));
    }
});

// View for the annotation results of global features in a featureset
isic.views.StudyResultsGlobalFeaturesView = isic.View.extend({
    initialize: function (settings) {
        this.annotation = settings.annotation;
        this.featureset = settings.featureset;

        this.results = new isic.collections.GlobalFeatureResultCollection();
        this.listenTo(this.featureset, 'change', this.render);
        this.listenTo(this.featureset, 'change', this.updateResults);
        this.listenTo(this.annotation, 'change', this.updateResults);

        this.tableView = new isic.views.StudyResultsGlobalFeaturesTableView({
            collection: this.results,
            parentView: this
        });

        this.updateResults();
        this.render();
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsGlobalFeaturesPage({
            title: 'Global Features',
            hasFeatureset: !_.isUndefined(this.featureset.id),
            hasGlobalFeatures: !_.isEmpty(this.featureset.get('image_features')),
            featureset: this.featureset
        }));

        this.tableView.setElement(
            this.$('#isic-study-results-global-features-table')).render();

        return this;
    },

    updateResults: function () {
        this.results.update(
            this.annotation.get('annotations'),
            this.featureset.get('image_features')
        );
    }
});

// View for a local feature image defined by an annotation and local feature
isic.views.StudyResultsFeatureImageView = isic.View.extend({
    initialize: function (settings) {
        this.listenTo(this.model, 'change', this.render);
    },

    render: function () {
        var featureId = this.model.get('featureId');
        var annotationId = this.model.get('annotationId');
        var imageUrl = null;
        if (featureId && annotationId) {
            imageUrl = [girder.apiRoot, 'annotation', annotationId, 'image', featureId].join('/');
        }

        this.$el.html(isic.templates.studyResultsFeatureImagePage({
            imageUrl: imageUrl
        }));
    }
});

// View to allow selecting a local feature from a featureset and to display an
// image showing the annotation for the feature
isic.views.StudyResultsLocalFeaturesView = isic.View.extend({
    initialize: function (settings) {
        this.annotation = settings.annotation;
        this.featureset = settings.featureset;
        this.features = new isic.collections.FeatureCollection();

        this.featureImageModel = new isic.models.FeatureImageModel();

        this.listenTo(this.featureset, 'change', this.render);
        this.listenTo(this.featureset, 'change', this.updateFeatureCollection);
        this.listenTo(this.annotation, 'change', this.updateFeatureImageModel);

        this.selectFeatureView = new isic.views.StudyResultsSelectView({
            title: 'Feature',
            collection: this.features,
            parentView: this
        });

        this.imageView = new isic.views.StudyResultsFeatureImageView({
            model: this.featureImageModel,
            parentView: this
        });

        this.listenTo(this.selectFeatureView, 'changed', this.featureChanged);
    },

    featureChanged: function (featureId) {
        this.featureId = featureId;
        this.updateFeatureImageModel();
    },

    updateFeatureImageModel: function () {
        this.featureImageModel.set({
            featureId: this.featureId,
            annotationId: this.annotation.id
        });
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsLocalFeaturesPage({
            title: 'Local Features',
            hasFeatureset: !_.isUndefined(this.featureset.id),
            hasLocalFeatures: !_.isEmpty(this.featureset.get('region_features')),
            featureset: this.featureset
        }));

        this.selectFeatureView.setElement(
            this.$('#isic-study-results-select-local-feature-container')).render();
        this.imageView.setElement(
            this.$('#isic-study-results-local-features-image-container')).render();

        return this;
    },

    updateFeatureCollection: function () {
        delete this.featureId;

        this.features.update(this.featureset.get('region_features'));
    }
});

// View for an image
isic.views.StudyResultsImageView = isic.View.extend({
    initialize: function (settings) {
        this.listenTo(this.model, 'change', this.render);
    },

    render: function () {
        var imageUrl = this.model.id ? this.model.downloadUrl({contentDisposition: 'inline'}) : null;

        this.$el.html(isic.templates.studyResultsImagePage({
            imageUrl: imageUrl
        }));
    }
});

// View for the results of an annotation study
isic.views.StudyResultsView = isic.View.extend({
    initialize: function (settings) {
        this.studies = new isic.collections.StudyCollection();
        this.studies.pageLimit = Number.MAX_SAFE_INTEGER;

        this.images = new isic.collections.ImageCollection();
        this.images.pageLimit = Number.MAX_SAFE_INTEGER;

        this.users = new girder.collections.UserCollection();
        this.users.pageLimit = Number.MAX_SAFE_INTEGER;

        this.image = new isic.models.ImageModel();
        this.user = new girder.models.UserModel();
        this.featureset = new isic.models.FeaturesetModel();
        this.annotation = new isic.models.AnnotationModel();

        this.selectStudyView = new isic.views.StudyResultsSelectView({
            title: 'Study',
            collection: this.studies,
            parentView: this
        });

        this.selectImageView = new isic.views.StudyResultsSelectView({
            title: 'Image',
            collection: this.images,
            parentView: this
        });

        this.selectUserView = new isic.views.StudyResultsSelectView({
            title: 'User',
            getName: function (model) {
                return model.get('login');
            },
            collection: this.users,
            parentView: this
        });

        this.globalFeaturesView = new isic.views.StudyResultsGlobalFeaturesView({
            annotation: this.annotation,
            featureset: this.featureset,
            parentView: this
        });

        this.localFeaturesView = new isic.views.StudyResultsLocalFeaturesView({
            annotation: this.annotation,
            featureset: this.featureset,
            parentView: this
        });

        this.imageView = new isic.views.StudyResultsImageView({
            model: this.image,
            parentView: this
        });

        this.studies.fetch();

        this.listenTo(this.selectStudyView, 'changed', this.studyChanged);
        this.listenTo(this.selectImageView, 'changed', this.imageChanged);
        this.listenTo(this.selectUserView, 'changed', this.userChanged);

        this.render();
    },

    studyChanged: function (studyId) {
        this.images.reset();
        this.users.reset();

        this.image.clear();
        this.user.clear();

        this.selectImageView.setEnabled(false);
        this.selectUserView.setEnabled(false);

        this.annotation.clear();
        this.featureset.clear();

        // Fetch selected study
        this.study = new isic.models.StudyModel({
            _id: studyId
        }).once('g:fetched', function () {
            // Populate images collection
            var imageModels = _.map(this.study.get('images'), function (image) {
                return new isic.models.ImageModel(image);
            });
            this.images.reset(imageModels);

            // Populate users collection
            var userModels = _.map(this.study.get('users'), function (user) {
                return new girder.models.UserModel(user);
            });
            this.users.reset(userModels);

            // Fetch featureset
            var featureset = new isic.models.FeaturesetModel(this.study.get('featureset'));
            featureset.once('g:fetched', function () {
                this.featureset.set(featureset.attributes);
            }, this).fetch();
        }, this).fetch();
    },

    imageChanged: function (imageId) {
        this.image.set('_id', imageId);
        this.annotation.clear();
        this.fetchAnnotation();
    },

    userChanged: function (userId) {
        this.user.set('_id', userId);
        this.annotation.clear();
        this.fetchAnnotation();
    },

    fetchAnnotation: function () {
        if (!this.image.id ||
            !this.user.id) {
            return;
        }

        var annotations = new isic.collections.AnnotationCollection();
        annotations.once('g:changed', function () {
            if (!annotations.isEmpty()) {
                // Fetch annotation detail
                this.annotation.set(annotations.first().attributes).fetch();
            }
        }, this).fetch({
            studyId: this.study.id,
            userId: this.user.id,
            imageId: this.image.id
        });
    },

    render: function () {
        this.$el.html(isic.templates.studyResultsPage({
            title: 'Annotation Study Results'
        }));

        this.selectStudyView.setElement(
            this.$('#isic-study-results-select-study-container')).render();
        this.selectImageView.setElement(
            this.$('#isic-study-results-select-image-container')).render();
        this.selectUserView.setElement(
            this.$('#isic-study-results-select-user-container')).render();
        this.globalFeaturesView.setElement(
            this.$('#isic-study-results-global-features-container')).render();
        this.localFeaturesView.setElement(
            this.$('#isic-study-results-local-features-container')).render();
        this.imageView.setElement(
            this.$('#isic-study-results-image-container')).render();

        return this;
    }
});

isic.router.route('studyResults', 'studyResults', function (id) {
    girder.events.trigger('g:navigateTo', isic.views.StudyResultsView);
});
<|endoftext|>


<commit_before>import { operationDelete } from '../operations/delete';
import { osmIsInterestingTag } from '../osm/tags';
import { osmOldMultipolygonOuterMemberOfRelation } from '../osm/multipolygon';
import { t } from '../util/locale';
import { utilDisplayLabel } from '../util';
import { validationIssue, validationIssueFix } from '../core/validation';

export function validationMissingTag(context) {
    var type = 'missing_tag';

    function hasDescriptiveTags(entity, graph) {
        var keys = Object.keys(entity.tags)
            .filter(function(k) {
                if (k === 'area' || k === 'name') {
                    return false;
                } else {
                    return osmIsInterestingTag(k);
                }
            });

        if (entity.type === 'relation' &&
            keys.length === 1 &&
            entity.tags.type === 'multipolygon') {
            // this relation's only interesting tag just says its a multipolygon,
            // which is not descriptive enough

            // It's okay for a simple multipolygon to have no descriptive tags
            // if its outer way has them (old model, see `outdated_tags.js`)
            return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
        }

        return keys.length > 0;
    }

    function isUnknownRoad(entity) {
        return entity.type === 'way' && entity.tags.highway === 'road';
    }

    function isUntypedRelation(entity) {
        return entity.type === 'relation' && !entity.tags.type;
    }

    var validation = function checkMissingTag(entity, graph) {

        // we can't know if the node is a vertex if the tile is undownloaded
        if ((entity.type === 'node' && !context.connection().isDataLoaded(entity.loc)) ||
            // allow untagged nodes that are part of ways
            entity.geometry(graph) === 'vertex' ||
            // allow untagged entities that are part of relations
            entity.hasParentRelations(graph)) {
            return [];
        }

        var subtype;

        if (Object.keys(entity.tags).length === 0) {
            subtype = 'any';
        } else if (!hasDescriptiveTags(entity, graph)) {
            subtype = 'descriptive';
        } else if (isUntypedRelation(entity)) {
            subtype = 'relation_type';
        } else if (isUnknownRoad(entity)) {
            subtype = 'highway_classification';
        }

        if (!subtype) return [];

        var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
        var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag';

        // can always delete if the user created it in the first place..
        var canDelete = (entity.version === undefined || entity.v !== undefined);
        var severity = (canDelete && subtype !== 'highway_classification') ? 'error' : 'warning';

        return [new validationIssue({
            type: type,
            subtype: subtype,
            severity: severity,
            message: function(context) {
                var entity = context.hasEntity(this.entityIds[0]);
                return entity ? t('issues.' + messageID + '.message', {
                    feature: utilDisplayLabel(entity, context)
                }) : '';
            },
            reference: showReference,
            entityIds: [entity.id],
            dynamicFixes: function(context) {

                var fixes = [];

                var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';

                fixes.push(new validationIssueFix({
                    icon: 'iD-icon-search',
                    title: t('issues.fix.' + selectFixType + '.title'),
                    onClick: function(context) {
                        context.ui().sidebar.showPresetList();
                    }
                }));

                var deleteOnClick;

                var id = this.entityIds[0];
                var operation = operationDelete([id], context);
                var disabledReasonID = operation.disabled();
                if (!disabledReasonID) {
                    deleteOnClick = function(context) {
                        var id = this.issue.entityIds[0];
                        var operation = operationDelete([id], context);
                        if (!operation.disabled()) {
                            operation();
                        }
                    };
                }

                fixes.push(
                    new validationIssueFix({
                        icon: 'iD-operation-delete',
                        title: t('issues.fix.delete_feature.title'),
                        disabledReason: disabledReasonID ? t('operations.delete.' + disabledReasonID + '.single') : undefined,
                        onClick: deleteOnClick
                    })
                );

                return fixes;
            }
        })];

        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.' + referenceID + '.reference'));
        }
    };

    validation.type = type;

    return validation;
}
<commit_msg>Add check to ensure osm service is available before calling isDataLoaded<commit_after>import { operationDelete } from '../operations/delete';
import { osmIsInterestingTag } from '../osm/tags';
import { osmOldMultipolygonOuterMemberOfRelation } from '../osm/multipolygon';
import { t } from '../util/locale';
import { utilDisplayLabel } from '../util';
import { validationIssue, validationIssueFix } from '../core/validation';

export function validationMissingTag(context) {
    var type = 'missing_tag';

    function hasDescriptiveTags(entity, graph) {
        var keys = Object.keys(entity.tags)
            .filter(function(k) {
                if (k === 'area' || k === 'name') {
                    return false;
                } else {
                    return osmIsInterestingTag(k);
                }
            });

        if (entity.type === 'relation' &&
            keys.length === 1 &&
            entity.tags.type === 'multipolygon') {
            // this relation's only interesting tag just says its a multipolygon,
            // which is not descriptive enough

            // It's okay for a simple multipolygon to have no descriptive tags
            // if its outer way has them (old model, see `outdated_tags.js`)
            return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
        }

        return keys.length > 0;
    }

    function isUnknownRoad(entity) {
        return entity.type === 'way' && entity.tags.highway === 'road';
    }

    function isUntypedRelation(entity) {
        return entity.type === 'relation' && !entity.tags.type;
    }

    var validation = function checkMissingTag(entity, graph) {

        var osm = context.connection();

        // we can't know if the node is a vertex if the tile is undownloaded
        if ((entity.type === 'node' && osm && !osm.isDataLoaded(entity.loc)) ||
            // allow untagged nodes that are part of ways
            entity.geometry(graph) === 'vertex' ||
            // allow untagged entities that are part of relations
            entity.hasParentRelations(graph)) {
            return [];
        }

        var subtype;

        if (Object.keys(entity.tags).length === 0) {
            subtype = 'any';
        } else if (!hasDescriptiveTags(entity, graph)) {
            subtype = 'descriptive';
        } else if (isUntypedRelation(entity)) {
            subtype = 'relation_type';
        } else if (isUnknownRoad(entity)) {
            subtype = 'highway_classification';
        }

        if (!subtype) return [];

        var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
        var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag';

        // can always delete if the user created it in the first place..
        var canDelete = (entity.version === undefined || entity.v !== undefined);
        var severity = (canDelete && subtype !== 'highway_classification') ? 'error' : 'warning';

        return [new validationIssue({
            type: type,
            subtype: subtype,
            severity: severity,
            message: function(context) {
                var entity = context.hasEntity(this.entityIds[0]);
                return entity ? t('issues.' + messageID + '.message', {
                    feature: utilDisplayLabel(entity, context)
                }) : '';
            },
            reference: showReference,
            entityIds: [entity.id],
            dynamicFixes: function(context) {

                var fixes = [];

                var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';

                fixes.push(new validationIssueFix({
                    icon: 'iD-icon-search',
                    title: t('issues.fix.' + selectFixType + '.title'),
                    onClick: function(context) {
                        context.ui().sidebar.showPresetList();
                    }
                }));

                var deleteOnClick;

                var id = this.entityIds[0];
                var operation = operationDelete([id], context);
                var disabledReasonID = operation.disabled();
                if (!disabledReasonID) {
                    deleteOnClick = function(context) {
                        var id = this.issue.entityIds[0];
                        var operation = operationDelete([id], context);
                        if (!operation.disabled()) {
                            operation();
                        }
                    };
                }

                fixes.push(
                    new validationIssueFix({
                        icon: 'iD-operation-delete',
                        title: t('issues.fix.delete_feature.title'),
                        disabledReason: disabledReasonID ? t('operations.delete.' + disabledReasonID + '.single') : undefined,
                        onClick: deleteOnClick
                    })
                );

                return fixes;
            }
        })];

        function showReference(selection) {
            selection.selectAll('.issue-reference')
                .data([0])
                .enter()
                .append('div')
                .attr('class', 'issue-reference')
                .text(t('issues.' + referenceID + '.reference'));
        }
    };

    validation.type = type;

    return validation;
}
<|endoftext|>


<commit_before>"use strict";

/**
 * API calls designed to execute against a local backend service
 */
define(['util', 'model/core'], function(util, model_core) {

    function RZ_API_Backend() {

        var rz_server_url = 'http://%h:%p';
        rz_server_url = rz_server_url.replace('%h', rz_config.rz_server_host);
        rz_server_url = rz_server_url.replace('%p', rz_config.rz_server_port);

        var common_req_ctx = function() {
            var common_ctx = { rzdoc_name: rz_config.rzdoc_cur__name }; // FIXME: call rz_core.rzdoc_get_current + avoid requirejs circular dep
            return common_ctx;
        };

        /**
         * issue rhizi server ajax call
         */
        var ajax_rs = function(path, req_opts, on_success, on_error) {

            function on_error_wrapper(xhr, text_status, err_thrown) {
                // log wrap callback
                var err_msg = xhr.responseJSON && xhr.responseJSON.error;
                console.error('ajax error: status: \'' + text_status + '\'', error msg: ' + err_msg);
                if (on_error && typeof (on_error) === "function") {
                    on_error(err_msg);
                }
            }

            function on_success_wrapper(xhr, text) {
                // log wrap callback
                var ret_data = xhr.data;
                util.assert(undefined == xhr.error); // assert we no longer return errors along with HTTP 200 status codes

                console.log('ajax success: return value:');
                console.dir(ret_data);
                if (on_success) {
                    on_success(ret_data);
                };
            }

            /*
             * add common request options
             */
            req_opts.dataType = "json";
            req_opts.contentType = "application/json; charset=utf-8";
            req_opts.error = on_error_wrapper;
            req_opts.success = on_success_wrapper;
            req_opts.headers = {};
            req_opts.timeout = 8000; // ms
            req_opts.crossDomain = true;

            $.ajax(rz_server_url + path, req_opts);
        }

        /**
         * common attr_diff
         */
        this.commit_diff__attr = function(attr_diff, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['attr_diff'] = attr_diff;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-attr', req_opts, on_success,
                    on_error);
        }

        /**
         * commit topo_diff
         */
        this.commit_diff__topo = function(topo_diff, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['topo_diff'] = topo_diff;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-topo', req_opts, on_success,
                    on_error);
        }

        /**
         * commit vis_diff
         */
        this.commit_diff__vis = function(vis_diff, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['vis_diff'] = vis_diff;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-vis', req_opts, on_success,
                    on_error);
        }

        /**
         * commit a diff_set
         */
        this.commit_diff__set = function(diff_set, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['diff_set'] = diff_set;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-set', req_opts, on_success,
                    on_error);
        }

        /**
         * load node-set by id attribute
         *
         * @param on_complete_cb
         *            will be called with the returned json data on successful
         *            invocation
         * @param on_error
         *            error callback
         */
        this.load_node_set = function(id_set, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['id_set'] = id_set;

            // prep request
            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/load/node-set-by-id', req_opts, on_success,
                    on_error);
        }

        /**
         * load link set by src / dst id
         */
        this.load_link_set = function(link_ptr_set, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['link_ptr_set'] = link_ptr_set;

            // prep request
            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/load/link-set/by_link_ptr_set', req_opts,
                    on_success, on_error);
        }

        /**
         * add a node set
         */
        this.add_node_set = function(n_set, on_success, on_error) {
            var topo_diff = new Topo_Diff();
            topo_diff.node_set_add = n_set;

            return this.topo_diff_commit(topo_diff, on_success, on_error);
        }

        /**
         * add a link set
         */
        this.add_link_set = function(l_set, on_success, on_error) {
            var topo_diff = new Topo_Diff();
            topo_diff.link_set_add = l_set;

            return this.topo_diff_commit(topo_diff);
        }

        /**
         * remove node set
         */
        this.remove_node_set = function() {
            var topo_diff = null;
            return this.topo_diff_commit(topo_diff);
        }

        /**
         * remove link set
         */
        this.remove_link_set = function() {
            var topo_diff = null;
            return this.topo_diff_commit(topo_diff);
        }

        /**
         * update node set
         */
        this.update_node_set = function(attr_diff, on_success, on_error) {
            return this.attr_diff_commit(attr_diff, on_success, on_error);
        }

        /**
         * update link set
         */
        this.update_link_set = function() {
            var attr_diff = null;
            return this.attr_diff_commit(null);
        }

        /**
         * clone rhizi repo
         */
        this.rzdoc_clone = function(on_success, on_error) {

            var req_data = common_req_ctx();

            // prep request
            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data)
            };

            ajax_rs('/graph/clone', req_opts, on_success, on_error);
        }

        /**
         * create rzdoc
         */
        this.rzdoc_create = function(rzdoc_name, on_success, on_error) {

            var req_opts = { type : 'POST' };
            return ajax_rs('/rzdoc/' + rzdoc_name + '/create', req_opts, on_success, on_error);
        }

        /**
         * list available rzdocs
         */
        this.rzdoc_list = function(on_success, on_error) {

            var req_opts = { type : 'POST' };
            return ajax_rs('/rzdoc/list', req_opts, on_success, on_error);
        }
    }

    return new RZ_API_Backend();
});
<commit_msg>rz_api_backend.js: fix misplaced quote in log message<commit_after>"use strict";

/**
 * API calls designed to execute against a local backend service
 */
define(['util', 'model/core'], function(util, model_core) {

    function RZ_API_Backend() {

        var rz_server_url = 'http://%h:%p';
        rz_server_url = rz_server_url.replace('%h', rz_config.rz_server_host);
        rz_server_url = rz_server_url.replace('%p', rz_config.rz_server_port);

        var common_req_ctx = function() {
            var common_ctx = { rzdoc_name: rz_config.rzdoc_cur__name }; // FIXME: call rz_core.rzdoc_get_current + avoid requirejs circular dep
            return common_ctx;
        };

        /**
         * issue rhizi server ajax call
         */
        var ajax_rs = function(path, req_opts, on_success, on_error) {

            function on_error_wrapper(xhr, text_status, err_thrown) {
                // log wrap callback
                var err_msg = xhr.responseJSON && xhr.responseJSON.error;
                console.error('ajax error: status: \'' + text_status + '\' error msg: ' + err_msg);
                if (on_error && typeof (on_error) === "function") {
                    on_error(err_msg);
                }
            }

            function on_success_wrapper(xhr, text) {
                // log wrap callback
                var ret_data = xhr.data;
                util.assert(undefined == xhr.error); // assert we no longer return errors along with HTTP 200 status codes

                console.log('ajax success: return value:');
                console.dir(ret_data);
                if (on_success) {
                    on_success(ret_data);
                };
            }

            /*
             * add common request options
             */
            req_opts.dataType = "json";
            req_opts.contentType = "application/json; charset=utf-8";
            req_opts.error = on_error_wrapper;
            req_opts.success = on_success_wrapper;
            req_opts.headers = {};
            req_opts.timeout = 8000; // ms
            req_opts.crossDomain = true;

            $.ajax(rz_server_url + path, req_opts);
        }

        /**
         * common attr_diff
         */
        this.commit_diff__attr = function(attr_diff, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['attr_diff'] = attr_diff;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-attr', req_opts, on_success,
                    on_error);
        }

        /**
         * commit topo_diff
         */
        this.commit_diff__topo = function(topo_diff, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['topo_diff'] = topo_diff;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-topo', req_opts, on_success,
                    on_error);
        }

        /**
         * commit vis_diff
         */
        this.commit_diff__vis = function(vis_diff, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['vis_diff'] = vis_diff;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-vis', req_opts, on_success,
                    on_error);
        }

        /**
         * commit a diff_set
         */
        this.commit_diff__set = function(diff_set, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['diff_set'] = diff_set;

            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/graph/diff-commit-set', req_opts, on_success,
                    on_error);
        }

        /**
         * load node-set by id attribute
         *
         * @param on_complete_cb
         *            will be called with the returned json data on successful
         *            invocation
         * @param on_error
         *            error callback
         */
        this.load_node_set = function(id_set, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['id_set'] = id_set;

            // prep request
            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/load/node-set-by-id', req_opts, on_success,
                    on_error);
        }

        /**
         * load link set by src / dst id
         */
        this.load_link_set = function(link_ptr_set, on_success, on_error) {

            var req_data = common_req_ctx();
            req_data['link_ptr_set'] = link_ptr_set;

            // prep request
            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data),
            };

            return ajax_rs('/load/link-set/by_link_ptr_set', req_opts,
                    on_success, on_error);
        }

        /**
         * add a node set
         */
        this.add_node_set = function(n_set, on_success, on_error) {
            var topo_diff = new Topo_Diff();
            topo_diff.node_set_add = n_set;

            return this.topo_diff_commit(topo_diff, on_success, on_error);
        }

        /**
         * add a link set
         */
        this.add_link_set = function(l_set, on_success, on_error) {
            var topo_diff = new Topo_Diff();
            topo_diff.link_set_add = l_set;

            return this.topo_diff_commit(topo_diff);
        }

        /**
         * remove node set
         */
        this.remove_node_set = function() {
            var topo_diff = null;
            return this.topo_diff_commit(topo_diff);
        }

        /**
         * remove link set
         */
        this.remove_link_set = function() {
            var topo_diff = null;
            return this.topo_diff_commit(topo_diff);
        }

        /**
         * update node set
         */
        this.update_node_set = function(attr_diff, on_success, on_error) {
            return this.attr_diff_commit(attr_diff, on_success, on_error);
        }

        /**
         * update link set
         */
        this.update_link_set = function() {
            var attr_diff = null;
            return this.attr_diff_commit(null);
        }

        /**
         * clone rhizi repo
         */
        this.rzdoc_clone = function(on_success, on_error) {

            var req_data = common_req_ctx();

            // prep request
            var req_opts = {
                type : 'POST',
                data : JSON.stringify(req_data)
            };

            ajax_rs('/graph/clone', req_opts, on_success, on_error);
        }

        /**
         * create rzdoc
         */
        this.rzdoc_create = function(rzdoc_name, on_success, on_error) {

            var req_opts = { type : 'POST' };
            return ajax_rs('/rzdoc/' + rzdoc_name + '/create', req_opts, on_success, on_error);
        }

        /**
         * list available rzdocs
         */
        this.rzdoc_list = function(on_success, on_error) {

            var req_opts = { type : 'POST' };
            return ajax_rs('/rzdoc/list', req_opts, on_success, on_error);
        }
    }

    return new RZ_API_Backend();
});
<|endoftext|>


<commit_before>// Hack to always define a console
if (!window["console"]) {
    window.console = { log: function () { } };
}

function glinamespace(name) {
    var parts = name.split(".");
    var current = window;
    for (var n = 0; n < parts.length; n++) {
        var part = parts[n];
        current[part] = current[part] || {};
        current = current[part];
    }
    return current;
}

function glisubclass(parent, child, args) {
    parent.apply(child, args);

    // TODO: this sucks - do it right

    for (var propertyName in parent.prototype) {
        if (propertyName == "constructor") {
            continue;
        }
        if (!child.__proto__[propertyName]) {
            child.__proto__[propertyName] = parent.prototype[propertyName];
        }
    }

    for (var propertyName in parent) {
        child[propertyName] = parent[propertyName];
    }
};

function glitypename(value) {
    function stripConstructor(value) {
        if (value) {
            return value.replace("Constructor", "");
        } else {
            return value;
        }
    };
    if (value) {
        var mangled = value.constructor.toString();
        if (mangled) {
            var matches = mangled.match(/function (.+)\(/);
            if (matches) {
                // ...function Foo()...
                if (matches[1] == "Object") {
                    // Hrm that's likely not right...
                    // constructor may be fubar
                    mangled = value.toString();
                } else {
                    return stripConstructor(matches[1]);
                }
            }

            // [object Foo]
            matches = mangled.match(/\[object (.+)\]/);
            if (matches) {
                return stripConstructor(matches[1]);
            }
        }
    }
    return null;
};

function scrollIntoViewIfNeeded(el) {
    if (el.scrollIntoViewIfNeeded) {
        el.scrollIntoViewIfNeeded();
    } else {
        // TODO: determine if el is in the current view of the parent
        var scrollTop = el.offsetParent.scrollTop;
        var scrollBottom = el.offsetParent.scrollTop + el.offsetParent.clientHeight;
        var elTop = el.offsetTop;
        var elBottom = el.offsetTop + el.offsetHeight;
        if ((elTop < scrollTop) || (elTop > scrollBottom)) {
            el.scrollIntoView();
        }
    }
};

(function () {
    var util = glinamespace("gli.util");

    util.getWebGLContext = function (canvas, baseAttrs, attrs) {
        var finalAttrs = {};

        // baseAttrs are all required and attrs are ORed in
        if (baseAttrs) {
            for (var k in baseAttrs) {
                finalAttrs[k] = baseAttrs[k];
            }
        }
        if (attrs) {
            for (var k in attrs) {
                if (finalAttrs[k] === undefined) {
                    finalAttrs[k] = attrs[k];
                } else {
                    finalAttrs[k] |= attrs[k];
                }
            }
        }

        var contextName = "experimental-webgl";
        var gl = null;
        try {
            if (canvas.getContextRaw) {
                gl = canvas.getContextRaw(contextName, finalAttrs);
            } else {
                gl = canvas.getContext(contextName, finalAttrs);
            }
        } catch (e) {
            // ?
            alert("Unable to get WebGL context: " + e);
        }

        if (gl) {
            gli.enableAllExtensions(gl);
            gli.hacks.installAll(gl);
        }

        return gl;
    };

    // Adjust TypedArray types to have consistent toString methods
    var typedArrayToString = function () {
        var s = "";
        var maxIndex = Math.min(64, this.length);
        for (var n = 0; n < maxIndex; n++) {
            s += this[n];
            if (n < this.length - 1) {
                s += ",";
            }
        }
        if (maxIndex < this.length) {
            s += ",... (" + (this.length) + " total)";
        }
        return s;
    };
    Int8Array.prototype.toString = typedArrayToString;
    Uint8Array.prototype.toString = typedArrayToString;
    Int16Array.prototype.toString = typedArrayToString;
    Uint16Array.prototype.toString = typedArrayToString;
    Int32Array.prototype.toString = typedArrayToString;
    Uint32Array.prototype.toString = typedArrayToString;
    Float32Array.prototype.toString = typedArrayToString;

    util.typedArrayToString = function (array) {
        if (array) {
            return typedArrayToString.apply(array);
        } else {
            return "(null)";
        }
    };

    util.isTypedArray = function (value) {
        if (value) {
            var typename = glitypename(value);
            switch (typename) {
                case "Int8Array":
                case "Uint8Array":
                case "Int16Array":
                case "Uint16Array":
                case "Int32Array":
                case "Uint32Array":
                case "Float32Array":
                    return true;
            }
            return false;
        } else {
            return false;
        }
    };

    util.arrayCompare = function (a, b) {
        if (a && b && a.length == b.length) {
            for (var n = 0; n < a.length; n++) {
                if (a[n] !== b[n]) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    };

    util.isWebGLResource = function (value) {
        if (value) {
            var typename = glitypename(value);
            switch (typename) {
                case "WebGLBuffer":
                case "WebGLFramebuffer":
                case "WebGLProgram":
                case "WebGLRenderbuffer":
                case "WebGLShader":
                case "WebGLTexture":
                    return true;
            }
            return false;
        } else {
            return false;
        }
    }

    function prepareDocumentElement(el) {
        // FF requires all content be in a document before it'll accept it for playback
        if (window.navigator.product == "Gecko") {
            var frag = document.createDocumentFragment();
            frag.appendChild(el);
        }
    };

    util.clone = function (arg) {
        if (arg) {
            if ((arg.constructor == Number) || (arg.constructor == String)) {
                // Fast path for immutables
                return arg;
            } else if (arg.constructor == Array) {
                return arg.slice(); // ghetto clone
            } else if (arg instanceof ArrayBuffer) {
                // There may be a better way to do this, but I don't know it
                var target = new ArrayBuffer(arg.byteLength);
                var sourceView = new DataView(arg, 0, arg.byteLength);
                var targetView = new DataView(target, 0, arg.byteLength);
                for (var n = 0; n < arg.byteLength; n++) {
                    targetView.setUint8(n, sourceView.getUint8(n));
                }
                return target;
            } else if (util.isTypedArray(arg)) {
                //} else if (arg instanceof ArrayBufferView) {
                // HACK: at least Chromium doesn't have ArrayBufferView as a known type (for some reason)
                var target = null;
                if (arg instanceof Int8Array) {
                    target = new Int8Array(arg);
                } else if (arg instanceof Uint8Array) {
                    target = new Uint8Array(arg);
                } else if (arg instanceof Int16Array) {
                    target = new Int16Array(arg);
                } else if (arg instanceof Uint16Array) {
                    target = new Uint16Array(arg);
                } else if (arg instanceof Int32Array) {
                    target = new Int32Array(arg);
                } else if (arg instanceof Uint32Array) {
                    target = new Uint32Array(arg);
                } else if (arg instanceof Float32Array) {
                    target = new Float32Array(arg);
                } else {
                    target = arg;
                }
                return target;
            } else if (glitypename(arg) == "ImageData") {
                var dummyCanvas = document.createElement("canvas");
                var dummyContext = dummyCanvas.getContext("2d");
                var target = dummyContext.createImageData(arg);
                for (var n = 0; n < arg.data.length; n++) {
                    target.data[n] = arg.data[n];
                }
                return target;
            } else if (arg instanceof HTMLCanvasElement) {
                // TODO: better way of doing this?
                var target = arg.cloneNode(true);
                var ctx = target.getContext("2d");
                ctx.drawImage(arg, 0, 0);
                prepareDocumentElement(target);
                return target;
            } else if (arg instanceof HTMLImageElement) {
                // TODO: clone image data (src?)
                var target = arg.cloneNode(true);
                target.width = arg.width;
                target.height = arg.height;
                prepareDocumentElement(target);
                return target;
            } else if (arg instanceof HTMLVideoElement) {
                // TODO: clone video data (is this even possible? we want the exact frame at the time of upload - maybe preserve seek time?)
                var target = arg.cloneNode(true);
                prepareDocumentElement(target);
                return target;
            } else {
                return arg;
            }
        } else {
            return arg;
        }
    };

})();
<commit_msg>preserve drawing buffers<commit_after>// Hack to always define a console
if (!window["console"]) {
    window.console = { log: function () { } };
}

function glinamespace(name) {
    var parts = name.split(".");
    var current = window;
    for (var n = 0; n < parts.length; n++) {
        var part = parts[n];
        current[part] = current[part] || {};
        current = current[part];
    }
    return current;
}

function glisubclass(parent, child, args) {
    parent.apply(child, args);

    // TODO: this sucks - do it right

    for (var propertyName in parent.prototype) {
        if (propertyName == "constructor") {
            continue;
        }
        if (!child.__proto__[propertyName]) {
            child.__proto__[propertyName] = parent.prototype[propertyName];
        }
    }

    for (var propertyName in parent) {
        child[propertyName] = parent[propertyName];
    }
};

function glitypename(value) {
    function stripConstructor(value) {
        if (value) {
            return value.replace("Constructor", "");
        } else {
            return value;
        }
    };
    if (value) {
        var mangled = value.constructor.toString();
        if (mangled) {
            var matches = mangled.match(/function (.+)\(/);
            if (matches) {
                // ...function Foo()...
                if (matches[1] == "Object") {
                    // Hrm that's likely not right...
                    // constructor may be fubar
                    mangled = value.toString();
                } else {
                    return stripConstructor(matches[1]);
                }
            }

            // [object Foo]
            matches = mangled.match(/\[object (.+)\]/);
            if (matches) {
                return stripConstructor(matches[1]);
            }
        }
    }
    return null;
};

function scrollIntoViewIfNeeded(el) {
    if (el.scrollIntoViewIfNeeded) {
        el.scrollIntoViewIfNeeded();
    } else {
        // TODO: determine if el is in the current view of the parent
        var scrollTop = el.offsetParent.scrollTop;
        var scrollBottom = el.offsetParent.scrollTop + el.offsetParent.clientHeight;
        var elTop = el.offsetTop;
        var elBottom = el.offsetTop + el.offsetHeight;
        if ((elTop < scrollTop) || (elTop > scrollBottom)) {
            el.scrollIntoView();
        }
    }
};

(function () {
    var util = glinamespace("gli.util");

    util.getWebGLContext = function (canvas, baseAttrs, attrs) {
        var finalAttrs = {
            preserveDrawingBuffer: true
        };

        // baseAttrs are all required and attrs are ORed in
        if (baseAttrs) {
            for (var k in baseAttrs) {
                finalAttrs[k] = baseAttrs[k];
            }
        }
        if (attrs) {
            for (var k in attrs) {
                if (finalAttrs[k] === undefined) {
                    finalAttrs[k] = attrs[k];
                } else {
                    finalAttrs[k] |= attrs[k];
                }
            }
        }

        var contextName = "experimental-webgl";
        var gl = null;
        try {
            if (canvas.getContextRaw) {
                gl = canvas.getContextRaw(contextName, finalAttrs);
            } else {
                gl = canvas.getContext(contextName, finalAttrs);
            }
        } catch (e) {
            // ?
            alert("Unable to get WebGL context: " + e);
        }

        if (gl) {
            gli.enableAllExtensions(gl);
            gli.hacks.installAll(gl);
        }

        return gl;
    };

    // Adjust TypedArray types to have consistent toString methods
    var typedArrayToString = function () {
        var s = "";
        var maxIndex = Math.min(64, this.length);
        for (var n = 0; n < maxIndex; n++) {
            s += this[n];
            if (n < this.length - 1) {
                s += ",";
            }
        }
        if (maxIndex < this.length) {
            s += ",... (" + (this.length) + " total)";
        }
        return s;
    };
    Int8Array.prototype.toString = typedArrayToString;
    Uint8Array.prototype.toString = typedArrayToString;
    Int16Array.prototype.toString = typedArrayToString;
    Uint16Array.prototype.toString = typedArrayToString;
    Int32Array.prototype.toString = typedArrayToString;
    Uint32Array.prototype.toString = typedArrayToString;
    Float32Array.prototype.toString = typedArrayToString;

    util.typedArrayToString = function (array) {
        if (array) {
            return typedArrayToString.apply(array);
        } else {
            return "(null)";
        }
    };

    util.isTypedArray = function (value) {
        if (value) {
            var typename = glitypename(value);
            switch (typename) {
                case "Int8Array":
                case "Uint8Array":
                case "Int16Array":
                case "Uint16Array":
                case "Int32Array":
                case "Uint32Array":
                case "Float32Array":
                    return true;
            }
            return false;
        } else {
            return false;
        }
    };

    util.arrayCompare = function (a, b) {
        if (a && b && a.length == b.length) {
            for (var n = 0; n < a.length; n++) {
                if (a[n] !== b[n]) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    };

    util.isWebGLResource = function (value) {
        if (value) {
            var typename = glitypename(value);
            switch (typename) {
                case "WebGLBuffer":
                case "WebGLFramebuffer":
                case "WebGLProgram":
                case "WebGLRenderbuffer":
                case "WebGLShader":
                case "WebGLTexture":
                    return true;
            }
            return false;
        } else {
            return false;
        }
    }

    function prepareDocumentElement(el) {
        // FF requires all content be in a document before it'll accept it for playback
        if (window.navigator.product == "Gecko") {
            var frag = document.createDocumentFragment();
            frag.appendChild(el);
        }
    };

    util.clone = function (arg) {
        if (arg) {
            if ((arg.constructor == Number) || (arg.constructor == String)) {
                // Fast path for immutables
                return arg;
            } else if (arg.constructor == Array) {
                return arg.slice(); // ghetto clone
            } else if (arg instanceof ArrayBuffer) {
                // There may be a better way to do this, but I don't know it
                var target = new ArrayBuffer(arg.byteLength);
                var sourceView = new DataView(arg, 0, arg.byteLength);
                var targetView = new DataView(target, 0, arg.byteLength);
                for (var n = 0; n < arg.byteLength; n++) {
                    targetView.setUint8(n, sourceView.getUint8(n));
                }
                return target;
            } else if (util.isTypedArray(arg)) {
                //} else if (arg instanceof ArrayBufferView) {
                // HACK: at least Chromium doesn't have ArrayBufferView as a known type (for some reason)
                var target = null;
                if (arg instanceof Int8Array) {
                    target = new Int8Array(arg);
                } else if (arg instanceof Uint8Array) {
                    target = new Uint8Array(arg);
                } else if (arg instanceof Int16Array) {
                    target = new Int16Array(arg);
                } else if (arg instanceof Uint16Array) {
                    target = new Uint16Array(arg);
                } else if (arg instanceof Int32Array) {
                    target = new Int32Array(arg);
                } else if (arg instanceof Uint32Array) {
                    target = new Uint32Array(arg);
                } else if (arg instanceof Float32Array) {
                    target = new Float32Array(arg);
                } else {
                    target = arg;
                }
                return target;
            } else if (glitypename(arg) == "ImageData") {
                var dummyCanvas = document.createElement("canvas");
                var dummyContext = dummyCanvas.getContext("2d");
                var target = dummyContext.createImageData(arg);
                for (var n = 0; n < arg.data.length; n++) {
                    target.data[n] = arg.data[n];
                }
                return target;
            } else if (arg instanceof HTMLCanvasElement) {
                // TODO: better way of doing this?
                var target = arg.cloneNode(true);
                var ctx = target.getContext("2d");
                ctx.drawImage(arg, 0, 0);
                prepareDocumentElement(target);
                return target;
            } else if (arg instanceof HTMLImageElement) {
                // TODO: clone image data (src?)
                var target = arg.cloneNode(true);
                target.width = arg.width;
                target.height = arg.height;
                prepareDocumentElement(target);
                return target;
            } else if (arg instanceof HTMLVideoElement) {
                // TODO: clone video data (is this even possible? we want the exact frame at the time of upload - maybe preserve seek time?)
                var target = arg.cloneNode(true);
                prepareDocumentElement(target);
                return target;
            } else {
                return arg;
            }
        } else {
            return arg;
        }
    };

})();
<|endoftext|>


<commit_before>define(['rz_core', 'Bacon'],
function(rz_core,   Bacon) {

function get_main_graph()
{
    // circular dependency on rz_core, so require.js cannot solve it.
    if (rz_core === undefined) {
        rz_core = require('rz_core');
        listen_on_diff_bus(rz_core.main_graph.diffBus);
    }
    return rz_core.main_graph;
}

var root_nodes = [], // these are the nodes that are requested via update
    selected_nodes = [],      // these are the nodes that are highlighted, generally the neighbours of selection_request
    selected_nodes__by_id = {},
    selectionChangedBus = new Bacon.Bus();

function listen_on_diff_bus(diffBus)
{
    diffBus
        .filter(".node_id_set_rm")
        .onValue(function (diff) {
            var node_node_cmp = (function (a, b) { return a.id > b.id; }),
                node_id_cmp = (function (a, b) { return a.id === b ? 0 : (a.id > b ? 1 : -1); });

            updateSelectedNodesBus(sortedArrayDiff(selected_nodes.sort(node_node_cmp),
                                             diff.node_id_set_rm.sort(), node_id_cmp));
        });
}

function sortedArrayDiff(a, b, a_cmp_b)
{
    var a_i = 0,
        b_i = 0,
        ret = [];

    while (a_i < a.length && b_i < b.length) {
        while (a_i < a.length && a_cmp_b(a[a_i], b[b_i]) == -1) {
            ret.push(a[a_i]);
            a_i += 1;
        }
        while (b_i < b.length && a_i < a.length && a_cmp_b(a[a_i], b[b_i]) == 0) {
            b_i += 1;
            a_i += 1;
        }
        while (b_i < b.length && a_cmp_b(a[a_i], b[b_i]) == 1) {
            b_i += 1;
        }
    }
    for (; a_i < a.length ; ++a_i) {
        ret.push(a[a_i]);
    }
    return ret;
}

function updateSelectedNodesBus(new_selected_nodes)
{
    selected_nodes = new_selected_nodes;
    selected_nodes__by_id = selected_nodes.reduce(
        function(d, v) {
            d[v.id] = v;
            return d;
        }, {});
    selectionChangedBus.push(selected_nodes);
}

function byVisitors(node_selector, link_selector) {
    var new_selected_nodes = get_main_graph().find__by_visitors(node_selector, link_selector);

    clear();
    connectedComponent(new_selected_nodes);
}

function connectedComponent(nodes) {
    var connected = get_main_graph().getConnectedNodesAndLinks(nodes, 1),
        i,
        node,
        link,
        data;

    for (i = 0 ; i < connected.nodes.length ; ++i) {
        data = connected.nodes[i];
        node = data.node;
        switch (data.type) {
        case 'exit':
            node.state = 'exit';
            break;
        case 'enter':
            node.state = 'enter';
            break;
        };
    }
    for (i = 0 ; i < connected.links.length ; ++i) {
        data = connected.links[i];
        link = data.link;
        switch (data.type) {
        case 'exit':
            link.state = 'exit';
            break;
        case 'enter':
            link.state = 'enter';
            break;
        };
    }
    nodes.forEach(function (n) { n.state = 'chosen'; });
    selected_nodes = connected.nodes.map(function (d) { return d.node; }).concat(nodes.slice());
    updateSelectedNodesBus(selected_nodes);
}

var node_selected = function(node) {
    return selected_nodes__by_id[node.id] !== undefined;
}

var link_selected = function(link) {
    return node_selected(link.__src) && node_selected(link.__dst);
}

var selected_class__node = function(node) {
    return selected_nodes.length > 0 ? (node_selected(node) ? "selected" : "notselected") : "";
}

var selected_class__link = function(link) {
    return selected_nodes.length > 0 ? (link_selected(link) ? "selected" : "notselected") : "";
}

var clear = function() {
    root_nodes = [];
    updateSelectedNodesBus([]);
}

function arr_compare(a1, a2)
{
    if (a1.length != a2.length) {
        return false;
    }
    for (var i = 0 ; i < a1.length ; ++i) {
        if (a1[i] != a2[i]) {
            return false;
        }
    }
    return true;
}

var update = function(nodes) {
    var set = !arr_compare(nodes, root_nodes);
    clear();
    if (set) {
        root_nodes = nodes;
        connectedComponent(nodes);
    }
}

return {
    byVisitors: byVisitors,
    connectedComponent: connectedComponent,
    clear: clear,
    update: update,
    selected_class__node: selected_class__node,
    selected_class__link: selected_class__link,
    node_selected: node_selected,
    link_selected: link_selected,
    selectionChangedBus: selectionChangedBus,
    __get_root_nodes: function() { return root_nodes; },
    __get_selected_nodes: function() { return selected_nodes; },
};

});
<commit_msg>client/view/selction: fix sortedArrayDiff<commit_after>define(['rz_core', 'Bacon'],
function(rz_core,   Bacon) {

function get_main_graph()
{
    // circular dependency on rz_core, so require.js cannot solve it.
    if (rz_core === undefined) {
        rz_core = require('rz_core');
        listen_on_diff_bus(rz_core.main_graph.diffBus);
    }
    return rz_core.main_graph;
}

var root_nodes = [], // these are the nodes that are requested via update
    selected_nodes = [],      // these are the nodes that are highlighted, generally the neighbours of selection_request
    selected_nodes__by_id = {},
    selectionChangedBus = new Bacon.Bus();

function listen_on_diff_bus(diffBus)
{
    diffBus
        .filter(".node_id_set_rm")
        .onValue(function (diff) {
            var node_node_cmp = (function (a, b) { return a.id > b.id; }),
                node_id_cmp = (function (a, b) { return a.id === b ? 0 : (a.id > b ? 1 : -1); });

            updateSelectedNodesBus(sortedArrayDiff(selected_nodes.sort(node_node_cmp),
                                             diff.node_id_set_rm.sort(), node_id_cmp));
        });
}

function sortedArrayDiff(a, b, a_cmp_b)
{
    var a_i = 0,
        b_i = 0,
        ret = [];

    while (a_i < a.length && b_i < b.length) {
        while (a_i < a.length && a_cmp_b(a[a_i], b[b_i]) == -1) {
            ret.push(a[a_i]);
            a_i += 1;
        }
        while (b_i < b.length && a_i < a.length && a_cmp_b(a[a_i], b[b_i]) == 0) {
            b_i += 1;
            a_i += 1;
        }
        while (b_i < b.length && a_i < a.length && a_cmp_b(a[a_i], b[b_i]) == 1) {
            b_i += 1;
        }
    }
    for (; a_i < a.length ; ++a_i) {
        ret.push(a[a_i]);
    }
    return ret;
}

function updateSelectedNodesBus(new_selected_nodes)
{
    selected_nodes = new_selected_nodes;
    selected_nodes__by_id = selected_nodes.reduce(
        function(d, v) {
            d[v.id] = v;
            return d;
        }, {});
    selectionChangedBus.push(selected_nodes);
}

function byVisitors(node_selector, link_selector) {
    var new_selected_nodes = get_main_graph().find__by_visitors(node_selector, link_selector);

    clear();
    connectedComponent(new_selected_nodes);
}

function connectedComponent(nodes) {
    var connected = get_main_graph().getConnectedNodesAndLinks(nodes, 1),
        i,
        node,
        link,
        data;

    for (i = 0 ; i < connected.nodes.length ; ++i) {
        data = connected.nodes[i];
        node = data.node;
        switch (data.type) {
        case 'exit':
            node.state = 'exit';
            break;
        case 'enter':
            node.state = 'enter';
            break;
        };
    }
    for (i = 0 ; i < connected.links.length ; ++i) {
        data = connected.links[i];
        link = data.link;
        switch (data.type) {
        case 'exit':
            link.state = 'exit';
            break;
        case 'enter':
            link.state = 'enter';
            break;
        };
    }
    nodes.forEach(function (n) { n.state = 'chosen'; });
    selected_nodes = connected.nodes.map(function (d) { return d.node; }).concat(nodes.slice());
    updateSelectedNodesBus(selected_nodes);
}

var node_selected = function(node) {
    return selected_nodes__by_id[node.id] !== undefined;
}

var link_selected = function(link) {
    return node_selected(link.__src) && node_selected(link.__dst);
}

var selected_class__node = function(node) {
    return selected_nodes.length > 0 ? (node_selected(node) ? "selected" : "notselected") : "";
}

var selected_class__link = function(link) {
    return selected_nodes.length > 0 ? (link_selected(link) ? "selected" : "notselected") : "";
}

var clear = function() {
    root_nodes = [];
    updateSelectedNodesBus([]);
}

function arr_compare(a1, a2)
{
    if (a1.length != a2.length) {
        return false;
    }
    for (var i = 0 ; i < a1.length ; ++i) {
        if (a1[i] != a2[i]) {
            return false;
        }
    }
    return true;
}

var update = function(nodes) {
    var set = !arr_compare(nodes, root_nodes);
    clear();
    if (set) {
        root_nodes = nodes;
        connectedComponent(nodes);
    }
}

return {
    byVisitors: byVisitors,
    connectedComponent: connectedComponent,
    clear: clear,
    update: update,
    selected_class__node: selected_class__node,
    selected_class__link: selected_class__link,
    node_selected: node_selected,
    link_selected: link_selected,
    selectionChangedBus: selectionChangedBus,
    __get_root_nodes: function() { return root_nodes; },
    __get_selected_nodes: function() { return selected_nodes; },
};

});
<|endoftext|>


<commit_before>
import "regenerator/runtime"
import { take, put, cps } from "redux-saga/effects"
import { addSaga } from "../utilities"

addSaga(function* share(getStore) {

  while (true) {
    const { payload } = yield take("SHARE.SHARE")

    let { share } = getStore()
    let msg = {}

    for (let key in share.content) {
      if (share.content[key] != null ) {
        msg[key] = share.content[key]
      }

    }

    if (
      typeof window != "undefined" &&
      window != null &&
      window.socialmessage &&
      Object.keys(msg).length
    ) {

      if (msg.image && msg.image[0] === "/") {
        msg.image = "http:" + msg.image
      }

      window.socialmessage.send(msg)
    }

    yield put({ type: "SHARE.SHARE" })

  }

})
<commit_msg>append share url to share text<commit_after>
import "regenerator/runtime"
import { take, put, cps } from "redux-saga/effects"
import { addSaga } from "../utilities"

addSaga(function* share(getStore) {

  while (true) {
    const { payload } = yield take("SHARE.SHARE")

    let { share } = getStore()
    let msg = {}

    for (let key in share.content) {
      if (share.content[key] != null ) {
        msg[key] = share.content[key]
      }

    }

    if (
      typeof window != "undefined" &&
      window != null &&
      window.socialmessage &&
      Object.keys(msg).length
    ) {

      if (msg.image && msg.image[0] === "/") {
        msg.image = "http:" + msg.image
      }

      if (msg.url) {
        msg.text = `${msg.text}\n${msg.url}`
      }

      window.socialmessage.send(msg)
    }

    yield put({ type: "SHARE.SHARE" })

  }

})
<|endoftext|>


<commit_before>define([
        '../../../shared/Utilities',
        '../../Helpers',
        '../../shared/TraceLine',
    ], function (
        util,
        helpers,
        traceLine
    ) {

    var VertexArrayView = function (w, elementRoot) {
        var self = this;
        this.window = w;
        this.elements = {
            view: elementRoot.getElementsByClassName("window-right")[0],
            listing: elementRoot.getElementsByClassName("vertexarray-listing")[0]
        };

        this.currentVertexArray = null;
    };

    VertexArrayView.prototype.layout = function () {
    };

    function appendHistoryLine(gl, el, vertexArray, call) {
        traceLine.appendHistoryLine(gl, el, call);

        // TODO: other custom stuff?
    }

    function generateVertexArrayHistory(gl, el, vertexArray, version) {
        var titleDiv = document.createElement("div");
        titleDiv.className = "info-title-secondary";
        titleDiv.textContent = "History";
        el.appendChild(titleDiv);

        var rootEl = document.createElement("div");
        rootEl.className = "vertexarray-history";
        el.appendChild(rootEl);

        for (var n = 0; n < version.calls.length; n++) {
            var call = version.calls[n];
            appendHistoryLine(gl, rootEl, vertexArray, call);
        }
    };

    function generateBufferValue(buffer) {
        if (buffer) {
            if (buffer.target) {
                return "[" + buffer.getName() + "]";
            }
            return "**unknown buffer";
        }
        return "null";
    }

    // Do I want the buffer at a certain state?
    function addBufferClickHandler(window, elem, buffer) {
      if (buffer && buffer.target) {
        elem.addEventListener('click', e => {
           window.showBuffer(buffer);
        });
        elem.className = elem.className + " vertexattrib-clickable";
      }
    }

    function generateVertexArrayDisplay(view, gl, el, vertexArray, version) {
        var titleDiv = document.createElement("div");
        titleDiv.className = "info-title-master";
        titleDiv.textContent = vertexArray.getName();
        el.appendChild(titleDiv);

        {
            const table = document.createElement("table");
            table.className = "info-parameters";

            const tr = document.createElement("tr");
            tr.className = "info-parameter-row";
            helpers.appendElement(tr, "td", "ELEMENT_ARRAY_BUFFER");
            const bufElem = helpers.ui.appendElement(tr, "td", generateBufferValue(version.extras.elementBuffer.buffer), "vertexattrib-buffer");
            addBufferClickHandler(view.window, bufElem, version.extras.elementBuffer.buffer);

            table.appendChild(tr);
            el.appendChild(table);
        }

        helpers.ui.appendbr(el);

        {
            const table = document.createElement("table");
            table.className = "vertexarray-struct";

            let tr = document.createElement("tr");
            helpers.appendElement(tr, "th", "index");
            helpers.appendElement(tr, "th", "enabled");
            helpers.appendElement(tr, "th", "size");
            helpers.appendElement(tr, "th", "type");
            helpers.appendElement(tr, "th", "normalized");
            helpers.appendElement(tr, "th", "stride");
            helpers.appendElement(tr, "th", "offset");
            helpers.appendElement(tr, "th", "divisor");
            helpers.appendElement(tr, "th", "buffer");
            helpers.appendElement(tr, "th", "value");
            table.appendChild(tr);

            const defaultAttrib = {
                enabled: false,
                value: [0, 0, 0, 1],
                size: 4,
                type: gl.FLOAT,
                normalize: false,
                stride: 0,
                offset: 0,
                buffer: null,
                divisor: 0,
            };
            const attributes = version.extras.attributes;
            const maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
            for (let n = 0; n < maxAttributes; ++n) {
              const attribute = attributes[n] || defaultAttrib;
              let tr = document.createElement("tr");
              tr.className = attribute.enabled ? "vertexattrib-enabled" : "vertexattrib-disabled";

              helpers.appendElement(tr, "td", n, "vertexattrib-index");
              helpers.appendElement(tr, "td", attribute.enabled ? "●" : "", "vertexattrib-enabled");
              helpers.appendElement(tr, "td", attribute.size, "vertexattrib-size");
              helpers.appendElement(tr, "td", glc.enumToString(attribute.type), "vertexattrib-type");
              helpers.appendElement(tr, "td", attribute.normalized ? "true" : "false", "vertexattrib-normalized");
              helpers.appendElement(tr, "td", attribute.stride, "vertexattrib-stride");
              helpers.appendElement(tr, "td", attribute.offset, "vertexattrib-offset");
              helpers.appendElement(tr, "td", attribute.divisor || defaultAttrib.divisor, "vertexattrib-divisor");
              const bufElem = helpers.appendElement(tr, "td", generateBufferValue(attribute.buffer), "vertexattrib-buffer");
              addBufferClickHandler(view.window, bufElem, attribute.buffer);
              helpers.appendElement(tr, "td", attribute.value || defaultAttrib.value, "vertexattrib-value");

              table.appendChild(tr);
            }

            el.appendChild(table);
        }

        helpers.appendbr(el);
        helpers.appendSeparator(el);

        generateVertexArrayHistory(gl, el, vertexArray, version);
        helpers.appendbr(el);

        var frame = gl.ui.controller.currentFrame;
        if (frame) {
            helpers.appendSeparator(el);
            traceLine.generateUsageList(gl, el, frame, vertexArray);
            helpers.appendbr(el);
        }

        helpers.appendSeparator(el);
        helpers.appendbr(el);
    }

    VertexArrayView.prototype.setVertexArray = function (vertexArray) {
        this.currentVertexArray = vertexArray;

        var node = this.elements.listing;
        while (node.hasChildNodes()) {
          node.removeChild(node.firstChild);
        }
        if (vertexArray) {
            var version;
            switch (this.window.activeVersion) {
                case null:
                    version = vertexArray.currentVersion;
                    break;
                case "current":
                    var frame = this.window.controller.currentFrame;
                    if (frame) {
                        version = frame.findResourceVersion(vertexArray);
                    }
                    version = version || vertexArray.currentVersion; // Fallback to live
                    break;
            }

            // Setup user preview options if not defined
            var lastDrawState = version.lastDrawState;
            if (!vertexArray.previewOptions && lastDrawState) {
                var elementArrayBufferArray = null;
                if (lastDrawState.elementArrayBuffer) {
                    elementArrayBufferArray = [lastDrawState.elementArrayBuffer, null];
                    // TODO: pick the right version of the ELEMENT_ARRAY_BUFFER
                    elementArrayBufferArray[1] = elementArrayBufferArray[0].currentVersion;
                }
            }

            generateVertexArrayDisplay(this, this.window.context, this.elements.listing, vertexArray, version);
        }

        this.elements.listing.scrollTop = 0;
    };

    return VertexArrayView;
});
<commit_msg>Remove unused module reference<commit_after>define([
        '../../Helpers',
        '../../shared/TraceLine',
    ], function (
        helpers,
        traceLine
    ) {

    var VertexArrayView = function (w, elementRoot) {
        var self = this;
        this.window = w;
        this.elements = {
            view: elementRoot.getElementsByClassName("window-right")[0],
            listing: elementRoot.getElementsByClassName("vertexarray-listing")[0]
        };

        this.currentVertexArray = null;
    };

    VertexArrayView.prototype.layout = function () {
    };

    function appendHistoryLine(gl, el, vertexArray, call) {
        traceLine.appendHistoryLine(gl, el, call);

        // TODO: other custom stuff?
    }

    function generateVertexArrayHistory(gl, el, vertexArray, version) {
        var titleDiv = document.createElement("div");
        titleDiv.className = "info-title-secondary";
        titleDiv.textContent = "History";
        el.appendChild(titleDiv);

        var rootEl = document.createElement("div");
        rootEl.className = "vertexarray-history";
        el.appendChild(rootEl);

        for (var n = 0; n < version.calls.length; n++) {
            var call = version.calls[n];
            appendHistoryLine(gl, rootEl, vertexArray, call);
        }
    };

    function generateBufferValue(buffer) {
        if (buffer) {
            if (buffer.target) {
                return "[" + buffer.getName() + "]";
            }
            return "**unknown buffer";
        }
        return "null";
    }

    // Do I want the buffer at a certain state?
    function addBufferClickHandler(window, elem, buffer) {
      if (buffer && buffer.target) {
        elem.addEventListener('click', e => {
           window.showBuffer(buffer);
        });
        elem.className = elem.className + " vertexattrib-clickable";
      }
    }

    function generateVertexArrayDisplay(view, gl, el, vertexArray, version) {
        var titleDiv = document.createElement("div");
        titleDiv.className = "info-title-master";
        titleDiv.textContent = vertexArray.getName();
        el.appendChild(titleDiv);

        {
            const table = document.createElement("table");
            table.className = "info-parameters";

            const tr = document.createElement("tr");
            tr.className = "info-parameter-row";
            helpers.appendElement(tr, "td", "ELEMENT_ARRAY_BUFFER");
            const bufElem = helpers.ui.appendElement(tr, "td", generateBufferValue(version.extras.elementBuffer.buffer), "vertexattrib-buffer");
            addBufferClickHandler(view.window, bufElem, version.extras.elementBuffer.buffer);

            table.appendChild(tr);
            el.appendChild(table);
        }

        helpers.ui.appendbr(el);

        {
            const table = document.createElement("table");
            table.className = "vertexarray-struct";

            let tr = document.createElement("tr");
            helpers.appendElement(tr, "th", "index");
            helpers.appendElement(tr, "th", "enabled");
            helpers.appendElement(tr, "th", "size");
            helpers.appendElement(tr, "th", "type");
            helpers.appendElement(tr, "th", "normalized");
            helpers.appendElement(tr, "th", "stride");
            helpers.appendElement(tr, "th", "offset");
            helpers.appendElement(tr, "th", "divisor");
            helpers.appendElement(tr, "th", "buffer");
            helpers.appendElement(tr, "th", "value");
            table.appendChild(tr);

            const defaultAttrib = {
                enabled: false,
                value: [0, 0, 0, 1],
                size: 4,
                type: gl.FLOAT,
                normalize: false,
                stride: 0,
                offset: 0,
                buffer: null,
                divisor: 0,
            };
            const attributes = version.extras.attributes;
            const maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
            for (let n = 0; n < maxAttributes; ++n) {
              const attribute = attributes[n] || defaultAttrib;
              let tr = document.createElement("tr");
              tr.className = attribute.enabled ? "vertexattrib-enabled" : "vertexattrib-disabled";

              helpers.appendElement(tr, "td", n, "vertexattrib-index");
              helpers.appendElement(tr, "td", attribute.enabled ? "●" : "", "vertexattrib-enabled");
              helpers.appendElement(tr, "td", attribute.size, "vertexattrib-size");
              helpers.appendElement(tr, "td", glc.enumToString(attribute.type), "vertexattrib-type");
              helpers.appendElement(tr, "td", attribute.normalized ? "true" : "false", "vertexattrib-normalized");
              helpers.appendElement(tr, "td", attribute.stride, "vertexattrib-stride");
              helpers.appendElement(tr, "td", attribute.offset, "vertexattrib-offset");
              helpers.appendElement(tr, "td", attribute.divisor || defaultAttrib.divisor, "vertexattrib-divisor");
              const bufElem = helpers.appendElement(tr, "td", generateBufferValue(attribute.buffer), "vertexattrib-buffer");
              addBufferClickHandler(view.window, bufElem, attribute.buffer);
              helpers.appendElement(tr, "td", attribute.value || defaultAttrib.value, "vertexattrib-value");

              table.appendChild(tr);
            }

            el.appendChild(table);
        }

        helpers.appendbr(el);
        helpers.appendSeparator(el);

        generateVertexArrayHistory(gl, el, vertexArray, version);
        helpers.appendbr(el);

        var frame = gl.ui.controller.currentFrame;
        if (frame) {
            helpers.appendSeparator(el);
            traceLine.generateUsageList(gl, el, frame, vertexArray);
            helpers.appendbr(el);
        }

        helpers.appendSeparator(el);
        helpers.appendbr(el);
    }

    VertexArrayView.prototype.setVertexArray = function (vertexArray) {
        this.currentVertexArray = vertexArray;

        var node = this.elements.listing;
        while (node.hasChildNodes()) {
          node.removeChild(node.firstChild);
        }
        if (vertexArray) {
            var version;
            switch (this.window.activeVersion) {
                case null:
                    version = vertexArray.currentVersion;
                    break;
                case "current":
                    var frame = this.window.controller.currentFrame;
                    if (frame) {
                        version = frame.findResourceVersion(vertexArray);
                    }
                    version = version || vertexArray.currentVersion; // Fallback to live
                    break;
            }

            // Setup user preview options if not defined
            var lastDrawState = version.lastDrawState;
            if (!vertexArray.previewOptions && lastDrawState) {
                var elementArrayBufferArray = null;
                if (lastDrawState.elementArrayBuffer) {
                    elementArrayBufferArray = [lastDrawState.elementArrayBuffer, null];
                    // TODO: pick the right version of the ELEMENT_ARRAY_BUFFER
                    elementArrayBufferArray[1] = elementArrayBufferArray[0].currentVersion;
                }
            }

            generateVertexArrayDisplay(this, this.window.context, this.elements.listing, vertexArray, version);
        }

        this.elements.listing.scrollTop = 0;
    };

    return VertexArrayView;
});
<|endoftext|>