├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── .travis └── composer.json ├── GruntFile.js ├── README.md ├── composer.json ├── modman ├── package.json ├── rulesets └── phpcs.xml └── src ├── app ├── code │ └── community │ │ └── Ak │ │ └── Locator │ │ ├── Block │ │ ├── Adminhtml │ │ │ ├── Location.php │ │ │ └── Location │ │ │ │ ├── Edit.php │ │ │ │ ├── Edit │ │ │ │ ├── Form.php │ │ │ │ ├── Map.php │ │ │ │ ├── Tab │ │ │ │ │ ├── Abstract.php │ │ │ │ │ ├── Address.php │ │ │ │ │ ├── Details.php │ │ │ │ │ └── Seo.php │ │ │ │ └── Tabs.php │ │ │ │ ├── Grid.php │ │ │ │ └── Helper │ │ │ │ └── Image.php │ │ ├── Breadcrumbs.php │ │ ├── Data.php │ │ ├── Location │ │ │ ├── Info.php │ │ │ ├── Map.php │ │ │ └── View.php │ │ ├── Search.php │ │ └── Search │ │ │ ├── Form.php │ │ │ ├── Infowindow.php │ │ │ ├── Infowindows.php │ │ │ ├── Init.php │ │ │ ├── List │ │ │ ├── Area.php │ │ │ └── Point.php │ │ │ ├── Noresults.php │ │ │ └── Quicksearch.php │ │ ├── Helper │ │ ├── Data.php │ │ ├── Location.php │ │ ├── Location │ │ │ └── Url.php │ │ └── Search.php │ │ ├── Model │ │ ├── Attribute.php │ │ ├── Exception.php │ │ ├── Exception │ │ │ ├── Geocode.php │ │ │ └── NoResults.php │ │ ├── Form.php │ │ ├── Indexer │ │ │ └── Url.php │ │ ├── Location.php │ │ ├── Location │ │ │ ├── Attribute │ │ │ │ └── Backend │ │ │ │ │ └── Image.php │ │ │ └── Url.php │ │ ├── Observer.php │ │ ├── Resource │ │ │ ├── Attribute.php │ │ │ ├── Attribute │ │ │ │ └── Collection.php │ │ │ ├── Form │ │ │ │ ├── Attribute.php │ │ │ │ └── Attribute │ │ │ │ │ └── Collection.php │ │ │ ├── Location.php │ │ │ ├── Location │ │ │ │ └── Collection.php │ │ │ ├── Search │ │ │ │ ├── Override.php │ │ │ │ └── Override │ │ │ │ │ └── Collection.php │ │ │ ├── Setup.php │ │ │ └── Url.php │ │ ├── Search.php │ │ ├── Search │ │ │ ├── Handler │ │ │ │ ├── Abstract.php │ │ │ │ ├── Area.php │ │ │ │ ├── Interface.php │ │ │ │ └── Point │ │ │ │ │ ├── Abstract.php │ │ │ │ │ ├── Closest.php │ │ │ │ │ ├── Latlong.php │ │ │ │ │ └── String.php │ │ │ └── Override.php │ │ ├── Url.php │ │ └── Urlrewrite │ │ │ └── Matcher │ │ │ └── Location.php │ │ ├── Test │ │ ├── Helper │ │ │ ├── Data.php │ │ │ └── Search.php │ │ └── Model │ │ │ ├── Location.php │ │ │ ├── Location │ │ │ └── fixtures │ │ │ │ └── default.yaml │ │ │ ├── Observer.php │ │ │ ├── Search.php │ │ │ ├── Search │ │ │ ├── Handler │ │ │ │ ├── Abstract.php │ │ │ │ ├── Area.php │ │ │ │ └── Point │ │ │ │ │ ├── Closest.php │ │ │ │ │ ├── Latlong.php │ │ │ │ │ └── String.php │ │ │ └── fixtures │ │ │ │ ├── testLatLongSearchDistance.yaml │ │ │ │ └── testLatLongSearchEnabled.yaml │ │ │ └── Url.php │ │ ├── controllers │ │ ├── Adminhtml │ │ │ └── LocatorController.php │ │ ├── IndexController.php │ │ ├── LocationController.php │ │ └── SearchController.php │ │ ├── etc │ │ ├── config.xml │ │ └── system.xml │ │ └── sql │ │ └── ak_locator_setup │ │ ├── install-0.0.0.1.php │ │ ├── upgrade-0.0.0.1-0.0.0.2.php │ │ ├── upgrade-0.0.0.2-0.0.0.3.php │ │ ├── upgrade-0.0.0.3-0.0.0.4.php │ │ ├── upgrade-0.0.0.4-0.0.0.5.php │ │ └── upgrade-0.0.0.5-0.0.0.6.php ├── design │ ├── adminhtml │ │ └── default │ │ │ └── default │ │ │ ├── layout │ │ │ └── locator.xml │ │ │ └── template │ │ │ └── locator │ │ │ └── location │ │ │ └── edit │ │ │ └── map.phtml │ └── frontend │ │ └── base │ │ ├── default │ │ ├── layout │ │ │ └── locator.xml │ │ └── template │ │ │ └── locator │ │ │ ├── location │ │ │ ├── info.phtml │ │ │ ├── map.phtml │ │ │ ├── others.phtml │ │ │ └── view.phtml │ │ │ ├── page │ │ │ └── html │ │ │ │ └── head │ │ │ │ ├── init-locator.phtml │ │ │ │ ├── init-search.phtml │ │ │ │ └── init-store.phtml │ │ │ └── search │ │ │ ├── form-australia.phtml │ │ │ ├── form-simple.phtml │ │ │ ├── infowindow.phtml │ │ │ ├── list │ │ │ ├── area.phtml │ │ │ └── point.phtml │ │ │ ├── no-results.phtml │ │ │ ├── quick.phtml │ │ │ └── search.phtml │ │ └── iphone │ │ ├── layout │ │ └── locator.xml │ │ └── template │ │ └── locator │ │ ├── location │ │ ├── others.phtml │ │ └── view.phtml │ │ └── search │ │ ├── search.phtml │ │ └── simple-form.phtml └── etc │ └── modules │ └── Ak_Locator.xml ├── js └── locator │ ├── locator.js │ ├── locator.js.map │ ├── locator.min.js │ ├── plugins.js │ └── src │ ├── history.js │ └── locator.js └── skin ├── adminhtml └── default │ └── default │ └── locator │ ├── css │ └── locator.css │ └── images │ ├── map.png │ ├── map_add.png │ ├── map_delete.png │ ├── map_edit.png │ ├── map_go.png │ └── map_magnify.png └── frontend └── base ├── default └── locator │ ├── css │ └── locator.css │ └── images │ ├── loader │ ├── loader-lrg.gif │ ├── loader-med.gif │ └── loader-sml.gif │ └── pin.png └── iphone └── css └── locator-mobile.css /.gitignore: -------------------------------------------------------------------------------- 1 | magento 2 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | tools: 2 | external_code_coverage: true 3 | php_cpd: false 4 | php_pdepend: 5 | enabled: true 6 | filter: 7 | paths: ["src/app/*"] 8 | js_hint: false 9 | php_code_sniffer: 10 | extensions: 11 | - php 12 | command: phpcs 13 | enabled: true 14 | filter: 15 | paths: ["src/app/*"] 16 | config: 17 | ruleset: rulesets/phpcs.xml 18 | php_mess_detector: 19 | enabled: true 20 | config: 21 | # ruleset: rulesets/phpmd-ruleset.xml 22 | design_rules: { eval_expression: false } 23 | filter: 24 | paths: ["src/app/*"] 25 | 26 | php_loc: 27 | enabled: true 28 | excluded_dirs: ["src/app/*"] 29 | # php_analyzer: true # cannot use as composer dependencies can't be found 30 | 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | env: 4 | # - MAGENTO_VERSION="1.5.0.1" 5 | # - MAGENTO_VERSION="1.6.0.0" 6 | # - MAGENTO_VERSION="1.6.1.0" 7 | - MAGENTO_VERSION="1.6.2.0" 8 | # - MAGENTO_VERSION="1.7.0.0" 9 | # - MAGENTO_VERSION="1.7.0.1" 10 | - MAGENTO_VERSION="1.7.0.2" 11 | # - MAGENTO_VERSION="1.8.0.0" 12 | - MAGENTO_VERSION="1.8.1.0" 13 | # - MAGENTO_VERSION="1.9.0.0" 14 | - MAGENTO_VERSION="1.9.0.1" 15 | - MAGENTO_VERSION="1.9.1.0" 16 | 17 | php: 18 | - 5.3 19 | - 5.4 20 | - 5.5 21 | 22 | before_install: 23 | 24 | before_script: 25 | - CURR_DIR=$(pwd) 26 | 27 | #move locator extension to new folder 28 | #- mkdir $CURR_DIR/locator 29 | - rsync -a $CURR_DIR/ $CURR_DIR/locator --exclude $CURR_DIR/locator --exclude $CURR_DIR/mageci --exclude $CURR_DIR/phpunit --exclude $CURR_DIR/magento 30 | 31 | #install mage ci 32 | - git clone git://github.com/EcomDev/MageCI.git $CURR_DIR/mageci/ 33 | 34 | #install modman 35 | - wget https://raw.githubusercontent.com/colinmollenhour/modman/master/modman -O $CURR_DIR/mageci/bin/modman 36 | - chmod +x $CURR_DIR/mageci/bin/modman 37 | 38 | #install magento 39 | - $CURR_DIR/mageci/bin/mage-ci install magento $MAGENTO_VERSION magento_test -c -t -r http://mage-ci.ecomdev.org 40 | 41 | #install php unit 42 | - git clone git://github.com/EcomDev/EcomDev_PHPUnit.git -b dev $CURR_DIR/phpunit/ 43 | - $CURR_DIR/mageci/bin/mage-ci install-module magento $CURR_DIR/phpunit 44 | 45 | #install locator to magento directory 46 | - $CURR_DIR/mageci/bin/mage-ci install-module magento $CURR_DIR/locator 47 | 48 | - cp ./.travis/composer.json magento 49 | - cd magento 50 | - composer install --prefer-dist 51 | script: 52 | 53 | - wget https://scrutinizer-ci.com/ocular.phar 54 | - phpunit --coverage-clover=coverage.clover 55 | - php ocular.phar code-coverage:upload --format=php-clover coverage.clover 56 | -------------------------------------------------------------------------------- /.travis/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "andrewkett/locator", 3 | "minimum-stability":"dev", 4 | "require": { 5 | "phayes/geophp": "*" 6 | }, 7 | "authors":[ 8 | { 9 | "name":"Andrew Kett" 10 | } 11 | ], 12 | "extra":{ 13 | "magento-root-dir" : "./", 14 | "magento-force" : "true" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /GruntFile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.loadNpmTasks('grunt-contrib-uglify'); 4 | grunt.loadNpmTasks('grunt-contrib-watch'); 5 | grunt.loadNpmTasks('grunt-contrib-concat'); 6 | 7 | grunt.initConfig({ 8 | uglify: { 9 | locatorjs: { 10 | options: { 11 | mangle: false, 12 | compress: true, 13 | sourceMap: true, 14 | sourceMapName: 'src/js/locator/locator.js.map' 15 | }, 16 | files: { 17 | 'src/js/locator/locator.min.js': [ 18 | 'src/js/locator/src/history.js', 19 | 'src/js/locator/src/locator.js' 20 | ] 21 | } 22 | } 23 | }, 24 | 25 | watch: { 26 | files: "./src/js/locator/src/**", 27 | tasks: ["uglify","concat"] 28 | 29 | }, 30 | concat: { 31 | dist: { 32 | src: ['src/js/locator/src/history.js', 'src/js/locator/src/locator.js'], 33 | dest: 'src/js/locator/locator.js' 34 | } 35 | } 36 | }); 37 | 38 | // Default task(s). 39 | grunt.registerTask('default', ['less']); 40 | grunt.registerTask( 'serve', [ 'connect', 'watch'] ); 41 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magento Store Locator 2 | 3 | [![Build Status](https://travis-ci.org/andrewkett/Ak_Locator.png?branch=master)](https://travis-ci.org/andrewkett/Ak_Locator) [![Code Coverage](https://scrutinizer-ci.com/g/andrewkett/Ak_Locator/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/andrewkett/Ak_Locator/?branch=master) [![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/andrewkett/Ak_Locator/badges/quality-score.png?s=ed69380af3f8cae9103d253d27e7c193fbe02914)](https://scrutinizer-ci.com/g/andrewkett/Ak_Locator/) [![Dependency Status](https://www.versioneye.com/user/projects/5309b07fec1375bb1b000013/badge.png)](https://www.versioneye.com/user/projects/5309b07fec1375bb1b000013) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/657284eb-b4cc-4d69-b110-2eed060b653d/mini.png)](https://insight.sensiolabs.com/projects/657284eb-b4cc-4d69-b110-2eed060b653d) 4 | 5 | 6 | This extension provides the ability to add physical stores to your Magento website, and for a customer to find your stores using a geolocation search. 7 | 8 | ## Features 9 | 10 | * Locations built with Magentos EAV system 11 | * Google Maps used for frontend display and search geocoding 12 | * Configurable search settings 13 | * Extensible code 14 | 15 | ## Installation. 16 | This extension can be installed with both modman and composer, however composer is the recommended method of installation. 17 | 18 | ### Using composer 19 | 20 | add a composer.json file to your root directory 21 | 22 | ```javascript 23 | { 24 | "repositories": [ 25 | { 26 | "type":"composer", 27 | "url":"http://packages.firegento.com" 28 | } 29 | ], 30 | "require": { 31 | "andrewkett/locator" : "@stable" 32 | }, 33 | "extra":{ 34 | "magento-root-dir":"./", 35 | "magento-force":"true" 36 | } 37 | } 38 | ``` 39 | then 40 | 41 | ``` 42 | composer.phar install 43 | ``` 44 | 45 | ### Download and install manually. 46 | 47 | [https://github.com/andrewkett/Ak_Locator/archive/master.zip](https://github.com/andrewkett/Ak_Locator/archive/master.zip) 48 | 49 | When installing manually, the [geoPHP](https://github.com/phayes/geoPHP) library must be added to the lib directory manually. 50 | 51 | ## Configuration 52 | 53 | Once installed you will need to add a [google maps API key](https://developers.google.com/maps/documentation/javascript/tutorial#api_key) in the Locator Settings configuration tab. 54 | 55 | ## How to Contribute 56 | 57 | - Fork and edit 58 | - Test locally 59 | - Submit pull request for consideration 60 | 61 | ## Licence 62 | [OSL - Open Software Licence 3.0](http://opensource.org/licenses/osl-3.0.php) 63 | 64 | ## Copyright 65 | (c) 2015 Andrew Kett 66 | 67 | Disclaimer: This extension is now reasonably stable and has been used in production websites, however it is provided "as is" and there are no guarantees that it will work for your site. 68 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "andrewkett/locator", 3 | "license": "OSL-3.0", 4 | "type": "magento-module", 5 | "description": "Magento Store Locator Extension", 6 | "homepage": "http://andrewkett.github.io/Ak_Locator/", 7 | "require": { 8 | "magento-hackathon/magento-composer-installer": "*", 9 | "phayes/geophp": "1.2" 10 | }, 11 | "repositories": [ 12 | { 13 | "type": "composer", 14 | "url": "http://packages.firegento.com" 15 | } 16 | ], 17 | "authors":[ 18 | { 19 | "name":"Andrew Kett" 20 | } 21 | ], 22 | "extra":{ 23 | "skip-package-deployment" : true, 24 | "magento-root-dir" : "./" 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | #extension files 2 | src/app/etc/modules/* app/etc/modules/ 3 | src/app/code/community/Ak/Locator app/code/community/Ak/Locator 4 | 5 | #template files 6 | src/app/design/adminhtml/default/default/layout/locator.xml app/design/adminhtml/default/default/layout/locator.xml 7 | src/app/design/adminhtml/default/default/template/locator app/design/adminhtml/default/default/template/locator 8 | src/app/design/frontend/base/default/layout/locator.xml app/design/frontend/base/default/layout/locator.xml 9 | src/app/design/frontend/base/default/template/locator app/design/frontend/base/default/template/locator 10 | src/app/design/frontend/base/iphone/layout/locator.xml app/design/frontend/base/iphone/layout/locator.xml 11 | src/app/design/frontend/base/iphone/template/locator app/design/frontend/base/iphone/template/locator 12 | 13 | #js 14 | src/js/locator js/locator 15 | 16 | #skin files 17 | src/skin/adminhtml/default/default/locator skin/adminhtml/default/default/locator 18 | src/skin/frontend/base/default/locator skin/frontend/base/default/locator 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Ak_Locator" 3 | , "description": "Grunt tasks to aid in development of Locator extension" 4 | , "author": "Andrew Kett" 5 | , "devDependencies": { 6 | "grunt": "~0.4.1" 7 | , "grunt-contrib-watch": "~0.5.3" 8 | , "grunt-contrib-uglify": "0.4.0" 9 | , "grunt-contrib-concat": "0.5.0" 10 | } 11 | } -------------------------------------------------------------------------------- /rulesets/phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Magento extension ruleset based on PSR-1 and PSR-2 but modified for magento 1 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location.php: -------------------------------------------------------------------------------- 1 | _controller = 'adminhtml_location'; 22 | $this->_headerText = Mage::helper('ak_locator')->__('Manage Locations'); 23 | $this->_blockGroup = 'ak_locator'; 24 | $this->_addButtonLabel = Mage::helper('ak_locator')->__('Add New Location'); 25 | 26 | parent::__construct(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location/Edit.php: -------------------------------------------------------------------------------- 1 | _objectId = 'id'; 26 | $this->_blockGroup = 'ak_locator'; 27 | $this->_controller = 'adminhtml_location'; 28 | $this->_mode = 'edit'; 29 | 30 | $this->_addButton('save_and_continue', array( 31 | 'label' => Mage::helper('adminhtml')->__('Save And Continue Edit'), 32 | 'onclick' => 'saveAndContinueEdit()', 33 | 'class' => 'save', 34 | ), -100); 35 | $this->_updateButton('save', 'label', Mage::helper('ak_locator')->__('Save Location')); 36 | 37 | $this->_formScripts[] = " 38 | function toggleEditor() { 39 | if (tinyMCE.getInstanceById('form_content') == null) { 40 | tinyMCE.execCommand('mceAddControl', false, 'edit_form'); 41 | } else { 42 | tinyMCE.execCommand('mceRemoveControl', false, 'edit_form'); 43 | } 44 | } 45 | 46 | function saveAndContinueEdit(){ 47 | editForm.submit($('edit_form').action+'back/edit/'); 48 | } 49 | "; 50 | } 51 | 52 | 53 | public function getHeaderText() 54 | { 55 | if (Mage::registry('location_data') && Mage::registry('location_data')->getId()) { 56 | return Mage::helper('ak_locator')->__('%s', $this->htmlEscape(Mage::registry('location_data')->getTitle())); 57 | } else { 58 | return Mage::helper('ak_locator')->__('New Location'); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location/Edit/Form.php: -------------------------------------------------------------------------------- 1 | 'edit_form', 24 | 'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))), 25 | 'method' => 'post', 26 | 'enctype' => 'multipart/form-data', 27 | )); 28 | 29 | $form->setUseContainer(true); 30 | 31 | $this->setForm($form); 32 | 33 | return parent::_prepareForm(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location/Edit/Map.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/location/edit/map.phtml'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location/Edit/Tab/Abstract.php: -------------------------------------------------------------------------------- 1 | getData('tab_structure'); 10 | foreach ($tabStructure as $tab) { 11 | foreach ($tab as $att) { 12 | $used[$att] = $att; 13 | } 14 | } 15 | 16 | foreach ($this->getLocationForm()->getAttributes() as $att) { 17 | if (!isset($used[$att->getAttributeCode()])) { 18 | $tabStructure['location_details'][] = $att->getAttributeCode(); 19 | } 20 | } 21 | return $tabStructure; 22 | } 23 | 24 | 25 | protected function getLocationForm() 26 | { 27 | $locationForm = Mage::getModel('ak_locator/form'); 28 | $locationForm->setEntity($this->getLocation()) 29 | ->setFormCode('location_create') 30 | ->initDefaultValues(); 31 | 32 | return $locationForm; 33 | } 34 | 35 | 36 | public function getLocation() 37 | { 38 | if (!isset($this->location)) { 39 | if (Mage::registry('location_data')) { 40 | $data = Mage::registry('location_data')->getData(); 41 | } else { 42 | $data = array(); 43 | } 44 | 45 | $location = Mage::getModel('ak_locator/location'); 46 | 47 | if (isset($data['entity_id'])) { 48 | $location->load($data['entity_id']); 49 | } 50 | 51 | 52 | } else { 53 | $location = $this->location; 54 | } 55 | 56 | return $location; 57 | } 58 | 59 | public function initForm() 60 | { 61 | $structure = $this->getTabStructure(); 62 | 63 | $addressAttributeCodes = @$structure[$this->tabAttrs]; 64 | 65 | 66 | //get location form 67 | $locationForm = $this->getLocationForm(); 68 | 69 | $form = new Varien_Data_Form(); 70 | 71 | $addressAttributes = array(); 72 | 73 | $attributes = $locationForm->getAttributes(); 74 | 75 | if ($addressAttributeCodes) { 76 | foreach ($addressAttributeCodes as $attributeCode) { 77 | if (isset($attributes[$attributeCode])) { 78 | $addressAttributes[$attributeCode] = $attributes[$attributeCode]; 79 | } 80 | 81 | } 82 | } 83 | 84 | $fieldset = $form->addFieldset('base_fieldset', array( 85 | 'legend' => Mage::helper('ak_locator')->__($this->tabLabel) 86 | )); 87 | 88 | $this->_setFieldset($addressAttributes, $fieldset, array(@$disableAutoGroupChangeAttributeName)); 89 | $form->setValues($this->getLocation()->getData()); 90 | $this->setForm($form); 91 | return $this; 92 | } 93 | 94 | protected function _getAdditionalElementTypes() 95 | { 96 | return array( 97 | 'image' => Mage::getConfig()->getBlockClassName('ak_locator/adminhtml_location_helper_image') 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location/Edit/Tab/Address.php: -------------------------------------------------------------------------------- 1 | setId('location_info_tabs'); 9 | $this->setDestElementId('edit_form'); 10 | $this->setTitle(Mage::helper('ak_locator')->__('Location Information')); 11 | 12 | $this->setTabStructure(array( 13 | 'location_address' => array( 14 | 'address', 15 | 'administrative_area', 16 | 'sub_administrative_area', 17 | 'locality', 18 | 'dependent_locality', 19 | 'postal_code', 20 | 'thoroughfare', 21 | 'premise', 22 | 'sub_premise', 23 | 'country', 24 | 'data', 25 | 'geocoded', 26 | 'latitude', 27 | 'longitude' 28 | ), 29 | 'location_details' => array( 30 | 'title', 31 | 'is_enabled' 32 | ), 33 | 'location_seo' => array( 34 | 'url_key', 35 | 'meta_title', 36 | 'meta_description', 37 | 'meta_keywords' 38 | ), 39 | )); 40 | } 41 | 42 | protected function _prepareLayout() 43 | { 44 | 45 | $this->addTab('location_details', array( 46 | 'label' => Mage::helper('ak_locator')->__('Location Details'), 47 | 'content' => $this->getLayout() 48 | ->createBlock('ak_locator/adminhtml_location_edit_tab_details') 49 | ->setTabStructure($this->getTabStructure()) 50 | ->initForm() 51 | ->toHtml() 52 | )); 53 | 54 | $this->addTab('location_address', array( 55 | 'label' => Mage::helper('ak_locator')->__('Location Address'), 56 | 'content' => $this->getLayout() 57 | ->createBlock('ak_locator/adminhtml_location_edit_tab_address') 58 | ->setTabStructure($this->getTabStructure()) 59 | ->initForm() 60 | ->toHtml() 61 | )); 62 | 63 | $this->addTab('location_seo', array( 64 | 'label' => Mage::helper('ak_locator')->__('SEO'), 65 | 'content' => $this->getLayout() 66 | ->createBlock('ak_locator/adminhtml_location_edit_tab_seo') 67 | ->setTabStructure($this->getTabStructure()) 68 | ->initForm() 69 | ->toHtml() 70 | )); 71 | 72 | return parent::_prepareLayout(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location/Grid.php: -------------------------------------------------------------------------------- 1 | setId('location_grid'); 23 | $this->setDefaultSort('id'); 24 | $this->setDefaultDir('desc'); 25 | $this->setSaveParametersInSession(true); 26 | } 27 | 28 | protected function _prepareCollection() 29 | { 30 | $collection = Mage::getModel('ak_locator/location')->getCollection() 31 | ->addAttributeToSelect('title') 32 | ->addAttributeToSelect('geocoded') 33 | ->addAttributeToSelect('address') 34 | ->addAttributeToSelect('postal_code') 35 | ->addAttributeToSelect('country'); 36 | 37 | $this->setCollection($collection); 38 | return parent::_prepareCollection(); 39 | } 40 | 41 | protected function _prepareColumns() 42 | { 43 | $this->addColumn('id', array( 44 | 'header' => Mage::helper('ak_locator')->__('ID'), 45 | 'align' =>'right', 46 | 'width' => '50px', 47 | 'index' => 'entity_id', 48 | )); 49 | 50 | $this->addColumn('title', array( 51 | 'header' => Mage::helper('ak_locator')->__('Title'), 52 | 'align' =>'left', 53 | 'index' => 'title', 54 | )); 55 | 56 | $this->addColumn('address', array( 57 | 'header' => Mage::helper('ak_locator')->__('Address'), 58 | 'align' =>'left', 59 | 'index' => 'address', 60 | )); 61 | 62 | $this->addColumn('postal_code', array( 63 | 'header' => Mage::helper('ak_locator')->__('Postalcode'), 64 | 'align' => 'left', 65 | 'index' => 'postal_code', 66 | )); 67 | 68 | $this->addColumn('country', array( 69 | 'header' => Mage::helper('ak_locator')->__('Country'), 70 | 'align' => 'left', 71 | 'index' => 'country', 72 | )); 73 | 74 | $this->addColumn('is_enabled', array( 75 | 'header' => Mage::helper('ak_locator')->__('Enabled'), 76 | 'align' => 'left', 77 | 'index' => 'is_enabled', 78 | 'type' => 'options', 79 | 'options' => array('1'=>'Yes','0'=>'No'), 80 | )); 81 | 82 | return parent::_prepareColumns(); 83 | } 84 | 85 | public function getRowUrl($row) 86 | { 87 | return $this->getUrl('*/*/edit', array('id' => $row->getId())); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Adminhtml/Location/Helper/Image.php: -------------------------------------------------------------------------------- 1 | getValue()) { 10 | $url = Mage::getBaseUrl('media').'locator/location/'. $this->getValue(); 11 | } 12 | return $url; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Breadcrumbs.php: -------------------------------------------------------------------------------- 1 | getLayout()->getBlock('breadcrumbs')) { 15 | $breadcrumbsBlock->addCrumb('home', array( 16 | 'label'=>Mage::helper('ak_locator')->__('Home'), 17 | 'title'=>Mage::helper('ak_locator')->__('Go to Home Page'), 18 | 'link'=>Mage::getBaseUrl() 19 | )); 20 | 21 | $breadcrumbsBlock->addCrumb('storeLocator', array( 22 | 'label'=>Mage::helper('ak_locator')->__('Store locator'), 23 | 'title'=>Mage::helper('ak_locator')->__('Go to Store locator page'), 24 | 'link'=>Mage::getBaseUrl().'locator/search' 25 | )); 26 | $path = Mage::helper('ak_locator')->getBreadcrumbPath(); 27 | if (count($path)>0) { 28 | foreach ($path as $name => $breadcrumb) { 29 | $breadcrumbsBlock->addCrumb($name, $breadcrumb); 30 | } 31 | } 32 | } 33 | return parent::_prepareLayout(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Data.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/data.phtml'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Location/Info.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/location/info.phtml'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Location/Map.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/location/map.phtml'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Location/View.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/location/view.phtml'); 24 | } 25 | 26 | /** 27 | * Prepare the layout 28 | * 29 | * @return Mage_Core_Block_Abstract 30 | */ 31 | protected function _prepareLayout() 32 | { 33 | $location = $this->getLocation(); 34 | 35 | if (!$location) { 36 | return; 37 | } 38 | 39 | $layout = $this->getLayout(); 40 | 41 | //Add Breadcrumbs 42 | $layout ->createBlock('ak_locator/breadcrumbs'); 43 | 44 | if ($headBlock = $layout->getBlock('head')) { 45 | 46 | if ($title = $location->getMetaTitle()) { 47 | $headBlock->setTitle($title); 48 | } else { 49 | $headBlock->setTitle($location->getTitle()); 50 | } 51 | 52 | if ($description = $location->getMetaDescription()) { 53 | $headBlock->setDescription($description); 54 | } 55 | 56 | if ($keywords = $location->getMetaKeywords()) { 57 | $headBlock->setKeywords($keywords); 58 | } 59 | 60 | $initLocator = $layout->createBlock('core/template'); 61 | $initLocator->setTemplate('locator/page/html/head/init-locator.phtml'); 62 | 63 | $initSearch = $layout->createBlock('core/template'); 64 | $initSearch->setTemplate('locator/page/html/head/init-store.phtml') 65 | ->setData('locations', $this->getLocations()); 66 | 67 | $headBlock->append($initLocator); 68 | $headBlock->append($initSearch); 69 | } 70 | 71 | 72 | 73 | $listBlock = $this->getLayout()->createBlock('ak_locator/location_info') 74 | ->setData('locations', $this->getLocations()); 75 | $mapBlock = $this->getLayout()->createBlock('ak_locator/location_map') 76 | ->setData('locations', $this->getLocations()); 77 | 78 | 79 | $nearbyBlock = $this->getLayout()->createBlock('ak_locator/search_list_point') 80 | ->setData('locations', $this->getNearbyLocations()) 81 | ->setTemplate('locator/location/others.phtml'); 82 | 83 | 84 | $this->setChild('others', $nearbyBlock); 85 | $this->setChild('info', $listBlock); 86 | $this->setChild('map', $mapBlock); 87 | 88 | return parent::_prepareLayout(); 89 | } 90 | 91 | 92 | /** 93 | * Retrieve a location collection containing the current location 94 | * 95 | * @return Ak_Locator_Model_Resource_Location_Collection 96 | */ 97 | public function getLocations() 98 | { 99 | if (!Mage::registry('locator_locations')) { 100 | 101 | $id = $this->getRequest()->getParam('id'); 102 | 103 | $locations = Mage::getModel('ak_locator/location')->getCollection() 104 | ->addAttributeToSelect('*') 105 | ->addAttributeToFilter('entity_id', $id); 106 | 107 | Mage::register('locator_locations', $locations); 108 | } 109 | return Mage::registry('locator_locations'); 110 | } 111 | 112 | 113 | /** 114 | * Get the location currently being viewed 115 | * 116 | * @return Ak_Locator_Model_Location 117 | */ 118 | public function getLocation() 119 | { 120 | return $this->getLocations()->getFirstItem(); 121 | } 122 | 123 | 124 | /** 125 | * Get locations near current location 126 | * 127 | * @return Ak_Locator_Model_Resource_Location_Collection 128 | */ 129 | public function getNearbyLocations() 130 | { 131 | $location = $this->getLocation(); 132 | $params = array( 133 | 'lat'=>$location->getLatitude(), 134 | 'long'=>$location->getLongitude(), 135 | 'limit' => 8 136 | ); 137 | 138 | $results = Mage::getModel('ak_locator/search') 139 | ->search($params) 140 | ->addAttributeToFilter('entity_id', array('neq'=>$location->getId())); 141 | 142 | return $results; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Search.php: -------------------------------------------------------------------------------- 1 | getLayout(); 32 | 33 | $this->getLayout()->createBlock('ak_locator/breadcrumbs'); 34 | 35 | if ($headBlock = $layout->getBlock('head')) { 36 | $headBlock->setTitle(Mage::getStoreConfig(self::XML_PATH_SEARCH_META_TITLE)); 37 | $headBlock->setDescription(Mage::getStoreConfig(self::XML_PATH_SEARCH_META_DESC)); 38 | $headBlock->setKeywords(Mage::getStoreConfig(self::XML_PATH_SEARCH_META_KEY)); 39 | } 40 | 41 | return parent::_prepareLayout(); 42 | } 43 | 44 | 45 | /** 46 | * Retrieve location collection based on search parameters 47 | * 48 | * @return Ak_Locator_Model_Resource_Location_Collection 49 | */ 50 | public function getLocations() 51 | { 52 | if (!Mage::registry('locator_locations')) { 53 | $locations = $this->getSearch()->search($this->getRequest()->getParams()); 54 | Mage::register('locator_locations', $locations); 55 | } else { 56 | $locations = Mage::registry('locator_locations'); 57 | } 58 | 59 | $listBlock = $this->getListBlock($locations)->setData('locations', $locations); 60 | $this->setChild('list', $listBlock); 61 | 62 | return $locations; 63 | } 64 | 65 | 66 | /** 67 | * Represent the current search in a json format 68 | * 69 | * @return string 70 | */ 71 | public function asJson() 72 | { 73 | $obj = $this->getLocations()->getResponseObject(); 74 | $obj->setOutput($this->getChild('list')->toHtml()); 75 | 76 | return $obj->toJson(); 77 | } 78 | 79 | 80 | public function setSearch($model) 81 | { 82 | $this->_searchModel = $model; 83 | } 84 | 85 | /** 86 | * @return Ak_Locator_Model_Search 87 | */ 88 | public function getSearch() 89 | { 90 | if ($this->_searchModel === null) { 91 | $this->setSearch(Mage::getModel('ak_locator/search')); 92 | } 93 | return $this->_searchModel; 94 | } 95 | 96 | 97 | /** 98 | * Get the child block which will render the list of locations 99 | * 100 | * @param $locations 101 | * 102 | * @return Mage_Core_Block_Abstract 103 | */ 104 | protected function getListBlock($locations) 105 | { 106 | $layout = $this->getLayout(); 107 | 108 | //if the collection contains a point of search render accordingly otherwise just list normally 109 | if (!$locations->getSearchPoint()) { 110 | return $layout->createBlock('ak_locator/search_list_area'); 111 | } else { 112 | return $layout->createBlock('ak_locator/search_list_point'); 113 | } 114 | } 115 | 116 | /** 117 | * Check if params are valid 118 | * 119 | * @return mixed 120 | */ 121 | public function hasValidParams() 122 | { 123 | return $this->getSearch()->isValidParams($this->getRequest()->getParams()); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Search/Form.php: -------------------------------------------------------------------------------- 1 | getParam('distance')) { 50 | return $request->getParam('distance'); 51 | } else { 52 | return Mage::getStoreConfig(self::XML_PATH_DEFAULT_DISTANCE); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Search/Infowindow.php: -------------------------------------------------------------------------------- 1 | _location)) { 24 | $this->setLocation(Mage::getModel('ak_locator/location')->load(Mage::app()->getRequest()->getParam('id'))); 25 | } 26 | 27 | return $this->_location; 28 | } 29 | 30 | public function setLocation($location) 31 | { 32 | $this->_location = $location; 33 | return $this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Search/Infowindows.php: -------------------------------------------------------------------------------- 1 | _location)) { 11 | $ids = explode(',', Mage::app()->getRequest()->getParam('ids')); 12 | $this->setLocations( 13 | Mage::getModel('ak_locator/location') 14 | ->getCollection() 15 | ->addAttributeToSelect('*') 16 | ->addAttributeToFilter('entity_id', array('in' => $ids)) 17 | ); 18 | } 19 | 20 | return $this->_locations; 21 | } 22 | 23 | public function setLocations($locations) 24 | { 25 | $this->_locations = $locations; 26 | } 27 | 28 | public function _toHtml() 29 | { 30 | $locations = array(); 31 | 32 | foreach ($this->getLocations() as $location) { 33 | $block = $this->getChild('infowindow'); 34 | $locations[$location->getId()] = $block->setLocation($location)->toHtml(); 35 | } 36 | 37 | $json = Zend_Json::encode($locations); 38 | //zend_json doesn't encode single quotes but they break in the browser 39 | $json = str_replace('\'', ''', $json); 40 | 41 | return $json; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Search/Init.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/search/list/area.phtml'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Search/List/Point.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/search/list/point.phtml'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Block/Search/Noresults.php: -------------------------------------------------------------------------------- 1 | setTemplate('locator/search/quick.phtml'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Helper/Data.php: -------------------------------------------------------------------------------- 1 | __('Use helper with defined EAV entity')); 29 | } 30 | 31 | /** 32 | * Default attribute entity type code 33 | * 34 | * @throws Mage_Core_Exception 35 | */ 36 | protected function _getEntityTypeCode() 37 | { 38 | Mage::throwException(Mage::helper('ak_locator')->__('Use helper with defined EAV entity')); 39 | } 40 | 41 | /** 42 | * Return available location attribute form as select options 43 | * 44 | * @return array 45 | */ 46 | public function getLocationAttributeFormOptions() 47 | { 48 | return Mage::helper('ak_locator/location')->getAttributeFormOptions(); 49 | } 50 | 51 | /** 52 | * Returns array of user defined attribute codes for location entity type 53 | * 54 | * @return array 55 | */ 56 | public function getLocationUserDefinedAttributeCodes() 57 | { 58 | return Mage::helper('ak_locator/location')->getUserDefinedAttributeCodes(); 59 | } 60 | 61 | 62 | /** 63 | * Is browser caching enabled for searches 64 | * 65 | * @return bool 66 | */ 67 | public function browserCacheEnabled() 68 | { 69 | return (bool)Mage::getStoreConfig(self::BROWSER_CACHE_CONFIG_PATH); 70 | } 71 | 72 | 73 | public function getBreadcrumbPath() 74 | { 75 | $path = array(); 76 | 77 | if ($id = Mage::app()->getRequest()->getParam('id')) { 78 | $locations = Mage::getModel('ak_locator/location')->getCollection() 79 | ->addAttributeToSelect('title') 80 | ->addAttributeToFilter('entity_id', $id) 81 | ->load(); 82 | $items = $locations->getItems(); 83 | $location = reset($items); 84 | $path['location_detail'] = array( 85 | 'label'=> $location->getTitle(), 86 | 'link' => '' 87 | ); 88 | } 89 | return $path; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Helper/Location.php: -------------------------------------------------------------------------------- 1 | Mage::helper('ak_locator')->__('Create Location'), 42 | 'value' => 'location_create' 43 | ), 44 | array( 45 | 'label' => Mage::helper('ak_locator')->__('Edit Location'), 46 | 'value' => 'location_edit' 47 | ), 48 | ); 49 | } 50 | 51 | 52 | /** 53 | * Retrieve location rewrite suffix for store 54 | * 55 | * @param int $storeId 56 | * @return string 57 | */ 58 | public function getLocationUrlSuffix($storeId = null) 59 | { 60 | if (is_null($storeId)) { 61 | $storeId = Mage::app()->getStore()->getId(); 62 | } 63 | 64 | if (!isset($this->_locationUrlSuffix[$storeId])) { 65 | $this->_locationUrlSuffix[$storeId] = Mage::getStoreConfig(self::XML_PATH_LOCATION_URL_SUFFIX, $storeId); 66 | } 67 | return $this->_locationUrlSuffix[$storeId]; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Helper/Location/Url.php: -------------------------------------------------------------------------------- 1 | 'and', '@' => 'at', '©' => 'c', '®' => 'r', 'À' => 'a', 30 | 'Á' => 'a', 'Â' => 'a', 'Ä' => 'a', 'Å' => 'a', 'Æ' => 'ae','Ç' => 'c', 31 | 'È' => 'e', 'É' => 'e', 'Ë' => 'e', 'Ì' => 'i', 'Í' => 'i', 'Î' => 'i', 32 | 'Ï' => 'i', 'Ò' => 'o', 'Ó' => 'o', 'Ô' => 'o', 'Õ' => 'o', 'Ö' => 'o', 33 | 'Ø' => 'o', 'Ù' => 'u', 'Ú' => 'u', 'Û' => 'u', 'Ü' => 'u', 'Ý' => 'y', 34 | 'ß' => 'ss','à' => 'a', 'á' => 'a', 'â' => 'a', 'ä' => 'a', 'å' => 'a', 35 | 'æ' => 'ae','ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 36 | 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ò' => 'o', 'ó' => 'o', 37 | 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 38 | 'û' => 'u', 'ü' => 'u', 'ý' => 'y', 'þ' => 'p', 'ÿ' => 'y', 'Ā' => 'a', 39 | 'ā' => 'a', 'Ă' => 'a', 'ă' => 'a', 'Ą' => 'a', 'ą' => 'a', 'Ć' => 'c', 40 | 'ć' => 'c', 'Ĉ' => 'c', 'ĉ' => 'c', 'Ċ' => 'c', 'ċ' => 'c', 'Č' => 'c', 41 | 'č' => 'c', 'Ď' => 'd', 'ď' => 'd', 'Đ' => 'd', 'đ' => 'd', 'Ē' => 'e', 42 | 'ē' => 'e', 'Ĕ' => 'e', 'ĕ' => 'e', 'Ė' => 'e', 'ė' => 'e', 'Ę' => 'e', 43 | 'ę' => 'e', 'Ě' => 'e', 'ě' => 'e', 'Ĝ' => 'g', 'ĝ' => 'g', 'Ğ' => 'g', 44 | 'ğ' => 'g', 'Ġ' => 'g', 'ġ' => 'g', 'Ģ' => 'g', 'ģ' => 'g', 'Ĥ' => 'h', 45 | 'ĥ' => 'h', 'Ħ' => 'h', 'ħ' => 'h', 'Ĩ' => 'i', 'ĩ' => 'i', 'Ī' => 'i', 46 | 'ī' => 'i', 'Ĭ' => 'i', 'ĭ' => 'i', 'Į' => 'i', 'į' => 'i', 'İ' => 'i', 47 | 'ı' => 'i', 'IJ' => 'ij','ij' => 'ij','Ĵ' => 'j', 'ĵ' => 'j', 'Ķ' => 'k', 48 | 'ķ' => 'k', 'ĸ' => 'k', 'Ĺ' => 'l', 'ĺ' => 'l', 'Ļ' => 'l', 'ļ' => 'l', 49 | 'Ľ' => 'l', 'ľ' => 'l', 'Ŀ' => 'l', 'ŀ' => 'l', 'Ł' => 'l', 'ł' => 'l', 50 | 'Ń' => 'n', 'ń' => 'n', 'Ņ' => 'n', 'ņ' => 'n', 'Ň' => 'n', 'ň' => 'n', 51 | 'ʼn' => 'n', 'Ŋ' => 'n', 'ŋ' => 'n', 'Ō' => 'o', 'ō' => 'o', 'Ŏ' => 'o', 52 | 'ŏ' => 'o', 'Ő' => 'o', 'ő' => 'o', 'Œ' => 'oe','œ' => 'oe','Ŕ' => 'r', 53 | 'ŕ' => 'r', 'Ŗ' => 'r', 'ŗ' => 'r', 'Ř' => 'r', 'ř' => 'r', 'Ś' => 's', 54 | 'ś' => 's', 'Ŝ' => 's', 'ŝ' => 's', 'Ş' => 's', 'ş' => 's', 'Š' => 's', 55 | 'š' => 's', 'Ţ' => 't', 'ţ' => 't', 'Ť' => 't', 'ť' => 't', 'Ŧ' => 't', 56 | 'ŧ' => 't', 'Ũ' => 'u', 'ũ' => 'u', 'Ū' => 'u', 'ū' => 'u', 'Ŭ' => 'u', 57 | 'ŭ' => 'u', 'Ů' => 'u', 'ů' => 'u', 'Ű' => 'u', 'ű' => 'u', 'Ų' => 'u', 58 | 'ų' => 'u', 'Ŵ' => 'w', 'ŵ' => 'w', 'Ŷ' => 'y', 'ŷ' => 'y', 'Ÿ' => 'y', 59 | 'Ź' => 'z', 'ź' => 'z', 'Ż' => 'z', 'ż' => 'z', 'Ž' => 'z', 'ž' => 'z', 60 | 'ſ' => 'z', 'Ə' => 'e', 'ƒ' => 'f', 'Ơ' => 'o', 'ơ' => 'o', 'Ư' => 'u', 61 | 'ư' => 'u', 'Ǎ' => 'a', 'ǎ' => 'a', 'Ǐ' => 'i', 'ǐ' => 'i', 'Ǒ' => 'o', 62 | 'ǒ' => 'o', 'Ǔ' => 'u', 'ǔ' => 'u', 'Ǖ' => 'u', 'ǖ' => 'u', 'Ǘ' => 'u', 63 | 'ǘ' => 'u', 'Ǚ' => 'u', 'ǚ' => 'u', 'Ǜ' => 'u', 'ǜ' => 'u', 'Ǻ' => 'a', 64 | 'ǻ' => 'a', 'Ǽ' => 'ae','ǽ' => 'ae','Ǿ' => 'o', 'ǿ' => 'o', 'ə' => 'e', 65 | 'Ё' => 'jo','Є' => 'e', 'І' => 'i', 'Ї' => 'i', 'А' => 'a', 'Б' => 'b', 66 | 'В' => 'v', 'Г' => 'g', 'Д' => 'd', 'Е' => 'e', 'Ж' => 'zh','З' => 'z', 67 | 'И' => 'i', 'Й' => 'j', 'К' => 'k', 'Л' => 'l', 'М' => 'm', 'Н' => 'n', 68 | 'О' => 'o', 'П' => 'p', 'Р' => 'r', 'С' => 's', 'Т' => 't', 'У' => 'u', 69 | 'Ф' => 'f', 'Х' => 'h', 'Ц' => 'c', 'Ч' => 'ch','Ш' => 'sh','Щ' => 'sch', 70 | 'Ъ' => '-', 'Ы' => 'y', 'Ь' => '-', 'Э' => 'je','Ю' => 'ju','Я' => 'ja', 71 | 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 72 | 'ж' => 'zh','з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l', 73 | 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 74 | 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch', 75 | 'ш' => 'sh','щ' => 'sch','ъ' => '-','ы' => 'y', 'ь' => '-', 'э' => 'je', 76 | 'ю' => 'ju','я' => 'ja','ё' => 'jo','є' => 'e', 'і' => 'i', 'ї' => 'i', 77 | 'Ґ' => 'g', 'ґ' => 'g', 'א' => 'a', 'ב' => 'b', 'ג' => 'g', 'ד' => 'd', 78 | 'ה' => 'h', 'ו' => 'v', 'ז' => 'z', 'ח' => 'h', 'ט' => 't', 'י' => 'i', 79 | 'ך' => 'k', 'כ' => 'k', 'ל' => 'l', 'ם' => 'm', 'מ' => 'm', 'ן' => 'n', 80 | 'נ' => 'n', 'ס' => 's', 'ע' => 'e', 'ף' => 'p', 'פ' => 'p', 'ץ' => 'C', 81 | 'צ' => 'c', 'ק' => 'q', 'ר' => 'r', 'ש' => 'w', 'ת' => 't', '™' => 'tm', 82 | ); 83 | 84 | /** 85 | * Check additional instruction for convertation table in configuration 86 | */ 87 | public function __construct() 88 | { 89 | $convertNode = Mage::getConfig()->getNode('default/url/convert'); 90 | if ($convertNode) { 91 | foreach ($convertNode->children() as $node) { 92 | $this->_convertTable[strval($node->from)] = strval($node->to); 93 | } 94 | } 95 | } 96 | 97 | /** 98 | * Get chars convertation table 99 | * 100 | * @return array 101 | */ 102 | public function getConvertTable() 103 | { 104 | return $this->_convertTable; 105 | } 106 | 107 | /** 108 | * Process string based on convertation table 109 | * 110 | * @param string $string 111 | * @return string 112 | */ 113 | public function format($string) 114 | { 115 | return strtr($string, $this->getConvertTable()); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Helper/Search.php: -------------------------------------------------------------------------------- 1 | _init('ak_locator/attribute'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Exception.php: -------------------------------------------------------------------------------- 1 | addFieldToFilter('attribute_code', array('neq' => 'created_at')); 43 | 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Indexer/Url.php: -------------------------------------------------------------------------------- 1 | array( 32 | Mage_Index_Model_Event::TYPE_SAVE 33 | ) 34 | ); 35 | 36 | protected $_relatedConfigSettings = array( 37 | Mage_Catalog_Helper_Category::XML_PATH_CATEGORY_URL_SUFFIX, 38 | Mage_Catalog_Helper_Product::XML_PATH_PRODUCT_URL_SUFFIX, 39 | Mage_Catalog_Helper_Product::XML_PATH_PRODUCT_URL_USE_CATEGORY, 40 | ); 41 | 42 | /** 43 | * Get Indexer name 44 | * 45 | * @return string 46 | */ 47 | public function getName() 48 | { 49 | return Mage::helper('ak_locator')->__('Locator URL Rewrites'); 50 | } 51 | 52 | /** 53 | * Get Indexer description 54 | * 55 | * @return string 56 | */ 57 | public function getDescription() 58 | { 59 | return Mage::helper('ak_locator')->__('Index location URL rewrites'); 60 | } 61 | 62 | /** 63 | * Check if event can be matched by process. 64 | * Overwrote for specific config save, store and store groups save matching 65 | * 66 | * @param Mage_Index_Model_Event $event 67 | * @return bool 68 | */ 69 | public function matchEvent(Mage_Index_Model_Event $event) 70 | { 71 | $data = $event->getNewData(); 72 | if (isset($data[self::EVENT_MATCH_RESULT_KEY])) { 73 | return $data[self::EVENT_MATCH_RESULT_KEY]; 74 | } 75 | 76 | $entity = $event->getEntity(); 77 | if ($entity == Mage_Core_Model_Store::ENTITY) { 78 | $store = $event->getDataObject(); 79 | if ($store && ($store->isObjectNew() || $store->dataHasChangedFor('group_id'))) { 80 | $result = true; 81 | } else { 82 | $result = false; 83 | } 84 | } elseif ($entity == Mage_Core_Model_Store_Group::ENTITY) { 85 | $storeGroup = $event->getDataObject(); 86 | $hasDataChanges = $storeGroup && ($storeGroup->dataHasChangedFor('root_category_id') 87 | || $storeGroup->dataHasChangedFor('website_id')); 88 | if ($storeGroup && !$storeGroup->isObjectNew() && $hasDataChanges) { 89 | $result = true; 90 | } else { 91 | $result = false; 92 | } 93 | } elseif ($entity == Mage_Core_Model_Config_Data::ENTITY) { 94 | $configData = $event->getDataObject(); 95 | if ($configData && in_array($configData->getPath(), $this->_relatedConfigSettings)) { 96 | $result = $configData->isValueChanged(); 97 | } else { 98 | $result = false; 99 | } 100 | } else { 101 | $result = parent::matchEvent($event); 102 | } 103 | 104 | $event->addNewData(self::EVENT_MATCH_RESULT_KEY, $result); 105 | 106 | return $result; 107 | } 108 | 109 | /** 110 | * Register data required by process in event object 111 | * 112 | * @param Mage_Index_Model_Event $event 113 | */ 114 | protected function _registerEvent(Mage_Index_Model_Event $event) 115 | { 116 | $event->addNewData(self::EVENT_MATCH_RESULT_KEY, true); 117 | $entity = $event->getEntity(); 118 | switch ($entity) { 119 | case Mage_Catalog_Model_Product::ENTITY: 120 | $this->_registerProductEvent($event); 121 | break; 122 | 123 | case Mage_Core_Model_Store::ENTITY: 124 | case Mage_Core_Model_Store_Group::ENTITY: 125 | case Mage_Core_Model_Config_Data::ENTITY: 126 | $process = $event->getProcess(); 127 | $process->changeStatus(Mage_Index_Model_Process::STATUS_REQUIRE_REINDEX); 128 | break; 129 | } 130 | return $this; 131 | } 132 | 133 | /** 134 | * Register event data during product save process 135 | * 136 | * @param Mage_Index_Model_Event $event 137 | */ 138 | protected function _registerLocationEvent(Mage_Index_Model_Event $event) 139 | { 140 | $location = $event->getDataObject(); 141 | $dataChange = $location->dataHasChangedFor('url_key') 142 | || $location->getIsChangedWebsites(); 143 | 144 | if (!$location->getExcludeUrlRewrite() && $dataChange) { 145 | $event->addNewData('rewrite_location_ids', array($location->getId())); 146 | } 147 | } 148 | 149 | 150 | /** 151 | * Process event 152 | * 153 | * @param Mage_Index_Model_Event $event 154 | */ 155 | protected function _processEvent(Mage_Index_Model_Event $event) 156 | { 157 | $data = $event->getNewData(); 158 | if (!empty($data['catalog_url_reindex_all'])) { 159 | $this->reindexAll(); 160 | } 161 | 162 | /* @var $urlModel Mage_Catalog_Model_Url */ 163 | $urlModel = Mage::getSingleton('catalog/url'); 164 | 165 | // Force rewrites history saving 166 | $dataObject = $event->getDataObject(); 167 | if ($dataObject instanceof Varien_Object && $dataObject->hasData('save_rewrites_history')) { 168 | $urlModel->setShouldSaveRewritesHistory($dataObject->getData('save_rewrites_history')); 169 | } 170 | 171 | if (isset($data['rewrite_location_ids'])) { 172 | $urlModel->clearStoreInvalidRewrites(); // Maybe some products were moved or removed from website 173 | foreach ($data['rewrite_location_ids'] as $productId) { 174 | $urlModel->refreshProductRewrite($productId); 175 | } 176 | } 177 | } 178 | 179 | /** 180 | * Rebuild all index data 181 | */ 182 | public function reindexAll() 183 | { 184 | /** @var $resourceModel Mage_Catalog_Model_Resource_Url */ 185 | $resourceModel = Mage::getResourceSingleton('ak_locator/url'); 186 | $resourceModel->beginTransaction(); 187 | try { 188 | Mage::getSingleton('ak_locator/url')->refreshRewrites(); 189 | $resourceModel->commit(); 190 | } catch (Exception $e) { 191 | $resourceModel->rollBack(); 192 | throw $e; 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Location.php: -------------------------------------------------------------------------------- 1 | _init('ak_locator/location'); 44 | } 45 | 46 | 47 | /** 48 | * If directions_link isn't already set in data first generate it 49 | * 50 | * @return string 51 | */ 52 | public function getDirectionsLink() 53 | { 54 | if (null === $this->getData('directions_link')) { 55 | $this->setDirectionsLink(); 56 | } 57 | 58 | return $this->getData('directions_link'); 59 | } 60 | 61 | 62 | /** 63 | * Create Google maps direction link and set in data 64 | * 65 | * @param array $options 66 | */ 67 | public function setDirectionsLink($options = array()) 68 | { 69 | 70 | $address = ""; 71 | $attrs = array('address', 'postal_code', 'country'); 72 | $count = 0; 73 | 74 | foreach ($attrs as $attr) { 75 | if ($this->getData($attr) && $this->getData($attr) != '') { 76 | if ($count > 0) { 77 | $address .= ', '; 78 | } 79 | 80 | $address .=$this->getData($attr); 81 | $count ++; 82 | } 83 | } 84 | 85 | $params = array( 86 | 'daddr' => $address . '@' . $this->getLatitude().','.$this->getLongitude() 87 | ); 88 | 89 | if (isset($options['start'])) { 90 | if ($options['start'] instanceof Point) { 91 | $params['saddr']=$options['start']->coords[1].','.$options['start']->coords[0]; 92 | } else { 93 | $params['saddr']=$options['start']; 94 | } 95 | } 96 | 97 | $this->setData( 98 | 'directions_link', 99 | Mage::helper('core/url')->addRequestParam('http://maps.google.com/maps', $params) 100 | ); 101 | } 102 | 103 | 104 | /** 105 | * Get url to location 106 | * 107 | * @return string 108 | */ 109 | public function getUrl() 110 | { 111 | return $this->getUrlModel()->getUrl($this, null); 112 | } 113 | 114 | 115 | /** 116 | * Get location url model 117 | * 118 | * @return Ak_Locator_Model_Location_Url 119 | */ 120 | public function getUrlModel() 121 | { 122 | if ($this->_urlModel === null) { 123 | $this->_urlModel = Mage::getSingleton('ak_locator/location_url'); 124 | } 125 | return $this->_urlModel; 126 | } 127 | 128 | 129 | /** 130 | * Formats URL key 131 | * 132 | * @param $str URL 133 | * @return string 134 | */ 135 | public function formatUrlKey($str) 136 | { 137 | return $this->getUrlModel()->formatUrlKey($str); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Location/Attribute/Backend/Image.php: -------------------------------------------------------------------------------- 1 | getData($this->getAttribute()->getName()); 29 | 30 | if (is_array($value) && !empty($value['delete'])) { 31 | $object->setData($this->getAttribute()->getName(), ''); 32 | $this->getAttribute()->getEntity() 33 | ->saveAttribute($object, $this->getAttribute()->getName()); 34 | return; 35 | } 36 | 37 | $path = Mage::getBaseDir('media') . DS . 'locator' . DS . 'location' . DS; 38 | 39 | try { 40 | $uploader = new Mage_Core_Model_File_Uploader($this->getAttribute()->getName()); 41 | $uploader->setAllowedExtensions(array('jpg','jpeg','gif','png')); 42 | $uploader->setAllowRenameFiles(true); 43 | $result = $uploader->save($path); 44 | 45 | $object->setData($this->getAttribute()->getName(), $result['file']); 46 | $this->getAttribute()->getEntity()->saveAttribute($object, $this->getAttribute()->getName()); 47 | 48 | 49 | } catch (Exception $e) { 50 | if ($e->getCode() != Mage_Core_Model_File_Uploader::TMP_NAME_EMPTY) { 51 | Mage::logException($e); 52 | } 53 | /** @TODO ??? */ 54 | return; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Location/Url.php: -------------------------------------------------------------------------------- 1 | _store = !empty($args['store']) ? $args['store'] : Mage::app()->getStore(); 60 | } 61 | 62 | /** 63 | * Retrieve URL Instance 64 | * 65 | * @return Mage_Core_Model_Url 66 | */ 67 | public function getUrlInstance() 68 | { 69 | if (null === $this->_url) { 70 | $this->_url = Mage::getModel('core/url'); 71 | } 72 | return $this->_url; 73 | } 74 | 75 | /** 76 | * Retrieve URL Rewrite Instance 77 | * 78 | * @return Mage_Core_Model_Url_Rewrite 79 | */ 80 | public function getUrlRewrite() 81 | { 82 | if (null === $this->_urlRewrite) { 83 | $this->_urlRewrite = Mage::getModel('core/url_rewrite'); 84 | } 85 | return $this->_urlRewrite; 86 | } 87 | 88 | /** 89 | * 'no_selection' shouldn't be a valid image attribute value 90 | * 91 | * @param string $image 92 | * @return string 93 | */ 94 | protected function _validImage($image) 95 | { 96 | if ($image == 'no_selection') { 97 | $image = null; 98 | } 99 | return $image; 100 | } 101 | 102 | /** 103 | * Retrieve URL in current store 104 | * 105 | * @param Ak_Locator_Model_Location $location 106 | * @param array $params the URL route params 107 | * @return string 108 | */ 109 | public function getUrlInStore(Ak_Locator_Model_Location $location, $params = array()) 110 | { 111 | $params['_store_to_url'] = true; 112 | return $this->getUrl($location, $params); 113 | } 114 | 115 | /** 116 | * Retrieve Location URL 117 | * 118 | * @param Ak_Locator_Model_Location $location 119 | * @param bool $useSid forced SID mode 120 | * @return string 121 | */ 122 | public function getLocationUrl(Ak_Locator_Model_Location $location, $useSid = null) 123 | { 124 | if ($useSid === null) { 125 | $useSid = Mage::app()->getUseSessionInUrl(); 126 | } 127 | 128 | $params = array(); 129 | if (!$useSid) { 130 | $params['_nosid'] = true; 131 | } 132 | 133 | return $this->getUrl($location, $params); 134 | } 135 | 136 | /** 137 | * Format Key for URL 138 | * 139 | * @param string $str 140 | * @return string 141 | */ 142 | public function formatUrlKey($str) 143 | { 144 | $urlKey = preg_replace('#[^0-9a-z]+#i', '-', Mage::helper('ak_locator/location_url')->format($str)); 145 | $urlKey = strtolower($urlKey); 146 | $urlKey = trim($urlKey, '-'); 147 | 148 | return $urlKey; 149 | } 150 | 151 | /** 152 | * Retrieve Location Url path 153 | * 154 | * @param Ak_Locator_Model_Location $location 155 | * 156 | * @return string 157 | */ 158 | public function getUrlPath($location) 159 | { 160 | $path = $location->getData('url_path'); 161 | return $path; 162 | } 163 | 164 | /** 165 | * Retrieve Product URL using UrlDataObject 166 | * 167 | * @param Ak_Locator_Model_Location $location 168 | * @param array $params 169 | * @return string 170 | */ 171 | public function getUrl(Ak_Locator_Model_Location $location, $params = array()) 172 | { 173 | $url = $location->getData('url'); 174 | 175 | if (!empty($url)) { 176 | return $url; 177 | } 178 | 179 | $requestPath = $location->getData('request_path'); 180 | 181 | if (empty($requestPath)) { 182 | $requestPath = $this->_getRequestPath($location); 183 | $location->setRequestPath($requestPath); 184 | } 185 | 186 | 187 | 188 | if (isset($params['_store'])) { 189 | $storeId = $this->_getStoreId($params['_store']); 190 | } else { 191 | $storeId = $location->getStoreId(); 192 | } 193 | 194 | if ($storeId != $this->_getStoreId()) { 195 | $params['_store_to_url'] = true; 196 | } 197 | 198 | // reset cached URL instance GET query params 199 | if (!isset($params['_query'])) { 200 | $params['_query'] = array(); 201 | } 202 | 203 | $this->getUrlInstance()->setStore($storeId); 204 | $locationUrl = $this->_getLocationUrl($location, $requestPath, $params); 205 | $location->setData('url', $locationUrl); 206 | 207 | 208 | return $location->getData('url'); 209 | } 210 | 211 | /** 212 | * Returns checked store_id value 213 | * 214 | * @param int|null $id 215 | * @return int 216 | */ 217 | protected function _getStoreId($id = null) 218 | { 219 | return Mage::app()->getStore($id)->getId(); 220 | } 221 | 222 | 223 | /** 224 | * Retrieve product URL based on requestPath param 225 | * 226 | * @param Ak_Locator_Model_Location $location 227 | * @param string $requestPath 228 | * @param array $routeParams 229 | * 230 | * @return string 231 | */ 232 | protected function _getLocationUrl($location, $requestPath, $routeParams) 233 | { 234 | if (!empty($requestPath)) { 235 | return $this->getUrlInstance()->getDirectUrl($requestPath, $routeParams); 236 | } 237 | $routeParams['id'] = $location->getId(); 238 | $routeParams['s'] = $location->getUrlKey(); 239 | 240 | return $this->getUrlInstance()->getUrl('locator/location/index', $routeParams); 241 | 242 | } 243 | 244 | /** 245 | * Retrieve request path 246 | * 247 | * @param Ak_Locator_Model_Location $location 248 | * 249 | * @return bool|string 250 | */ 251 | protected function _getRequestPath(Ak_Locator_Model_Location $location) 252 | { 253 | $idPath = sprintf('location/%d', $location->getEntityId()); 254 | 255 | $rewrite = $this->getUrlRewrite(); 256 | $rewrite->setStoreId($location->getStoreId()) 257 | ->loadByIdPath($idPath); 258 | if ($rewrite->getId()) { 259 | return $rewrite->getRequestPath(); 260 | } 261 | 262 | return false; 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Observer.php: -------------------------------------------------------------------------------- 1 | addError( 27 | 'Warning: You haven\'t yet set a Google API key in locator configuration, 28 | the locator module requires the Google Maps API to function. 29 | You can sign up for a key here.' 30 | ); 31 | 32 | } 33 | 34 | if (!@class_exists('geoPHP')) { 35 | Mage::getSingleton('core/session')->addError( 36 | 'Warning: The geoPHP library could not be detected, 37 | this is a requirement of the Locator extension. 38 | Please download the library and add it to the lib directory' 39 | ); 40 | } 41 | } 42 | 43 | /** 44 | * Attempt to load geoPHP from lib and vendor directories 45 | */ 46 | public function loadLibraries() 47 | { 48 | $files = array( 49 | Mage::getBaseDir('lib').'/geoPHP/geoPHP.inc', 50 | Mage::getBaseDir().'/vendor/phayes/geophp/geoPHP.inc' 51 | ); 52 | //try to find the geoPHP library 53 | foreach ($files as $file) { 54 | if (file_exists($file)) { 55 | require $file; 56 | return; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Attribute.php: -------------------------------------------------------------------------------- 1 | getTable('ak_locator/eav_attribute_website'); 31 | } 32 | 33 | /** 34 | * Get Form attribute table 35 | * 36 | * Get table, where dependency between form name and attribute ids is stored 37 | * 38 | * @return string|null 39 | */ 40 | protected function _getFormAttributeTable() 41 | { 42 | return $this->getTable('ak_locator/form_attribute'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Attribute/Collection.php: -------------------------------------------------------------------------------- 1 | _entityTypeCode; 36 | } 37 | 38 | /** 39 | * Get EAV website table 40 | * 41 | * Get table, where website-dependent attribute parameters are stored 42 | * If realization doesn't demand this functionality, let this function just return null 43 | * 44 | * @return string|null 45 | */ 46 | protected function _getEavWebsiteTable() 47 | { 48 | return $this->getTable('ak_locator/eav_attribute_website'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Form/Attribute.php: -------------------------------------------------------------------------------- 1 | _init('ak_locator/form_attribute', 'attribute_id'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Form/Attribute/Collection.php: -------------------------------------------------------------------------------- 1 | _init('eav/attribute', 'ak_locator/form_attribute'); 40 | } 41 | 42 | /** 43 | * Get EAV website table 44 | * 45 | * Get table, where website-dependent attribute parameters are stored. 46 | * If realization doesn't demand this functionality, let this function just return null 47 | * 48 | * @return string|null 49 | */ 50 | protected function _getEavWebsiteTable() 51 | { 52 | return $this->getTable('ak_locator/eav_attribute_website'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Location.php: -------------------------------------------------------------------------------- 1 | setType(Ak_Locator_Model_Location::ENTITY); 24 | 25 | $this->setConnection( 26 | $resource->getConnection('ak_locator_read'), 27 | $resource->getConnection('ak_locator_write') 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Location/Collection.php: -------------------------------------------------------------------------------- 1 | _init('ak_locator/location'); 35 | } 36 | 37 | /** 38 | * Override parent method to remove entity_type_id filter 39 | * 40 | * @return $this 41 | */ 42 | protected function _initSelect() 43 | { 44 | $this->getSelect()->from(array('e' => $this->getEntity()->getEntityTable())); 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * Use Haversine formula to find locations within a given radius of a point 51 | * http://en.wikipedia.org/wiki/Haversine_formula 52 | * 53 | * @param Point $point 54 | * @param int $radius 55 | * 56 | * @return $this 57 | */ 58 | public function nearPoint(Point $point, $radius = 0) 59 | { 60 | $this->addExpressionAttributeToSelect( 61 | 'distance', 62 | sprintf( 63 | "(6371 * acos(cos(radians('%s')) * cos(radians(latitude)) * cos(radians(longitude) - radians('%s')) + sin(radians('%s')) * sin( radians(latitude))))", 64 | $point->coords[1], 65 | $point->coords[0], 66 | $point->coords[1], 67 | $radius 68 | ), 69 | array('entity_id') 70 | ); 71 | 72 | if ($radius !== 0) { 73 | $this->getSelect()->having('distance < ?', $radius); 74 | } 75 | 76 | $this->setSearchPoint($point); 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * @param string $valueField 83 | * @param string $labelField 84 | * @param array $additional 85 | * 86 | * @return mixed 87 | */ 88 | public function toOptionArray($valueField = 'entity_id', $labelField = 'title', $additional = array()) 89 | { 90 | return $this->_toOptionArray($valueField, $labelField, $additional); 91 | } 92 | 93 | /** 94 | * Output this collection as a json object to be used by search frontend 95 | * 96 | * @return mixed 97 | */ 98 | public function toJson() 99 | { 100 | $locations = array(); 101 | 102 | foreach ($this->getItems() as $location) { 103 | $loc = array(); 104 | $loc['id'] = $location->getId(); 105 | $loc['title'] = $location->getTitle(); 106 | $loc['latitude'] = $location->getLatitude(); 107 | $loc['longitude'] = $location->getLongitude(); 108 | $loc['distance'] = (string)round($location->getDistance(), 2); 109 | $loc['directions'] = $location->getDirectionsLink(); 110 | 111 | $locations[(int)$location->getEntityId()] = $loc; 112 | } 113 | 114 | $obj = new Varien_Object(); 115 | $obj->setLocations($locations); 116 | 117 | //dispatch event to allow other modules to add to the json 118 | Mage::dispatchEvent('ak_locator_before_search_json_output', array('collection'=>$this, 'json_data'=>$obj)); 119 | 120 | $json = Zend_Json::encode($obj->getLocations()); 121 | //zend_json doesn't encode single quotes but they break in the browser 122 | $json = str_replace('\'', ''', $json); 123 | return $json; 124 | } 125 | 126 | /** 127 | * @param Point $point 128 | */ 129 | public function setSearchPoint(Point $point) 130 | { 131 | $this->_point = $point; 132 | } 133 | 134 | /** 135 | * @return Point 136 | */ 137 | public function getSearchPoint() 138 | { 139 | return $this->_point; 140 | } 141 | 142 | /** 143 | * @param $search 144 | */ 145 | public function setSearch($search) 146 | { 147 | $this->_search = $search; 148 | } 149 | 150 | 151 | public function getSearch() 152 | { 153 | return $this->_search; 154 | } 155 | 156 | 157 | /** 158 | * Get object containing result to be output 159 | * 160 | * @return Varien_Object 161 | */ 162 | public function getResponseObject() 163 | { 164 | $obj = new Varien_Object(); 165 | $point = $this->getSearchPoint(); 166 | 167 | 168 | $obj->setLocations($this->toJson()); 169 | 170 | if (!is_null($point) 171 | && Mage::getStoreConfig(self::XML_PATH_SEARCH_SHOW_POINT) 172 | ) { 173 | $obj->setSearchPoint($point); 174 | } 175 | 176 | return $obj; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Search/Override.php: -------------------------------------------------------------------------------- 1 | _init('ak_locator/search_override', 'string'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Resource/Search/Override/Collection.php: -------------------------------------------------------------------------------- 1 | _init('ak_locator/search_override'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Search/Handler/Abstract.php: -------------------------------------------------------------------------------- 1 | getCollection(); 38 | } 39 | 40 | 41 | /** 42 | * Get the collection class that will be used to find locations 43 | * 44 | * @return Mage_Eav_Model_Entity_Collection_Abstract 45 | */ 46 | public function getCollection() 47 | { 48 | if (!$this->_collection) { 49 | $this->setCollection( 50 | $this->getModel() 51 | ->getCollection() 52 | ->addAttributeToFilter('is_enabled', '1') 53 | ); 54 | } 55 | 56 | return $this->_collection; 57 | } 58 | 59 | /** 60 | * 61 | * 62 | * @return Mage_Core_Model_Abstract 63 | */ 64 | public function getModel() 65 | { 66 | if (!$this->_model) { 67 | $this->setModel(Mage::getModel('ak_locator/location')); 68 | } 69 | 70 | return $this->_model; 71 | } 72 | 73 | /** 74 | * Set the collection class that will be used to find locations 75 | * 76 | * @param Mage_Eav_Model_Entity_Collection_Abstract $collection 77 | * @return $this 78 | */ 79 | public function setCollection(Mage_Eav_Model_Entity_Collection_Abstract $collection) 80 | { 81 | $this->_collection = $collection; 82 | 83 | return $this; 84 | } 85 | 86 | /** 87 | * 88 | * @param Mage_Core_Model_Abstract $model 89 | * @return $this 90 | */ 91 | public function setModel(Mage_Core_Model_Abstract $model) 92 | { 93 | $this->_model = $model; 94 | 95 | return $this; 96 | } 97 | 98 | 99 | /** 100 | * Make any manipulations to parameters required by this handler 101 | * 102 | * @param array $params 103 | * @return array 104 | */ 105 | public function parseParams(array $params) 106 | { 107 | return $params; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Search/Handler/Area.php: -------------------------------------------------------------------------------- 1 | isValidParams($params)) { 37 | throw new Exception('At least one valid search parameter must be passed'); 38 | } 39 | 40 | $collection = $this->areaSearch($params); 41 | $collection->setSearch($this); 42 | 43 | return $collection; 44 | } 45 | 46 | /** 47 | * Make any manipulations to parameters required by this handler 48 | * 49 | * @param array $params 50 | * @return array 51 | */ 52 | public function parseParams(array $params) 53 | { 54 | if (isset($params['a']) && !isset($params['administrative_area'])) { 55 | $params['administrative_area'] = $params['a']; 56 | } 57 | 58 | if (isset($params['c']) && !isset($params['country'])) { 59 | $params['country'] = $params['c']; 60 | } 61 | 62 | return $params; 63 | } 64 | 65 | 66 | /** 67 | * Validate params 68 | * 69 | * @param array $params 70 | * @return bool 71 | */ 72 | public function isValidParams(array $params) 73 | { 74 | if ((isset($params['a']) && $params['a'] != '') 75 | || (isset($params['c']) && $params['c'] != '') 76 | || (isset($params['country']) && $params['country'] != '') 77 | || (isset($params['administrative_area']) && $params['administrative_area'] != '') 78 | || (isset($params['postcode']) && $params['postcode'] != '') 79 | ) { 80 | return true; 81 | } 82 | 83 | return false; 84 | } 85 | 86 | 87 | /** 88 | * Find locations based on area attributes 89 | * 90 | * @param string name of the administrative area 91 | * @return Ak_Locator_Model_Resource_Location_Collection 92 | */ 93 | public function areaSearch($params) 94 | { 95 | $collection = $this->getCollection(); 96 | 97 | if (isset($params['country']) && $params['country'] != '') { 98 | $collection->addAttributeToFilter('country', $params['country']); 99 | } 100 | 101 | if (isset($params['administrative_area']) && $params['administrative_area'] != '') { 102 | $collection->addAttributeToFilter('administrative_area', $params['administrative_area']); 103 | } 104 | 105 | if (isset($params['postcode']) && $params['postcode'] != '') { 106 | $collection->addAttributeToFilter('postcode', $params['postcode']); 107 | } 108 | 109 | //area searches cant be sorted by proximity so sort them by title 110 | $collection->setOrder('title'); 111 | 112 | $collection->addAttributeToSelect('*'); 113 | return $collection; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Search/Handler/Interface.php: -------------------------------------------------------------------------------- 1 | getCollection() 40 | ->addAttributeToSelect('*') 41 | ->nearPoint($point, $radius) 42 | ->setOrder('distance'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Search/Handler/Point/Closest.php: -------------------------------------------------------------------------------- 1 | isValidParams($params)) { 16 | throw new InvalidArgumentException('A point object must be passed'); 17 | } 18 | 19 | $collection = $this->pointToLocations($params['point'], 50000); 20 | $collection->getSelect()->limit(1); 21 | $collection->setSearch($this); 22 | 23 | return $collection; 24 | } 25 | 26 | 27 | /** 28 | * Validate params 29 | * 30 | * @param array $params 31 | * @return bool 32 | */ 33 | public function isValidParams(array $params) 34 | { 35 | if (isset($params['point']) 36 | && is_object($params['point']) 37 | && get_class($params['point']) == 'Point' 38 | ) { 39 | return true; 40 | } 41 | 42 | return false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Search/Handler/Point/Latlong.php: -------------------------------------------------------------------------------- 1 | isValidParams($params)) { 37 | throw new InvalidArgumentException('Both latitude and longitude values are required to do a lat/long search'); 38 | } 39 | 40 | $point = new Point($params['long'], $params['lat']); 41 | 42 | $collection = $this->pointToLocations($point, @$params['distance']); 43 | $collection->setSearch($this); 44 | 45 | return $collection; 46 | } 47 | 48 | 49 | /** 50 | * Validate params 51 | * 52 | * @param array $params 53 | * @return bool 54 | */ 55 | public function isValidParams(array $params) 56 | { 57 | //lat and long must be set 58 | if (isset($params['lat']) && $params['lat'] != '' && isset($params['long']) && $params['long'] != '') { 59 | //and numeric 60 | if (is_numeric($params['lat']) && is_numeric($params['long'])) { 61 | return true; 62 | }; 63 | } 64 | 65 | return false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Search/Handler/Point/String.php: -------------------------------------------------------------------------------- 1 | isValidParams($params)) { 50 | throw new InvalidArgumentException('A search string must be passed to perform a string search'); 51 | } 52 | 53 | $point = $this->stringToPoint($this->createSearchString($params)); 54 | 55 | if (isset($params['distance'])) { 56 | $collection = $this->pointToLocations($point, $params['distance']); 57 | } else { 58 | $collection = $this->pointToLocations($point); 59 | } 60 | 61 | $collection->setSearch($this); 62 | 63 | return $collection; 64 | 65 | } 66 | 67 | 68 | protected function createSearchString (array $params) 69 | { 70 | 71 | $query = $params['s']; 72 | 73 | if (isset($params['a'])) { 74 | $query .= ' '.$params['a']; 75 | } 76 | 77 | if (isset($params['country'])) { 78 | $query .= ' '.$params['country']; 79 | } 80 | 81 | $appendText = (Mage::getStoreConfig(self::XML_SEARCH_SHOULDAPPEND_PATH))?Mage::getStoreConfig(self::XML_SEARCH_APPENDTEXT_PATH):''; 82 | $query .= ' '.$appendText; 83 | 84 | return $query; 85 | } 86 | 87 | /** 88 | * Validate params 89 | * 90 | * @param array $params 91 | * @return bool 92 | */ 93 | public function isValidParams(array $params) 94 | { 95 | if (isset($params['s']) && $params['s'] != '') { 96 | return true; 97 | } 98 | 99 | return false; 100 | } 101 | 102 | 103 | /** 104 | * Geocode a search string into a Lat/Long Point 105 | * 106 | * @param $query 107 | * 108 | * @return Point 109 | * @throws Ak_Locator_Model_Exception_Geocode 110 | * @throws Exception 111 | */ 112 | protected function stringToPoint($query) 113 | { 114 | $cache = $this->getCache(); 115 | 116 | $this->log('geocoding '.$query); 117 | 118 | if (!$this->_isCacheEnabled() || !$result = unserialize($cache->load(self::CACHE_TAG.'_'.$query))) { 119 | $key = Mage::getStoreConfig(self::XML_SEARCH_APIKEY_PATH); 120 | 121 | try { 122 | $geocoder = new GoogleGeocode($key); 123 | $result = $geocoder->read($query); 124 | 125 | $this->log('result '.$this->formatLogOutput($result)); 126 | 127 | $cache->save(serialize($result), self::CACHE_TAG.'_'.$query, array(self::CACHE_TAG)); 128 | 129 | } catch (Exception $e) { 130 | 131 | if (strpos($e->getMessage(), 'ZERO_RESULTS')) { 132 | throw new Ak_Locator_Model_Exception_Geocode($e->getMessage()); 133 | } 134 | 135 | throw $e; 136 | } 137 | } else { 138 | $this->log('result from cache '.$this->formatLogOutput($result)); 139 | } 140 | 141 | return $result; 142 | } 143 | 144 | /** 145 | * Format result for logging 146 | * 147 | * @param Geometry $result 148 | * @return string 149 | */ 150 | protected function formatLogOutput(Geometry $result) 151 | { 152 | switch (get_class($result)) { 153 | case "Point": 154 | return 'lat: '.$result->coords[1].', long:'.$result->coords[0]; 155 | default: 156 | return 'unknown result format'; 157 | } 158 | 159 | } 160 | 161 | /** 162 | * 163 | * @return mixed 164 | */ 165 | protected function getCache() 166 | { 167 | if (!$this->_cache) { 168 | $this->_cache = Mage::app()->getCache(); 169 | } 170 | 171 | return $this->_cache; 172 | } 173 | 174 | 175 | /** 176 | * Check cache availability 177 | * 178 | * @return bool 179 | */ 180 | protected function _isCacheEnabled() 181 | { 182 | if ($this->_isCacheEnabled === null) { 183 | $this->_isCacheEnabled = Mage::app()->useCache(self::CACHE_ID); 184 | } 185 | return $this->_isCacheEnabled; 186 | } 187 | 188 | protected function log($message, $level = Zend_Log::DEBUG, $file = 'locator_geocoding.log') 189 | { 190 | if (Mage::getStoreConfig(self::XML_SEARCH_LOG_GEO)) { 191 | Mage::log($message, $level, $file); 192 | } 193 | 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Search/Override.php: -------------------------------------------------------------------------------- 1 | _init('ak_locator/search_override'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Model/Urlrewrite/Matcher/Location.php: -------------------------------------------------------------------------------- 1 | _seoSuffix = Mage::getStoreConfig(Ak_Locator_Helper_Location::XML_PATH_LOCATION_URL_SUFFIX); 9 | } 10 | 11 | /** 12 | * Match product rewrite 13 | * 14 | * @param array $rewriteRow 15 | * @param string $requestPath 16 | * @return bool 17 | */ 18 | public function match(array $rewriteRow, $requestPath) 19 | { 20 | $entityType = Mage::getModel('eav/config')->getEntityType('ak_locator_location'); 21 | $entityTypeId = $entityType->getEntityTypeId(); 22 | 23 | if ($entityTypeId != $rewriteRow['entity_type']) { 24 | return false; 25 | } 26 | 27 | $rewriteParts = explode('/', $rewriteRow['request_path']); 28 | $rewriteTail = array_pop($rewriteParts); 29 | 30 | if (!empty($this->_seoSuffix)) { 31 | $rewriteTail .= $this->_seoSuffix; 32 | } 33 | 34 | $requestParts = explode('/', $requestPath); 35 | $requestTail = array_pop($requestParts); 36 | 37 | if (strcmp($rewriteTail, $requestTail) === 0) { 38 | 39 | $locationId = substr($rewriteRow['target_path'], strrpos($rewriteRow['target_path'], '/')+1); 40 | 41 | $isMatched = !empty($locationId); 42 | // && $this->_isRewriteRedefinedInStore($locationId, $rewriteRow['request_path']); 43 | 44 | if ($isMatched) { 45 | //$this->_checkStoreRedirect($productId, $categoryPath); 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | 52 | 53 | // /** 54 | // * Is rewrite redefined on store level 55 | // * 56 | // * @param $productId 57 | // * @param $requestPath 58 | // * @return bool 59 | // */ 60 | // protected function _isRewriteRedefinedInStore($locationId, $requestPath) 61 | // { 62 | // // Check that url key isn't redefined on store level 63 | // $storeRewriteRow = $this->_productResource->getRewriteByStoreId($this->_prevStoreId, $locationId); 64 | // if (!empty($storeRewriteRow) && $storeRewriteRow['request_path'] != $requestPath) { 65 | // return false; 66 | // } 67 | // return true; 68 | // } 69 | // 70 | // /** 71 | // * Redirect to product from another store if custom url key defined 72 | // * 73 | // * @param int $productId 74 | // * @param string $categoryPath 75 | // */ 76 | // protected function _checkStoreRedirect($productId, $categoryPath) 77 | // { 78 | // if ($this->_prevStoreId != $this->_storeId) { 79 | // $rewrite = $this->_productResource->getRewriteByProductId($productId, $this->_storeId); 80 | // if (!empty($rewrite)) { 81 | // $requestPath = $rewrite['request_path']; 82 | // if (!empty($this->_newStoreSeoSuffix)) { 83 | // $requestPath .= '.' . $this->_newStoreSeoSuffix; 84 | // } 85 | // if (!empty($categoryPath)) { 86 | // $requestPath = $this->_getNewStoreCategoryPath($categoryPath) . '/' . $requestPath; 87 | // } 88 | // 89 | // $requestPath = $this->_getBaseUrl() . $requestPath; 90 | // $this->_response->setRedirect($requestPath, 301); 91 | // $this->_request->setDispatched(true); 92 | // } 93 | // } 94 | // } 95 | } 96 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Helper/Data.php: -------------------------------------------------------------------------------- 1 | _helper = Mage::helper('ak_locator'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Helper_Data', $this->_helper); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Helper/Search.php: -------------------------------------------------------------------------------- 1 | _helper = Mage::helper('ak_locator/search'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Helper_Search', $this->_helper); 25 | } 26 | 27 | 28 | /** 29 | * @test 30 | */ 31 | public function testParseQuery() 32 | { 33 | 34 | $string = 'lat=-37.814207400000&long=144.964045100000'; 35 | 36 | $result = $this->_helper->parseQueryString($string); 37 | $expected = array('lat'=>'-37.814207400000', 'long'=>'144.964045100000'); 38 | 39 | $this->assertInternalType('array', $result); 40 | 41 | $this->assertArrayHasKey('lat', $result); 42 | $this->assertArrayHasKey('long', $result); 43 | 44 | $this->assertEquals(json_encode($expected), json_encode($result)); 45 | 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Location.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/location'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Location', $this->_model); 25 | } 26 | 27 | public function testDefaultDirectionLink() 28 | { 29 | $this->assertInternalType('string', $this->_model->getDirectionsLink()); 30 | } 31 | 32 | 33 | /** 34 | * @test 35 | * @loadFixture default 36 | */ 37 | public function testSetDirectionLinkNoParams() 38 | { 39 | $this->_model->load(1); 40 | $this->_model->setDirectionsLink(); 41 | 42 | $link = $this->_model->getDirectionsLink(); 43 | 44 | $parts = parse_url($link); 45 | parse_str($parts['query'], $queryParams); 46 | 47 | $this->assertInternalType('string', $link); 48 | $this->assertStringStartsWith('http://maps.google.com/', $link); 49 | $this->assertEquals('@-37.814207400000,144.964045100000', $queryParams['daddr']); 50 | } 51 | 52 | 53 | /** 54 | * @test 55 | * @loadFixture default 56 | */ 57 | public function testSetDirectionsLinkStartPoint() 58 | { 59 | $params = array( 60 | 'start' => new Point(-37.815207400000, 144.924045100000) 61 | ); 62 | 63 | $this->_model->setDirectionsLink($params); 64 | 65 | $link = $this->_model->getDirectionsLink(); 66 | $parts = parse_url($link); 67 | parse_str($parts['query'], $queryParams); 68 | 69 | $this->assertInternalType('string', $link); 70 | $this->assertStringStartsWith('http://maps.google.com/', $link); 71 | $this->assertEquals('144.9240451,-37.8152074', $queryParams['saddr']); 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Location/fixtures/default.yaml: -------------------------------------------------------------------------------- 1 | eav: 2 | ak_locator_location: 3 | - entity_id: 1 4 | title: Test Location 5 | name: Test Location 6 | latitude: -37.81420740.0000 7 | longitude: 144.964045100000 8 | is_enabled: 1 9 | - entity_id: 2 10 | latitude: -37.798571000000 11 | longitude: 144.976710000000 12 | is_enabled: 1 -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Observer.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/observer'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Observer', $this->_model); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/search'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Search', $this->_model); 25 | } 26 | 27 | 28 | /** 29 | * @test 30 | */ 31 | public function testStringSearchResultInstance() 32 | { 33 | $params = array('s' => '3141 australia'); 34 | $this->assertInstanceOf('Ak_Locator_Model_Resource_Location_Collection', $this->_model->search($params)); 35 | } 36 | 37 | /** 38 | * @test 39 | */ 40 | public function testLatLongSearchResultInstance() 41 | { 42 | $params = array('lat'=>-37.814207400000, 'long'=>144.964045100000); 43 | $this->assertInstanceOf('Ak_Locator_Model_Resource_Location_Collection', $this->_model->search($params)); 44 | 45 | } 46 | 47 | /** 48 | * @test 49 | */ 50 | public function testPointSearchResultInstance() 51 | { 52 | $params = array('point'=> new Point(-37.814207400000, 144.964045100000)); 53 | $this->assertInstanceOf('Ak_Locator_Model_Resource_Location_Collection', $this->_model->search($params)); 54 | } 55 | 56 | /** 57 | * @test 58 | * @loadFixture 59 | */ 60 | public function testLatLongSearchDistance() 61 | { 62 | $params = array( 63 | 'lat'=>-37.814207400000, 64 | 'long'=>144.964045100000, 65 | 'distance' => 5 66 | ); 67 | 68 | $this->assertEquals(2, $this->_model->search($params)->count()); 69 | } 70 | 71 | /** 72 | * @test 73 | * @loadFixture testLatLongSearchDistance 74 | */ 75 | public function testClosest() 76 | { 77 | $params = array( 78 | 'point'=> new Point(144.964045100000, -37.814207400000) 79 | ); 80 | 81 | $this->assertEquals(1, $this->_model->search($params)->count()); 82 | } 83 | 84 | 85 | /** 86 | * @test 87 | * @loadFixture 88 | */ 89 | public function testLatLongSearchEnabled() 90 | { 91 | $params = array( 92 | 'lat'=>-37.814207400000, 93 | 'long'=>144.964045100000, 94 | 'distance' => 20 95 | ); 96 | 97 | $this->assertEquals(2, $this->_model->search($params)->count()); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search/Handler/Abstract.php: -------------------------------------------------------------------------------- 1 | _model = $this->getMockForAbstractClass('Ak_Locator_Model_Search_Handler_Abstract'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testDefaultCollectionClass() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Resource_Location_Collection', $this->_model->getCollection()); 25 | } 26 | 27 | /** 28 | * @test 29 | */ 30 | public function testDefaultModelClass() 31 | { 32 | $this->assertInstanceOf('Mage_Core_Model_Abstract', $this->_model->getModel()); 33 | } 34 | 35 | /** 36 | * @test 37 | */ 38 | public function testParseParams() 39 | { 40 | $params = array('s'=>'australia'); 41 | $this->assertInternalType('array', $this->_model->parseParams($params)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search/Handler/Area.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/search_handler_area'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Search_Handler_Area', $this->_model); 25 | } 26 | 27 | /** 28 | * @test 29 | */ 30 | public function testValidParams() 31 | { 32 | $params = array('a'=>'victoria'); 33 | $this->assertTrue($this->_model->isValidParams($params)); 34 | 35 | 36 | $params = array('country'=>'australia'); 37 | $this->assertTrue($this->_model->isValidParams($params)); 38 | 39 | $params = array('a'=>'victoria', 'country'=>'australia'); 40 | $this->assertTrue($this->_model->isValidParams($params)); 41 | 42 | $params = array('s'=>'123 test street', 'country'=>'australia'); 43 | $this->assertTrue($this->_model->isValidParams($params)); 44 | } 45 | 46 | /** 47 | * @test 48 | */ 49 | public function testInvalidParams() 50 | { 51 | $params = array(); 52 | $this->assertFalse($this->_model->isValidParams($params)); 53 | 54 | $params = array('s'=>'australia'); 55 | $this->assertFalse($this->_model->isValidParams($params)); 56 | } 57 | 58 | 59 | /** 60 | * @test 61 | */ 62 | public function testParseParams() 63 | { 64 | $params = array('s'=>'australia'); 65 | $this->assertInternalType('array', $this->_model->parseParams($params)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search/Handler/Point/Closest.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/search_handler_point_closest'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Search_Handler_Point_Closest', $this->_model); 25 | } 26 | 27 | /** 28 | * @test 29 | */ 30 | public function testValidParams() 31 | { 32 | $params = array('point'=> new Point(-37.814207400000, 144.964045100000)); 33 | $this->assertTrue($this->_model->isValidParams($params)); 34 | } 35 | 36 | /** 37 | * @test 38 | */ 39 | public function testInvalidParams() 40 | { 41 | $params = array('something' => 'australia'); 42 | $this->assertFalse($this->_model->isValidParams($params)); 43 | 44 | $params = array('point' => 'here'); 45 | $this->assertFalse($this->_model->isValidParams($params)); 46 | 47 | $params = array('point' => 144.964045100000); 48 | $this->assertFalse($this->_model->isValidParams($params)); 49 | } 50 | 51 | 52 | /** 53 | * @test 54 | */ 55 | public function testValidArgumentSearch() 56 | { 57 | $params = array('point'=> new Point(-37.814207400000, 144.964045100000)); 58 | $result = $this->_model->search($params); 59 | $this->assertInstanceOf('Ak_Locator_Model_Resource_Location_Collection', $result); 60 | } 61 | 62 | 63 | /** 64 | * @test 65 | * @expectedException InvalidArgumentException 66 | */ 67 | public function testInvalidArgumentSearch() 68 | { 69 | $params = array('test'=>'test'); 70 | $this->_model->search($params); 71 | 72 | $params = array('point'=>'here'); 73 | $this->_model->search($params); 74 | 75 | $params = array('point'=>1); 76 | $this->_model->search($params); 77 | 78 | $params = array('point'=> new StdClass()); 79 | $this->_model->search($params); 80 | } 81 | 82 | 83 | /** 84 | * @test 85 | */ 86 | public function testParseParams() 87 | { 88 | $params = array('s'=>'australia'); 89 | $this->assertInternalType('array', $this->_model->parseParams($params)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search/Handler/Point/Latlong.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/search_handler_point_latlong'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Search_Handler_Point_Latlong', $this->_model); 25 | } 26 | 27 | /** 28 | * @test 29 | */ 30 | public function testValidParams() 31 | { 32 | $params = array('lat'=>-37.814207400000, 'long'=>144.964045100000); 33 | $this->assertTrue($this->_model->isValidParams($params)); 34 | 35 | $params = array('lat'=>'-37.814207400000', 'long'=>'144.964045100000'); 36 | $this->assertTrue($this->_model->isValidParams($params)); 37 | } 38 | 39 | /** 40 | * @test 41 | */ 42 | public function testInvalidParams() 43 | { 44 | $params = array('country'=>'australia'); 45 | $this->assertFalse($this->_model->isValidParams($params)); 46 | 47 | $params = array('lat'=>-37.814207400000); 48 | $this->assertFalse($this->_model->isValidParams($params)); 49 | 50 | $params = array('long'=>144.964045100000); 51 | $this->assertFalse($this->_model->isValidParams($params)); 52 | 53 | $params = array('lat'=>'-37.81420740.0000', 'long'=>'144.964045100000'); 54 | $this->assertFalse($this->_model->isValidParams($params)); 55 | 56 | $params = array('lat'=>'lat', 'long'=>'long'); 57 | $this->assertFalse($this->_model->isValidParams($params)); 58 | } 59 | 60 | 61 | /** 62 | * @test 63 | */ 64 | public function testValidArgumentSearch() 65 | { 66 | $params = array('lat'=>-37.814207400000, 'long'=>144.964045100000); 67 | $result = $this->_model->search($params); 68 | $this->assertInstanceOf('Ak_Locator_Model_Resource_Location_Collection', $result); 69 | } 70 | 71 | 72 | /** 73 | * @test 74 | * @expectedException InvalidArgumentException 75 | */ 76 | public function testInvalidArgumentSearch() 77 | { 78 | $params = array('s'=>'3141 australia'); 79 | $this->_model->search($params); 80 | } 81 | 82 | 83 | /** 84 | * @test 85 | */ 86 | public function testParseParams() 87 | { 88 | $params = array('s'=>'australia'); 89 | $this->assertInternalType('array', $this->_model->parseParams($params)); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search/Handler/Point/String.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/search_handler_point_string'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Search_Handler_Point_String', $this->_model); 25 | } 26 | 27 | /** 28 | * @test 29 | */ 30 | public function testValidParams() 31 | { 32 | $params = array('s'=>'123 test street'); 33 | 34 | $this->assertTrue($this->_model->isValidParams($params)); 35 | } 36 | 37 | /** 38 | * @test 39 | */ 40 | public function testInvalidParams() 41 | { 42 | $params = array('country'=>'australia'); 43 | 44 | $this->assertFalse($this->_model->isValidParams($params)); 45 | } 46 | 47 | 48 | /** 49 | * @test 50 | */ 51 | public function testValidArgumentSearch() 52 | { 53 | $params = array('s'=>'3141 australia'); 54 | $result = $this->_model->search($params); 55 | $this->assertInstanceOf('Ak_Locator_Model_Resource_Location_Collection', $result); 56 | } 57 | 58 | 59 | /** 60 | * @test 61 | * @expectedException InvalidArgumentException 62 | */ 63 | public function testInvalidArgumentSearch() 64 | { 65 | $params = array('a'=>'3141 australia'); 66 | $this->_model->search($params); 67 | } 68 | 69 | /** 70 | * @test 71 | */ 72 | public function testParseParams() 73 | { 74 | $params = array('s'=>'australia'); 75 | $this->assertInternalType('array', $this->_model->parseParams($params)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search/fixtures/testLatLongSearchDistance.yaml: -------------------------------------------------------------------------------- 1 | eav: 2 | ak_locator_location: 3 | - entity_id: 1 4 | latitude: -37.81420740.0000 5 | longitude: 144.964045100000 6 | is_enabled: 1 7 | - entity_id: 2 8 | latitude: -37.798571000000 9 | longitude: 144.976710000000 10 | is_enabled: 1 11 | - entity_id: 3 12 | latitude: -27.81420740.0000 13 | longitude: 154.964045100000 14 | is_enabled: 1 -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Search/fixtures/testLatLongSearchEnabled.yaml: -------------------------------------------------------------------------------- 1 | eav: 2 | ak_locator_location: 3 | - entity_id: 1 4 | latitude: -37.81420740.0000 5 | longitude: 144.964045100000 6 | is_enabled: 1 7 | - entity_id: 2 8 | latitude: -37.798571000000 9 | longitude: 144.976710000000 10 | is_enabled: 1 11 | - entity_id: 3 12 | latitude: -37.798571000000 13 | longitude: 144.976710000000 14 | is_enabled: 0 -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/Test/Model/Url.php: -------------------------------------------------------------------------------- 1 | _model = Mage::getModel('ak_locator/url'); 17 | } 18 | 19 | /** 20 | * @test 21 | */ 22 | public function testInstance() 23 | { 24 | $this->assertInstanceOf('Ak_Locator_Model_Url', $this->_model); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/controllers/Adminhtml/LocatorController.php: -------------------------------------------------------------------------------- 1 | _title($this->__('Locator')) 22 | ->_title($this->__('Manage Locations')); 23 | 24 | $this->loadLayout()->renderLayout(); 25 | } 26 | 27 | public function newAction() 28 | { 29 | Mage::register('location_isnew', true); 30 | $this->_forward('edit'); 31 | } 32 | 33 | public function editAction() 34 | { 35 | 36 | $id = $this->getRequest()->getParam('id', null); 37 | $model = Mage::getModel('ak_locator/location'); 38 | if ($id) { 39 | $model->load((int) $id); 40 | if ($model->getId()) { 41 | $data = Mage::getSingleton('adminhtml/session')->getFormData(true); 42 | if ($data) { 43 | $model->setData($data)->setId($id); 44 | } 45 | } else { 46 | Mage::getSingleton('adminhtml/session')->addError( 47 | Mage::helper('ak_locator')->__('Example does not exist') 48 | ); 49 | $this->_redirect('*/*/'); 50 | } 51 | } 52 | Mage::register('location_data', $model); 53 | 54 | $this->loadLayout(); 55 | 56 | if (Mage::registry('location_isnew')) { 57 | $this->getLayout()->getBlock('root')->addBodyClass('location-new'); 58 | } else { 59 | $this->getLayout()->getBlock('root')->addBodyClass('location-edit'); 60 | } 61 | 62 | $this->getLayout()->getBlock('head')->setCanLoadExtJs(true); 63 | $this->renderLayout(); 64 | } 65 | 66 | public function deleteAction() 67 | { 68 | if ($id = $this->getRequest()->getParam('id')) { 69 | try { 70 | $model = Mage::getModel('ak_locator/location'); 71 | $model->setId($id); 72 | $model->delete(); 73 | Mage::getSingleton('adminhtml/session')->addSuccess( 74 | Mage::helper('ak_locator')->__('The example has been deleted.') 75 | ); 76 | $this->_redirect('*/*/'); 77 | return; 78 | } catch (Exception $e) { 79 | Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 80 | $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id'))); 81 | return; 82 | } 83 | } 84 | Mage::getSingleton('adminhtml/session')->addError( 85 | Mage::helper('adminhtml')->__('Unable to find the example to delete.') 86 | ); 87 | $this->_redirect('*/*/'); 88 | } 89 | 90 | public function saveAction() 91 | { 92 | if ($data = $this->getRequest()->getPost()) { 93 | $model = Mage::getModel('ak_locator/location'); 94 | $id = $this->getRequest()->getParam('id'); 95 | if ($id) { 96 | $model->load($id); 97 | } 98 | $model->setData($data); 99 | 100 | Mage::getSingleton('adminhtml/session')->setFormData($data); 101 | try { 102 | if ($id) { 103 | $model->setId($id); 104 | } 105 | $model->save(); 106 | 107 | if (!$model->getId()) { 108 | Mage::throwException(Mage::helper('ak_locator')->__('Error saving location')); 109 | } 110 | 111 | Mage::getSingleton('adminhtml/session')->addSuccess( 112 | Mage::helper('ak_locator')->__('Location was successfully saved.') 113 | ); 114 | Mage::getSingleton('adminhtml/session')->setFormData(false); 115 | 116 | // The following line decides if it is a "save" or "save and continue" 117 | if ($this->getRequest()->getParam('back')) { 118 | $this->_redirect('*/*/edit', array('id' => $model->getId())); 119 | } else { 120 | $this->_redirect('*/*/'); 121 | } 122 | 123 | } catch (Exception $e) { 124 | Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 125 | if ($model && $model->getId()) { 126 | $this->_redirect('*/*/edit', array('id' => $model->getId())); 127 | } else { 128 | $this->_redirect('*/*/'); 129 | } 130 | } 131 | 132 | return; 133 | } 134 | Mage::getSingleton('adminhtml/session')->addError(Mage::helper('ak_locator')->__('No data found to save')); 135 | $this->_redirect('*/*/'); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/controllers/IndexController.php: -------------------------------------------------------------------------------- 1 | loadLayout(); 28 | $this->renderLayout(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/controllers/LocationController.php: -------------------------------------------------------------------------------- 1 | loadLayout(); 29 | 30 | //if there are no matching locations forward to the 404 page 31 | if (!$this->getLayout()->getBlock('view')->getLocation()) { 32 | $this->_forward('noresults'); 33 | return; 34 | } 35 | 36 | $this->renderLayout(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/controllers/SearchController.php: -------------------------------------------------------------------------------- 1 | loadLayout(); 30 | 31 | /** @var Ak_Locator_Block_Search $search */ 32 | $search = $this->getLayout()->getBlock('search'); 33 | 34 | //if search block doesn't know how to handle the parameters, forward onto the search form page 35 | if (!$search->hasValidParams()) { 36 | $this->_redirect('*/index/index'); 37 | return; 38 | } 39 | 40 | //if there are no locations returned go to the noresults action now 41 | if (!count($search->getLocations()->getItems())) { 42 | $this->_forward('noresults'); 43 | return; 44 | 45 | } 46 | 47 | if ($this->getRequest()->isXmlHttpRequest() || $this->getRequest()->getParam('xhr') == 1) { 48 | if (Mage::helper('ak_locator')->browserCacheEnabled()) { 49 | $this->setCacheHeaders(); 50 | } 51 | $this->getResponse()->setBody($search->asJson()); 52 | return; 53 | } else { 54 | $this->renderLayout(); 55 | } 56 | 57 | } catch (Exception $e) { 58 | 59 | if ($e instanceof Ak_Locator_Model_Exception_Geocode 60 | || $e instanceof Ak_Locator_Model_Exception_NoResults 61 | ) { 62 | $this->_forward('noresults'); 63 | return; 64 | } 65 | 66 | throw $e; 67 | } 68 | } 69 | 70 | /** 71 | * Output info window html for a given location marker 72 | */ 73 | public function infowindowAction() 74 | { 75 | $this->loadLayout(); 76 | if (Mage::helper('ak_locator')->browserCacheEnabled()) { 77 | $this->setCacheHeaders(); 78 | } 79 | $this->renderLayout(); 80 | } 81 | 82 | /** 83 | * Output json object containing info window html for a group of markers 84 | */ 85 | public function infowindowsAction() 86 | { 87 | $this->loadLayout(); 88 | if (Mage::helper('ak_locator')->browserCacheEnabled()) { 89 | $this->setCacheHeaders(); 90 | } 91 | $this->renderLayout(); 92 | } 93 | 94 | /** 95 | * Handle empty result 96 | */ 97 | public function noresultsAction() 98 | { 99 | if ($this->getRequest()->isXmlHttpRequest() || $this->getRequest()->getParam('xhr') == 1) { 100 | $obj = new Varien_Object(); 101 | $obj->setError(true); 102 | $obj->setErrorType('noresults'); 103 | $obj->setMessage('No Results Found'); 104 | $this->getResponse()->setBody($obj->toJson()); 105 | return; 106 | } else { 107 | $this->loadLayout(); 108 | $this->renderLayout(); 109 | } 110 | } 111 | 112 | /** 113 | * Set cache headers 114 | */ 115 | protected function setCacheHeaders() 116 | { 117 | $expire = 'Expires: ' . gmdate('D, d M Y H:i:s', strtotime('+1 days')) . ' GMT'; 118 | header($expire); 119 | header_remove('Pragma'); 120 | header_remove('Cache-Control'); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/sql/ak_locator_setup/upgrade-0.0.0.1-0.0.0.2.php: -------------------------------------------------------------------------------- 1 | startSetup(); 21 | 22 | //remove old is_active attribute 23 | $installer->removeAttribute(Ak_Locator_Model_Location::ENTITY, 'is_active'); 24 | 25 | //add new enabled attribute 26 | $installer->addAttribute(Ak_Locator_Model_Location::ENTITY, 'is_enabled', array( 27 | 'input' => 'select', 28 | 'type' => 'int', 29 | 'label' => 'Enabled', 30 | 'backend_label' => 'Enabled', 31 | 'source' => 'eav/entity_attribute_source_boolean', 32 | 'user_defined' => false, 33 | 'visible' => 1, 34 | 'required' => 1, 35 | 'position' => 11, 36 | 'default' =>1, 37 | 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 38 | )); 39 | 40 | 41 | //add new attribute to location edit form 42 | $eavConfig = Mage::getSingleton('eav/config'); 43 | 44 | $formAttributes = array( 45 | 'is_enabled' 46 | ); 47 | 48 | foreach ($formAttributes as $code) { 49 | $attribute = $eavConfig->getAttribute(Ak_Locator_Model_Location::ENTITY, $code); 50 | $attribute->setData('used_in_forms', array('location_edit','location_create')); 51 | $attribute->save(); 52 | } 53 | 54 | $installer->endSetup(); 55 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/sql/ak_locator_setup/upgrade-0.0.0.2-0.0.0.3.php: -------------------------------------------------------------------------------- 1 | startSetup(); 21 | 22 | 23 | $installer->updateAttribute(Ak_Locator_Model_Location::ENTITY, 'latitude', array('attribute_code' => 'latitude_bak')); 24 | $installer->updateAttribute(Ak_Locator_Model_Location::ENTITY, 'longitude', array('attribute_code' => 'longitude_bak')); 25 | 26 | 27 | $installer->getConnection() 28 | ->addColumn($installer->getTable('ak_locator/location'), 'latitude', array( 29 | 'type' => Varien_Db_Ddl_Table::TYPE_DECIMAL, 30 | 'unsigned' => true, 31 | 'nullable' => false, 32 | 'scale' => 12, 33 | 'precision' => 18, 34 | 'default' => '0', 35 | 'comment' => 'location latitude value' 36 | )); 37 | 38 | $installer->getConnection() 39 | ->addColumn($installer->getTable('ak_locator/location'), 'longitude', array( 40 | 'type' => Varien_Db_Ddl_Table::TYPE_DECIMAL, 41 | 'unsigned' => false, 42 | 'nullable' => true, 43 | 'scale' => 12, 44 | 'precision' => 18, 45 | 'default' => '0', 46 | 'comment' => 'location latitude value' 47 | )); 48 | 49 | $installer->getConnection() 50 | ->addKey( 51 | $installer->getTable('ak_locator/location'), 52 | 'LOCATION_LATITUDE', 53 | 'latitude' 54 | ); 55 | 56 | $installer->getConnection() 57 | ->addKey( 58 | $installer->getTable('ak_locator/location'), 59 | 'LOCATION_LONGITUDE', 60 | 'longitude' 61 | ); 62 | 63 | $installer->endSetup(); 64 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/sql/ak_locator_setup/upgrade-0.0.0.3-0.0.0.4.php: -------------------------------------------------------------------------------- 1 | startSetup(); 21 | 22 | 23 | $installer->updateAttribute(Ak_Locator_Model_Location::ENTITY, 'latitude_bak', array('is_visible' => 0)); 24 | $installer->updateAttribute(Ak_Locator_Model_Location::ENTITY, 'longitude_bak', array('is_visible' => 0)); 25 | 26 | //add new enabled attribute 27 | $installer->addAttribute(Ak_Locator_Model_Location::ENTITY, 'latitude', array( 28 | 'input' => 'text', 29 | 'type' => 'static', 30 | 'label' => 'Latitude', 31 | 'user_defined' => false, 32 | 'visible' => 1, 33 | 'required' => 1, 34 | 'position' => 30, 35 | 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 36 | )); 37 | 38 | $installer->addAttribute(Ak_Locator_Model_Location::ENTITY, 'longitude', array( 39 | 'input' => 'text', 40 | 'type' => 'static', 41 | 'label' => 'Longitude', 42 | 'user_defined' => false, 43 | 'visible' => 1, 44 | 'required' => 1, 45 | 'position' => 30, 46 | 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL, 47 | )); 48 | 49 | 50 | //add new attribute to location edit form 51 | $eavConfig = Mage::getSingleton('eav/config'); 52 | 53 | $formAttributes = array( 54 | 'latitude', 55 | 'longitude' 56 | ); 57 | 58 | foreach ($formAttributes as $code) { 59 | $attribute = $eavConfig->getAttribute(Ak_Locator_Model_Location::ENTITY, $code); 60 | $attribute->setData('used_in_forms', array('location_edit','location_create')); 61 | $attribute->save(); 62 | } 63 | 64 | $installer->endSetup(); 65 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/sql/ak_locator_setup/upgrade-0.0.0.4-0.0.0.5.php: -------------------------------------------------------------------------------- 1 | startSetup(); 21 | 22 | /* Create table 'ak_locator/location' */ 23 | $table = $installer->getConnection() 24 | //->newTable('ak_locator_search_override') 25 | ->newTable($installer->getTable('ak_locator/search_override')) 26 | ->addColumn('string', Varien_Db_Ddl_Table::TYPE_TEXT, 255, array( 27 | 'nullable' => false, 28 | 'primary' => true, 29 | ), 'Search String') 30 | ->addColumn('params', Varien_Db_Ddl_Table::TYPE_TEXT, 255, array( 31 | ), 'Overide Parameters') 32 | ->setComment('Custom Search Table'); 33 | 34 | $installer->getConnection()->createTable($table); 35 | 36 | $installer->endSetup(); 37 | -------------------------------------------------------------------------------- /src/app/code/community/Ak/Locator/sql/ak_locator_setup/upgrade-0.0.0.5-0.0.0.6.php: -------------------------------------------------------------------------------- 1 | startSetup(); 21 | 22 | $installer->addAttribute(Ak_Locator_Model_Location::ENTITY, 'meta_title', array( 23 | 'input' => 'text', 24 | 'type' => 'varchar', 25 | 'label' => 'Meta Title', 26 | 'backend' => '', 27 | 'user_defined' => false, 28 | 'visible' => 1, 29 | 'required' => 0, 30 | 'position' => 300, 31 | )); 32 | 33 | $installer->addAttribute(Ak_Locator_Model_Location::ENTITY, 'meta_keywords', array( 34 | 'input' => 'text', 35 | 'type' => 'varchar', 36 | 'label' => 'Meta Keywords', 37 | 'backend' => '', 38 | 'user_defined' => false, 39 | 'visible' => 1, 40 | 'required' => 0, 41 | 'position' => 310, 42 | )); 43 | 44 | $installer->addAttribute(Ak_Locator_Model_Location::ENTITY, 'meta_description', array( 45 | 'input' => 'textarea', 46 | 'type' => 'text', 47 | 'label' => 'Meta Description', 48 | 'backend' => '', 49 | 'user_defined' => false, 50 | 'visible' => 1, 51 | 'required' => 0, 52 | 'position' => 320, 53 | )); 54 | 55 | 56 | $formAttributes = array( 57 | 'meta_description', 58 | 'meta_keywords', 59 | 'meta_title' 60 | ); 61 | 62 | 63 | $eavConfig = Mage::getSingleton('eav/config'); 64 | 65 | foreach ($formAttributes as $code) { 66 | $attribute = $eavConfig->getAttribute(Ak_Locator_Model_Location::ENTITY, $code); 67 | $attribute->setData('used_in_forms', array('location_edit','location_create')); 68 | $attribute->save(); 69 | } 70 | 71 | $installer->endSetup(); 72 | -------------------------------------------------------------------------------- /src/app/design/adminhtml/default/default/layout/locator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/app/design/adminhtml/default/default/template/locator/location/edit/map.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 193 | 194 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/layout/locator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/location/info.phtml: -------------------------------------------------------------------------------- 1 | 16 | 17 | getLocations()->getFirstItem(); 19 | ?> 20 | 21 |

title; ?>

22 | 23 | 24 |

Address:

address;?>

25 | 32 | 33 | 34 | email):?> 35 |

Email: email;?>

36 | 37 | phone):?> 38 |

Phone: phone;?>

39 | 40 | fax):?> 41 |

Fax: fax;?>

42 | 43 | website):?> 44 |

Website:

45 | 46 | 47 |
48 | 49 | 50 |
51 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/location/map.phtml: -------------------------------------------------------------------------------- 1 | 16 | 17 | getLocations()->getItems(); 19 | $location = reset($locations); 20 | ?> 21 | 22 | getGeocoded()): ?> 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/location/others.phtml: -------------------------------------------------------------------------------- 1 | getLocations()): ?> 2 | 3 |

Others Nearby

4 | 20 | 21 | 22 | No results found 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/location/view.phtml: -------------------------------------------------------------------------------- 1 |
2 |
getChildHtml('info') ?>
3 |
getChildHtml('map') ?>
4 |
5 | 6 |
7 | getChildHtml('others') ?> 8 |
9 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/page/html/head/init-locator.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 11 | // Uncomment this line to start customizing the look of the google map displayed 12 | // document.observe("dom:loaded", function() { 13 | // 14 | // Locator.Map.addMethods({ 15 | // getMarkerImage: function(l){ 16 | // return new google.maps.MarkerImage( 17 | // '/skin/frontend/default/mytheme/locator/images/pin.png', 18 | // new google.maps.Size(40, 50), 19 | // new google.maps.Point(0, 0), 20 | // new google.maps.Point(20, 50) 21 | // ); 22 | // }, 23 | // getTheme: function(){ 24 | // return [ 25 | // { 26 | // featureType: "all", 27 | // elementType: "all", 28 | // stylers: [ 29 | // { saturation: -100 } 30 | // ] 31 | // } 32 | // ]; 33 | // } 34 | // }); 35 | // }); 36 | // 37 | ?> 38 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/page/html/head/init-search.phtml: -------------------------------------------------------------------------------- 1 | 38 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/page/html/head/init-store.phtml: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/form-australia.phtml: -------------------------------------------------------------------------------- 1 |
2 |

Search

3 |
4 | 5 | 6 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | or 26 | 29 | 30 | VIC 31 | NSW 32 | QLD 33 | WA 34 | NT 35 | SA 36 | TAS 37 | All Australia 38 | 39 |
40 | 41 |
42 | 45 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/form-simple.phtml: -------------------------------------------------------------------------------- 1 |
2 |

Search

3 |
4 | 5 | 'Australia', 8 | 'New Zealand' => 'New Zealand', 9 | 'Other' => '' 10 | ); 11 | $param = $this->getRequest()->getParam('country'); 12 | 13 | if (isset($param)) { 14 | $selected = $this->getRequest()->getParam('country'); 15 | } else { 16 | //if no parameters are passed from the url, see if we can get them from config 17 | $defaultsearch = Mage::helper('ak_locator/search')->parseQueryString(Mage::getStoreConfig('locator_settings/search/default_search_params')); 18 | if (isset($defaultsearch['country'])) { 19 | $selected = $defaultsearch['country']; 20 | } 21 | } 22 | ?> 23 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | or 39 | 42 | 43 | VIC 44 | NSW 45 | QLD 46 | WA 47 | NT 48 | SA 49 | TAS 50 | All Australia 51 | 52 |
53 | 54 |
55 | 58 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/infowindow.phtml: -------------------------------------------------------------------------------- 1 | getLocation(); ?> 2 |
3 |

title; ?>

4 |
5 |
getAddress() ?>
6 | View More | Get Directions 7 |
8 |
9 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/list/area.phtml: -------------------------------------------------------------------------------- 1 | 16 | 17 | getLocations()->getItems(); 19 | ?> 20 | 21 | 0): ?> 22 |

Locations

23 | 38 | 39 | 40 | No results found 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/list/point.phtml: -------------------------------------------------------------------------------- 1 | 16 | 17 | getLocations()->getItems(); 19 | $closest = $this->getLocations()->getFirstItem(); 20 | ?> 21 | 22 | 23 | 24 |

Closest Store

25 |
26 |
27 |

getTitle(); ?>

28 |
getAddress() ?>
29 |

Approx getDistance(),1); ?>km from you

30 | | Get Directions 31 |
32 | 33 | 34 |
35 |
36 |
37 |
38 | 39 | 1): ?> 40 | 41 |

Others

42 | 65 | 66 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/no-results.phtml: -------------------------------------------------------------------------------- 1 |
There are no matching results
2 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/quick.phtml: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Find a Store

4 |
5 |
6 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/default/template/locator/search/search.phtml: -------------------------------------------------------------------------------- 1 | getChildHtml('form'); ?> 2 |
3 |
4 | getChildHtml('list') ?> 5 |
6 |
7 |
8 |
9 | 10 |
getChildHtml('empty') ?>
11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/iphone/layout/locator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 51 | 52 | 53 | 54 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 77 | 78 | 79 | 80 | 81 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/iphone/template/locator/location/others.phtml: -------------------------------------------------------------------------------- 1 | getLocations()): ?> 2 | 3 |

Others Nearby

4 | 15 | 16 | 17 | No results found 18 | 19 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/iphone/template/locator/location/view.phtml: -------------------------------------------------------------------------------- 1 |
2 |
getChildHtml('map') ?>
3 |
getChildHtml('info') ?>
4 |
5 | 6 |
7 | getChildHtml('others') ?> 8 |
9 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/iphone/template/locator/search/search.phtml: -------------------------------------------------------------------------------- 1 | getChildHtml('form'); ?> 2 | 3 |
4 |
5 | getChildHtml('list') ?> 6 |
7 |
8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/app/design/frontend/base/iphone/template/locator/search/simple-form.phtml: -------------------------------------------------------------------------------- 1 |
2 | 11 | 12 | 13 | 14 | or 15 | 16 | 17 | VIC 18 | NSW 19 | QLD 20 | WA 21 | TAS 22 | 23 |
24 | 27 | -------------------------------------------------------------------------------- /src/app/etc/modules/Ak_Locator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/js/locator/plugins.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/js/locator/plugins.js -------------------------------------------------------------------------------- /src/skin/adminhtml/default/default/locator/css/locator.css: -------------------------------------------------------------------------------- 1 | .head-adminhtml-location, .head-adminhtml-location-attribute{ 2 | background-image: url(../images/map.png); 3 | } 4 | 5 | 6 | .adminhtml-locator-edit .head-adminhtml-location{ 7 | background-image: url(../images/map_edit.png); 8 | } 9 | 10 | .location-new .head-adminhtml-location{ 11 | background-image: url(../images/map_add.png); 12 | } 13 | -------------------------------------------------------------------------------- /src/skin/adminhtml/default/default/locator/images/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/adminhtml/default/default/locator/images/map.png -------------------------------------------------------------------------------- /src/skin/adminhtml/default/default/locator/images/map_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/adminhtml/default/default/locator/images/map_add.png -------------------------------------------------------------------------------- /src/skin/adminhtml/default/default/locator/images/map_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/adminhtml/default/default/locator/images/map_delete.png -------------------------------------------------------------------------------- /src/skin/adminhtml/default/default/locator/images/map_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/adminhtml/default/default/locator/images/map_edit.png -------------------------------------------------------------------------------- /src/skin/adminhtml/default/default/locator/images/map_go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/adminhtml/default/default/locator/images/map_go.png -------------------------------------------------------------------------------- /src/skin/adminhtml/default/default/locator/images/map_magnify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/adminhtml/default/default/locator/images/map_magnify.png -------------------------------------------------------------------------------- /src/skin/frontend/base/default/locator/css/locator.css: -------------------------------------------------------------------------------- 1 | /* Base style for location map */ 2 | .loc-map{ 3 | -webkit-transform: translate3d(0, 0, 0); 4 | } 5 | 6 | .loc-infowindow-loader.is-loading{ 7 | width: 100%; height:50px; 8 | } 9 | 10 | .loc-map img { 11 | max-width: none !important; 12 | } 13 | 14 | /* Base style for location teasers */ 15 | .loc-teaser{ 16 | -webkit-transition: .5s background ease-in; padding: 10px 0 10px 20px; margin-left:-20px; 17 | } 18 | .loc-teaser.is-hidden{ 19 | display:none; 20 | } 21 | .loc-teaser:hover{ 22 | background: #efefef; 23 | } 24 | 25 | .loc-teaser h3{ 26 | margin-top: 0; margin-bottom: 0.6em; 27 | } 28 | 29 | /* Locator search form */ 30 | .loc-srch{ 31 | background: #eee; padding: 20px; margin-bottom: 20px; 32 | } 33 | .loc-srch h4{ 34 | margin: 0; 35 | } 36 | 37 | .loc-srch-form{ 38 | 39 | } 40 | .loc-srch-s{ 41 | width: 200px; padding: 5px; 42 | } 43 | 44 | .loc-srch-dis{ 45 | width: 40px; padding: 5px; 46 | } 47 | 48 | 49 | /* Locator search results */ 50 | .loc-srch-res{ 51 | 52 | } 53 | /* hide no results page by default */ 54 | .loc-srch-res-noresults{ 55 | display:none; 56 | } 57 | 58 | /* when no results are shown show no results and hide search; */ 59 | .loc-srch-res.is-no-results .loc-srch-res-list, .loc-srch-res.is-no-results .loc-srch-res-map{ 60 | display:none; 61 | } 62 | .loc-srch-res.is-no-results .loc-srch-res-noresults{ 63 | display:block; 64 | } 65 | 66 | /* Map */ 67 | .loc-srch-res-map-wrap{ 68 | float:left; 69 | background: #fefefe; border: #ccc 1px solid; padding: 5px; margin-right: -10px; 70 | } 71 | .loc-srch-res-map-wrap.is-fixed{ 72 | position:fixed; top:0; margin-left: 298px; 73 | } 74 | .loc-srch-res-map{ 75 | width: 588px; height: 588px; 76 | } 77 | 78 | 79 | /* Teaser List */ 80 | .loc-srch-res-list{ 81 | float: left; width: 298px; padding: 20px 0; 82 | } 83 | 84 | /* Individual Location Page */ 85 | .loc-page{ 86 | float:left; width: 100%; clear:both; 87 | margin-bottom: 20px; 88 | } 89 | 90 | .loc-page-data{ 91 | float: left; width: 385px; 92 | } 93 | .loc-page-data h2{ 94 | margin-bottom: 10px; 95 | } 96 | .loc-page-map-wrap{ 97 | float:left; background: #fefefe; border: #ccc 1px solid; padding: 5px; 98 | } 99 | .loc-page-map{ 100 | width: 500px; height: 400px; 101 | } 102 | 103 | /* Nearby Locations */ 104 | .loc-nearby{ 105 | float:left; margin-top: 20px; 106 | } 107 | .loc-nearby-item{ 108 | display:inline-block; position: relative; vertical-align: top; 109 | width: 207px; margin-right: 20px; margin-bottom: 10px; 110 | } 111 | .loc-nearby-item .loc-teaser{ 112 | padding-right: 20px; 113 | } 114 | .loc-nearby-item:nth-child(4n){ 115 | margin-right:0; 116 | } 117 | 118 | /* Loader styles */ 119 | .loader { display: none; width: 24px; height: 24px; text-indent: -9999px;} 120 | .loader.is-loading { display: inline-block; background: url(../images/loader/loader-med.gif) center no-repeat; } 121 | .loader-tiny { width: 10px; height: 10px; } 122 | .loader-tiny.is-loading { background-image: url(../images/loader/loader-tiny.gif); } 123 | .loader-sml { width: 16px; height: 16px; } 124 | .loader-sml.is-loading { background-image: url(../images/loader/loader-sml.gif); } 125 | .loader-lrg { width: 48px; height: 48px; } 126 | .loader-lrg.is-loading { background-image: url(../images/loader/loader-lrg.gif); } 127 | -------------------------------------------------------------------------------- /src/skin/frontend/base/default/locator/images/loader/loader-lrg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/frontend/base/default/locator/images/loader/loader-lrg.gif -------------------------------------------------------------------------------- /src/skin/frontend/base/default/locator/images/loader/loader-med.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/frontend/base/default/locator/images/loader/loader-med.gif -------------------------------------------------------------------------------- /src/skin/frontend/base/default/locator/images/loader/loader-sml.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/frontend/base/default/locator/images/loader/loader-sml.gif -------------------------------------------------------------------------------- /src/skin/frontend/base/default/locator/images/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewkett/Ak_Locator/82a5a76399786179a02beb100256aa96e58f7113/src/skin/frontend/base/default/locator/images/pin.png -------------------------------------------------------------------------------- /src/skin/frontend/base/iphone/css/locator-mobile.css: -------------------------------------------------------------------------------- 1 | .locator-search-form{ 2 | background: #eee; padding: 20px; margin-bottom: 20px; 3 | } 4 | .locator-search-form h4{ 5 | margin: 0; 6 | } 7 | 8 | 9 | #locator-results{ 10 | 11 | } 12 | 13 | #search-info{ 14 | padding: 20px; 15 | } 16 | #search-info h2{ 17 | font-size: 20px; 18 | } 19 | 20 | .loc-teaser{ 21 | border-bottom: #eee 1px solid; padding-bottom: 10px; margin-bottom: 10px; 22 | line-height: 1.4em; 23 | } 24 | 25 | .loc-teaser h3{ 26 | margin: 10px 0; 27 | } 28 | 29 | #location-details, #other-locations { 30 | padding: 0 20px; 31 | } 32 | 33 | 34 | #location-details h2{ 35 | margin-bottom: 10px; 36 | } 37 | 38 | 39 | #location-details .map{ 40 | 41 | } 42 | #location-details #location-map{ 43 | width: 100%; padding: 0 20px; height: 300px; margin-left: -20px; margin-bottom: 20px; 44 | } 45 | 46 | 47 | .locations{ 48 | padding: 0; margin: 0; list-style:none; 49 | } 50 | 51 | #other-locations .location-info{ 52 | border-bottom: #eee 1px solid; margin-bottom: 10px; padding-bottom: 10px; position:relative; 53 | } 54 | #other-locations .location-info a{ 55 | position: absolute; display: block; top: 0; left: 0; width: 100%; height: 100%; text-indent: -9999px; 56 | } 57 | 58 | 59 | 60 | #location-map{ 61 | width: 600px; height: 600px; 62 | } 63 | 64 | 65 | 66 | .loader { display: none; width: 24px; height: 24px; } 67 | .loader.is-loading { display: inline-block; background: url(../images/locator/loader/loader-med.gif) center no-repeat; } 68 | .loader-tiny { width: 10px; height: 10px; } 69 | .loader-tiny.is-loading { background-image: url(../images/locator/loader/loader-tiny.gif); } 70 | .loader-sml { width: 16px; height: 16px; } 71 | .loader-sml.is-loading { background-image: url(../images/locator/loader/loader-sml.gif); } 72 | .loader-lrg { width: 48px; height: 48px; } 73 | .loader-lrg.is-loading { background-image: url(../images/locator/loader/loader-lrg.gif); } 74 | --------------------------------------------------------------------------------