<commit_before>/*
 * Copyright 2017 Next Century Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* exported configTransforms */
/* jshint camelcase:false */

var configTransforms = (function(_, commonTransforms) {
  function createDateProperties(searchFieldsObject) {
    return {
      start: {
        key: searchFieldsObject.key + '_start',
        field: searchFieldsObject.field,
        title: searchFieldsObject.title + ' From',
        dateIdentifier: 'start'
      },
      end: {
        key: searchFieldsObject.key + '_end',
        field: searchFieldsObject.field,
        title: searchFieldsObject.title + ' To',
        dateIdentifier: 'end'
      }
    };
  }

  function findAggregationsInResponse(response, property) {
    if(response && response.length && response[0].result && response[0].result.aggregations && response[0].result.aggregations['?' + property]) {
      return response[0].result.aggregations['?' + property].buckets || [];
    }
    return [];
  }

  function createFacetTransform(linkType, fieldType, fieldId) {
    return function(response, key) {
      var aggregations = findAggregationsInResponse(response, key);
      return aggregations.reduce(function(data, bucket) {
        /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
        var count = bucket.doc_count;
        /* jscs:enable requireCamelCaseOrUpperCaseIdentifiers */
        var id = commonTransforms.getFacetsDataId(bucket.key, fieldType);
        if(id) {
          data.push({
            count: count,
            id: id,
            link: commonTransforms.getLink(bucket.key, linkType, fieldType, fieldId),
            text: commonTransforms.getFacetsDataText(bucket.key, fieldType)
          });
        }
        return data;
      }, []);
    };
  }

  return {
    aggregationFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        // Dates will be shown in the histograms, images in the galleries, and locations in the maps.
        return searchFieldsObject.type !== 'date' && searchFieldsObject.type !== 'image' && searchFieldsObject.type !== 'location';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    dateConfig: function(searchFields) {
      var dateConfig = {};
      searchFields.forEach(function(searchFieldsObject) {
        if(searchFieldsObject.type === 'date') {
          var dateProperties = createDateProperties(searchFieldsObject);
          dateConfig[dateProperties.start.key] = searchFieldsObject.key;
          dateConfig[dateProperties.end.key] = searchFieldsObject.key;
        }
      });
      return dateConfig;
    },

    dateFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'date';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    documentInfo: function(document, searchFields) {
      var searchKeys = searchFields.map(function(searchFieldsObject) {
        return searchFieldsObject.key;
      });

      var headerExtractions = (document.headerExtractions || []).filter(function(extraction) {
        return extraction.key !== '_domain';
      }).map(function(extraction) {
        var index = searchKeys.indexOf(extraction.key);
        var config = index >= 0 ? searchFields[index] : {};
        return {
          config: config,
          data: extraction.data
        };
      });

      var detailExtractions = (document.detailExtractions || []).map(function(extraction) {
        var index = searchKeys.indexOf(extraction.key);
        var config = index >= 0 ? searchFields[index] : {};
        return {
          config: config,
          data: extraction.data
        };
      });

      return headerExtractions.concat(detailExtractions);
    },

    fields: function(clientConfig) {
      return clientConfig.fields || {};
    },

    filterCollection: function(searchFields) {
      return searchFields.reduce(function(filterCollection, searchFieldsObject) {
        filterCollection[searchFieldsObject.key] = [];
        return filterCollection;
      }, {});
    },

    filtersBuilderConfig: function(searchFields) {
      return searchFields.reduce(function(filtersBuilderConfig, searchFieldsObject) {
        filtersBuilderConfig[searchFieldsObject.key] = {
          field: searchFieldsObject.field
        };
        return filtersBuilderConfig;
      }, {});
    },

    formatId: function(id) {
      return decodeURIComponent(id);
    },

    formatName: function(id, type) {
      return commonTransforms.getExtractionDataText(id, id, type);
    },

    histogramFields: function(searchFields) {
      var entityFields = searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.link === 'entity';
      });
      var dateFields = searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'date';
      });
      var histogramFields = dateFields.reduce(function(fields, dateFieldsObject) {
        return fields.concat(entityFields.map(function(entityFieldsObject) {
          return {
            date: dateFieldsObject,
            entity: entityFieldsObject
          };
        }));
      }, []);
      return histogramFields.map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    imageFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'image';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    mapFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'location';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    pageConfig: function(searchFields, key) {
      var index = _.findIndex(searchFields, function(searchFieldsObject) {
        return searchFieldsObject.key === key;
      });
      return index >= 0 ? searchFields[index] : {};
    },

    searchFields: function(fields) {
      var searchFields =  _.keys(fields || {}).filter(function(id) {
        return !!fields[id].type;
      }).map(function(id) {
        /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
        var searchFieldsObject = {
          key: id,
          // Material design color.
          color: fields[id].color || 'grey',
          // Whether to show in the facets.
          facets: fields[id].show_in_facets || false,
          // The aggregation field.
          field: 'knowledge_graph.' + id + '.key',
          // A polymer or fontawesome icon.
          icon: fields[id].icon || 'icons:text-format',
          // Either entity, text, or undefined.
          link: fields[id].show_as_link !== 'no' ? fields[id].show_as_link : undefined,
          // Either header, detail, title, description, or undefined.
          result: fields[id].show_in_result !== 'no' ? fields[id].show_in_result : undefined,
          // Whether to show in the search fields.
          search: fields[id].show_in_search || false,
          // The singular pretty name to show.
          title: fields[id].screen_label || 'Extraction',
          // The plural pretty name to show.
          titlePlural: fields[id].screen_label_plural || 'Extractions',
          // Either date, email, hyphenated, image, location, phone, string, or username.
          type: fields[id].type
        };
        /* jscs:enable requireCamelCaseOrUpperCaseIdentifiers */

        // The facet aggregation transform function.
        searchFieldsObject.facetTransform = createFacetTransform(searchFieldsObject.link, searchFieldsObject.type, searchFieldsObject.key);
        // Add style class (e.g. 'entity-grey').
        searchFieldsObject.styleClass = commonTransforms.getStyleClass(searchFieldsObject.color);

        searchFieldsObject.sort = {
          sortId: 2,
          sortType: 'extraction'
        };
        if(searchFieldsObject.type === 'date') {
          searchFieldsObject.sort = {
            sortId: 6,
            sortType: 'date'
          };
        } else if(searchFieldsObject.link === 'entity') {
          searchFieldsObject.sort = {
            sortId: 1,
            sortType: 'entity'
          };
        } else if(searchFieldsObject.result === 'title') {
          searchFieldsObject.sort = {
            sortId: 3,
            sortType: 'document'
          };
        } else if(searchFieldsObject.result === 'description') {
          searchFieldsObject.sort = {
            sortId: 4,
            sortType: 'document'
          };
        } else if(searchFieldsObject.result === 'tld' || searchFieldsObject.key === 'website') {
          searchFieldsObject.sort = {
            sortId: 5,
            sortType: 'document'
          };
        }

        // Properties for the date facets.
        searchFieldsObject.dateProperties = fields[id].type === 'date' ? createDateProperties(searchFieldsObject) : {};

        return searchFieldsObject;
      }).sort(function(a, b) {
        if(a.sort.sortId < b.sort.sortId) {
          return -1;
        }
        if(a.sort.sortId > b.sort.sortId) {
          return 1;
        }
        return a.title > b.title ? 1 : (a.title < b.title ? -1 : 0);
      });

      console.log('searchFields', searchFields);
      return searchFields;
    },

    searchFieldsDialogConfig: function(searchFields) {
      var config = [];

      searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'date';
      }).forEach(function(searchFieldsObject) {
        var dateProperties = createDateProperties(searchFieldsObject);
        config.push({
          name: searchFieldsObject.title,
          type: 'date',
          data: [
            dateProperties.start,
            dateProperties.end
          ]
        });
      });

      config.push({
        name: 'Entity',
        data: searchFields.filter(function(searchFieldsObject) {
          return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'entity';
        }).map(function(searchFieldsObject) {
          return {
            key: searchFieldsObject.key,
            field: searchFieldsObject.field,
            title: searchFieldsObject.title
          };
        })
      });

      config.push({
        name: 'Extraction',
        data: searchFields.filter(function(searchFieldsObject) {
          return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'extraction';
        }).map(function(searchFieldsObject) {
          return {
            key: searchFieldsObject.key,
            field: searchFieldsObject.field,
            title: searchFieldsObject.title
          };
        })
      });

      config.push({
        name: 'Document',
        data: searchFields.filter(function(searchFieldsObject) {
          return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'document';
        }).map(function(searchFieldsObject) {
          return {
            key: searchFieldsObject.key,
            field: searchFieldsObject.field,
            title: searchFieldsObject.title
          };
        })
      });

      return config;
    },

    searchKeys: function(searchFields) {
      return searchFields.map(function(searchFieldsObject) {
        return searchFieldsObject.key;
      });
    },

    searchParameters: function(searchFields) {
      return searchFields.reduce(function(searchParameters, searchFieldsObject) {
        searchParameters[searchFieldsObject.key] = {};
        return searchParameters;
      }, {});
    },

    sortField: function(searchFields) {
      var index = _.findIndex(searchFields, function(searchFieldsObject) {
        return searchFieldsObject.type === 'date';
      });
      return index >= 0 ? searchFields[index].field : '';
    }
  };
});

<commit_msg>Excluded title and description from entity page aggregations.<commit_after>/*
 * Copyright 2017 Next Century Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* exported configTransforms */
/* jshint camelcase:false */

var configTransforms = (function(_, commonTransforms) {
  function createDateProperties(searchFieldsObject) {
    return {
      start: {
        key: searchFieldsObject.key + '_start',
        field: searchFieldsObject.field,
        title: searchFieldsObject.title + ' From',
        dateIdentifier: 'start'
      },
      end: {
        key: searchFieldsObject.key + '_end',
        field: searchFieldsObject.field,
        title: searchFieldsObject.title + ' To',
        dateIdentifier: 'end'
      }
    };
  }

  function findAggregationsInResponse(response, property) {
    if(response && response.length && response[0].result && response[0].result.aggregations && response[0].result.aggregations['?' + property]) {
      return response[0].result.aggregations['?' + property].buckets || [];
    }
    return [];
  }

  function createFacetTransform(linkType, fieldType, fieldId) {
    return function(response, key) {
      var aggregations = findAggregationsInResponse(response, key);
      return aggregations.reduce(function(data, bucket) {
        /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
        var count = bucket.doc_count;
        /* jscs:enable requireCamelCaseOrUpperCaseIdentifiers */
        var id = commonTransforms.getFacetsDataId(bucket.key, fieldType);
        if(id) {
          data.push({
            count: count,
            id: id,
            link: commonTransforms.getLink(bucket.key, linkType, fieldType, fieldId),
            text: commonTransforms.getFacetsDataText(bucket.key, fieldType)
          });
        }
        return data;
      }, []);
    };
  }

  return {
    aggregationFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        // Dates will be shown in the histograms, images in the galleries, and locations in the maps.
        return searchFieldsObject.type !== 'date' && searchFieldsObject.type !== 'image' && searchFieldsObject.type !== 'location' && searchFieldsObject.result !== 'title' && searchFieldsObject.result !== 'description';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    dateConfig: function(searchFields) {
      var dateConfig = {};
      searchFields.forEach(function(searchFieldsObject) {
        if(searchFieldsObject.type === 'date') {
          var dateProperties = createDateProperties(searchFieldsObject);
          dateConfig[dateProperties.start.key] = searchFieldsObject.key;
          dateConfig[dateProperties.end.key] = searchFieldsObject.key;
        }
      });
      return dateConfig;
    },

    dateFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'date' && searchFieldsObject.result !== 'title' && searchFieldsObject.result !== 'description';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    documentInfo: function(document, searchFields) {
      var searchKeys = searchFields.map(function(searchFieldsObject) {
        return searchFieldsObject.key;
      });

      var headerExtractions = (document.headerExtractions || []).filter(function(extraction) {
        return extraction.key !== '_domain';
      }).map(function(extraction) {
        var index = searchKeys.indexOf(extraction.key);
        var config = index >= 0 ? searchFields[index] : {};
        return {
          config: config,
          data: extraction.data
        };
      });

      var detailExtractions = (document.detailExtractions || []).map(function(extraction) {
        var index = searchKeys.indexOf(extraction.key);
        var config = index >= 0 ? searchFields[index] : {};
        return {
          config: config,
          data: extraction.data
        };
      });

      return headerExtractions.concat(detailExtractions);
    },

    fields: function(clientConfig) {
      return clientConfig.fields || {};
    },

    filterCollection: function(searchFields) {
      return searchFields.reduce(function(filterCollection, searchFieldsObject) {
        filterCollection[searchFieldsObject.key] = [];
        return filterCollection;
      }, {});
    },

    filtersBuilderConfig: function(searchFields) {
      return searchFields.reduce(function(filtersBuilderConfig, searchFieldsObject) {
        filtersBuilderConfig[searchFieldsObject.key] = {
          field: searchFieldsObject.field
        };
        return filtersBuilderConfig;
      }, {});
    },

    formatId: function(id) {
      return decodeURIComponent(id);
    },

    formatName: function(id, type) {
      return commonTransforms.getExtractionDataText(id, id, type);
    },

    histogramFields: function(searchFields) {
      var entityFields = searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.link === 'entity' && searchFieldsObject.result !== 'title' && searchFieldsObject.result !== 'description';
      });
      var dateFields = searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'date' && searchFieldsObject.result !== 'title' && searchFieldsObject.result !== 'description';
      });
      var histogramFields = dateFields.reduce(function(fields, dateFieldsObject) {
        return fields.concat(entityFields.map(function(entityFieldsObject) {
          return {
            date: dateFieldsObject,
            entity: entityFieldsObject
          };
        }));
      }, []);
      return histogramFields.map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    imageFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'image' && searchFieldsObject.result !== 'title' && searchFieldsObject.result !== 'description';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    mapFields: function(searchFields) {
      return searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.type === 'location' && searchFieldsObject.result !== 'title' && searchFieldsObject.result !== 'description';
      }).map(function(searchFieldsObject) {
        return _.cloneDeep(searchFieldsObject);
      });
    },

    pageConfig: function(searchFields, key) {
      var index = _.findIndex(searchFields, function(searchFieldsObject) {
        return searchFieldsObject.key === key;
      });
      return index >= 0 ? searchFields[index] : {};
    },

    searchFields: function(fields) {
      var searchFields =  _.keys(fields || {}).filter(function(id) {
        return !!fields[id].type;
      }).map(function(id) {
        /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
        var searchFieldsObject = {
          key: id,
          // Material design color.
          color: fields[id].color || 'grey',
          // Whether to show in the facets.
          facets: fields[id].show_in_facets || false,
          // The aggregation field.
          field: 'knowledge_graph.' + id + '.key',
          // A polymer or fontawesome icon.
          icon: fields[id].icon || 'icons:text-format',
          // Either entity, text, or undefined.
          link: fields[id].show_as_link !== 'no' ? fields[id].show_as_link : undefined,
          // Either header, detail, title, description, or undefined.
          result: fields[id].show_in_result !== 'no' ? fields[id].show_in_result : undefined,
          // Whether to show in the search fields.
          search: fields[id].show_in_search || false,
          // The singular pretty name to show.
          title: fields[id].screen_label || 'Extraction',
          // The plural pretty name to show.
          titlePlural: fields[id].screen_label_plural || 'Extractions',
          // Either date, email, hyphenated, image, location, phone, string, or username.
          type: fields[id].type
        };
        /* jscs:enable requireCamelCaseOrUpperCaseIdentifiers */

        // The facet aggregation transform function.
        searchFieldsObject.facetTransform = createFacetTransform(searchFieldsObject.link, searchFieldsObject.type, searchFieldsObject.key);
        // Add style class (e.g. 'entity-grey').
        searchFieldsObject.styleClass = commonTransforms.getStyleClass(searchFieldsObject.color);

        searchFieldsObject.sort = {
          sortId: 2,
          sortType: 'extraction'
        };
        if(searchFieldsObject.type === 'date') {
          searchFieldsObject.sort = {
            sortId: 6,
            sortType: 'date'
          };
        } else if(searchFieldsObject.link === 'entity') {
          searchFieldsObject.sort = {
            sortId: 1,
            sortType: 'entity'
          };
        } else if(searchFieldsObject.result === 'title') {
          searchFieldsObject.sort = {
            sortId: 3,
            sortType: 'document'
          };
        } else if(searchFieldsObject.result === 'description') {
          searchFieldsObject.sort = {
            sortId: 4,
            sortType: 'document'
          };
        } else if(searchFieldsObject.result === 'tld' || searchFieldsObject.key === 'website') {
          searchFieldsObject.sort = {
            sortId: 5,
            sortType: 'document'
          };
        }

        // Properties for the date facets.
        searchFieldsObject.dateProperties = fields[id].type === 'date' ? createDateProperties(searchFieldsObject) : {};

        return searchFieldsObject;
      }).sort(function(a, b) {
        if(a.sort.sortId < b.sort.sortId) {
          return -1;
        }
        if(a.sort.sortId > b.sort.sortId) {
          return 1;
        }
        return a.title > b.title ? 1 : (a.title < b.title ? -1 : 0);
      });

      console.log('searchFields', searchFields);
      return searchFields;
    },

    searchFieldsDialogConfig: function(searchFields) {
      var config = [];

      searchFields.filter(function(searchFieldsObject) {
        return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'date';
      }).forEach(function(searchFieldsObject) {
        var dateProperties = createDateProperties(searchFieldsObject);
        config.push({
          name: searchFieldsObject.title,
          type: 'date',
          data: [
            dateProperties.start,
            dateProperties.end
          ]
        });
      });

      config.push({
        name: 'Entity',
        data: searchFields.filter(function(searchFieldsObject) {
          return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'entity';
        }).map(function(searchFieldsObject) {
          return {
            key: searchFieldsObject.key,
            field: searchFieldsObject.field,
            title: searchFieldsObject.title
          };
        })
      });

      config.push({
        name: 'Extraction',
        data: searchFields.filter(function(searchFieldsObject) {
          return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'extraction';
        }).map(function(searchFieldsObject) {
          return {
            key: searchFieldsObject.key,
            field: searchFieldsObject.field,
            title: searchFieldsObject.title
          };
        })
      });

      config.push({
        name: 'Document',
        data: searchFields.filter(function(searchFieldsObject) {
          return searchFieldsObject.search && searchFieldsObject.sort.sortType === 'document';
        }).map(function(searchFieldsObject) {
          return {
            key: searchFieldsObject.key,
            field: searchFieldsObject.field,
            title: searchFieldsObject.title
          };
        })
      });

      return config;
    },

    searchKeys: function(searchFields) {
      return searchFields.map(function(searchFieldsObject) {
        return searchFieldsObject.key;
      });
    },

    searchParameters: function(searchFields) {
      return searchFields.reduce(function(searchParameters, searchFieldsObject) {
        searchParameters[searchFieldsObject.key] = {};
        return searchParameters;
      }, {});
    },

    sortField: function(searchFields) {
      var index = _.findIndex(searchFields, function(searchFieldsObject) {
        return searchFieldsObject.type === 'date' && searchFieldsObject.result !== 'title' && searchFieldsObject.result !== 'description';
      });
      return index >= 0 ? searchFields[index].field : '';
    }
  };
});

<|endoftext|>


<commit_before>define([
  'text!./decision-list.html'
], function(
  template
) {
  'use strict';

  return [ 'ViewsProvider', function (ViewsProvider) {
    ViewsProvider.registerDefaultView('cockpit.dashboard', {
      id: 'decision-list',
      label: 'Deployed Decision Tables',
      dashboardMenuLabel: 'DMN Decisions',
      template: template,
      controller: [
              '$scope', 'camAPI',
      function($scope,   camAPI) {

        var decisionDefinitionService = camAPI.resource('decision-definition');

        // get ALL the decisions
        decisionDefinitionService.list({latestVersion: true}, function(err, data) {
          $scope.decisionCount = data.length;
          $scope.decisions = data;
        });

      }],

      priority: -5 // display below the process definition list
    });
  }];
});
<commit_msg>fix(dashboard): sort dmn definitions by name<commit_after>define([
  'text!./decision-list.html'
], function(
  template
) {
  'use strict';

  return [ 'ViewsProvider', function (ViewsProvider) {
    ViewsProvider.registerDefaultView('cockpit.dashboard', {
      id: 'decision-list',
      label: 'Deployed Decision Tables',
      dashboardMenuLabel: 'DMN Decisions',
      template: template,
      controller: [
              '$scope', 'camAPI',
      function($scope,   camAPI) {

        var decisionDefinitionService = camAPI.resource('decision-definition');

        // get ALL the decisions
        decisionDefinitionService.list({
          latestVersion: true,
          sortBy: 'name',
          sortOrder: 'asc'
        }, function(err, data) {
          $scope.decisionCount = data.length;
          $scope.decisions = data;
        });

      }],

      priority: -5 // display below the process definition list
    });
  }];
});
<|endoftext|>


<commit_before>var Backbone = require('backbone');
var InputColorFixedView = require('builder/components/form-components/editors/fill-color/inputs/input-color-fixed');

describe('components/form-components/editors/fill-color/inputs/input-color-fixed', function () {
  var inputColor;

  function createView () {
    inputColor = new InputColorFixedView({
      model: new Backbone.Model({
        type: 'color',
        fixed: '#FF0000',
        opacity: 0.9
      }),
      columns: {},
      editorAttrs: { help: '' }
    });
  }

  beforeEach(function () {
    createView();
  });

  it('renders a colorbar', function () {
    inputColor.render();

    expect(inputColor._getValue()).toBe('rgba(255, 0, 0, 0.9)');
    expect(inputColor._getOpacity()).toBe(0.9);

    var colorBarBackground = inputColor.$el.find('.ColorBar')[0].style.backgroundColor;
    expect(colorBarBackground).toBe('rgba(255, 0, 0, 0.9)');
  });

  it('can create a color picker to choose one', function () {
    inputColor._createContentView();
    expect(inputColor._colorPickerView).not.toBeNull();
  });
});
<commit_msg>Fix some rounding issues in spec<commit_after>var Backbone = require('backbone');
var InputColorFixedView = require('builder/components/form-components/editors/fill-color/inputs/input-color-fixed');

describe('components/form-components/editors/fill-color/inputs/input-color-fixed', function () {
  var inputColor;

  function createView () {
    inputColor = new InputColorFixedView({
      model: new Backbone.Model({
        type: 'color',
        fixed: '#FF0000',
        opacity: 0.90
      }),
      columns: {},
      editorAttrs: { help: '' }
    });
  }

  beforeEach(function () {
    createView();
  });

  it('renders a colorbar', function () {
    inputColor.render();

    expect(inputColor._getValue()).toContain('rgba(255, 0, 0, 0.9');
    expect(inputColor._getOpacity()).toBe(0.9);

    var colorBarBackground = inputColor.$el.find('.ColorBar')[0].style.backgroundColor;
    expect(colorBarBackground).toContain('rgba(255, 0, 0, 0.9');
  });

  it('can create a color picker to choose one', function () {
    inputColor._createContentView();
    expect(inputColor._colorPickerView).not.toBeNull();
  });
});
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

var createClass = function() {
    var privateApi = {
        "classes": {}, //All defined classes will be saved here
        "getClone": function(item) { //If item is an object it gets clonned, if not it just return the passed item
            if (typeof item === "object") {
                var itemClone = {};
                for (key in item) {
                    itemClone[key] = privateApi.getClone(item[key]);
                }
                item = itemClone;
            }
            return item;
        },
         //Only builds the object and returns it
        "buildObject": function(classId, objectProtected, objectPublic) {
            var classOptions = privateApi.classes[classId];
            if (!classOptions) {
                throw "Error: There is no class registered with the id \"" + classId + "\"!";
            }

            //The protected- and public-object are shared in the whole family
            if (typeof objectProtected !== "undefined" && typeof objectPublic !== "undefined") {
                var object = {
                    "private": {}, //We use our own private-object
                    "protected": objectProtected,
                    "public": objectPublic
                };
            } else {
                var object = {
                    "private": {},
                    "protected": {},
                    "public": {}
                };
            }

            //Do we have a parent class?
            if (classOptions.extends && (parentClassId = classOptions.extends.prototype.__id)) {
                privateApi.buildObject(parentClassId, object.protected, object.public);

                //Save current object as parent-object
                //( object.protected and object.public were written by privateApi.buildObject() )
                parentObject = { //No access to the private stuff
                    "protected": privateApi.getClone(object.protected),
                    "public": privateApi.getClone(object.public),
                };
            }

            for (var visibility in object) {
                for (var key in classOptions[visibility] || {}) {
                    object[visibility][key] = privateApi.getClone(classOptions[visibility][key]);

                    //Bind to "object" if function
                    if (object[visibility][key].bind) {
                        object[visibility][key] = object[visibility][key].bind(object);
                    }
                }
            }

            //Add parent-object to current object
            if (typeof parentObject !== "undefined") {
                object.parent = parentObject;
            }

            return object;
        },
         //Build the object, calls the constructor and returns the public properties and methods
        "getObjectForCaller": function(classId, contructArguments) {
            //Build object
            var object = privateApi.buildObject(classId);

            //Call constructor
            (object.public["__construct"] || object.public["__"] || function() {}).apply(object, contructArguments);

            //Return public properties and methods
            return object.public;
        }
    };

    return function(classOptions) {
        do {
            var classId = Math.random().toString(36).substr(2);
        } while (typeof privateApi.classes[classId] !== "undefined");
        privateApi.classes[classId] = classOptions;

        var classCaller = function() {
            return privateApi.getObjectForCaller(this.__id, arguments);
        };
        classCaller.prototype.__id = classId;
        return classCaller;
    };
}();

if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
    module.exports = createClass;
}
<commit_msg>Additions for the strict mode<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";

var createClass = function() {
    var privateApi = {
        "classes": {}, //All defined classes will be saved here
        "getClone": function(item) { //If item is an object it gets clonned, if not it just return the passed item
            if (typeof item === "object") {
                var itemClone = {};
                for (var key in item) {
                    itemClone[key] = privateApi.getClone(item[key]);
                }
                item = itemClone;
            }
            return item;
        },
         //Only builds the object and returns it
        "buildObject": function(classId, objectProtected, objectPublic) {
            var classOptions = privateApi.classes[classId];
            if (!classOptions) {
                throw "Error: There is no class registered with the id \"" + classId + "\"!";
            }

            //The protected- and public-object are shared in the whole family
            if (typeof objectProtected !== "undefined" && typeof objectPublic !== "undefined") {
                var object = {
                    "private": {}, //We use our own private-object
                    "protected": objectProtected,
                    "public": objectPublic
                };
            } else {
                var object = {
                    "private": {},
                    "protected": {},
                    "public": {}
                };
            }

            //Do we have a parent class?
            if (classOptions.extends && classOptions.extends.prototype.__id) {
                privateApi.buildObject(classOptions.extends.prototype.__id, object.protected, object.public);

                //Save current object as parent-object
                //( object.protected and object.public were written by privateApi.buildObject() )
                var parentObject = { //No access to the private stuff
                    "protected": privateApi.getClone(object.protected),
                    "public": privateApi.getClone(object.public),
                };
            }

            for (var visibility in object) {
                for (var key in classOptions[visibility] || {}) {
                    object[visibility][key] = privateApi.getClone(classOptions[visibility][key]);

                    //Bind to "object" if function
                    if (object[visibility][key].bind) {
                        object[visibility][key] = object[visibility][key].bind(object);
                    }
                }
            }

            //Add parent-object to current object
            if (typeof parentObject !== "undefined") {
                object.parent = parentObject;
            }

            return object;
        },
         //Build the object, calls the constructor and returns the public properties and methods
        "getObjectForCaller": function(classId, contructArguments) {
            //Build object
            var object = privateApi.buildObject(classId);

            //Call constructor
            (object.public["__construct"] || object.public["__"] || function() {}).apply(object, contructArguments);

            //Return public properties and methods
            return object.public;
        }
    };

    return function(classOptions) {
        do {
            var classId = Math.random().toString(36).substr(2);
        } while (typeof privateApi.classes[classId] !== "undefined");
        privateApi.classes[classId] = classOptions;

        var classCaller = function() {
            return privateApi.getObjectForCaller(this.__id, arguments);
        };
        classCaller.prototype.__id = classId;
        return classCaller;
    };
}();

if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
    module.exports = createClass;
}
<|endoftext|>


<commit_before>sb.forms.editable = {};
sb.include('Element.prototype.isWithin');
/**
@Name: sb.forms.editable.field
@Description: Creates a click to edit text block
@Param: Object
type string input or textarea
editableElement object/string The element to edit #myDiv, $('#myDiv')
className string the classname for the widget, defaults to
attributes object additional html attributes you want assigned to the textfield, cols, rows, size, maxlength, etc
onBeforeEdit function Fires before editing begins,  Can be used to load raw text wihtout HTML from server
onSave function Fires after save, send back to server, stop editing

@Example:
//use the following in a dblclick event for the text you want to make editable

var editor = sb.forms.editable.field({
	editableElement : e.target,
	type : 'textarea',
	onBeforeEdit : function(){},
	onSave : function(value){}
});

editor.edit();
//example CSS

.sb_forms_editable textarea{
	cursor:text;
	display:block;
	width:97%;
	height:100px;
	overflow:auto;
	font-family:tahoma;
	font-size:1.1em;
}

.sb_forms_editable editbar.input{
	margin-left:5px;
}

.sb_forms_editable editbar.textarea{
	display:block;
	text-align:right;
}

.sb_forms_editable button{
	background-color:#d88713;
	color:#7c4e0d;
}

.sb_forms_editable button:hover{
	background-color:#e2b370;
}

*/
sb.forms.editable.field = function(params){
	if(!params.editableElement){
		throw('You must define the element with sb.forms.editable.field');
	}
	this.editableElement = sb.$(params.editableElement);
	if(this.editableElement.sb_editor){
		return this.editableElement.editor;
	}

	sb.objects.infuse(params, this);
	this.editableElement.sb_editor = this;

	this.className = params.className || 'sb_forms_editable';
};

sb.forms.editable.field.prototype = {

	/**
	@Name: sb.forms.editable.field.onBeforeEdit
	@Description: Fires before editing begins.  Can be used to load raw data with ajax
	to fill the textField with.  Reference the textField with this.textField.  The default is
	to use the innerHTML of the area being edited
	@Example:
	editor.onBeforeEdit = function(){
		this.setValue('loading...');
		var editor = this;

		var aj = new sb.ajax({
			url : '/url/rawtext',
			data : {
				doc_id : doc_id
			},
			onResponse : function(raw_desc){
				editor.setValue(raw_desc);
			}
		}).fetch();
	};
	*/
	onBeforeEdit : function(){
		this.setValue(this.editableElement.innerHTML);
	},

	/**
	@Name: sb.forms.editable.field.onSave
	@Description: Passes the value of the textField for you to save back with ajax
	@Param string save The value of the textField when save if fired
	editor.onSave = function(){
		if(value != 'loading...'){
			var editor = this;
			var aj = new sb.ajax({
				url : '/url/save',
				data : {
					doc_id : doc_id,
					value : value
				},
				onResponse : function(html){
					editor.setHTML(html);
				}
			}).fetch();
		}
	};

	*/
	onSave : function(value){},

	/**
	@Name: sb.forms.editable.field.onButtonPress
	@Description: Fires when a button is pressed other than save or cancel
	@Param event e The press event
	@Example:
	editor.onButtonPress = function(e){
		var button = e.target;
	};
	*/
	onButtonPress : function(e){},

	/**
	@Name: sb.forms.editable.field.onMaxLength
	@Description: Fires when user exceeds textField maxlength if set.
	@Param event e The press event
	@Example:
	editor.onMaxLength = function(e){};
	*/
	onMaxLength : function(e){e.preventDefault();},

	/**
	@Name: sb.forms.editable.field.onKeyDown
	@Description: Fires when a key is pressed, lets you do something with it
	@Param event e The press event
	@Example:
	editor.onKeyDown = function(e){};
	*/
	onKeyDown : function(e){},

	/**
	@Name: sb.forms.editable.field.onKeyUp
	@Description: Fires when a key is released, lets you do something with it
	@Param event e The press event
	@Example:
	editor.onKeyDown = function(e){
		//get rid of digits
		e.target.value = e.target.value.replace(/\d/, '');
	};
	*/
	onKeyUp : function(e){},

	/**
	@Name: sb.forms.editable.field.setValue
	@Description: Sets the value of the textField, use in onBeforeEdit after loading raw text from ajax
	@Example:
	editor.setValue('text to edit');
	*/
	setValue : function(value){
		this.textField.value = value;
		this.focus();
	},

	/**
	@Name: sb.forms.editable.field.setHTML
	@Description: Sets the html of the element being edited, use in onSave after saving
	@Example:
	editor.setHTML('
text that was edited
');
	*/
	setHTML : function(html){
		this.editableElement.innerHTML = html;
		this.editStop();
	},

	/**
	@Name: sb.forms.editable.field.edit
	@Description: Put the editor in edit mode
	@Example:
	editor.edit(target);
	*/
	edit : function(){
		if(!this.editor){
			this.create();
		}

		this.editor.replace(this.editableElement);

		if(typeof this.onBeforeEdit == 'function'){
			this.onBeforeEdit.call(this);
		}
	},

	/**
	@Name: sb.forms.editable.field.editStop
	@Description: Exit edit mode
	@Example:
	editor.editStop();
	*/
	editStop : function(){

		this.editableElement.replace(this.editor);
		this._origValue = '';
	},

	/**
	@Name: sb.forms.editable.field.focus
	@Description: Focuses on text area and puts cursor at top left. automatically fires after setValue
	@Example:
	editor.focus();
	*/
	focus : function(){
		var ta = this.textField;
		var range;
		if (this.textField.setSelectionRange) {
			this.textField.setSelectionRange(0, 0);
		} else if(this.textField.createTextRange){
			range = this.textField.createTextRange();
			range.collapse(true);
			range.moveStart("character", 0);
			range.moveEnd("character", 0 - 0);
			range.select();
		}
		this.textField.focus();

	},

	/**
	@Name: sb.forms.editable.field.addButton
	@Description: Adds a button to the editBar
	@Param string str The name of the button to add
	@Example:
	editor.addButton('email');
	*/
	addButton : function(str){
		this.editBar.innerHTML = '<button>'+str+'</button>'+this.editBar.innerHTML;

	},

	/**
	@Name: sb.forms.editable.field.isNotEdited
	@Description: Determines if field is edited or not
	@Example:
	if(editor.isNotEdited()){}
	*/
	isNotEdited : function(){
		return !this._origValue || this._origValue == this.textField.value;
	},

	/**
	@Name: sb.forms.editable.field.editStop
	@Description: Used internally Creates editor
	*/
	create : function(){
		var self = this;
		if(!this.editor){
			this.editor = new sb.element({
				tag : 'div',
				className : self.className,
				title : 'shortcuts: esc to cancel, ctrl+s'
			});

			if(this.type == 'input'){
				this.editor.title += ' or enter ';
			}

			this.editor.title += 'to save';

			this.textField = new sb.element({
				tag : this.type,
				value : this.value || '',
				className : this.className,
				events : {
					keydown : function(e){

						if(!self._origValue){
							self._origValue = self.textField.value;
						}

						if(e.ctrlKey){
							self.bluring = false;
						}

						if(e.keyCode == 9 && self.isNotEdited()){
							self.editStop();
						} else if(e.keyCode == 27){
							self.editStop();
						} else if(
							this.nodeName == 'INPUT' && e.keyCode == 13
							|| (e.ctrlKey || e.metaKey) && e.keyCode == 83
						){
							e.stopPropagation();
							e.preventDefault();
							self.onSave.call(self, self.textField.value);
						}

						var maxlength = this.getAttribute('maxlength');
						if(maxlength && this.value.length == maxlength && e.keyCode != 8){
							return self.onMaxLength(e);
						}

						if(self.onKeyDown(e) === false){
							return false;
						}

						if(self.onKeyUp(e) === false){
							return false;
						}
					},
					blur : function(e){
						if(self.isNotEdited()){
							self.bluring = true;
							window.setTimeout(function(){
							if(self.bluring){
									self.editStop();
							}}, 400);
						}

					}
				}
			});

			if(this.type == 'input'){
				this.textField.setAttribute('type', 'text');
			}

			for(var prop in this.attributes){
				this.textField.setAttribute(prop, this.attributes[prop]);
			}

			this.textField.appendTo(this.editor);

			this.editBar = new sb.element({
				tag : 'editbar',
				innerHTML : '<button class="cancel">cancel</button><button class="save">save</button>',
				className : this.type,
				events : {
					mousedown : function(e){
						var target = e.target;
						e.preventDefault();
						e.stopPropagation();
						if(target.nodeName == 'BUTTON'){

							switch(target.innerHTML){
								case 'save':
									self.onSave(self.textField.value);
									break;

								case 'cancel':
									self.editStop();
									break;

								default:
									self.onButtonPress(e);
							}
						}

						return true;

					}
				}
			});

			this.editBar.appendTo(this.editor);
		}
	}
};<commit_msg>added new onEditStop prototype method<commit_after>sb.forms.editable = {};
sb.include('Element.prototype.isWithin');
/**
@Name: sb.forms.editable.field
@Description: Creates a click to edit text block
@Param: Object
type string input or textarea
editableElement object/string The element to edit #myDiv, $('#myDiv')
className string the classname for the widget, defaults to
attributes object additional html attributes you want assigned to the textfield, cols, rows, size, maxlength, etc
onBeforeEdit function Fires before editing begins,  Can be used to load raw text wihtout HTML from server
onSave function Fires after save, send back to server, stop editing

@Example:
//use the following in a dblclick event for the text you want to make editable

var editor = sb.forms.editable.field({
	editableElement : e.target,
	type : 'textarea',
	onBeforeEdit : function(){},
	onSave : function(value){}
});

editor.edit();
//example CSS

.sb_forms_editable textarea{
	cursor:text;
	display:block;
	width:97%;
	height:100px;
	overflow:auto;
	font-family:tahoma;
	font-size:1.1em;
}

.sb_forms_editable editbar.input{
	margin-left:5px;
}

.sb_forms_editable editbar.textarea{
	display:block;
	text-align:right;
}

.sb_forms_editable button{
	background-color:#d88713;
	color:#7c4e0d;
}

.sb_forms_editable button:hover{
	background-color:#e2b370;
}

*/
sb.forms.editable.field = function(params){
	if(!params.editableElement){
		throw('You must define the element with sb.forms.editable.field');
	}
	this.editableElement = sb.$(params.editableElement);
	if(this.editableElement.sb_editor){
		return this.editableElement.editor;
	}

	sb.objects.infuse(params, this);
	this.editableElement.sb_editor = this;

	this.className = params.className || 'sb_forms_editable';
};

sb.forms.editable.field.prototype = {

	/**
	@Name: sb.forms.editable.field.onBeforeEdit
	@Description: Fires before editing begins.  Can be used to load raw data with ajax
	to fill the textField with.  Reference the textField with this.textField.  The default is
	to use the innerHTML of the area being edited
	@Example:
	editor.onBeforeEdit = function(){
		this.setValue('loading...');
		var editor = this;

		var aj = new sb.ajax({
			url : '/url/rawtext',
			data : {
				doc_id : doc_id
			},
			onResponse : function(raw_desc){
				editor.setValue(raw_desc);
			}
		}).fetch();
	};
	*/
	onBeforeEdit : function(){
		this.setValue(this.editableElement.innerHTML);
	},

	/**
	@Name: sb.forms.editable.field.onSave
	@Description: Passes the value of the textField for you to save back with ajax
	@Param string save The value of the textField when save if fired
	editor.onSave = function(){
		if(value != 'loading...'){
			var editor = this;
			var aj = new sb.ajax({
				url : '/url/save',
				data : {
					doc_id : doc_id,
					value : value
				},
				onResponse : function(html){
					editor.setHTML(html);
				}
			}).fetch();
		}
	};

	*/
	onSave : function(value){},

	/**
	@Name: sb.forms.editable.field.onButtonPress
	@Description: Fires when a button is pressed other than save or cancel
	@Param event e The press event
	@Example:
	editor.onButtonPress = function(e){
		var button = e.target;
	};
	*/
	onButtonPress : function(e){return true;},

	/**
	@Name: sb.forms.editable.field.onEditStop
	@Description: Fires when a button is pressed other than save or cancel
	@Param event e The press event
	@Example:
	editor.onEditStop = function(){

	};
	*/
	onEditStop : function(e){},

	/**
	@Name: sb.forms.editable.field.onMaxLength
	@Description: Fires when user exceeds textField maxlength if set.
	@Param event e The press event
	@Example:
	editor.onMaxLength = function(e){};
	*/
	onMaxLength : function(e){e.preventDefault();},

	/**
	@Name: sb.forms.editable.field.onKeyDown
	@Description: Fires when a key is pressed, lets you do something with it
	@Param event e The press event
	@Example:
	editor.onKeyDown = function(e){};
	*/
	onKeyDown : function(e){},

	/**
	@Name: sb.forms.editable.field.onKeyUp
	@Description: Fires when a key is released, lets you do something with it
	@Param event e The press event
	@Example:
	editor.onKeyDown = function(e){
		//get rid of digits
		e.target.value = e.target.value.replace(/\d/, '');
	};
	*/
	onKeyUp : function(e){},

	/**
	@Name: sb.forms.editable.field.setValue
	@Description: Sets the value of the textField, use in onBeforeEdit after loading raw text from ajax
	@Example:
	editor.setValue('text to edit');
	*/
	setValue : function(value){
		this.textField.value = value;
		this.focus();
	},

	/**
	@Name: sb.forms.editable.field.setHTML
	@Description: Sets the html of the element being edited, use in onSave after saving
	@Example:
	editor.setHTML('
text that was edited
');
	*/
	setHTML : function(html){
		this.editableElement.innerHTML = html;
		this.editStop();
	},

	/**
	@Name: sb.forms.editable.field.edit
	@Description: Put the editor in edit mode
	@Example:
	editor.edit(target);
	*/
	edit : function(){
		if(!this.editor){
			this.create();
		}

		this.editor.replace(this.editableElement);

		if(typeof this.onBeforeEdit == 'function'){
			this.onBeforeEdit.call(this);
		}
	},

	/**
	@Name: sb.forms.editable.field.editStop
	@Description: Exit edit mode
	@Example:
	editor.editStop();
	*/
	editStop : function(e){
		if(typeof this.onEditStop == 'function'){
			this.onEditStop(e);
		}
		this.editableElement.replace(this.editor);
		this._origValue = '';
	},

	/**
	@Name: sb.forms.editable.field.focus
	@Description: Focuses on text area and puts cursor at top left. automatically fires after setValue
	@Example:
	editor.focus();
	*/
	focus : function(){
		var ta = this.textField;
		var range;
		if (this.textField.setSelectionRange) {
			this.textField.setSelectionRange(0, 0);
		} else if(this.textField.createTextRange){
			range = this.textField.createTextRange();
			range.collapse(true);
			range.moveStart("character", 0);
			range.moveEnd("character", 0 - 0);
			range.select();
		}
		this.textField.focus();

	},

	/**
	@Name: sb.forms.editable.field.addButton
	@Description: Adds a button to the editBar
	@Param string str The name of the button to add
	@Example:
	editor.addButton('email');
	*/
	addButton : function(str){
		this.editBar.innerHTML = '<button>'+str+'</button>'+this.editBar.innerHTML;

	},

	/**
	@Name: sb.forms.editable.field.isNotEdited
	@Description: Determines if field is edited or not
	@Example:
	if(editor.isNotEdited()){}
	*/
	isNotEdited : function(){
		return !this._origValue || this._origValue == this.textField.value;
	},

	/**
	@Name: sb.forms.editable.field.editStop
	@Description: Used internally Creates editor
	*/
	create : function(){
		var self = this;
		if(!this.editor){
			this.editor = new sb.element({
				tag : 'div',
				className : self.className,
				title : 'shortcuts: esc to cancel, ctrl+s'
			});

			if(this.type == 'input'){
				this.editor.title += ' or enter ';
			}

			this.editor.title += 'to save';

			this.textField = new sb.element({
				tag : this.type,
				value : this.value || '',
				className : this.className,
				events : {
					keydown : function(e){

						if(!self._origValue){
							self._origValue = self.textField.value;
						}

						if(e.ctrlKey){
							self.bluring = false;
						}

						if(e.keyCode == 9 && self.isNotEdited()){
							self.editStop();
						} else if(e.keyCode == 27){
							self.editStop();
						} else if(
							this.nodeName == 'INPUT' && e.keyCode == 13
							|| (e.ctrlKey || e.metaKey) && e.keyCode == 83
						){
							e.stopPropagation();
							e.preventDefault();
							self.onSave.call(self, self.textField.value);
						}

						var maxlength = this.getAttribute('maxlength');
						if(maxlength && this.value.length == maxlength && e.keyCode != 8){
							return self.onMaxLength(e);
						}

						if(self.onKeyDown(e) === false){
							return false;
						}

						if(self.onKeyUp(e) === false){
							return false;
						}
					},
					blur : function(e){
						if(self.isNotEdited()){
							self.bluring = true;
							window.setTimeout(function(){
							if(self.bluring){
									self.editStop();
							}}, 400);
						}

					}
				}
			});

			if(this.type == 'input'){
				this.textField.setAttribute('type', 'text');
			}

			for(var prop in this.attributes){
				this.textField.setAttribute(prop, this.attributes[prop]);
			}

			this.textField.appendTo(this.editor);

			this.editBar = new sb.element({
				tag : 'editbar',
				innerHTML : '<button class="cancel">cancel</button><button class="save">save</button>',
				className : this.type,
				events : {
					mousedown : function(e){
						var target = e.target;
						if(target.nodeName == 'BUTTON'){
							if(self.onButtonPress.call(self, e) === false){
								return false;
							}
							switch(target.innerHTML){
								case 'save':
									self.onSave(self.textField.value);
									break;

								case 'cancel':
									self.editStop(e);
									break;
							}
						}
						e.preventDefault();
						e.stopPropagation();

						return true;

					}
				}
			});

			this.editBar.appendTo(this.editor);
		}
	}
};<|endoftext|>


<commit_before>var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var _ = require('underscore');
var PanelWithOptionsView = require('../../../../editor/components/view-options/panel-with-options-view');
var CodeMirrorView = require('../../../../editor/components/code-mirror/code-mirror-view');
var InfowindowContentView = require('./infowindow-content-view');
var ScrollView = require('../../../../components/scroll/scroll-view');
var TabPaneView = require('../../../../components/tab-pane/tab-pane-view');
var TabPaneCollection = require('../../../../components/tab-pane/tab-pane-collection');
var Toggler = require('../../../../editor/components/toggler/toggler-view');

module.exports = CoreView.extend({

  initialize: function (opts) {
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
    if (!opts.editorModel) throw new Error('editorModel is required');
    this._layerDefinitionModel = opts.layerDefinitionModel;
    this._editorModel = opts.editorModel;

    this._initBinds();
    this._initTemplates();
  },

  _initBinds: function () {
    this.model.bind('change', this._onChange.bind(this), this.model);
  },

  _onChange: function () {
    this._layerDefinitionModel.save();
  },

  render: function () {
    this.clearSubViews();

    var self = this;

    // CodeMirror placeholder
    var CodeMirrorModel = new Backbone.Model({
      content: 'Hola mundo'
    });

    var Dummy = CoreView.extend({
      render: function () {
        this.$el.html(this.options.content);
        return this;
      }
    });

    var tabPaneTabs = [{
      selected: true,
      createContentView: function () {
        return new ScrollView({
          createContentView: function () {
            return new InfowindowContentView(_.extend(self.options, { templates: self._templates }));
          }
        });
      }
    }, {
      selected: false,
      createContentView: function () {
        return new ScrollView({
          createContentView: function () {
            return new CodeMirrorView({
              model: CodeMirrorModel
            });
          }
        });
      }
    }];

    var collectionPane = new TabPaneCollection(tabPaneTabs);

    var panelWithOptionsView = new PanelWithOptionsView({
      className: 'Editor-content',
      editorModel: self._editorModel,
      createContentView: function () {
        return new TabPaneView({
          collection: collectionPane
        });
      },
      createControlView: function () {
        return new Toggler({
          editorModel: self._editorModel,
          collection: collectionPane,
          labels: ['VALUES', 'HTML']
        });
      },
      createActionView: function () {
        return new Dummy({
          content: ''
        });
      }
    });

    this.$el.append(panelWithOptionsView.render().el);
    this.addView(panelWithOptionsView);

    return this;
  },

  clean: function () {
    this.model.unbind('change', null, this.model);
    CoreView.prototype.clean.apply(this);
  }
});<commit_msg>linter<commit_after>var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var _ = require('underscore');
var PanelWithOptionsView = require('../../../../editor/components/view-options/panel-with-options-view');
var CodeMirrorView = require('../../../../editor/components/code-mirror/code-mirror-view');
var InfowindowContentView = require('./infowindow-content-view');
var ScrollView = require('../../../../components/scroll/scroll-view');
var TabPaneView = require('../../../../components/tab-pane/tab-pane-view');
var TabPaneCollection = require('../../../../components/tab-pane/tab-pane-collection');
var Toggler = require('../../../../editor/components/toggler/toggler-view');

module.exports = CoreView.extend({

  initialize: function (opts) {
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
    if (!opts.editorModel) throw new Error('editorModel is required');
    this._layerDefinitionModel = opts.layerDefinitionModel;
    this._editorModel = opts.editorModel;

    this._initBinds();
    this._initTemplates();
  },

  _initBinds: function () {
    this.model.bind('change', this._onChange.bind(this), this.model);
  },

  _onChange: function () {
    this._layerDefinitionModel.save();
  },

  render: function () {
    this.clearSubViews();

    var self = this;

    // CodeMirror placeholder
    var CodeMirrorModel = new Backbone.Model({
      content: 'Hola mundo'
    });

    var Dummy = CoreView.extend({
      render: function () {
        this.$el.html(this.options.content);
        return this;
      }
    });

    var tabPaneTabs = [{
      selected: true,
      createContentView: function () {
        return new ScrollView({
          createContentView: function () {
            return new InfowindowContentView(_.extend(self.options, { templates: self._templates }));
          }
        });
      }
    }, {
      selected: false,
      createContentView: function () {
        return new ScrollView({
          createContentView: function () {
            return new CodeMirrorView({
              model: CodeMirrorModel
            });
          }
        });
      }
    }];

    var collectionPane = new TabPaneCollection(tabPaneTabs);

    var panelWithOptionsView = new PanelWithOptionsView({
      className: 'Editor-content',
      editorModel: self._editorModel,
      createContentView: function () {
        return new TabPaneView({
          collection: collectionPane
        });
      },
      createControlView: function () {
        return new Toggler({
          editorModel: self._editorModel,
          collection: collectionPane,
          labels: ['VALUES', 'HTML']
        });
      },
      createActionView: function () {
        return new Dummy({
          content: ''
        });
      }
    });

    this.$el.append(panelWithOptionsView.render().el);
    this.addView(panelWithOptionsView);

    return this;
  },

  clean: function () {
    this.model.unbind('change', null, this.model);
    CoreView.prototype.clean.apply(this);
  }

});
<|endoftext|>


<commit_before>// mobile javascript
var data;

$(document).ready(function() {

    var course_data = null;
    var book_data = null;

    //probably extraneous
    Handlebars.registerHelper("formatTime", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10);
        if (formatted[0] > 12) {
            formatted[0] -= 12;
        }
        return formatted.join(":");
    });

    //converts 24 hour time to 12 hour
    Handlebars.registerHelper("formatTimeAMPM", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10);
        if (formatted[0] < 12) {
            formatted[1] += "AM";
        }
        else {
            formatted[1] += "PM";
        }

        if (formatted[0] > 12) {
            formatted[0] = formatted[0] - 12;
        }
        return formatted.join(":");
    });

    Handlebars.registerHelper("ucfirst", function(str) {
        return str.replace(/^([a-z])/, function(match) {
            return match.toUpperCase();
        });
    });

    Handlebars.registerHelper("formatPrice", function(price) {
        formatted = price.toString().split(".");
        if (formatted[1] && formatted[1].length == 1) {
            formatted[1] += "0";
        }
        return formatted.join(".");
    });

    Handlebars.registerHelper('equal', function(value1, value2, options) {
        if (arguments.length < 3)
            throw new Error("Handlebars Helper equal needs 2 parameters");
        if(value1 != value2) {
            return options.inverse(this);
        }
        else {
            return options.fn(this);
        }
    });

    History.Adapter.bind(window,'statechange',function(){
        var history_state = History.getState();
        var data = history_state.data;
        var state = data.state;

        if (state === undefined) {
            show_page_from_url();
        }
        else if (state === "course_list") {
            // Figure out what to do from the url
            CourseList.show_list(data.course_index);
        }
        else if (state === "instructor") {
            Instructor.show_instructor(data.instructor);
        }
        else if (state === "textbooks") {
            TextBooks.show_books();
        }
        else if (state === "quicklinks") {
            QuickLinks.show_links();
        }
        else if (state === "visual") {
            VisualSchedule.show_visual_schedule(data.course_index);
        }
    });

    function show_page_from_url() {
        var path = window.location.pathname;

        var hist = window.History;

        // The replaceState is for MUWM-368
        if (path === "/mobile/") {
            hist.replaceState({
                state: "course_list",
                }, "", "/mobile"
            );
            //CourseList.show_list();
        }
        else if (path.match("/mobile/visual")) {
            var matches = path.match(/^\/my\/visual\/([0-9]+)/);
            if (matches) {
                hist.replaceState({
                    state: "visual",
                    course_index: matches[1]
                },  "", "/mobile/visual");
                //VisualSchedule.show_visual_schedule(matches[1]);
            }
            else {
                hist.replaceState({
                    state: "visual"
                },  "", "/mobile/visual");
                //VisualSchedule.show_visual_schedule();
            }
        }
        else if (path === "/mobile/textbooks") {
            hist.replaceState({
                state: "textbooks"
            },  "", "/mobile/textbooks");
            //TextBooks.show_books();
        }
        else if (path === "/mobile/textbooks") {
            hist.replaceState({
                state: "textbooks"
            },  "", "/mobile/textbooks");
            //TextBooks.show_books();
        }
        else if (path === "/mobile/links") {
            hist.replaceState({
                state: "quicklinks"
            },  "", "/mobile/links");
            //QuickLinks.show_links();
        }
        else if (path.match(/^\/my\/instructor\/[A-Z0-9]+/)) {
            var matches = path.match(/^\/my\/instructor\/([A-Z0-9]+)/);
            hist.pushState({
                state: "instructor",
                instructor: matches[1]
            },  "", "/mobile/instructor/"+matches[1]);

//            Instructor.show_instructor(matches[1]);
        }
        else {
            // Just fall back to the course list?
            hist.replaceState({
                state: "course_list",
                }, "", "/my"
            );
            //CourseList.show_list();
        }
        History.Adapter.trigger(window, 'statechange');
    }

    show_page_from_url();

    $(".quicklinks").bind("click", function(ev) {
        $("#myuw_nav").collapse('hide');
        var hist = window.History;
        hist.pushState({
            state: "quicklinks",
        },  "", "/mobile/links");

        return false;
    });

});
<commit_msg>A few more /my to /mobile changes<commit_after>// mobile javascript
var data;

$(document).ready(function() {

    var course_data = null;
    var book_data = null;

    //probably extraneous
    Handlebars.registerHelper("formatTime", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10);
        if (formatted[0] > 12) {
            formatted[0] -= 12;
        }
        return formatted.join(":");
    });

    //converts 24 hour time to 12 hour
    Handlebars.registerHelper("formatTimeAMPM", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10);
        if (formatted[0] < 12) {
            formatted[1] += "AM";
        }
        else {
            formatted[1] += "PM";
        }

        if (formatted[0] > 12) {
            formatted[0] = formatted[0] - 12;
        }
        return formatted.join(":");
    });

    Handlebars.registerHelper("ucfirst", function(str) {
        return str.replace(/^([a-z])/, function(match) {
            return match.toUpperCase();
        });
    });

    Handlebars.registerHelper("formatPrice", function(price) {
        formatted = price.toString().split(".");
        if (formatted[1] && formatted[1].length == 1) {
            formatted[1] += "0";
        }
        return formatted.join(".");
    });

    Handlebars.registerHelper('equal', function(value1, value2, options) {
        if (arguments.length < 3)
            throw new Error("Handlebars Helper equal needs 2 parameters");
        if(value1 != value2) {
            return options.inverse(this);
        }
        else {
            return options.fn(this);
        }
    });

    History.Adapter.bind(window,'statechange',function(){
        var history_state = History.getState();
        var data = history_state.data;
        var state = data.state;

        if (state === undefined) {
            show_page_from_url();
        }
        else if (state === "course_list") {
            // Figure out what to do from the url
            CourseList.show_list(data.course_index);
        }
        else if (state === "instructor") {
            Instructor.show_instructor(data.instructor);
        }
        else if (state === "textbooks") {
            TextBooks.show_books();
        }
        else if (state === "quicklinks") {
            QuickLinks.show_links();
        }
        else if (state === "visual") {
            VisualSchedule.show_visual_schedule(data.course_index);
        }
    });

    function show_page_from_url() {
        var path = window.location.pathname;

        var hist = window.History;

        // The replaceState is for MUWM-368
        if (path === "/mobile/") {
            hist.replaceState({
                state: "course_list",
                }, "", "/mobile"
            );
            //CourseList.show_list();
        }
        else if (path.match("/mobile/visual")) {
            var matches = path.match(/^\/mobile\/visual\/([0-9]+)/);
            if (matches) {
                hist.replaceState({
                    state: "visual",
                    course_index: matches[1]
                },  "", "/mobile/visual");
                //VisualSchedule.show_visual_schedule(matches[1]);
            }
            else {
                hist.replaceState({
                    state: "visual"
                },  "", "/mobile/visual");
                //VisualSchedule.show_visual_schedule();
            }
        }
        else if (path === "/mobile/textbooks") {
            hist.replaceState({
                state: "textbooks"
            },  "", "/mobile/textbooks");
            //TextBooks.show_books();
        }
        else if (path === "/mobile/textbooks") {
            hist.replaceState({
                state: "textbooks"
            },  "", "/mobile/textbooks");
            //TextBooks.show_books();
        }
        else if (path === "/mobile/links") {
            hist.replaceState({
                state: "quicklinks"
            },  "", "/mobile/links");
            //QuickLinks.show_links();
        }
        else if (path.match(/^\/mobile\/instructor\/[A-Z0-9]+/)) {
            var matches = path.match(/^\/mobile\/instructor\/([A-Z0-9]+)/);
            hist.pushState({
                state: "instructor",
                instructor: matches[1]
            },  "", "/mobile/instructor/"+matches[1]);

//            Instructor.show_instructor(matches[1]);
        }
        else {
            // Just fall back to the course list?
            hist.replaceState({
                state: "course_list",
                }, "", "/mobile"
            );
            //CourseList.show_list();
        }
        History.Adapter.trigger(window, 'statechange');
    }

    show_page_from_url();

    $(".quicklinks").bind("click", function(ev) {
        $("#myuw_nav").collapse('hide');
        var hist = window.History;
        hist.pushState({
            state: "quicklinks",
        },  "", "/mobile/links");

        return false;
    });

});
<|endoftext|>


<commit_before>import React from 'react';
import Document, { Head, Main, NextScript } from 'next/document';

import { GA_TRACKING_ID } from '../lib/gtag';

export default class extends Document {
  render() {
    return (

          <meta charSet="utf-8" />
          <meta content="width=device-width, initial-scale=1" name="viewport" />
          <meta property="og:type" content="website" />
          <meta content="summary" name="twitter:card" />
          <link rel="icon" type="image/x-icon" href="/static/img/favicon.ico" />


<commit_before>/*
 * @copyright 2011 - present by OpenGamma Inc
 * @license See distribution for license
 */
$.register_module({
    name: 'og.common.gadgets.GadgetsContainer',
    dependencies: ['og.common.gadgets.manager', 'og.api.text'],
    obj: function () {
        var api = og.api, tabs_template, overflow_template, header = ' .ui-layout-header', panels = {
                '.OG-layout-analytics-south': 'south',
                '.OG-layout-analytics-dock-north': 'dock-north',
                '.OG-layout-analytics-dock-center': 'dock-center',
                '.OG-layout-analytics-dock-south': 'dock-south'
            };
        /**
         * @param {String} selector Selector to initialize a GadgetsContainer in
         */
        return function (selector) {
            var initialized = false, loading, counter = 1, gadgets = [], container = this,
                pane, // layout pannel
                live_id, // active tab id
                overflow = {}, // document offet of overflow panel
                $overflow_panel; // panel that houses non visible tabs
            /**
             * @param {Number|Null} id
             *        if id is a Number set the active tab to that ID
             *        if id is undefined use the current Live ID and reflow tabs
             *        if id is null set tabs to a single empty tab
             */
            var update_tabs = function (id) {
                var $header = $(selector + header), tabs, reflow;
                /** Manages the widths of the tabs when the panel is resized, the following stages exist:
                 *  0 - all tabs are full size
                 *  1 - all but the active tab are truncated
                 *  2 - tabs are truncated plus some/all are moved to an overflow panel
                 *  3 - same as above with active tab being truncated
                 */
                reflow = function () {
                    var overflow_buffer = 25, // space for the overflow button
                        buttons_buffer = {'south': 23}, // add extra buffer space if the tabs area has buttons
                        min_tab_width = 30,
                        $tabs_container = $(selector + ' .OG-gadget-tabs'),
                        $tabs = $tabs_container.find('li[class^=og-tab-]'),
                        $active_tab = $(selector + ' .og-active'),
                        $overflow_button = $(selector + ' .og-overflow'),
                        active_tab_width = $active_tab.outerWidth(),
                        num_inactive_tabs = $tabs.length - 1,
                        new_tab_width, // new truncated width of a tab
                        compressed_tabs_width, // new full width of all tabs
                        space_needed, // number of pixles needed to reclaim
                        num_tabs_to_hide, // number of tabs to move to overflow
                        $tabs_to_move, // the actual tabs we are moving
                        // full available width
                        full_width = $tabs_container.width() - (overflow_buffer + (buttons_buffer[pane] || 0)),
                        // the full width of all the tabs
                        tabs_width = Array.prototype.reduce.apply($tabs
                            .map(function () {return $(this).outerWidth();}), [function (a, b) {return a + b;}, 0]);
                    // stage 1
                    if (tabs_width > full_width) {
                        new_tab_width = ~~((full_width - active_tab_width) / num_inactive_tabs);
                        new_tab_width = new_tab_width < min_tab_width ? min_tab_width : new_tab_width;
                        compressed_tabs_width = (num_inactive_tabs * new_tab_width) + active_tab_width;
                        // stage 2
                        if (compressed_tabs_width > full_width) {
                            $overflow_button.show().on('click', function (e) {
                                e.stopPropagation();
                                $overflow_panel.toggle();
                                var wins = Array.prototype.concat.apply(window, window.frames);
                                if ($overflow_panel.is(":visible")) $(wins).on('click.overflow_handler', function () {
                                    $overflow_panel.hide();
                                    $(wins).off('click.overflow_handler');
                                });
                                else $(wins).off('click.overflow_handler');
                            });
                            space_needed = full_width - compressed_tabs_width;
                            num_tabs_to_hide = Math.ceil(Math.abs(space_needed) / new_tab_width);
                            if (num_tabs_to_hide) $overflow_panel.find('ul').html(
                                $tabs_to_move = $tabs.filter(':not(.og-active):lt(' + num_tabs_to_hide + ')')
                            );
                            // stage 3
                            if (num_tabs_to_hide >= $tabs.length) $active_tab.width(
                                active_tab_width
                                + (space_needed + ((num_inactive_tabs * min_tab_width) - overflow_buffer))
                                + 'px'
                            );
                        } else {
                            $overflow_panel.hide();
                        }
                        // set inactive tab widths to calculated value
                        $tabs.each(function () {if (!$(this).hasClass('og-active')) $(this).outerWidth(new_tab_width)});
                        // unset width of tabs in overflow panel
                        if ($tabs_to_move) $tabs_to_move.each(function () {$(this).attr('style', '');});
                        // set position of overflow panel
                        overflow.right = $(document).width() - ($overflow_button.offset().left + 25 - 5);
                        overflow.height = $overflow_button.height();
                        overflow.top = $overflow_button.offset().top + overflow.height + 4;
                        $overflow_panel.css({'right': overflow.right + 'px', 'top': overflow.top + 'px'});
                        // add tooltips to truncated tabs only
                        $tabs.each(function () {
                            var $this = $(this);
                            if (!!$this.attr('style')) $this.attr('title', $this.text().trim());
                        });

                    }
                };
                if (id === null) $header.html(tabs_template({'tabs': [{'name': 'empty'}]})); // empty tabs
                else {
                    if (id === void 0) id = live_id;
                    tabs = gadgets.reduce(function (acc, val) {
                        return acc.push({
                            'name': val.name, 'active': (id === val.id), 'delete': true, 'id': val.id
                        }) && acc;
                    }, []);
                    if (pane === 'south') tabs.toggle = true; // add min/max toggle button
                    $header.html(tabs_template({'tabs': tabs}));
                    reflow();
                    show_gadget(id);
                }
            };
            /**
             * @param id Id of gadget to show, hide all others
             */
            var show_gadget = function (id) {
                $(selector).find('.OG-gadget-container [class*=OG-gadget-]')
                    .hide().filter('.OG-gadget-' + id).show();
                live_id = id;
            };
            /**
             * @param {String} pane Pane to toggle
             * @param {Boolean} open_only Don't close, only open
             */
            var toggle_pane = function (pane, open_only) {
                var max = '50%', min = $('.OG-layout-analytics-' + pane + ' .OG-gadget-tabs').height(),
                    minimize = function () {
                        og.views.common.layout.inner.sizePane(pane, min);
                        $('.OG-layout-analytics-' + pane + ' .og-js-toggle')
                            .toggleClass('og-icon-minimize og-icon-maximize');
                    },
                    maximize = function () {
                        og.views.common.layout.inner.sizePane(pane, max);
                        $('.OG-layout-analytics-' + pane + ' .og-js-toggle')
                            .toggleClass('og-icon-minimize og-icon-maximize');
                    };
                og.views.common.layout.inner.state[pane].size === min
                        ? maximize()
                        : open_only ? null : minimize();
            };
            container.init = function (arr) {
                loading = true;
                $.when(
                    api.text({module: 'og.analytics.tabs_tash'}),
                    api.text({module: 'og.analytics.tabs_overflow_tash'})
                ).then(function (tabs_tmpl, overflow_tmpl) {
                    pane = panels[selector];
                    if (!tabs_template) tabs_template = Handlebars.compile(tabs_tmpl);
                    if (!overflow_template) overflow_template = Handlebars.compile(overflow_tmpl);
                    if (!$overflow_panel) $overflow_panel = $(overflow_template({pane: pane})).appendTo('body');
                    initialized = true;
                    loading = false;
                    // setup click handlers
                    $(selector + header + ' , .og-js-overflow-' + pane)
                        // handler for tabs (including the ones in the overflow pane)
                        .on('click', 'li[class^=og-tab-]', function () {
                            if (!$(this).hasClass('og-active')) {
                                var id = +$(this).attr('class').replace(/og\-tab\-/, '');
                                update_tabs(id);
                                gadgets[id - 1].gadget.resize();
                            }
                            if (pane === 'south') toggle_pane(pane, true);
                        })
                        // handler for min/max toggle button
                        .on('click', '.og-js-toggle', function () {if (pane === 'south') toggle_pane(pane);});
                    if (!arr) update_tabs(null); else container.add(arr);
                    og.common.gadgets.manager.register(container);
                });
            };
            /**
             * @param {Array}          arr An array of gadget configuration objects
             * @param {Function}       arr[x].gadget
             * @param {Object}         arr[x].options
             * @param {String}         arr[x].name Tab name
             * @param {Boolean}        arr[x].margin Add margin to the container
             */
            container.add = function (arr) {
                if (!loading && !initialized)
                    return container.init(), setTimeout(container.add.partial(arr), 10), container;
                if (!initialized) return setTimeout(container.add.partial(arr), 10), container;
                if (!selector) throw new TypeError('GadgetsContainer has not been initialized');
                var panel_container = selector + ' .OG-gadget-container', new_gadgets;
                new_gadgets = arr.map(function (obj) {
                    var id, gadget_class = 'OG-gadget-' + (id = counter++), gadget,
                        gadget_selector = panel_container + ' .' + gadget_class;
                    $(panel_container)
                        .append('<div class="' + gadget_class + '" />')
                        .find('.' + gadget_class)
                        .css({height: '100%', margin: obj.margin ? 10 : 0});
                    gadgets.push(gadget = {
                        id: id,
                        name: obj.name,
                        gadget: new obj.gadget($.extend(true, obj.options, {selector: gadget_selector}))
                    });
                    return gadget;
                });
                update_tabs(new_gadgets[new_gadgets.length - 1].id);
                return container;
            };
            container.alive = function () {return !!$(selector).length;};
            container.resize = function () {
                gadgets.forEach(function (obj) {
                    if (obj.id === live_id) {
                        $(selector + ' .ui-layout-content').show();
                        update_tabs();
                        obj.gadget.resize();
                    }
                });
            }
        };
    }
});<commit_msg>window and frame array bugfix<commit_after>/*
 * @copyright 2011 - present by OpenGamma Inc
 * @license See distribution for license
 */
$.register_module({
    name: 'og.common.gadgets.GadgetsContainer',
    dependencies: ['og.common.gadgets.manager', 'og.api.text'],
    obj: function () {
        var api = og.api, tabs_template, overflow_template, header = ' .ui-layout-header', panels = {
                '.OG-layout-analytics-south': 'south',
                '.OG-layout-analytics-dock-north': 'dock-north',
                '.OG-layout-analytics-dock-center': 'dock-center',
                '.OG-layout-analytics-dock-south': 'dock-south'
            };
        /**
         * @param {String} selector Selector to initialize a GadgetsContainer in
         */
        return function (selector) {
            var initialized = false, loading, counter = 1, gadgets = [], container = this,
                pane, // layout pannel
                live_id, // active tab id
                overflow = {}, // document offet of overflow panel
                $overflow_panel; // panel that houses non visible tabs
            /**
             * @param {Number|Null} id
             *        if id is a Number set the active tab to that ID
             *        if id is undefined use the current Live ID and reflow tabs
             *        if id is null set tabs to a single empty tab
             */
            var update_tabs = function (id) {
                var $header = $(selector + header), tabs, reflow;
                /** Manages the widths of the tabs when the panel is resized, the following stages exist:
                 *  0 - all tabs are full size
                 *  1 - all but the active tab are truncated
                 *  2 - tabs are truncated plus some/all are moved to an overflow panel
                 *  3 - same as above with active tab being truncated
                 */
                reflow = function () {
                    var overflow_buffer = 25, // space for the overflow button
                        buttons_buffer = {'south': 23}, // add extra buffer space if the tabs area has buttons
                        min_tab_width = 50,
                        $tabs_container = $(selector + ' .OG-gadget-tabs'),
                        $tabs = $tabs_container.find('li[class^=og-tab-]'),
                        $active_tab = $(selector + ' .og-active'),
                        $overflow_button = $(selector + ' .og-overflow'),
                        active_tab_width = $active_tab.outerWidth(),
                        num_inactive_tabs = $tabs.length - 1,
                        new_tab_width, // new truncated width of a tab
                        compressed_tabs_width, // new full width of all tabs
                        space_needed, // number of pixles needed to reclaim
                        num_tabs_to_hide, // number of tabs to move to overflow
                        $tabs_to_move, // the actual tabs we are moving
                        // full available width
                        full_width = $tabs_container.width() - (overflow_buffer + (buttons_buffer[pane] || 0)),
                        // the full width of all the tabs
                        tabs_width = Array.prototype.reduce.apply($tabs
                            .map(function () {return $(this).outerWidth();}), [function (a, b) {return a + b;}, 0]);
                    // stage 1
                    if (tabs_width > full_width) {
                        new_tab_width = ~~((full_width - active_tab_width) / num_inactive_tabs);
                        new_tab_width = new_tab_width < min_tab_width ? min_tab_width : new_tab_width;
                        compressed_tabs_width = (num_inactive_tabs * new_tab_width) + active_tab_width;
                        // stage 2
                        if (compressed_tabs_width > full_width) {
                            $overflow_button.show().on('click', function (e) {
                                e.stopPropagation();
                                $overflow_panel.toggle();
                                var wins = [window].concat(Array.prototype.slice.call(window.frames));
                                if ($overflow_panel.is(":visible")) $(wins).on('click.overflow_handler', function () {
                                    $overflow_panel.hide();
                                    $(wins).off('click.overflow_handler');
                                });
                                else $(wins).off('click.overflow_handler');
                            });
                            space_needed = full_width - compressed_tabs_width;
                            num_tabs_to_hide = Math.ceil(Math.abs(space_needed) / new_tab_width);
                            if (num_tabs_to_hide) $overflow_panel.find('ul').html(
                                $tabs_to_move = $tabs.filter(':not(.og-active):lt(' + num_tabs_to_hide + ')')
                            );
                            // stage 3
                            if (num_tabs_to_hide >= $tabs.length) $active_tab.width(
                                active_tab_width
                                + (space_needed + ((num_inactive_tabs * min_tab_width) - overflow_buffer))
                                + 'px'
                            );
                        } else {
                            $overflow_panel.hide();
                        }
                        // set inactive tab widths to calculated value
                        $tabs.each(function () {if (!$(this).hasClass('og-active')) $(this).outerWidth(new_tab_width)});
                        // unset width of tabs in overflow panel
                        if ($tabs_to_move) $tabs_to_move.each(function () {$(this).attr('style', '');});
                        // set position of overflow panel
                        overflow.right = $(document).width() - ($overflow_button.offset().left + 25 - 5);
                        overflow.height = $overflow_button.height();
                        overflow.top = $overflow_button.offset().top + overflow.height + 4;
                        $overflow_panel.css({'right': overflow.right + 'px', 'top': overflow.top + 'px'});
                        // add tooltips to truncated tabs only
                        $tabs.each(function () {
                            var $this = $(this);
                            if (!!$this.attr('style')) $this.attr('title', $this.text().trim());
                        });

                    }
                };
                if (id === null) $header.html(tabs_template({'tabs': [{'name': 'empty'}]})); // empty tabs
                else {
                    if (id === void 0) id = live_id;
                    tabs = gadgets.reduce(function (acc, val) {
                        return acc.push({
                            'name': val.name, 'active': (id === val.id), 'delete': true, 'id': val.id
                        }) && acc;
                    }, []);
                    if (pane === 'south') tabs.toggle = true; // add min/max toggle button
                    $header.html(tabs_template({'tabs': tabs}));
                    reflow();
                    show_gadget(id);
                }
            };
            /**
             * @param id Id of gadget to show, hide all others
             */
            var show_gadget = function (id) {
                $(selector).find('.OG-gadget-container [class*=OG-gadget-]')
                    .hide().filter('.OG-gadget-' + id).show();
                live_id = id;
            };
            /**
             * @param {String} pane Pane to toggle
             * @param {Boolean} open_only Don't close, only open
             */
            var toggle_pane = function (pane, open_only) {
                var max = '50%', min = $('.OG-layout-analytics-' + pane + ' .OG-gadget-tabs').height(),
                    minimize = function () {
                        og.views.common.layout.inner.sizePane(pane, min);
                        $('.OG-layout-analytics-' + pane + ' .og-js-toggle')
                            .toggleClass('og-icon-minimize og-icon-maximize');
                    },
                    maximize = function () {
                        og.views.common.layout.inner.sizePane(pane, max);
                        $('.OG-layout-analytics-' + pane + ' .og-js-toggle')
                            .toggleClass('og-icon-minimize og-icon-maximize');
                    };
                og.views.common.layout.inner.state[pane].size === min
                        ? maximize()
                        : open_only ? null : minimize();
            };
            container.init = function (arr) {
                loading = true;
                $.when(
                    api.text({module: 'og.analytics.tabs_tash'}),
                    api.text({module: 'og.analytics.tabs_overflow_tash'})
                ).then(function (tabs_tmpl, overflow_tmpl) {
                    pane = panels[selector];
                    if (!tabs_template) tabs_template = Handlebars.compile(tabs_tmpl);
                    if (!overflow_template) overflow_template = Handlebars.compile(overflow_tmpl);
                    if (!$overflow_panel) $overflow_panel = $(overflow_template({pane: pane})).appendTo('body');
                    initialized = true;
                    loading = false;
                    // setup click handlers
                    $(selector + header + ' , .og-js-overflow-' + pane)
                        // handler for tabs (including the ones in the overflow pane)
                        .on('click', 'li[class^=og-tab-]', function () {
                            if (!$(this).hasClass('og-active')) {
                                var id = +$(this).attr('class').replace(/og\-tab\-/, '');
                                update_tabs(id);
                                gadgets[id - 1].gadget.resize();
                            }
                            if (pane === 'south') toggle_pane(pane, true);
                        })
                        // handler for min/max toggle button
                        .on('click', '.og-js-toggle', function () {if (pane === 'south') toggle_pane(pane);});
                    if (!arr) update_tabs(null); else container.add(arr);
                    og.common.gadgets.manager.register(container);
                });
            };
            /**
             * @param {Array}          arr An array of gadget configuration objects
             * @param {Function}       arr[x].gadget
             * @param {Object}         arr[x].options
             * @param {String}         arr[x].name Tab name
             * @param {Boolean}        arr[x].margin Add margin to the container
             */
            container.add = function (arr) {
                if (!loading && !initialized)
                    return container.init(), setTimeout(container.add.partial(arr), 10), container;
                if (!initialized) return setTimeout(container.add.partial(arr), 10), container;
                if (!selector) throw new TypeError('GadgetsContainer has not been initialized');
                var panel_container = selector + ' .OG-gadget-container', new_gadgets;
                new_gadgets = arr.map(function (obj) {
                    var id, gadget_class = 'OG-gadget-' + (id = counter++), gadget,
                        gadget_selector = panel_container + ' .' + gadget_class;
                    $(panel_container)
                        .append('<div class="' + gadget_class + '" />')
                        .find('.' + gadget_class)
                        .css({height: '100%', margin: obj.margin ? 10 : 0});
                    gadgets.push(gadget = {
                        id: id,
                        name: obj.name,
                        gadget: new obj.gadget($.extend(true, obj.options, {selector: gadget_selector}))
                    });
                    return gadget;
                });
                update_tabs(new_gadgets[new_gadgets.length - 1].id);
                return container;
            };
            container.alive = function () {return !!$(selector).length;};
            container.resize = function () {
                gadgets.forEach(function (obj) {
                    if (obj.id === live_id) {
                        $(selector + ' .ui-layout-content').show();
                        update_tabs();
                        obj.gadget.resize();
                    }
                });
            }
        };
    }
});<|endoftext|>