css Audio - Active file-generic CSS - Active Generic - Active HTML - Active JS - Active SVG - Active Text - Active file-generic Video - Active header Love html icon-new-collection icon-person icon-team numbered-list123 pop-out spinner split-screen star tv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              #loc-8-component

    #loc-8-view.row(v-if='uiState==="view"')
        //-
          This is the View state
          This will show the current location either from WP
          or values be saved to WP upon a form submit
        .one-half.first
          h2(v-if='hasLocation') Current Location
          h2(v-else) Address Only

          tempate(v-if='hasLocation || fullAddress(loc) !== ""')
              p.l8-address {{ fullAddress(loc) }}
              p(v-if="hasLocation").l8-latlong ({{ loc.lat + ', ' + loc.long }})
          template(v-else)
              p.l8-address No Location
          template(v-if='canEdit')
              template(v-if='hasLocation')
                  button(v-on:click.prevent="currentEdit()") Edit
                  button(v-on:click.prevent="currentRemove()") Remove
              template(v-else-if='!hasLocation && fullAddress(loc) === ""')
                  button(v-on:click.prevent="currentEdit()") Add
              template(v-else)
                  button(v-on:click.prevent="currentEdit()") Edit & Geocode
        .one-half
            template(v-if='hasLocation')
              map-component(v-bind:loc="loc")

    #loc-8-edit.row(v-if='uiState==="edit"')
        //-
          This is the Edit state
          User can input address or Lat/Long and do a geocode search
          When the Geocode completes - goes to Choice state
        .one-half    
          h2 Edit Location
          label(for="l8address") Address
          input(type="text" v-model="editLoc.address" id="l8address")
          label(for="l8address2") Address2
          input(type="text" v-model="editLoc.address2" id="l8address2")
          label(for="l8city") City/Town
          input(type="text" v-model="editLoc.city" id="l8city")
          label(for="l8state") State/Province/Region
          input(type="text" v-model="editLoc.state" id="l8state")
          label(for="l8zip") Zip/Postal Code
          input(type="text" v-model="editLoc.zip" id="l8zip")
          label(for="l8country") Country
          input(type="text" v-model="editLoc.country" id="l8country")
          label(for="l8lat") Latitude
          input(type="text" v-model="editLoc.lat" id="l8lat")
          label(for="l8long") Longitutde
          input(type="text" v-model="editLoc.long" id="l8long")
          button(v-on:click.prevent="editOk()") OK
          button(v-on:click.prevent="geocode()") Geocode
          button(v-on:click.prevent="editCancel()") Cancel
          button(v-on:click.prevent="choiceUseMyAddress()") Use this address without Geocoding without Geocoding
          #loc-8-spinner(v-show="request") Requesting....

        .one-half
          //-
            Had to add key attribute so Vue wouldn't try to reuse map-component.  See - https://vuejs.org/v2/guide/conditional.html
          map-component(v-bind:loc="editLoc" key="loc-8-edit")
          
    #loc-8-choice.row(v-if='uiState === "choice"')
        //-
          This is the Choice state
          Allows the user to select the address that was
          returned by Geocode
          Or to use the address inputted if not found
          v-if is used so this markup is recreated each time (new map instances)

        .one-half
          ul 
            li(v-for='(item, index) in results' v-bind:class="{'selected': selected == index}" v-on:click.prevent='choiceSelect(index)')
              p.loc-8-address {{ fullAddress(item) }}
              p.loc-8-latlong {{ item.lat + ', ' + item.long }}
          button(v-show="selected != null" v-on:click.prevent="choiceUseSelected()") Use Selected
          button(v-show="selected != null" v-on:click.prevent="choiceUseSelectedLocation()") Use Selected for Location but keep my address info
          button(v-on:click.prevent='uiState="edit"') None of these, Search again
          //- button(v-on:click.prevent="choiceUseMyAddress()") None but use my address info anyway
        .one-half
          //-
            Had to add key attribute so Vue wouldn't try to reuse map-component.  See - https://vuejs.org/v2/guide/conditional.html
          map-component(v-bind:loc="results" key="loc-8-choice")            

    #loc-8-post-inputs
        //-
          If this component is in WP admin page it will be in a form
          These contain the values to be returned via $_POST
          if there is a submit.
          Remember to add the WP nonce
        input(type="hidden" v-model="loc.lat" name="loc-8-lat")
        input(type="hidden" v-model="loc.long" name="loc-8-long")
        input(type="hidden" v-model="loc.address" name="loc-8-address")
        input(type="hidden" v-model="loc.address2" name="loc-8-address2")
        input(type="hidden" v-model="loc.city" name="loc-8-city")
        input(type="hidden" v-model="loc.state" name="loc-8-state")
        input(type="hidden" v-model="loc.zip" name="loc-8-zip")
        input(type="hidden" v-model="loc.country" name="loc-8-country")
        input(type="hidden" v-model="addressChanged" name="loc-8-changed")
        input(type="hidden" v-model="addressDeleted" name="loc-8-deleted")

            
          
!
            
              @use postcss-simple-vars;

.row {
  display: flex;
  padding: 3rem;
  flex-wrap: wrap;
  justify-content: center;
    align-items: center;
}
.one-half {
  width: 45%;
  min-width: 35rem;
  
}
.aMap {
  min-height: 280px;
  width: 100%;
}

.loc-8-edit-tabs li {
  cursor: pointer;
  display: inline-block;
  padding: 5px;
  font-weight :bold;

}
ul, li {
    list-style-type: none;
  padding: 0;
  margin: 0;
}

#loc-8-choice li {
  cursor: pointer;

}

#loc-8-choice .selected {
  border: 1px solid #000;
}

.double-input {
  margin-top: 1rem;
}

.double-input span {
  font-size: 1rem;
}
.double-input span:before {
  content: "(Prev:";
  font-weight: 800;
}
.double-input span:after {
  content: ")";
}
.double-input label {
  display: block;
}
#loc-8-choice ul {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
#loc-8-choice li {
  line-height: 1;
  padding: 1rem;
  font-size: 1.4rem;
  width: 90%;
}
#loc-8-choice li:nth-child(2n+1) {
  background: #eee;
}
#loc-8-choice li:hover {
  background: #ccc;
}
            
          
!
            
              // Simulate the data WP will populate on page creation
let loc_8_fwp = {
    result: {
        lat: '32.3336368',
        long: '-95.2930722',
        address: '1329 S Beckham Ave',
        address2: '',
        city: 'Tyler',
        state: 'TX',
        zip: '75701',
        country: 'USA'
    },
    canEdit: true,
    mapTileLayer: 'https://api.mapbox.com/styles/v1/mapbox/streets-v10/tiles/256/{z}/{x}/{y}?access_token={accessToken}',
    mapAttribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://mapbox.com">Mapbox</a>',
    mapAccessId: 'CodePen',
    mapMaxZoom: 18,
         mapAccessToken: 'pk.eyJ1IjoiamVyMGRoIiwiYSI6ImNpeGo3MGRjaTAwNGIyd280ODJ0dzA1bm4ifQ.tFc-Mw0uY6Zf5056W_R5qw',
         action: 'loc_8_geocode',
         ajax_url: 'http://staging3.adv.jhtechservices.com/wp-admin/admin-ajax.php'
}

// Simulate a sample result of an Ajax or REST geocode request
let fwpResults = {
    results: [{
        lat: '30.0075278',
        long: '-95.7369283',
        address: '16125 Country Fair Ln',
        city: 'Cypress',
        state: 'TX',
        zip: '77433',
        country: 'USA'
    }, {
        lat: '29.9316274',
        long: '-95.6702606',
        address: '11655 Green Canyon Dr',
        city: 'Houston',
        state: 'TX',
        zip: '77095',
        country: 'USA'
    }, {
        lat: '39.612032',
        long: '-82.904623',
        address: '1476 Lancaster Pike',
        city: 'Circleville',
        state: 'OH',
        zip: '43113',
        country: 'USA'
    }]
}
// Vue component as a simple bus to pass events between components
let bus = new Vue();


// Vue component to hold the Leaflet Map
// Pass in the Location object containing the lat and long in props
// Added ability to add an array for multiple markers.  It will emit the
// index of the location array that was clicked. Using a simple bus
// Currently does not update the map if lat/long change in the array
Vue.component('map-component', {
    template: '<div class="aMap"></div>',
    props: ['loc'],
    data: function() {
        return {
            map: {},
            markers: []
        }
    },
    // Initialize map
    mounted: function() {
        this.map = L.map(this.$el);
        L.tileLayer(loc_8_fwp.mapTileLayer, {
            attribution: loc_8_fwp.mapAttribution,
            maxZoom: loc_8_fwp.mapMaxZoom,
            id: loc_8_fwp.mapAccessId,
            accessToken: loc_8_fwp.mapAccessToken
        }).addTo(this.map);

        if (Array.isArray(this.loc)) {
            console.log(this.loc);
            for(let i = 0; i < this.loc.length; i++){
                let marker = L.marker([this.loc[i].lat, this.loc[i].long])
                    .addTo(this.map)
                    .on('click', this.markerClick);
                marker.loc_8_id = i;
                this.markers.push( marker );
            }
            let group = new L.featureGroup(this.markers);
            this.map.fitBounds(group.getBounds().pad(0.5));
        } else {
            let marker = L.marker([this.loc.lat, this.loc.long]).addTo(this.map);
            this.markers[0] = marker;
            this.map.setView([this.loc.lat, this.loc.long], 13);
        }
    },
    destroyed: function() { console.log ('destroyed'); },
    methods: {
        markerClick: function(e) {
            console.log("emitting" + e.target.loc_8_id);
            bus.$emit('marker-click', e.target.loc_8_id);
        }
    },
    // if Location changes from parent,
    // update map
    watch: {
        'loc': {
            deep: true,
            handler: function() {
                console.log("a map given new coords");
                if(Array.isArray(this.loc)) {
                    //To implement if needed.
                } else {
                    this.map.setView([this.loc.lat, this.loc.long], 13)
                        .removeLayer(this.markers[0]);
                    this.markers[0] = L.marker([this.loc.lat, this.loc.long]).addTo(this.map);
                }
            }
        }
    },

});

// Start and bind Vue framework
let vm = new Vue({
    el: '#loc-8-component',
    data: {
        loc: {
                    lat: '',
                    long: '',
                    address: '',
                    address2: '',
                    city: '',
                    state: '',
                    zip: '',
                    country: '',
                    geo_date: ''
        },
        editLoc: {},
                canEdit: false,
        uiState: 'view', //'view, 'edit', 'choice'
        request: false,
        results: [],
        selected: null,
        action: null,
        ajax_url: null,
        changed: false,
        deleted: false,
         originalLocation: ''

    },

            created: function() {
                if(typeof(loc_8_fwp) !== 'undefined') {
                    this.canEdit = loc_8_fwp.canEdit;
                    if (typeof(loc_8_fwp.result) !== 'undefined') {
                        this.copyLocation(loc_8_fwp.result, this.loc)
                    }
                    this.ajax_url = loc_8_fwp.ajax_url;
                    this.action = loc_8_fwp.action;
                    this.ajax_nonce = loc_8_fwp._ajax_nonce;
                }
                this.originalLocation = this.fullAddressHash(this.loc);
    },
    mounted: function() {
                console.log('setting up $on');
        let that = this;
        bus.$on('marker-click', function(s) {
            console.log('in bus.$on:masterClick with ' + s)
            that.selected = s;
        });
    },
    computed: {
        hasLocation: function() {
            return this.loc.long && this.loc.lat
        },
        editAddressChange : function() {
            return this.fullAddress(this.loc).toLowercase() !== this.fullAddress(this.editLoc).toLowercase();
        },
        editLocationChange: function() {
            return (this.loc.lat + this.loc.long) !== (this.editLoc.lat + this.editLoc.long);
                },
                addressChanged: function() {
                    return (this.originalLocation !== this.fullAddressHash(this.loc));
                },
                addressDeleted: function() {
                    return ( (( this.originalLocation !== '') && this.fullAddressHash(this.loc) === ''));
        }

    },
    methods: {
        // View State functions
        //---------------------------------------------
        // copies current location to editLoc for user manipulation
        // and changes to Edit state
        currentEdit: function() {
            this.editLoc = JSON.parse(JSON.stringify(this.loc));
            this.uiState = 'edit';
        },

        // Edit State functions
        //---------------------------------------------

        // Remove pressed so blank out location
        currentRemove: function() {
            this.loc = this.blankLocation();
        },

        // OK pressed so go back to View Stat
        // Move editLoc to loc
        // Check to see if address or loc has changed
        editOk: function() {
            this.copyLocation(this.editLoc, this.loc);
            this.selected=null;
            this.uiState = "view";
        },
        // Cancel pressed so go back to View State
        editCancel: function() {
            this.uiState = "view";
        },

        // Will send request to WP to geocode editLoc object
        // If multiple add a label: A-Z for markers
        geocode: function() {
            this.request = true;
            let that = this;
                /*    //Get the inputs for this component
                    let data = {};
                    $.each($('input[name^=geo_loc_8_]'),function(i,v){data[$(v).attr('name')] = $(v).val()});
                    data['action'] = this.action;
                    data['_ajax_nonce'] = this.ajax_nonce;
                    console.log(data);
                    $.ajax(this.ajax_url,{
                        method: 'POST',
                        data: data ,

                    } )
                        .done( (results) => {
                            console.log(results);
                            if(results.data.results.length > 0) {
                                that.results = results.data.results;
                                that.uiState = "choice";
                            }

                        })
                        .fail( (error) => {
                            console.log('failed: ' + error);
                        })
                        .always( () => {
                            that.request = false;
                        });

                   */
            setTimeout(
                function() {
                    that.request = false;
                    that.results = fwpResults.results;
                    that.uiState = 'choice';
                    that.selected = null;
                }, 500);
        },

        // The Choice State
        //-----------------------------------------------

        // Use the selected returned location so copy to loc
        // and change to View state
        choiceUseSelected: function() {
            this.copyLocation(this.results[this.selected], this.loc);
            this.selected = null;
            this.uiState = 'view';
        },

        // Use the selected results Lat/Long but use any inputted
        // field value from editLoc
        choiceUseSelectedLocation: function() {
            let result = this.results[this.selected];
            let editLoc = this.editLoc;
            this.loc.lat = result.lat;
            this.loc.long = result.long;
            // if editLoc prop has a value use it, otherwise use result
            let address = editLoc.address !== '' ? editLoc.address : result.address,
                address2 = editLoc.address2 !== '' ? editLoc.address2 : result.address2,
                city = editLoc.city !== '' ? editLoc.city : result.city,
                zip = editLoc.zip !== '' ? editLoc.zip : result.zip,
                state = editLoc.state !== '' ? editLoc.state : result.state,
                country = editLoc.country !== '' ? editLoc.country : result.country;
            this.loc.address = address;
            this.loc.address2 = address2;
            this.loc.city = city;
            this.loc.zip = zip;
            this.loc.country = country;
            this.copyLocation(this.loc, this.editLoc)
            this.uiState = "edit";
        },

        // If user clicks on address, assign selected to index
        choiceSelect: function(index) {
            this.selected = index;
        },

        // Just use the address inputted and not result
        // Also used in Edit state
        choiceUseMyAddress: function() {
            this.copyLocation(this.editLoc, this.loc);
            this.uiState = "view";
        },

        // Utility Functions
        //-----------------------------------------

        blankLocation: function() {
            return {
                lat: '',
                long: '',
                address: '',
                address2: '',
                city: '',
                state: '',
                zip: '',
                country: '',
            }
        },
        copyLocation: function(from, to) {
            to.lat = from.lat;
            to.long = from.long;
            to.address = from.address;
            to.address2 = from.address2;
            to.city = from.city;
            to.state = from.state;
            to.zip = from.zip;
            to.country = from.country;
        },
        fullAddress: function(loc = {}) {
            let result = '';
            result += loc.address ? loc.address : '';
            result += loc.address2 ? ', ' + loc.address2 : '';
            result += loc.city ? ', ' + loc.city : '';
            result += loc.state ? ', ' + loc.state : '';
            result += loc.zip ? ', ' + loc.zip : '';
            result += loc.country ? ', ' + loc.country : '';
            // return result after removing any beginning comma
                    return result.replace(/^,/g, '').trim();
                },

                fullAddressHash: function(loc = {}) {
                    let result = '';
                    result = this.fullAddress(loc);
                    result += loc.lat ? ',' + loc.lat : '';
                    result += loc.long ? ',' + loc.long : '';
                    return result.trim();
        }
    },

});
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console