Sort files on gulp-inject index task - javascript

I am trying to sort my files since I am getting an Angular error because of the sort of the files.
This is my Gulp file
var gulp = require('gulp');
var angularFilesort = require('gulp-angular-filesort');
var naturalSort = require('gulp-natural-sort');
var inject = require('gulp-inject');
gulp.task('index', function () {
var target = gulp.src('./public/index.html');
var sources = gulp.src(
['./**/*.js', './**/*.css'],
{
read: false,
cwd: __dirname + "/public/",
}
).pipe(angularFilesort());
return target.pipe(inject(sources, { addRootSlash: false }))
.pipe(gulp.dest('./public'));
});
the files are sorting like this
<!-- inject:js -->
<script src="app.js"></script>
<script src="controllers/add.js"></script>
<script src="controllers/main.js"></script>
<script src="filters/fromNow.js"></script>
<script src="services/show.js"></script>
<script src="vendor/angular-cookies.js"></script>
<script src="vendor/angular-messages.js"></script>
<script src="vendor/angular-resource.js"></script>
<script src="vendor/angular-route.js"></script>
<script src="vendor/angular-strap.js"></script>
<script src="vendor/angular-strap.tpl.js"></script>
<script src="vendor/angular.min.js"></script>
<script src="vendor/moment.min.js"></script>
<!-- endinject -->
and here the folders
and the console errors
so what am I missing?

Drop the {read: false} option. gulp-angular-sort needs the file contents to function and read: false prevents those from being read.
From the docs:
NOTE Do not use the read option for gulp.src! This plugin analyzes the contents of each file to determine sort order.

Related

html5 template content (document fragment) load order on appendChild

consider the following code -->
<template id="foo">
<script type="text/javascript">
console.log("00000000");
</script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
console.log(11111111);
</script>
<script type="text/javascript">
console.log(22222222);
var xyz = $;
console.log(33333333);
</script>
</template>
now on appending this to the DOM
var template = document.getElementById('foo')
var clone = document.importNode(template.content,true);
document.appendChild(clone);
gives this output in console -->
00000000
11111111
22222222
Uncaught ReferenceError: $ is not defined
So the question in general is -->
How to properly load into DOM, an html <template> that has
an external script (like jQuery in this case), followed by an inline script having some dependency on it.
Also - this does not happen if template tag is removed -->
<script type="text/javascript">
console.log("00000000");
</script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
console.log(11111111);
</script>
<script type="text/javascript">
console.log(22222222);
var xyz = $;
console.log(33333333);
</script>
How in the latter case, does the browser download it synchronously?
Is it possible to have blocking script download (line by line) in the former case (with template) ?
The problem is that the script is loaded async. That means that it start to load the script from the web, but continues running the code below. So in that case it will execute code below without having loaded jQuery yet.
You only need to load it once, so you could do it at the start, and only once:
var template = document.getElementById('foo')
var clone = document.importNode(template.content,true);
document.body.appendChild(clone);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<template id="foo">
<script type="text/javascript">
console.log(00000000);
</script>
<script type="text/javascript">
console.log(11111111);
</script>
<script type="text/javascript">
console.log(22222222);
var xyz = $;
console.log(33333333);
</script>
</template>
Another option would be to make sure code below is only executed once the file is loaded:
var template = document.getElementById('foo')
var clone = document.importNode(template.content, true);
document.body.appendChild(clone);
<template id="foo">
<script type="text/javascript">
console.log(00000000);
</script>
<script type="text/javascript">
function scriptOnload() {
console.log(11111111);
console.log(22222222);
var xyz = $;
console.log(33333333);
}
</script>
<script onload="scriptOnload()" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</template>
Here's how I handle it in my application (with jQuery):
//Load the template from an external file and append it to the HEAD of the document
$.get("/path/to/your_external_template_file.html", function (html_string) {
$('head', top.document).append(
new DOMParser().parseFromString(html_string, 'text/html').querySelector('template')
);
}, 'html');
//Locate the template after you've imported it
var $template = $("#top_template_element_id");
//If you want to reuse the content, be sure to clone the node.
var content = $template.prop('content').cloneNode(true);
//Add a copy of the template to desired container on the page
var $container = $('#target_container_id').append(content);

Angular still trying to look for templates even though I've $templateCached them

I'm trying to merge gulp, angular ngbp, and ionic. So far I've restructured the sample app code to the ngbp style and I've compiled the templates into a js file so that they could be loaded into the $templateCache and then my app js files could just fetch templates from the cache.
In my index.html
<!-- inject:js -->
<script src="/vendor/angular/angular.min.js"></script>
<script src="/vendor/angular-animate/angular-animate.min.js"></script>
<script src="/vendor/angular-sanitize/angular-sanitize.min.js"></script>
<script src="/vendor/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="/vendor/ionic/js/ionic.min.js"></script>
<script src="/vendor/ionic/js/ionic-angular.min.js"></script>
<script src="/vendor/ionic/js/ionic.bundle.js"></script>
<script src="/src/app/app.js"></script>
<script src="/src/app/browse/browse.js"></script>
<script src="/src/app/browse/routes.js"></script>
<script src="/src/app/playlist/controllers.js"></script>
<script src="/src/app/playlist/playlist.js"></script>
<script src="/src/app/playlist/routes.js"></script>
<script src="/src/app/playlists/controllers.js"></script>
<script src="/src/app/playlists/playlists.js"></script>
<script src="/src/app/playlists/routes.js"></script>
<script src="/src/app/search/routes.js"></script>
<script src="/src/app/search/search.js"></script>
<script src="/templates-app.js"></script>
<!-- endinject -->
In my templates-app.js
(function(module) {
try { module = angular.module("templates-app"); }
catch(err) { module = angular.module("templates-app", []); }
module.run(["$templateCache", function($templateCache) {
$templateCache.put("browse/templates/browse.tpl.html",
"<ion-view view-title=\"Browse\">\n" +
" <ion-content>\n" +
" <h1>Browse</h1>\n" +
" </ion-content>\n" +
"</ion-view>\n" +
"");
}]);
})();
(function(module) {
try { module = angular.module("templates-app"); }
catch(err) { module = angular.module("templates-app", []); }
module.run(["$templateCache", function($templateCache) {
$templateCache.put("login/templates/login.tpl.html",
//..........
Sample route (browse/routes.js), templates are in src/app/browse/templates/ (templates not included in build, thus, requiring templates-app.js to cache templates)
function BrowseConfig($stateProvider){
$stateProvider
.state('app.browse', {
url: "/browse",
views: {
'menuContent': {
templateUrl: "browse/templates/browse.tpl.html"
}
}
})
;
}
angular.module('browse.routes', ['ui.router'])
.config(['$stateProvider', BrowseConfig])
;
This normally works fine with the generic ngbp project, but for some reason, when I load up localhost:8080 for my project, the angular app still tries to GET the template files (404). Why is my app not using the cache?
you have to include "templates-app" as a dependency in your "browse.routes" module otherwise he won't know the templates exist

How to set Arcgis Javascript dojoConfig relative path of packages

I am using Arcgis Javascript API. API is built on dojo toolkit. So I need to use dojo features in API. I am preparing dojo config file as following.
var pathRegex = new RegExp("/\/[^\/]+$/");
var locationPath = location.pathname.replace(pathRegex, '');
var dojoConfig = {
async: true,
parseOnLoad: false,
baseUrl:"js/",
packages: [
{
name: "application",
location: locationPath + '/js/application'
}]
};
I created a bootstrapper.js like following.
require(["application/main", "dojo/domReady!"], function (application) {
console.log("bootstrapper is running");
application.Run();
})
And index.html file is like this.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Arcgis Javacsript API Samples</title>
<link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.5/js/dojo/dijit/themes/claro/claro.css">
<link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/3.5/js/esri/css/esri.css">
</head>
<body class="claro">
<div id="map"></div>
<script src="//js.arcgis.com/3.6/"></script>
<script src="js/application/djConfig.js"></script>
<script src="js/application/bootstrapper.js"></script>
</body>
</html>
My application is hosted on IIS and has addres like this htp://domain/Demo/Sample1/index.html
when I run application, this code giving error like following.
"NetworkError: 404 Not Found - http://js.arcgis.com/3.6/js/dojo/application/main.js"
If I set bootstrapper.js file as following, problem is solwing.
require(["js/application/main.js", "dojo/domReady!"], function (application) {
console.log("bootstrapper is running");
application.Run();
})
Try to change your script order in index.html file. Your config settings should load before CDN.
<div id="map"></div>
<script src="js/application/djConfig.js"></script>
<script src="//js.arcgis.com/3.6/"></script>
<script src="js/application/bootstrapper.js"></script>
</body>

How to use a javascript file in options.html

I have trouble adding a personal javascript file in my option.html for my google-chrome extension.
I've added this line to my options.html:
<script type="text/javasctipt" src="/js/content/toto.js"></script>
And the object $.toto, described in this file is unreachable.
I would like to know if it's possible to add a personal js file and how or if you have to do everything in the options.js ?
Thank in advance for your answers.
Here is a part of the code as the project is already large:
options.html:
<!DOCTYPE html>
<html lang="fr">
<body>
<script type="text/javascript" src="/js/lib/jquery-1.8.3.min.js"></script>
<script type="text/javascript" src="/js/lib/sprintf-0.6.js"></script>
<script type="text/javascript" src="/js/lib/bootstrap/bootstrap-modal.js"></script>
<script type="text/javascript" src="/js/shared/constant.js"></script>
<script type="text/javascript" src="/js/shared/storage.js"></script>
<script type="text/javasctipt" src="/js/content/toto.js"></script>
<script type="text/javascript" src="/js/content/messages.js"></script>
<script type="text/javascript" src="/js/content/debug.js"></script>
<script type="text/javascript" src="/js/content/form.js"></script>
<script type="text/javascript" src="/js/content/base.js"></script>
<script type="text/javascript" src="/js/content/options.js"></script>
</body>
</html>
options.js:
$.options = $.extend({}, $.base, {
ready: function() {
// onMessage
chrome.extension.onMessage.addListener(this.onMessage);
// init events
$("#logout_btn").live("click",function() {
$.options.logout();
});
// init ui
$.toto.initialize();
this.displayCorrectContext();
this.initMailPrescrip();
}
});
toto.js:
$.toto = $.extend({}, $.base, {
TAG: "MESSAGES",
ready: function() {
$("[title-message]").each(function() {
var txt = chrome.i18n.getMessage($(this).attr("title-message"));
$(this).attr('title', txt);
});
$("[data-message]").each(function() {
var txt = chrome.i18n.getMessage($(this).attr("data-message"));
$(this).html(txt);
});
},
log: function(message) {
$.base.log($.messages.TAG,message);
}
});
Use .ready event like this.
jQuery(document).ready(function(){
// jquery function code
});
In the manifest.json, try adding it in the "scripts" line, like so:
"app": {
"background": {
"scripts": ["exampleReference1.js", "exampleReference2.js", "toto.js"],
"transient": true
}
},
Hope it works.

What's a good way to build a Backbone.js project?

We're currently kicking off our first Backbone.js project here at work. In fact it's our first major JavaScript project apart from the odd jQuery stuff.
Anyway, we struggle with the architecture for our stuff. What is the best way to sort stuff out?
We've started with having everything in separate files broken up in folders for; views, models, collections and routers and then we include everything in our index.html. The issue, though, is that this leaves us with having to check for the document ready event in every file. Is this the best way to do it?
Here's an example:
This is the file called PageModel, the first line seems wrong...
$(function(){
app.models.Page = Backbone.Model.extend({
//stuff
});
});
Then in our index.html we have:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
<link href="assets/css/style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
var app = app || {};
app.models = app.models || {};
app.collections = app.collections || {};
app.views = app.views || {};
app.routers = app.collections || {};
app.templates = app.templates || {};
app.models.griditems = app.models.griditems || {};
app.views.griditems = app.views.griditems || {};
</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
<script src="assets/js/libs/json2.js" type="text/javascript"></script>
<script src="assets/js/libs/underscore-1.1.7.min.js" type="text/javascript"></script>
<script src="assets/js/libs/backbone-0.5.3.min.js" type="text/javascript"></script>
<script src="assets/js/models/GridItemModel.js" type="text/javascript"></script>
<script src="assets/js/models/GalleryGridItemModel.js" type="text/javascript"></script>
<script src="assets/js/models/NewsGridItemModel.js" type="text/javascript"></script>
<script src="assets/js/models/VideoGridItemModel.js" type="text/javascript"></script>
<script src="assets/js/collections/GridCollection.js" type="text/javascript"></script>
<script src="assets/js/templates/Submenu.js" type="text/javascript"></script>
<script src="assets/js/templates/GalleryGridItemTemplate.js" type="text/javascript"></script>
<script src="assets/js/views/GridView.js" type="text/javascript"></script>
<script src="assets/js/views/GridItemView.js" type="text/javascript"></script>
<script src="assets/js/views/GalleryGridItemView.js" type="text/javascript"></script>
<script src="assets/js/views/VideoGridItemView.js" type="text/javascript"></script>
<script src="assets/js/routers/Router.js" type="text/javascript"></script>
<script src="assets/js/Application.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
This is structure we use in our Backbone projects
<!-- Libs Section -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/jquery-1.5.2.min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/jquery.validate.min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/jquery.maskedinput-1.3.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/jquery.mousewheel.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/jquery.scrollpane.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/fileuploader.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/modernizr.min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/json2.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/underscore-min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Content/static/js/libs/backbone-min.js")"></script>
<!-- Libs Section -->
<!-- Core Section -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/config.js")"></script> <!-- Global configs -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/core.js")"></script> <!-- Core methods for easier working with views, models and collections + additional useful utils -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/app.js")"></script> <!-- Application object inherites core.js as prototype -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/renisans.js")"></script> <!-- Project Object. Creates Namespace and Extends it with project specific methods -->
<!-- Core Section -->
<!-- Routers Section -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/routers/workspace.js")"></script>
<!-- Routers Section -->
<!-- Models Section -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/models/profile.js")"></script>
...
<!-- Models Section -->
<!-- Collections Section -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/collections/messages.js")"></script>
...
<!-- Collections Section -->
<!-- Views Section -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/views/workspace.js")"></script>
...
<!-- Views Section -->
<!-- Localization Section -->
<script type="text/javascript" src="#Url.Content("~/Content/static/js/localizations/ru_RU.js")"></script>
<!-- Localization Section -->
<!-- Init Section -->
<script type="text/javascript">
$(function() {
Rens.container = $('.l-wrapper'); // Some parameters
Rens.init({
Localization: LocalizationStrings || {}, // Object with localization strings
Profile: {
// Bootstraping initial data to Profile model
}
});
});
</script>
<!-- Init Section -->
content of app.js
var App = function() {
this.Views = {};
this.Routers = {};
this.Models = {};
this.Collections = {};
this.User = {};
this.router = null;
this.view = null;
this.baseLocation = null;
this.beforeInit = function() {};
this.afterInit = function() {};
this.init = function(initData) {
if (typeof(this.beforeInit) === 'function') {
this.beforeInit.apply(this, arguments);
}
if (this.Views.Workspace) {
this.view = new this.Views.Workspace();
}
this.baseLocation = window.location.href.replace(/[?#].*/, '') == Config.web.host;
if (this.Routers.Workspace) {
this.router = new this.Routers.Workspace(initData);
}
this.view && this.view.setListeners && this.view.setListeners();
Backbone.history.start();
if (typeof(this.afterInit) === 'function') {
this.afterInit.apply(this, arguments);
}
}.bind(this);
};
App.prototype = Core;
and content of renisans.js
var Rens = new App();
$.extend(Rens, {
container: null,
Error: function(data) {
// Handling error
},
Localization: function(dictionary) {
return {
get: function(name) {
var argumentsList = Array.prototype.slice.call(arguments),
strings = argumentsList.slice(1),
text = this[name];
if (text && strings.length) {
$(strings).each(function(i, string) {
var reg = new RegExp('\\$' + i, 'go');
text = text.replace(reg, string);
});
}
return text || 'SLB.Localization.' + name + ' not found!';
}.bind(dictionary)
}
},
formatDate: function(rawDate) {
var timestamp = /\d+/.exec(rawDate)[0],
date = Rens.DateUTC(timestamp),
months = Rens.Localization.get('months');
return {
date: date,
fullDate: [date.dd, months[date.mm], date.hh].join(' '),
shortDate: [date.dd, date.MM, date.hh].join('.')
};
},
beforeInit: function(initData) {
this.Localization = new this.Localization(initData.Localization);
}
});
also simplified content of models/profile.js
Rens.Models.Profile = Backbone.Model.extend({
...
});
If you are creating an application of this shape, i strongly suggest to use dynamic loading of your assets, like javascript and more.
you have several options for this:
Require.js
LABjs
...
i myself have no experience with LABjs, but i've been using Require.js in smaller projects for myself. But have yet to use it in a major project.
the advantages of such a system:
you can work with dependancies, and your models or views will only be loaded when they are requested by another part of your code. not all at the beginning.
require.js also provides features for minifying and agregating your code based on the dependancies you specified.
require.js has a few small plugins for loading in text files (if you use a templating system this could be useful, or a plugin to define the order in which files need to be loaded.
and require.js also has a special version for working together with jquery and its modules. (but you are not required to use this one, you can load in jquery trough manually as well)
you will need to wrap your models / views / ... in modules so require.js can load them dynamically. I asked about this here on stack overflow last week... you can find the info on how to do that here
I suggest you read the 'getting started with require.js' and see if you feel like using it.
because working with all models / views / ... in separate files is quite handy in development fase, but is defenately not recommended when going into production. the fewer requests have to be sent by the browser to the server the better.

Categories

Resources