Category Archives: Uncategorized

Create Node based Chrome Extension

Creating a Node based Chrome Extension starter project is easy using yo’s chrome-chrome-extension generator.

To start, make sure you have yo and the generator installed.

$  npm install -g yo
$  npm install -g generator-chrome-extension

Then.

$  mkdir your-new-ext-name; cd your-new-ext-name
$  yo chrome-extension --skip-install

From chrome://extensions/

Press Load upacked extension…

Select your app.

Yup.

Still working on getting this to work with Ember-Cli.

Looks like .bowerrc, bower.json, and package.json need to be reworked.

.bowerrc

{
  "directory": "bower_components",
  "analytics": false
}

bower.json

{
  "name": "your-new-ext-name",
  "dependencies": {
    "ember": "1.11.1",
    "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
    "ember-cli-test-loader": "ember-cli-test-loader#0.1.3",
    "ember-data": "1.0.0-beta.16.1",
    "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.4",
    "ember-qunit": "0.3.1",
    "ember-qunit-notifications": "0.0.7",
    "ember-resolver": "~0.1.15",
    "jquery": "^1.11.1",
    "loader.js": "ember-cli/loader.js#3.2.0",
    "qunit": "~1.17.1"
  }
}

In package.json update the following

  "scripts": {
    "start": "ember server",
    "build": "ember build",
    "test": "ember test",
    "postinstall": "./node_modules/bower/bin/bower install"
  },
  "repository": "",
  "engines": {
    "node": ">= 0.10.0"
  },
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "bower": "^1.4.1",
    "broccoli-asset-rev": "^2.0.2",
    "ember-browserify": "^0.6.4",
    "ember-cli": "0.2.3",
    "ember-cli-app-version": "0.3.3",
    "ember-cli-babel": "^5.0.0",
    "ember-cli-content-security-policy": "^0.4.0",
    "ember-cli-dependency-checker": "0.0.8",
    "ember-cli-htmlbars": "0.7.4",
    "ember-cli-ic-ajax": "0.1.1",
    "ember-cli-inject-live-reload": "^1.3.0",
    "ember-cli-qunit": "0.3.10",
    "ember-cli-uglify": "1.0.1",
    "ember-data": "1.0.0-beta.16.1",
    "ember-export-application-global": "^1.0.2"
  }

Re-run

$ npm install

Ember.js – Image Component with backup Default Image

Because of things outside of our control as developers, images don’t always load and the design suffers. This occurs because of a connectivity issues, or when an image path is incorrect or points to a resource that is no longer available.

In the interest of graceful failure, I include a default image as a backup for images that don’t load.

components/default-img.js

import Ember from 'ember';

export default Ember.Component.extend({
    tagName: 'img',
    attributeBindings: ['src'],

    didInsertElement: function(){
        var _this = this;

        // With jQuery
        this.$().on('load', function(evt){
            return _this.imageLoaded(evt);
        }).on('error', function(evt){
            return _this.errorLoading(evt);
        });

        // Without jQuery / for Mobile
        /*
        var domRef = document.getElementById(this.get('elementId'));
        domRef.addEventListener('load', function (evt) {
            return _this.imageLoaded(evt);
        }, false);
        domRef.addEventListener("error", function (evt) {
            return _this.errorLoading(evt);
        }, false);
        */
    },

    willDestroyElement: function(){
        this.$().off('load', 'error');
    },

    imageLoaded: function(event){
        console.log("Image Loaded");
    },

    errorLoading: function(event){
        this.set('src', this.get('defaultImg'));
    }

});

Use:

Controller:

// path to the Expected image
var img = data.imgPath; 

// path to Default / backup image
// change this to match design requirements or default image path.
var defaultImg = 'http://placehold.it/190x200'; 

View:

{{default-img src=img defaultImg=defaultImg}}

Ember -> Heroku

After you’ve created a Ember-Cli app, create a Procfile, it will tell Heroku what to do when your application starts.

“Procfile is a mechanism for declaring what commands are run by your application’s dynos on the Heroku platform.”

touch Procfile

In Procfile.

web: ember serve --port $PORT --live-reload=false

In package.json make sure you have something like the following.

Note: the Ember team is depreciating Bower moving forward but Heroku is happy with it for the moment. This will install dependencies.

"scripts": {
    "start": "ember server",
    "build": "ember build",
    "test": "ember test",
    "postinstall": "./node_modules/bower/bin/bower install"
  },

Change the package.json node “devDependencies” to “dependencies” or change the Heroku config to use the Dev Dependencies with the following line.

heroku config:set NPM_CONFIG_PRODUCTION=false

If you are using external resources, in config/environment.js, do something like the following to get things running and then strip it back.

Note: use relative protocols to avoid mixed content issues.

“mixed content was loaded over HTTPS, but requested an insecure script”

Caution! This is for a TEST application that uses external javascript, fonts, images and stylesheets.

ENV.contentSecurityPolicy = {

    'default-src': "'self'",
    'script-src': "'self' http://localhost:4200 'unsafe-eval' * 'unsafe-inline' *",
    'font-src': "'self' 'unsafe-eval' * 'unsafe-inline' *",
    'connect-src': "'self'",
    'img-src': "'self' 'unsafe-eval' * 'unsafe-inline' *",
    'style-src': "'self' 'unsafe-eval' * 'unsafe-inline' *",
    'media-src': "'self'"
  }

EMBER INSTALL PROCESS

EMBER INSTALL PROCESS

# global install of ember / bower / watchman / phantomjs
npm install -g ember-cli
npm install -g bower
brew install watchman
which -a watchman
npm install -g phantomjs

# create project
ember new graceNote

# Switch to project folder
cd graceNote/
ember server 
# Cannot find module 'ember-cli/lib/broccoli/ember-app'
ls
npm install 
# Reload dependencies
ember server 
# More missing dependencies
bower install 
# Run `bower install` to install missing dependencies.
ember server 
# killed grunt server / Livereload failed on port 35729.  It is either in use or you do not have permission.
ember server 
# We're Up!

Open Chrome

Add the Ember Inspector

To include Node Modules to a project using Ember CLI, it looks like Ember-Browserify is the preferred way to add npm modules.

Ember Team – “we plan to drop bower_components entirely, likely no extra effort will be spent on this, rather that energy will go towards NPM improvements.”

npm install ember-browserify --save-dev

Observer Implementation – using defineProperties

Testing Object.defineProperties using the Observer pattern. MDN shows that defaults for configurable, enumerable and writable are false. The implementation below is explicitly setting those values to false as a reminder.

function MakeObservable(obj) {

    obj = obj || this;

    //obj._observers = [];

    Object.defineProperties (obj, {

        _observers: {
            value: [],
            configurable: false,
            enumerable: false,
            writable : false
        },

        _watch: {
            value: function (name, observer, func) {
                if (!obj._observers.hasOwnProperty(name)) {
                    obj._observers[name] = ({observer:observer, func:func});
                } else {
                    console.log('This property already exists on this object');
                }

            },
            configurable: false,
            writable : false
        },
        
        _unwatch: {
            value: function (observer) {
                var idx = obj._observers.indexOf(observer);
                if (idx > -1) {
                    obj.slice(idx, 1);
                }
            },
            configurable: false,
            writable : false
        },

        _updateWatcher: {
            value: function (observer) {
                console.log("Generic Notification from Watched Object\n - Cannot Customize");
            },
            configurable: false, 
            writable : false
        },
        
        _updateWatchers: {
            value: function (prop, value) {
                var len = obj._observers.length;
                for (var prop in obj._observers) {
                    // INTERNAL OBJECT NOTIFICATION
                    //obj._updateWatcher(obj._observers[watcher]);
                    // GET WATCHER
                    var watcher = obj._observers[prop];
                    // CALL WATCHERS CUSTOM METHOD
                    watcher.func(prop, value);
                };
            },
        },
        set: {
            value: function(prop, value) {
                obj[prop] = value;
                obj._updateWatchers(prop, value);
            }
        },
        get: {
            value: function(prop) {
                return obj[prop];
            }
        }
    });
    
    obj.set = function(prop, value) {
        obj[prop] = value;
        obj._updateWatchers(prop);

    };

    obj.get = function(prop) {
        return obj[prop];
    };

    return obj;
}

var obj = new MakeObservable();

// CREATE WATCHER
var watcher = {
    func: function(prop, value) {
        console.log("FIRST WATCHER", prop, value);
    }
};

// ADD WATCHER NAME, WATCHER AND FUNCTION TO BE CALLED ON UPDATE
obj._watch("watcher", watcher, watcher.func);

// TEST WATCHERS
obj.set('name', 'First Name');

// CREATE WATCHER
var watcher2 = { 
    func: function(prop, value) { 
        console.log("SECOND WATCHER", prop, value); 
    }
};

// ADD SECOND WATCHER NAME, WATCHER AND FUNCTION TO BE CALLED ON UPDATE
obj._watch("watcher2", watcher2, watcher2.func);

// TEST WATCHERS
obj.set('name', 'Second Name');

Javascript – Object.defineProperty – Eloquent Javascript – Chapter 6

This is the first time I’ve used Object.defineProperty. Below, I’m using it to create a property on an object. The requirement is that the property is a function that is called without parens.

It reveals some interesting things I’ve stumbled across recently. Console.log shows non enumerable properties when called on an object but those properties are not included in a for loop. Why? Because those properties have a property called enumerable that is set to false. If this property should show up in a for loop, include the following when using Object.defineProperty.

If you stumble across this blog, these are my programming notes more than a blog. If you have any comments or questions, feel free to comment.

        enumerable: true

Here’s an example of the code I wrote for the Vector assignment in Chapter 6.

function Vector(x, y) {

    // variables
    this.x = x;
    this.y = y;

    // functions
    this.powUp = function () {
        return Math.pow(this.x, 2) + Math.pow(this.y,2);
    }

    this.plus = function (obj) {
        return new Vector(this.x + obj.x, this.y + obj.y);
    };

    this.minus = function (x, y) {
        return new Vector(this.x - obj.x, this.y - obj.y);
    };

    // requires parens to call / reset value;
    //this.length = function() {
    //  return Math.sqrt(this.powUp())
    //}

    // removes the need for parens / adds code
    // extend the object 1st param
    // give it the name 'length'

    Object.defineProperty (this, 'length', {
        get: function () {
            return  Math.sqrt(this.powUp())
        }
        //set: function () {
        //  return  Math.sqrt(this.powUp())
        //}
    });

    // make it chainable
    return this;
};


// Object.defineProperty Notes:

    Object.defineProperty properties
    get: function() {}        // function to returns value
    set: function() {}        // function to set value
    value: 0,                 // current value
    enumerable: true,         // shows up in for loop
    configurable: true,       // prop can be changed / deleted
    writable: false           // can be modified

    // Can be expressed as an object
    /*
    Object.defineProperties (this, { 
        prop1: { get: function() {}, set: function() {} },
        prop2: { get: function() {}, set: function() {} }
    });
    */

Chrome Developer Tips and Tricks

We’ve all spent time solving problems that have been addressed in new releases of languages or tools. I just found the following and am surprised by the toolset available for troubleshooting in Chrome. If you find yourself troubleshooting Javascript, take a look at Tips and Tricks for Chrome Devtools before solving a problem that no longer exists. The following examples are taken from the Google Devtools page.

Grouping Console Log Items

Console will nest a series of responses that are preceded by console.group() and terminated by console.groupEnd();

Example:

console.group("Authentication phase");
console.log("Authenticating user '%s'", user);
// authentication code here...
if (!authenticated) {
    console.log("User '%s' not authenticated.", user)
}
console.groupEnd();

Table Formatting for Objects and Arrays

Console can output objects and arrays as a table with the headers the property names or array index.

console.table([{a:1, b:2, c:3}, {a:"foo", b:false, c:undefined}]);

Dir displays non-enumerable and hierarchical information. Exceptionally helpful for checking html elements.

console.dir(document.body.getElementsByTagName('a');

Track the Time it takes for a process to complete

console.time("Array initialize");
    var array= new Array(1000000);
    for (var i = array.length - 1; i >= 0; i--) {
        array[i] = new Object();
    };
console.timeEnd("Array initialize");

Image Aspect Ratio – CSS Object Fit / object-fit

Hell Yes!

Displaying images in a container div while respecting aspect ratio has always felt cumbersome. But, it looks like all of the past solutions are now giving way to object-fit. I’d seen this tag in the but the lack of cross browser support made it unusable prior to the addition of support by Firefox 36 and Safari 8 (and the announcement that IE is being discontinued).

A quick intro.

Note *object-fit requires that the img tag or containing element be given a width and height.

object-fit values.

fill : stretches the image to the requested height / width.

contain : retains aspect ratio using max width or height to calculate the ratio for the other side.

cover : fills the box using max width or height, allowing overflow.

scale-down : uses none or contain defaulting to which ever displays the image first.

none : if the original image fits, it is displayed

Example CSS:

img {
    width: 300px;
    height: 300px;
    object-fit: contain;
}

Example on CodePen

Again, object-fit is not supported by IE, but a polyfill is available and IE is on it’s way out.

Read MDN Object fit for more concise info.

And check caniuse.com for up to date browser support.

Console Log – Javascript Preformance in Chrome

Updated and Adjusted to accept optional arguments and track time or memory use as an indicator of performance.

If you are measuring Memory used please launch Chrome from Terminal.

By default, Chrome quantizes/rounds memory use making it inaccurate.

Run the following command from terminal to launch Chrome and prevent quantizing.

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --enable-precise-memory-info
// performanceType should be a string 'time' or 'memory'
// Optional Arguments (performanceType, divisor, precision, suffix)
var performanceCheck = function () {

  
  // Can't wait for defaults ES2015
  var divisor = 1;
  var precision = false;
  var suffix = (arguments[0] === 'memory') ? ' bytes' : ' ms';

  if (arguments.length > 1) {
    divisor = arguments[1];
  }
  
  if (arguments.length > 2) {
    precision = arguments[2];
  }

  if (arguments.length > 3) {
    suffix = arguments[3] || suffix;
  }

  var start;
  var func = (arguments[0] === 'memory') ? getMemoryUsed : getTime;
  var end;

  start = func();

  function getMemoryUsed() {
    return console.memory.usedJSHeapSize;
  }

  function getTime() {
    return Date.now();
  }

  function convertToUnits(num) {
    if (precision) return (num / divisor).toPrecision(precision);
    return (num / divisor);
  }

  function formatMsg(prefix, usage, suffix) {
    console.log(prefix + usage + suffix);
  }

  return function () {

    var total;
    
    end = func();
    
    total = end - start;

    formatMsg('Initial: ', convertToUnits(start), suffix); 
    formatMsg('Current: ', convertToUnits(end), suffix);
    formatMsg('Use: ', convertToUnits(total), suffix);

  }
}

// USAGE

// Set Initial Use Memory or Time
var check = performanceCheck('time');

// A javascript operation
var doJavascriptThings = [];
for (var i = 1000 - 1; i >= 0; i--) {
  doJavascriptThings[i] = [{'random':'values'}];
};

// Check again after process is complete
check();