Silverstripe: How to add custom css/js from module - silverstripe

I am building a small module that replaces the default FileField in Silverstripe and changes it into a fancier upload (in the front end). I replace the class through the injector method in Yaml. This seems to be working all right.
However, I need to add some js and css that only has to be included when the specific field is used. I tried the forTemplate method and the constructor of the filefield class, but both do not result in the files being added to the html.
Is there a way to do this?
I am using SS 3.4

You can add requirements in the CMS by adding the following to your config.yml file, however this will add globally...
LeftAndMain:
extra_requirements_css:
- mymodule/css/mymodule.css
extra_requirements_javascript:
- mymodule/javascript/mymodule.js
Instead including the required source files just within the FormField constructor would include just when this field is shown...
Requirements::javascript("mymodule/javascript/mymodule.js");
Requirements::css('mymodule/css/mymodule.css');
You can also add code directly possibly including values from the PHP like this...
Requirements::customCSS('
#Form_FilterForm .field {
display:inline-block;
width:31%
}
');
Requirements::customScript('
jQuery(document).ready(function(){
//JS Code here
});
');
Or as above but it must be included in the header...
Requirements::insertHeadTags("
<style>
#Form_FilterForm .field {
display:inline-block;
width:31%
}
</style>
<script>
jQuery(document).ready(function(){
//JS Code here
});
</script>
");

Related

Custom js added in custom module in magento

I have created a module. In this a custom js file is added with requirejs-config.js, But to load the js file, I need to write the following lines on phtml,
<script type="text/javascript">
require(['jquery','customjs']});</script>
If I don't add the above line js is not adding .Can some body please tell is this the right approach or I am doing some thing wrong.
Require js code added at (Namespace\Modulename\view\frontend)
define([
'jquery',
'underscore',
'mage/template',
], function (
$,
_,
template
) {
//custom code
});
Yes this is the right approach. because you have created custom.js right . so that custom.js you need to call in your requirejs-config.js
But now when you want to use this actuall js functions and properties you need to pass below code
<script type="text/javascript">
require(['jquery','customjs']});</script>
What it mean actually , to load your customjs it requires jquery so first load the jquery then load your customjs and then you can pass the parameters.
require([ 'jquery', 'customjs'], function(){
alert("test");
});
so alert box will prompt when you add this in your template
Jfyi - in your requirejs-config.js you need to write like below code you dont'need to write extension of js file like.js as require js automatically render that . and lastly put the js file in web/js folder in your module
var config = {
"map": {
"*": {
"customjs": "Vendor_Modulename/js/custom"
}
}
};

(AngularJS) Only one less file for entire Website

I am a beginner with AngularJS and I have a little problem, I installed grunt-contrib-less to support less files instead css but now I have to declare all less styles that will be compiled into only one css file.
But my problem is normally when I'm using less, I write some code for a specific page, and here I have to write the style code for all pages. This is confusing and not really maintanable so is there a best practice to organize less styles?
I tought that there may be multiple solution:
Apply a class to body tag and change it with I don't know what
(controller, services or other)
(Import LESS file only for one page)
Generate multiple css file depending which style is compiled (but I can't do this because I can't configure grunt correctly)
Do this with DOM manipulation (but it don't find it beautifull because I think Angular must have a good way to solve that problem)
Could you explain me how to have different style for differents views ? I don't want to have the same style for all links in all views and without create hundreds classes I don't know how to do that.
Use directive
and add whatever variables/code/logic you want to add
HTML template(directive) of style can be added to your view and after compile you will get different ui for all your views
for reference read
angular directive
I solve my problem by adding specific class on body tag depending the route.
I put a variable in rootScope called 'pageStyle' with correspond to the classname that I want. This variable is updated automatically when route change (see run function). There is an event when the route change ($stateChangeSuccess or $routeChangeSuccess depending if you are using ngRoute or -angularui-routeur).
In my case i would like to add the name of the route but you can do it with the controller name or something else.
Here is an example
This is the routes :
angular
.module('frontApp', [])
.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider, $mdThemingProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: '../views/home.html',
controller: function ($scope) {
$scope.msg = 'Xavier';
}
})
.state('form', {
url: '/form',
templateUrl: '../views/form.html',
controller: 'FormCtrl'
});
}])
And in the run function you will see the event bound to adapt the class when route change :
.run(function($rootScope) {
$rootScope.pageStyle = '';
// Watch state and set controller name in pageStyle variable when state change
$rootScope.$on('$stateChangeSuccess', function(event, toState) {
event.preventDefault();
if (toState && toState.name && typeof toState.name === 'string'){
$rootScope.pageStyle = toState.name;
} else {
$rootScope.pageStyle = '';
}
});
});
Extra informations :
Note that the event called when route change is different if you are using ngroute. use "$routeChangeSuccess" if you use ngRoute and "$stateChangeSuccess" if you choose to use angular-ui-routeur
If you want to add the controller name instead the route name simply use the follow and replace 'ctrl' with you controller suffixe:
if (toState && toState.controller && typeof toState.controller !== 'function'){
$rootScope.pageStyle = toState.controller.toLowerCase().replace('ctrl','');
}
Hope it help someone else

How to add dynamically css in AngularJS?

Hi I am trying to add css dynamically but it's not working bellow is my code
angular.module('myApp', [ 'myApp.controllers','myApp.services']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/new', { templateUrl: 'partials/add.html', controller: 'add' ,resolve: {
style : function(){
/* check if already exists first - note ID used on link element*/
/* could also track within scope object*/
alert("DSAF");
angular.element('head').append(' <link rel="stylesheet" href="css/app.css"/>');
}
}}) }]);
Without more info on your code it will be difficult to help but anyway here are a two (easy) things that come to my mind :
Be sure that the path css/app.css redirects to a file i.e no 404,
angular.element('head') will work only if jquery is loaded before angular otherwise you will have an error regarding jqLite.
Finally I have assemble a plunker here where everything is working the way it should base on your extract of code. Let me know if it helps.

Excluding bootstrap from specific routes in Meteor

I was hoping anyone could give some input on this,
I'm creating a meteor app in which I would like to use bootstrap to creating the admin environment, but have the visitor facing side using custom css. When I add the bootstrap package to my app using meteor it's available on every page, is there a way to restrict the loading of bootstrap to routes that are in '/admin' ?
When you add bootstrap package it's not possible. You can, however, add bootstrap csses to public directory and then load them in a header subtemplate that will only be rendered when you're in the dashboard.
EDIT
But then how would you go about creating seperate head templates?
Easy:
<head>
...
{{> adminHeader}}
...
</head>
<template name="adminHeader">
{{#if adminPage}}
... // Put links to bootstrap here
{{/if}}
</template>
Template.adminHeader.adminPage = function() {
return Session.get('adminPage');
}
Meteor.router.add({
'/admin': function() {
Session.set('adminPage', true);
...
}
});
DISCLAIMER: I am unsure of a 'meteor way' to do this, so here is how I would do it with plain JS.
jQuery
$("link[href='bootstrap.css']").remove();
JS - Credit to javascriptkit
function removejscssfile(filename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist from
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(filename)!=-1)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
}
removejscssfile("bootstrap.css", "css")
However, doing that would complete remove it from the page. I am not sure whether meteor would then try to readd it when a user goes to another page. If that does not automatically get readded, then you have an issue of bootstrap not being included when someone goes from the admin section to the main site, which would break the look of the site.
The way I would get around that would be to disable and enable the stylesheets:
Meteor.autorun(function(){
if(Session.get('nobootstrap')){
$("link[href='bootstrap.css']").disabled = true;
}else{
$("link[href='bootstrap.css']").disabled = false;
}
});
There my be other bootstrap resources which may need to be removed, take a look at what your page is loading.
To use jQuery in the same way but for the javascript files, remember to change link to script and href to src
From my tests, Meteor does not automatically re-add the files once they have been removed so you would need to find some way of re-adding them dynamically if you want the same user to be able to go back and forth between the main site and the admin site. Or simply if the http referrer to the main site is from the admin, force reload the page and then the bootstrap resources will load and everything will look pretty.
P.s. make sure you get the href correct for the jQuery version
If somebody is interested in including any js/css files, I've written a helper for it:
if (Meteor.isClient) {
// dynamic js / css include helper from public folder
Handlebars.registerHelper("INCLUDE_FILES", function(files) {
if (files != undefined) {
var array = files.split(',');
array.forEach(function(entity){
var regex = /(?:\.([^.]+))?$/;
var extension = regex.exec(entity)[1];
if(extension == "js"){
$('head').append('<script src="' + entity + '" data-dynamicJsCss type="text/javascript" ></script>');
} else if (extension == "css"){
$('head').append('<link href="' + entity + '" data-dynamicJsCss type="text/css" rel="stylesheet" />');
};
});
}
});
Router.onStop(function(){
$("[data-dynamicJsCss]").remove();
});
}
Then simply use:
{{INCLUDE_FILES '/css/html5reset.css, /js/test.js'}}
in any of your loaded templates :)

javascript contents are not getting loaded,if i create a tab/contentPane dymaically with .xhtml as input

I am creating a dynamic tab/contentPane as below in home.xhtml file and i am trying to call a function display which is present in order.xhtml,its not getting called. what ever java script is there in order.xhtml is not getting loaded.
In home.xhtml
if(dijit.byId('ordersummary')!=null){
dijit.byId('ordersummary').destroy();
}
newTab= new dijit.layout.ContentPane({
id : 'ordersummary',
title : 'Order Summary',
href : 'order.xhtml',
closable : true
});
dijit.byId('tabContainer').addChild(newTab);
dijit.byId('tabContainer').selectChild(dijit.byId("ordersummary"));
javascript in order.xhtml
<script type="text/javascript">
//<![CDATA[
function display(){
alert(" I M BEING CALLED");
}
</script>
There are two ways about this, either a make the script type dojo/method.
Or use the extended dojox/layout/ContentPane.
http://livedocs.dojotoolkit.org/dijit/layout/ContentPane#executing-javascript-inside-contentpane
While I'm not familiar with the dojo toolkit, I think you should put the JavaScript function in the main file or load the JavaScript dynamically like;
How do I include a JavaScript file in another JavaScript file?
dijit.layout.ContentPane will not support javascript,i mean it will not execute the javascript content in the input file.
dojox.layout.ContentPane is advanced one and it will support javascript.

Resources