WordPress Report Sales by State and Month improved (legacy)

<?php
/**
 * @snippet       Get Sales by State & Month @ WooCommerce Admin
 * @author        Original: Rodolfo Melogli, Modified: Alex Frascona
 * @testedwith    WooCommerce 6
 */
 
// -----------------------
// 1. Create extra tab under Reports / Orders
 
add_filter( 'woocommerce_admin_reports', 'bbloomer_admin_add_report_orders_tab' );
 
function bbloomer_admin_add_report_orders_tab( $reports ) { 
 
    $array = array(
        'sales_by_state' => array(
            'title' => 'Sales by state',
            'description' => '',
            'hide_title' => 1,
            'callback' => 'bbloomer_yearly_sales_by_state'
        )
    );
    
    if(isset($reports['orders']))
    $reports['orders']['reports'] = array_merge($reports['orders']['reports'],$array);
    
    return $reports; 
}
 
// -----------------------
// 2. Calculate sales by state & month
 
function bbloomer_yearly_sales_by_state() {
 
    $year = (isset($_GET['year'])) ? $_GET['year']: date("Y"); // change this if needed
    
    $total_sales = 0;

    $us_state_abbrevs_names = array();

    $empty_orders = array();
 
    $args = [
        'post_type' => 'shop_order',
        'posts_per_page' => '-1',
        'year' => $year,
        'post_status' => ['completed', 'processing']
    ];
    $my_query = new WP_Query($args);
    $orders = $my_query->posts;
 
    foreach ($orders as $order => $value) {
        
        $order_id = $value->ID;
        $order = wc_get_order($order_id);
        $order_data = $order->get_data();
        
        $order_paid = $order->get_date_paid();
        $date_month = (int)date_format(date_create($order_paid), 'm');

        if( $order_data['billing']['state'] == null ){
            $empty_orders[] = $order_id;
            $order_data['billing']['state'] = 'No Billing State!';
        }

        if (array_key_exists($order_data['billing']['state'], $us_state_abbrevs_names)){
            $us_state_abbrevs_names[$order_data['billing']['state']]['total'] += $order->get_total();

            if (array_key_exists($date_month, $us_state_abbrevs_names[$order_data['billing']['state']])){
                $us_state_abbrevs_names[$order_data['billing']['state']][$date_month] += $order->get_total();
            }else{
                $us_state_abbrevs_names[$order_data['billing']['state']][$date_month] = $order->get_total();
            }
        }else{
            $us_state_abbrevs_names[] = $order_data['billing']['state'];
            $us_state_abbrevs_names[$order_data['billing']['state']]['total'] = $order->get_total();
            $us_state_abbrevs_names[$order_data['billing']['state']][$date_month] = $order->get_total();
        }
        
        $total_sales += $order->get_total();
 
    }

    if(!empty($empty_orders)){
    echo "<p>Fix these Orders without a Billing State!: ";
    foreach($empty_orders as $order_id){
        echo "<a target='_blank' href='/wp-admin/post.php?post=" . $order_id . "&action=edit'>" . $order_id . "</a> ";
    }
    echo "</p>";
    }

    // echo "<pre>";
    // print_r($us_state_abbrevs_names); //exit;
    // echo "</pre>";
    ?>
        <style>
            table#sales_by_state{
                font-size: 12px;
                font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
                border-collapse: collapse;
                border-spacing: 0;
                width: 100%;
                display: table;
                border: 1px solid #ccc;
            }
            #sales_by_state td{
                padding: 6px;
            }
            #sales_by_state th {
                background-color: #6ba65d63;
                border-bottom: 1px solid #ccc;
            }
            #sales_by_state tr:nth-child(even){
                background-color: #E7E9EB;
            }
            #sales_by_state tr:nth-child(odd){
                background-color: #FFFFFF;
            }
            #sales_by_state tr:hover{
				background-color: #eddd807a;
			}
            .sales_final_row{
                border-top: 1px solid #ccc;
            }
        </style>

    <?php
        $years = array(2017, 2018, 2019, 2020, 2021, 2022);
    ?>
    <select onchange="this.options[this.selectedIndex].value && (window.location = this.options[this.selectedIndex].value);">
        <?php
            foreach($years as $single_year){
                $current_year = '';
                if($year == $single_year){
                    $current_year = 'selected';
                }
                echo '<option ' . $current_year . ' value="/wp-admin/admin.php?page=wc-reports&tab=orders&report=sales_by_state&year=' . $single_year . '">' . $single_year . '</option>';
            }
            
        ?>
    </select><br /><br />

    <table id='sales_by_state'><tr><th></th><th>Jan</th> <th>Feb</th><th>Mar</th><th>Apr</th> <th>May</th> <th>Jun</th> <th>Jul</th> <th>Aug</th> <th>Sep</th> <th>Oct</th> <th>Nov</th> <th>Dec</th> <th>Total</th> </tr>

<?php

    foreach($us_state_abbrevs_names as $abbreviation => $full){
        if(gettype($full) == 'array'){
            foreach ( $full as $key => $value ){
                if ( $value == "$0.00" || $value == 0 ){ unset($full[$key]); }
            }
            
            ?>
            <tr>
                <td><?php echo $abbreviation; ?></td>
                <td><?php echo (isset($full['1']))? wc_price($full['1']): ''; ?></td>
                <td><?php echo (isset($full['2']))? wc_price($full['2']): ''; ?></td>
                <td><?php echo (isset($full['3']))? wc_price($full['3']): ''; ?></td>
                <td><?php echo (isset($full['4']))? wc_price($full['4']): ''; ?></td>
                <td><?php echo (isset($full['5']))? wc_price($full['5']): ''; ?></td>
                <td><?php echo (isset($full['6']))? wc_price($full['6']): ''; ?></td>
                <td><?php echo (isset($full['7']))? wc_price($full['7']): ''; ?></td>
                <td><?php echo (isset($full['8']))? wc_price($full['8']): ''; ?></td>
                <td><?php echo (isset($full['9']))? wc_price($full['9']): ''; ?></td>
                <td><?php echo (isset($full['10']))? wc_price($full['10']): ''; ?></td>
                <td><?php echo (isset($full['11']))? wc_price($full['11']): ''; ?></td>
                <td><?php echo (isset($full['12']))? wc_price($full['12']): ''; ?></td>
                <td><?php echo wc_price($full['total']); ?></td>
            
            </tr>
            <?php
        }
    }

    ?>
        <tr class='sales_final_row'>
            <td>Total Sales:</td>
            <td></td><td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td><td></td>
            <td><?php echo wc_price($total_sales); ?></td>
        </tr>
    <?php
}
?>
Posted in HTML, PHP, Wordpress | Leave a comment

WordPress Sales by State Report (legacy)

Just add this to your theme functions.php and replace {** replace with your site **} with your site

/**
 * @snippet       Get Sales by State @ WooCommerce Admin
 * @author        Original: Rodolfo Melogli Updated: Alex Frascona
 * @testedwith    WooCommerce 6
 */
 
// 1. Create extra tab under Reports / Orders
 
add_filter( 'woocommerce_admin_reports', 'bbloomer_admin_add_report_orders_tab' );
 
function bbloomer_admin_add_report_orders_tab( $reports ) { 
 
$array = array(
    'sales_by_state' => array(
        'title' => 'Sales by state',
        'description' => '',
        'hide_title' => 1,
        'callback' => 'bbloomer_yearly_sales_by_state'
    )
);
 
$reports['orders']['reports'] = array_merge($reports['orders']['reports'],$array);
 
return $reports; 
}
 
// -----------------------
// 2. Calculate sales by state
 
function bbloomer_yearly_sales_by_state() {
 
    $year = (isset($_GET['year'])) ? $_GET['year']: date("Y"); // change this if needed
    
    $total_sales = 0;

    $us_state_abbrevs_names = array( 'AL'=>'ALABAMA', 'AK'=>'ALASKA', 'AS'=>'AMERICAN SAMOA', 'AZ'=>'ARIZONA', 'AR'=>'ARKANSAS', 'CA'=>'CALIFORNIA', 'CO'=>'COLORADO', 'CT'=>'CONNECTICUT', 'DE'=>'DELAWARE', 'DC'=>'DISTRICT OF COLUMBIA', 'FM'=>'FEDERATED STATES OF MICRONESIA', 'FL'=>'FLORIDA', 'GA'=>'GEORGIA', 'GU'=>'GUAM GU', 'HI'=>'HAWAII', 'ID'=>'IDAHO', 'IL'=>'ILLINOIS', 'IN'=>'INDIANA', 'IA'=>'IOWA', 'KS'=>'KANSAS', 'KY'=>'KENTUCKY', 'LA'=>'LOUISIANA', 'ME'=>'MAINE', 'MH'=>'MARSHALL ISLANDS', 'MD'=>'MARYLAND', 'MA'=>'MASSACHUSETTS', 'MI'=>'MICHIGAN', 'MN'=>'MINNESOTA', 'MS'=>'MISSISSIPPI', 'MO'=>'MISSOURI', 'MT'=>'MONTANA', 'NE'=>'NEBRASKA', 'NV'=>'NEVADA', 'NH'=>'NEW HAMPSHIRE', 'NJ'=>'NEW JERSEY', 'NM'=>'NEW MEXICO', 'NY'=>'NEW YORK', 'NC'=>'NORTH CAROLINA', 'ND'=>'NORTH DAKOTA', 'MP'=>'NORTHERN MARIANA ISLANDS', 'OH'=>'OHIO', 'OK'=>'OKLAHOMA', 'OR'=>'OREGON', 'PW'=>'PALAU', 'PA'=>'PENNSYLVANIA', 'PR'=>'PUERTO RICO', 'RI'=>'RHODE ISLAND', 'SC'=>'SOUTH CAROLINA', 'SD'=>'SOUTH DAKOTA', 'TN'=>'TENNESSEE', 'TX'=>'TEXAS', 'UT'=>'UTAH', 'VT'=>'VERMONT', 'VI'=>'VIRGIN ISLANDS', 'VA'=>'VIRGINIA', 'WA'=>'WASHINGTON', 'WV'=>'WEST VIRGINIA', 'WI'=>'WISCONSIN', 'WY'=>'WYOMING', 'AE'=>'ARMED FORCES AFRICA \ CANADA \ EUROPE \ MIDDLE EAST', 'AA'=>'ARMED FORCES AMERICA (EXCEPT CANADA)', 'AP'=>'ARMED FORCES PACIFIC' );
    
    foreach($us_state_abbrevs_names as $key => $value){
        ${key} = 0;
        //echo ${key} . ", ";
    }
 
    $args = [
        'post_type' => 'shop_order',
        'posts_per_page' => '-1',
        'year' => $year,
        'post_status' => ['completed', 'processing']
    ];
    $my_query = new WP_Query($args);
    $orders = $my_query->posts;
 
    foreach ($orders as $order => $value) {

        $order_id = $value->ID;
        $order = wc_get_order($order_id);
        $order_data = $order->get_data();
    
        if ( $order_data['billing']['country'] === 'US' ) {
            
            foreach($us_state_abbrevs_names as $abbreviation => $full){
                if ( $order_data['billing']['state'] == $abbreviation ){
                    ${$abbreviation} += $order->get_total();
                    $total_sales += $order->get_total();
                }
            }
            
        } 
 
    }
    ?>
        <style>
            table#sales_by_state{
                font-size: 16px;
                font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
                border-collapse: collapse;
                border-spacing: 0;
                width: 100%;
                display: table;
                border: 1px solid #ccc;
            }
            #sales_by_state td{
                padding: 6px;
            }
            #sales_by_state th {
                text-align: left;
                padding: 8px;
            }
            #sales_by_state tr:nth-child(even){
                background-color: #E7E9EB;
            }
            #sales_by_state tr:nth-child(odd){
                background-color: #FFFFFF;
            }
            #sales_by_state tr:hover{
				background-color: #ffff99;
			}
            .sales_final_row{
                border-top: 1px solid #ccc;
            }
        </style>

    <?php
        $years = array(2017, 2018, 2019, 2020, 2021, 2022);
    ?>
    <select onchange="this.options[this.selectedIndex].value && (window.location = this.options[this.selectedIndex].value);">
        <?php
            foreach($years as $single_year){
                $current_year = '';
                if($year == $single_year){
                    $current_year = 'selected';
                }
                echo '<option ' . $current_year . ' value="https://{** replace with your site **}/wp-admin/admin.php?page=wc-reports&tab=orders&report=sales_by_state&year=' . $single_year . '">' . $single_year . '</option>';
            }
            
        ?>
    </select><br /><br />

    <?php

    //echo "<h3>Sales by State for " . $year . "</h3>";
    
    echo "<table id='sales_by_state'>";
    
    foreach($us_state_abbrevs_names as $abbreviation => $full){
        if(${$abbreviation} != 0)
        echo "<tr><td>$abbreviation</td><td>" . wc_price(${$abbreviation}) . "</td></tr>";
    }

    echo "<tr class='sales_final_row'><td>Total Sales:</td><td>" .  wc_price($total_sales) . "</td></tr></table>";
   
 
}
Posted in HTML, PHP, Wordpress | Leave a comment

Lookup zip city state latitude longitude simple JavaScript

Posted in Uncategorized | Leave a comment

lightSlider drag opens magnificPopup stopped

We’re using lightSlider for just that, a photo slider.

We’re using magnificPopup in conjunction with lightSlider to open an image Popup Gallery.

The trouble is, dragging lightSlider (which is nice), fires the magnificPopup ondragend (not desired).

Solution: Checked for a body class before firing the magnificPopup. If it’s still there, don’t even attach it. The class is added by the lightslider library change below, onmouseout, and removed again with a slight delay onmouseup.

Fix:

<a onclick="
if( jQuery('body').hasClass('dragging') ){								console.log('dragging now');
}else{
jQuery.magnificPopup.open({									items: MyArrayOfImagesToFeedToMagnific,									type: 'image',									gallery: {								      enabled: true								    },														callbacks: {										beforeOpen: function() {
// unused					   										 },									open: function() {										
// unused								},
}, ` + i + `); // i (index of the MyArrayOfImagesToFeedToMagnific Array) is the item the visitor clicked on
}">

lightslider.js

...
$(window).on('mousemove', function (e) {
if (isDraging) {

// Added
$('body').addClass('dragging');

endCoords = (settings.vertical === true) ? e.pageY : e.pageX;
$this.touchMove(endCoords, startCoords);
}
});
$(window).on('mouseup', function (e) {
if (isDraging) {
$slide.find('.lightSlider').removeClass('lsGrabbing').addClass('lsGrab');

// Added
setTimeout(function(){
$('body').removeClass('dragging');
}, 500);

isDraging = false;
...
Posted in CSS, HTML, JavaScript, jQuery | Leave a comment

PHP WordPress wp_remote_get when hitting a 3rd party REST API returns content-type windows-1252, but I need utf-8

I’m calling a REST API, but they’re returning items with content-type ‘windows-1252’, yuck.
Result was either ? marks all over, or /’/g
Here’s an example sentence returned:

//Young Life/’/gs Washington Family Ranch, nestled in a high desert valley in Central Oregon, seeks to…

The key is getting the correct order of parameters, and the correct content-type you’re receiving, and the one you’d like instead:
mb_convert_encoding($mixed, ‘utf-8’, ‘windows-1252’)

This goes FROM windows-1252 TO utf-8

And it still leaves a few items, namely curly brackets “’” still, so a string_replace is still required after the conversion.

Additionally, the endpoint returns… an object? an array? one inside the other? ug, so this calls itself recursively until it’s handled.
Just pass in the whole thing, whatever it is, returned:
$searchResult = utf8ize($searchResult);
Nice.

This was a super hassle to figure out, so I’m saving the reminder here. Hope it helps someone.

function utf8ize( $mixed ) {
if (is_object($mixed)) {
foreach ($mixed as $key => $value){
$mixed->$key = utf8ize($value);
}
}
if (is_array($mixed)) {
foreach ($mixed as $key => $value) {
$mixed[$key] = utf8ize($value);
}
}
if (is_string($mixed)) {
//return mb_convert_encoding($mixed, “UTF-8”);
$mixed = str_replace(“’”, “‘”, mb_convert_encoding($mixed, ‘utf-8’, ‘windows-1252’));
}
return $mixed;
}

Posted in JavaScript, PHP | Leave a comment

Include Paths Reference

Simple, entry-level stuff right? But how often do you have to fuss around a while before you succeed at including that darn file?

PHP:

define('ROOTPATH', __DIR__);

Result: /Applications/MAMP/htdocs/ankrommoisan/wp-content/themes/ankrommoisan-2017/template-parts/page

$_SERVER['DOCUMENT_ROOT'];

Result: /Applications/MAMP/htdocs

$_SERVER["HTTP_HOST"];

Result: localhost

getcwd();

Result: Current Working Directory, ie: /Applications/MAMP/htdocs/active-theme-folder

WordPress:

get_template_directory();

Result: /Applications/MAMP/htdocs/site/wp-content/themes/active-theme-folder

Javascript:

window.location.pathname

Example: “check-path-example”

window.location.href

Example: “https://js-tricks.info/check-path-example”

window.location.origin

Example: “https://js-tricks.info/check-path-example”

jQuery:

$(location).attr('host')

Result: path

$(location).attr('href')

Result: href

$(location).attr('protocol')

Result: protocol

HTML File Paths

src="image.jpg"

Result: file is in the same folder as the page using it

src="images/image.jpg"

Result: file is in an images folder that resides in the current file’s location

src="/images/image.jpg"

Result: at the web root there is an images folder with the file inside it

src="../image.jpg"

Result: the file is in a folder one level up from the current file’s location

../ is not to be confused with ./ which points to the current directory in a computer file structure setting

Posted in JavaScript, jQuery, PHP, Uncategorized, Wordpress | Leave a comment

Linux File Permissions -> number reference

This is kind of silly, but sometimes I just need to quickly find common ones:

  • drwx—r-x = 705
  • -rwx—r-x = 705
  • drw—-r– = 604
  • -rw—-r– = 604
  • drw-r–r– = 644
  • -rw-r–r– = 644
  • drwxr–r-x = 745
  • -rwxr–r-x = 745
  • drwxr-xr-x = 755
  • -rwxr-xr-x = 755
Posted in command line, Misc, Reference, Terminal | Leave a comment

Laravel 5.0.32 & PHP7.2.10 mcrypt errors

Error – mcrypt is not installed/deprecated (it was removed from php7, need to add it back in to your env), see my other post:
http://alexyz.com/code/troubleshooting-various-things-on-a-mac-find-active-php-ini-laravel-add-mcrypt-extension-to-php7-2-10-and-verify-it/

Error – Function mcrypt_get_iv_size() is deprecated
Upgrade to Laravel 5.1
Credit: https://github.com/AsgardCms/Platform/issues/271
steps:

edit composer.json to:
“laravel/framework”: “~5.1”,

Remove the two service providers from config/app.php:
Illuminate\Foundation\Providers\ArtisanServiceProvider::class,
Illuminate\Routing\ControllerServiceProvider::class,

Illuminate\Bus\BusServiceProvider,
\Providers\ConfigServiceProvider,


Update (don’t update equivalents in vendor folder!):
App\Providers\RouteServiceProvider
App\Providers\EventServiceProvider
App\Providers\AuthServiceProvider
from:
public function boot(DispatcherContract $events){parent::boot($events);…
to:
public function boot( { parent::boot();
Credit: https://laracasts.com/discuss/channels/forge/laravel-53-update-causing-error-on-forge-only

app/HTTP/Controllers/Controller.php
replace:
use Illuminate\Foundation\Bus\DispatchesCommands;
with:
use Illuminate\Foundation\Bus\DispatchesJobs;
https://stackoverflow.com/questions/34589987/trait-illuminate-foundation-bus-dispatchescommands-not-found-error-while-larav

Error: Auth guard[] is not defined:
replace config/auth.php with this:
https://github.com/laravel/laravel/blob/v5.2.0/config/auth.php

run composer update or php composer.phar update
or php composer.phar update –no-scripts
possibly this prior as well: php composer.phar dump-autoload

and then troubleshoot resulting errors of that, most likely:
– create /Applications/MAMP/htdocs/{siteName}/bootstrap/cache directory, and make it writable
– add line to app.php: ‘Illuminate\Routing\ControllerServiceProvider’
– change app.php ‘cipher’ => ‘MCRYPT_MODE_CBC’ to ‘cipher’ => ‘AES-256-CBC’,

php artisan key:generate
copy into .env & config/app.php

Some laravel, artisan, composer commands, check version:
php artisan list
php artisan –version

Posted in Uncategorized | Leave a comment

MAC: find active php.ini, add mcrypt extension to php7.2.10, verify

Find your active php.ini:
php -i | grep ‘Configuration File’
php –info | grep php.ini

Add extension to your php.ini (anywhere):
extension=mcrypt.so

Add mcrypt.so to php7.2.10
Credit: https://stackoverflow.com/questions/42504777/enable-mcrypt-using-mamp

“Go to bin directory inside current active PHP version directory. In my case it is /Applications/MAMP/bin/php/php7.2.10/bin
It might be different in your case. Now run the below command with sudo”

sudo ./pecl install channel://pecl.php.net/mcrypt-1.0.1

Could also need to have done:
brew install autoconf mcrypt

Now check that it’s active via one of these:

if(function_exists('mcrypt_encrypt')) {
    echo "mcrypt is loaded!<br />";
} else {
    echo "mcrypt isn't loaded!<br />";
}

if(extension_loaded('mcrypt')) {
    echo "mcrypt extension is loaded!<br />";
} else {
    echo "mcrypt extension isn't loaded!<br />";
}

or on the command line:
php -r “if(function_exists(‘mcrypt_encrypt’)){echo ‘exists’;}else{echo ‘nope’;}”

Credit: https://stackoverflow.com/questions/25476889/how-to-check-if-mcrypt-extension-exists-on-php

Posted in apache2, Laravel, Mac, MAMP, PHP, Terminal | Leave a comment

WordPress CLI wp-cli notes

wp core download
wp cli version
wp cli update
wp user list
wp user update {user ID or login} –user_pass
wp plugin list
wp plugin activate/deactive/delete/install/uninstall {plugin} –activate
wp plugin update –all
wp theme delete {theme}
wp theme update –all
wp config set WP_DEBUG true –raw
other useful config parameters: WP_DEBUG_LOG, WP_DEBUG_DISPLAY, WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT

wp package install wp-cli/admin-command
if “wp-cli ran out of memory”:
php -d memory_limit=512M “$(which wp)” package install <package-name>

wp-config.php version of the same:
define( ‘WP_DEBUG_LOG’, true );
define( ‘WP_DEBUG_DISPLAY’, false );
define(‘WP_MEMORY_LIMIT’, ‘512M’);
define( ‘WP_MAX_MEMORY_LIMIT’, ‘512M’ );

wp package install wp-cli/admin-command
if “wp-cli ran out of memory”:
php -d memory_limit=512M “$(which wp)” package install <package-name>

Posted in Mac, MAMP, PHP, Terminal, Wordpress | Leave a comment

Mac, Symlink, Terminal

ln -S “I’d like to see THIS” “HERE”

Example:
ln -S “/Documents/funProject/wp-content/themes/greatTheme” “/Applications/MAMP/htdocs/funProject/wp-content/themes”

Posted in Mac, Reference, Terminal | Leave a comment

MAMP host & vhosts

You Must Use the MAMP files, NOT the Apple default system versions!

  1. Update the hosts file in /etc/hosts
    add:
    127.0.0.1 newsitename.local
  2. Create a vhost in: /Applications/MAMP/conf/apache/extra/httpd-vhost.conf
  3. In this file: /Applications/MAMP/conf/apache/httpd.conf
    Uncomment this line
    #Include /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf
  4. Then in httpd-vhosts.conf, add a default localhost vhost, AND any new sites you need:
<VirtualHost *:80>
    DocumentRoot "/Applications/MAMP/htdocs"
    ServerName localhost
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin [email protected]
    DocumentRoot "/Applications/MAMP/htdocs/newsitename"
    ServerName newsitename
    ServerAlias newsitename
    ErrorLog "logs/dummy-host.example.com-error_log"
    CustomLog "logs/dummy-host.example.com-access_log" common
</VirtualHost>

Then check via Terminal:
cd /Applications/MAMP/Library/bin
apachectl -S

NOTES!

If you’re using these, they’re not going to work!
/etc/apache2/httpd.conf
/etc/apache2/extra/http-vhost.conf

If you’re pointing to a WordPress, you’ll have to update domain values in the database, and possibly wp-content.php for it not to forward after the server logic, to the values in the db!

Posted in apache2, MAMP | Leave a comment

WordPress “Headers already sent” or “Cookies are blocked due to unexpected output.” also turn on Debug

A few things could cause this, but the first step, is to make sure you didn’t add a space to the top of a file before the <?php!

Warning: Cannot modify header information – headers already sent by (output started at /Applications/MAMP/htdocs/…/wp-login.php:1) in /Applications/MAMP/htdocs/cao/wp-login.php on line 424

Warning: Cannot modify header information – headers already sent by (output started at /Applications/MAMP/htdocs/…/wp-login.php:1) in /Applications/MAMP/htdocs/cao/wp-login.php on line 437

Turning on debugging can help turn the “Cookies are blocked due to unexpected output.” in the warning block just above the login element, into the warning message above, too, which helps.

Add the following to wp-config.php to turn on debugging:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true); 
define('WP_DEBUG_DISPLAY', true);
Posted in PHP, Uncategorized, Wordpress | Leave a comment

Wand Timesheet simple select option selection fill-in automation jQuery bookmarklet

test
//Mon

$('select[name="billingDetailItems[0].billingTimeSpans[0].startHourM"] option[value="8"]').attr('selected', 'selected'); //Mon start

$('select[name="billingDetailItems[0].billingTimeSpans[0].endHourM"] option[value="12"]').attr('selected', 'selected'); //Mon end

$('select[name="billingDetailItems[0].billingTimeSpans[0].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM
doTotalHoursForTimeSpans12('0', '1','0.0');addNew(0,'timeEntry');

$('select[name="billingDetailItems[0].billingTimeSpans[1].startHourM"] option[value="12"]').attr('selected', 'selected'); //lunch start

$('select[name="billingDetailItems[0].billingTimeSpans[1].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[0].billingTimeSpans[1].endHourM"] option[value="1"]').attr('selected', 'selected'); //lunch end

$('select[name="billingDetailItems[0].billingTimeSpans[1].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[0].billingTimeSpans[1].timeEntrySpanType"] option[value="Lunch"]').attr('selected', 'selected'); //type

doTotalHoursForTimeSpans12('0', '2', '0.0');addNew(0,'timeEntry');

$('select[name="billingDetailItems[0].billingTimeSpans[2].startHourM"] option[value="1"]').attr('selected', 'selected'); //after start

$('select[name="billingDetailItems[0].billingTimeSpans[2].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[0].billingTimeSpans[2].endHourM"] option[value="5"]').attr('selected', 'selected'); //after end

$('select[name="billingDetailItems[0].billingTimeSpans[2].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('0', '3', '0.0');

//Tues

$('select[name="billingDetailItems[1].billingTimeSpans[0].startHourM"] option[value="8"]').attr('selected', 'selected'); //Tues start

$('select[name="billingDetailItems[1].billingTimeSpans[0].endHourM"] option[value="12"]').attr('selected', 'selected'); //Tues end

$('select[name="billingDetailItems[1].billingTimeSpans[0].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('1', '1', '0.0');

addNew(1,'timeEntry');

$('select[name="billingDetailItems[1].billingTimeSpans[1].startHourM"] option[value="12"]').attr('selected', 'selected'); //lunch start

$('select[name="billingDetailItems[1].billingTimeSpans[1].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[1].billingTimeSpans[1].endHourM"] option[value="1"]').attr('selected', 'selected'); //lunch end

$('select[name="billingDetailItems[1].billingTimeSpans[1].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[1].billingTimeSpans[1].timeEntrySpanType"] option[value="Lunch"]').attr('selected', 'selected'); //type

doTotalHoursForTimeSpans12('1', '2', '0.0');

addNew(1,'timeEntry');

$('select[name="billingDetailItems[1].billingTimeSpans[2].startHourM"] option[value="1"]').attr('selected', 'selected'); //after start

$('select[name="billingDetailItems[1].billingTimeSpans[2].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[1].billingTimeSpans[2].endHourM"] option[value="5"]').attr('selected', 'selected'); //after end

$('select[name="billingDetailItems[1].billingTimeSpans[2].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('1', '3', '0.0');

//Wed

$('select[name="billingDetailItems[2].billingTimeSpans[0].startHourM"] option[value="8"]').attr('selected', 'selected'); //Tues start

$('select[name="billingDetailItems[2].billingTimeSpans[0].endHourM"] option[value="12"]').attr('selected', 'selected'); //Tues end

$('select[name="billingDetailItems[2].billingTimeSpans[0].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('2', '1', '0.0');

addNew(2,'timeEntry');

$('select[name="billingDetailItems[2].billingTimeSpans[1].startHourM"] option[value="12"]').attr('selected', 'selected'); //lunch start

$('select[name="billingDetailItems[2].billingTimeSpans[1].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[2].billingTimeSpans[1].endHourM"] option[value="1"]').attr('selected', 'selected'); //lunch end

$('select[name="billingDetailItems[2].billingTimeSpans[1].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[2].billingTimeSpans[1].timeEntrySpanType"] option[value="Lunch"]').attr('selected', 'selected'); //type

doTotalHoursForTimeSpans12('2', '2', '0.0');

addNew(2,'timeEntry');

$('select[name="billingDetailItems[2].billingTimeSpans[2].startHourM"] option[value="1"]').attr('selected', 'selected'); //after start

$('select[name="billingDetailItems[2].billingTimeSpans[2].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[2].billingTimeSpans[2].endHourM"] option[value="5"]').attr('selected', 'selected'); //after end

$('select[name="billingDetailItems[2].billingTimeSpans[2].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('2', '3', '0.0');

//Thrs

$('select[name="billingDetailItems[3].billingTimeSpans[0].startHourM"] option[value="8"]').attr('selected', 'selected'); //Thrs start

$('select[name="billingDetailItems[3].billingTimeSpans[0].endHourM"] option[value="12"]').attr('selected', 'selected'); //Thrs end

$('select[name="billingDetailItems[3].billingTimeSpans[0].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('3', '1', '0.0');

addNew(3,'timeEntry');

$('select[name="billingDetailItems[3].billingTimeSpans[1].startHourM"] option[value="12"]').attr('selected', 'selected'); //lunch start

$('select[name="billingDetailItems[3].billingTimeSpans[1].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[3].billingTimeSpans[1].endHourM"] option[value="1"]').attr('selected', 'selected'); //lunch end

$('select[name="billingDetailItems[3].billingTimeSpans[1].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[3].billingTimeSpans[1].timeEntrySpanType"] option[value="Lunch"]').attr('selected', 'selected'); //type

doTotalHoursForTimeSpans12('3', '2', '0.0');

addNew(3,'timeEntry');

$('select[name="billingDetailItems[3].billingTimeSpans[2].startHourM"] option[value="1"]').attr('selected', 'selected'); //after start

$('select[name="billingDetailItems[3].billingTimeSpans[2].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[3].billingTimeSpans[2].endHourM"] option[value="5"]').attr('selected', 'selected'); //after end

$('select[name="billingDetailItems[3].billingTimeSpans[2].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('3', '3', '0.0');

//Fri

$('select[name="billingDetailItems[4].billingTimeSpans[0].startHourM"] option[value="8"]').attr('selected', 'selected'); //Fri start

$('select[name="billingDetailItems[4].billingTimeSpans[0].endHourM"] option[value="12"]').attr('selected', 'selected'); //Fri end

$('select[name="billingDetailItems[4].billingTimeSpans[0].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('4', '1', '0.0');

addNew(4,'timeEntry');

$('select[name="billingDetailItems[4].billingTimeSpans[1].startHourM"] option[value="12"]').attr('selected', 'selected'); //lunch start

$('select[name="billingDetailItems[4].billingTimeSpans[1].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[4].billingTimeSpans[1].endHourM"] option[value="1"]').attr('selected', 'selected'); //lunch end

$('select[name="billingDetailItems[4].billingTimeSpans[1].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[4].billingTimeSpans[1].timeEntrySpanType"] option[value="Lunch"]').attr('selected', 'selected'); //type

doTotalHoursForTimeSpans12('4', '2', '0.0');

addNew(4,'timeEntry');

$('select[name="billingDetailItems[4].billingTimeSpans[2].startHourM"] option[value="1"]').attr('selected', 'selected'); //after start

$('select[name="billingDetailItems[4].billingTimeSpans[2].startMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

$('select[name="billingDetailItems[4].billingTimeSpans[2].endHourM"] option[value="5"]').attr('selected', 'selected'); //after end

$('select[name="billingDetailItems[4].billingTimeSpans[2].endMeridiem"] option[value="1"]').attr('selected', 'selected'); // PM

doTotalHoursForTimeSpans12('4', '3', '0.0');
Posted in bookmarklet, JavaScript, jQuery | Leave a comment

Google Chrome version 49 Chromecast extension for Mac OS 10.7.5

If you have an older Mac, that can no longer upgrade its OS, and thus can’t install the new version of Chrome, you could be stuck with a version that doesn’t have the new features, and also has casting removed. Google removed the extension you need in this scenario for Chrome to cast to your Chromecast. Mediafire: Get and add this extension to your Chrome extensions

You can try here too (looks like it’s still in the store though dark): https://chrome.google.com/webstore/detail/google-cast/boadgeojelhgndaghljhdicfkmllpafd

Posted in Uncategorized | Leave a comment

simple git, yarn, react, mongo project checklist

mkdir foo && cd $_

git init

yarn add react

vi yarn.lock (if you’d like to see versions)

git add package.json yarn.lock

echo “/node_modules” >> .gitignore

git add .gitignore

touch README

git add README

git remote add origin [email protected]:credentials/foobar.git

git commit -m “Initial commit”

git push -u origin master

git checkout -b develop

git push -u origin develop

git checkout -b feature/foo develop

vi foo.js

git add foo.js

git commit -m “New foo file”

git rebase develop (if we believe changes have been made to origin develop, will pull those and then apply our commits)

git checkout develop

git merge feature/foo

git push

git checkout -b release/1.0 develop

git push -u origin release/1.0

git checkout -b hotfix/1.0 develop

etc.

——————

example index connecting to mongo:

require(‘dotenv’).config();

var MongoClient = require(‘mongodb’).MongoClient;

MongoClient.connect(process.env.MONGO_URI, function(err, db) {

    if (err) {

        console.log(‘Cannot connect to MongoDB!’, err);

    } else {

        console.log(‘Connected to MongoDB!’);

    }

});

(put env vars in .env file)

vi .env

MONGO_URI = mongodb://localhost:27017/foo

yarn add mongodb

yarn add dotenv

(have mongo installed and started first!):

brew install mongodb —with-openssl

brew services start mongodb

Connected to MongoDB!”

Posted in Git, JavaScript, Node, REACTJS, Reference | Leave a comment

ReactJS Next.js Isomorphic replace cp CodeIgniter Frontend

Setup

  • Install nvm
  • Target node 6.6.0
    • nvm install 6.6.0
    • nvm use 6.6.0
  • yarn install
  • yarn run dev to start application in development environment

Testing

get-help-fe uses Jest + Enzyme for component testing.

  • yarn run test will run all tests
  • yarn run test:watch will watch/run tests when changes are made
  • yarn run coverage will produce code coverage reports
    • An HTML file located at coverage/icov-report/index.html contains a clean code coverage report

Directory Structure

  • _tests_/ – Jest/Enzyme unit tests
  • actions/ – Redux Actions
  • components/ – Reusable React components
  • config/ – Keystone pipeline configuration
  • coverage/ – Code coverage report output directory
  • dist/ – Bundled code used for code-splitting and production builds
  • layouts/ – Higher-order React components that wrap pages, aka: layouts, themes, templates
  • pages/ – Single instance React components implemented as pages
  • pipelines/ – node-pipeline specific build pipeline configuration
  • reducers/ – Redux reducers
  • static/ – Directory used to host static assets for serving without pre-processing (images, fonts, etc)
  • .babelrc – Configuration file for Babel – transpiles ES6 to better supported ECMA2015 for end users
  • .eslintrc – Configuration file for ESLint
  • api.js – API endpoint definitions
  • application.yaml – Keystone build pipeline configuration
  • next.config.js – Next.js configuration file
  • package.json – Application dependencies
  • pm2.json – PM2 Application Monitoring
  • redirects.js – Legacy URL path redirects
  • routes.js – Application routes
  • server.js – Application server
  • yarn.lock – Yarn lock file — Do not edit, always commit!
Posted in JavaScript, Oracle RightNow CX Technologies, REACTJS | Leave a comment

Electron ReactJS PHP Oracle Service Cloud Multiple Interfaces Quick Deploy via Curl

quick-deploy

Electron application boilerplate based on ReactReduxReact RouterWebpackReact Transform HMR for rapid application development

Install

  • Note: requires a node version >= 6 and an npm version >= 3.

First, clone the repo via git

Install dependencies with yarn

yarn install

:bulb: In order to remove boilerplate sample code, simply run yarn run cleanup. After this is run, the initial sample boilerplate code will be removed in order for a clean project for starting custom dev

$ yarn run dev

CSS Modules

This boilerplate out of the box is configured to use css-modules.

All .css file extensions will use css-modules unless it has .global.css.

If you need global styles, stylesheets with .global.css will not go through the css-modules loader. e.g. app.global.css

If you want to import global css libraries (like bootstrap), you can just write the following code in .global.css:

@import "~bootstrap/dist/css/bootstrap.css";

Packaging

To package apps for the local platform:

$ yarn run package

To package apps for all platforms:

 

$ yarn run package-all

To package apps with options:

$ yarn run package -- --[option]

Further commands

To run the application without packaging run

$ yarn run build
$ yarn start

To run End-to-End Test

$ yarn run build
$ yarn run test-e2e

Options

See electron-builder CLI Usage

Module Structure

This boilerplate uses a two package.json structure.

  1. If the module is native to a platform or otherwise should be included with the published package (i.e. bcrypt, openbci), it should be listed under dependencies in ./app/package.json.
  2. If a module is imported by another module, include it in dependencies in ./package.json. See this ESLint rule.
  3. Otherwise, modules used for building, testing and debugging should be included in devDependencies in ./package.json.

 

Posted in CSS, Electron App, Git, JavaScript, REACTJS | Leave a comment

NodeJS ReactJS, NOT using Isomorphic-fetch, using jQuery JSONP GET -> Oracle Service Cloud Article Feedback ci/ajaxCustom Endpoint

app.js

'use strict';

const compression = require('compression');
const express = require('express');
const next = require('next');
const path = require('path');
const fetch = require('isomorphic-fetch');

const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const auth = '...';
const site = 'help-*-*';
const server = express();

class GetHelp {
constructor() {

this.initApp();
}

/*
Start express application and express healthcheck.
*/
initApp() {
app.prepare().then(() =&amp;amp;gt; {

/*
* API Server
*/

server.get('/api/search/:searchTerm', (req, res, next) =&amp;amp;gt; {
const searchTerm = req.params.searchTerm;
var endpoint = `services/rest/connect/v1.3/analyticsReportResults`;

fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'POST',
mode: 'no-cors',
body: JSON.stringify({
"id": 178394,
"filters": [{
"name": "os_search",
"values": [
searchTerm
]
}]
})
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ article: data }));
});
});

server.get('/api/article/:articleId', (req, res, next) =&amp;amp;gt; {
const articleId = req.params.articleId;
var endpoint = "";
if (parseInt(articleId)) {
endpoint = `/services/rest/connect/v1.3/answers/${articleId}/?fields=solution,summary`;
} else {
endpoint = `/services/rest/connect/v1.3/queryResults/?query=select summary,solution from answers where customFields.c.slug='${articleId}'and customFields.c.lang_id=2035 and language=1 and AccessLevels.NamedIDList.ID=11`;
}

fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'GET',
mode: 'no-cors',
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ article: data }));
});
});

var endpoint = "services/rest/connect/v1.3/queryResults/?query=select lookupName,value from messageBases ";
endpoint += "where lookupName in (" + msgToGet + ")";

fetch(
`https://${auth}@${site}.....com/${endpoint}`, {
method: 'GET',
mode: 'no-cors',
})
.then(function(res) { return res.json(); })
.then(function(data) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ messageBase: data }));
});
});

/*
* APP Routes
*/

server.get('/search/:searchTerm/page/:page', (req, res) =&amp;amp;gt; {
const params = { searchTerm: req.params.searchTerm, page: req.params.page }
return app.render(req, res, '/search', params);
});

server.get('/article/:articleId', (req, res) =&amp;amp;gt; {
const params = { articleId: req.params.articleId }
return app.render(req, res, '/article', params);
});

server.get('*', (req, res) =&amp;amp;gt; {
return handle(req, res);
});

server.listen(8080, 'local-www....dev.com', () =&amp;amp;gt; {
this.initHealthcheck();
});
});
}

}

module.exports = new GetHelp();

/components/StarRating.js

</pre></pre>
import React from 'react';

import Link from '../components/Link';

import Router from 'next/router'

import 'isomorphic-fetch';

import Modal from 'react-modal';

&nbsp;

&nbsp;

const site = 'help-en-us';

const customStyles = {

content : {

top: '50%',

left: '50%',

right: 'auto',

bottom: 'auto',

marginRight: '-50%',

transform: 'translate(-50%, -50%)'

}

};

&nbsp;

&nbsp;

export default class extends React.Component {

constructor(props) {

super(props);

this.state = {

starRating: 0,

articleId: this.props.articleId,

thankYou: false,

showStars: true

};

&nbsp;

&nbsp;

this.handleStar = this.handleStar.bind(this);

this.submitRating = this.submitRating.bind(this);

this.getToken = this.getToken.bind(this);

this.onKeyPress = this.onKeyPress.bind(this);

this.openModal = this.openModal.bind(this);

this.afterOpenModal = this.afterOpenModal.bind(this);

this.closeModal = this.closeModal.bind(this);

this.cancelModal = this.cancelModal.bind(this);

this.submitAnswerFeedback = this.submitAnswerFeedback.bind(this);

this.getToken = this.getToken.bind(this);

}

&nbsp;

&nbsp;

async submitRating(rating) {

let result = await $.ajax({

url: `http://${site}.....com/ci/ajaxCustom/submitAnswerRating`,

data: `a_id=${this.props.articleId}&amp;amp;rate=${rating}&amp;amp;options_count=5`,

dataType: 'jsonp',

jsonpCallback: 'submitAnswerRating',

success: function(response){

console.log(response.submitted);

}

});

let flag = await result;

return flag

};

&nbsp;

&nbsp;

async getToken(rating){

let result = await $.ajax({

url: `http://${site}.....com/ci/ajaxCustom/getNewFormToken`,

data: `formToken=${Math.random().toString(36).substr(2)}`,

dataType: 'jsonp',

jsonpCallback: 'getNewFormToken',

success: function(response){

//console.log(typeof(response.newToken));

return response;

}

});

let token = await result;

return token

};

&nbsp;

&nbsp;

async submitAnswerFeedback(){

let a_id = this.props.articleId;

let rating = this.state.starRating;

let feedbackMessageValue = this.state.feedbackMessageValue;

let token = this.state.token;

console.log('sAF: ' + token);

&nbsp;

&nbsp;

let result = await $.ajax({

url: `http://${site}.....com/ci/ajaxCustom/submitAnswerFeedback`,

data: `a_id=${a_id}&amp;amp;rate=${rating}&amp;amp;message=${feedbackMessageValue}&amp;amp;f_tok=${token}`,

dataType: 'jsonp',

jsonpCallback: 'submitAnswerFeedback',

success: function(response){

console.log(response);

}

});

&nbsp;

&nbsp;

let message = await result;

this.closeModal();

&nbsp;

&nbsp;

return message

};

&nbsp;

&nbsp;

async handleStar(rating){

// submit the star rating clicked

let ratingSubmitted = await this.submitRating(rating);

if(rating >= 3){

// submitted, and done

this.setState({

thankYou: true,

starRating: rating,

ratingSubmitted: ratingSubmitted,

showStars: false

})

} else {

// less than 3, so get a token, and open popup

let token = await this.getToken(rating);

console.log('obj: ' + token.newToken);

console.log(typeof(token.newToken));

this.openModal();

this.setState({

thankYou: true,

starRating: rating,

ratingSubmitted: ratingSubmitted,

token: token.newToken,

showStars: false

})

}

}

&nbsp;

&nbsp;

onKeyPress(e) {

let feedbackMessageValue = e.target.value;

}

&nbsp;

&nbsp;

onChange(e) {

let feedbackMessageValue = e.target.value;

this.setState({

feedbackMessageValue: feedbackMessageValue

});

}

&nbsp;

&nbsp;

openModal() {

this.setState({

modalIsOpen: true

});

}

&nbsp;

&nbsp;

afterOpenModal() {

// references are now sync'd and can be accessed.

this.subtitle.style.color = '#f00';

}

&nbsp;

&nbsp;

closeModal() {

this.setState({

modalIsOpen: false

});

}

&nbsp;

&nbsp;

cancelModal() {

this.setState({

modalIsOpen: false,

showStars: true,

thankYou: false

})

}

&nbsp;

&nbsp;

render () {

const stars = [1,2,3,4,5];

const starRating = this.state.starRating;

const thankYou = this.state.thankYou;

const showStars = this.state.showStars;

&nbsp;

&nbsp;

return (

&nbsp;

&nbsp;

<div className="box">

<div className="answerFeedback">

{!thankYou ? <div className="title">Please rate this article:</div> : ""}

{showStars ? (  <div className="starsBox">

{

stars.map((star) => {

return(

<span

key={star}

className={`g72-star ${star<=starRating?'selectedStar':''}`}

onClick={(e) => this.handleStar(star)}>

</span>

)

})

}

</div>) : (<span></span>)

}

{thankYou ? <div className="thankYou">Thank you for your feedback!</div> : ""}

<div> {

//<button onClick={this.openModal}>Open Modal</button> }

<Modal

isOpen={this.state.modalIsOpen}

onAfterOpen={this.afterOpenModal}

onRequestClose={this.closeModal}

style={customStyles}

contentLabel="Example Modal">

&nbsp;

<h2 ref = { subtitle => this.subtitle = subtitle }>Provide Additional Information</h2>

<div className = "submittedMessage">Your rating has been submitted, please tell us how we can make this answer more useful.</div>

<div className = "faqQuestion">FAQ Feedback – How can we improve this answer? *</div>

<textarea

className = "feedbackMessage"

id = "feedbackMessage"

name = "feedbackMessage"

rows = "4"

cols = "50"

value = { this.state.feedbackMessageValue }

onKeyPress = { (e) => this.onKeyPress(e) }

onChange={(e) => this.onChange(e)}></textarea>

<div className="formButtons">

<button onClick = { this.submitAnswerFeedback } className="submitButton">Submit</button>

<button onClick = { this.cancelModal } className="cancelButton">Cancel</button>

</div>

&nbsp;

&nbsp;

</Modal>

</div>

</div>

<style jsx>{`

.answerFeedback .title {

font-weigth: bold;

}

.answerFeedback .g72-star {

font-size: 1.5em;

margin: 5px;

cursor: pointer;

color: #6d6b6b;

}

.answerFeedback .g72-star:hover, .selectedStar{

color: rgb(251, 224, 0) !important;

}

.starsBox {

background: #a09e9e;

border-radius: 10px;

padding: 0 10px;

width: 170px;

text-align: center;

}

.feedbackMessage {

border: 1px solid;

margin: 10px 10px 10px 0;

padding: 10px;

width: 100%;

}

.formButtons {

text-align: right;

}

.submitButton, .cancelButton {

width: 100%;

margin: 0;

padding: 10px;

font-weight: bold;

color: white;

text-transform: uppercase;

border-radius: 3px;

text-align: center;

text-decoration: none;

}

.submitButton {

background-color: rgba(250, 84, 0, 1);

}

.submitButton:hover {

background-color: #666;

}

.cancelButton {

background-color: rgb(153, 153, 153);

}

.cancelButton:hover {

background-color: #666;

}

.submitbutton:hover {

&nbsp;

&nbsp;

}

`}</style>

</div>

);

}

}
<pre>
Oracle AjaxCustom Service endpoint
function submitAnswerRating()
 {
 $answerID = $this-&amp;gt;input-&amp;gt;get('a_id');
 $rating = $this-&amp;gt;input-&amp;gt;get('rate');
 $scale = $this-&amp;gt;input-&amp;gt;get('options_count');
 if($answerID){
 if($this-&amp;gt;model('Answer')-&amp;gt;rate($answerID, $rating, $scale)){
 print "submitAnswerRating({'submitted':'true'})";
 }else{
 print "submitAnswerRating({'submitted':'false'})";
 }
 }
 }
 
 function getNewFormToken()
 {
 if($formToken = $this-&amp;gt;input-&amp;gt;get('formToken'))
 {
 $newToken = Framework::createTokenWithExpiration(0, false);
 print "getNewFormToken({'newToken':'" . $newToken . "'})";
 }
 }
 
 function submitAnswerFeedback()
 {
 AbuseDetection::check();
 $answerID = $this-&gt;input-&gt;get('a_id');
 if($answerID === 'null')
 $answerID = null;
 $rate = $this-&gt;input-&gt;get('rate');
 $message = $this-&gt;input-&gt;get('message');
 $givenEmail = '[email protected]';
 $threshold = 3;
 $optionsCount = 5;
 $formToken = $this-&gt;input-&gt;get('f_tok');
 $incidentResult = $this-&gt;model('Incident')-&gt;submitFeedback($answerID, $rate, $threshold, null, $message, $givenEmail, $optionsCount);
 if($incidentResult-&gt;result){
 print "submitAnswerFeedback({'ID':'" . $incidentResult-&gt;result-&gt;ID . "'})";
 //$this-&gt;_renderJSON(array('ID' =&gt; $incidentResult-&gt;result-&gt;ID));
 }else{
 if($incidentResult-&gt;error){
 print "submitAnswerFeedback({'error 2':'" . $incidentResult-&gt;error-&gt;externalMessage . "'})";
 }
 }
Posted in JavaScript, Node, Oracle RightNow CX Technologies, REACTJS | Leave a comment

Google Chrome version 58 Emulate User-Agent (UA) so hard to find!

This functionality keeps moving. If you Google it, depending on the version, it could be super hard to find. I finally re-found where to change the User-Agent, at least in my current version of Chrome, at the time of this posting, version 58.

NOT easy to find, nor Google, ironic eh, but super useful. I was needing to emulate IE7, which is what Oracle’s console “Browser Control” utilizes (so lame, keep up people). Anyway:

  • Obviously, open the developer tools (I prefer to right click->inspect element)
  • Bottom right corner (if docked at the bottom of the window), Top right corner (if docked to the right side, this is where I prefer it), is a three little dots menu
  • more tools->Network conditions (seriously?)->User Agent!!

Credit/thanks to:

Posted in Chrome, Google, Internet Explorer | Leave a comment

Oracle Service Cloud RightNowCX External Events / Custom Process: Curl a service on Save or Update

/*
* CPMObjectEventHandler: updateContact
* Package: OracleServiceCloud
* Objects: Contact
* Actions: Create, Update
* Version: 1.3
*/

use \RightNow\CPM\v1 as RNCPM;
use \RightNow\Connect\v1_3 as RNCPHP;

load_curl();

class updateContact implements RNCPM\ObjectEventHandler {

/**
* Apply CPM logic to object.
* @param int $runMode
* @param int $action
* @param object $contact
* @param int $cycle
*/
public static function apply($run_mode, $action, $contact, $n_cycles) {

if ($n_cycles != 0) return;

try {

$contact->CustomFields->c->contact_field_being_checked = new RNCPHP\NamedIDLabel();
$contact->CustomFields->c->contact_field_being_checked->ID = 2192; // Unregistered CPM
$header[] = "Content-Type: application/x-www-form-urlencoded";
$service_endpoint = 'http://INTERFACE-URL/cgi-bin/nikeagent.cfg/php/custom/scriptName.php?email=';

$noEmail = true;

foreach ($contact->Emails as $email) {
if ($email) {
$noEmail = false; // found an email

$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $service_endpoint . $email->Address,
CURLOPT_HEADER => 0,
CURLOPT_HTTPHEADER => $header,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSL_VERIFYHOST => 0
));
$resp = curl_exec($ch);

if ($resp !== false) {
$respObj = json_decode($resp, true);
$regUserString = $respObj['contact_field_being_checked']; // 1 or empty, is boolean
if ($regUserString == 1) {
$contact->CustomFields->c->contact_field_being_checked->ID = 2189; // Registered CPM
}else{
}
}
curl_close($ch);
}
}

$contact->save(RNCPHP\RNObject::SuppressAll);
} catch (\Exception $e) {
throw $e;
}

return;
}
}

class updateContact_TestHarness implements RNCPM\ObjectEventHandler_TestHarness {
static $test_contact = null;

public static function setup() {
// TODO: Pass array of contacts
// Should pass an array of contacts with different
// emails and different orders of registered emails

// We want to create contacts on the fly, but
// you can't duplicate emails, so we should probably check
// if the email exists, and delete it - perhaps have a set test
// contact
try {
$contact = new RNCPHP\Contact;
$contact->Emails = new RNCPHP\EmailArray();
$contact->Emails[0] = new RNCPHP\Email();
$contact->Emails[0]->AddressType = new RNCPHP\NamedIDOptList();
$contact->Emails[0]->AddressType->LookupName = "Email - Primary";
$contact->Emails[0]->Address = "[email protected]";
$contact->Emails[0]->Invalid = false;
$contact->CRMModules = new RNCPHP\CRMModules();
$contact->CRMModules->Service = 1;
$contact->save(RNCPHP\RNObject::SuppressAll);

static::$test_contact = $contact;
} catch (\Exception $e) {
echo $e->getMessage();
}

return;
}

public static function fetchObject($action, $object_type) {
// Returned object is passed to apply()
return (static::$test_contact);
}

public static function validate($action, $object) {
if (RNCPM\ActionCreate == $action) {
if (assert($object->CustomFields->c->contact_field_being_checked->ID == 2189)) {
echo "Create test passed - " . $object->Emails[0]->Address . "\n";
return true;
} else {
echo "Create test FAILED - " . $object->Emails[0]->Address . "\n";
}
} elseif (RNCPM\ActionUpdate == $action) {
if (assert($object->CustomFields->c->contact_field_being_checked->ID == 2189)) {
echo "Update test passed - " . $object->Emails[0]->Address . "\n";
return true;
} else {
echo "Update test FAILED - " . $object->Emails[0]->Address . "\n";
}
} else {
echo "Invalid action";
}
}

public static function cleanup() {
// Delete temporary test contact
$contact = static::$test_contact;
$contact->destroy();

static::$test_contact = null;
}
}

Posted in Codeigniter, Oracle RightNow CX Technologies | Leave a comment

Oracle Service Cloud RightNowCX Event subscribe Notes

RightNow.Event.subscribe("evt_chatCobrowseAcceptResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatCobrowseStatusResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_fileUploadUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatNotifyFattachUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatPostResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEngagementParticipantAddedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEngagementParticipantRemovedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEngagementConcludedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatCobrowseInvitationResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatReconnectUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatAgentAbsentUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatAgentStatusChangeResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatPostCompletion",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatEventBusInitializedResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatConnectResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatFetchUpdateResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatStateChangeResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatSetParametersResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatValidateParametersResponse",function(e, f){console.log(e,f);},null);
RightNow.Event.subscribe("evt_chatCheckAnonymousResponse",function(e, f){console.log(e,f);},null);

example:

RightNow.Event.subscribe("evt_chatStateChangeResponse",function(e,f){
if(f[0].data.currentState && f[0].data.currentState == 2) {
window.chatID = RightNow.Chat.Controller.ChatCommunicationsController._engagementID;
}
},null);

Posted in Codeigniter, Oracle RightNow CX Technologies, PHP | Leave a comment

Oracle Service Cloud RightNowCX Configuration for Developer Chatting with Self

-> Chat starts

-> Triggers Rules evaluation

-> Rule matches regex on email submitted

-> Routes the chat to a particular queue

-> Queue is assigned to a profile

-> Profile is assigned to dev

Now you can submit a chat request via the page/UI, and receive it via the console, or let it sit to develop “waiting”/unconnected experience!

Posted in Codeigniter, Oracle RightNow CX Technologies, PHP | Leave a comment

Oracle Service Cloud RightnowCX Custom Controller: Lookup Contact, Create Incident

<?php

namespace Custom\Controllers;

/************* Agent Authentication ***************/
require_once( get_cfg_var("doc_root")."/ConnectPHP/Connect_init.php" );
initConnectAPI();

use RightNow\Connect\v1_2 as RNCPHP;

class GSChatIncident extends \RightNow\Controllers\Base
{

function __construct()
{
parent::__construct();
}

public function createContactIncident() {

try{
\RightNow\Libraries\AbuseDetection::check();

//$incident->SiteInterface = new RNCPHP\NamedIDLabel();
//$incident->SiteInterface->ID = 111;

$email = $_POST['email'];
$cID = (int)$_POST['countryID'];
$languageID = (int)$_POST['langID'];

$CI = &get_instance();
$contactmodelobj=$CI->load->model('standard/Contact_model');

$found = $this->Contact_model->lookupContactByEmail($email, null, null)->result;

if($found != null && is_int($found) && $found != false){
$creatingContact = $found;
} else {
$creatingContact = 1;
}

$incident = new RNCPHP\Incident();
$incident->Subject = "Chat cancelled";
$incident->CustomFields->c->system_source->ID = 2156;
$incident->CustomFields->c->country = new RNCPHP\NamedIDLabel();
$incident->CustomFields->c->country = $cID;
$incident->Language = $languageID;
$incident->PrimaryContact = RNCPHP\Contact::fetch($creatingContact); //Required field to create an incident through connect PHP
$incident->save(RNCPHP\RNObject::SuppressAll);
}

catch (Exception $err ){
echo $err->getMessage();
}
}
}
?>

Posted in Codeigniter, Oracle RightNow CX Technologies, PHP | Leave a comment

Oracle Service Cloud RightNow CX PHP Connect API write to Custom Business Object example Custom Controller

url: /cc/GSChatLog/createChatLog

<?php

namespace Custom\Controllers;

/************* Agent Authentication ***************/
require_once( get_cfg_var("doc_root")."/ConnectPHP/Connect_init.php" );
initConnectAPI();
use RightNow\Connect\v1_2 as RNCPHP;

class GSChatLog extends \RightNow\Controllers\Base
{

function __construct()
{
parent::__construct();
}

public function createChatLog() {

try{
\RightNow\Libraries\AbuseDetection::check();

$email = $_POST['email'];
$cID = (int)$_POST['countryID'];
$languageID = (int)$_POST['langID'];
$name = $_POST['name'];
$referrerUrl = $_POST['referrerUrl'];
$siteID = $_POST["siteID"];
$platformID = $_POST["platformID"];
$chatStatus = $_POST["chatStatus"];
$chatID = $_POST["chatID"];
$lob = strtoupper($_POST["lob"]);

$log = new RNCPHP\ContactUs\chat_log();
$log->chat_id = $chatID;
$log->chat_log_status = $chatStatus;
$log->site_id = $siteID;
$log->chat_group = 2156;
$log->referring_url = $referrerUrl;
$log->interface = $platformID;
$log->email_address = $email;
$log->name = $name;
$log->language_id = $languageID;
$log->country_id = $cID;
$log->lob_id = $lob;
$log->save();

catch (Exception $err ){
echo $err->getMessage();
}
}
}
?>

Posted in Codeigniter, Oracle RightNow CX Technologies, PHP | Leave a comment

Oracle Service Cloud RightNow CX PHP Connect API Analytics Report example

$report_id = ..74..;
$report = RNCPHP\AnalyticsReport::fetch($report_id);

$report_filter = new RNCPHP\AnalyticsReportSearchFilter;
$report_filter->Name = 'chats.email';
$report_filter->Values = array($email);
$filters = new RNCPHP\AnalyticsReportSearchFilterArray;
$filters[] = $report_filter;

$report_result = $report->run(0,$filters);

while($reportRow = $report_result->next())
{
print_r($reportRow);
$chatID = (int)$reportRow['chat_id'];
}

Posted in Codeigniter, Oracle RightNow CX Technologies, PHP | Leave a comment

Oracle Service Cloud (RNT/RNW) promote straight to Production shortcut

/ci/admin/deploy/stageandpromote

also straight to a tier environment:

ci/admin/overview/set_cookie/development

optional:

ci/admin/overview/set_cookie/development/mobile (etc)

ci/admin/overview/developmentRedirect/{page, ie: app/home/country/es}

Posted in Oracle RightNow CX Technologies | Leave a comment

test return values of user’s browser

var $temp = $('<div style="background-color:#ffffff"/>').appendTo('body');
var thisBrowserWhite = $temp.css('background-color');
$temp.remove();
console.log(thisBrowserWhite);
Posted in JavaScript | Leave a comment

add unique to Javascript Array prototype

Array.prototype.unique = function() {
    var a = this.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }
    return a;
};
Posted in JavaScript | Leave a comment

Google maps, mySQL locations, PHP service

HTML:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    <link rel="stylesheet" href="dealers.css">
</head>
    <body>
        <div class="row mapSection">
            <div class="col-xs-12">

                <div id="map"></div>
                <div id="panel">
                    <div id="entryRow">
                        <div><select id="locationSelect" style="width:100%;visibility:hidden"></select></div>
                        <input type="text" id="addressInput" />
                        <select id="radiusSelect">
                            <option value="5" selected>5 miles</option>
                            <option value="25" selected>25 miles</option>
                            <option value="100">100 miles</option>
                            <option value="200">200 miles</option>
                            <option value="500">500 miles</option>
                        </select>
                        <input type="text" id="find" value="Search"/>
                        <input type="button" id="refresh" value="redo Search"/>
                    </div>
                    <ul class="resultDealers">
                    </ul>
                </div>

            </div>
        </div>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
        <script src="https://maps.googleapis.com/maps/api/js?key=***YOUR*KEY*HERE***" type="text/javascript"></script>
        <script type="text/javascript" src="Maps.js"></script>
    </body>
</html>

CSS:

body {
  font-family: sans-serif;
  margin: 0px;
  padding: 0px;
}
#map,
#panel {
  height: 500px;
  float: left;
}
#map {
  width: 60%;
}
#entryRow {
  margin: 0 0 0 15px;
}
#panel {
  width: 40%;
}
.resultDealers {
  padding: 0;
  margin: 15px;
  overflow: scroll;
  height: 420px;
}
.resultDealers li {
  list-style-type: none;
  border-left: 1px solid;
  border-top: 1px solid;
  border-right: 1px solid;
  padding: 10px;
}
.resultDealers li:last-child {
  border-bottom: 1px solid;
}
.highlightDealer {
  background: #E8E8E8;
}
.markerBox {
  cursor: pointer;
}
.markerBox:hover {
  background: #E3F4F9;
}
#panel .feature-filter label {
  width: 130px;
}
p.attribution,
p.attribution a {
  color: #666;
}
#find {
  background: #DEDCDC;
  border: 1px solid gray;
  width: 65px;
  padding: 2px;
  text-align: center;
  font-weight: bold;
  cursor: pointer;
  margin-left: 15px;
}
#find:hover {
  background: #F9F4F4;
}
#radiusSelect {
  margin-left: 15px;
}
#addressInput {
  float: left;
  margin-left: 5px;
  padding-left: 10px;
  width: 65px;
}
#locationSelect {
  margin: 10px 5px;
  width: 95% !important;
}

JavaScript:

/* ---------  Start Maps.js  --------- */

Maps Module
//Usage: Maps.init();

Maps = (function ( window, google ) {

	var map,
		markers = [],
		infoWindow,
		locationSelect;

	var load = function load () {
			map = new google.maps.Map(document.getElementById("map"), {
				center: new google.maps.LatLng(40, -100),
				zoom: 4,
				mapTypeId: 'roadmap',
				// scrollWheel: false,
				// zoomControl: false,
				streetViewControl: false,
				rotateControl: false,
				fullscreenControl: false,
				navigationControl: false,
				scaleControl: false,
				// draggable: false,
				mapTypeControl: false,
				mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}
		});
		infoWindow = new google.maps.InfoWindow();

		locationSelect = document.getElementById("locationSelect");
		locationSelect.onchange = function() {
			var markerNum = locationSelect.options[locationSelect.selectedIndex].value;
			if (markerNum != "none"){
				google.maps.event.trigger(markers[markerNum], 'click');
			}
		};

		refreshMap();

		google.maps.event.addListener(map, 'zoom_changed', function() {
			//$('#radiusSelect option:selected').next().attr('selected', 'selected');
			//console.log(map.getCenter());
			//searchLocationsNear (map.getCenter());
		});

	}

	var bindInfoWindow = function bindInfoWindow ( marker, map, infoWindow, html ) {
      google.maps.event.addListener(marker, 'click', function() {
        infoWindow.setContent(html);
        infoWindow.open(map, marker);
      });
    }

    var refreshMap = function refreshMap () {
    	if(navigator.geolocation) {
			navigator.geolocation.getCurrentPosition(function(position) {

				var latLng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);

				var geocoder = new google.maps.Geocoder();

				geocoder.geocode({ 'latLng': latLng}, function (results, status) {
					if (status == google.maps.GeocoderStatus.OK) {

						for ( var j = 0; j < results[0].address_components.length; j++ ) {
							for ( var k = 0; k < results[0].address_components[j].types.length; k++ ) {
								if ( results[0].address_components[j].types[k] == "postal_code" ) {
									zipcode = results[0].address_components[j].short_name;
								}
							}
						}

						document.getElementById("addressInput").value = zipcode;
						searchLocations();
					} else {
						console.log("Geocoding failed: " + status);
					}
				});
			});
		}
	}

	var downloadUrl = function downloadUrl ( url, callback ) {
		var request = window.ActiveXObject ? new ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest;
		request.onreadystatechange = function() {
			if ( request.readyState == 4 ) {
				request.onreadystatechange = doNothing;
				callback(request.responseText, request.status);
			}
		};

		request.open('GET', url, true);
		request.send(null);
	}

	var searchLocations = function searchLocations () {
		var address = document.getElementById("addressInput").value;
		var geocoder = new google.maps.Geocoder();
		geocoder.geocode({address: address}, function(results, status) {
			if (status == google.maps.GeocoderStatus.OK) {
	  			searchLocationsNear(results[0].geometry.location);
			} else {
	  			alert(address + ' not found');
			}
		});
	}

	var clearLocations = function clearLocations() {
		infoWindow.close();
		for (var i = 0; i < markers.length; i++) {
			markers[i].setMap(null);
		}
		markers.length = 0;

		locationSelect.innerHTML = "";
		var option = document.createElement("option");
		option.value = "none";
		option.innerHTML = "See all results:";
		locationSelect.appendChild(option);
	}

	var searchLocationsNear = function searchLocationsNear ( center ) {
		clearLocations();

		var radius = document.getElementById('radiusSelect').value;
		var searchUrl = '/dealers.php?lat=' + center.lat() + '&lng=' +  center.lng() + '&radius=' + radius;
		downloadUrl( searchUrl, function(data) {
			var xml = parseXml(data);
			var markerNodes = xml.documentElement.getElementsByTagName("marker");
			var bounds = new google.maps.LatLngBounds();
			for (var i = 0; i < markerNodes.length; i++) {
				var id = markerNodes[i].getAttribute("id");
				var name = markerNodes[i].getAttribute("name");
				var address = markerNodes[i].getAttribute("address");
				var city = markerNodes[i].getAttribute("city");
				var state = markerNodes[i].getAttribute("state");
				var zip = markerNodes[i].getAttribute("zip");
				var url = markerNodes[i].getAttribute("url");
				var email = markerNodes[i].getAttribute("email");
				var distance = parseFloat(markerNodes[i].getAttribute("distance"));
				var latlng = new google.maps.LatLng(
					parseFloat(markerNodes[i].getAttribute("lat")),
					parseFloat(markerNodes[i].getAttribute("lng")));

				createOption(name, distance, i);
				createMarker(id, latlng, name, address, city, state, zip, url, email);
				bounds.extend(latlng);
			}
			map.fitBounds(bounds);
			locationSelect.style.visibility = "visible";
			locationSelect.onchange = function() {
			 var markerNum = locationSelect.options[locationSelect.selectedIndex].value;
			 google.maps.event.trigger(markers[markerNum], 'click');
			};
		});
	}

	var createMarker = function createMarker ( id, latlng, name, address, city, state, zip, url, email ) {
		var html = "<div class='marker-" + id + "'><b>" + name + "</b> <br/>" + address +  "<br/>" + city + " " + state + ", " + zip + "<br />" + url + "<br /><a href='mailto:" + email + "'>" + email + "</a></div>";
		var marker = new google.maps.Marker({
			map: map,
			position: latlng
		});
		google.maps.event.addListener(marker, 'click', function() {
			//infoWindow.setContent(html);
			//infoWindow.open(map, marker);
			$("li[class*='marker-']").removeClass('highlightDealer');
			$("li.marker-" + id).addClass('highlightDealer');
			window.location.href = "#marker-"+ id;
			window.scrollTo(0, 0);

			map.setZoom(16);
			map.setCenter(marker.getPosition());
		});
		markers.push(marker);

		$("#panel ul").append("<li class='markerBox marker-" + id + "'><a name='marker-" + id + "'></a><b>" + name + "</b><br/>" + address +  "<br/>" + city + " " + state + ", " + zip + "<br />" + url + "<br /><a href='mailto:" + email + "'>" + email + "</a></li>");
		$('.marker-' + id).on('click', function() {
			$("li[class*='marker-']").removeClass('highlightDealer');
			$("li.marker-" + id).addClass('highlightDealer');
			map.setZoom(16);
			map.setCenter(marker.getPosition());
		});
	}

	var createOption = function createOption ( name, distance, num ) {
		var option = document.createElement("option");
		option.value = num;
		option.innerHTML = name + "(" + distance.toFixed(1) + ")";
		locationSelect.appendChild(option);
	}

	var parseXml = function parseXml(str) {
		if (window.ActiveXObject) {
			var doc = new ActiveXObject('Microsoft.XMLDOM');
			doc.loadXML(str);
			return doc;
		} else if (window.DOMParser) {
			return (new DOMParser).parseFromString(str, 'text/xml');
		}
	}

    function doNothing() {}

	$('#find').on('click', function() {
		$('#panel ul').empty();
		searchLocations();
	});
	$('#addressInput').on('click', function () {
		$(this).val('');
	});
	$('#radiusSelect').on('change', function () {
		$('#panel ul').empty();
		searchLocations();
	});
	$('#refresh').on('click', function () {
		var bounds = map.getBounds();
		var ne = bounds.getNorthEast(); // LatLng of the north-east corner
		var sw = bounds.getSouthWest(); // LatLng of the south-west corder

		var nw = new google.maps.LatLng(ne.lat(), sw.lng());
		var se = new google.maps.LatLng(sw.lat(), ne.lng());
		console.log('nw: ' + nw);
		console.log('se: ' + se);
		//searchLocationsNear();
		//searchLocations();
	});

	return {
		load: load
	}

})( window, google );

$(function(){
    loadModules.start();
})

var loadModules = loadModules || {};
loadModules.start = function(){
    // Maps module init
    Maps.load();
};
/* ---------  End Maps.js --------- */

PHP:

<?php
    header("Access-Control-Allow-Origin: *");
    $servername = "***Your*DB*URL***";
    $username = "***Your*DB*USERNAME***";
    $password = "***Your*DB*PASS***";
    $dbname = "***Your*DB*NAME***";

    // Get parameters from URL
    $center_lat = $_GET["lat"];
    $center_lng = $_GET["lng"];
    $radius = $_GET["radius"];

    // Start XML file, create parent node
    $dom = new DOMDocument("1.0");
    $node = $dom->createElement("markers");
    $parnode = $dom->appendChild($node);

    // Opens a connection to a mySQL server
    $connection=mysql_connect ($servername, $username, $password);
    if (!$connection) {
      die("Not connected : " . mysql_error());
    }

    // Set the active mySQL database
    $db_selected = mysql_select_db($dbname, $connection);
    if (!$db_selected) {
      die ("Can\'t use db : " . mysql_error());
    }

    // Search the rows in the markers table
    $query = sprintf("SELECT id, name, address, city, state, zip, url, email, lat, lng, ( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance FROM dealers HAVING distance < '%s' ORDER BY distance LIMIT 0 , 20",
      mysql_real_escape_string($center_lat),
      mysql_real_escape_string($center_lng),
      mysql_real_escape_string($center_lat),
      mysql_real_escape_string($radius));
    $result = mysql_query($query);

    $result = mysql_query($query);
    if (!$result) {
      die("Invalid query: " . mysql_error());
    }

    header("Content-type: text/xml");

    // Iterate through the rows, adding XML nodes for each
    while ($row = @mysql_fetch_assoc($result)){
        $node = $dom->createElement("marker");
        $newnode = $parnode->appendChild($node);
        $newnode->setAttribute("id", $row['id']);
        $newnode->setAttribute("name", $row['name']);
        $newnode->setAttribute("address", $row['address']);
        $newnode->setAttribute("city", $row['city']);
        $newnode->setAttribute("state", $row['state']);
        $newnode->setAttribute("zip", $row['zip']);
        $newnode->setAttribute("url", $row['url']);
        $newnode->setAttribute("email", $row['email']);
        $newnode->setAttribute("lat", $row['lat']);
        $newnode->setAttribute("lng", $row['lng']);
        $newnode->setAttribute("distance", $row['distance']);
    }

    echo $dom->saveXML();

?>

Posted in Google, HTML, JavaScript, jQuery, Maps, MySQL, PHP | Leave a comment

Styling radio buttons

Hide/replace radio buttons

CSS:

[type="radio"] {
  border: 0; 
  clip: rect(0 0 0 0); 
  height: 1px; margin: -1px; 
  overflow: hidden; 
  padding: 0; 
  position: absolute; 
  width: 1px;
}

[type="radio"] + span {
  display: block;
}

/* the basic, unchecked style */
[type="radio"] + span:before {
  content: '';
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.25em;
  border-radius: .5em;
  border: 0.15em solid @base-gray-medium;
  box-shadow: 0 0 0 0.1em @base-gray-medium;
  margin-right: 0.75em;
  transition: 0.5s ease all;
}

/* the checked style using the :checked pseudo class */
[type="radio"]:checked + span:before {
  background: red;
  box-shadow: 0 0 0 0.1em @base-gray-medium;
}

/* never forget focus styling */
[type="radio"]:focus + span:after {
  content: '\0020\2190';
  font-size: 1.5em;
  line-height: 1;
  vertical-align: -0.125em;
}

Handlebars template markup:

<script id="dealer-list-template" type="text/x-handlebars-template">
	<label for="dealer{{id}}" class="col-xs-10 dealerItem">
		<input type="radio" value="{{title}}" name="dealers" id="dealer{{id}}">
			<span class="dealerTitle">{{title}}</span>
			<span class="dealerAddress">{{address}}</span>
	</label>
	<div class="col-xs-2 distance">{{distance}}</div>
</script>
Posted in CSS, Handlebars, HTML, JavaScript | Leave a comment

WordPress Powerpress Youtube loop to show all posts with thumbnail

Add a loop to index.php (Main Index Template) to show all the blog’s posts/youtube videos with thumbnails below the homepage most recent single post.

<?php
/* added loop to return all wordpress posts */
	$rPosts = new WP_Query();
    	$rPosts->query('showposts=-1');
    	while ($rPosts->have_posts()) : $rPosts->the_post();

/* retrieve custom 'enclosure' value, which contains the Youtube embed code, from each post */	
		$enclosure = get_post_custom_values('enclosure');

/* don't render it immediately so that we can see what we're getting back */
		$enclosure = str_replace("<iframe", "", $enclosure[0]);

/* turn html content into an array so that we can target the Youtube video id */
		$enclosure = explode("http://www.youtube.com/embed/",$enclosure);
		$enclosure = explode("?", $enclosure[1]);

/* append the video id onto the youtube thumbnail url */
		$final = "<img src='http://img.youtube.com/vi/$enclosure[0]/default.jpg' />";
		?>

/* display thumb wrapped in an anchor */
		<a href="<?php the_permalink(); ?>"><?php echo $final; ?></a>
<?php
	endwhile;
	wp_reset_query();
?>
Posted in PHP, Powerpress, Wordpress, Youtube | Leave a comment

Javascript Module of jQuery extensions, example: animateRotate

/* ---------  Start jquery.extensions.module.js  --------- */

// jquery extensions Module

(function ( $ ) {

	$.fn.animateRotate = function(angle, duration, easing, complete) {
		var args = $.speed(duration, easing, complete);
		var step = args.step;
		return $(this).each(function(i, e) {
		   	args.complete = $.proxy(args.complete, e);
		    args.step = function(now) {
		    	$.style(e, 'transform', 'rotate(' + now + 'deg)');
		    	if (step) return step.apply(e, arguments);
		    };

		    $({deg: 0}).animate({deg: angle}, args);
		});
	}

// method/extension #2 goes here, and so on...

})( window.jQuery );

/* ---------  End jquery.extensions.module.js --------- */

Posted in JavaScript, jQuery | Leave a comment

Return positions of matching closing parenthesis

def get_closing_paren(sentence, opening_paren_index):
    open_nested_parens = 0
    position = opening_paren_index + 1

    for char in sentence[position:]:
        if char == '(':
            open_nested_parens += 1
        elseif char == ')':
            if open_nested_parens == 0:
                return position
            else:
                open_nested_parens -= 1
        position += 1

    raise Exception("No closing parenthesis :(")

source: https://www.interviewcake.com/question/matching-parens

Posted in Algorithms, Interview Questions, JAVA | Leave a comment

Google Maps API v3 load array of locations, detect ip and zoom, generate list by distance to locations

In the template or HTML:

<div id="container">
<div class="row mapSubNav">
<div class="col-xs-6">
<div class="mapNavLeft">Find a Store</div>
</div>
<div class="col-xs-6 mapNavRight">
<a id="mapView">Map View</a> | <a id="listView">List View</a>
</div>
</div>
<div class="row">
<div class="col-xs-12 noPad">
<div id="floating-panel">
<input id="findAddress" name="findAddress" type="textbox" value="Find a Store - City, State, Zip">
<select id="findRadius">
<option value="13" selected="selected">radius</option>
<option value="12">5 miles</option> <!-- 4 miles -->
<option value="11">10 miles</option> <!-- 8 miles -->
<option value="10">15 miles</option> <!-- 16 miles -->
</select>
<input id="findSubmit" type="submit" value="Find a shop" class="btnLeft">
</div>
<div class="sideBar">
<div class="closeBtn">x</div>
<h3>Our Stores:</h3>
</div>
<div id="map"></div>
<div id="outputList"></div>
</div>
</div>
</div><strong>
</strong>

<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry&amp;amp;key=**YOUR_KEY_HERE**"</script>;
<script type="text/javascript" src="${sharedResourcePath}/js/locations.js"</script>;
<script type="text/javascript" src="${sharedResourcePath}/js/maps-module.js"</script>;

Locations array example:

var DEALERS = (function() {
var image = '../images/marker.png';

var locations = [
['location name 1',32.215143,-90.151818,map,image,'detailed description'],
['location name 2',47.336401,-116.888100,map,image,'detailed description'],
['location name 3',33.755219,-90.715672,map,image,'detailed description'],
['location name 4',33.646063,-87.058802,map,image,'detailed description'],
['location name 5',48.548468,-117.909399,map,image,'detailed description']
];
})();

 

MAPS MODULE JS:

MAPMOD = (function( window, google, DEALERS ) {

 var gmarkers = [],
 infos = [],
 map = {},
 whichMap = "";

 var init = (function init () {
 
 if( !document.getElementById("map") ) { return; }

 whichMap = $('#map').attr("data-map-type");

 switch( whichMap ) {
 case "dealer":
 var myOptions = {
 //center: new google.maps.LatLng(37.4419, -122.1419),
 zoom: 4,
 mapTypeId: google.maps.MapTypeId.ROADMAP,
 scrollwheel: false,
 disableDefaultUI: true,
 draggable: false,
 scaleControl: false,
 zoomControl: false
 };
 initDealerDetail(myOptions);
 break;

 case "all": 
 var myOptions = {
 zoom: 4,
 mapTypeId: google.maps.MapTypeId.ROADMAP,
 scrollwheel: false
 };
 allDealers(myOptions);
 break;
 }
 });

 var allDealers = (function allDealers (myOptions) {
 
 map = new google.maps.Map( document.getElementById("map"), myOptions );

 setMarkers( map, DEALERS.locations );

 var geocoder = new google.maps.Geocoder();

 var US = {
 NorthEast: {
 lat: 49.38,
 lng: -66.94
 },
 SouthWest: {
 lat: 25.82,
 lng: -124.39
 }
 }
 
 var USbounds = new google.maps.LatLngBounds(new google.maps.LatLng(US.SouthWest.lat, US.SouthWest.lng),
 new google.maps.LatLng(US.NorthEast.lat, US.NorthEast.lng));

 map.fitBounds(USbounds);
 //var USrect = new google.maps.Rectangle({map:map, bounds: USbounds});

 $('#findSubmit').on('click', function() {
 geocodeAddress(geocoder, map);
 });

 $("#findAddress").on("click", function() {
 $(this).val("");
 })

 $("#mapView").on("click", function() {
 $("#outputList").hide();
 $("#map").show();
 })
 
 $("#listView").on("click", function() {
 $("#map").hide();
 $("#outputList").show();
 })
 
 document.onkeydown=function() {
 if(window.event.keyCode=='13') {
 $('#findSubmit').click();
 }
 }

 geolocate(geocoder, map);
 });

 var geolocate = (function geolocate (geocoder, map) {

 // Try HTML5 geolocation.
 if (navigator.geolocation) {

 //var address = document.getElementById('findAddress').value ? document.getElementById('findAddress').value : {};

 navigator.geolocation.getCurrentPosition(function(position) {
 var pos = {
 lat: position.coords.latitude,
 lng: position.coords.longitude
 };

 //infoWindow.setPosition(pos);
 //infoWindow.setContent('Location found.');
 document.getElementById('findAddress').value = pos.lat + " " + pos.lng;
 $('#findRadius').val(8);
 geocodeAddress(geocoder, map);

 //map.setCenter(pos);
 //map.setZoom(9);
 }, function() {
 handleLocationError(true, infoWindow, map.getCenter());
 });
 } else {
 // Browser doesn't support Geolocation
 handleLocationError(false, infoWindow, map.getCenter());
 }
 });

 var initDealerDetail = (function initDealerDetail (myOptions) {

 map = new google.maps.Map( document.getElementById("map"), myOptions );

 setMarkers( map, DEALERS.locations );

 var lat = parseFloat( $('#map').attr("data-map-lat") );
 var lng = parseFloat( $('#map').attr("data-map-lng") );

 var pos = {
 lat: lat,
 lng: lng
 };

 map.setCenter(pos);
 map.setZoom(15);
 map.panBy(-250, 0);
 });
 
 function handleLocationError(browserHasGeolocation, map, pos) {
 map.setPosition(pos);
 map.setContent(browserHasGeolocation ? 'Error: The Geolocation service failed.' : 'Error: Your browser doesn\'t support geolocation.');
 }
 
 function geocodeAddress(geocoder, resultsMap) {
 
 var address = document.getElementById('findAddress').value;
 
 var radius = parseInt($( "#findRadius option:selected" ).val());
 if(isNaN(radius)){ radius = 8; }

 geocoder.geocode({'address': address}, function(results, status) {
 
 if (status === google.maps.GeocoderStatus.OK) {
 resultsMap.setCenter(results[0].geometry.location);

 var marker = new google.maps.Marker({
 map: resultsMap,
 position: results[0].geometry.location,
 });

 closest = findClosestN(results[0].geometry.location,10);

 // get driving distance
 closest = closest.splice(0,10);
 $('#findAddress').val(results[0].formatted_address);

 calculateDistances(results[0].geometry.location, closest,10);
 
 resultsMap.setZoom(radius);
 
 } else {
 $('#findAddress').val("No results. Please try again");
 }
 });
 }
 
 function findClosestN(pt,numberOfResults) {
 var closest = [];

 for (var i=0; i<gmarkers.length;i++) {
 gmarkers[i].distance = google.maps.geometry.spherical.computeDistanceBetween(pt,gmarkers[i].getPosition());
 
 //$('#findAddress').val("process " + i + ":" + gmarkers[i].getPosition().toUrlValue(6) + ":" + gmarkers[i].distance.toFixed(2) + "<br>");
 //gmarkers[i].setMap(null);
 closest.push(gmarkers[i]);
 }
 closest.sort(sortByDist);
 return closest;
 }

 function sortByDist(a,b) {
 return (a.distance- b.distance)
 }

 function calculateDistances(pt,closest,numberOfResults) {
 $('#outputList').html('');
 var service = new google.maps.DistanceMatrixService();
 var request = {
 origins: [pt],
 destinations: [],
 travelMode: google.maps.TravelMode.DRIVING,
 unitSystem: google.maps.UnitSystem.IMPERIAL,
 avoidHighways: false,
 avoidTolls: false
 };
 
 for (var i=0; i<closest.length; i++) request.destinations.push(closest[i].getPosition());
 service.getDistanceMatrix(request, function (response, status) {
 if (status != google.maps.DistanceMatrixStatus.OK) {
 alert('Error was: ' + status);
 } else {
 var origins = response.originAddresses;
 var destinations = response.destinationAddresses;
 
 var results = response.rows[0].elements;
 for (var i = 0; i < numberOfResults; i++) {

 $('#outputList').append('\
 <label for="dealer' + i + '" class="col-xs-8 dealerItem">\
 <input type="radio" value="' + closest[i].title + '" name="dealers" id="dealer' + i + '">\
 <span>' + closest[i].title + '</span>\
 <span class="dealerAddress">' + destinations[i] + '</span>\
 </label>\
 <div class="col-xs-4 distance">' + results[i].distance.text + '</div>');
 }
 }
 });
 }
 
 function setMarkers(map,locations) {
 
 var marker, i
 
 for (i = 0; i < locations.length; i++) { 
 
 var loan = locations[i][0],
 lat = locations[i][1],
 lng = locations[i][2],
 add = locations[i][5];
 
 latlngset = new google.maps.LatLng(lat, lng);

 var marker = new google.maps.Marker({ 
 map: map,
 title: loan ,
 position: latlngset,
 icon: './images/tp.png'
 });

 gmarkers.push(marker);
 
 //console.log(marker.getPosition());
 //map.setCenter(marker.getPosition());
 
 var content = add;
 var infowindow = new google.maps.InfoWindow();
 
 google.maps.event.addListener(marker,'click', (function(marker,content,infowindow){ 
 
 return function() {
 
 /* close the previous info-window */
 closeInfos();
 
 infowindow.setContent(content);
 infowindow.open(map,marker);
 
 /* keep the handle, in order to close it on next click event */
 infos[0]=infowindow;
 
 };

 })(marker,content,infowindow)); 
 
 }
 }
 
 function closeInfos() {
 
 if(infos.length > 0) {
 
 /* detach the info-window from the marker ... undocumented in the API docs */
 infos[0].set("marker", null);
 
 /* and close it */
 infos[0].close();
 
 /* blank the array */
 infos.length = 0;
 }
 }
 
 return {
 init: init
 }

})(window, google, window.DEALERS);
MAPMOD.initMap();
Posted in Google, JavaScript, jQuery, Maps | Leave a comment

trying out Gulp, node-modules for browerify, babel (to support/convert es6), & bootstrap

gulpfile.js

var gulp = require('gulp'),
    babel = require('gulp-babel'),
    browserify = require('gulp-browserify'),
    jshint = require('gulp-jshint'),
    less = require('gulp-less'),
    path = require('path'),
    gp_concat = require('gulp-concat'),
    gp_rename = require('gulp-rename'),
    gp_uglify = require('gulp-uglify'),
    gp_sourcemaps = require('gulp-sourcemaps'),
    mainBowerFiles = require('main-bower-files'),
    minifyCSS = require('gulp-minify-css');

// Initial bootstrap setup
// Copy bootstrap from bower-components to public/lib
gulp.task('bower', function() {
    return gulp.src(mainBowerFiles(), {
            base: 'bower_components'
        })
        .pipe(gulp.dest('public/lib'));
});
// overwrite variables.less with our own edited version
gulp.task('bootstrap:prepareLess', ['bower'], function() {
    return gulp.src('public/lib/styles/less/variables.less')
        .pipe(gulp.dest('public/lib/bootstrap/less'));
});
// compile bootstrap less to css
gulp.task('bootstrap:compileLess', ['bootstrap:prepareLess'], function() {
    return gulp.src(['bower_components/bootstrap/less/bootstrap.less'])
    //return gulp.src('public/lib/bootstrap/less/bootstrap.less')
        .pipe(less())
        .pipe(gp_rename('bootstrap.css'))
        .pipe(gulp.dest('public/lib/styles/css'));
});
// End bootstrap setup

// concatenate css files altogether and minify
gulp.task('minifyCSS', function(){
    return gulp.src(['public/lib/styles/css/*.css'])
        .pipe(gp_concat('all.css'))
        .pipe(minifyCSS())
        .pipe(gp_rename('styles.min.css'))
        .pipe(gulp.dest('public/lib/styles/dist'));
});


// Lint/jshint JS
gulp.task('lint', function() {
    return gulp.src('public/lib/js/main.js')
        .pipe(jshint({'esnext': true}))
        .pipe(jshint.reporter('default'));
});


// Concatenate & Minify JS
gulp.task('scripts', function() {
    return gulp.src(['public/lib/js/main.js', 'pubilc/lib/bootstrap/dist/js/bootstrap.js'])
        .pipe(browserify({
            insertGlobals : true,
            debug : false
        }))
        .pipe(babel({compact: false}))
        .pipe(gp_concat('all.js'))
        .pipe(gp_rename('bundle.min.js'))
        .pipe(gp_uglify({ mangle: false }))
        .pipe(gulp.dest('public/lib/js/dist'));
});


// Just convert ES6
var paths = {
    es6: ['es6/myapp.js'],
    es5: 'es5',
    // Must be absolute or relative to source map
    sourceRoot: ('es6'),
};
gulp.task('babel', function () {
    return gulp.src(paths.es6)
        .pipe(gp_sourcemaps.init())
        .pipe(babel({compact: false}))
        .pipe(gp_sourcemaps.write('.', { sourceRoot: paths.sourceRoot }))
        .pipe(gp_rename('bundle.min.js'))
        .pipe(gulp.dest(paths.es5));
});


// start watch CSS & JS files for changes
gulp.task('watch', function() {
    gulp.watch(['public/lib/styles/**/*.*', 'public/lib/js/*.js'], ['lint', 'scripts', 'minifyCSS']);
});


// Default
gulp.task('default', ['lint', 'scripts', 'minifyCSS'], function(){});

Now let’s have a look at main.js using browerify’s require:

/*jshint strict:false */

let loadUnderscore = require('./loadunderscore');
loadUnderscore.logUnderscoreVersion();

let myUtils = require('./myutils');
myUtils.logDate();
myUtils.logMonth();

window.$ = window.jQuery = require('jquery');
require('jquery-ui');

// ES6 experiments, these ARE converted
var getName = () => "Hetal";

$(function(){
	$('#main').text('rewritten 10');
	console.log( $().jquery );
	/*alert('changed!');*/
	
	$( "#draggable" ).draggable();
});

// ES6 experiments, these are not converted/supported
/*
let developer = 'Alex';
console.log('Developer: ${developer}!');

let book = {
	author: 'John',
    title: 'Some Fancy Title'
};

$('#main').append('If you like ${author.name}, then read the new book, ${book.title}');
*/
Posted in Bootstrap, Build tools: Grunt, Gulp, JavaScript, Node | Leave a comment

OOP vs Functional Programming

Short story, add reviewing this to my before interviews list:
https://en.wikipedia.org/wiki/Comparison_of_programming_paradigms

Posted in Interview Questions | Leave a comment

Reverse Linked List JavaScript

Reverse a Linked List in Javascript.
Requires Underscore.js
also here:
http://jsfiddle.net/afrascona/fuhmhqf3/

Array.prototype.getLinkedList = function () {
    var i,
        head;    
    for (i = this.length - 1; i >= 0; i -= 1) {
        head = {
            value: this[i],
            next: head
        };
    }
    return head;
};

function reverseList (head) {
    var current = head,
        tempHead,
        previous;
    while ('object' === typeof current) {
        tempHead = current.next;
        current.next = previous;
        previous = _.clone(current);
        current = _.clone(tempHead);
    }
    return previous;
}

var list = [0,1,2,3,4,5,6,7,8,9].getLinkedList();

console.dir(list);
console.dir(reverseList(list));
Posted in Algorithms, Interview Questions, JavaScript | Leave a comment

MxN Matrix 0 element makes row & column 0s

var matrix = [
	[ 2, 3, 1, 4, 5 ],
	[ 4, 6, 0, 9, 8 ],
	[ 3, 2, 1, 8, 2 ],
	[ 6, 3, 4, 7, 6 ],
	[ 8, 5, 7, 2, 1 ]
	],
	saveRows = [],
	saveColumns = [],
	i,
	j;

var onceRowLength = matrix.length;
var onceColumnLength = matrix[0].length;

function displayMatrix(matrix) {
	for ( i = 0; i < onceRowLength; i++ ) {
		for ( j = 0; j < onceColumnLength; j++ ) {
			document.writeln(matrix[i][j]);
		}
		document.writeln('<br />');
	}
}

function saveRowsAndColumns(matrix) {
	for ( i = 0; i < onceRowLength; i++ ) {
		for ( j = 0; j < onceColumnLength; j++ ) {
			if ( matrix[i][j] == 0) {
				saveRows[i] = true;
				saveColumns[j] = true;
			}
		}
	}
}

function zeroTheMatrix(matrix) {
	for ( i = 0; i < onceRowLength; i++) {
		for ( j = 0; j < onceColumnLength; j++ ) {
			if ( saveRows[i] || saveColumns[j] ) {
				matrix[i][j] = 0;
			}
		}
	}
}

displayMatrix(matrix);
saveRowsAndColumns(matrix);
zeroTheMatrix(matrix);
document.writeln('<br />');
displayMatrix(matrix);
Posted in Algorithms, Interview Questions, JavaScript | Leave a comment

String of all unique characters?

function isUnique(str){

	//more than 256 chars means at least one is not unique assuming ASCII
	if( str.length>256 ) { return false; } 

	    //array for which chars have been used
	    var char_set = [];
	    var i;

	    //iterate over the string
	    for( i = 0; i < str.length; i++ ) {

	        val = str[i];

	        //if this has been set to true this char is not unique
	        if( char_set[val] ) {
	            return false;
	        }

	        //record this char
	        char_set[val] = true;
	    } 

	//string is unique
	return true;
}
document.writeln(isUnique('abcd'));
document.writeln(isUnique('abcdd'));
Posted in Algorithms, Interview Questions | Leave a comment

Interview Fisher-Yates Shuffle in-place algorithm JavaScript

function shuffle(arrayToShuffle) {
  var arrayLengthCountdown = 	arrayToShuffle.length,
  								lastElementVal,
  								randomIndex;

  while (arrayLengthCountdown) {

    // Pick a random element from the shortening 'length' of the array, the 'front'
    randomIndex = Math.floor(Math.random() * arrayLengthCountdown--);

    console.log('randomIndex: ' + randomIndex + ' arrayLengthCountdown: ' + arrayLengthCountdown + '; swapping ' + arrayToShuffle[randomIndex] + ' with ' + arrayToShuffle[arrayLengthCountdown]);

    // And swap it with the last element of the shortening 'length', taken from the 'back' of the array, which gets injected into the 'front' to await getting shuffled
    lastElementVal = arrayToShuffle[arrayLengthCountdown];
    arrayToShuffle[arrayLengthCountdown] = arrayToShuffle[randomIndex];
    arrayToShuffle[randomIndex] = lastElementVal;

    console.log( arrayToShuffle );
  }

  return arrayToShuffle;
};
shuffle([0,1,2,3,4,5,6,7,8,9]);
Posted in Algorithms, Interview Questions, JavaScript | Leave a comment

Eureka Call Library Oracle RightNow get article count per category

/**
* Description: Get all categories, display in a list with number of articles in each, alphabetical listing of category level 3
* Date: March 2013
* Classes: GetAllCategories, Generator, Category, CategoryDepot
* Brief Technical:
* Page calls CallLibraryCatList widget
* widget view instantiates GetAllCategories Class, which uses Prodcat model to retrieve categories object
* GetAllCategories Class in turn activates Generator Class
* Generator Class utilizes Category & Category Depot Classes, converting the categories object into instantiated individual category objects that can leverage each other, and then be displayed
*/
class GetAllCategories{
	public $CI;
	public $catListObject;
	public $currentTier = -1;
	public $tier3 = array();
	public $lastLevel = -1;
	public $newLevel = -1;
	public $categoryDepot;

	function __construct() {
		$this->CI =& get_instance();
		$this->CI->load->model('standard/Prodcat_model');
		$this->catListObject = $this->CI->Prodcat_model->getHierPopup(14);
		$this->categoryDepot = new Generator;
		$this->iterateConvert();
	}

	// loops through the returned categories, and uses Generator Class to organize as Category Objects
	function iterateConvert() {
		for( $i=0; $i < count($this->catListObject); $i++ ) {
			if($this->catListObject[$i]['hier_list'] == 588)
			{
				$this->newLevel = $this->catListObject[$i]['level'];

				if ( $this->newLevel < 3 && $this->lastLevel == 3 ) {
					// sort tier 3 alphabetically, then add to collection
					foreach ($this->tier3 as $key => $row) {
						$title[$key] = $row[0];
						$href[$key] = $row['href_list'];
						$level[$key] = $row['level'];
					}
					array_multisort($title, SORT_ASC, $href, SORT_ASC, $level, SORT_ASC, $this->tier3);
					foreach($this->tier3 as $key => $catObject) {
						// create and add tiers 1 & 2 to collection
						$this->categoryDepot->generateCategory($catObject);
					}
					unset($this->tier3);
				}
				if($this->newLevel != 3) {
					// create and add tiers 1 & 2 to collection
					$this->categoryDepot->generateCategory($this->catListObject[$i]);
				}
				if($this->newLevel == 3) {
					// collect tier 3 items
					$this->tier3[] = $this->catListObject[$i];
				}

				$this->lastLevel = $this->newLevel;
				}
			}

			$this->categoryDepot->renderCollection();
		}
	}

class Generator{
	public $categoryDepot;
	public $CI;

	function __construct() {
		$this->categoryDepot = new CategoryDepot;
		$this->CI =& get_instance();
		$this->CI->load->model('custom/AnswersInCategoriesCounter_model');
	}

	function generateCategory($catSent) {
		$category = new Category;
		$category->setTier($catSent['level']);
		$category->setTitle($catSent[0]);
		$categoryArray = $category->setCategories($catSent['hier_list']);
		$finalCategory = $category->getFinalCategory();
		$articleCount = $this->CI->AnswersInCategoriesCounter_model->getCountOfAnswersByCat($finalCategory);
		if($finalCategory != 588 || 0 || null) {
			$this->categoryDepot->addToCollection($category);
		}
		foreach($categoryArray as $key => $categoryId) {
			$this->categoryDepot->updateCategoryArticleCounts($categoryId, $articleCount);
		}
	}	

	function renderCollection() {
		return $this->categoryDepot->getCollection();
	}
}

/**
* $catListObject[$i]['level'] / 0-3
* $catListObject[$i]['hier_list'] / Categories
* $catListObject[$i][0]
*/
class Category {
	public $tier;
	public $categoriesList;
	public $categoryArray;
	public $finalCategory;
	public $title;
	public $parentCategory;
	public $articleCount;
	public $articleTotal;

	function __construct() {
		//echo "Category instantiated";
	}

	function setTier($input) {
		$this->tier = $input;
	}
	
	function setCategories($input) {
		$this->categoriesList = $input;
		$this->setCategoryArray();
		$this->setParentCategory();
		$this->setFinalCategory();
		return $this->categoryArray;
	}

	function setCategoryArray() {
		$this->categoryArray = explode(',',$this->categoriesList);
	}

	function setParentCategory() {
		$itemLevel = $this->tier - 1;
		$this->parentCategory = $this->categoryArray[$itemLevel];
	}

	function setFinalCategory() {
		$this->finalCategory = $this->categoryArray[$this->tier];
	}

	function setTitle($input) {
		$this->title = $input;
	}

	function setArticleCount($input) {
		$newSet = array_unique(array_merge((array)$this->articleCount,(array)$input));
		$this->articleCount = $newSet;
		$this->setArticleTotal();
	}

	function getFinalCategory() { return $this->finalCategory; }
	
	function setArticleTotal() {
		$this->articleTotal = count($this->articleCount);
		return $this->articleTotal;
	}
}

// archives Category Objects, updates each Class's article count, and returns/displays the Collection
class CategoryDepot {
	public $collection;
	public $baseURL = '/app/list_call_library_no_search/r_id/108720/p/646/c/';
	public $currentTier = -1;

	function __construct() {
	}

	function addToCollection($input) {
		$this->collection[] = $input;
	}

	function getCollection() {
		foreach($this->collection as $category) {
			// if articleCount is 0, don't even show count
			if($category->articleTotal != 0){ $articleCount = " (" . $category->articleTotal . ")"; }else{ $articleCount = ''; }

			if($category->tier > $currentTier) {
				$currentTier = $category->tier;
				echo "<ul><li><a href='" . $this->baseURL . $category->categoriesList . "' class='noIntercept'>" . $category->title . $articleCount . "</a>";
			} elseif( $category->tier == $currentTier ) {
				echo "</li><li class='level_" . $category->tier . "'><a href='" . $this->baseURL . $category->categoriesList . "'>" . $category->title . $articleCount . "</a>";
			} elseif($category->tier < $currentTier) {
				$numberToClose = ($currentTier - $category->tier);
				$currentTier = $tier;
				switch ( $numberToClose ) {
					case 1:
						echo "</li></ul></li></ul><ul><li><a href='" . $this->baseURL . $categoriesList . "' class='noIntercept'>" . $category->title . $articleCount . "</a>";
					break;
					case 2:
						echo "</li></ul></li></ul></li></ul><ul><li><a href='" . $this->baseURL . $categoriesList . "' class='noIntercept'>" . $category->title . $articleCount . "</a>";
					break;
				}
			}
		}
	}

	// accepts a finalCategory int and the amount to increment that object's article count
	function updateCategoryArticleCounts($categoryId, $articleCount) {
		foreach ( $this->collection as $category ) {
			if ( $categoryId == $category->finalCategory ) {
				$category->setArticleCount($articleCount);
				break;
			}
		}
	}
}
Posted in Codeigniter, Oracle RightNow CX Technologies, PHP, Uncategorized | Leave a comment

Git frequently used

// reset local branch to origin’s state

git checkout {branch}

git reset –hard origin/{branch}

// checkout new branch from origin

git checkout –track origin/{branch}

// merge

git merge {{branch}}

// stash when you need to keep changes but aren’t ready to commit them, say to switch branches or pull new work from team members into your unfinished state

git stash

git stash list

git stash apply {stashName}

// get git remote url

git config –get remote.origin.url
or
git remote show origin


// create a local branch and switch to it

git checkout -b {name the new branch}

edit, add, commit, push

git push -u origin {new branch name}

// invalidate user so to force password reset

git config –global credential.helper store

// remove already added files/folder from git and add to ignore 

git rm -r –cached file-path

// did hard reset, clean, need it back!? It hasn’t been garbage collected yet, pfew

$ git reflog
1a75c1d… [email protected]{0}: reset –hard HEAD^: updating HEAD
f6e5064… [email protected]{1}: commit: added file2

$ git reset –hard f6e5064
HEAD is now at f6e5064… added file2

// commit everything including untracked

git commit -A

// delete folder from repo

git rm -r folder-name

// output all branches

git branch -a

// delete local branch

git branch branch-name -D

// delete remote branch, just add -r for remote flag

git branch -dr branch-name

// configure git global difftool & mergetool

git config –global diff.tool bc3
git config –global merge.tool bc3
git config –global mergetool.bc3.trustExitCode true

// remove folder from git but don’t delete it

git rm -r –cached myFolder

GIT_TRACE=1 GIT_SSH_COMMAND=”ssh -vvv” git push

Posted in Git, Uncategorized | Leave a comment

Interview JavaScript Module Pattern Singleton

var accountObj = (function() {
     var balance = 0;
     var type = 'savings';
     return {
          get_balance: function(){
               return balance;
          },
          deposit: function(a){
               balance += a;
          },
     };
}());

var myAccount = accountObj;
document.writeln('Balance: ' + myAccount.get_balance()); // 0
document.writeln('Add 5: ' + myAccount.deposit(5)); // undefined
document.writeln('Balance: ' + myAccount.get_balance()); // 5
Posted in Interview Questions, JavaScript | Leave a comment

Interview JavaScript private methods with closures for multiple objects exercise (not Module Singleton pattern!)

JavaScript private methods with closures

var accountObj = function() {
     var privateBalance = 0;
     function privateDeposit(val) { privateBalance += val; }
     return {
          deposit: function(n) { privateDeposit(n); },
          balance: function() { return privateBalance; }
     }
};

var myAccount = accountObj();
var yourAccount = accountObj();

myAccount.deposit(10);
console.log('My account balance: ' + myAccount.balance()); //10

yourAccount.deposit(200);
console.log('Your account balance: ' + yourAccount.balance()); //200

myAccount.deposit(5);
console.log('Added 5, balance updated: ' + myAccount.balance()); //15

console.log(myAccount.privateBalance); // undefined

source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures

Another example:

var animal = function (spec) {
     var privateName = spec.name;
     var privateSaying = spec.saying;
     var privateReturnName = function(){
          return privateName;
     };
     var privateReturnSaying = function(){
          return privateSaying;
     }
     return {
          get_name: function(){
               return privateReturnName();
          },
          get_saying: function(){
               return privateReturnSaying();
          }
     }
};
var myHorse = animal({name: 'Wilbur', saying: 'Neeeeeeh'});
var myPig = animal({name: 'Charlotte', saying: 'Oink!'});
document.writeln(myHorse.get_name() + ' says ' + myHorse.get_saying()); <span style="color: #ff0000;">// Wilbur says Neeeeeeeh
document.writeln(myPig.get_name() + ' says ' + myPig.get_saying());

document.writeln(myPig.privateSaying); // undefined

Posted in Interview Questions, JavaScript | Leave a comment

JavaScript Factorial with Memoization

var memoizer = function (memo, formula) {
     var recur = function(n) {
          var result = memo[n];
          if(typeof result !== 'number') {
               result = formula(recur, n);
               memo[n] = result;
          }
          return result;
     };
     return recur;
};
 
var factorial = memoizer([1,1], function (recur, n) {
     return n * recur(n - 1);
});
 
document.writeln(factorial(10)); // 3628800

credit: Crockford, Douglas. JavaScript: The Good Parts, p.45. O’Reilly 2008

Posted in Algorithms, Interview Questions, JavaScript | Leave a comment

JavaScript Fibonacci with & without Memoization

// simple Fibonacci w/o Memoization

var fibonacci = function(n){
     return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};
var showF = function(n){
     for(var i = 0; i <= n; i += 1) {
          document.writeln('//' + i + ': ' + fibonacci(i));
     }
};

showF(10); //55

 

//Fibonacci with Memoization

var fibonacci = (function() {
     var memo = {};

     function f(n) {
          var value;
          if (n in memo) {
               value = memo[n];
          } else {
               if (n === 0 || n === 1)
               value = n;
          } else {
               value = f(n - 1) + f(n - 2);
               memo[n] = value;
          }
          return value;
     }
     return f;
})();

document.writeln(fibonacci(50));

 

// Fibonacci with Memoizer abstracted function

var memoizer = function (memo, formula) {
     var recur = function(n) {
          var result = memo[n];
          if(typeof result !== 'number') {
               result = formula(recur, n);
               memo[n] = result;
          }
     return result;
     };
     return recur;
};

var fibonacci2 = memoizer([0,1], function (recur, n) {
     return recur(n - 1) + recur(n - 2);
});

document.writeln(fibonacci2(50)); <span style="color: #ff0000;">//12586269025</span>

 

credit: Crockford, Douglas. JavaScript: The Good Parts, p.45. O’Reilly 2008

credit: http://www.sitepoint.com/implementing-memoization-in-javascript/

Posted in Algorithms, Interview Questions, JavaScript | Leave a comment

JavaScript Curry

// Curry

“Currying allows us to produce a new function by combining a function and an argument”

Function.prototype.method = function (name, func) { // makes Augmenting Types beautifully easy when needed
if (!this.prototype[name]) {
this.prototype[name] = func;
return this;
}
};

var add = function (a, b) {
return a + b;
};

Function.method(‘curry’, function () { // leveraging our Augmentation shortcut…
var slice = Array.prototype.slice,
args = slice.apply(arguments),
that = this;

return function () {
return that.apply(null, args.concat(slice.apply(arguments)));
};
});

var add1 = add.curry(1);
document.writeln(add1(6)); //7

 

credit:

Crockford, Douglas. JavaScript: The Good Parts, p.43. O’Reilly 2008

Posted in Interview Questions, JavaScript | Leave a comment

Foundation 5 Framework Animate Accordion (multiple, with dynamic AJAX content using reflow, and also nested)

Out of the box there is no animation on these.  I tried for a CSS3 transition but couldn’t get one. If anyone finds one do tell. Anyhow, my current project has 3 accordion levels, the main off-canvas accordion, a second one loaded dynamically via AJAX into the main content area, and third level of accordions nested in each of the 2nd level accordions.

First, I gave them each an id, so that I could address them easily and individually:

<dl class=”accordion firstLevelAccordions” data-accordion> (in the ‘off-canvas’ left)

<dl class=’accordion secondLevelAccordions’ data-accordion> (in the main content right section, content thereof loaded dynamically via AJAX)

<dl class=’accordion thirdLevelAccordions’ data-accordion> (this one nested inside the secondLevelAccordions)

After the dynamic content load, Foundation makes you reflow to find/activate the new content:

$(document).foundation(‘reflow’);

The initialization of each accordion (you could merge these into one function, or parameter-ize the class piece, but for simplicity’s sake, this works just fine):

$(function(){ // onready

// first level off-canvas menu accordions
$(document).on(“click”, “.firstLevelAccordions > dd:not(‘.active’) > a”, function (event) {
$(“.firstLevelAccordions > dd.active”).removeClass(‘active’).children(“.content”).slideUp(1000);
$(this).parent().addClass(‘active’).children(“.content”).slideToggle(1000);
})

$(document).on(“click”, “.firstLevelAccordions > dd.active > a”, function (event) {
$(“.firstLevelAccordions > dd.active”).removeClass(‘active’).children(“.content”).slideUp(1000);
$(this).parent().removeClass(‘active’);//.find(“.content”).slideToggle(“fast”);
})

// second level article list/detail accordions
$(document).on(“click”, “.secondLevelAccordions > dd:not(‘.active’) > a”, function (event) {
$(“.secondLevelAccordions > dd.active”).removeClass(‘active’).children(“.content”).slideUp(1000);
$(this).parent().addClass(‘active’).children(“.content”).slideToggle(1000);
})

$(document).on(“click”, “.secondLevelAccordions > dd.active > a”, function (event) {
$(“.secondLevelAccordions > dd.active”).removeClass(‘active’).children(“.content”).slideUp(1000);
$(this).parent().removeClass(‘active’);//.find(“.content”).slideToggle(“fast”);
})

// third level nested accordions
$(document).on(“click”, “.thirdLevelAccordions > dd:not(‘.active’) > a”, function (event) {
$(“.thirdLevelAccordions > dd.active”).removeClass(‘active’).children(“.content”).slideUp(1000);
$(this).parent().addClass(‘active’).children(“.content”).slideToggle(1000);
})

$(document).on(“click”, “.thirdLevelAccordions > dd.active > a”, function (event) {
$(“.thirdLevelAccordions > dd.active”).removeClass(‘active’).children(“.content”).slideUp(1000);
$(this).parent().removeClass(‘active’);//.find(“.content”).slideToggle(“fast”);
})

});

Posted in CSS, Foundation, Front-end Frameworks, HTML, JavaScript | Leave a comment

Angularjs switching ngview view-container animation direction – left, then right – using view-frames and keyframes and rootScope

index.html:

<div class=”view-container” id=”view-containerWrapper”>
<div class=”{{rootAnimation}}” ng-view></div>
</div>

_animate.scss:

.view-container {
/* position: relative;*/
}
/* Index loads w/o animation */
.view-frame-0.ng-enter {
background: white;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.view-frame-0.ng-leave {
background: white;
position: absolute;
top: 0;
left: 0;
right: 0;
}
/* Page 2 animated in from the right, index animates out to the left */
.view-frame-1.ng-enter {
background: white;
position: absolute;
top: 0;
left: 0;
right: 0;

-webkit-animation: 1.0s slide2;
-moz-animation: 1.0s slide2;
-o-animation: 1.0s slide2;
animation: 1.0s slide2;
z-index: 100;
}

.view-frame-1.ng-leave {
background: white;
position: absolute;
top: 0;
left: 0;
right: 0;
width:100%;

-webkit-animation: 1.0s slide0;
-moz-animation: 1.0s slide0;
-o-animation: 1.0s slide0;
animation: 1.0s slide0;
z-index: 100;
}
/* Page 2 animates out to the right, index animates back from the left */
.view-frame-2.ng-enter {
background: white;
position: absolute;
top: 0;
left: 0;
right: 0;
width:100%;

-webkit-animation: 1.0s slide3;
-moz-animation: 1.0s slide3;
-o-animation: 1.0s slide3;
animation: 1.0s slide3;
z-index: 100;
}

.view-frame-2.ng-leave {
background: white;
position: absolute;
top: 0;
left: 0;
right: 0;

-webkit-animation: 1.0s slide1;
-moz-animation: 1.0s slide1;
-o-animation: 1.0s slide1;
animation: 1.0s slide1;
z-index: 100;
}

/* Slide 0 – From active to the left */
@keyframes slide0 {
0% {
left: 0;
top: 0;
}
100% {
left: -100%;
top: 0;
}
}
@-moz-keyframes slide0 {
0% {
left: 0;
top: 0;
}
100% {
left: -100%;
top: 0;
}
}

@-webkit-keyframes slide0 {
0% {
left: 0;
top: 0;
}
100% {
left: -100%;
top: 0;
}
}

@keyframes slide0 {
0% {
left: 0;
top: 0;
}
100% {
left: -100%;
top: 0;
}
}

@-moz-keyframes slide0 {
0% {
left: 0;
top: 0;
}
100% {
left: -100%;
top: 0;
}
}

@-webkit-keyframes slide0 {
0% {
left: 0;
top: 0;
}
100% {
left: -100%;
top: 0;
}
}

/* slide 1 – from active to the right */

@keyframes slide1 {
0% {
left: 0;
top: 0;
}
100% {
left: 100%;
top: 0;
}
}
@-moz-keyframes slide1 {
0% {
left: 0;
top: 0;
}
100% {
left: 100%;
top: 0;
}
}

@-webkit-keyframes slide1 {
0% {
left: 0;
top: 0;
}
100% {
left: 100%;
top: 0;
}
}

@keyframes slide1 {
0% {
left: 0;
top: 0;
}
100% {
left: 100%;
top: 0;
}
}

@-moz-keyframes slide1 {
0% {
left: 0;
top: 0;
}
100% {
left: 100%;
top: 0;
}
}

@-webkit-keyframes slide1 {
0% {
left: 0;
top: 0;
}
100% {
left: 100%;
top: 0;
}
}

/* slide 2 – from the right to active */

@keyframes slide2 {
0% {
left: 100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}
@-moz-keyframes slide2 {
0% {
left: 100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@-webkit-keyframes slide2 {
0% {
left: 100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@keyframes slide2 {
0% {
left: 100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@-moz-keyframes slide2 {
0% {
left: 100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@-webkit-keyframes slide2 {
0% {
left: 100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

/* slide 3 – from the left to active */

@keyframes slide3 {
0% {
left: -100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}
@-moz-keyframes slide3 {
0% {
left: -100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@-webkit-keyframes slide3 {
0% {
left: -100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@keyframes slide3 {
0% {
left: -100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@-moz-keyframes slide3 {
0% {
left: -100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

@-webkit-keyframes slide3 {
0% {
left: -100%;
top: 0;
}
100% {
left: 0;
top: 0;
}
}

products.html:

<div ng-repeat-start=”prod in products” headersloaded class=”followMeBar”>
<i class=”iseFontIcons icon-{{prod.icon}}”></i>
{{ prod.Name | uppercase }}
</div>

<ul class=”nav nav-tabs nav-stacked” ng-repeat-end>
<li ng-repeat=”cat in prod.Categories” productsloaded>
<a href=” ng-click=’go(“product_{{prod.ID}}/category_{{cat.ID}}”,”view-frame-1″)’>{{cat.Name}}</a>
</li>
</ul>

finally, in the controller…that go method:

$scope.go = function(path,newAnimation) {
$rootScope.rootAnimation = newAnimation;
$location.path(path);
}

 can’t remember if this ends up mattering, if so just for the sake of it, the important wrappers from _main.scss:

#mainWrap{
position:relative;
}
.ng-view{
position:relative;
}
#headerBar{

width:100%;
}
.view-container{
width:100%;
position: relative;
}
#view-containerWrapper{
position:relative;
}
.viewsWrapper{
border-right: 1px solid #f1f1f1;
border-left: 1px solid #f1f1f1;
width:100%;
position:absolute;
}
#productsWrapper{
top:0px;
z-index:0;
}

Posted in Angular, JavaScript | Leave a comment