From e198190c8c77bfb56b4ed357a431928ddd076525 Mon Sep 17 00:00:00 2001 From: Aleksandr Smaga Date: Tue, 28 May 2013 13:39:02 +0200 Subject: [PATCH 001/394] BAP-875 Improve templates on view pages --- .../Resources/config/services.yml | 9 +- .../views/Include/viewMacro.html.twig | 56 +++++++++ .../Unit/Twig/HasAddressExtensionTest.php | 112 ++++++++++++++++++ .../Twig/HasAddressExtension.php | 55 +++++++++ 4 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig create mode 100644 src/Oro/Bundle/AddressBundle/Tests/Unit/Twig/HasAddressExtensionTest.php create mode 100644 src/Oro/Bundle/AddressBundle/Twig/HasAddressExtension.php diff --git a/src/Oro/Bundle/AddressBundle/Resources/config/services.yml b/src/Oro/Bundle/AddressBundle/Resources/config/services.yml index 80f45580b43..ee8b638b9b3 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/AddressBundle/Resources/config/services.yml @@ -31,6 +31,8 @@ parameters: oro_address.attribute.address.class: Oro\Bundle\AddressBundle\AttributeType\AddressType + oro_address.twig.hasAddress.extension.class: Oro\Bundle\AddressBundle\Twig\HasAddressExtension + services: oro_address.address.provider: class: %oro_address.provider.address.class% @@ -182,4 +184,9 @@ services: - "address" - "oro_address" tags: - - { name: oro_flexibleentity.attributetype, alias: oro_address } \ No newline at end of file + - { name: oro_flexibleentity.attributetype, alias: oro_address } + + oro_address.twig.hasAddress.extension: + class: %oro_address.twig.hasAddress.extension.class% + tags: + - { name: twig.extension } diff --git a/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig new file mode 100644 index 00000000000..063778c0cf4 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig @@ -0,0 +1,56 @@ +{% macro renderAddress(address) %} + {% import _self as __ %} + + {% set fields = [ + {label: "First name", data: "firstName"}, + {label: "Last name", data: "lastName"}, + {label: "Street", data: "street"}, + {label: "Street 2", data: "street2"}, + {label: "City", data: "city"}, + {label: "State", data: "state"}, + {label: "Country", data: "country"}, + {label: "Zip/postal code", data: "postalCode"} + ] %} + + {{ __.renderAddressView(address, fields) }} +{% endmacro %} + +{% macro renderAddressView(address, fields, renderFlexibleAttributes) %} + {# Render flexible attributes by default #} + {% set renderFlexibleAttributes = renderFlexibleAttributes|default(true) %} + + {# Render static attributes #} + {% for field in fields %} + {{ block('addressStaticAttribute') }} + {% endfor %} + + {# Render flexible attributes #} + {% if (address.values is defined and renderFlexibleAttributes) %} + {% for attribute in address.values %} + {{ block('addressFlexibleAttribute') }} + {% endfor %} + {% endif %} +{% endmacro %} + +{% block addressStaticAttribute %} + {% set defaultValue = field.defaultValue|default('N/A') %} +
+ +
+
+

{{ attribute(address, field.data)|default(defaultValue) }}

+
+
+
+{% endblock addressStaticAttribute %} + +{% block addressFlexibleAttribute %} +
+ +
+
+

{{ attr.__toString|default('N/A') }}

+
+
+
+{% endblock addressFlexibleAttribute %} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Twig/HasAddressExtensionTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Twig/HasAddressExtensionTest.php new file mode 100644 index 00000000000..2f441928338 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Twig/HasAddressExtensionTest.php @@ -0,0 +1,112 @@ +extension = new HasAddressExtension(); + $this->entityMock = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexible'); + $this->valuesMock = $this->getMock('Doctrine\Common\Collections\ArrayCollection'); + $this->valueMock = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface'); + } + + public function testGetName() + { + $this->assertEquals('oro_address_hasAddress', $this->extension->getName()); + } + + public function testGetFilters() + { + $filters = $this->extension->getFilters(); + + $this->assertArrayHasKey('hasAddress', $filters); + $this->assertInstanceOf('\Twig_Filter_Method', $filters['hasAddress']); + } + + public function testHasAddressTrueScenario() + { + $this->valueMock->expects($this->once()) + ->method('getData') + ->will($this->returnValue(true)); + + $this->entityMock->expects($this->once()) + ->method('getValue') + ->with($this->equalTo('address')) + ->will($this->returnValue($this->valueMock)); + + $this->assertTrue($this->extension->hasAddress($this->entityMock, 'address')); + } + + public function testHasAddressFalseScenario() + { + $this->valueMock->expects($this->once()) + ->method('getData') + ->will($this->returnValue(null)); + + $this->entityMock->expects($this->once()) + ->method('getValue') + ->with($this->equalTo('address')) + ->will($this->returnValue($this->valueMock)); + + $this->assertFalse($this->extension->hasAddress($this->entityMock, 'address')); + } + + public function testHasAddressTrueScenarioWithoutCode() + { + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('filter') + ->will($this->returnValue($this->valuesMock)); + $this->valuesMock->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(false)); + + $this->assertTrue($this->extension->hasAddress($this->entityMock)); + } + + public function testHasAddressFalseScenarioWithoutCode() + { + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('filter') + ->will($this->returnValue($this->valuesMock)); + $this->valuesMock->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(true)); + + $this->assertFalse($this->extension->hasAddress($this->entityMock)); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Twig/HasAddressExtension.php b/src/Oro/Bundle/AddressBundle/Twig/HasAddressExtension.php new file mode 100644 index 00000000000..bdb44400038 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Twig/HasAddressExtension.php @@ -0,0 +1,55 @@ + new \Twig_Filter_Method($this, 'hasAddress') + ); + } + + /** + * Check whenever flexible entity contains not empty address attribute + * + * @param \Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexible $entity + * @param null $addressCode + * @return bool + */ + public function hasAddress(AbstractEntityFlexible $entity, $addressCode = null) + { + if ($addressCode !== null) { + $address = $entity->getValue($addressCode); + + return $address->getData() != null; + } + + /** @var \Doctrine\Common\Collections\ArrayCollection $values **/ + $values = $entity->getValues(); + $values = $values->filter( + function ($value) { + if (strpos($value->getAttribute()->getCode(), 'address') !== false) { + return $value->getData() != null; + } + + return false; + } + ); + return !$values->isEmpty(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_address_hasAddress'; + } +} From 804742b3a126fbe2519a999c219bd0fb1de52579 Mon Sep 17 00:00:00 2001 From: Aleksandr Smaga Date: Tue, 28 May 2013 16:24:38 +0200 Subject: [PATCH 002/394] BAP-875 Improve templates on view pages FilterAttributes twig extension Added twig extension to servives --- .../Resources/config/services.yml | 6 ++ .../Twig/FilterAttributesExtensionTest.php | 99 +++++++++++++++++++ .../Twig/FilterAttributesExtension.php | 68 +++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Twig/FilterAttributesExtensionTest.php create mode 100644 src/Oro/Bundle/FlexibleEntityBundle/Twig/FilterAttributesExtension.php diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml b/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml index 18b8a58ac24..09597039d24 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml @@ -3,6 +3,7 @@ parameters: oro_flexibleentity.registry.class: Oro\Bundle\FlexibleEntityBundle\Manager\FlexibleManagerRegistry oro_flexibleentity.attributetype.factory.class: Oro\Bundle\FlexibleEntityBundle\AttributeType\AttributeTypeFactory oro_flexibleentity.value_form.value_subscriber.class: Oro\Bundle\FlexibleEntityBundle\Form\EventListener\FlexibleValueSubscriber + oro_flexibleentity.filterAttributes.twig.extension.class: Oro\Bundle\FlexibleEntityBundle\Twig\FilterAttributesExtension services: oro_flexibleentity.value_form.value_subscriber: @@ -89,3 +90,8 @@ services: class: Oro\Bundle\FlexibleEntityBundle\Form\Type\EmailCollectionType tags: - { name: form.type, alias: oro_flexibleentity_email_collection } + + oro_flexibleentity.filterAttributes.twig.extension: + class: %oro_flexibleentity.filterAttributes.twig.extension.class% + tags: + - { name: twig.extension } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Twig/FilterAttributesExtensionTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Twig/FilterAttributesExtensionTest.php new file mode 100644 index 00000000000..6c1006ad1a2 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Twig/FilterAttributesExtensionTest.php @@ -0,0 +1,99 @@ +extension = new FilterAttributesExtension(); + $this->entityMock = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexible'); + $this->valuesMock = $this->getMock('Doctrine\Common\Collections\ArrayCollection'); + } + + public function testGetName() + { + $this->assertEquals('oro_flexibleentity_getAttributes', $this->extension->getName()); + } + + public function testGetFilters() + { + $filters = $this->extension->getFilters(); + + $this->assertArrayHasKey('getAttributes', $filters); + $this->assertInstanceOf('\Twig_Filter_Method', $filters['getAttributes']); + } + + public function testGetAttributesEmptyValuesScenario() + { + $this->entityMock->expects($this->exactly(2)) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->exactly(2)) + ->method('isEmpty') + ->will($this->returnValue(true)); + + $result = $this->extension->getAttributes($this->entityMock, 'test attribute'); + $this->assertInstanceOf('\PHPUnit_Framework_MockObject_MockObject', $result); + + $result = $this->extension->getAttributes($this->entityMock, array('test'), true); + $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $result); + } + + public function testGetAttributesValuesScenario() + { + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('filter') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(false)); + + $result = $this->extension->getAttributes($this->entityMock, 'test attribute', true); + $this->assertInstanceOf('\PHPUnit_Framework_MockObject_MockObject', $result); + $this->assertEquals($this->valuesMock, $result); + } + + public function testGetAttributesEmptyAttributesScenario() + { + $this->entityMock->expects($this->exactly(2)) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->exactly(2)) + ->method('isEmpty') + ->will($this->returnValue(true)); + + $result = $this->extension->getAttributes($this->entityMock); + $this->assertInstanceOf('\PHPUnit_Framework_MockObject_MockObject', $result); + + $result = $this->extension->getAttributes($this->entityMock, array(), true); + $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $result); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Twig/FilterAttributesExtension.php b/src/Oro/Bundle/FlexibleEntityBundle/Twig/FilterAttributesExtension.php new file mode 100644 index 00000000000..7975c44f486 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Twig/FilterAttributesExtension.php @@ -0,0 +1,68 @@ + new \Twig_Filter_Method($this, 'getAttributes') + ); + } + + /** + * Returns attribute values array and filter if attributes array filled + * |getAttributes() - will return all attributes + * |getAttributes('address') - will return attribute with code "address" + * |getAttributes(['firstName', 'lastName']) - will filter by few attribute codes + * + * If third parameter equals true method will return attributes that not in given array(or string) + * + * @param AbstractEntityFlexible $entity + * @param string|array $attributes attribute names + * @param bool $skip + * @return ArrayCollection + */ + public function getAttributes(AbstractEntityFlexible $entity, $attributes = array(), $skip = false) + { + if (!empty($attributes) && !is_array($attributes)) { + $attributes = array($attributes); + } + + /** @var ArrayCollection $values */ + $values = $entity->getValues(); + + if ($values->isEmpty() || empty($attributes)) { + $values = $skip ? new ArrayCollection() : $values; + return $values; + } + + $values = $values->filter( + function ($value) use ($attributes, $skip) { + if (in_array($value->getAttribute()->getCode(), $attributes)) { + return !$skip; + } + + return $skip; + } + ); + + return $values; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_flexibleentity_getAttributes'; + } +} From c8caf184ebb45b82b22b954046e91529fca9d765 Mon Sep 17 00:00:00 2001 From: Aleksandr Smaga Date: Tue, 28 May 2013 16:34:58 +0200 Subject: [PATCH 003/394] BAP-875 Improve templates on view pages --- .../Bundle/UserBundle/Resources/views/User/view.html.twig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig b/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig index 61a9950e314..69c6d060cb4 100644 --- a/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig +++ b/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig @@ -148,12 +148,12 @@

{{ 'Additional data'|trans }}

- {% for attr in user.values %} + {% for value in user|getAttributes() %}
- +
-

{{ attr.__toString }}

+

{{ value.__toString }}

From 0452ca4b4242b5c81343a4a510cc377b86068cc1 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 28 May 2013 18:48:56 +0300 Subject: [PATCH 004/394] BAP-854: DataAudit logger doesn't work with flexible collections --- .../Bundle/DataAuditBundle/EventListener/LoggableListener.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php b/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php index 17397b2c6bf..236ed609f84 100644 --- a/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php +++ b/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php @@ -207,7 +207,9 @@ function ($item) { $newData = implode( ', ', $newData->map(function ($item) { - return $item->getOptionValue()->getValue(); + return $item instanceof AbstractEntityAttributeOption + ? $item->getOptionValue()->getValue() + : (string) $item; })->toArray() ); } From caeebe521fda231aba79bb16aedff71663d35f94 Mon Sep 17 00:00:00 2001 From: Aleksandr Smaga Date: Wed, 29 May 2013 12:46:32 +0200 Subject: [PATCH 005/394] BAP-563 Create addresses collection flexible attribute type --- .../AttributeType/AddressCollectionType.php | 25 +++++++++++ .../Form/Type/AddressBookType.php | 8 ++++ .../Form/Type/AdressCollectionType.php | 42 +++++++++++++++++++ .../Resources/config/services.yml | 18 +++++++- 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 src/Oro/Bundle/AddressBundle/AttributeType/AddressCollectionType.php create mode 100644 src/Oro/Bundle/AddressBundle/Form/Type/AddressBookType.php create mode 100644 src/Oro/Bundle/AddressBundle/Form/Type/AdressCollectionType.php diff --git a/src/Oro/Bundle/AddressBundle/AttributeType/AddressCollectionType.php b/src/Oro/Bundle/AddressBundle/AttributeType/AddressCollectionType.php new file mode 100644 index 00000000000..c69c5f9e7da --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/AttributeType/AddressCollectionType.php @@ -0,0 +1,25 @@ +add( + 'collection', + 'collection', + array( + 'type' => new AddressBookType(), + + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + 'prototype' => true, + 'prototype_name' => '__name__', + 'label' => ' ' + ) + ); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_address_collection'; + } +} diff --git a/src/Oro/Bundle/AddressBundle/Resources/config/services.yml b/src/Oro/Bundle/AddressBundle/Resources/config/services.yml index 80f45580b43..e30f64285f9 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/AddressBundle/Resources/config/services.yml @@ -30,6 +30,7 @@ parameters: oro_address.form.listener.address.class: Oro\Bundle\AddressBundle\Form\EventListener\BuildAddressFormListener oro_address.attribute.address.class: Oro\Bundle\AddressBundle\AttributeType\AddressType + oro_address.attribute.address_collection.class: Oro\Bundle\AddressBundle\AttributeType\AddressCollectionType services: oro_address.address.provider: @@ -182,4 +183,19 @@ services: - "address" - "oro_address" tags: - - { name: oro_flexibleentity.attributetype, alias: oro_address } \ No newline at end of file + - { name: oro_flexibleentity.attributetype, alias: oro_address } + + + # Flexible attribute + oro_address.attribute_type.address_collection: + class: %oro_address.attribute.address_collection.class% + arguments: + - "address" + - "oro_address" + tags: + - { name: oro_flexibleentity.attributetype, alias: oro_address_collection } + + oro_address.twig.hasAddress.extension: + class: %oro_address.twig.hasAddress.extension.class% + tags: + - { name: twig.extension } From 408e852537b774d4aa1222a6a2c615f588d270dd Mon Sep 17 00:00:00 2001 From: Alexander Nezdoiminoga Date: Wed, 29 May 2013 14:11:22 +0300 Subject: [PATCH 006/394] BAP-820 remove pagestate response listener --- .../Event/ResponsePagestateListener.php | 72 ------------------- .../Resources/config/services.yml | 7 -- .../views/Pagestate/redirect.html.twig | 4 -- 3 files changed, 83 deletions(-) delete mode 100644 src/Oro/Bundle/NavigationBundle/Event/ResponsePagestateListener.php delete mode 100644 src/Oro/Bundle/NavigationBundle/Resources/views/Pagestate/redirect.html.twig diff --git a/src/Oro/Bundle/NavigationBundle/Event/ResponsePagestateListener.php b/src/Oro/Bundle/NavigationBundle/Event/ResponsePagestateListener.php deleted file mode 100644 index e545334c1e3..00000000000 --- a/src/Oro/Bundle/NavigationBundle/Event/ResponsePagestateListener.php +++ /dev/null @@ -1,72 +0,0 @@ -router = $router; - $this->security = $security; - $this->templating = $templating; - } - - /** - * Process onResponse event - * - * @param FilterResponseEvent $event - * @return bool|void - */ - public function onResponse(FilterResponseEvent $event) - { - $request = $event->getRequest(); - $response = $event->getResponse(); - - $isTest = $request->server->get('HTTP_USER_AGENT') == 'Symfony2 BrowserKit' && $request->server->get('HTTP_HOST') == 'localhost'; - if (!is_object($this->security->getToken()) - && HttpKernel::MASTER_REQUEST == $event->getRequestType() - && $request->getMethod() == 'PUT' - && $request->getRequestFormat() == 'json' - && $response->getStatusCode() == 401 - && !$isTest - ) { - return $event->setResponse( - $this->templating->renderResponse( - 'OroNavigationBundle:Pagestate:redirect.html.twig', - array( - 'location' => $this->router->generate('oro_user_security_login'), - ) - ) - ); - } - - return; - } -} diff --git a/src/Oro/Bundle/NavigationBundle/Resources/config/services.yml b/src/Oro/Bundle/NavigationBundle/Resources/config/services.yml index 5046882f8fd..813e8bea7ef 100644 --- a/src/Oro/Bundle/NavigationBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/NavigationBundle/Resources/config/services.yml @@ -16,7 +16,6 @@ parameters: oro_navigation.event.response_history.listener.class: Oro\Bundle\NavigationBundle\Event\ResponseHistoryListener oro_navigation.event.response_hashnav.listener.class: Oro\Bundle\NavigationBundle\Event\ResponseHashnavListener - oro_navigation.event.response_pagestate.listener.class: Oro\Bundle\NavigationBundle\Event\ResponsePagestateListener oro_navigation.menu.matcher.voter.request: Oro\Bundle\NavigationBundle\Menu\Matcher\Voter\RequestVoter oro_navigation.menu.matcher.voter.routepattern: Oro\Bundle\NavigationBundle\Menu\Matcher\Voter\RoutePatternVoter @@ -239,12 +238,6 @@ services: - { name: kernel.event_listener, event: kernel.response, method: onResponse } arguments: [@security.context, @templating] - kernel.listener.pagestate_response: - class: %oro_navigation.event.response_pagestate.listener.class% - tags: - - { name: kernel.event_listener, event: kernel.response, method: onResponse } - arguments: [@router, @templating, @security.context] - oro_navigation.twig.hash_nav_extension: class: %oro_navigation.twig_hash_nav_extension.class% tags: diff --git a/src/Oro/Bundle/NavigationBundle/Resources/views/Pagestate/redirect.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/Pagestate/redirect.html.twig deleted file mode 100644 index 5720f053706..00000000000 --- a/src/Oro/Bundle/NavigationBundle/Resources/views/Pagestate/redirect.html.twig +++ /dev/null @@ -1,4 +0,0 @@ -

{{ 'Session expired. Redirect to Login page'|trans }}

- From ba310d647eab5e2683500f7469832ed6cc3c9fc2 Mon Sep 17 00:00:00 2001 From: Alexander Nezdoiminoga Date: Wed, 29 May 2013 14:33:46 +0300 Subject: [PATCH 007/394] BAP-820 Backbone.sync error dispatcher --- .../Resources/public/js/backbone/error.js | 68 +++++++++++++------ .../Resources/public/js/backbone/setup.js | 2 +- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js b/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js index 857cfd05c48..517954cf8cd 100644 --- a/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js +++ b/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js @@ -16,24 +16,52 @@ Oro.BackboneError.Header = "Server error"; Oro.BackboneError.Message = "Error! Incorrect server response."; $(function() { - /** - * Backbone error modal - * - * @param {Object} model - * @param {Object} xhr - * @param {Object} options - * @constructor - */ - Oro.BackboneError.Modal = function(model, xhr, options) { - var message = Oro.BackboneError.Message; - if (Oro.debug) { - message += '
Debug:' + xhr.responseText; - } - - var modal = new Oro.BootstrapModal({ - title: Oro.BackboneError.Header, - content: message - }); - modal.open(); + Oro.BackboneError.Dispatch = function (model, xhr, options) { + var self = Oro.BackboneError.Dispatch; + self.init(model, xhr, options); }; -}); + + _.extend(Oro.BackboneError.Dispatch, { + /** + * Backbone error dispatch + * + * @param {Object} model + * @param {Object} xhr + * @param {Object} options + */ + init: function(model, xhr, options) { + if (xhr.status == 401) { + this._processRedirect(); + } else { + this._processModal(xhr); + } + }, + + /** + * Backbone error - modal window + * @param {Object} xhr + * @private + */ + _processModal: function(xhr) { + var message = Oro.BackboneError.Message; + if (Oro.debug) { + message += '
Debug:' + xhr.responseText; + } + + var modal = new Oro.BootstrapModal({ + title: Oro.BackboneError.Header, + content: message + }); + modal.open(); + }, + + /** + * Backbone error - redirect to login + * @private + */ + _processRedirect: function() { + document.location.href = Routing.generate('oro_user_security_login'); + return; + } + }); +}); \ No newline at end of file diff --git a/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/setup.js b/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/setup.js index 6644b303dff..7ec0736595a 100644 --- a/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/setup.js +++ b/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/setup.js @@ -13,7 +13,7 @@ $(function() { Backbone.basicSync = Backbone.sync; Backbone.sync = function(method, model, options) { if (!options || !_.has(options, 'error')) { - options['error'] = Oro.BackboneError.Modal; + options['error'] = Oro.BackboneError.Dispatch; } Backbone.basicSync(method, model, options); From a15fd095c4ca42edf30513ddacf4a28975f716a4 Mon Sep 17 00:00:00 2001 From: Alexander Nezdoiminoga Date: Wed, 29 May 2013 14:36:23 +0300 Subject: [PATCH 008/394] fix --- src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js b/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js index 517954cf8cd..d03e31853d9 100644 --- a/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js +++ b/src/Oro/Bundle/UIBundle/Resources/public/js/backbone/error.js @@ -64,4 +64,4 @@ $(function() { return; } }); -}); \ No newline at end of file +}); From e3680d17ea3a19dd5190c1d1ee585c49e2cc2472 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 29 May 2013 16:18:08 +0300 Subject: [PATCH 009/394] BAP-884: Serialize error during contact save --- .../AddressBundle/Entity/AddressBase.php | 22 ++++++------ .../Bundle/AddressBundle/Entity/Country.php | 36 ++++++++++--------- .../EventListener/LoggableListener.php | 4 +-- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php b/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php index d4ea7250643..ef21956d163 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php +++ b/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php @@ -103,7 +103,7 @@ class AddressBase extends AbstractEntityFlexible /** * Get id * - * @return integer + * @return integer */ public function getId() { @@ -119,14 +119,14 @@ public function getId() public function setStreet($street) { $this->street = $street; - + return $this; } /** * Get street * - * @return string + * @return string */ public function getStreet() { @@ -142,14 +142,14 @@ public function getStreet() public function setStreet2($street2) { $this->street2 = $street2; - + return $this; } /** * Get street2 * - * @return string + * @return string */ public function getStreet2() { @@ -165,14 +165,14 @@ public function getStreet2() public function setCity($city) { $this->city = $city; - + return $this; } /** * Get city * - * @return string + * @return string */ public function getCity() { @@ -188,7 +188,7 @@ public function getCity() public function setState($state) { $this->state = $state; - + return $this; } @@ -238,14 +238,14 @@ public function getStateText() public function setPostalCode($postalCode) { $this->postalCode = $postalCode; - + return $this; } /** * Get postal_code * - * @return string + * @return string */ public function getPostalCode() { @@ -261,7 +261,7 @@ public function getPostalCode() public function setCountry($country) { $this->country = $country; - + return $this; } diff --git a/src/Oro/Bundle/AddressBundle/Entity/Country.php b/src/Oro/Bundle/AddressBundle/Entity/Country.php index d8792afcd76..cfaffc77a65 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Country.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Country.php @@ -3,8 +3,10 @@ namespace Oro\Bundle\AddressBundle\Entity; use JMS\Serializer\Annotation\Exclude; + use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; + use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap; /** @@ -22,7 +24,7 @@ class Country * @ORM\Column(name="iso2_code", type="string", length=2) * @Soap\ComplexType("string", nillable=true) */ - private $iso2Code; + protected $iso2Code; /** * @var string @@ -30,7 +32,7 @@ class Country * @ORM\Column(name="iso3_code", type="string", length=3) * @Soap\ComplexType("string", nillable=true) */ - private $iso3Code; + protected $iso3Code; /** * @var string @@ -38,7 +40,7 @@ class Country * @ORM\Column(name="name", type="string", length=100) * @Soap\ComplexType("string", nillable=true) */ - private $name; + protected $name; /** * @var ArrayCollection @@ -46,18 +48,20 @@ class Country * @ORM\OneToMany(targetEntity="Region", mappedBy="country", cascade={"ALL"}, fetch="EXTRA_LAZY") * @Exclude */ - private $regions; + protected $regions; /** - * @param null|string $name - * @param null|string $iso2Code - * @param null|string $iso3Code + * @param null|string $name [optional] Country name + * @param null|string $iso2Code [optional] ISO2 country code + * @param null|string $iso3Code [optional] ISO3 country code */ public function __construct($name = null, $iso2Code = null, $iso3Code = null) { - $this->setName($name); - $this->setIso2Code($iso2Code); - $this->setIso3Code($iso3Code); + $this + ->setName($name) + ->setIso2Code($iso2Code) + ->setIso3Code($iso3Code) + ->setRegions(new ArrayCollection()); } /** @@ -99,14 +103,14 @@ public function hasRegions() public function setIso2Code($iso2Code) { $this->iso2Code = $iso2Code; - + return $this; } /** * Get iso2_code * - * @return string + * @return string */ public function getIso2Code() { @@ -122,14 +126,14 @@ public function getIso2Code() public function setIso3Code($iso3Code) { $this->iso3Code = $iso3Code; - + return $this; } /** * Get iso3_code * - * @return string + * @return string */ public function getIso3Code() { @@ -145,14 +149,14 @@ public function getIso3Code() public function setName($name) { $this->name = $name; - + return $this; } /** * Get country name * - * @return string + * @return string */ public function getName() { diff --git a/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php b/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php index 236ed609f84..aa273cf2af6 100644 --- a/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php +++ b/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php @@ -224,8 +224,8 @@ function ($item) { (array) $logEntry->getData(), array( $object->getAttribute()->getCode() => array( - 'old' => $oldData, - 'new' => $newData, + 'old' => is_object($oldData) && method_exists($oldData, '__toString') ? (string) $oldData : $oldData, + 'new' => is_object($newData) && method_exists($newData, '__toString') ? (string) $newData : $newData, ) ) ); From f653620972c68eb1654361c5d3ae9605d042d069 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 29 May 2013 16:19:35 +0300 Subject: [PATCH 010/394] CS fix --- .../AddressBundle/Entity/AddressBase.php | 15 ++++++------- .../AddressBundle/Entity/AddressType.php | 2 +- .../Bundle/AddressBundle/Entity/Country.php | 6 +++--- .../Entity/Manager/AddressManager.php | 21 ++++++++++--------- .../Entity/Manager/AddressTypeManager.php | 6 +++--- .../Entity/Manager/StorageInterface.php | 6 +++--- .../Bundle/AddressBundle/Entity/Region.php | 18 ++++++++-------- 7 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php b/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php index ef21956d163..23345e2714e 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php +++ b/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php @@ -113,7 +113,7 @@ public function getId() /** * Set street * - * @param string $street + * @param string $street * @return AddressBase */ public function setStreet($street) @@ -136,7 +136,7 @@ public function getStreet() /** * Set street2 * - * @param string $street2 + * @param string $street2 * @return AddressBase */ public function setStreet2($street2) @@ -159,7 +159,7 @@ public function getStreet2() /** * Set city * - * @param string $city + * @param string $city * @return AddressBase */ public function setCity($city) @@ -182,7 +182,7 @@ public function getCity() /** * Set state * - * @param Region $state + * @param Region $state * @return AddressBase */ public function setState($state) @@ -209,7 +209,7 @@ public function getState() /** * Set state text * - * @param Region $stateText + * @param Region $stateText * @return AddressBase */ public function setStateText($stateText) @@ -232,7 +232,7 @@ public function getStateText() /** * Set postal_code * - * @param string $postalCode + * @param string $postalCode * @return AddressBase */ public function setPostalCode($postalCode) @@ -255,7 +255,7 @@ public function getPostalCode() /** * Set country * - * @param Country $country + * @param Country $country * @return AddressBase */ public function setCountry($country) @@ -385,6 +385,7 @@ public function __toString() $this->getCountry(), $this->getPostalCode(), ); + return implode(' ', $data); } } diff --git a/src/Oro/Bundle/AddressBundle/Entity/AddressType.php b/src/Oro/Bundle/AddressBundle/Entity/AddressType.php index c69b60616bb..5851efd46fa 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/AddressType.php +++ b/src/Oro/Bundle/AddressBundle/Entity/AddressType.php @@ -41,7 +41,7 @@ public function getId() /** * Set route * - * @param string $type + * @param string $type * @return AddressType */ public function setType($type) diff --git a/src/Oro/Bundle/AddressBundle/Entity/Country.php b/src/Oro/Bundle/AddressBundle/Entity/Country.php index cfaffc77a65..a1e28e9242a 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Country.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Country.php @@ -97,7 +97,7 @@ public function hasRegions() /** * Set iso2_code * - * @param string $iso2Code + * @param string $iso2Code * @return Country */ public function setIso2Code($iso2Code) @@ -120,7 +120,7 @@ public function getIso2Code() /** * Set iso3_code * - * @param string $iso3Code + * @param string $iso3Code * @return Country */ public function setIso3Code($iso3Code) @@ -143,7 +143,7 @@ public function getIso3Code() /** * Set country name * - * @param string $name + * @param string $name * @return Country */ public function setName($name) diff --git a/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressManager.php b/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressManager.php index 80694ec9c34..e5bf60ac540 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressManager.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressManager.php @@ -36,9 +36,9 @@ class AddressManager implements StorageInterface /** * Constructor * - * @param string $class Entity name - * @param ObjectManager $om Object manager - * @param FlexibleManager $fm Proxy for methods of flexible manager + * @param string $class Entity name + * @param ObjectManager $om Object manager + * @param FlexibleManager $fm Proxy for methods of flexible manager */ public function __construct($class, ObjectManager $om, $fm) { @@ -64,8 +64,8 @@ public function createAddress() /** * Updates an address * - * @param AddressBase $address - * @param bool $flush Whether to flush the changes (default true) + * @param AddressBase $address + * @param bool $flush Whether to flush the changes (default true) * @throws \RuntimeException */ public function updateAddress(AddressBase $address, $flush = true) @@ -90,7 +90,7 @@ public function deleteAddress(AddressBase $address) /** * Finds one address by the given criteria * - * @param array $criteria + * @param array $criteria * @return AddressBase */ public function findAddressBy(array $criteria) @@ -141,22 +141,23 @@ public function getStorageManager() /** * Returns basic query instance to get collection with all user instances * - * @param int $limit - * @param int $offset + * @param int $limit + * @param int $offset * @return Paginator */ public function getListQuery($limit = 10, $offset = 1) { /** @var FlexibleEntityRepository $repository */ $repository = $this->fm->getFlexibleRepository(); + return $repository->findByWithAttributesQB(array(), null, array('id' => 'ASC'), $limit, $offset); } /** * Provide proxy method calls to flexible manager * - * @param string $name - * @param array $args + * @param string $name + * @param array $args * @return mixed * @throws \RuntimeException */ diff --git a/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php b/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php index 33098eaaa5d..8b38822f95d 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php @@ -25,8 +25,8 @@ class AddressTypeManager /** * Constructor * - * @param string $class Entity name - * @param ObjectManager $om Object manager + * @param string $class Entity name + * @param ObjectManager $om Object manager */ public function __construct($class, ObjectManager $om) { @@ -76,7 +76,7 @@ public function deleteAddressType(AddressType $addressType) /** * Finds one address type by the given criteria * - * @param array $criteria + * @param array $criteria * @return AddressType */ public function findAddressTypeBy(array $criteria) diff --git a/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php b/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php index 2b99a5f0efd..c0b8759ee3b 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php @@ -16,8 +16,8 @@ public function createAddress(); /** * Updates an address * - * @param AddressBase $address - * @param bool $flush Whether to flush the changes (default true) + * @param AddressBase $address + * @param bool $flush Whether to flush the changes (default true) * @throws \RuntimeException */ public function updateAddress(AddressBase $address, $flush = true); @@ -32,7 +32,7 @@ public function deleteAddress(AddressBase $address); /** * Finds one address by the given criteria * - * @param array $criteria + * @param array $criteria * @return AddressBase */ public function findAddressBy(array $criteria); diff --git a/src/Oro/Bundle/AddressBundle/Entity/Region.php b/src/Oro/Bundle/AddressBundle/Entity/Region.php index 8252dee18ff..6984c044544 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Region.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Region.php @@ -62,7 +62,7 @@ class Region /** * Get id * - * @return integer + * @return integer */ public function getId() { @@ -72,13 +72,13 @@ public function getId() /** * Set country * - * @param Country $country + * @param Country $country * @return Region */ public function setCountry($country) { $this->country = $country; - + return $this; } @@ -95,20 +95,20 @@ public function getCountry() /** * Set code * - * @param string $code + * @param string $code * @return Region */ public function setCode($code) { $this->code = $code; - + return $this; } /** * Get code * - * @return string + * @return string */ public function getCode() { @@ -118,20 +118,20 @@ public function getCode() /** * Set name * - * @param string $name + * @param string $name * @return Region */ public function setName($name) { $this->name = $name; - + return $this; } /** * Get name * - * @return string + * @return string */ public function getName() { From 88317cf5cefe82ad122808fab613896edae1dee7 Mon Sep 17 00:00:00 2001 From: Ignat Shcheglovskyi Date: Wed, 29 May 2013 16:19:54 +0300 Subject: [PATCH 011/394] BAP-885: Add form type for autocomplete - moved form types from OroUIBundle to OroFormBundle --- src/Oro/Bundle/FormBundle/.gitignore | 4 ++++ .../DependencyInjection/Configuration.php | 22 ++++++++++++++++++ .../DependencyInjection/OroFormExtension.php | 23 +++++++++++++++++++ .../ArrayToStringTransformer.php | 2 +- .../EntitiesToIdsTransformer.php | 2 +- .../FixArrayToStringListener.php | 2 +- .../Form/Type/EntityIdentifierType.php | 8 +++---- .../Form/Type/OroDateTimeType.php | 2 +- .../Form/Type/OroDateType.php | 2 +- src/Oro/Bundle/FormBundle/OroFormBundle.php | 9 ++++++++ src/Oro/Bundle/FormBundle/README.md | 8 +++++++ .../FormBundle/Resources/config/services.yml | 21 +++++++++++++++++ .../doc/reference/form_components.md | 20 ++++++++-------- .../ArrayToStringTransformerTest.php | 4 ++-- .../EntitiesToIdsTransformerTest.php | 4 ++-- .../FixArrayToStringListenerTest.php | 4 ++-- .../Form/Type/EntityIdentifierTypeTest.php | 10 ++++---- src/Oro/Bundle/FormBundle/composer.json | 21 +++++++++++++++++ src/Oro/Bundle/UIBundle/README.md | 3 +-- .../UIBundle/Resources/config/services.yml | 19 --------------- 20 files changed, 140 insertions(+), 50 deletions(-) create mode 100644 src/Oro/Bundle/FormBundle/.gitignore create mode 100644 src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php create mode 100644 src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php rename src/Oro/Bundle/{UIBundle => FormBundle}/Form/DataTransformer/ArrayToStringTransformer.php (97%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Form/DataTransformer/EntitiesToIdsTransformer.php (98%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Form/EventListener/FixArrayToStringListener.php (93%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Form/Type/EntityIdentifierType.php (94%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Form/Type/OroDateTimeType.php (98%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Form/Type/OroDateType.php (97%) create mode 100644 src/Oro/Bundle/FormBundle/OroFormBundle.php create mode 100644 src/Oro/Bundle/FormBundle/README.md create mode 100644 src/Oro/Bundle/FormBundle/Resources/config/services.yml rename src/Oro/Bundle/{UIBundle => FormBundle}/Resources/doc/reference/form_components.md (70%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Tests/Unit/Form/DataTransformer/ArrayToStringTransformerTest.php (97%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Tests/Unit/Form/DataTransformer/EntitiesToIdsTransformerTest.php (99%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Tests/Unit/Form/EventListener/FixArrayToStringListenerTest.php (91%) rename src/Oro/Bundle/{UIBundle => FormBundle}/Tests/Unit/Form/Type/EntityIdentifierTypeTest.php (97%) create mode 100644 src/Oro/Bundle/FormBundle/composer.json diff --git a/src/Oro/Bundle/FormBundle/.gitignore b/src/Oro/Bundle/FormBundle/.gitignore new file mode 100644 index 00000000000..dad62749d16 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/.gitignore @@ -0,0 +1,4 @@ +/.settings +/.buildpath +/.project +/.idea diff --git a/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php b/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php new file mode 100644 index 00000000000..2087802f32d --- /dev/null +++ b/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php @@ -0,0 +1,22 @@ +root('oro_form'); + + return $treeBuilder; + } +} diff --git a/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php b/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php new file mode 100644 index 00000000000..8826227f103 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php @@ -0,0 +1,23 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->load('services.yml'); + } +} diff --git a/src/Oro/Bundle/UIBundle/Form/DataTransformer/ArrayToStringTransformer.php b/src/Oro/Bundle/FormBundle/Form/DataTransformer/ArrayToStringTransformer.php similarity index 97% rename from src/Oro/Bundle/UIBundle/Form/DataTransformer/ArrayToStringTransformer.php rename to src/Oro/Bundle/FormBundle/Form/DataTransformer/ArrayToStringTransformer.php index 7b438bc29d0..c81589f966c 100644 --- a/src/Oro/Bundle/UIBundle/Form/DataTransformer/ArrayToStringTransformer.php +++ b/src/Oro/Bundle/FormBundle/Form/DataTransformer/ArrayToStringTransformer.php @@ -1,6 +1,6 @@ type = $this->getMockBuilder('Oro\Bundle\UIBundle\Form\Type\EntityIdentifierType') + $this->type = $this->getMockBuilder('Oro\Bundle\FormBundle\Form\Type\EntityIdentifierType') ->setMethods(array('createEntitiesToIdsTransformer')) ->setConstructorArgs(array($this->getMockManagerRegistry())) ->getMock(); @@ -282,7 +282,7 @@ public function testCreateEntitiesToIdsTransformer() $this->callback( function ($transformer) use ($options) { \PHPUnit_Framework_TestCase::assertInstanceOf( - 'Oro\Bundle\UIBundle\Form\DataTransformer\EntitiesToIdsTransformer', + 'Oro\Bundle\FormBundle\Form\DataTransformer\EntitiesToIdsTransformer', $transformer ); \PHPUnit_Framework_TestCase::assertAttributeEquals( @@ -412,7 +412,7 @@ protected function getMockEntitiesToIdsTransformer() { if (!$this->entitiesToIdsTransformer) { $this->entitiesToIdsTransformer = - $this->getMockBuilder('Oro\Bundle\UIBundle\Form\DataTransformer\EntitiesToIdsTransformer') + $this->getMockBuilder('Oro\Bundle\FormBundle\Form\DataTransformer\EntitiesToIdsTransformer') ->disableOriginalConstructor() ->setMethods(array('transform', 'reverseTransform')) ->getMockForAbstractClass(); diff --git a/src/Oro/Bundle/FormBundle/composer.json b/src/Oro/Bundle/FormBundle/composer.json new file mode 100644 index 00000000000..1366b813328 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/composer.json @@ -0,0 +1,21 @@ +{ + "name": "oro/form-bundle", + "type": "symfony-bundle", + "description": "BAP Form Bundle", + "keywords": ["BAP", "Form"], + "license": "MIT", + "require": { + "php": ">=5.3.3", + "symfony/symfony": ">=2.1" + }, + "autoload": { + "psr-0": { "Oro\\Bundle\\FormBundle": "" } + }, + "target-dir": "Oro/Bundle/FormBundle", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + } +} diff --git a/src/Oro/Bundle/UIBundle/README.md b/src/Oro/Bundle/UIBundle/README.md index 88ab24389f4..2937a1e5b8a 100644 --- a/src/Oro/Bundle/UIBundle/README.md +++ b/src/Oro/Bundle/UIBundle/README.md @@ -4,10 +4,9 @@ User interface layouts and controls. ## Table of Contents -- [Form Components](./Resources/doc/reference/form_components.md) - [JavaScript Tools and Libraries](./Resources/doc/reference/js_tools_and_libraries.md) ## Configuration Settings - oro_ui.application_name - application name to display in header -- oro_ui.application_title - application title for name reference in header \ No newline at end of file +- oro_ui.application_title - application title for name reference in header diff --git a/src/Oro/Bundle/UIBundle/Resources/config/services.yml b/src/Oro/Bundle/UIBundle/Resources/config/services.yml index c3ef9aa7eec..a570ebbf227 100644 --- a/src/Oro/Bundle/UIBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/UIBundle/Resources/config/services.yml @@ -1,26 +1,7 @@ parameters: - oro_ui.date.class: Oro\Bundle\UIBundle\Form\Type\OroDateType - oro_ui.datetime.class: Oro\Bundle\UIBundle\Form\Type\OroDateTimeType - oro_ui.type.entity_identifier.class: Oro\Bundle\UIBundle\Form\Type\EntityIdentifierType oro_ui.twig.ceil.class: Oro\Bundle\UIBundle\Twig\CeilExtension services: - oro_ui.type.oro_date: - class: %oro_ui.date.class% - tags: - - { name: form.type, alias: oro_date } - - oro_ui.type.oro_datetime: - class: %oro_ui.datetime.class% - tags: - - { name: form.type, alias: oro_datetime } - - oro_ui.type.entity_identifier: - class: %oro_ui.type.entity_identifier.class% - tags: - - { name: form.type, alias: oro_entity_identifier } - arguments: ["@doctrine"] - oro_ui.twig.ceil_extension: class: %oro_ui.twig.ceil.class% tags: From eebfe0d35bc69bd104777791974f9771578894bd Mon Sep 17 00:00:00 2001 From: Aleksandr Smaga Date: Wed, 29 May 2013 15:37:58 +0200 Subject: [PATCH 012/394] BAP-884: Serialize error during contact save Fix unit tests --- .../Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php | 4 ++-- .../Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php | 2 +- .../Form/EventListener/BuildAddressFormListenerTest.php | 6 +++--- .../Tests/Unit/Provider/ImportExport/ManagerTest.php | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php index 6b6547b5e2a..291ca631981 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php @@ -33,7 +33,7 @@ public function testBeforeSave() public function testToString() { $obj = new Address(); - $country = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $country = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $country->expects($this->once()) ->method('__toString') ->will($this->returnValue('Ukraine')); @@ -61,7 +61,7 @@ public function testToString() */ public function provider() { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $regionMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Region'); return array( array('id', 1), diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php index 0d973dceb12..3b2814f0c65 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php @@ -19,7 +19,7 @@ public function testConstructorData() */ public function testCountrySetter() { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $obj = new Region(); $obj->setCountry($countryMock); diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php index 6604a6f00b7..56183697c96 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php @@ -79,7 +79,7 @@ public function testPreSetDataHasState() ->disableOriginalConstructor() ->getMock(); - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $countryMock->expects($this->once()) ->method('hasRegions') ->will($this->returnValue(true)); @@ -142,7 +142,7 @@ public function testPreSetDataNoState() ->disableOriginalConstructor() ->getMock(); - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $countryMock->expects($this->once()) ->method('hasRegions') ->will($this->returnValue(true)); @@ -190,7 +190,7 @@ public function testPreBindData() ->disableOriginalConstructor() ->getMock(); - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $countryMock->expects($this->once()) ->method('hasRegions') ->will($this->returnValue(true)); diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/ManagerTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/ManagerTest.php index 030c9dd8694..8c747f89f49 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/ManagerTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/ManagerTest.php @@ -30,7 +30,7 @@ public function setUp() */ public function testSync() { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $this->reader ->expects($this->exactly(2)) @@ -60,7 +60,7 @@ public function testSync() */ public function testArraySync() { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $data = array($countryMock); $this->writer From 117579d556abca4c6fae69c29c9347de4cefd5b5 Mon Sep 17 00:00:00 2001 From: Alexander Nezdoiminoga Date: Wed, 29 May 2013 17:02:42 +0300 Subject: [PATCH 013/394] BAP-881 fix - allow only one instance of changeHistory window instance --- src/Oro/Bundle/UserBundle/Resources/public/js/user.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Oro/Bundle/UserBundle/Resources/public/js/user.js b/src/Oro/Bundle/UserBundle/Resources/public/js/user.js index cbb0681f7cc..a83f43380c9 100644 --- a/src/Oro/Bundle/UserBundle/Resources/public/js/user.js +++ b/src/Oro/Bundle/UserBundle/Resources/public/js/user.js @@ -141,6 +141,10 @@ $(function() { }); $(document).on('click', '#view-activity-btn', function (e) { + if ($(":ui-dialog").has('#historyDatagridGridTemplate').length) { + return false; + } + var scrollable = $('.scrollable-container'); var container = scrollable.length ? scrollable.get(scrollable.length - 1) : '#container'; new Oro.widget.DialogView({ From bbaee6d0d9ce2619551b72d1ec5b00ed3785108d Mon Sep 17 00:00:00 2001 From: Alexander Nezdoiminoga Date: Wed, 29 May 2013 17:28:51 +0300 Subject: [PATCH 014/394] CS fix --- src/Oro/Bundle/UserBundle/Resources/public/js/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Oro/Bundle/UserBundle/Resources/public/js/user.js b/src/Oro/Bundle/UserBundle/Resources/public/js/user.js index a83f43380c9..d27d7846e46 100644 --- a/src/Oro/Bundle/UserBundle/Resources/public/js/user.js +++ b/src/Oro/Bundle/UserBundle/Resources/public/js/user.js @@ -141,7 +141,7 @@ $(function() { }); $(document).on('click', '#view-activity-btn', function (e) { - if ($(":ui-dialog").has('#historyDatagridGridTemplate').length) { + if ($(':ui-dialog').has('#historyDatagridGridTemplate').length) { return false; } From 62f6fd252c95518eee637a2db736d33dd2494cda Mon Sep 17 00:00:00 2001 From: bogdan Date: Wed, 29 May 2013 17:46:58 +0300 Subject: [PATCH 015/394] BAP-849: ajax hash param removed, fixes for scrollspy --- .../Event/ResponseHashnavListener.php | 3 - .../Event/ResponseHistoryListener.php | 8 +- .../Resources/public/js/hash.navigation.js | 102 ++++++++++-------- .../views/HashNav/hashNavAjax.html.twig | 6 ++ 4 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/Oro/Bundle/NavigationBundle/Event/ResponseHashnavListener.php b/src/Oro/Bundle/NavigationBundle/Event/ResponseHashnavListener.php index 8f42e3b5e9d..892d06dd1d6 100644 --- a/src/Oro/Bundle/NavigationBundle/Event/ResponseHashnavListener.php +++ b/src/Oro/Bundle/NavigationBundle/Event/ResponseHashnavListener.php @@ -8,8 +8,6 @@ class ResponseHashnavListener { - const HASH_NAV_PARAM = 'is_hash_ajax'; - /** * @var \Symfony\Component\Security\Core\SecurityContextInterface */ @@ -48,7 +46,6 @@ public function onResponse(FilterResponseEvent $event) $location = $request->getUri(); $isFullRedirect = true; } - $location = preg_replace('/[\?&](' . self::HASH_NAV_PARAM . '=1)/', '', $location); if ($location) { $event->setResponse( $this->templating->renderResponse( diff --git a/src/Oro/Bundle/NavigationBundle/Event/ResponseHistoryListener.php b/src/Oro/Bundle/NavigationBundle/Event/ResponseHistoryListener.php index 25dd002f431..b9a1e86afef 100644 --- a/src/Oro/Bundle/NavigationBundle/Event/ResponseHistoryListener.php +++ b/src/Oro/Bundle/NavigationBundle/Event/ResponseHistoryListener.php @@ -69,15 +69,9 @@ public function onResponse(FilterResponseEvent $event) if (!$this->matchRequest($response, $request)) { return false; } - //Remove hash navigation param from url - $url = preg_replace( - '/[\?&](' . ResponseHashnavListener::HASH_NAV_PARAM . '=1)/', - '', - $request->getRequestUri() - ); $postArray = array( - 'url' => $url, + 'url' => $request->getRequestUri(), 'user' => $this->user, ); diff --git a/src/Oro/Bundle/NavigationBundle/Resources/public/js/hash.navigation.js b/src/Oro/Bundle/NavigationBundle/Resources/public/js/hash.navigation.js index b93fcc53f17..8e3473eee20 100644 --- a/src/Oro/Bundle/NavigationBundle/Resources/public/js/hash.navigation.js +++ b/src/Oro/Bundle/NavigationBundle/Resources/public/js/hash.navigation.js @@ -95,7 +95,7 @@ Oro.Navigation = Backbone.Router.extend({ this.encodedStateData = encodedStateData; this.url = page; if (!this.skipAjaxCall) { - this.loadPage(this.url); + this.loadPage(); } this.skipAjaxCall = false; }, @@ -154,7 +154,7 @@ Oro.Navigation = Backbone.Router.extend({ var i; if ((i = this.contentCacheUrls.indexOf(this.removePageStateParam(this.url))) !== -1) { if (this.contentCache[i]) { - this.handleResponse(this.contentCache[i], {skipMessages: true, skipMenuTabs: true, skipTriggerComplete: true}); + this.handleResponse(this.contentCache[i], {fromCache: true}); this.clearPageCache(i); //this.reorderCache(i); //this.afterRequest(); @@ -163,7 +163,6 @@ Oro.Navigation = Backbone.Router.extend({ var pageUrl = this.baseUrl + this.url; $.ajax({ url: pageUrl, - data: {'is_hash_ajax' : 1}, //added to prevent browser caching of raw requests without hash nav headers: { 'x-oro-hash-navigation': true }, beforeSend: function( xhr ) { //remove standard ajax header because we already have a custom header sent @@ -190,7 +189,7 @@ Oro.Navigation = Backbone.Router.extend({ * @param data */ savePageToCache: function(data) { - if (this.contentCacheUrls.length == this.maxCachedPages) { + if (this.contentCacheUrls.length === this.maxCachedPages) { this.clearPageCache(0); } var j = this.contentCacheUrls.indexOf(this.removePageStateParam(this.url)); @@ -213,7 +212,7 @@ Oro.Navigation = Backbone.Router.extend({ this.contentCacheUrls[i - 1] = this.contentCacheUrls[i]; } this.contentCacheUrls[this.contentCacheUrls.length - 1] = tempUrl; - for (var i = pos + 1; i < this.contentCache.length; i++) { + for (i = pos + 1; i < this.contentCache.length; i++) { this.contentCache[i - 1] = this.contentCache[i]; } this.contentCache[this.contentCacheUrls.length - 1] = tempContent; @@ -258,7 +257,7 @@ Oro.Navigation = Backbone.Router.extend({ Oro.Events.bind( "grid_load:complete", function () { - this.processClicks('.grid-container ' + this.selectors.links) + this.processClicks($('.grid-container').find(this.selectors.links)); }, this ); @@ -290,7 +289,7 @@ Oro.Navigation = Backbone.Router.extend({ Oro.Events.bind( "top_search_request:complete", function () { - this.processClicks(this.selectors.searchDropdown + ' ' + this.selectors.links); + this.processClicks($(this.selectors.searchDropdown).find(this.selectors.links)); }, this ); @@ -350,7 +349,7 @@ Oro.Navigation = Backbone.Router.extend({ */ handleResponse: function (data, options) { if (_.isUndefined(options)) { - var options = {}; + options = {}; } try { /** @@ -359,7 +358,7 @@ Oro.Navigation = Backbone.Router.extend({ document.getElementById('container').innerHTML = ''; var redirectUrl = $(data).filter('#redirect').text(); if (redirectUrl) { - urlParts = redirectUrl.split('url='); + var urlParts = redirectUrl.split('url='); if (urlParts[1]) { redirectUrl = urlParts[1]; } @@ -377,7 +376,7 @@ Oro.Navigation = Backbone.Router.extend({ var js = ''; $(data).filter('#head').find('script:not([src])').each(function () { js = js + this.outerHTML; - }) + }); $(this.selectors.container).append(js); /** * Setting page title @@ -391,25 +390,26 @@ Oro.Navigation = Backbone.Router.extend({ titleSerialized = $.parseJSON(titleSerialized); $('.top-action-box .btn').filter('.minimize-button, .favorite-button').data('title', titleSerialized); } - this.processClicks(this.selectors.menu + ' ' + this.selectors.links); - this.processClicks(this.selectors.container + ' ' + this.selectors.links); - this.processAnchors(this.selectors.container + ' ' + this.selectors.scrollLinks); - if (!options.skipMenuTabs) { + if (!options.fromCache) { + this.processClicks($(this.selectors.menu).find(this.selectors.links)); + this.processClicks($(this.selectors.container).find(this.selectors.links)); + this.processAnchors($(this.selectors.container).find(this.selectors.scrollLinks)); this.updateMenuTabs(data); - } - this.processForms(this.selectors.container + ' ' + this.selectors.forms); - if (!options.skipMessages) { + this.processForms($(this.selectors.container).find(this.selectors.forms)); this.updateMessages(data); + this.processPinButton(data); } this.hideActiveDropdowns(); - this.processPinButton(data); + } } catch (err) { - console.log(err); + if (!_.isUndefined(console)) { + console.error(err); + } this.showError('', "Sorry, page was not loaded correctly"); } - if (!options.skipTriggerComplete) { + if (!options.fromCache) { this.triggerCompleteEvent(); } }, @@ -456,7 +456,8 @@ Oro.Navigation = Backbone.Router.extend({ * @param data */ processPinButton: function(data) { - if ($(data).filter(this.selectors.pinButton).html().indexOf("true") != - 1) { + var pinBar = $(data).filter(this.selectors.pinButton).html(); + if (pinBar && (pinBar.indexOf("true") !== - 1)) { $(this.selectors.pinButton).show(); } else { $(this.selectors.pinButton).hide(); @@ -474,8 +475,8 @@ Oro.Navigation = Backbone.Router.extend({ /** * Processing links for history and most viewed tabs */ - this.processClicks(this.selectors.historyTab + ' ' + this.selectors.links + ', ' + - this.selectors.mostViewedTab + ' ' + this.selectors.links); + this.processClicks($(this.selectors.historyTab).find(this.selectors.links)); + this.processClicks($(this.selectors.mostViewedTab).find(this.selectors.links)); }, /** @@ -497,7 +498,7 @@ Oro.Navigation = Backbone.Router.extend({ */ processClicks: function (selector) { $(selector).not('.no-hash').on('click', _.bind(function (e) { - if (e.shiftKey || e.ctrlKey || e.metaKey || e.which == 2) { + if (e.shiftKey || e.ctrlKey || e.metaKey || e.which === 2) { return true; } var target = e.currentTarget; @@ -515,18 +516,36 @@ Oro.Navigation = Backbone.Router.extend({ }, this)); }, + /** + * Manually process anchors to prevent changing urls hash. If anchor doesn't have click events attached assume it + * a standard anchor and emulate browser anchor scroll behaviour + * + * @param selector + */ processAnchors: function(selector) { - $(selector).on('click', _.bind(function (e) { - var target = e.currentTarget; - if ($(target).is('a')) { - e.preventDefault(); - var href = $(target).attr('href'); - if (/^#\w/.test(href) && $(this.selectors.scrollSpy).length) { - $(this.selectors.scrollSpy).scrollTop($(href).position().top + $(this.selectors.scrollSpy).scrollTop()); - $(target).blur(); + $(selector).each(function() { + var href = $(this).attr('href'); + var $href = /^#\w/.test(href) && $(href); + if ($href) { + var events = $._data($(this).get(0), 'events'); + if (_.isUndefined(events) || !events.click) { + $(this).on('click', function (e) { + e.preventDefault(); + //finding parent div with scroll + var scrollDiv = $href.parents().filter(function() { + return $(this).get(0).scrollHeight > $(this).innerHeight(); + }); + if (!scrollDiv) { + scrollDiv = $(window); + } else { + scrollDiv = scrollDiv.eq(0); + } + scrollDiv.scrollTop($href.position().top + scrollDiv.scrollTop()); + $(this).blur(); + }); } } - }, this)) + }); }, /** @@ -539,8 +558,7 @@ Oro.Navigation = Backbone.Router.extend({ var target = e.currentTarget; e.preventDefault(); - var url = ''; - url = $(target).attr('action'); + var url = $(target).attr('action'); this.method = $(target).attr('method') ? $(target).attr('method') : "get"; if (url) { @@ -548,7 +566,7 @@ Oro.Navigation = Backbone.Router.extend({ Oro.Events.trigger("hash_navigation_request:form-start", target); if (Oro.Registry.getElement('form_validate')) { var data = $(target).serialize(); - if (this.method == 'get') { + if (this.method === 'get') { if (data) { url += '?' + data; } @@ -572,7 +590,7 @@ Oro.Navigation = Backbone.Router.extend({ } } return false; - }, this)) + }, this)); }, /** @@ -587,7 +605,7 @@ Oro.Navigation = Backbone.Router.extend({ */ var urlParts = Backbone.history.fragment.split('|g/'); url = urlParts[0].replace('url=', ''); - if (urlParts[1] && (!_.isUndefined(includeGrid) && includeGrid == true)) { + if (urlParts[1] && (!_.isUndefined(includeGrid) && includeGrid === true)) { url += '#g/' + urlParts[1]; } if (!url) { @@ -600,12 +618,12 @@ Oro.Navigation = Backbone.Router.extend({ /** * Check if url is a 3d party link * - * @todo Implement check * @param url * @return {Boolean} */ checkThirdPartyLink: function(url) { - return false; + var external = RegExp('^(https?:)?//(?!' + location.host + ')'); + return (url.indexOf('http') !== -1) && external.test(url); }, /** @@ -616,14 +634,14 @@ Oro.Navigation = Backbone.Router.extend({ */ setLocation: function (url, options) { if (_.isUndefined(options)) { - var options = {}; + options = {}; } if (this.enabled && !this.checkThirdPartyLink(url)) { if (options.clearCache) { this.clearPageCache(); } url = url.replace(this.baseUrl, '').replace(/^(#\!?|\.)/, '').replace('#g/', '|g/'); - if (url == this.url) { + if (url === this.url) { this.loadPage(); } else { window.location.hash = '#url=' + url; diff --git a/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig index c66574ccedb..a6613f7d095 100644 --- a/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig +++ b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig @@ -1,3 +1,9 @@ +{# to prevent showing cached ajax response, reload the page#} +
{% endblock addressStaticAttribute %} - -{% block addressFlexibleAttribute %} -
- -
-
-

{{ attr.__toString|default('N/A') }}

-
-
-
-{% endblock addressFlexibleAttribute %} diff --git a/src/Oro/Bundle/UIBundle/Resources/views/macros.html.twig b/src/Oro/Bundle/UIBundle/Resources/views/macros.html.twig index e91ad16a3d4..5cd6cb7dbea 100644 --- a/src/Oro/Bundle/UIBundle/Resources/views/macros.html.twig +++ b/src/Oro/Bundle/UIBundle/Resources/views/macros.html.twig @@ -26,3 +26,14 @@
{% endmacro %} + +{% macro flexibleAttributeRow(value) %} +
+ +
+
+

{{ value.__toString|default('N/A') }}

+
+
+
+{% endmacro %} diff --git a/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig b/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig index 69c6d060cb4..b76d54f0f1f 100644 --- a/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig +++ b/src/Oro/Bundle/UserBundle/Resources/views/User/view.html.twig @@ -1,5 +1,6 @@ {% extends bap.layout is defined ? bap.layout : 'OroUserBundle::layout.html.twig' %} {% import 'OroUserBundle::macros.html.twig' as macros %} +{% import 'OroUIBundle::macros.html.twig' as UI %} {% set format = get_user_value('oro_user.name_format') %} {% oro_title_set({params : {"%username%": user.fullname(format)|default('N/A') }}) %} @@ -149,14 +150,7 @@
{% for value in user|getAttributes() %} -
- -
-
-

{{ value.__toString }}

-
-
-
+ {{ UI.flexibleAttributeRow(value) }} {% endfor %}
From 8ee0d371d81b6fdcafb226bae11332ad739ee57e Mon Sep 17 00:00:00 2001 From: yurio Date: Thu, 30 May 2013 14:56:52 +0300 Subject: [PATCH 019/394] BAP-896: positions sceleton --- .../Resources/config/positions.yml | 3 ++ .../DependencyInjection/OroUIExtension.php | 21 ++++++++++ .../UIBundle/Resources/config/services.yml | 7 ++++ .../Resources/views/Default/index.html.twig | 1 + .../UIBundle/Twig/Node/PositionNode.php | 41 +++++++++++++++++++ .../Twig/Parser/PositionTokenParser.php | 36 ++++++++++++++++ src/Oro/Bundle/UIBundle/Twig/UiExtension.php | 33 +++++++++++++++ 7 files changed, 142 insertions(+) create mode 100644 src/Oro/Bundle/SearchBundle/Resources/config/positions.yml create mode 100644 src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php create mode 100644 src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php create mode 100644 src/Oro/Bundle/UIBundle/Twig/UiExtension.php diff --git a/src/Oro/Bundle/SearchBundle/Resources/config/positions.yml b/src/Oro/Bundle/SearchBundle/Resources/config/positions.yml new file mode 100644 index 00000000000..e7e778fcac9 --- /dev/null +++ b/src/Oro/Bundle/SearchBundle/Resources/config/positions.yml @@ -0,0 +1,3 @@ +top_block: + top_search_block: + action: OroSearchBundle:Search:searchBar diff --git a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php index 6b3b713bf03..5aa80fa9941 100644 --- a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php +++ b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php @@ -6,6 +6,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\Yaml\Yaml; /** * This is the class that loads and manages your bundle configuration @@ -24,5 +25,25 @@ public function load(array $configs, ContainerBuilder $container) $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); + + $this->positionsConfig($container); + } + + /** + * Add position mapping + * + * @param ContainerBuilder $container + */ + private function positionsConfig(ContainerBuilder $container) + { + $positions = array(); + $bundles = $container->getParameter('kernel.bundles') ; + foreach ($bundles as $bundle) { + $reflection = new \ReflectionClass($bundle); + if (is_file($file = dirname($reflection->getFilename()).'/Resources/config/positions.yml')) { + $positions += Yaml::parse(realpath($file)); + } + } + $container->setParameter('oro_ui.positions', $positions); } } diff --git a/src/Oro/Bundle/UIBundle/Resources/config/services.yml b/src/Oro/Bundle/UIBundle/Resources/config/services.yml index c3ef9aa7eec..7b8d67b01b1 100644 --- a/src/Oro/Bundle/UIBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/UIBundle/Resources/config/services.yml @@ -3,6 +3,7 @@ parameters: oro_ui.datetime.class: Oro\Bundle\UIBundle\Form\Type\OroDateTimeType oro_ui.type.entity_identifier.class: Oro\Bundle\UIBundle\Form\Type\EntityIdentifierType oro_ui.twig.ceil.class: Oro\Bundle\UIBundle\Twig\CeilExtension + oro_ui.twig.extension.class: Oro\Bundle\UIBundle\Twig\UiExtension services: oro_ui.type.oro_date: @@ -25,3 +26,9 @@ services: class: %oro_ui.twig.ceil.class% tags: - { name: twig.extension } + + oro_ui.twig.ui_extension: + class: %oro_ui.twig.extension.class% + arguments: [%oro_ui.positions%] + tags: + - { name: twig.extension } \ No newline at end of file diff --git a/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig b/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig index 47aa26ac4b7..e5a8a8647ed 100644 --- a/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig +++ b/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig @@ -81,6 +81,7 @@ {% endblock %} +{% position top_block %}
{% block header %} diff --git a/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php new file mode 100644 index 00000000000..623297bccc9 --- /dev/null +++ b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php @@ -0,0 +1,41 @@ + $blocks), $line); + $this->blocks = $blocks; + $this->line = $line; + $this->tag = $tag; + } + + public function compile(Twig_Compiler $compiler) + { + foreach ($this->blocks as $blockData) { + if (array_key_exists('template', $blockData)) { + $expr = new Twig_Node_Expression_Constant($blockData['template'], $this->line); + $block = new Twig_Node_Include($expr, null, true, $this->line, $this->tag); + $block->compile($compiler); + } elseif (array_key_exists('action', $blockData)) { + $expr = new Twig_Node_Expression_Constant($blockData['action'], $this->line); + $attr = new Twig_Node_Expression_Constant(array(), $this->line); + $block = new RenderNode($expr, $attr, $attr, $this->line, $this->tag); + $block->compile($compiler); + } + } + } +} \ No newline at end of file diff --git a/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php b/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php new file mode 100644 index 00000000000..7fafd9a2902 --- /dev/null +++ b/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php @@ -0,0 +1,36 @@ +positions = $positions; + } + /** + * {@inheritDoc} + */ + public function parse(\Twig_Token $token) + { + $parser = $this->parser; + $stream = $parser->getStream(); + + $name = $stream->expect(\Twig_Token::NAME_TYPE)->getValue(); + $stream->expect(\Twig_Token::BLOCK_END_TYPE); + + return new PositionNode($this->positions[$name], $token->getLine(), $this->getTag()); + } + + /** + * {@inheritDoc} + */ + public function getTag() + { + return 'position'; + } + +} \ No newline at end of file diff --git a/src/Oro/Bundle/UIBundle/Twig/UiExtension.php b/src/Oro/Bundle/UIBundle/Twig/UiExtension.php new file mode 100644 index 00000000000..8c066e7de27 --- /dev/null +++ b/src/Oro/Bundle/UIBundle/Twig/UiExtension.php @@ -0,0 +1,33 @@ +positions = $positions; + } + + /** + * {@inheritDoc} + */ + public function getTokenParsers() + { + return array( + new PositionTokenParser($this->positions) + ); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_ui'; + } +} \ No newline at end of file From 3f4bc869b6ac9611bc7a9c2133df3f8b223025d3 Mon Sep 17 00:00:00 2001 From: Aleksandr Smaga Date: Thu, 30 May 2013 14:04:58 +0200 Subject: [PATCH 020/394] BAP-875 Improve templates on view pages Typo fix --- .../AddressBundle/Resources/views/Include/viewMacro.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig index 906d4328649..cfbcb3d2757 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig +++ b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig @@ -25,7 +25,7 @@ {% endfor %} {# Render flexible attributes #} - {% import 'OroUIBundle::macrow.html.twig' as UI %} + {% import 'OroUIBundle::macros.html.twig' as UI %} {% for value in address|getAttributes() %} UI.flexibleAttributeRow(value) {% endfor %} From 5a7b55132badd56696ff422a24565172e483713f Mon Sep 17 00:00:00 2001 From: Aleksandr Smaga Date: Thu, 30 May 2013 15:36:08 +0200 Subject: [PATCH 021/394] BAP-875 Improve templates on view pages Fixed typo --- .../AddressBundle/Resources/views/Include/viewMacro.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig index cfbcb3d2757..e074b2faeee 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig +++ b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig @@ -27,7 +27,7 @@ {# Render flexible attributes #} {% import 'OroUIBundle::macros.html.twig' as UI %} {% for value in address|getAttributes() %} - UI.flexibleAttributeRow(value) + {{ UI.flexibleAttributeRow(value) }} {% endfor %} {% endmacro %} From 97576b25605091f3cda9e04e3794b36b1e7d2ba0 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 30 May 2013 17:30:36 +0300 Subject: [PATCH 022/394] Minor refactoring --- .../UserBundle/Controller/UserController.php | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/Oro/Bundle/UserBundle/Controller/UserController.php b/src/Oro/Bundle/UserBundle/Controller/UserController.php index affe1340e68..3b809cb119d 100644 --- a/src/Oro/Bundle/UserBundle/Controller/UserController.php +++ b/src/Oro/Bundle/UserBundle/Controller/UserController.php @@ -4,7 +4,6 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Bundle\FrameworkBundle\Controller\Controller; -use Symfony\Component\HttpFoundation\Request; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; @@ -43,7 +42,6 @@ public function viewAction(User $user) /** * @Route("/apigen/{id}", name="oro_user_apigen", requirements={"id"="\d+"}) - * @Template * @Acl( * id="oro_user_user_apigen", * name="Generate new API key", @@ -67,7 +65,7 @@ public function apigenAction(User $user) return $this->getRequest()->isXmlHttpRequest() ? new JsonResponse($api->getApiKey()) - : $this->forward('OroUserBundle:User:show', array('user' => $user)); + : $this->forward('OroUserBundle:User:view', array('user' => $user)); } /** @@ -84,7 +82,7 @@ public function apigenAction(User $user) */ public function createAction() { - $user = $this->getManager()->createFlexible(); + $user = $this->get('oro_user.manager')->createFlexible(); return $this->updateAction($user); } @@ -105,6 +103,7 @@ public function updateAction(User $entity) { if ($this->get('oro_user.form.handler.user')->process($entity)) { $this->get('session')->getFlashBag()->add('success', 'User successfully saved'); + return $this->redirect($this->generateUrl('oro_user_index')); } @@ -127,24 +126,12 @@ public function updateAction(User $entity) * parent="oro_user_user" * ) */ - public function indexAction(Request $request) + public function indexAction() { - $datagrid = $this->get('oro_user.user_datagrid_manager')->getDatagrid(); - $view = 'json' == $request->getRequestFormat() - ? 'OroGridBundle:Datagrid:list.json.php' - : 'OroUserBundle:User:index.html.twig'; - - return $this->render( - $view, - array('datagrid' => $datagrid->createView()) - ); - } + $view = $this->get('oro_user.user_datagrid_manager')->getDatagrid()->createView(); - /** - * @return UserManager - */ - protected function getManager() - { - return $this->get('oro_user.manager'); + return 'json' == $this->getRequest()->getRequestFormat() + ? $this->get('oro_grid.renderer')->renderResultsJsonResponse($view) + : $this->render('OroUserBundle:User:index.html.twig', array('datagrid' => $view)); } } From 2b274cddc7851dbcc4ed92d123bbc1e8c16f2066 Mon Sep 17 00:00:00 2001 From: yurio Date: Thu, 30 May 2013 17:56:44 +0300 Subject: [PATCH 023/394] BAP-896: positions blocks order --- .../DependencyInjection/OroUIExtension.php | 41 ++++++++++++++++++- .../UIBundle/Twig/Node/PositionNode.php | 11 +++++ .../Twig/Parser/PositionTokenParser.php | 10 ++++- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php index 5aa80fa9941..8fbe9ee66c5 100644 --- a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php +++ b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php @@ -34,7 +34,7 @@ public function load(array $configs, ContainerBuilder $container) * * @param ContainerBuilder $container */ - private function positionsConfig(ContainerBuilder $container) + protected function positionsConfig(ContainerBuilder $container) { $positions = array(); $bundles = $container->getParameter('kernel.bundles') ; @@ -44,6 +44,43 @@ private function positionsConfig(ContainerBuilder $container) $positions += Yaml::parse(realpath($file)); } } - $container->setParameter('oro_ui.positions', $positions); + + $container->setParameter('oro_ui.positions', $this->changeOrders($positions)); + } + + /** + * Change position block order + * + * @param array $positions + * + * @return array + */ + protected function changeOrders(array $positions) + { + foreach ($positions as $positionName => $positionBlocks) { + usort($positions[$positionName], array($this, "comparePositionBlocks")); + } + + return $positions; + } + + /** + * Compare function + * + * @param $a + * @param $b + * + * @return int + */ + protected function comparePositionBlocks($a, $b) + { + $aOrder = isset($a['order']) ? $a['order'] : 0; + $bOrder = isset($b['order']) ? $b['order'] : 0; + + if ($aOrder == $bOrder) { + + return 0; + } + return ($aOrder < $bOrder) ? -1 : 1; } } diff --git a/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php index 623297bccc9..ab8bfd71c6f 100644 --- a/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php +++ b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php @@ -9,12 +9,20 @@ class PositionNode extends \Twig_Node { + /** + * @var array Array of blocks in the position + */ protected $blocks; protected $line; protected $tag; + /** + * @param array $blocks Array of blocks in the position + * @param array $line Line + * @param int $tag twig tag + */ public function __construct(array $blocks, $line, $tag) { parent::__construct(array(), array('value' => $blocks), $line); @@ -23,6 +31,9 @@ public function __construct(array $blocks, $line, $tag) $this->tag = $tag; } + /** + * {@inheritDoc} + */ public function compile(Twig_Compiler $compiler) { foreach ($this->blocks as $blockData) { diff --git a/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php b/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php index 7fafd9a2902..79bae0928c8 100644 --- a/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php +++ b/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php @@ -5,8 +5,14 @@ class PositionTokenParser extends \Twig_TokenParser { + /** + * @var array + */ protected $positions; + /** + * @param array $positions Array with positions + */ public function __construct(array $positions) { $this->positions = $positions; @@ -22,7 +28,9 @@ public function parse(\Twig_Token $token) $name = $stream->expect(\Twig_Token::NAME_TYPE)->getValue(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); - return new PositionNode($this->positions[$name], $token->getLine(), $this->getTag()); + if (isset($this->positions[$name])) { + return new PositionNode($this->positions[$name], $token->getLine(), $this->getTag()); + } } /** From 00c6cdb25a3cede8ce266bce633cda73d2716114 Mon Sep 17 00:00:00 2001 From: yurio Date: Thu, 30 May 2013 18:19:00 +0300 Subject: [PATCH 024/394] BAP-896: wrap position blocks --- src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php | 3 +++ src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php index 8fbe9ee66c5..d06088b5940 100644 --- a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php +++ b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php @@ -58,6 +58,9 @@ protected function positionsConfig(ContainerBuilder $container) protected function changeOrders(array $positions) { foreach ($positions as $positionName => $positionBlocks) { + foreach ($positionBlocks as $blockName => $block) { + $positions[$positionName][$blockName]['name'] = $blockName; + } usort($positions[$positionName], array($this, "comparePositionBlocks")); } diff --git a/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php index ab8bfd71c6f..3865adea953 100644 --- a/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php +++ b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php @@ -37,6 +37,7 @@ public function __construct(array $blocks, $line, $tag) public function compile(Twig_Compiler $compiler) { foreach ($this->blocks as $blockData) { + $compiler->raw('echo \'
\';'); if (array_key_exists('template', $blockData)) { $expr = new Twig_Node_Expression_Constant($blockData['template'], $this->line); $block = new Twig_Node_Include($expr, null, true, $this->line, $this->tag); @@ -47,6 +48,7 @@ public function compile(Twig_Compiler $compiler) $block = new RenderNode($expr, $attr, $attr, $this->line, $this->tag); $block->compile($compiler); } + $compiler->raw('echo \'
\';'); } } } \ No newline at end of file From 4685501b12324553e1888669324d07c1f49e52e1 Mon Sep 17 00:00:00 2001 From: yurio Date: Thu, 30 May 2013 18:42:21 +0300 Subject: [PATCH 025/394] BAP-896: wrap position blocks --- src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php index d06088b5940..a432c84509f 100644 --- a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php +++ b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php @@ -41,7 +41,7 @@ protected function positionsConfig(ContainerBuilder $container) foreach ($bundles as $bundle) { $reflection = new \ReflectionClass($bundle); if (is_file($file = dirname($reflection->getFilename()).'/Resources/config/positions.yml')) { - $positions += Yaml::parse(realpath($file)); + $positions = array_merge_recursive($positions, Yaml::parse(realpath($file))); } } From 9b452f92ca174b0fe67d892d836999e244876088 Mon Sep 17 00:00:00 2001 From: yurio Date: Thu, 30 May 2013 19:12:46 +0300 Subject: [PATCH 026/394] BAP-896: add class parameter for wrap position div --- .../UIBundle/DependencyInjection/Configuration.php | 7 +++++++ .../UIBundle/DependencyInjection/OroUIExtension.php | 2 ++ src/Oro/Bundle/UIBundle/Resources/config/services.yml | 2 +- src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php | 8 ++++++-- .../UIBundle/Twig/Parser/PositionTokenParser.php | 10 +++++++--- src/Oro/Bundle/UIBundle/Twig/UiExtension.php | 7 +++++-- 6 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/Oro/Bundle/UIBundle/DependencyInjection/Configuration.php b/src/Oro/Bundle/UIBundle/DependencyInjection/Configuration.php index 238991b83f1..6c7eb06c8d1 100644 --- a/src/Oro/Bundle/UIBundle/DependencyInjection/Configuration.php +++ b/src/Oro/Bundle/UIBundle/DependencyInjection/Configuration.php @@ -23,6 +23,13 @@ public function getConfigTreeBuilder() $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('oro_ui'); + $rootNode->children() + ->scalarNode('wrap_class') + ->cannotBeEmpty() + ->defaultValue('block-wrap') + ->end() + ->end(); + SettingsBuilder::append( $rootNode, array( diff --git a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php index a432c84509f..4c9c1b0538d 100644 --- a/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php +++ b/src/Oro/Bundle/UIBundle/DependencyInjection/OroUIExtension.php @@ -26,6 +26,8 @@ public function load(array $configs, ContainerBuilder $container) $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); + $container->setParameter('oro_ui.wrap_class', $config['wrap_class']); + $this->positionsConfig($container); } diff --git a/src/Oro/Bundle/UIBundle/Resources/config/services.yml b/src/Oro/Bundle/UIBundle/Resources/config/services.yml index 7b8d67b01b1..724a5085554 100644 --- a/src/Oro/Bundle/UIBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/UIBundle/Resources/config/services.yml @@ -29,6 +29,6 @@ services: oro_ui.twig.ui_extension: class: %oro_ui.twig.extension.class% - arguments: [%oro_ui.positions%] + arguments: [%oro_ui.positions%, %oro_ui.wrap_class%] tags: - { name: twig.extension } \ No newline at end of file diff --git a/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php index 3865adea953..fb37fc03603 100644 --- a/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php +++ b/src/Oro/Bundle/UIBundle/Twig/Node/PositionNode.php @@ -14,19 +14,23 @@ class PositionNode extends \Twig_Node */ protected $blocks; + protected $wrapClassName; + protected $line; protected $tag; /** * @param array $blocks Array of blocks in the position + * @param string $wrapClassName * @param array $line Line * @param int $tag twig tag */ - public function __construct(array $blocks, $line, $tag) + public function __construct(array $blocks, $wrapClassName, $line, $tag) { parent::__construct(array(), array('value' => $blocks), $line); $this->blocks = $blocks; + $this->wrapClassName = $wrapClassName; $this->line = $line; $this->tag = $tag; } @@ -37,7 +41,7 @@ public function __construct(array $blocks, $line, $tag) public function compile(Twig_Compiler $compiler) { foreach ($this->blocks as $blockData) { - $compiler->raw('echo \'
\';'); + $compiler->raw('echo \'
\';'); if (array_key_exists('template', $blockData)) { $expr = new Twig_Node_Expression_Constant($blockData['template'], $this->line); $block = new Twig_Node_Include($expr, null, true, $this->line, $this->tag); diff --git a/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php b/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php index 79bae0928c8..7f937a7aaba 100644 --- a/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php +++ b/src/Oro/Bundle/UIBundle/Twig/Parser/PositionTokenParser.php @@ -10,12 +10,16 @@ class PositionTokenParser extends \Twig_TokenParser */ protected $positions; + protected $wrapClassName; + /** - * @param array $positions Array with positions + * @param array $positions Array with positions + * @param string $wrapClassName Wrapper css class */ - public function __construct(array $positions) + public function __construct(array $positions, $wrapClassName) { $this->positions = $positions; + $this->wrapClassName = $wrapClassName; } /** * {@inheritDoc} @@ -29,7 +33,7 @@ public function parse(\Twig_Token $token) $stream->expect(\Twig_Token::BLOCK_END_TYPE); if (isset($this->positions[$name])) { - return new PositionNode($this->positions[$name], $token->getLine(), $this->getTag()); + return new PositionNode($this->positions[$name], $this->wrapClassName, $token->getLine(), $this->getTag()); } } diff --git a/src/Oro/Bundle/UIBundle/Twig/UiExtension.php b/src/Oro/Bundle/UIBundle/Twig/UiExtension.php index 8c066e7de27..c3d84e350bb 100644 --- a/src/Oro/Bundle/UIBundle/Twig/UiExtension.php +++ b/src/Oro/Bundle/UIBundle/Twig/UiExtension.php @@ -8,9 +8,12 @@ class UiExtension extends \Twig_Extension { protected $positions; - public function __construct($positions) + protected $wrapClassName; + + public function __construct($positions, $wrapClassName) { $this->positions = $positions; + $this->wrapClassName = $wrapClassName; } /** @@ -19,7 +22,7 @@ public function __construct($positions) public function getTokenParsers() { return array( - new PositionTokenParser($this->positions) + new PositionTokenParser($this->positions, $this->wrapClassName) ); } From baadc7fa6fa9b857812948d19f478bfbef0bcae3 Mon Sep 17 00:00:00 2001 From: Ignat Shcheglovskyi Date: Fri, 31 May 2013 15:32:52 +0300 Subject: [PATCH 027/394] BAP-885: Add form type for autocomplete - added SearchHandlerInterface, EntitySearchHandler, QueryBuilderSearchHandler and SearchPropertyConfig - updated Configuration to support autocomplete config structure (structure is not complete yet) - updated OroFormExtension to load form autocomplete configs from app/conifg.yml file and from Resources/conifg/form.yml files of bundles --- .../DependencyInjection/Configuration.php | 16 +- .../DependencyInjection/OroFormExtension.php | 30 +++ .../Doctrine/EntitySearchHandler.php | 37 ++++ .../Doctrine/QueryBuilderSearchHandler.php | 187 ++++++++++++++++++ .../SearchHandlerInterface.php | 16 ++ .../SearchPropertyConfig.php | 70 +++++++ 6 files changed, 354 insertions(+), 2 deletions(-) create mode 100644 src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/EntitySearchHandler.php create mode 100644 src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/QueryBuilderSearchHandler.php create mode 100644 src/Oro/Bundle/FormBundle/EntityAutocomplete/SearchHandlerInterface.php create mode 100644 src/Oro/Bundle/FormBundle/EntityAutocomplete/SearchPropertyConfig.php diff --git a/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php b/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php index 2087802f32d..b69858889de 100644 --- a/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php +++ b/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php @@ -5,8 +5,6 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; -use Oro\Bundle\ConfigBundle\DependencyInjection\SettingsBuilder; - class Configuration implements ConfigurationInterface { /** @@ -16,6 +14,20 @@ public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('oro_form'); + $rootNode + ->children() + ->arrayNode('autocomplete_entities') + ->useAttributeAsKey('autocomplete_entities') + ->prototype('array') + ->children() + ->scalarNode('class') + ->cannotBeEmpty() + ->end() + ->scalarNode('resource')->end() + ->scalarNode('property')->end() + ->end() + ->end() + ->end(); return $treeBuilder; } diff --git a/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php b/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php index 8826227f103..e528a17d432 100644 --- a/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php +++ b/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php @@ -4,20 +4,50 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\Yaml\Yaml; class OroFormExtension extends Extension { + const BUNDLE_CONFIG_FILE = 'form.yml'; + /** * {@inheritDoc} */ public function load(array $configs, ContainerBuilder $container) { + $bundleConfigs = $this->getBundleConfigs($container); + $configs = array_merge($bundleConfigs, $configs); + $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); + $container->setParameter('oro_form.autocomplete_entities', $config['autocomplete_entities']); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); } + + /** + * Get a list of configs from all bundles + * + * @param ContainerBuilder $container + * @return array + */ + protected function getBundleConfigs(ContainerBuilder $container) + { + $bundleConfigs = array(); + foreach ($container->getParameter('kernel.bundles') as $bundle) { + $reflection = new \ReflectionClass($bundle); + $file = dirname($reflection->getFilename()) . '/Resources/config/' . self::BUNDLE_CONFIG_FILE; + if (is_file($file)) { + $file = realpath($file); + $bundleConfigs[] = Yaml::parse($file); + $container->addResource(new FileResource($file)); + } + } + return $bundleConfigs; + } } diff --git a/src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/EntitySearchHandler.php b/src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/EntitySearchHandler.php new file mode 100644 index 00000000000..7cdaf19dee6 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/EntitySearchHandler.php @@ -0,0 +1,37 @@ +getRepository($className)->createQueryBuilder('e'); + $this->queryBuilderSearchHandler = new QueryBuilderSearchHandler($queryBuilder, 'e', $searchProperties); + } + + /** + * {@inheritdoc} + */ + public function search($search, $page, $perPage) + { + return $this->queryBuilderSearchHandler->search($search, $page, $perPage); + } +} diff --git a/src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/QueryBuilderSearchHandler.php b/src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/QueryBuilderSearchHandler.php new file mode 100644 index 00000000000..fa976c41259 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/EntityAutocomplete/Doctrine/QueryBuilderSearchHandler.php @@ -0,0 +1,187 @@ +queryBuilder = $queryBuilder; + $this->entityAlias = $entityAlias; + $this->searchPropertiesConfig = $searchProperties; + $this->exprFactory = new Expr(); + } + + + /** + * {@inheritdoc} + */ + public function search($search, $page, $perPage) + { + $queryBuilder = $this->getApplyQueryBuilder(); + $this->applyFiltering($queryBuilder, $search); + $this->applySorting($queryBuilder); + $this->applyPagination($queryBuilder, $page, $perPage); + return $this->getResults($queryBuilder); + } + + /** + * @return QueryBuilder + */ + protected function getApplyQueryBuilder() + { + return clone $this->queryBuilder; + } + + /** + * @param QueryBuilder $queryBuilder + * @param string $query + */ + protected function applyFiltering(QueryBuilder $queryBuilder, $query) + { + $whereSearchExpr = $this->exprFactory->orX(); + $havingSearchExpr = $this->exprFactory->orX(); + + foreach ($this->searchPropertiesConfig as $searchPropertyConfig) { + $expression = $this->createSearchPropertyExpression( + $queryBuilder, + $searchPropertyConfig, + $query + ); + + if ($searchPropertyConfig->getOption('having', false)) { + $havingSearchExpr->add($expression); + } else { + $whereSearchExpr->add($expression); + } + } + + if ($whereSearchExpr->count()) { + $queryBuilder->andWhere($whereSearchExpr); + } + + if ($havingSearchExpr->count()) { + $queryBuilder->andHaving($havingSearchExpr); + } + } + + /** + * @param QueryBuilder $queryBuilder + * @param SearchPropertyConfig $config + * @param string $search + * @return Expr\Base + */ + protected function createSearchPropertyExpression( + QueryBuilder $queryBuilder, + SearchPropertyConfig $config, + $search + ) { + $parameterName = $this->getUniqueParameterName($config); + $propertyPath = $this->getPropertyPath($config); + + switch ($config->getOperatorType()) { + case SearchPropertyConfig::OPERATOR_TYPE_START_WITH: + $result = $this->exprFactory->like($propertyPath, $parameterName); + $queryBuilder->setParameter($parameterName, $search . '%'); + break; + + case SearchPropertyConfig::OPERATOR_TYPE_CONTAINS: default: + $result = $this->exprFactory->like($propertyPath, $parameterName); + $queryBuilder->setParameter($parameterName, '%' . $search . '%'); + break; + } + + return $result; + } + + /** + * @param SearchPropertyConfig $config + * @return string + */ + protected function getUniqueParameterName(SearchPropertyConfig $config) + { + return $config->getProperty() . '_' . $config->getOperatorType() . '_' . $this->uniqueParametersCounter++; + } + + /** + * @param SearchPropertyConfig $config + * @return string + */ + protected function getPropertyPath(SearchPropertyConfig $config) + { + return $config->getOption('entity_alias', $this->entityAlias) . '.' . $config->getProperty(); + } + + /** + * @param QueryBuilder $queryBuilder + */ + protected function applySorting(QueryBuilder $queryBuilder) + { + foreach ($this->searchPropertiesConfig as $searchPropertyConfig) { + $queryBuilder->addOrderBy( + $this->getPropertyPath($searchPropertyConfig), + $searchPropertyConfig->getOption('order', 'ASC') + ); + } + } + + /** + * @param QueryBuilder $queryBuilder + * @param int $page + * @param int $perPage + */ + protected function applyPagination(QueryBuilder $queryBuilder, $page, $perPage) + { + if (null !== $perPage) { + $queryBuilder->setFirstResult($page * $perPage); + $queryBuilder->setMaxResults($perPage); + } else { + $queryBuilder->setFirstResult($page); + } + } + + /** + * @param QueryBuilder $queryBuilder + * @return array + */ + protected function getResults(QueryBuilder $queryBuilder) + { + return $queryBuilder->getQuery()->execute(); + } +} diff --git a/src/Oro/Bundle/FormBundle/EntityAutocomplete/SearchHandlerInterface.php b/src/Oro/Bundle/FormBundle/EntityAutocomplete/SearchHandlerInterface.php new file mode 100644 index 00000000000..ea8a83c04a4 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/EntityAutocomplete/SearchHandlerInterface.php @@ -0,0 +1,16 @@ +options = $options; + } + + /** + * @return string + */ + public function getProperty() + { + return $this->getRequiredOption('property'); + } + + /** + * @return string + */ + public function getOperatorType() + { + return $this->getOption('operator_type', self::OPERATOR_TYPE_CONTAINS); + } + + /** + * @param string $name + * @param mixed $default + * @return mixed + */ + public function getOption($name, $default = null) + { + if (array_key_exists($name, $this->options)) { + return $this->options[$name]; + } + return $default; + } + + /** + * @param string $name + * @return mixed + * @throws \LogicException + */ + public function getRequiredOption($name) + { + if (array_key_exists($name, $this->options)) { + return $this->options[$name]; + } else { + throw new \LogicException("Option '$name' of search property config has no value."); + } + } +} From aa75c00c709ffd70d055d632341e54ec26e544fe Mon Sep 17 00:00:00 2001 From: Roman Grebenchuk Date: Fri, 31 May 2013 16:36:44 +0300 Subject: [PATCH 028/394] BAP-887 Run functional and unit test with GitLab - fixed selenium tests --- .../Bundle/TestFrameworkBundle/Pages/Objects/Group.php | 2 +- .../Bundle/TestFrameworkBundle/Pages/Objects/Search.php | 4 ++-- src/Oro/Bundle/TestFrameworkBundle/Pages/Page.php | 8 ++++++-- src/Oro/Bundle/TestFrameworkBundle/Pages/PageGrid.php | 3 +++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Group.php b/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Group.php index fa7fa9050b5..c53a205aa9b 100644 --- a/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Group.php +++ b/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Group.php @@ -50,7 +50,7 @@ public function save() public function close() { - $this->byXPath("//button[@class ='ui-dialog-titlebar-close']")->click(); + //$this->byXPath("//button[@class ='ui-dialog-titlebar-close']")->click(); //support return to groups page only return new Groups($this->test, false); } diff --git a/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Search.php b/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Search.php index 2bf8d5db7ba..c0033560887 100644 --- a/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Search.php +++ b/src/Oro/Bundle/TestFrameworkBundle/Pages/Objects/Search.php @@ -38,9 +38,9 @@ public function suggestions($filter = null) public function result($filter) { if (!is_null($filter)) { - $result = $this->elements($this->using("xpath")->value("//div[@class= 'container-fluid']/div/h3/a[contains(., '{$filter}')]")); + $result = $this->elements($this->using("xpath")->value("//div[@id='oro_search_resultsDatagridBody']//tr//h1/a[contains(., '{$filter}')]")); } else { - $result = $this->elements($this->using("xpath")->value("//div[@class= 'container-fluid']/div/h3/a")); + $result = $this->elements($this->using("xpath")->value("//div[@id='oro_search_resultsDatagridBody']//tr//h1/a")); } return $result; diff --git a/src/Oro/Bundle/TestFrameworkBundle/Pages/Page.php b/src/Oro/Bundle/TestFrameworkBundle/Pages/Page.php index 9b2ecfafb54..efdb73f2fa6 100644 --- a/src/Oro/Bundle/TestFrameworkBundle/Pages/Page.php +++ b/src/Oro/Bundle/TestFrameworkBundle/Pages/Page.php @@ -133,8 +133,12 @@ public function assertTitle($title, $message = '') public function assertMessage($messageText, $message = '') { PHPUnit_Framework_Assert::assertTrue( - $this->isElementPresent("//div[contains(@class,'alert') and contains(., '{$messageText}')]"), - $message + $this->isElementPresent("//div[contains(@class,'alert') and not(contains(@class, 'alert-empty'))]"), + 'Flash message is missing' + ); + $actualResult = $this->byXPath("//div[contains(@class,'alert') and not(contains(@class, 'alert-empty'))]/div")->text(); + + PHPUnit_Framework_Assert::assertEquals($messageText, $actualResult, $message ); return $this; } diff --git a/src/Oro/Bundle/TestFrameworkBundle/Pages/PageGrid.php b/src/Oro/Bundle/TestFrameworkBundle/Pages/PageGrid.php index 897b21f167b..92d9872f902 100644 --- a/src/Oro/Bundle/TestFrameworkBundle/Pages/PageGrid.php +++ b/src/Oro/Bundle/TestFrameworkBundle/Pages/PageGrid.php @@ -40,12 +40,15 @@ public function getRandomEntity($pageSize = 10) public function changePage($page = 1) { $pager = $this->byXPath("{$this->filtersPath}//div[contains(@class,'pagination')]/ul//input"); + $pagerLabel = $this->byXPath("{$this->filtersPath}//div[contains(@class,'pagination')]/label[@class = 'dib' and text() = 'Page:']"); //set focus $pager->click(); //clear field $this->clearInput($pager); $pager->value($page); + //simulate lost focus $this->keysSpecial('enter'); + $pagerLabel->click(); $this->waitForAjax(); return $this; } From 4d34666b82af574b0bdfd687f4451e122fef6ad0 Mon Sep 17 00:00:00 2001 From: Dmitry Khrysev Date: Fri, 31 May 2013 16:41:32 +0300 Subject: [PATCH 029/394] CRM-110: combobox for remote data with datagrid source --- .../AddressBundle/Form/Type/CountryType.php | 7 +- src/Oro/Bundle/AddressBundle/composer.json | 1 + .../FormBundle/Resources/config/services.yml | 1 + .../Resources/views/Form/fields.html.twig | 90 +++ .../public/css/select2/select2-spinner.gif | Bin 0 -> 1849 bytes .../Resources/public/css/select2/select2.css | 652 ++++++++++++++++++ .../Resources/public/css/select2/select2.png | Bin 0 -> 613 bytes .../public/css/select2/select2x2.png | Bin 0 -> 845 bytes .../UIBundle/Resources/public/js/layout.js | 2 +- .../public/lib/jquery/select2.min.js | 22 + .../UserBundle/Form/Type/UserSelectType.php | 19 +- 11 files changed, 783 insertions(+), 11 deletions(-) create mode 100644 src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig create mode 100644 src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2-spinner.gif create mode 100644 src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2.css create mode 100644 src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2.png create mode 100644 src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2x2.png create mode 100644 src/Oro/Bundle/UIBundle/Resources/public/lib/jquery/select2.min.js diff --git a/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php b/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php index 58cebad248b..8e51df89f4f 100644 --- a/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php +++ b/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php @@ -16,7 +16,10 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) return $er->createQueryBuilder('c') ->orderBy('c.name', 'ASC'); }, - 'empty_value' => 'Choose a country...', + 'configs' => array( + 'placeholder' => 'Choose a country...' + ), + 'empty_value' => '', 'empty_data' => null ) ); @@ -24,7 +27,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) public function getParent() { - return 'entity'; + return 'genemu_jqueryselect2_entity'; } public function getName() diff --git a/src/Oro/Bundle/AddressBundle/composer.json b/src/Oro/Bundle/AddressBundle/composer.json index 1de58a3bc06..22244d8f970 100644 --- a/src/Oro/Bundle/AddressBundle/composer.json +++ b/src/Oro/Bundle/AddressBundle/composer.json @@ -14,6 +14,7 @@ "friendsofsymfony/jsrouting-bundle": "1.1.*@dev", "nelmio/api-doc-bundle": "dev-master", "oro/flexible-entity-bundle": "dev-master", + "oro/form-bundle": "dev-master", "besimple/soap-bundle": "dev-master" }, "autoload": { diff --git a/src/Oro/Bundle/FormBundle/Resources/config/services.yml b/src/Oro/Bundle/FormBundle/Resources/config/services.yml index 0fcc7d3523a..832025cbb4d 100644 --- a/src/Oro/Bundle/FormBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/FormBundle/Resources/config/services.yml @@ -1,6 +1,7 @@ parameters: oro_form.type.date.class: Oro\Bundle\FormBundle\Form\Type\OroDateType oro_form.type.datetime.class: Oro\Bundle\FormBundle\Form\Type\OroDateTimeType + oro_form.type.combobox_local.class: Oro\Bundle\FormBundle\Form\Type\OroComboboxLocalType oro_form.type.entity_identifier.class: Oro\Bundle\FormBundle\Form\Type\EntityIdentifierType services: diff --git a/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig b/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig new file mode 100644 index 00000000000..b0bb52a7583 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig @@ -0,0 +1,90 @@ +{% block oro_ticker_symbol_widget %} + + + {{ form_widget(form) }} +{% endblock %} + +{% block genemu_jqueryselect2_javascript %} + +{% endblock %} + +{% block oro_combobox_dataconfig_grid %} + {% set url = configs.ajax.url is defined ? configs.ajax.url : path(configs.route, {'_format': 'json'}) %} + + select2Config.ajax = { + 'url': {{ url|json_encode|raw }}, + 'type': 'GET', + 'data': function (query, page) { + return { + '{{ configs.grid.name }}[_pager][_page]': page, + '{{ configs.grid.name }}[_pager][_per_page]': {{ configs.grid.per_page|default(10) }}, + '{{ configs.grid.name }}[_sort_by][{{ configs.grid.sort_by|default(configs.grid.property) }}]': "{{ configs.grid.sort_order|default('ASC') }}", + '{{ configs.grid.name }}[_filter][{{ configs.grid.property }}][type]': 1, + '{{ configs.grid.name }}[_filter][{{ configs.grid.property }}][value]': query + }; + }, + 'results': function (data, page) { + return { + results: $.map(data.data, function(item) { + return {'id': item.id, 'text': item.{{- configs.grid.property -}} }; + }), + more: page*10 < data.options.totalRecords + }; + } + } +{% endblock %} diff --git a/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2-spinner.gif b/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2-spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2.css b/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2.css new file mode 100644 index 00000000000..abe59c9554b --- /dev/null +++ b/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2.css @@ -0,0 +1,652 @@ +/* +Version: 3.4.0 Timestamp: Tue May 14 08:27:33 PDT 2013 +*/ +.select2-container { + margin: 0; + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + vertical-align: middle; +} + +.select2-container, +.select2-drop, +.select2-search, +.select2-search input{ + /* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + + More Info : http://www.quirksmode.org/css/box.html + */ + -webkit-box-sizing: border-box; /* webkit */ + -khtml-box-sizing: border-box; /* konqueror */ + -moz-box-sizing: border-box; /* firefox */ + -ms-box-sizing: border-box; /* ie */ + box-sizing: border-box; /* css3 */ +} + +.select2-container .select2-choice { + display: block; + height: 26px; + padding: 0 0 0 8px; + overflow: hidden; + position: relative; + + border: 1px solid #aaa; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white)); + background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 50%); + background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 50%); + background-image: -o-linear-gradient(bottom, #eeeeee 0%, #ffffff 50%); + background-image: -ms-linear-gradient(top, #ffffff 0%, #eeeeee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(top, #ffffff 0%, #eeeeee 50%); +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #aaa; + + -webkit-border-radius:0 0 4px 4px; + -moz-border-radius:0 0 4px 4px; + border-radius:0 0 4px 4px; + + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.9, white)); + background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 90%); + background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 90%); + background-image: -o-linear-gradient(bottom, #eeeeee 0%, white 90%); + background-image: -ms-linear-gradient(top, #eeeeee 0%,#ffffff 90%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); + background-image: linear-gradient(top, #eeeeee 0%,#ffffff 90%); +} + +.select2-container.select2-allowclear .select2-choice span { + margin-right: 42px; +} + +.select2-container .select2-choice span { + margin-right: 26px; + display: block; + overflow: hidden; + + white-space: nowrap; + + -ms-text-overflow: ellipsis; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; +} + +.select2-container .select2-choice abbr { + display: none; + width: 12px; + height: 12px; + position: absolute; + right: 24px; + top: 8px; + + font-size: 1px; + text-decoration: none; + + border: 0; + background: url('select2.png') right top no-repeat; + cursor: pointer; + outline: 0; +} + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-drop-mask { + position: absolute; + left: 0; + top: 0; + z-index: 9998; +} + +.select2-drop { + width: 100%; + margin-top:-1px; + position: absolute; + z-index: 9999; + top: 100%; + + background: #fff; + color: #000; + border: 1px solid #aaa; + border-top: 0; + + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; + + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-auto-width { + border-top: 1px solid #aaa; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + +.select2-drop.select2-drop-above { + margin-top: 1px; + border-top: 1px solid #aaa; + border-bottom: 0; + + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; + + -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + -moz-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); +} + +.select2-container .select2-choice div { + display: inline-block; + width: 18px; + height: 100%; + position: absolute; + right: 0; + top: 0; + + border-left: 1px solid #aaa; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; + + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -o-linear-gradient(bottom, #ccc 0%, #eee 60%); + background-image: -ms-linear-gradient(top, #cccccc 0%, #eeeeee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); + background-image: linear-gradient(top, #cccccc 0%, #eeeeee 60%); +} + +.select2-container .select2-choice div b { + display: block; + width: 100%; + height: 100%; + background: url('select2.png') no-repeat 0 1px; +} + +.select2-search { + display: inline-block; + width: 100%; + min-height: 26px; + margin: 0; + padding-left: 4px; + padding-right: 4px; + + position: relative; + z-index: 10000; + + white-space: nowrap; +} + +.select2-search input { + width: 100%; + height: auto !important; + min-height: 26px; + padding: 4px 20px 4px 5px; + margin: 0; + + outline: 0; + font-family: sans-serif; + font-size: 1em; + + border: 1px solid #aaa; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + + background: #fff url('select2.png') no-repeat 100% -22px; + background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); + background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%, #eeeeee 99%); +} + +.select2-drop.select2-drop-above .select2-search input { + margin-top: 4px; +} + +.select2-search input.select2-active { + background: #fff url('select2-spinner.gif') no-repeat 100%; + background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); + background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('select2-spinner.gif') no-repeat 100%, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); + background: url('select2-spinner.gif') no-repeat 100%, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); + background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(top, #ffffff 85%, #eeeeee 99%); +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); + -moz-box-shadow: 0 0 5px rgba(0,0,0,.3); + box-shadow: 0 0 5px rgba(0,0,0,.3); +} + +.select2-dropdown-open .select2-choice { + border-bottom-color: transparent; + -webkit-box-shadow: 0 1px 0 #fff inset; + -moz-box-shadow: 0 1px 0 #fff inset; + box-shadow: 0 1px 0 #fff inset; + + -webkit-border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; + border-bottom-left-radius: 0; + + -webkit-border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; + border-bottom-right-radius: 0; + + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee)); + background-image: -webkit-linear-gradient(center bottom, white 0%, #eeeeee 50%); + background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%); + background-image: -o-linear-gradient(bottom, white 0%, #eeeeee 50%); + background-image: -ms-linear-gradient(top, #ffffff 0%,#eeeeee 50%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); + background-image: linear-gradient(top, #ffffff 0%,#eeeeee 50%); +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid #5897fb; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, white), color-stop(0.5, #eeeeee)); + background-image: -webkit-linear-gradient(center top, white 0%, #eeeeee 50%); + background-image: -moz-linear-gradient(center top, white 0%, #eeeeee 50%); + background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%); + background-image: -ms-linear-gradient(bottom, #ffffff 0%,#eeeeee 50%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); + background-image: linear-gradient(bottom, #ffffff 0%,#eeeeee 50%); +} + +.select2-dropdown-open .select2-choice div { + background: transparent; + border-left: none; + filter: none; +} +.select2-dropdown-open .select2-choice div b { + background-position: -18px 1px; +} + +/* results */ +.select2-results { + max-height: 200px; + padding: 0 0 0 4px; + margin: 4px 4px 4px 0; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-tap-highlight-color: rgba(0,0,0,0); +} + +.select2-results ul.select2-result-sub { + margin: 0; + padding-left: 0; +} + +.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px } +.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px } + +.select2-results li { + list-style: none; + display: list-item; + background-image: none; +} + +.select2-results li.select2-result-with-children > .select2-result-label { + font-weight: bold; +} + +.select2-results .select2-result-label { + padding: 3px 7px 4px; + margin: 0; + cursor: pointer; + + min-height: 1em; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} + +.select2-results li em { + background: #feffde; + font-style: normal; +} + +.select2-results .select2-highlighted em { + background: transparent; +} + +.select2-results .select2-highlighted ul { + background: white; + color: #000; +} + + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-selection-limit { + background: #f4f4f4; + display: list-item; +} + +/* +disabled look for disabled choices in the results dropdown +*/ +.select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + +.select2-results .select2-selected { + display: none; +} + +.select2-more-results.select2-active { + background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%; +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* disabled styles */ + +.select2-container.select2-container-disabled .select2-choice { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container.select2-container-disabled .select2-choice div { + background-color: #f4f4f4; + background-image: none; + border-left: 0; +} + +.select2-container.select2-container-disabled .select2-choice abbr { + display: none; +} + + +/* multiselect */ + +.select2-container-multi .select2-choices { + height: auto !important; + height: 1%; + margin: 0; + padding: 0; + position: relative; + + border: 1px solid #aaa; + cursor: text; + overflow: hidden; + + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: linear-gradient(top, #eeeeee 1%, #ffffff 15%); +} + +.select2-locked { + padding: 3px 5px 3px 5px !important; +} + +.select2-container-multi .select2-choices { + min-height: 26px; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); + -moz-box-shadow: 0 0 5px rgba(0,0,0,.3); + box-shadow: 0 0 5px rgba(0,0,0,.3); +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +.select2-container-multi .select2-choices .select2-search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.select2-container-multi .select2-choices .select2-search-field input { + padding: 5px; + margin: 1px 0; + + font-family: sans-serif; + font-size: 100%; + color: #666; + outline: 0; + border: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + background: transparent !important; +} + +.select2-container-multi .select2-choices .select2-search-field input.select2-active { + background: #fff url('select2-spinner.gif') no-repeat 100% !important; +} + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + + line-height: 13px; + color: #333; + cursor: default; + border: 1px solid #aaaaaa; + + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + + -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + -moz-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0 ); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -ms-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); +} +.select2-container-multi .select2-choices .select2-search-choice span { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + width: 12px; + height: 13px; + position: absolute; + right: 3px; + top: 4px; + + font-size: 1px; + outline: none; + background: url('select2.png') right top no-repeat; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + +/* disabled styles */ +.select2-container-multi.select2-container-disabled .select2-choices{ + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { + padding: 3px 5px 3px 5px; + border: 1px solid #ddd; + background-image: none; + background-color: #f4f4f4; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background:none; +} +/* end multiselect */ + + +.select2-result-selectable .select2-match, +.select2-result-unselectable .select2-match { + text-decoration: underline; +} + +.select2-offscreen, .select2-offscreen:focus { + clip: rect(0 0 0 0); + width: 1px; + height: 1px; + border: 0; + margin: 0; + padding: 0; + overflow: hidden; + position: absolute; + outline: 0; + left: 0px; +} + +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} +/* Retina-ize icons */ + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { + .select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice div b { + background-image: url('select2x2.png') !important; + background-repeat: no-repeat !important; + background-size: 60px 40px !important; + } + .select2-search input { + background-position: 100% -21px !important; + } +} diff --git a/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2.png b/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2.png new file mode 100644 index 0000000000000000000000000000000000000000..1d804ffb99699b9e030f1010314de0970b5a000d GIT binary patch literal 613 zcmV-r0-F7aP)#WY!I$JQV$)A5aAS1BM||2XVJl=+L1^1S1H% zM-&lx?NZpUrHhn>fk<>POqf2sh40}xxGZfc+t+#Eb(qHy9_3*1(U%t9t)QDnI#YAL(|ACV(>)>6WD-t!8tutHkdb^#3`HzoJG3A2@T`% zA|K@o*b!`R#(7)PWrMFn2))Ca3MR4(zaT`Zr61*kZK5NPnZwQszxh$fyv3?&4c>$q z2m=+yc0dRXRAsPDxF6sD;@rK4JGdR_``1S~o6Xi@2&aR6hcSrEp9HVRzEqVDqBn<1%hR=D4e1f^ra^A|34Cjc=Gny{F(o#MrvPYgZuTJOz(n)-F<| zj()qR;C={)N<0RRvDZ^@6ND+W*}gh-Lip(MDt!(zMSO)!j2j+*hxgzC-e3$@(O2p* zu;+gddm(cZwXTCLx*Ky4THOa*^b^F`woveIeCK^0aR|TJ00000NkvXXu0mjfA#WC6 literal 0 HcmV?d00001 diff --git a/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2x2.png b/src/Oro/Bundle/UIBundle/Resources/public/css/select2/select2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..4bdd5c961d452c49dfa0789c2c7ffb82c238fc24 GIT binary patch literal 845 zcmV-T1G4;yP)upQ6WKflyv?C|ADVW!U!t`EpA+x zB)5#EjWk-_X77YJZtQo`E0SF)^1bZr%)B7Cd`*OK*r z5WG-7e-R9G9^69ksDt29&oyHqxPSt|-S>xi3%PTd+GjY+BGF|nWC(7D-sd(kxqd9~ zS@2YF5vB+>dP8+$l^{oO3-lEWiGA*QIU)Wds#9M6RZ9N zcQ4y4)xqQOxD=vwu%7cz1nY#$lT&y8HCmkWgpwQP#3dhnYj9|2aS_R}IUF_^6s#$= zTm%~>A#oM?KIg$kh=<`gJkeoHa2LrulVy$Yx+N_0R3$4I!R*0677f(FKqm`2_o4~W z0h}fQZ`lC^1A+m;fM7uI(R1`S0KtG@KrkQ}5DW+&@cTnDVIow56KciMk7a899t0bC zC1KI{TsMe5NAR%GD_5`B-@ad4k~K3SO%H z_M31|`HV?E6)u$E3c&*<*n20+V@mRCop>R5;DWuZCmjSo7p@R&OYl^@G++d&&(c.context=c[0]=this[d])&&b.call(c[0],d,c)!==!1;);return this}})})(jQuery),function(a,b){"use strict";function m(a,b){for(var c=0,d=b.length;d>c;c+=1)if(o(a,b[c]))return c;return-1}function n(){var b=a(l);b.appendTo("body");var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function o(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function p(b,c){var d,e,f;if(null===b||1>b.length)return[];for(d=b.split(c),e=0,f=d.length;f>e;e+=1)d[e]=a.trim(d[e]);return d}function q(a){return a.outerWidth(!1)-a.width()}function r(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function s(c){c.on("mousemove",function(c){var d=i;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function t(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function u(a){var c,b=!1;return function(){return b===!1&&(c=a(),b=!0),c}}function v(a,b){var c=t(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){m(a.target,b.get())>=0&&c(a)})}function w(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus(),a.is(":visible")&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function x(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function y(a){a.preventDefault(),a.stopPropagation()}function z(a){a.preventDefault(),a.stopImmediatePropagation()}function A(b){if(!h){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);h=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),h.attr("class","select2-sizer"),a("body").append(h)}return h.text(b.val()),h.width()}function B(b,c,d){var e,g,f=[];e=b.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=c.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(this))})),b.attr("class",f.join(" "))}function C(a,c,d,e){var f=a.toUpperCase().indexOf(c.toUpperCase()),g=c.length;return 0>f?(d.push(e(a)),b):(d.push(e(a.substring(0,f))),d.push(""),d.push(e(a.substring(f,f+g))),d.push(""),d.push(e(a.substring(f+g,a.length))),b)}function D(c){var d,e=0,f=null,g=c.quietMillis||100,h=c.url,i=this;return function(j){window.clearTimeout(d),d=window.setTimeout(function(){e+=1;var d=e,g=c.data,k=h,l=c.transport||a.fn.select2.ajaxDefaults.transport,m={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},n=a.extend({},a.fn.select2.ajaxDefaults.params,m);g=g?g.call(i,j.term,j.page,j.context):null,k="function"==typeof k?k.call(i,j.term,j.page,j.context):k,null!==f&&f.abort(),c.params&&(a.isFunction(c.params)?a.extend(n,c.params.call(i)):a.extend(n,c.params)),a.extend(n,{url:k,dataType:c.dataType,data:g,success:function(a){if(!(e>d)){var b=c.results(a,j.page);j.callback(b)}}}),f=l.call(i,n)},g)}}function E(c){var e,f,d=c,g=function(a){return""+a.text};a.isArray(d)&&(f=d,d={results:f}),a.isFunction(d)===!1&&(f=d,d=function(){return f});var h=d();return h.text&&(g=h.text,a.isFunction(g)||(e=h.text,g=function(a){return a[e]})),function(c){var h,e=c.term,f={results:[]};return""===e?(c.callback(d()),b):(h=function(b,d){var f,i;if(b=b[0],b.children){f={};for(i in b)b.hasOwnProperty(i)&&(f[i]=b[i]);f.children=[],a(b.children).each2(function(a,b){h(b,f.children)}),(f.children.length||c.matcher(e,g(f),b))&&d.push(f)}else c.matcher(e,g(b),b)&&d.push(b)},a(d().results).each2(function(a,b){h(b,f.results)}),c.callback(f),b)}}function F(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]};a(d?c():c).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g)}}function G(b){if(a.isFunction(b))return!0;if(!b)return!1;throw Error("formatterName must be a function or a falsy value")}function H(b){return a.isFunction(b)?b():b}function I(b){var c=0;return a.each(b,function(a,b){b.children?c+=I(b.children):c++}),c}function J(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||1>e.tokenSeparators.length)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice(h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(o(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:b}function K(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,h,i,j,k,c={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case c.LEFT:case c.RIGHT:case c.UP:case c.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case c.SHIFT:case c.CTRL:case c.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="
";j=a(document),g=function(){var a=1;return function(){return a++}}(),j.on("mousemove",function(a){i={x:a.pageX,y:a.pageY}}),d=K(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,h,i,f=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&this.destroy(),this.container=this.createContainer(),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+g()),this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.body=u(function(){return c.element.closest("body")}),B(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.css(H(c.containerCss)),this.container.addClass(H(c.containerCssClass)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),this.dropdown.addClass(H(c.dropdownCssClass)),this.dropdown.data("select2",this),this.results=d=this.container.find(f),this.search=e=this.container.find("input.select2-input"),this.resultsPage=0,this.context=null,this.initContainer(),s(this.results),this.dropdown.on("mousemove-filtered touchstart touchmove touchend",f,this.bind(this.highlightUnderEvent)),v(80,this.results),this.dropdown.on("scroll-debounced",f,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),y(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),y(a))}),r(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",f,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown",function(a){a.stopPropagation()}),a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),k=k||n(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus()},destroy:function(){var a=this.opts.element.data("select2");this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),a!==b&&(a.container.remove(),a.dropdown.remove(),a.opts.element.removeClass("select2-offscreen").removeData("select2").off(".select2").attr({tabindex:this.elementTabIndex}).prop("autofocus",this.autofocus||!1).show())},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:o(a.attr("locked"),"locked")}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:b},prepareOpts:function(c){var d,e,f,g,h=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw Error("Option '"+this+"' is not allowed for Select2 when attached to a ","
"," ","
    ","
","
"].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var b,c;this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.search.focus(),b=this.search.get(0),b.createTextRange&&(c=b.createTextRange(),c.collapse(!1),c.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.removeAttr("disabled"),this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.removeAttr("disabled"),this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.removeAttr("disabled"),this.focusser.focus()},initContainer:function(){var d,e=this.container,f=this.dropdown;this.showSearch(!1),this.selection=d=e.find(".select2-choice"),this.focusser=e.find(".select2-focusser"),this.focusser.attr("id","s2id_autogen"+g()),a("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.focusser.attr("id")),this.focusser.attr("tabindex",this.elementTabIndex),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){if(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)return y(a),b;switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),y(a),b;case c.ENTER:return this.selectHighlighted(),y(a),b;case c.TAB:return this.selectHighlighted({noFocus:!0}),b;case c.ESC:return this.cancel(a),y(a),b}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body().get(0)&&window.setTimeout(this.bind(function(){this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){return!this.isInterfaceEnabled()||a.which===c.TAB||c.isControl(a)||c.isFunctionKey(a)||a.which===c.ESC?b:this.opts.openOnEnter===!1&&a.which===c.ENTER?(y(a),b):a.which==c.DOWN||a.which==c.UP||a.which==c.ENTER&&this.opts.openOnEnter?(this.open(),y(a),b):a.which==c.DELETE||a.which==c.BACKSPACE?(this.opts.allowClear&&this.clear(),y(a),b):b})),r(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){a.stopPropagation(),this.opened()||this.open()})),d.on("mousedown","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),z(a),this.close(),this.selection.focus())})),d.on("mousedown",this.bind(function(b){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),y(b)})),f.on("mousedown",this.bind(function(){this.search.focus()})),d.on("focus",this.bind(function(a){y(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.setPlaceholder()},clear:function(a){var b=this.selection.data("select2-data");b&&(this.opts.element.val(""),this.selection.find("span").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),a!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(b),choice:b}),this.triggerChange({removed:b})))},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text())this.updateSelection([]),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder())})}},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find(":selected");b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=o(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&""!==this.select.find("option").first().text()?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(""===this.opts.element.val()&&a!==b){if(this.select&&""!==this.select.find("option:first").text())return;this.selection.find("span").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,c,d){var e=0,f=this;if(this.findHighlightableChoices().each2(function(a,c){return o(f.id(c.data("select2-data")),f.opts.element.val())?(e=a,!1):b}),d!==!1&&this.highlight(e),c===!0&&this.showSearchInput===!1){var h=this.opts.minimumResultsForSearch;h>=0&&this.showSearch(I(a.results)>=h)}},showSearch:function(b){this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b)},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.close(),b&&b.noFocus||this.selection.focus(),o(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,c=this.selection.find("span");this.selection.data("select2-data",a),c.empty(),d=this.opts.formatSelection(a,c),d!==b&&c.append(this.opts.escapeMarkup(d)),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find(":selected").each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(this.opts.initSelection===b)throw Error("cannot call val() if initSelection() is not defined");if(!a&&0!==a)return this.clear(c),b;this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a,c){var d;return 0===arguments.length?(d=this.selection.data("select2-data"),d==b&&(d=null),d):(a&&""!==a?(d=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),c&&this.triggerChange({added:a,removed:d})):this.clear(c),b)}}),f=K(d,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["
    ","
  • "," ","
  • ","
","
","
    ","
","
"].join("")); +return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find(":selected").each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=p(c.val(),b.separator),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return o(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;e.length>c;c++)for(var g=e[c],h=0;f.length>h;h++){var i=f[h];if(o(g,b.id(i))){a.push(i),f.splice(h,1);break}}d(a)}:a.noop})}),b},selectChoice:function(a){var b=this.container.find(".select2-search-choice-focus");b.length&&a&&a[0]==b[0]||(b.length&&this.opts.element.trigger("choice-deselected",b),b.removeClass("select2-search-choice-focus"),a&&a.length&&(this.close(),a.addClass("select2-search-choice-focus"),this.opts.element.trigger("choice-selected",a)))},initContainer:function(){var e,d=".select2-choices";this.searchContainer=this.container.find(".select2-search-field"),this.selection=e=this.container.find(d);var f=this;this.selection.on("mousedown",".select2-search-choice",function(){f.search[0].focus(),f.selectChoice(a(this))}),this.search.attr("id","s2id_autogen"+g()),a("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.search.attr("id")),this.search.on("input paste",this.bind(function(){this.isInterfaceEnabled()&&(this.opened()||this.open())})),this.search.attr("tabindex",this.elementTabIndex),this.keydowns=0,this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){++this.keydowns;var d=e.find(".select2-search-choice-focus"),f=d.prev(".select2-search-choice:not(.select2-locked)"),g=d.next(".select2-search-choice:not(.select2-locked)"),h=x(this.search);if(d.length&&(a.which==c.LEFT||a.which==c.RIGHT||a.which==c.BACKSPACE||a.which==c.DELETE||a.which==c.ENTER)){var i=d;return a.which==c.LEFT&&f.length?i=f:a.which==c.RIGHT?i=g.length?g:null:a.which===c.BACKSPACE?(this.unselect(d.first()),this.search.width(10),i=f.length?f:g):a.which==c.DELETE?(this.unselect(d.first()),this.search.width(10),i=g.length?g:null):a.which==c.ENTER&&(i=null),this.selectChoice(i),y(a),i&&i.length||this.open(),b}if((a.which===c.BACKSPACE&&1==this.keydowns||a.which==c.LEFT)&&0==h.offset&&!h.length)return this.selectChoice(e.find(".select2-search-choice:not(.select2-locked)").last()),y(a),b;if(this.selectChoice(null),this.opened())switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),y(a),b;case c.ENTER:return this.selectHighlighted(),y(a),b;case c.TAB:return this.selectHighlighted({noFocus:!0}),b;case c.ESC:return this.cancel(a),y(a),b}if(a.which!==c.TAB&&!c.isControl(a)&&!c.isFunctionKey(a)&&a.which!==c.BACKSPACE&&a.which!==c.ESC){if(a.which===c.ENTER){if(this.opts.openOnEnter===!1)return;if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return}this.open(),(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)&&y(a),a.which===c.ENTER&&y(a)}}})),this.search.on("keyup",this.bind(function(){this.keydowns=0,this.resizeSearch()})),this.search.on("blur",this.bind(function(b){this.container.removeClass("select2-container-active"),this.search.removeClass("select2-focused"),this.selectChoice(null),this.opened()||this.clearSearch(),b.stopImmediatePropagation(),this.opts.element.trigger(a.Event("select2-blur"))})),this.container.on("mousedown",d,this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").length>0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",d,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),this.updateResults(!0),this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){0>m(e.id(this),c)&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer(a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,b){this.triggerSelect(a)&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()&&this.updateResults(!0),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),b&&b.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,d=!c.locked,e=a("
  • "),f=a("
  • "),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div")),j!=b&&g.find("div").replaceWith("
    "+this.opts.escapeMarkup(j)+"
    "),d&&g.find(".select2-search-choice-close").on("mousedown",y).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").fadeOut("fast",this.bind(function(){this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),this.close(),this.focusSearch()})).dequeue(),y(b))})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(a){var c,d,b=this.getVal();if(a=a.closest(".select2-search-choice"),0===a.length)throw"Invalid argument: "+a+". Must be .select2-search-choice";c=a.data("select2-data"),c&&(d=m(this.id(c),b),d>=0&&(b.splice(d,1),this.setVal(b),this.select&&this.postprocessResults()),a.remove(),this.opts.element.trigger({type:"removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));m(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&this.results.append("
  • "+g.opts.formatNoMatches(g.search.val())+"
  • ")},getMaxSearchWidth:function(){return this.selection.width()-q(this.search)},resizeSearch:function(){var a,b,c,d,e,f=q(this.search);a=A(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(e)},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),p(a,this.opts.separator))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){0>m(this,c)&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;b.length>c;c++)for(var d=0;a.length>d;d++)o(this.opts.id(b[c]),this.opts.id(a[d]))&&(b.splice(c,1),c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),b;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a(b).map(f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(this.buildChangeDetails(e,this.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw Error("Sorting of elements is not supported when attached to instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(c,d){var f,g,e=this;return 0===arguments.length?this.selection.find(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(g=this.data(),c||(c=[]),f=a.map(c,function(a){return e.opts.id(a)}),this.setVal(f),this.updateSelection(c),this.clearSearch(),d&&this.triggerChange(this.buildChangeDetails(g,this.data())),b)}}),a.fn.select2=function(){var d,g,h,i,c=Array.prototype.slice.call(arguments,0),j=["val","destroy","opened","open","close","focus","isFocused","container","onSortStart","onSortEnd","enable","readonly","positionDropdown","data"],k=["val","opened","isFocused","container","data"];return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?i=d.element.prop("multiple"):(i=d.multiple||!1,"tags"in d&&(d.multiple=i=!0)),g=i?new f:new e,g.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(0>m(c[0],j))throw"Unknown method: "+c[0];if(h=b,g=a(this).data("select2"),g===b)return;if(h="container"===c[0]?g.container:g[c[0]].apply(g,c.slice(1)),m(c[0],k)>=0)return!1}}),h===b?this:h},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return C(a.text,c.term,e,d),e.join("")},formatSelection:function(a){return a?a.text:b},sortResults:function(a){return a},formatResultCssClass:function(){return b},formatNoMatches:function(){return"No matches found"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results..."},formatSearching:function(){return"Searching..."},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a.id},matcher:function(a,b){return(""+b).toUpperCase().indexOf((""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:J,escapeMarkup:function(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return(a+"").replace(/[&<>"'\/\\]/g,function(a){return b[a]})},blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null}},a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:D,local:E,tags:F},util:{debounce:t,markMatch:C},"class":{"abstract":d,single:e,multi:f}}}}(jQuery); \ No newline at end of file diff --git a/src/Oro/Bundle/UserBundle/Form/Type/UserSelectType.php b/src/Oro/Bundle/UserBundle/Form/Type/UserSelectType.php index 6d9d5b783b6..dec926cf015 100644 --- a/src/Oro/Bundle/UserBundle/Form/Type/UserSelectType.php +++ b/src/Oro/Bundle/UserBundle/Form/Type/UserSelectType.php @@ -1,7 +1,6 @@ setDefaults( array( - 'class' => 'OroUserBundle:User', - 'query_builder' => function (EntityRepository $er) { - return $er->createQueryBuilder('u') - ->orderBy('u.username', 'ASC'); - }, - 'empty_value' => 'Choose a user...', + 'configs' => array( + 'placeholder' => 'Choose a user...', + 'datasource' => 'grid', + 'route' => 'oro_user_index', + 'grid' => array( + 'name' => 'users', + 'property' => 'username' + ) + ), + 'empty_value' => '', 'empty_data' => null ) ); @@ -24,7 +27,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) public function getParent() { - return 'entity'; + return 'genemu_jqueryselect2_hidden'; } /** From 6094b9d95a69ce70e22ad8e23976919b032d8ef4 Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 31 May 2013 16:55:30 +0300 Subject: [PATCH 030/394] BAP-893: Entities configuration --- .../DependencyInjection/Configuration.php | 13 ++- .../OroConfigExtension.php | 20 +++- .../Resources/config/services.yml | 2 +- .../ConfigBundle/Twig/ConfigExtension.php | 33 +++++- .../Resources/views/Default/index.html.twig | 4 +- .../Resources/config/entity_output.yml | 14 +++ .../Resources/translations/config.en.yml | 12 +++ .../views/Reset/checkEmail.html.twig | 2 +- .../Resources/views/Reset/reset.html.twig | 2 +- .../Resources/views/Security/login.html.twig | 2 +- .../views/User/searchResult.html.twig | 102 +++++++++--------- .../Resources/views/User/update.html.twig | 18 ++-- .../Resources/views/User/view.html.twig | 2 +- 13 files changed, 154 insertions(+), 72 deletions(-) create mode 100644 src/Oro/Bundle/UserBundle/Resources/config/entity_output.yml create mode 100644 src/Oro/Bundle/UserBundle/Resources/translations/config.en.yml diff --git a/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php b/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php index 4612d396be3..0f01cdf50a8 100644 --- a/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php +++ b/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php @@ -13,7 +13,18 @@ class Configuration implements ConfigurationInterface public function getConfigTreeBuilder() { $builder = new TreeBuilder(); - $root = $builder->root('oro_config'); + $root = $builder + ->root('oro_config') + ->children() + ->arrayNode('entity_output') + ->prototype('array') + ->children() + ->scalarNode('icon_class')->end() + ->scalarNode('name')->end() + ->scalarNode('description')->end() + ->end() + ->end() + ->end(); return $builder; } diff --git a/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php b/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php index 236f2f6aed7..525c720a09e 100644 --- a/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php +++ b/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php @@ -3,9 +3,10 @@ namespace Oro\Bundle\ConfigBundle\DependencyInjection; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader; use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\Yaml\Yaml; /** * This is the class that loads and manages your bundle configuration @@ -19,10 +20,25 @@ class OroConfigExtension extends Extension */ public function load(array $configs, ContainerBuilder $container) { + $data = array(); + + foreach ($container->getParameter('kernel.bundles') as $bundle) { + $reflection = new \ReflectionClass($bundle); + + if (file_exists($file = dirname($reflection->getFilename()) . '/Resources/config/entity_output.yml')) { + $data = array_merge($data, Yaml::parse(realpath($file))); + } + } + + $configs[] = array('entity_output' => $data); $configuration = new Configuration(); + $config = $this->processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('services.yml'); + + $container->setParameter('oro_config.entities', $data); } } diff --git a/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml b/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml index 7ceef9efdb9..ea40dd3b1d3 100644 --- a/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml @@ -13,6 +13,6 @@ services: oro_config.twig.config_extension: class: %oro_config.twig_extension.class% - arguments: ["@oro_config.user"] + arguments: ["@oro_config.user", %oro_config.entities%] tags: - { name: twig.extension } diff --git a/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php b/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php index c506955ae61..7c0502b5652 100644 --- a/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php +++ b/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php @@ -11,9 +11,15 @@ class ConfigExtension extends \Twig_Extension */ protected $userConfigManager; - public function __construct(UserConfigManager $userConfigManager) + /** + * @var array + */ + protected $entityOutput; + + public function __construct(UserConfigManager $userConfigManager, $entityOutput = array()) { $this->userConfigManager = $userConfigManager; + $this->entityOutput = $entityOutput; } /** @@ -24,7 +30,8 @@ public function __construct(UserConfigManager $userConfigManager) public function getFunctions() { return array( - 'get_user_value' => new \Twig_Function_Method($this, 'getUserValue'), + 'oro_config_value' => new \Twig_Function_Method($this, 'getUserValue'), + 'oro_config_entity' => new \Twig_Function_Method($this, 'getEntityOutput'), ); } @@ -37,6 +44,28 @@ public function getUserValue($name) return $this->userConfigManager->get($name); } + /** + * Get entity output config (if any provided). + * Provided parameters: + * "icon" - path to entity icon, relative to web dir + * "name" - custom entity name + * "description" - entity description + * + * @param string $class FQCN of the entity + * @return array + */ + public function getEntityOutput($class) + { + $default = explode('\\', $class); + + return isset($this->entityOutput[$class]) + ? $this->entityOutput[$class] + : array( + 'icon' => '', + 'name' => end($default), + 'description' => 'No description' + ); + } /** * Returns the name of the extension. diff --git a/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig b/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig index 47aa26ac4b7..1b51c1d3e8a 100644 --- a/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig +++ b/src/Oro/Bundle/UIBundle/Resources/views/Default/index.html.twig @@ -89,8 +89,8 @@ {% block logo %}

    - - {{ get_user_value('oro_ui.application_name') }} + + {{ oro_config_value('oro_ui.application_name') }}

    {% endblock logo %} diff --git a/src/Oro/Bundle/UserBundle/Resources/config/entity_output.yml b/src/Oro/Bundle/UserBundle/Resources/config/entity_output.yml new file mode 100644 index 00000000000..e7a5ef84a5a --- /dev/null +++ b/src/Oro/Bundle/UserBundle/Resources/config/entity_output.yml @@ -0,0 +1,14 @@ +Oro\Bundle\UserBundle\Entity\User: + icon_class: icon-user + name: entity.user.name + description: entity.user.description + +Oro\Bundle\UserBundle\Entity\Role: + icon_class: icon-signal + name: entity.role.name + description: entity.role.description + +Oro\Bundle\UserBundle\Entity\Group: + icon_class: icon-home + name: entity.group.name + description: entity.group.description \ No newline at end of file diff --git a/src/Oro/Bundle/UserBundle/Resources/translations/config.en.yml b/src/Oro/Bundle/UserBundle/Resources/translations/config.en.yml new file mode 100644 index 00000000000..1130ed1b470 --- /dev/null +++ b/src/Oro/Bundle/UserBundle/Resources/translations/config.en.yml @@ -0,0 +1,12 @@ +entity: + user: + name: Profile + description: Represent user profile + + role: + name: Role + description: User's role + + group: + name: Group + description: Group of roles \ No newline at end of file diff --git a/src/Oro/Bundle/UserBundle/Resources/views/Reset/checkEmail.html.twig b/src/Oro/Bundle/UserBundle/Resources/views/Reset/checkEmail.html.twig index fcfd4c4c592..ed46170ac7d 100644 --- a/src/Oro/Bundle/UserBundle/Resources/views/Reset/checkEmail.html.twig +++ b/src/Oro/Bundle/UserBundle/Resources/views/Reset/checkEmail.html.twig @@ -6,7 +6,7 @@