Javascript

Overriding Backbone.sync for local use

If you’re using Backbone to develop the front end in a local application you’ll have to override the Backbone.sync functionality to replace the REST functionality normally used by the library. Using Backbone in a local environment to store data, whether to store data in a file on the hard drive or using a local DB, is a bit different from its normal usage. The REST functionality has to be replaced with a file write or some other data storage code. The code below works for me:

Backbone.sync = function(method, model, options) {
    if (method === "create"){
        let attrs = model.changed;
        if(Object.keys(attrs).length>0){
            console.log("Update a record.");
        }else{
            console.log("Create a record.");
        }
    }
    if(method === "read"){
        if(model.length === 0){
            console.log("Pull the entire collection of records.");
        }else{
            console.log("Pull a single record.");
        }
    }
    if(method === "delete"){
        console.log("Delete this record and return nothing.");
    }
    if(method === "update"){
        console.log("This update functionality never runs.");
    }
};
Advertisements
Standard
Browser Extension, Firefox, Javascript, Useful-New-Tab-Page

Firefox Useful New Tab Page Now in the Public Index at the Mozilla AMO

Firefox Useful New Tab Page

Firefox Useful New Tab Page

Firefox Useful New Tab Page addon is out of experimental hosting at Mozilla now and is available here; https://addons.mozilla.org/en-US/firefox/addon/useful-new-tab-page/

I also placed the source code for it on Github here: https://github.com/timtocci/Firefox-Useful-New-Tab-Page in case anyone wants to check out the source code.

Standard
Apache, FlightPHP, Javascript, PHP

Setting up FlightPHP to work with Backbonejs

FlightPHP and Backbonejs work well together inherently by design. Even though the two frameworks are written in two different languages and are designed for different tiers in your enterprise application development design, its hard to ignore the ease of integrating the two.. Most Backbone examples you see posted on the Internet involves node.js on the server; which makes sense considering you program both in javascript. However, the most common (and cheapest) hosting on the Internet is shared host PHP hosting. As long as your load is relatively light you can get really great results out of a shared PHP host as the new PHP runs virtually as fast as C++ on the server (takes about 2x the RAM though).

http://flightphp.com/learn
http://backbonejs.org/

How Backbone works with FlightPHP

Backbone is a REST-centric library. Basically what that means is that you have to set up four endpoints in your FlightPHP index file for every collection of models in your application. With Backbone, you will not be setting up AJAX calls – the library handles all of the traffic cop stuff for you automatically. Using a Backbone model: a save uses a POST if the model does not have an id set on it from a previous save, and uses a PUT to update the record if it does have an id; a get without and id in the path returns the array of JSON objects (used by Backbone.Collection), including an id in the path returns that record; and a model.destroy uses a DELETE verb to indicate a record delete.

Your CRUD functions will map to the GET, POST, PUT, and DELETE HTTP verbs on your server.

/* basic PHP pseudocode structure for handling backbone CRUD functionality */
// Create
Flight::route('POST /rest/somecollectionname', function($id){
    // posting a new record (saving the model)
        // return the object saved with new id created by db
});
// Read
Flight::route('GET /rest/somecollectionname(/@id)', function($id){
    // getting a collection or a single record if id was provided
        // return an array of javascript objects or a single
        // object if an id was provided
});
// Update
Flight::route('PUT /rest/somecollectionname/@id', function($id){
    // updating a record (saving a model with an id)
        // return updated object
});
// Delete
Flight::route('DELETE /rest/somecollectionname/@id', function($id){
    // deleting a record (destroying a model)
});

Flight also allows you to map these endpoints to a separate class which is probably the best way to go if you are working on an API that’s larger than a couple of endpoints.

Apache issues – something Node users never have to deal with

On some shared hosts PUT and DELETE requests are blocked by default. You’ll get a 403 Denied error on the first PUT or DELETE attempt if these HTTP verbs are blocked. Its, unfortunately, a fact of life that has to be dealt with. Apache allows PUT and DELETE by default, so its probably the way they have their virtual hosts configuration set (usually because of security issues). You can sometimes (probably) get away with a .htaccess directive to overcome this shortfall. Other than that I recommend you contact whatever host you have for a solution.

# try this in .htaccess
# https://gist.github.com/umidjons/9107445
<Limit GET POST PUT DELETE>
order deny,allow
allow from all
</Limit>

Even if your shared host vehemently denies you access to these verbs, a workaround is relatively easy to script. For instance: add an updateid to your model to indicate an update and handle it as a new record on the client, etc. It shouldn’t come down to that though (a paying customer is a paying customer).

If you are running your own server you should open “/etc/httpd/conf/httpd.conf” as root and look for something that looks like:

<Directory /home/*>
AllowOverride All
Options -MultiViews -Indexes FollowSymlinks IncludesNoExec +Includes
<Limit GET POST OPTIONS PROPFIND>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST OPTIONS PROPFIND>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>

Anywhere you see “GET POST” just add put and delete : “GET POST PUT DELETE”. Then restart httpd server with “/sbin/service httpd restart” and they should work. Also, here is a link to a good how-to for Apache in case you get confused: https://www3.ntu.edu.sg/home/ehchua/programming/howto/Apache_HowToConfigure.html
Apache Docs
http://httpd.apache.org/docs/current/

In many cases you might not even need those two verbs. Many people use Backbonejs to display and sort data on the client without ever needing to use PUT or DELETE.

Standard
Google Chrome, Javascript, NodeJS, Opera

Video – Memory Management Masterclass with Addy Osmani

Really good video on managing memory using Google Chrome Dev Tools.
From YouTube:Published on Sep 2, 2014

Addy is a senior engineer on the Chrome web engineering team, focusing on tools to help improve developer productivity and satisfaction. He works on Polymer – a Web Component library, is the the lead engineer on Yeoman and Web Starter Kit and regularly writes about web application architecture and the front-end. Outside of Google, Addy enjoys both hacking on open-source projects like TodoMVC and Grunt-UnCSS. He has authored books on JavaScript design patterns and frameworks.

Efficient JavaScript webapps need to be fluid and fast. Any app with significant user interaction needs to consider how to effectively keep memory usage down because if too much is consumed, a page might be killed, forcing the user to reload it and cry in a corner. Automatic garbage collection isn’t a substitute for effective memory management, especially in large, long-running web apps. In this talk we’ll walk through how to master the Chrome DevTools for effective memory management. Learn how to tackle performance issues like memory leaks, frequent garbage collection pauses, and overall memory bloat that can really drag you down.


Standard
AIR, Javascript, Prattsville N.Y., Windows

Adobe AIR Application – Prattsville NY Creek Gauge (Alpha release – Windows only)

Simple System Tray Icon application that keeps a small meter that displays the water level of the Schoharie Creek in Prattsville N.Y. within sight on the Windows desktop

This is a useless application to anyone other than people who live in Prattsville N.Y. and the surrounding area. It utilizes the data received from the unmanned experimental sensor located in Prattsville (the gage house is on the side of the creek down by the bridge). There is no Mac functionality at this time for this application (maybe later on). The code is less than elegant at this point. However, there is a view source context menu item if you would like to view the code anyway (Mac users unzip the installer).
I wrote this application for myself to keep an eye on the creek water level in my neighborhood – sorry if its not perfect at this point.

  • Downloads water level datum and default hydrograph every 30 minutes (And caches them on the system in case of disconnection).
  • Click on the icon to download and display the most recent NOAA hydrograph in the lower right corner of the viewport
    (click on it again to make it go away)

  • Icon displayed changes to reflect changes in the water level.
  • Added context menu items that open various pages related to Prattsville N.Y. in the default browser

Download Prattsville NY Creek Gauge
(Requires Adobe AIR)

				  File: PrattsvilleCreek.air
				CRC-32: 4d057fdb
				   MD4: 0f5aa9605d292368cb546fc55ef8d81c
				   MD5: f53dbe407bfc5b477c84a7d9f66d0071
				 SHA-1: fdf93f2f2af533d8e80c84ad1a7621a7269279c5
                

Standard
Browser Extension, Google Chrome, Javascript, Look-It-Up, Opera

Google Chrome and Opera Extension – Look-it-up, a Dictionary Context Menu Extension

Adds context menu item that looks up selected text on dictionary sites. You have the choice of dictionary.com, merriam-webster.com (dictionary and thesaurus), thefreedictionary.com, thesaurus.com, urbandictionary.com, wikipedia.org, wiktionary.org, and yourdictionary.com to look selected terms up with. There is an options page to enable or disable the different menu items included. This is actually a rewrite and improvement of an older version that looked up terms on dictionary.com exclusively. While using the old version, I eventually found myself in need of more options for this add-on so here it is.
 

manifest.json


{
  "name": "Look-it-up",
  "description": "Adds context menu item that looks up selected text on dictionary sites",
  "version": "0.2",
  "permissions": ["contextMenus"],
  "background": {
    "scripts": ["app.js"]
  },
  "options_page": "options.html",
  "icons" : {
        "16" : "book16.png",
        "32" : "book32.png",
        "48" : "book48.png",
        "128" : "book128.png"
    },
  "manifest_version": 2
}

app.js


/** app.js */
var defaultentries = [
	{
	"menu":"dictionary.com",
	"active":1
	},{
	"menu":"merriam-webster.com-dict",
	"active":1
	},{
	"menu":"merriam-webster.com-thes",
	"active":1
	},{
	"menu":"thefreedictionary.com",
	"active":1
	},{
	"menu":"thesaurus.com",
	"active":1
	},{
	"menu":"urbandictionary.com",
	"active":1
	},{
	"menu":"wikipedia.org",
	"active":1
	},{
	"menu":"wiktionary.org",
	"active":1
	},{
	"menu":"yourdictionary.com",
	"active":1
	},
];
var entries = {};
if (!localStorage.getItem("entries")) {
	localStorage.setItem("entries", JSON.stringify(defaultentries));
}
entries = JSON.parse(localStorage.getItem("entries"));
function isActive(menu){
	console.log("isActive");
	var elen = entries.length;
	console.assert(!elen == 0);
	for(i=0;i<elen;i++){
		if(entries[i]["menu"] == menu){
			console.log(entries[i]["menu"]);
			if(entries[i]["active"] == 1){
				return true;
			}else{
				return false;
			}
		}
	}
}
function setActive(menu){
	console.log("setActive");
	var elen = entries.length;
	console.log(menu);
	console.assert(!elen == 0);
	for(i=0;i<elen;i++){
		if(entries[i]["menu"] == menu){
			entries[i]["active"] = 1;
		}
	}
	localStorage.setItem("entries", JSON.stringify(entries));
}
function setInactive(menu){
	console.log("setInactive");
	var elen = entries.length;
	console.log(menu);
	console.assert(!elen == 0);
	for(i=0;i<elen;i++){
		if(entries[i]["menu"] == menu){
			entries[i]["active"] = 0;
		}
	}
	localStorage.setItem("entries", JSON.stringify(entries));
}
/* Create the context menu */
var tm = chrome.contextMenus.create({"title": "Look-it-up", "contexts":["selection"]});
if(isActive("dictionary.com")){
	chrome.contextMenus.create({"title": "dictionary.com", "contexts":["selection"], "parentId": tm, "onclick": lookItUp1});
}
function lookItUp1(i, t){
	var createProperties = {url: "http://www.dictionary.com/cgi-bin/dict.pl?term=" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("merriam-webster.com-dict")){
	chrome.contextMenus.create({"title": "merriam-webster.com-dict", "contexts":["selection"], "parentId": tm, "onclick": lookItUp2});
}
function lookItUp2(i, t){
	var createProperties = {url: "http://www.merriam-webster.com/dictionary/" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("merriam-webster.com-thes")){
	chrome.contextMenus.create({"title": "merriam-webster.com-thes", "contexts":["selection"], "parentId": tm, "onclick": lookItUp3});
}
function lookItUp3(i, t){
	var createProperties = {url: "http://www.merriam-webster.com/thesaurus/" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("thefreedictionary.com")){
	chrome.contextMenus.create({"title": "thefreedictionary.com", "contexts":["selection"], "parentId": tm, "onclick": lookItUp4});
}
function lookItUp4(i, t){
	var createProperties = {url: "http://www.thefreedictionary.com/" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("thesaurus.com")){
	chrome.contextMenus.create({"title": "thesaurus.com", "contexts":["selection"], "parentId": tm, "onclick": lookItUp5});
}
function lookItUp5(i, t){
	var createProperties = {url: "http://thesaurus.com/search?q=" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("urbandictionary.com")){
	chrome.contextMenus.create({"title": "urbandictionary.com", "contexts":["selection"], "parentId": tm, "onclick": lookItUp6});
}
function lookItUp6(i, t){
	var createProperties = {url: "http://www.urbandictionary.com/define.php?term=" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("wikipedia.org")){
	chrome.contextMenus.create({"title": "wikipedia.org", "contexts":["selection"], "parentId": tm, "onclick": lookItUp7});
}
function lookItUp7(i, t){
	var createProperties = {url: "http://en.wikipedia.org/wiki/" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("wiktionary.org")){
	chrome.contextMenus.create({"title": "wiktionary.org", "contexts":["selection"], "parentId": tm, "onclick": lookItUp8});
}
function lookItUp8(i, t){
	var createProperties = {url: "http://en.wiktionary.org/wiki/" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}
if(isActive("yourdictionary.com")){
	chrome.contextMenus.create({"title": "yourdictionary.com", "contexts":["selection"], "parentId": tm, "onclick": lookItUp9});
}
function lookItUp9(i, t){
	var createProperties = {url: "http://www.yourdictionary.com/" + encodeURIComponent(i.selectionText)};
	chrome.tabs.create(createProperties);
}

options.html


<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Look-it-up Options</title>
	<script type="text/javascript" src="options.js"></script>
</head>
<body>
<ul id="menu">
</ul>
<div class="summary">Changes will take place the next time you start your browser. 
Or if you don't want to close the browser you could uncheck and recheck the enabled box next to this extension on the Extensions tab page.</div>

</body>
</html>

options.js


window.onload = function () {
	ckb = chrome.extension.getBackgroundPage().entries;
	var list = document.getElementById("menu");
	for(i = 0; i < ckb.length; i++){
		console.log(ckb[i]["active"]);
		if(ckb[i]["active"] == 1){
			var li = document.createElement("li");
			var temp = "<input type=\"checkbox\" class=\"butt\" checked=\"true\" value=\"" + ckb[i]["menu"] + "\"><span>" + ckb[i]["menu"] + "</span></input>";
			
			li.innerHTML = temp;
			list.appendChild(li);
		}else{
			var li = document.createElement("li");
			var tempp = "<input type=\"checkbox\" class=\"butt\" value=\"" + ckb[i]["menu"] + "\"><span>" + ckb[i]["menu"] + "</span></input>";
			li.innerHTML = tempp;
			list.appendChild(li);
			
		}
	}
	as = document.getElementsByClassName("butt");
	for(i=0;i<as.length;i++){
		as[i].addEventListener("click",function(evt){
			if(evt.target.checked == true){
				
				chrome.extension.getBackgroundPage().setActive(evt.target.value);
			}else{
				chrome.extension.getBackgroundPage().setInactive(evt.target.value);
			}
		},false)
	}
}


Install Look-it-up Context Menu Extension in Chrome (Google Chrome Store)

Install Look-it-up Context Menu Extension in Opera (My Repository)

Standard
Browser Extension, Google Chrome, Javascript, uTube-Search, You-Tube-Search

Update – The You-Tube Search extension for Chrome is now renamed to uTube Search

You-Tube Search was taken down and replaced with uTube Search

You-Tube Search was taken down and replaced with uTube Search

Google is fussy about copyright stuff and browser extensions. I used a dash in the name to get around their copyright rules – they caught me. Google owns youtube.com, as well as you-tube.com apparently (even though it doesn’t resolve, it goes through google nameservers) – they don’t own utube.com (Universal Tube & Rollform Equipment Corporation does – I don’t think they’ll complain about my browser extension). So I think this new name will be OK (hopefully). I just want to mention that I am just trying to make searching youtube.com easier and more convenient  – nothing more.  I’m sorry if this caused my users or Google any inconvenience or problems.

The newly named version (uTube Search) is available in the Chrome Store here.

Standard