<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Creates collapsible content blocks.
//>>label: Collapsible
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.collapsible.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [
	"jquery",
	"../jquery.mobile.core",
	"../jquery.mobile.widget",
	"../jquery.mobile.registry" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

var rInitialLetter = /([A-Z])/g;

$.widget( "mobile.collapsible", {
	options: {
		expandCueText: null,
		collapseCueText: null,
		collapsed: true,
		heading: "h1,h2,h3,h4,h5,h6,legend",
		collapsedIcon: null,
		expandedIcon: null,
		iconpos: null,
		theme: null,
		contentTheme: null,
		inset: null,
		corners: null,
		mini: null
	},

	_create: function() {
		var anchor,
			$el = this.element.addClass( "ui-collapsible" ),
			opts = this.options,
			heading = $el.children( opts.heading ).first(),
			replacementHeading = heading,
			content = $el.wrapInner( "

" ).children( ".ui-collapsible-content" ),
			accordion = $el.closest( ":jqmData(role='collapsible-set')" + ( $.mobile.collapsibleset ? ", :mobile-collapsibleset" : "" ) ).addClass( "ui-collapsible-set" );

		// Replace collapsibleHeading if it's a legend
		if ( heading.is( "legend" ) ) {
			replacementHeading = $( "
"+ heading.html() +"
" );
			heading.remove();
		}

		anchor = replacementHeading
			//modify markup & attributes
			.addClass( "ui-collapsible-heading" )
			.append( "" )
			.wrapInner( "" )
			.find( "a" )
				.first()
				.addClass( "ui-btn" );

			//drop heading in before content
			replacementHeading.insertBefore( content );

		$.extend( this, {
			_accordion: accordion,
			_accordionWidget: null,
			_anchorClasses: "",
			_elClasses: "",
			_contentTheme: "",
			_anchor: anchor,
			_content: content,
			_collapsibleHeading: heading,
			_collapsibleContent: content
		});

		//events
		this._on({
			"expand": "_handleExpandCollapse",
			"collapse": "_handleExpandCollapse"
		});

		this._on( heading, {
			"tap": function(/* event */) {
				heading.find( "a" ).first().addClass( $.mobile.activeBtnClass );
			},

			"click": function( event ) {

				var type = heading.hasClass( "ui-collapsible-heading-collapsed" ) ? "expand" : "collapse";

				$el.trigger( type );

				event.preventDefault();
				event.stopPropagation();
			}
		});

		this._setOptions( opts );
	},

	_handleExpandCollapse: function( event ) {
		var isCollapse, key, opts;

		if ( !event.isDefaultPrevented() ) {
			opts = $.extend( {}, this.options );

			// Adjust for inherited values.
			for ( key in opts ) {
				opts[ key ] = this._optionValue( opts, key );
			}

			isCollapse = ( event.type === "collapse" );

			event.preventDefault();

			this._collapsibleHeading
				.toggleClass( "ui-collapsible-heading-collapsed", isCollapse )
				.find( ".ui-collapsible-heading-status" )
				.text( isCollapse ? opts.expandCueText : opts.collapseCueText )
				.end()
				.find( "a" ).first()
				.toggleClass( "ui-icon-" + opts.expandedIcon, !isCollapse )

				// logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
				.toggleClass( "ui-icon-" + opts.collapsedIcon, ( isCollapse || opts.expandedIcon === opts.collapsedIcon ) )
				.removeClass( $.mobile.activeBtnClass );

			this.element.toggleClass( "ui-collapsible-collapsed", isCollapse );
			this._collapsibleContent
				.toggleClass( "ui-collapsible-content-collapsed", isCollapse )
				.attr( "aria-hidden", isCollapse )
				.trigger( "updatelayout" );
		}
	},

	_toggleClasses: function( destination, varForOld, newClasses ) {
		if ( this[ varForOld ] !== newClasses ) {
			if ( this[ varForOld ] ) {
				destination.removeClass( this[ varForOld ] );
				this[ varForOld ] = "";
			}

			if ( newClasses ) {
				this[ varForOld ] = newClasses;
				destination.addClass( this[ varForOld ] );
			}
		}
		return this;
	},

	// Retrieve the option value first from the options object passed in and, if
	// null, from the parent accordion or, if that's null too, or if there's no
	// parent accordion, then from the defaults.
	_optionValue: function( options, name ) {
		var ret,
			accordion = this._accordion,
			accordionWidget = this._accordionWidget;

		if ( accordion.length && !accordionWidget ) {
			this._accordionWidget = accordionWidget = accordion.data( "mobile-collapsibleset" );
		}

		ret =
			( options[ name ] != null ) ? options[ name ] :
			( accordionWidget ) ? accordionWidget.options[ name ] :
			accordion.length ? $.mobile.getAttribute( accordion[ 0 ], name.replace( rInitialLetter, "-$1" ).toLowerCase(), true ):
			null;

		if ( null == ret ) {
			ret = $.mobile.collapsible.defaults[ name ];
		}

		return ret;
	},

	_setOptions: function( options ) {
		var key,
			opts = $.extend( {}, this.options, options ),
			$el = this.element,
			classes = "",
			anchorClasses = "";

		// Override inheritable options from the accordion or from defaults if
		// unset in this widget
		for ( key in opts ) {
			opts[ key ] = this._optionValue( opts, key );
		}

		// Set corners for individual collapsibles to false when in a collapsible-set
		if ( this._accordion.length > 0 ) {
			opts.corners = false;
		}

		if ( opts.contentTheme === "none" ) {
			opts.contentTheme = "";
		}

		if ( options.collapsed !== undefined ) {
			$el.trigger( options.collapsed ? "collapse" : "expand" );
		}

		// Establish classes for outermost element
		if ( !!opts.inset ) {
			classes += " ui-collapsible-inset";
			if ( !!opts.corners ) {
				classes += " ui-corner-all" ;
			}
		}
		if ( opts.contentTheme ) {
			classes += " ui-collapsible-themed-content";
		}

		// Establish classes for anchor
		if ( $el.hasClass( "ui-collapsible-collapsed" ) ) {
			anchorClasses += " ui-icon-" + opts.collapsedIcon;
		} else {
			anchorClasses += " ui-icon-" + opts.expandedIcon;
		}
		anchorClasses += " ui-btn-icon-" + opts.iconpos;
		if ( opts.theme ) {
			anchorClasses += " ui-btn-" + opts.theme;
		}
		if ( opts.mini ) {
			anchorClasses += " ui-mini";
		}

		this
			._toggleClasses( this._content, "_contentTheme", opts.contentTheme ? ( "ui-body-" + opts.contentTheme ) : "" )
			._toggleClasses( $el, "_elClasses", classes )
			._toggleClasses( this._anchor, "_anchorClasses", anchorClasses );

		return this._super( options );
	}
});

// Defaults to be used by all instances of collapsible if per-instance values
// are unset or if nothing is specified by way of inheritance from an accordion.
$.mobile.collapsible.defaults = {
	expandCueText: " click to expand contents",
	collapseCueText: " click to collapse contents",
	collapsedIcon: "plus",
	expandedIcon: "minus",
	iconpos: "left",
	inset: true,
	corners: true,
	mini: false
};

$.mobile.collapsible.initSelector = ":jqmData(role='collapsible')";

//auto self-init widgets
$.mobile._enhancer.add( "mobile.collapsible", { dependencies: [ "mobile.page","mobile.toolbar" ] });

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>Collapsible: Add refresh() method which basically applies an empty set of options.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Creates collapsible content blocks.
//>>label: Collapsible
//>>group: Widgets
//>>css.structure: ../css/structure/jquery.mobile.collapsible.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [
	"jquery",
	"../jquery.mobile.core",
	"../jquery.mobile.widget",
	"../jquery.mobile.registry" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

var rInitialLetter = /([A-Z])/g;

$.widget( "mobile.collapsible", {
	options: {
		expandCueText: null,
		collapseCueText: null,
		collapsed: true,
		heading: "h1,h2,h3,h4,h5,h6,legend",
		collapsedIcon: null,
		expandedIcon: null,
		iconpos: null,
		theme: null,
		contentTheme: null,
		inset: null,
		corners: null,
		mini: null
	},

	_create: function() {
		var anchor,
			$el = this.element.addClass( "ui-collapsible" ),
			opts = this.options,
			heading = $el.children( opts.heading ).first(),
			replacementHeading = heading,
			content = $el.wrapInner( "

" ).children( ".ui-collapsible-content" ),
			accordion = $el.closest( ":jqmData(role='collapsible-set')" + ( $.mobile.collapsibleset ? ", :mobile-collapsibleset" : "" ) ).addClass( "ui-collapsible-set" );

		// Replace collapsibleHeading if it's a legend
		if ( heading.is( "legend" ) ) {
			replacementHeading = $( "
"+ heading.html() +"
" );
			heading.remove();
		}

		anchor = replacementHeading
			//modify markup & attributes
			.addClass( "ui-collapsible-heading" )
			.append( "" )
			.wrapInner( "" )
			.find( "a" )
				.first()
				.addClass( "ui-btn" );

			//drop heading in before content
			replacementHeading.insertBefore( content );

		$.extend( this, {
			_accordion: accordion,
			_accordionWidget: null,
			_anchorClasses: "",
			_elClasses: "",
			_contentTheme: "",
			_anchor: anchor,
			_content: content,
			_collapsibleHeading: heading,
			_collapsibleContent: content
		});

		//events
		this._on({
			"expand": "_handleExpandCollapse",
			"collapse": "_handleExpandCollapse"
		});

		this._on( heading, {
			"tap": function(/* event */) {
				heading.find( "a" ).first().addClass( $.mobile.activeBtnClass );
			},

			"click": function( event ) {

				var type = heading.hasClass( "ui-collapsible-heading-collapsed" ) ? "expand" : "collapse";

				$el.trigger( type );

				event.preventDefault();
				event.stopPropagation();
			}
		});

		this._setOptions( opts );
	},

	_handleExpandCollapse: function( event ) {
		var isCollapse, key, opts;

		if ( !event.isDefaultPrevented() ) {
			opts = $.extend( {}, this.options );

			// Adjust for inherited values.
			for ( key in opts ) {
				opts[ key ] = this._optionValue( opts, key );
			}

			isCollapse = ( event.type === "collapse" );

			event.preventDefault();

			this._collapsibleHeading
				.toggleClass( "ui-collapsible-heading-collapsed", isCollapse )
				.find( ".ui-collapsible-heading-status" )
				.text( isCollapse ? opts.expandCueText : opts.collapseCueText )
				.end()
				.find( "a" ).first()
				.toggleClass( "ui-icon-" + opts.expandedIcon, !isCollapse )

				// logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
				.toggleClass( "ui-icon-" + opts.collapsedIcon, ( isCollapse || opts.expandedIcon === opts.collapsedIcon ) )
				.removeClass( $.mobile.activeBtnClass );

			this.element.toggleClass( "ui-collapsible-collapsed", isCollapse );
			this._collapsibleContent
				.toggleClass( "ui-collapsible-content-collapsed", isCollapse )
				.attr( "aria-hidden", isCollapse )
				.trigger( "updatelayout" );
		}
	},

	_toggleClasses: function( destination, varForOld, newClasses ) {
		if ( this[ varForOld ] !== newClasses ) {
			if ( this[ varForOld ] ) {
				destination.removeClass( this[ varForOld ] );
				this[ varForOld ] = "";
			}

			if ( newClasses ) {
				this[ varForOld ] = newClasses;
				destination.addClass( this[ varForOld ] );
			}
		}
		return this;
	},

	// Retrieve the option value first from the options object passed in and, if
	// null, from the parent accordion or, if that's null too, or if there's no
	// parent accordion, then from the defaults.
	_optionValue: function( options, name ) {
		var ret,
			accordion = this._accordion,
			accordionWidget = this._accordionWidget;

		if ( accordion.length && !accordionWidget ) {
			this._accordionWidget = accordionWidget = accordion.data( "mobile-collapsibleset" );
		}

		ret =
			( options[ name ] != null ) ? options[ name ] :
			( accordionWidget ) ? accordionWidget.options[ name ] :
			accordion.length ? $.mobile.getAttribute( accordion[ 0 ], name.replace( rInitialLetter, "-$1" ).toLowerCase(), true ):
			null;

		if ( null == ret ) {
			ret = $.mobile.collapsible.defaults[ name ];
		}

		return ret;
	},

	refresh: function() {
		this._setOptions( {} );
	},

	_setOptions: function( options ) {
		var key,
			opts = $.extend( {}, this.options, options ),
			$el = this.element,
			classes = "",
			anchorClasses = "";

		// Override inheritable options from the accordion or from defaults if
		// unset in this widget
		for ( key in opts ) {
			opts[ key ] = this._optionValue( opts, key );
		}

		// Set corners for individual collapsibles to false when in a collapsible-set
		if ( this._accordion.length > 0 ) {
			opts.corners = false;
		}

		if ( opts.contentTheme === "none" ) {
			opts.contentTheme = "";
		}

		if ( options.collapsed !== undefined ) {
			$el.trigger( options.collapsed ? "collapse" : "expand" );
		}

		// Establish classes for outermost element
		if ( !!opts.inset ) {
			classes += " ui-collapsible-inset";
			if ( !!opts.corners ) {
				classes += " ui-corner-all" ;
			}
		}
		if ( opts.contentTheme ) {
			classes += " ui-collapsible-themed-content";
		}

		// Establish classes for anchor
		if ( $el.hasClass( "ui-collapsible-collapsed" ) ) {
			anchorClasses += " ui-icon-" + opts.collapsedIcon;
		} else {
			anchorClasses += " ui-icon-" + opts.expandedIcon;
		}
		anchorClasses += " ui-btn-icon-" + opts.iconpos;
		if ( opts.theme ) {
			anchorClasses += " ui-btn-" + opts.theme;
		}
		if ( opts.mini ) {
			anchorClasses += " ui-mini";
		}

		this
			._toggleClasses( this._content, "_contentTheme", opts.contentTheme ? ( "ui-body-" + opts.contentTheme ) : "" )
			._toggleClasses( $el, "_elClasses", classes )
			._toggleClasses( this._anchor, "_anchorClasses", anchorClasses );

		return this._super( options );
	}
});

// Defaults to be used by all instances of collapsible if per-instance values
// are unset or if nothing is specified by way of inheritance from an accordion.
$.mobile.collapsible.defaults = {
	expandCueText: " click to expand contents",
	collapseCueText: " click to collapse contents",
	collapsedIcon: "plus",
	expandedIcon: "minus",
	iconpos: "left",
	inset: true,
	corners: true,
	mini: false
};

$.mobile.collapsible.initSelector = ":jqmData(role='collapsible')";

//auto self-init widgets
$.mobile._enhancer.add( "mobile.collapsible", { dependencies: [ "mobile.page","mobile.toolbar" ] });

})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>


<commit_before>import {
  AlphaPipelineStage,
  CustomShader,
  CustomShaderMode,
  FeatureIdPipelineStage,
  CustomShaderPipelineStage,
  DequantizationPipelineStage,
  GeometryPipelineStage,
  LightingPipelineStage,
  MaterialPipelineStage,
  PickingPipelineStage,
  ModelExperimentalPrimitive,
} from "../../../Source/Cesium.js";
import BatchTexturePipelineStage from "../../../Source/Scene/ModelExperimental/BatchTexturePipelineStage.js";

describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
  var mockPrimitive = {
    featureIdAttributes: [],
    featureIdTextures: [],
  };
  var mockNode = {};
  var mockModel = {
    allowPicking: true,
    featureIdAttributeIndex: 0,
  };

  var emptyVertexShader =
    "void vertexMain(VertexInput vsInput, inout vec3 position) {}";
  var emptyFragmentShader =
    "void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {}";

  function verifyExpectedStages(stages, expectedStages) {
    expect(stages.length, expectedStages.stages);
    for (var i = 0; i < stages.length; i++) {
      expect(expectedStages[i].name).toEqual(stages[i].name);
    }
  }

  it("throws for undefined primitive", function () {
    expect(function () {
      return new ModelExperimentalPrimitive({
        primitive: undefined,
        node: mockNode,
        model: mockModel,
      });
    }).toThrowDeveloperError();
  });

  it("throws for undefined node", function () {
    expect(function () {
      return new ModelExperimentalPrimitive({
        primitive: mockPrimitive,
        node: undefined,
        model: mockModel,
      });
    }).toThrowDeveloperError();
  });

  it("throws for undefined model", function () {
    expect(function () {
      return new ModelExperimentalPrimitive({
        primitive: mockPrimitive,
        node: mockNode,
        model: undefined,
      });
    }).toThrowDeveloperError();
  });

  it("constructs", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: mockModel,
    });

    expect(primitive.primitive).toBe(mockPrimitive);
    expect(primitive.node).toBe(mockNode);
    expect(primitive.model).toBe(mockModel);
  });

  it("configures the pipeline stages for model picking", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: mockModel,
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);

    primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        allowPicking: false,
      },
    });

    expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("configures the pipeline stages for instance feature picking", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: {
        instances: {
          featureIdAttributes: [{}],
        },
      },
      model: mockModel,
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      FeatureIdPipelineStage,
      BatchTexturePipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("configures the pipeline stages for feature picking", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: {
        featureIdAttributes: [{}, {}],
        featureIdTextures: [],
      },
      node: {},
      model: {
        allowPicking: true,
        featureIdAttributeIndex: 1,
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      FeatureIdPipelineStage,
      BatchTexturePipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);

    primitive = new ModelExperimentalPrimitive({
      primitive: {
        featureIdAttributes: [],
        featureIdTextures: [{}, {}],
      },
      node: {},
      model: {
        allowPicking: true,
        featureIdTextureIndex: 1,
      },
    });

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("configures dequantization", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: {
        featureIdAttributes: [],
        featureIdTextures: [],
        attributes: [
          {
            semantic: "POSITION",
          },
          {
            semantic: "NORMAL",
            quantization: {},
          },
        ],
      },
      node: mockNode,
      model: mockModel,
    });

    expect(primitive.pipelineStages).toEqual([
      GeometryPipelineStage,
      DequantizationPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ]);
  });

  it("configures the pipeline stages for custom shaders", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        customShader: new CustomShader({
          vertexShaderText: emptyVertexShader,
          fragmentShaderText: emptyFragmentShader,
        }),
        allowPicking: false,
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      CustomShaderPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("disables the material stage if the custom shader mode is REPLACE_MATERIAL", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        customShader: new CustomShader({
          mode: CustomShaderMode.REPLACE_MATERIAL,
          vertexShaderText: emptyVertexShader,
          fragmentShaderText: emptyFragmentShader,
        }),
        allowPicking: false,
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      CustomShaderPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("does not disable the material stage if the custom shader has no fragment shader", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        customShader: new CustomShader({
          mode: CustomShaderMode.REPLACE_MATERIAL,
          vertexShaderText: emptyVertexShader,
        }),
        allowPicking: false,
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      CustomShaderPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });
});
<commit_msg>Fix specs<commit_after>import {
  AlphaPipelineStage,
  CustomShader,
  CustomShaderMode,
  FeatureIdPipelineStage,
  CustomShaderPipelineStage,
  DequantizationPipelineStage,
  GeometryPipelineStage,
  LightingPipelineStage,
  MaterialPipelineStage,
  PickingPipelineStage,
  ModelExperimentalPrimitive,
} from "../../../Source/Cesium.js";
import BatchTexturePipelineStage from "../../../Source/Scene/ModelExperimental/BatchTexturePipelineStage.js";

describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
  var mockPrimitive = {
    featureIdAttributes: [],
    featureIdTextures: [],
  };
  var mockNode = {};
  var mockModel = {
    content: {},
    allowPicking: true,
    featureIdAttributeIndex: 0,
  };

  var emptyVertexShader =
    "void vertexMain(VertexInput vsInput, inout vec3 position) {}";
  var emptyFragmentShader =
    "void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {}";

  function verifyExpectedStages(stages, expectedStages) {
    expect(stages.length, expectedStages.stages);
    for (var i = 0; i < stages.length; i++) {
      expect(expectedStages[i].name).toEqual(stages[i].name);
    }
  }

  it("throws for undefined primitive", function () {
    expect(function () {
      return new ModelExperimentalPrimitive({
        primitive: undefined,
        node: mockNode,
        model: mockModel,
      });
    }).toThrowDeveloperError();
  });

  it("throws for undefined node", function () {
    expect(function () {
      return new ModelExperimentalPrimitive({
        primitive: mockPrimitive,
        node: undefined,
        model: mockModel,
      });
    }).toThrowDeveloperError();
  });

  it("throws for undefined model", function () {
    expect(function () {
      return new ModelExperimentalPrimitive({
        primitive: mockPrimitive,
        node: mockNode,
        model: undefined,
      });
    }).toThrowDeveloperError();
  });

  it("constructs", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: mockModel,
    });

    expect(primitive.primitive).toBe(mockPrimitive);
    expect(primitive.node).toBe(mockNode);
    expect(primitive.model).toBe(mockModel);
  });

  it("configures the pipeline stages for model picking", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: mockModel,
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);

    primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        allowPicking: false,
        content: {},
      },
    });

    expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("configures the pipeline stages for instance feature picking", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: {
        instances: {
          featureIdAttributes: [{}],
        },
      },
      model: mockModel,
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      FeatureIdPipelineStage,
      BatchTexturePipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("configures the pipeline stages for feature picking", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: {
        featureIdAttributes: [{}, {}],
        featureIdTextures: [],
      },
      node: {},
      model: {
        allowPicking: true,
        featureIdAttributeIndex: 1,
        content: {},
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      FeatureIdPipelineStage,
      BatchTexturePipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);

    primitive = new ModelExperimentalPrimitive({
      primitive: {
        featureIdAttributes: [],
        featureIdTextures: [{}, {}],
      },
      node: {},
      model: {
        allowPicking: true,
        featureIdTextureIndex: 1,
        content: {},
      },
    });

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("configures dequantization", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: {
        featureIdAttributes: [],
        featureIdTextures: [],
        attributes: [
          {
            semantic: "POSITION",
          },
          {
            semantic: "NORMAL",
            quantization: {},
          },
        ],
      },
      node: mockNode,
      model: mockModel,
    });

    expect(primitive.pipelineStages).toEqual([
      GeometryPipelineStage,
      DequantizationPipelineStage,
      MaterialPipelineStage,
      LightingPipelineStage,
      PickingPipelineStage,
      AlphaPipelineStage,
    ]);
  });

  it("configures the pipeline stages for custom shaders", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        content: {},
        customShader: new CustomShader({
          vertexShaderText: emptyVertexShader,
          fragmentShaderText: emptyFragmentShader,
        }),
        allowPicking: false,
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      CustomShaderPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("disables the material stage if the custom shader mode is REPLACE_MATERIAL", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        content: {},
        customShader: new CustomShader({
          mode: CustomShaderMode.REPLACE_MATERIAL,
          vertexShaderText: emptyVertexShader,
          fragmentShaderText: emptyFragmentShader,
        }),
        allowPicking: false,
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      CustomShaderPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });

  it("does not disable the material stage if the custom shader has no fragment shader", function () {
    var primitive = new ModelExperimentalPrimitive({
      primitive: mockPrimitive,
      node: mockNode,
      model: {
        content: {},
        customShader: new CustomShader({
          mode: CustomShaderMode.REPLACE_MATERIAL,
          vertexShaderText: emptyVertexShader,
        }),
        allowPicking: false,
      },
    });

    var expectedStages = [
      GeometryPipelineStage,
      MaterialPipelineStage,
      CustomShaderPipelineStage,
      LightingPipelineStage,
      AlphaPipelineStage,
    ];

    verifyExpectedStages(primitive.pipelineStages, expectedStages);
  });
});
<|endoftext|>


<commit_before>import Component from '@ember/component';
import { computed } from '@ember/object';
import { task, timeout } from 'ember-concurrency';
import { map } from 'rsvp';
import { inject as service } from '@ember/service';
import { all } from 'rsvp';

export default Component.extend({
  flashMessages: service(),
  users: null,
  matchedGroups: null,
  learnerGroup: null,
  finalData: computed('users.[]', 'matchedGroups.[]', 'learnerGroup', function(){
    const users = this.users;
    const learnerGroup = this.learnerGroup;
    const matchedGroups = this.matchedGroups;
    const finalUsers = users.map(obj => {
      let selectedGroup = learnerGroup;
      if (obj.subGroupName) {
        const match = matchedGroups.findBy('name', obj.subGroupName);
        if (match) {
          selectedGroup = match.group;
        }
      }
      return {
        user: obj.userRecord,
        learnerGroup: selectedGroup
      };
    });

    return finalUsers;
  }),

  save: task(function* () {
    yield timeout(10);
    const finalData = this.finalData;
    const done = this.done;
    const flashMessages = this.flashMessages;
    const treeGroups = yield map(finalData, async ({ learnerGroup, user }) => {
      return learnerGroup.addUserToGroupAndAllParents(user);
    });

    const flat = treeGroups.reduce((flattened, arr) => {
      return flattened.pushObjects(arr);
    }, []);

    const groupsToSave = flat.uniq();
    yield all(groupsToSave.invoke('save'));
    flashMessages.success('general.savedSuccessfully');
    done();
  }),
});
<commit_msg>minimal code cleanup.<commit_after>import Component from '@ember/component';
import { computed } from '@ember/object';
import { task, timeout } from 'ember-concurrency';
import { map } from 'rsvp';
import { inject as service } from '@ember/service';
import { all } from 'rsvp';

export default Component.extend({
  flashMessages: service(),
  users: null,
  matchedGroups: null,
  learnerGroup: null,
  finalData: computed('users.[]', 'matchedGroups.[]', 'learnerGroup', function(){
    const users = this.users;
    const learnerGroup = this.learnerGroup;
    const matchedGroups = this.matchedGroups;
    return users.map(obj => {
      let selectedGroup = learnerGroup;
      if (obj.subGroupName) {
        const match = matchedGroups.findBy('name', obj.subGroupName);
        if (match) {
          selectedGroup = match.group;
        }
      }
      return {
        user: obj.userRecord,
        learnerGroup: selectedGroup
      };
    });
  }),

  save: task(function* () {
    yield timeout(10);
    const finalData = this.finalData;
    const done = this.done;
    const flashMessages = this.flashMessages;
    const treeGroups = yield map(finalData, async ({ learnerGroup, user }) => {
      return learnerGroup.addUserToGroupAndAllParents(user);
    });

    const flat = treeGroups.reduce((flattened, arr) => {
      return flattened.pushObjects(arr);
    }, []);

    const groupsToSave = flat.uniq();
    yield all(groupsToSave.invoke('save'));
    flashMessages.success('general.savedSuccessfully');
    done();
  }),
});
<|endoftext|>


<commit_before>export default function content() {
  return {
    name: 'content',

    parse(text) {
      return text.trim();
    },

    autofill(item) {
      if (item.context.code.indexOf('@content') > -1) {
        return '';
      }
    },

    allowedOn: ['mixin'],

    multiple: false,
  };
}
<commit_msg>Do not autofill `content` if already defined<commit_after>export default function content() {
  return {
    name: 'content',

    parse(text) {
      return text.trim();
    },

    autofill(item) {
      if (!item.content && item.context.code.indexOf('@content') > -1) {
        return '';
      }
    },

    allowedOn: ['mixin'],

    multiple: false,
  };
}
<|endoftext|>


<commit_before>import React from 'react';
import * as _ from 'lodash';
import styled from 'styled-components';
import TrendingDown from 'material-ui/svg-icons/action/trending-down';
import TrendingUp from 'material-ui/svg-icons/action/trending-up';
import Counts from './counts';

const TitleStats = styled.h2`
  svg {
    margin-right: 10px;
  }
`;

const iconStyle = {
  width: '32px',
  height: '32px',
  fill: '#5F288D',
};

export default function LeftColumn(props) {
  return (

{props.stats.incidentsByCounty.length} sesizări de la votanți

      <TitleStats>
        <TrendingUp style={iconStyle} />
        Cele mai multe sesizări
      </TitleStats>
      <Counts counts={_.slice(_.reverse(_.sortBy(props.stats.incidentsByCounty, [(county) => county.incidentsCount])), 0, 5)} />
      <TitleStats>
        <TrendingDown style={iconStyle} />
        Cele mai puține sesizări
      </TitleStats>
      <Counts counts={_.slice(_.sortBy(props.stats.incidentsByCounty, [(county) => county.incidentsCount]), 0, 5)} />

  );
}

LeftColumn.propTypes = {
  stats: React.PropTypes.object,
};
<commit_msg>Hot fix - total incidents count<commit_after>import React from 'react';
import * as _ from 'lodash';
import styled from 'styled-components';
import TrendingDown from 'material-ui/svg-icons/action/trending-down';
import TrendingUp from 'material-ui/svg-icons/action/trending-up';
import Counts from './counts';

const TitleStats = styled.h2`
  svg {
    margin-right: 10px;
  }
`;

const iconStyle = {
  width: '32px',
  height: '32px',
  fill: '#5F288D',
};

export default function LeftColumn(props) {
  return (

{props.stats.totalIncidents} sesizări de la votanți

      <TitleStats>
        <TrendingUp style={iconStyle} />
        Cele mai multe sesizări
      </TitleStats>
      <Counts counts={_.slice(_.reverse(_.sortBy(props.stats.incidentsByCounty, [(county) => county.incidentsCount])), 0, 5)} />
      <TitleStats>
        <TrendingDown style={iconStyle} />
        Cele mai puține sesizări
      </TitleStats>
      <Counts counts={_.slice(_.sortBy(props.stats.incidentsByCounty, [(county) => county.incidentsCount]), 0, 5)} />

  );
}

LeftColumn.propTypes = {
  stats: React.PropTypes.object,
};
<|endoftext|>


<commit_before>import express from "express"
import shrinkRay from "shrink-ray"
import uuid from "uuid"
import parameterProtection from "hpp"
import helmet from "helmet"
import PrettyError from "pretty-error"
import favicon from "serve-favicon"
import createLocaleMiddleware from "express-locale"
import cookieParser from "cookie-parser"
import bodyParser from "body-parser"

import {
  ABSOLUTE_CLIENT_OUTPUT_PATH,
  ABSOLUTE_PUBLIC_PATH
} from "./config"

const pretty = new PrettyError()

// this will skip events.js and http.js and similar core node files
pretty.skipNodeFiles()

// this will skip all the trace lines about express` core and sub-modules
pretty.skipPackage("express")

export default function createExpressServer(config)
{
  // Create our express based server.
  const server = express()

  // Create new middleware to serve a favicon from the given path to a favicon file.
  server.use(favicon(`${ABSOLUTE_PUBLIC_PATH}/favicon.ico`))

  // Attach a unique "nonce" to every response. This allows use to declare
  // inline scripts as being safe for execution against our content security policy.
  // @see https://helmetjs.github.io/docs/csp/
  server.use((request, response, next) => {
    response.locals.nonce = uuid() // eslint-disable-line no-param-reassign
    next()
  })

  // and use it for our app's error handler:
  server.use((error, request, response, next) => { // eslint-disable-line max-params
    console.log(pretty.render(error))
    next()
  })

  // Don't expose any software information to hackers.
  server.disable("x-powered-by")

  // Prevent HTTP Parameter pollution.
  server.use(parameterProtection())

  // Content Security Policy (CSP)
  //
  // If you are unfamiliar with CSPs then I highly recommend that you do some
  // reading on the subject:
  //  - https://content-security-policy.com/
  //  - https://developers.google.com/web/fundamentals/security/csp/
  //  - https://developer.mozilla.org/en/docs/Web/Security/CSP
  //  - https://helmetjs.github.io/docs/csp/
  //
  // If you are relying on scripts/styles/assets from other servers (internal or
  // external to your company) then you will need to explicitly configure the
  // CSP below to allow for this.  For example you can see I have had to add
  // the polyfill.io CDN in order to allow us to use the polyfill script.
  // It can be a pain to manage these, but it's a really great habit to get in
  // to.
  //
  // You may find CSPs annoying at first, but it is a great habit to build.
  // The CSP configuration is an optional item for helmet, however you should
  // not remove it without making a serious consideration that you do not require
  // the added security.
  const cspConfig = {
    directives: {
      defaultSrc: [ "'self'" ],

      scriptSrc:
      [
        // Allow scripts hosted from our application.
        "'self'",

        // Note: We will execution of any inline scripts that have the following
        // nonce identifier attached to them.
        // This is useful for guarding your application whilst allowing an inline
        // script to do data store rehydration (redux/mobx/apollo) for example.
        // @see https://helmetjs.github.io/docs/csp/
        (request, response) => `'nonce-${response.locals.nonce}'`,

        // FIXME: Required for eval-source-maps (devtool in webpack)
        process.env.NODE_ENV === "development" ? "'unsafe-eval'" : ""
      ].filter((value) => value !== ""),

      styleSrc: [ "'self'", "'unsafe-inline'", "blob:" ],
      imgSrc: [ "'self'", "data:" ],
      fontSrc: [ "'self'", "data:" ],

      // Note: Setting this to stricter than * breaks the service worker. :(
      // I can't figure out how to get around this, so if you know of a safer
      // implementation that is kinder to service workers please let me know.
      // ["'self'", 'ws:'],
      connectSrc: [ "*" ],

      // objectSrc: [ "'none'" ],
      // mediaSrc: [ "'none'" ],

      childSrc: [ "'self'" ]
    }
  }

  if (process.env.NODE_ENV === "development") {
    // When in development mode we need to add our secondary express server that
    // is used to host our client bundle to our csp config.
    Object.keys(cspConfig.directives).forEach((directive) =>
      cspConfig.directives[directive].push(`localhost:${process.env.CLIENT_DEVSERVER_PORT}`)
    )
  }

  server.use(helmet.contentSecurityPolicy(cspConfig))

  // The xssFilter middleware sets the X-XSS-Protection header to prevent
  // reflected XSS attacks.
  // @see https://helmetjs.github.io/docs/xss-filter/
  server.use(helmet.xssFilter())

  // Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
  // @see https://helmetjs.github.io/docs/frameguard/
  server.use(helmet.frameguard("deny"))

  // Sets the X-Download-Options to prevent Internet Explorer from executing
  // downloads in your site’s context.
  // @see https://helmetjs.github.io/docs/ienoopen/
  server.use(helmet.ieNoOpen())

  // Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
  // to guess (“sniff”) the MIME type, which can have security implications. It
  // does this by setting the X-Content-Type-Options header to nosniff.
  // @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
  server.use(helmet.noSniff())

  // Parse cookies via standard express tooling
  server.use(cookieParser())

  // Detect client locale and match it with configuration
  server.use(createLocaleMiddleware({
    priority: [ "query", "cookie", "accept-language", "default" ],
    default: config.DEFAULT_LOCALE.replace(/-/, "_"),
    allowed: config.ALLOWED_LOCALES.map((entry) => entry.replace(/-/, "_"))
  }))

  // Parse application/x-www-form-urlencoded
  server.use(bodyParser.urlencoded({ extended: false }))

  // Parse application/json
  server.use(bodyParser.json())

  // Advanced response compression using a async zopfli/brotli combination
  // https://github.com/aickin/shrink-ray
  server.use(shrinkRay())

  // Configure static serving of our webpack bundled client files.
  server.use(
    process.env.CLIENT_BUNDLE_HTTP_PATH,
    express.static(ABSOLUTE_CLIENT_OUTPUT_PATH, {
      maxAge: process.env.CLIENT_BUNDLE_CACHE_MAXAGE
    })
  )

  // Configure static serving of our "public" root http path static files.
  server.use(express.static(ABSOLUTE_PUBLIC_PATH))

  return server
}
<commit_msg>Adds hooks to createExpressServer Allows to plug in own middleware to server if e.g. the body must not be parsed before using the middleware<commit_after>import express from "express"
import shrinkRay from "shrink-ray"
import uuid from "uuid"
import parameterProtection from "hpp"
import helmet from "helmet"
import PrettyError from "pretty-error"
import favicon from "serve-favicon"
import createLocaleMiddleware from "express-locale"
import cookieParser from "cookie-parser"
import bodyParser from "body-parser"

import {
  ABSOLUTE_CLIENT_OUTPUT_PATH,
  ABSOLUTE_PUBLIC_PATH
} from "./config"

const pretty = new PrettyError()

// this will skip events.js and http.js and similar core node files
pretty.skipNodeFiles()

// this will skip all the trace lines about express` core and sub-modules
pretty.skipPackage("express")

export default function createExpressServer(config, hooks)
{
  // Create our express based server.
  const server = express()

  // Create new middleware to serve a favicon from the given path to a favicon file.
  server.use(favicon(`${ABSOLUTE_PUBLIC_PATH}/favicon.ico`))

  // Attach a unique "nonce" to every response. This allows use to declare
  // inline scripts as being safe for execution against our content security policy.
  // @see https://helmetjs.github.io/docs/csp/
  server.use((request, response, next) => {
    response.locals.nonce = uuid() // eslint-disable-line no-param-reassign
    next()
  })

  // and use it for our app's error handler:
  server.use((error, request, response, next) => { // eslint-disable-line max-params
    console.log(pretty.render(error))
    next()
  })

  // Don't expose any software information to hackers.
  server.disable("x-powered-by")

  // Prevent HTTP Parameter pollution.
  server.use(parameterProtection())

  // Content Security Policy (CSP)
  //
  // If you are unfamiliar with CSPs then I highly recommend that you do some
  // reading on the subject:
  //  - https://content-security-policy.com/
  //  - https://developers.google.com/web/fundamentals/security/csp/
  //  - https://developer.mozilla.org/en/docs/Web/Security/CSP
  //  - https://helmetjs.github.io/docs/csp/
  //
  // If you are relying on scripts/styles/assets from other servers (internal or
  // external to your company) then you will need to explicitly configure the
  // CSP below to allow for this.  For example you can see I have had to add
  // the polyfill.io CDN in order to allow us to use the polyfill script.
  // It can be a pain to manage these, but it's a really great habit to get in
  // to.
  //
  // You may find CSPs annoying at first, but it is a great habit to build.
  // The CSP configuration is an optional item for helmet, however you should
  // not remove it without making a serious consideration that you do not require
  // the added security.
  const cspConfig = {
    directives: {
      defaultSrc: [ "'self'" ],

      scriptSrc:
      [
        // Allow scripts hosted from our application.
        "'self'",

        // Note: We will execution of any inline scripts that have the following
        // nonce identifier attached to them.
        // This is useful for guarding your application whilst allowing an inline
        // script to do data store rehydration (redux/mobx/apollo) for example.
        // @see https://helmetjs.github.io/docs/csp/
        (request, response) => `'nonce-${response.locals.nonce}'`,

        // FIXME: Required for eval-source-maps (devtool in webpack)
        process.env.NODE_ENV === "development" ? "'unsafe-eval'" : ""
      ].filter((value) => value !== ""),

      styleSrc: [ "'self'", "'unsafe-inline'", "blob:" ],
      imgSrc: [ "'self'", "data:" ],
      fontSrc: [ "'self'", "data:" ],

      // Note: Setting this to stricter than * breaks the service worker. :(
      // I can't figure out how to get around this, so if you know of a safer
      // implementation that is kinder to service workers please let me know.
      // ["'self'", 'ws:'],
      connectSrc: [ "*" ],

      // objectSrc: [ "'none'" ],
      // mediaSrc: [ "'none'" ],

      childSrc: [ "'self'" ]
    }
  }

  if (process.env.NODE_ENV === "development") {
    // When in development mode we need to add our secondary express server that
    // is used to host our client bundle to our csp config.
    Object.keys(cspConfig.directives).forEach((directive) =>
      cspConfig.directives[directive].push(`localhost:${process.env.CLIENT_DEVSERVER_PORT}`)
    )
  }

  server.use(helmet.contentSecurityPolicy(cspConfig))

  // The xssFilter middleware sets the X-XSS-Protection header to prevent
  // reflected XSS attacks.
  // @see https://helmetjs.github.io/docs/xss-filter/
  server.use(helmet.xssFilter())

  // Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
  // @see https://helmetjs.github.io/docs/frameguard/
  server.use(helmet.frameguard("deny"))

  // Sets the X-Download-Options to prevent Internet Explorer from executing
  // downloads in your site’s context.
  // @see https://helmetjs.github.io/docs/ienoopen/
  server.use(helmet.ieNoOpen())

  // Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
  // to guess (“sniff”) the MIME type, which can have security implications. It
  // does this by setting the X-Content-Type-Options header to nosniff.
  // @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
  server.use(helmet.noSniff())

  if (hook.onSecuredServerCreated)
    hook.onSecuredServerCreated(server)

  // Parse cookies via standard express tooling
  server.use(cookieParser())

  // Detect client locale and match it with configuration
  server.use(createLocaleMiddleware({
    priority: [ "query", "cookie", "accept-language", "default" ],
    default: config.DEFAULT_LOCALE.replace(/-/, "_"),
    allowed: config.ALLOWED_LOCALES.map((entry) => entry.replace(/-/, "_"))
  }))

  // Parse application/x-www-form-urlencoded
  server.use(bodyParser.urlencoded({ extended: false }))

  // Parse application/json
  server.use(bodyParser.json())

  // Advanced response compression using a async zopfli/brotli combination
  // https://github.com/aickin/shrink-ray
  server.use(shrinkRay())

  // Configure static serving of our webpack bundled client files.
  server.use(
    process.env.CLIENT_BUNDLE_HTTP_PATH,
    express.static(ABSOLUTE_CLIENT_OUTPUT_PATH, {
      maxAge: process.env.CLIENT_BUNDLE_CACHE_MAXAGE
    })
  )

  // Configure static serving of our "public" root http path static files.
  server.use(express.static(ABSOLUTE_PUBLIC_PATH))

  return server
}
<|endoftext|>


<commit_before>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2013 pimcore GmbH (http://www.pimcore.org)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.object.tags.localizedfields");
pimcore.object.tags.localizedfields = Class.create(pimcore.object.tags.abstract, {

    type: "localizedfields",

    dropdownLayout: false,

    availablePanels: [],

    frontendLanguages: null,

    initialize: function (data, fieldConfig) {

        this.data = {};
        this.metaData = {};
        this.inherited = false;
        this.languageElements = {};
        this.inheritedFields = {};
        this.referencedFields = [];

        if (pimcore.currentuser.admin || fieldConfig.permissionView === undefined) {
            this.frontendLanguages = pimcore.settings.websiteLanguages;
        } else {
            this.frontendLanguages = fieldConfig.permissionView;
        }

        var maxTabs = 15;
        if (typeof fieldConfig.maxTabs == "number") {
            maxTabs = fieldConfig.maxTabs;
        }

        if (this.frontendLanguages.length > maxTabs) {
            this.dropdownLayout = true;
        }

        if (data) {
            if (data.data) {
                this.data = data.data;
            }
            if (data.metaData) {
                this.metaData = data.metaData;
            }
            if (data.inherited) {
                this.inherited = data.inherited;
            }
        }
        this.fieldConfig = fieldConfig;

        this.keysToWatch = [];

        if (this.inherited) {
            for (var i=0; i < this.frontendLanguages.length; i++) {
                var currentLanguage = this.frontendLanguages[i];

                var metadataForLanguage = this.metaData[currentLanguage];
                var dataKeys = Object.keys(metadataForLanguage);

                for (var k = 0; k < dataKeys.length; k++) {
                    var dataKey = dataKeys[k];
                    var metadataForKey = metadataForLanguage[dataKey];
                    if (metadataForKey.inherited) {
                        this.keysToWatch.push({
                            lang: currentLanguage,
                            key: dataKey
                        });
                    }
                }
            }
        }
    },

    getLayoutEdit: function () {

        this.fieldConfig.datatype ="layout";
        this.fieldConfig.fieldtype = "panel";

        var wrapperConfig = {
            border: false,
            layout: "fit"
        };

        if(this.fieldConfig.width) {
            wrapperConfig.width = this.fieldConfig.width;
        }

        if(this.fieldConfig.region) {
            wrapperConfig.region = this.fieldConfig.region;
        }

        if(this.fieldConfig.title) {
            wrapperConfig.title = this.fieldConfig.title;
        }

        var nrOfLanguages = this.frontendLanguages.length;

        if (this.dropdownLayout) {
            //TODO choose default language
            var data = [];
            for (var i = 0; i < nrOfLanguages; i++) {
                var language = this.frontendLanguages[i];
                data.push([language, pimcore.available_languages[language]]);
            }

            var store = new Ext.data.ArrayStore({
                    fields: ["key", "value"],
                    data: data
                }
            );

            var options = {
                triggerAction: "all",
                editable: true,
                selectOnFocus: true,
                queryMode: 'local',
                typeAhead: true,
                forceSelection: true,
                store: store,
                itemCls: "object_field",
                mode: "local",
                width: 300,
                padding: 10,
                displayField: "value",
                valueField: "key",
                value: this.frontendLanguages[0],
                listeners:  {
                    select:    function( combo, record, index ) {
                        var oldLanguage = this.currentLanguage;
                        var newLanguage = record.data.key;
                        if (oldLanguage == newLanguage) {
                            return;
                        }

                        this.availablePanels[oldLanguage].hide();
                        this.availablePanels[newLanguage].show();
                        this.currentLanguage = newLanguage;
                        this.component.doLayout();
                    }.bind(this)
                }
            };

            this.countrySelect = new Ext.form.ComboBox(options);

            wrapperConfig.items = []

            //TODO choose default language, maybe user-specific ?
            for (var i = nrOfLanguages - 1; i >= 0; i--) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                var items =  this.getRecursiveLayout(this.fieldConfig, !editable).items;

                panelConf = {
                    height: "auto",
                    layout: "pimcoreform",
                    border: true,
                    padding: "10px",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: items,
                    hidden: (i > 0)     //TODO default language
                };

                if(this.fieldConfig.height) {
                    panelConf.height = this.fieldConfig.height;
                    panelConf.autoHeight = false;
                    panelConf.autoScroll = true;
                } else {
                    panelConf.autoHeight = true;
                }

                this.tabPanel = new Ext.Panel(panelConf);

                this.availablePanels[this.currentLanguage] = this.tabPanel;
                wrapperConfig.items.push(this.tabPanel);

                wrapperConfig.tbar = [new Ext.Toolbar.TextItem({
                    text: t("language")
                }), this.countrySelect];
            }
        } else {
            var panelConf = {
                autoScroll: true,
                monitorResize: true,
                cls: "object_field",
                activeTab: 0,
                height: 10,
                items: [],
                deferredRender: true,
                forceLayout: true,
                hideMode: "offsets",
                enableTabScroll:true
            };

            if(this.fieldConfig.height) {
                panelConf.height = this.fieldConfig.height;
                panelConf.autoHeight = false;
            }

            // this is because the tabpanel has a strange behavior with automatic height, this corrects the problem
            panelConf.listeners = {
                afterrender: function () {
                    this.tabPanelAdjustIntervalCounter = 0;
                    this.tabPanelAdjustInterval = window.setInterval(function () {

                        this.tabPanelAdjustIntervalCounter++;
                        if(this.tabPanelAdjustIntervalCounter > 20) {
                            clearInterval(this.tabPanelAdjustInterval);
                        }

                        if(!this.fieldConfig.height && !this.fieldConfig.region) {
                            try {
                                var panelBodies = this.tabPanel.items.first().getEl().query(".x-panel-body");
                                var panelBody = Ext.get(panelBodies[0]);
                                panelBody.applyStyles("height: auto;");
                                var height = panelBody.getHeight();
                                // 100 is just a fixed value which seems to be ok(caused by title bar, tabs itself, ... )
                                this.component.setHeight(height+100);

                                //this.tabPanel.getEl().applyStyles("position:relative;");
                                this.component.doLayout();
                            } catch (e) {
                                console.log(e);
                            }
                        }
                    }.bind(this), 100);
                }.bind(this)
            };

            for (var i=0; i < nrOfLanguages; i++) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                panelConf.items.push({
                    xtype: "panel",
                    layout: "pimcoreform",
                    border:false,
                    autoScroll: true,
                    padding: "10px",
                    deferredRender: false,
                    hideMode: "offsets",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: this.getRecursiveLayout(this.fieldConfig, !editable).items
                });
            }

            this.tabPanel = new Ext.TabPanel(panelConf);

            wrapperConfig.items = [this.tabPanel];
        }

        this.component = new Ext.Panel(wrapperConfig);
        this.component.doLayout();
        return this.component;
    },

    getLayoutShow: function () {

        this.component = this.getLayoutEdit();
        this.component.disable();

        return this.component;
    },

    getDataForField: function (name) {
        try {
            if (this.data[this.currentLanguage]) {
                if (this.data[this.currentLanguage][name]) {
                    return this.data[this.currentLanguage][name];
                } else if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return null;
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;
    },

    getMetaDataForField: function(name) {
        try {
            if (this.metaData[this.currentLanguage]) {
                if (this.metaData[this.currentLanguage][name]) {
                    return this.metaData[this.currentLanguage][name];
                } else if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return null;
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;

    },

    addToDataFields: function (field, name) {
        this.languageElements[this.currentLanguage].push(field);
    },

    addFieldsToMask: function (field) {
        this.object.edit.fieldsToMask.push(field);
    },

    addReferencedField: function (field) {
        this.referencedFields.push(field);
    },

    getValue: function () {

        var localizedData = {};
        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {
            currentLanguage = this.frontendLanguages[i];
            localizedData[currentLanguage] = {};

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    localizedData[currentLanguage][this.languageElements[currentLanguage][s].getName()]
                        = this.languageElements[currentLanguage][s].getValue();
                }
            }
        }

        // also add the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                localizedData = array_merge_recursive(localizedData, this.referencedFields[r].getValue());
            }
        }

        return localizedData;
    },

    getName: function () {
        return this.fieldConfig.name;
    },

    isDirty: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isDirty()) {
                    return true;
                }
            }
        }

        if(!this.isRendered()) {
            return false;
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    return true;
                }
            }
        }

        return false;
    },

    isMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    return true;
                }
            }
        }

        return false;
    },

    isInvalidMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isInvalidMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;
        var isInvalid = false;
        var invalidMandatoryFields = [];

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    if(this.languageElements[currentLanguage][s].isInvalidMandatory()) {
                        invalidMandatoryFields.push(this.languageElements[currentLanguage][s].getTitle() + " - "
                            + currentLanguage.toUpperCase() + " ("
                            + this.languageElements[currentLanguage][s].getName() + ")");
                        isInvalid = true;
                    }
                }
            }
        }

        // return the error messages not bool, this is handled in object/edit.js
        if(isInvalid) {
            return invalidMandatoryFields;
        }

        return isInvalid;
    },

    dataIsNotInherited: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                this.referencedFields[r].dataIsNotInherited();
            }
        }

        if (!this.inherited) {
            return true;
        }

        var foundUnmodifiedInheritedField = false;
        for (var i=0; i < this.frontendLanguages.length; i++) {

            var currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {

                if (this.metaData[currentLanguage]) {
                    var languageElement = this.languageElements[currentLanguage][s];
                    var key = languageElement.name;
                    if (this.metaData[currentLanguage][key]) {
                        if (this.metaData[currentLanguage][key].inherited) {
                            if(languageElement.isDirty()) {
                                this.metaData[currentLanguage][key].inherited = false;
                                languageElement.unmarkInherited();
                            } else {
                                foundUnmodifiedInheritedField = true;
                            }
                        }
                    }
                }
            }
        }

        if (!foundUnmodifiedInheritedField) {
            this.inherited = false;
        }
        return !this.inherited;
    },

    markInherited:function (metaData) {
        // nothing to do, only sub-elements can be marked
    }

});

pimcore.object.tags.localizedfields.addMethods(pimcore.object.helpers.edit);<commit_msg>PIMCORE-2193 - localizedfields : layoutShow should not disable child tags but not the localizedfields tag itself<commit_after>/**
 * Pimcore
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.pimcore.org/license
 *
 * @copyright  Copyright (c) 2009-2013 pimcore GmbH (http://www.pimcore.org)
 * @license    http://www.pimcore.org/license     New BSD License
 */

pimcore.registerNS("pimcore.object.tags.localizedfields");
pimcore.object.tags.localizedfields = Class.create(pimcore.object.tags.abstract, {

    type: "localizedfields",

    dropdownLayout: false,

    availablePanels: [],

    frontendLanguages: null,

    initialize: function (data, fieldConfig) {

        this.data = {};
        this.metaData = {};
        this.inherited = false;
        this.languageElements = {};
        this.inheritedFields = {};
        this.referencedFields = [];

        if (pimcore.currentuser.admin || fieldConfig.permissionView === undefined) {
            this.frontendLanguages = pimcore.settings.websiteLanguages;
        } else {
            this.frontendLanguages = fieldConfig.permissionView;
        }

        var maxTabs = 15;
        if (typeof fieldConfig.maxTabs == "number") {
            maxTabs = fieldConfig.maxTabs;
        }

        if (this.frontendLanguages.length > maxTabs) {
            this.dropdownLayout = true;
        }

        if (data) {
            if (data.data) {
                this.data = data.data;
            }
            if (data.metaData) {
                this.metaData = data.metaData;
            }
            if (data.inherited) {
                this.inherited = data.inherited;
            }
        }
        this.fieldConfig = fieldConfig;

        this.keysToWatch = [];

        if (this.inherited) {
            for (var i=0; i < this.frontendLanguages.length; i++) {
                var currentLanguage = this.frontendLanguages[i];

                var metadataForLanguage = this.metaData[currentLanguage];
                var dataKeys = Object.keys(metadataForLanguage);

                for (var k = 0; k < dataKeys.length; k++) {
                    var dataKey = dataKeys[k];
                    var metadataForKey = metadataForLanguage[dataKey];
                    if (metadataForKey.inherited) {
                        this.keysToWatch.push({
                            lang: currentLanguage,
                            key: dataKey
                        });
                    }
                }
            }
        }
    },

    getLayoutEdit: function (showMode) {

        this.fieldConfig.datatype ="layout";
        this.fieldConfig.fieldtype = "panel";

        var wrapperConfig = {
            border: false,
            layout: "fit"
        };

        if(this.fieldConfig.width) {
            wrapperConfig.width = this.fieldConfig.width;
        }

        if(this.fieldConfig.region) {
            wrapperConfig.region = this.fieldConfig.region;
        }

        if(this.fieldConfig.title) {
            wrapperConfig.title = this.fieldConfig.title;
        }

        var nrOfLanguages = this.frontendLanguages.length;

        if (this.dropdownLayout) {
            //TODO choose default language
            var data = [];
            for (var i = 0; i < nrOfLanguages; i++) {
                var language = this.frontendLanguages[i];
                data.push([language, pimcore.available_languages[language]]);
            }

            var store = new Ext.data.ArrayStore({
                    fields: ["key", "value"],
                    data: data
                }
            );

            var options = {
                triggerAction: "all",
                editable: true,
                selectOnFocus: true,
                queryMode: 'local',
                typeAhead: true,
                forceSelection: true,
                store: store,
                itemCls: "object_field",
                mode: "local",
                width: 300,
                padding: 10,
                displayField: "value",
                valueField: "key",
                value: this.frontendLanguages[0],
                listeners:  {
                    select:    function( combo, record, index ) {
                        var oldLanguage = this.currentLanguage;
                        var newLanguage = record.data.key;
                        if (oldLanguage == newLanguage) {
                            return;
                        }

                        this.availablePanels[oldLanguage].hide();
                        this.availablePanels[newLanguage].show();
                        this.currentLanguage = newLanguage;
                        this.component.doLayout();
                    }.bind(this)
                }
            };

            this.countrySelect = new Ext.form.ComboBox(options);

            wrapperConfig.items = []

            //TODO choose default language, maybe user-specific ?
            for (var i = nrOfLanguages - 1; i >= 0; i--) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  !showMode && (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                var items =  this.getRecursiveLayout(this.fieldConfig, !editable).items;

                panelConf = {
                    height: "auto",
                    layout: "pimcoreform",
                    border: true,
                    padding: "10px",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: items,
                    hidden: (i > 0)     //TODO default language
                };

                if(this.fieldConfig.height) {
                    panelConf.height = this.fieldConfig.height;
                    panelConf.autoHeight = false;
                    panelConf.autoScroll = true;
                } else {
                    panelConf.autoHeight = true;
                }

                this.tabPanel = new Ext.Panel(panelConf);

                this.availablePanels[this.currentLanguage] = this.tabPanel;
                wrapperConfig.items.push(this.tabPanel);

                wrapperConfig.tbar = [new Ext.Toolbar.TextItem({
                    text: t("language")
                }), this.countrySelect];
            }
        } else {
            var panelConf = {
                autoScroll: true,
                monitorResize: true,
                cls: "object_field",
                activeTab: 0,
                height: 10,
                items: [],
                deferredRender: true,
                forceLayout: true,
                hideMode: "offsets",
                enableTabScroll:true
            };

            if(this.fieldConfig.height) {
                panelConf.height = this.fieldConfig.height;
                panelConf.autoHeight = false;
            }

            // this is because the tabpanel has a strange behavior with automatic height, this corrects the problem
            panelConf.listeners = {
                afterrender: function () {
                    this.tabPanelAdjustIntervalCounter = 0;
                    this.tabPanelAdjustInterval = window.setInterval(function () {

                        this.tabPanelAdjustIntervalCounter++;
                        if(this.tabPanelAdjustIntervalCounter > 20) {
                            clearInterval(this.tabPanelAdjustInterval);
                        }

                        if(!this.fieldConfig.height && !this.fieldConfig.region) {
                            try {
                                var panelBodies = this.tabPanel.items.first().getEl().query(".x-panel-body");
                                var panelBody = Ext.get(panelBodies[0]);
                                panelBody.applyStyles("height: auto;");
                                var height = panelBody.getHeight();
                                // 100 is just a fixed value which seems to be ok(caused by title bar, tabs itself, ... )
                                this.component.setHeight(height+100);

                                //this.tabPanel.getEl().applyStyles("position:relative;");
                                this.component.doLayout();
                            } catch (e) {
                                console.log(e);
                            }
                        }
                    }.bind(this), 100);
                }.bind(this)
            };

            for (var i=0; i < nrOfLanguages; i++) {
                this.currentLanguage = this.frontendLanguages[i];
                this.languageElements[this.currentLanguage] = [];

                var editable =  (pimcore.currentuser.admin ||
                    this.fieldConfig.permissionEdit === undefined ||  this.fieldConfig.permissionEdit.length == 0 || in_array(this.currentLanguage, this.fieldConfig.permissionEdit));

                panelConf.items.push({
                    xtype: "panel",
                    layout: "pimcoreform",
                    border:false,
                    autoScroll: true,
                    padding: "10px",
                    deferredRender: false,
                    hideMode: "offsets",
                    title: pimcore.available_languages[this.frontendLanguages[i]],
                    items: this.getRecursiveLayout(this.fieldConfig, !editable).items
                });
            }

            this.tabPanel = new Ext.TabPanel(panelConf);

            wrapperConfig.items = [this.tabPanel];
        }

        this.component = new Ext.Panel(wrapperConfig);
        this.component.doLayout();
        return this.component;
    },

    getLayoutShow: function () {

        this.component = this.getLayoutEdit(true);
        return this.component;
    },

    getDataForField: function (name) {
        try {
            if (this.data[this.currentLanguage]) {
                if (this.data[this.currentLanguage][name]) {
                    return this.data[this.currentLanguage][name];
                } else if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return null;
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;
    },

    getMetaDataForField: function(name) {
        try {
            if (this.metaData[this.currentLanguage]) {
                if (this.metaData[this.currentLanguage][name]) {
                    return this.metaData[this.currentLanguage][name];
                } else if (typeof this.data[this.currentLanguage][name] !== undefined){
                    return null;
                }
            }
        } catch (e) {
            console.log(e);
        }
        return;

    },

    addToDataFields: function (field, name) {
        this.languageElements[this.currentLanguage].push(field);
    },

    addFieldsToMask: function (field) {
        this.object.edit.fieldsToMask.push(field);
    },

    addReferencedField: function (field) {
        this.referencedFields.push(field);
    },

    getValue: function () {

        var localizedData = {};
        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {
            currentLanguage = this.frontendLanguages[i];
            localizedData[currentLanguage] = {};

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    localizedData[currentLanguage][this.languageElements[currentLanguage][s].getName()]
                        = this.languageElements[currentLanguage][s].getValue();
                }
            }
        }

        // also add the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                localizedData = array_merge_recursive(localizedData, this.referencedFields[r].getValue());
            }
        }

        return localizedData;
    },

    getName: function () {
        return this.fieldConfig.name;
    },

    isDirty: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isDirty()) {
                    return true;
                }
            }
        }

        if(!this.isRendered()) {
            return false;
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isDirty()) {
                    return true;
                }
            }
        }

        return false;
    },

    isMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;

        for (var i=0; i < this.frontendLanguages; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    return true;
                }
            }
        }

        return false;
    },

    isInvalidMandatory: function () {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                if(this.referencedFields[r].isInvalidMandatory()) {
                    return true;
                }
            }
        }

        var currentLanguage;
        var isInvalid = false;
        var invalidMandatoryFields = [];

        for (var i=0; i < this.frontendLanguages.length; i++) {

            currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {
                if(this.languageElements[currentLanguage][s].isMandatory()) {
                    if(this.languageElements[currentLanguage][s].isInvalidMandatory()) {
                        invalidMandatoryFields.push(this.languageElements[currentLanguage][s].getTitle() + " - "
                            + currentLanguage.toUpperCase() + " ("
                            + this.languageElements[currentLanguage][s].getName() + ")");
                        isInvalid = true;
                    }
                }
            }
        }

        // return the error messages not bool, this is handled in object/edit.js
        if(isInvalid) {
            return invalidMandatoryFields;
        }

        return isInvalid;
    },

    dataIsNotInherited: function() {

        // also check the referenced localized fields
        if(this.referencedFields.length > 0) {
            for(var r=0; r<this.referencedFields.length; r++) {
                this.referencedFields[r].dataIsNotInherited();
            }
        }

        if (!this.inherited) {
            return true;
        }

        var foundUnmodifiedInheritedField = false;
        for (var i=0; i < this.frontendLanguages.length; i++) {

            var currentLanguage = this.frontendLanguages[i];

            for (var s=0; s<this.languageElements[currentLanguage].length; s++) {

                if (this.metaData[currentLanguage]) {
                    var languageElement = this.languageElements[currentLanguage][s];
                    var key = languageElement.name;
                    if (this.metaData[currentLanguage][key]) {
                        if (this.metaData[currentLanguage][key].inherited) {
                            if(languageElement.isDirty()) {
                                this.metaData[currentLanguage][key].inherited = false;
                                languageElement.unmarkInherited();
                            } else {
                                foundUnmodifiedInheritedField = true;
                            }
                        }
                    }
                }
            }
        }

        if (!foundUnmodifiedInheritedField) {
            this.inherited = false;
        }
        return !this.inherited;
    },

    markInherited:function (metaData) {
        // nothing to do, only sub-elements can be marked
    }

});

pimcore.object.tags.localizedfields.addMethods(pimcore.object.helpers.edit);<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import Relay from 'react-relay';
import { Link } from 'react-router';
import TeamRoute from '../../relay/TeamRoute';
import teamFragment from '../../relay/teamFragment';
import CheckContext from '../../CheckContext';
import ProjectList from '../project/ProjectList';

class TeamHeaderComponent extends Component {
  updateContext() {
    new CheckContext(this).setContextStore({ team: this.props.team });
  }

  componentWillMount() {
    this.updateContext();
  }

  componentWillUpdate() {
    this.updateContext();
  }

  render() {
    const team = this.props.team;

    return (

        <Link to="/" className="team-header__clickable" title={team.name}>
          <div className="team-header__avatar" style={{ backgroundImage: `url(${team.avatar})` }}>

        </Link>

            {team.name}

            <ProjectList team={team} />

    );
  }
}

TeamHeaderComponent.contextTypes = {
  store: React.PropTypes.object,
};

const TeamHeaderContainer = Relay.createContainer(TeamHeaderComponent, {
  fragments: {
    team: () => teamFragment,
  },
});

class TeamHeader extends Component {
  render() {
    const route = new TeamRoute({ teamId: '' });
    return (
      <Relay.RootContainer
        Component={TeamHeaderContainer}
        route={route}
        renderLoading={function() {
          return (

              <Link to="/" className="team-header__clickable" title='Back to team'>

              </Link>

          );
        }}
      />
    );
  }
}

export default TeamHeader;
<commit_msg>Ticket #5616: Auto-refresh team projects when project is created<commit_after>import React, { Component, PropTypes } from 'react';
import Relay from 'react-relay';
import { Link } from 'react-router';
import Pusher from 'pusher-js';
import TeamRoute from '../../relay/TeamRoute';
import teamFragment from '../../relay/teamFragment';
import CheckContext from '../../CheckContext';
import ProjectList from '../project/ProjectList';

class TeamHeaderComponent extends Component {
  getPusher() {
    const context = new CheckContext(this);
    return context.getContextStore().pusher;
  }

  updateContext() {
    new CheckContext(this).setContextStore({ team: this.props.team });
  }

  componentWillMount() {
    this.updateContext();
  }

  componentWillUpdate() {
    this.updateContext();
  }

  subscribe() {
    const pusher = this.getPusher();
    if (pusher) {
      const that = this;
      pusher.subscribe(this.props.team.pusher_channel).bind('project_created', (data) => {
        that.props.relay.forceFetch();
      });
    }
  }

  componentDidMount() {
    this.subscribe();
  }

  unsubscribe() {
    const pusher = this.getPusher();
    if (pusher) {
      pusher.unsubscribe(this.props.team.pusher_channel);
    }
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  render() {
    const team = this.props.team;

    return (

        <Link to="/" className="team-header__clickable" title={team.name}>
          <div className="team-header__avatar" style={{ backgroundImage: `url(${team.avatar})` }}>

        </Link>

            {team.name}

            <ProjectList team={team} />

    );
  }
}

TeamHeaderComponent.contextTypes = {
  store: React.PropTypes.object,
};

const TeamHeaderContainer = Relay.createContainer(TeamHeaderComponent, {
  fragments: {
    team: () => teamFragment,
  },
});

class TeamHeader extends Component {
  render() {
    const route = new TeamRoute({ teamId: '' });
    return (
      <Relay.RootContainer
        Component={TeamHeaderContainer}
        route={route}
        renderLoading={function() {
          return (

              <Link to="/" className="team-header__clickable" title='Back to team'>

              </Link>

          );
        }}
      />
    );
  }
}

export default TeamHeader;
<|endoftext|>