Sylius: How to modify/customize app.js? - javascript

I'm overriding the general theme in Sylius with my custom theme, which is working fine so far. I created a new theme in app/themes/myCustomTheme and am overwriting e.g. the twig templates in /SyliusShopBundle/views/.
Now I want to override the general app.js located in vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/private/js/. E.g. instead on line 18:
$('.ui.accordion').accordion();
I would like to use a different selector to initialize the accordion:
$('.my-custom-accordion').accordion();
Assume this is the only change I want to do in the whole javascript code. What is the best and most efficient way to do this? I would like to have as minimum conflicts as possible when there is a Sylius version update and therefore touch as less files as possible. And of course, not have to rewrite the whole javascript functionality by myself.
I can think about different ways to do this, but I hope there's an even better one:
Duplicate everything. Copy all the UiBundle & ShopBundle javascript code to my theme and modify the necessary parts. Update the global gulpfile to no longer use the gulpfile in vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Gulpfile.js and instead use the duplicated one /myCustomTheme/SyliusShopBundle/Gulpfile.js. Downside: duplicated code, javascript updates no longer possible.
Add custom path to existing gulpfile. Update the gulpfile in vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Gulpfile.js, which means removing the line which includes the app.js: vendorShopPath + 'Resources/private/js/**' and instead reference all single files without the app.js AND reference to the customized app.js in my theme folder. Downside: Changes to the gulpfile are probably overwritten by the next update.
How do I efficiently modify/customize/extend the existing javascript code in Sylius?

I solved this for me creating a custom gulpfile in my bundle (AppBundle) and adding it to the global gulpfile in the same way of "admin" and "shop". After that you can include your custom app.js in the layout or whatever template. In my case I modified the Product/show.html.twig to add my custom .js:
{% block javascripts %}
{{ parent() }}
{% include '#SyliusUi/_javascripts.html.twig' with {'path': 'assets/app/js/app.js'} %}
{% endblock %}

Related

How do I reference the root directory of my site? And why won't Jekyll render some pages?

I have a fairly complex javascript project that I've been working on locally up until recently. Its destined for deployment on my github-pages site as a project page.
The problem is, several locations in code, the url starts at the root directory (eg, /js/script.js). This is kind of necessary, since these files are scattered across sub directories, and I don't want to try and think about ".."-ing my way up a directory tree. This method works perfectly fine locally. But once it gets pushed to github, everything breaks, due to the intervening project name in the url, pushing the root directory one step away from where I want to get files.
I tried what was outlined in this answer, pertaining to using Jekyll's templating features and site.baseurl, but for some reason, Jekyll refuses to actually replace those templates! The urls are all messed up with the {{ site.baseurl }} just sitting in the url, with escape characters and everything. And I refuse to install ruby just so I can try running this thing locally with it, just to debug github's own mess; I have no desire to use Jekyll beyond solving this problem if I can help it.
To complicate matters, I actually have two repos this same code is going into; since this project is rather complex, I have a "Test" version of the repo (seeing as only the "gh-pages" branch ends up remotely accessible as a page on github.io, the solution was to make two repos and push from one to the other). So statically defining baseurl is distasteful anyway, but if it makes the thing work, I'll live with it.
What am I doing wrong??
(It took me several hours of head banging to solve this, which is why I figured I would submit this pre-answered question, to help others that have similar aspects of my problem.)
Let's take the answer in small, independently usable chunks:
Why Jekyll refuses to replace the templates everyone keeps suggesting
Though several places tell you about the wonders of the Liquid Templating system's {{ output }} and {% tags %}, very few places tell you that in order for Jekyll to actually process these templates, the files must contain Front Matter. That is, the file you wish to process must begin with the following, at the least:
---
---
Yes, three dashes, on two separate lines. No, you may not condense them to one line. This is required for every file you want Jekyll to actually process the template syntax for, instead of just copying as is.
How you can access your project's path on github-pages dynamically
As I mentioned above, I have two different repositories that the same code was going to end up in, so if I could avoid hard-coding the name of my project, it would be lovely.
Fortunately, github provides a non-standard jekyll site variable in the form of site.github, which is a treasure trove of various repository metadata and hidden information about how github-pages operates.
And fortunately one of the many metadata properties is site.github.project_title, which gives you the title of the project, which coincidentally is the path the pages will be running under. Surely I can just assign that to site.baseurl, and all will be well.
How Jekyll is not as flexible as it makes itself out to be
Sadly not. The _config.yml file is actually quite rigid: you may not reference other variables from here, it is only for static text and object definitions. The same, to my dismay, also goes for the Front Matter that you must have at the top of each file to process.
The format the templating system uses is also rather unconventional: There are no traditional operators. You cannot assign with "=", nor can you concatenate strings with "+" or "." or any other character. To assign to a variable a concatenated string of literals and variables, you need to use a "capture tag".
So how do I get the contents of the very convenient variable github provides into my urls? Well, I can use the following:
{% capture baseurl %}{{ site.github.project_title | prepend:'/' }}{% endcapture %}
This conglomeration of tags and output prepends a slash onto the previously mentioned project title, and then assigns that to a variable called "baseurl". (It might also be possible to simply put a slash before the output, but this is what I went with.) No, this variable is not the same as "site.baseurl". This variable is available only on the page this line is run on, and is referenced with the output {{ baseurl }}. Thus:
<script src="{{ baseurl }}/js/jquery-2.1.1.min.js"></script>
Thus at the top of every one of my html files, I have the following:
---
---
{% capture baseurl %}{{ site.github.project_title | prepend:'/' }}{% endcapture %}
(And then in the head tag, because I don't want to have to put it also at the top of my js files, I have <script>window.BASEURL = "{{ baseurl }}";</script>)
Fortunately for me, I have a build process already setup (involving browserify) so I have simply added these lines to the start of any .html files via a build step. Those without such a thing will have to remember to manually add it.
How this may screw over those who actually use jekyll
I don't use Jekyll, and I simply wanted my program to work on github-pages. My aforementioned build process takes another step after it is finished to shallowly replicate Jekyll insomuch as it strips out all the templating syntax, so I can test it locally. Those who use Jekyll to test locally may find that setting site.github.project_title as a command-line argument or in the _config.yml will result in paths that have an extraneous slash in them.
I hope this helps someone save a couple hours, at least in trying to figure out why jekyll won't process templates, if not the other sections.

Extending Handlebars.js templates

Is there a way to extend templates like in Django? My base template has a header that only needs to be a few pages. I'd like to change that for the the other templates.
Something similar to
{% extends "base.html" %}
...
{% endblock %}
I'm using Ember.js.
As far as i know this notation does not exist, also i haven't seen the concept of inheritance on handlebars templates layer.
However, i can think of two ways to achieve what you want,
1. using the {{partial}} helper http://emberjs.com/guides/templates/rendering-with-helpers/
The {{partial}} helper can render the header part and it can be included only on those templates of the pages that require the header.
2. using layouts http://emberjs.com/guides/views/adding-layouts-to-views/
Have two layouts one with the header and another without it, then specify on the pages/views that need the header the corresponding layout using the layoutName property.
I was looking for the same as I come from the same Django background. Here I've found exactly what you are looking for. It uses another module from npm called Handlebar-layouts. which is really useful.

Cassette Add Individual Javascript Script Link Reference Inline

Is there a way to add an inline script link reference using Cassette?
What I want is to be able to add something like the following to my page:
#Bundles.AddInlineScriptReference("/MyScripts/TheScript.js")
(note: Bundles.AddInlineScriptReference doesn't exists, just an example)
and have Cassette write out the script link including handling the minification, etc.
<script src="/cassette.axd/asset/MyScripts/TheScript.js?voB4kL0uy2HIpjkJnSuycghlp-8=" type="text/javascript"></script>
I see a way to add inline scripts and bundles but not script link references. I could setup bundles that include individual files. However that seems like it's unnecessarily tedious for a single script that's used throughout an entire section of a site.
Reading the Cassette Bundle helper documentation I thought something like this would work.
#Bundles.Reference("/MyScripts/TheScript.js")
However it throws the following error:
Cannot find an asset bundle containing the path
I'd appreciate any advice. I feel like this is such a simple question that I must be missing something obvious.
bundles.Add<ScriptBundle>("MyBundle", new[]{ "path/to/script/script.js"});

multiple script tags and concatenation + minification + preprocessing

I have a html file with multiple script tags(close to 20). I've decided to concatenate all the JS files into one and then minify the concatenated file. I am using ant tasks to concatenate and will do so for minification as well. I am aware that I need to provide the option of a non-concatenated/non-minified version for the purposes of debugging(aka in the dev env).
I was wondering how to achieve this. For ex: the file main.html has 20 script tags, one way I figured to do it was use a HTML preprocessor and conditionally include script tags:
#ifdef perf
<script src="main.min.js"></script>
#else
<script src="ctrl.js"></script>
<script src="services.js"></script>
<script src="directives.js"></script>
<script src="model.js"></script>
.
.
.P.S
<script src="file_no_20.js"></script>
#endif
main.min.js is the concatenated and minified file during the build process using ant.
Is there a better way of doing this? What are the downsides of this approach?
Thanks,
Chris.
P.S: Thinking of using the http://fmpp.sourceforge.net/ for html preprocessing, any other suggestions are appreciated.
Chrome supports an awesome feature called "source mapping" that is perfect for this. I'd suggest you read the guide here for more info:
http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
There are some caveats if you're using AngularJS in regards to minification. From the docs:
Since angular infers the controller's dependencies from the names of arguments to the controller's constructor function, if you were to minify the JavaScript code for PhoneListCtrl controller, all of its function arguments would be minified as well, and the dependency injector would not being able to identify services correctly.
To overcome issues caused by minification, just assign an array with service identifier strings into the $inject property of the controller function, just like the last line in the snippet (commented out) suggests:
PhoneListCtrl.$inject = ['$scope', '$http'];
There is also one more way to specify this dependency list and avoid minification issues — using the bracket notation which wraps the function to be injected into an array of strings (representing the dependency names) followed by the function to be injected:
var PhoneListCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */ }];
Both of these methods work with any function that can be injected by Angular, so it's up to your project's style guide to decide which one you use.
http://docs.angularjs.org/tutorial/step_05
I suggest using tag libraries, something like http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags4.html#67771 to acheieve this. Include your script's like:
<script:include src="myscript1.js" />
<script:include src="myscript2.js" />
<script:include src="myscript3.js" />
..
And the use a page parameter for your system to decide if the scripts has to be concatenated and minified. Something like below:
www.yourapp.com/app?debugMode=true
By default the scripts are concatinated and minified. If you are a developer working on the project just add a page parameter like debugMode=true. When debugMode is true, just render the scripts as it is.
There are many services out there in the market like http://developer.yahoo.com/yui/compressor/ that can be integrated with your project to do this job for you.
Do not compress the scripts everytime you load the page. Do it the first time and cache it so that you dont have to do it everytime. At any point of time to rebuild the latest script file, just add another parameter like ?rebuild=true so that all the latest files and minfied and cached. You could do the same with CSS too.

When using (only) a templating system, how should I manage CSS, javascript etc for sub-templates?

I've had this same question when working with different templating systems in different languages in the past, so first,
The general question
I want to use a sub-template to include a certain UI component which might appear in different places on a number of different pages. This UI component requires certain CSS and JS files.
I want to Do The Right Thing with CSS and JS resources, which, as far as I know and in broad terms, is to a) combine as many as possible b) minify as much as possible and maybe c) put what I can at the end of my markup so the browser doesn't have to wait for them to load before displaying content.
So, if I've got various different UI components, as well as different headers and sidebars in different sections of the site, which all require their own special CSS and JS to function correctly, what's the best way for me to manage them through a templating system so that the final markup is as small and well-organised as possible?
Specifics of my situation
I'm working on a large legacy PHP site, on which, to give the original authors the benefit of the doubt, development may have begun before MVC became really mainstream, and before there were so many choices of frameworks around to use. So there is no consistent MVC framework, no routing, no templating (no ORM either, but that particular curse isn't as relevant here).
I'm going to have to keep things ticking over, squashing bugs and adding a few new features until a complete rewrite is usable, so I'm trying to breathe some sanity into things as I go along.
The easiest place to start seemed to be the views layer, for which I'm using TinyButStrong. An example of their sub-templates can be found here, but like I said, I think this is a very general question.
Things I've considered
With a more integrated framework I'd like to be able to do something like $view->add_js($foo), but transitioning to a full-blown framework is what other people are doing while I try keep the existing codebase seaworthy. There isn't even really enough consistent organisation of files to roll something like this by hand.
At the moment the best thing I can come up with is making a DOMDocument out of the view right before it's output and manipulating <link> and <script> tags at that point. I don't know if that's a bit crazy though. Given the generality of the problem I'd like to think that there's a known sensible way to go about it.
Many thanks for your input.
It's hard for the reader to know what can or cannot be done with your code base. A common way to handle this situation would be to pass parameters to the view template, and the template can then include conditional chunks or include sub-templates based on your parameters. This does not require a full-fledged framework, a stand-alone template engine should do. If your template engine supports inheritance there is a nice pattern for handling assets in your templates - check here for example http://symfony.com/doc/2.0/book/templating.html.
Manipulating the Dom for each request to handle this kind of thing seems bit unorthodox.
What you want in this situation is some form of template inheritance; that is, technology whereby a sub-template has access to areas in a 'parent' template, and can edit or replace content in those areas. Using this ability, CSS and JS required for a component included via a sub-template can be added in to the <head> element of the parent page.
In Twig, this is achieved using named blocks. First, you create your parent template (or layout, as it's called in Twig), e.g. index.html.twig. You include in it a named block like {% block myCss %}.
Next, to create a sub-template, you begin the template with the line {% extends ::index.html.twig %}. Then, the content of a block defined in the sub-template with the same name as a block in the parent template (in this case {% block myCSS %}) will get substituted into the parent template. To append rather than replace content in the parent template, use {{ parent() }} to include content already existing in the parent.
An example of this with code is available at the link given by #Basel Shishani. I've heard that Twig is modelled after Django, and template inheritance in Django looks very similar (with the exception of using {{ block.super }} instead of {{ parent() }}. There is a discussion of how to achieve the same ends in TinyButStrong.
As a wider point, the Assetic library looks like a very promising solution for managing CSS and JS assets, in order to avoid duplication (e.g. where the same JS file is required by multiple components/subtemplates), enable concatenation and minification of assets, and more. This presentation of its features gives more details.

Categories

Resources