How to remove url protocol from Angular $http get response - angularjs

I'm working on a chrome extension that uses the iframe.ly API to grab the responsive iframe markup from a video on the page the user is currently on. I'm using Angular JS (v1.5.8) to communicate with the API, and to generate a preview of the iframe markup. Everything's working splendidly if the extension is being used on a YouTube page. Here's the basic flow:
content script <-- grabs current url
chrome.runtime.sendMessage({
theurl: window.location.href
});
background script <-- puts current url into url made for the API call:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse){
localStorage["theurl"] = request.theurl;
}
);
var url = "http://iframe.ly/api/iframely?url="
+ localStorage["theurl"] + "&api_key=**my api key, to be removed in production**>";
stuff.js <-- not greatly named, but the Angular bit that makes the call:
var iframeApp = angular.module('iframeApp', ['ngSanitize']);
iframeApp.controller('linkCtrl', function($scope, $http) {
$http.get(url).success(function(data) {
$scope.iframe = data;
});
});
iframeApp.filter('trusted', ['$sce', function ($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
}]);
iframeApp.filter('rawHtml', ['$sce', function($sce){
return function(val) {
return $sce.trustAsHtml(val);
};
}]);
sandboxed.html <-- again, not greatly named (leftover from when I was trying a different approach for this extension), but the default popup when browser icon is clicked:
<html class="ng-scope" ng-csp ng-app="iframeApp">
<head>
<meta charset="utf-8">
<title>Angular.js JSON Fetching Example</title>
<link rel="stylesheet" href="bootstrap.min.css">
<script src="angular.min.js"></script>
<script src="angular-sanitize.min.js"></script>
<script src="backgroundscript.js"></script>
<script src="stuff.js"></script>
</head>
<body ng-controller="linkCtrl">
<h4>Responsive iFrame code is <pre>{{iframe.links.player[0].html}}</pre></h4>
<div ng-bind-html="iframe.links.player[0].html | rawHtml"></div>
</body>
</body>
</html>
Now! On a YouTube page (for example), this is what happens when the browser icon is clicked:
Wonderful! BUT! Things get a bit, um, not working at all when I attempt to make the same call when on a Vimeo page. Here's the problem: The source url on the iframe.ly API call to a YouTube page returns a URL that's appended with a https protocol. However, a Vimeo call returns a URL with a non-relative, "//" protocol appended to the source. So, this happens, because obviously this won't work unless you're doing it on an HTML file that's running on a server of some sort, because it otherwise attempts to access a local file:
Now, I'd like to fix this by calling for the source url (by replacing the iframe.links.player[0].html with iframe.links.player[0].href) and then putting that inside an iframe inside of a hardcoded responsive div element. That way, my call would return, say //player.vimeo.com/video/177375994?byline=0&badge=0&portrait=0&title=0.
So, how could I remove all the protocols from the URLs from the API calls? This would be great, because player.vimeo.com/video/177375994?byline=0&badge=0&portrait=0&title=0 automatically routes the browser to append the proper protocol, rather than making it think that I'm trying to load a local file, and it does the same when there's no protocol on a YouTube URL, and I'm assuming any other URL for a video as well.
The functionality of the extension is to allow a developer to quickly copy/paste iframe markup, instead of having to type it out, just to make things a tad easier. So, the "//" protocol would actually be fine in the long run if a site is being built, because then it's running on a server, and it doesn't matter. But, for purposes of not looking ugly, it'd be nice if the preview worked for all videos with the extension.
Thank you!

In case you're working on an extension or app with Angular, and you're communicating with public API that you don't have control over, and that API is giving you some guff with some unwanted characters its responses: Never fear!
I successfully pulled the protocol from the get request's returning URL, but after realizing that a URL without a protocol is treated like a local file, too, I added an "http://" protocol to the URL after stripping it. This way, any Vimeo source in the iframe.ly API that had a protocol of "//" would be replaced with an "http://", which ends up redirecting it to an "https://" protocol anyway (it seems safe to put "http://" on anything and have your bases covered, because, at least in Chrome, it'll be sufficient to route to anything SSL protected as well).
So, basically, the problem was that the iframe.ly API was spectacular for finding the source URLs for videos, but the protocols weren't normalized, which caused problems when trying to use those URLs inside of the chrome extension. Here's the code I'm currently using to pull the URLs from the API, and then normalize their protocols to all be "http://":
In the poorly named stuff.js, where the Angular code for the extension lives:
var iframeApp = angular.module('iframeApp', ['ngSanitize']);
iframeApp.controller('linkCtrl', function($scope, $http, $sce) {
$http.get(url).success(function(data) {
$scope.iframe = data;
var newurl = $scope.iframe.links.player[0].href;
var secondurl = newurl.split('/').slice(2).join('/');
$scope.iframe2 = $sce.trustAsResourceUrl((secondurl.indexOf('://') == -1) ? 'http://' + secondurl : secondurl) ;
var testurl = $scope.iframe.links.player[0].href;
$scope.iframe3 = testurl;
$scope.iframe3 = $sce.trustAsResourceUrl(testurl);
});
});
iframeApp.filter('trusted', ['$sce', function ($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
}]);
iframeApp.filter('rawHtml', ['$sce', function($sce){
return function(val) {
return $sce.trustAsHtml(val);
};
}]);
And, in the also-poorly-named sandboxed.html, which is the extension's default popup:
<html class="ng-scope" ng-csp ng-app="iframeApp">
<head>
<meta charset="utf-8">
<title>Angular.js JSON Fetching Example</title>
<link rel="stylesheet" href="bootstrap.min.css">
<script src="angular.min.js"></script>
<script src="angular-sanitize.min.js"></script>
<script src="backgroundscript.js"></script>
<script src="stuff.js"></script>
</head>
<body ng-controller="linkCtrl">
<h4>Responsive iFrame: <pre><code><div style="left: 0px; width: 100%; height: 0px; position: relative; padding-bottom: 56.2493%;"><iframe src="{{iframe2}}" frameborder="0" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" style="top: 0px; left: 0px; width: 100%; height: 100%; position: absolute;"></iframe></div></code></pre>
<div>Source URL is: <code>{{iframe2}}</code></div>
<div style="left: 0px; width: 100%; height: 0px; position: relative; padding-bottom: 56.2493%;"><iframe ng-src="{{iframe2}}" frameborder="0" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true" style="top: 0px; left: 0px; width: 100%; height: 100%; position: absolute;"></iframe></div>
</body>
</html>
And now, clicking the browser action icon on a Vimeo video's page will not return with the Sad Face graphic that I've come to loathe so, so very much over the past couple weeks:
And, if I copy/paste that source URL into the browser, we can see that it automatically routes the "http://" protocol to its rightful "https://" protocol:
And, just for fun, an html page that's populated with stuff copy/pasted from the Responsive iFrame Code section of the default popup:
Gives us this, when the file is opened locally:
I have a feeling that any AngularJS purist is looking at this code and shouting "NO NO NO NO NO" at their screen, because, even as a n00b, I'm pretty sure that this Angular code is ugly, and should be separated into different pieces. BUT! It is working, and I'd love to hear any suggestions on accomplishing this in a more proper, "Angular Way" :)

Related

Not getting json rest response in my AngularJS application

This has been frustrating me a bit. I have a restful services giving JSON data running on the link:
http://localhost:51133/API/SalesSystem/
So its running locally on my computer. I can get the data from this service with no problem using my WPF based interface.
Another service I am testing with is this one:
http://rest-service.guides.spring.io/greeting
But from my own service something seems to go wrong somehow and I cannot figure out what goes wrong. I have even tried just taking the full response and printing it. With the second service, I get a long list of data regarding the response, but with my own I still get nothing. As if the function was not used at all.
This is my Angular code:
angular.module('demo', [])
.controller('Hello', function ($scope, $http) {
$http.get('http://localhost:51133/api/salessystem/').
//http://rest-service.guides.spring.io/greeting
//http://localhost:51133/API/SalesSystem/
then(function (response) {
$scope.hello = 'hello';
$scope.district = response;
});
});
and this is my html code:
<!doctype html>
<html ng-app="demo">
<head>
<title>Hello AngularJS</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<script src="Scripts/hello.js"></script>
</head>
<body>
<div ng-controller="Hello">
<li>Id: <button>{{hello}}</button></li>
<li>Area: {{district}}</li>
<ul ng-repeat="obj in hello">
<li>Area: {{obj.area}}</li>
</ul>
<p>The ID is {{hello.Id}}</p>
<p>The content is {{hello.Area}}</p>
</div>
</body>
</html>
Can anyone see the problem? The spring rest service shows all kinds of data about the response and it also shows the button with "hello" inside it. But when I use my own service link it seems there is no $scope returned at all.
Oh, and this is the json returned when I just visit the link directly in the browser: (its an array of 3 districts)
[{"Id":1,"Area":"North Denmark","PrimarySalespersonID":1,"PrimarySalesperson":{"Id":1,"Name":"Tom B. Erichsen"},"SecondarySalespersons":null,"Stores":null},{"Id":2,"Area":"Southern Denmark","PrimarySalespersonID":2,"PrimarySalesperson":{"Id":2,"Name":"Eric B. Thomsen"},"SecondarySalespersons":null,"Stores":null},{"Id":3,"Area":"Eastern Denmark","PrimarySalespersonID":3,"PrimarySalesperson":{"Id":3,"Name":"Ben Anderson"},"SecondarySalespersons":null,"Stores":null}]

How do I load Google Maps script in a Chrome extension using Angular?

I am building a Chrome extension using AngularJS that is using Google Maps (specifically Locations).
I am looking for functionality that is similar to
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<style type="text/css">
body
{
font-family: Arial;
font-size: 10pt;
}
</style>
</head>
<body>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
<script type="text/javascript">
google.maps.event.addDomListener(window, 'load', function () {
var places = new google.maps.places.Autocomplete(document.getElementById('txtPlaces'));
google.maps.event.addListener(places, 'place_changed', function () {
var place = places.getPlace();
var address = place.formatted_address;
var latitude = place.geometry.location.lat();
var longitude = place.geometry.location.lng();
var mesg = "Address: " + address;
mesg += "\nLatitude: " + latitude;
mesg += "\nLongitude: " + longitude;
alert(mesg);
});
});
</script>
<span>Location:</span>
<input type="text" id="txtPlaces" style="width: 250px" placeholder="Enter a location" />
</body>
</html>
The above works fine if it's not a Chrome extension. However, because I'm building a Chrome extension when I try to load the Google Maps script
http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places
I get an error saying
Refused to load the script 'http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places' because it violates the following Content Security Policy directive: "script-src 'self' https://ssl.google-analytics.com".
When I change the manifest to
"content_security_policy": "script-src 'self' https://maps.googleapis.com https://ssl.google-analytics.com; object-src 'self'",
I still get the same 'Refused to load script' error.
So my question is: how do I load the Google Maps library without loading it directly in the HTML file?
I was able to add https://maps.googleapis.com to the manifest. It wasn't working before because I wasn't reloading the files to chrome. Now that I reloaded, that is working!
By default, inline script won't be executed and only local script is loaded.
Besides adding remote url (starting with https) in content_securiy_policy field, you should also extract your inline script to an external file then include it.

AngularJS CouchDB, get data with authentication

Simple AngularJS script with user:passw and server.ip
<!DOCTYPE html>
<html >
<script src= "angularjs/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="customersCtrl">
<p>{{ names }}</p>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('customersCtrl', ['$scope','$http', function($scope,$http) {
$http.get('http://user:passwd#server.ip:5984/dbp/3c9f8c470a4a40d81d43467346000010')
.success(function (data) {
$scope.names = data.rows;
});
}]);
</script>
</body>
</html>
If I use url & put in address bar in my browser, everything works fine
http://user:passwd#server.ip:5984/dbp/3c9f8c470a4a40d81d43467346000010
I mean I get json data.
When I use previous script I get
Remote Address:server.ip:5984
Request URL:http://server.ip:5984/dbp/3c9f8c470a4a40d81d43467346000010
Request Method:GET
Status Code:401 Unauthorized
How can I get json data from CouchDB with authorization header in AngularJS?
CouchDB & AngularJS are on the same server!
I read all 111 q/a (AngularJS CouchDB) from stackoverflow and I didn't find right answer.
I have enable CORS!
You have to send the username/password pair in an Authorization header. (as #pankajparkar has answered correctly before)
The reason why it simply works in the browser address bar is that the browser does this step automatically for you.

Routing single page application using angular js

I am building a web Single Page Application using AngularJS. I need that clicking on link change URI in client browser without http request.
http://example.com/ ---> it shows my single page application and clicking on a specific link I need the URL is http://example.com/about but without send http request and show hidden div.
I don't know what you precisely want to do but if you only want do one http request you can perhaps use angular ui router with something like
$stateProvider
.state('main', {
url: "/",
templateUrl: "main.html"
})
.state('about', {
url: "/about",
templateUrl: "main.html",
controller: function($scope) {
$scope.showDiv = "true";
}
})
That way you can switch state and because everything you need is already loaded, nothing gets loaded anymore. Or perhaps you can also use parameters.
But why is it so bad to have one additional request? That would be something interesting to know! :)
EDIT: The easy approach with $location
(https://docs.angularjs.org/guide/$location)
index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example</title>
<base href="/">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="html5-mode">
<div ng-controller="LocationController">
<button ng-click="changeUrl()">Change url</button>
</div>
</body>
</html>
app.js:
angular.module('html5-mode', [])
.controller("LocationController", function ($scope, $location) {
$scope.$location = {};
$scope.changeUrl = function () {
// https://docs.angularjs.org/guide/$location
console.log("The current path: " + $location.path());
console.log("Changing url...");
$location.path('/newValue')
};
})
.config(function ($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
Be sure to set the basePath correct.
Take a look at html2js. This is a grunt task to convert your html templates into a pre-cached js file.
Ideally you would run this as part of your build process. As well you can run a watch task to compile your HTML templates into the pre-cache whenever you save a template -- this is nice for development.
If you are already using gulp, there is a package for you. There are many alternatives to html2js that do essentially the same thing. So if it doesn't suit your needs, try another.
So with this in place, when you navigate to another page -- the HTML template will just be pulled out of angular's cache, and not grabbed from the server.

loader not showing up in chrome-extension

I've an app that retrieve server data using ajax. I've tested in localhost, the loader work fine, but when I install my extension and click on the browser action popup, the loader won't show. The little popup delayed for 2 second and shows the result.
popup.html
<div class="cssLoader" ng-show="loader">Fetching...</div>
js
app.controller('MainControl', function($scope, $http){
$scope.loader = true;
$http({
url: "http://www.corsproxy.com/mydomain.net/items.php",
method: "GET",
}).success(function(data) {
$scope.data = data;
$scope.loader = false;
});
});
Without seeing more of your code it is difficult to know for sure. Nonetheless, my suspicion (based upon the fact that your code works outside of the Chrome extension environment but not inside that environment) is that since you're operating in a Chrome Extension environment, you'll need to include the ng-csp directive (see Chrome documentation or Angular documentation).
I developed an Angular app inside a chrome extension and I needed to use ng-csp in order for Angular to load and fully function properly.
Essentially, Chrome extensions (and even more apps) place a number of restrictive security permissions on the browser environment and ng-csp tells Angular to operate in a way that is more consistent with a strict CSP.
I have included an example below that shows loading the entire Angular application properly:
<!DOCTYPE html>
<html ng-app="myApp" ng-csp>
<head>
<meta charset="utf-8">
<title>My Extension</title>
<link href="css/index.css" rel="stylesheet">
<!-- Include in the next line your Angular library code -->
<script type="text/javascript" src="js/angular-lib.js"></script>
<!-- Include in the next line your custom Angular code such as the $http to load the loader -->
<script type="text/javascript" src="js/myapp.js"></script>
</head>
<body>
<!-- Place your HTML code for the 'Fetching' anywhere here in the body -->
</body>
</html>
According to the docs, CSP "is necessary when developing things like Google Chrome Extensions" (more info can be found on the linked page).
Furthermore, besides defining ng-csp on your root element, there is on more crucial point (which affects ngShow/ngHide):
CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically includes some CSS rules (e.g. ngCloak). To make those directives work in CSP mode, include the angular-csp.css manually.
I found this to be necessary only if the angular.js script is defined inside the app's context.
In any case, here is the source code of minimal demo extension that seems to work fine for me:
Structure:
extension-root-dir/
|_____manifest.json
|_____popup.html
|_____popup.js
|_____angular.js
|_____angular-csp.css
manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"browser_action": {
"default_title": "Test Extension",
//"default_icon": {
// "19": "img/icon19.png",
// "38": "img/icon38.png"
//},
"default_popup": "popup.html"
}
}
popup.html:
<!DOCTYPE html>
<html>
<head>
<title>Test Extension</title>
<link rel="stylesheet" href="angular-csp.css" />
</head>
<body ng-csp ng-app="myApp" ng-controller="mainCtrl">
<div ng-show="loader">Fetching...</div>
<div ng-hide="loader">{{status}}</div>
<script src="angular.js"></script>
<script src="popup.js"></script>
</body>
</html>
popup.js:
var app = angular.module('myApp', []);
app.controller('mainCtrl', function ($http, $scope) {
$scope.loader = true;
$http({
url: "http://www.corsproxy.com/mydomain.net/items.php",
method: "GET"
}).finally(function () {
$scope.loader = false;
}).then(function (response) {
$scope.data = response.data;
$scope.status = 'Success !';
}, function (response) {
$scope.status = 'ERROR !';
});
});
(BTW, I am using AngularJS v1.2.16.)

Resources