How to customize Silverstripe login page content? - silverstripe

I'm using SilverStripe 3.5.3 I want to customize content ($Content) of the Security/login page. How do I do it?

You can also modify the page template by putting a template file named Security_login.ss in your templates/Layout directory.
The contents of one i've used in a previous project is:
<div class="row security-spacer">
<div class="large-12 columns">
<h1>$Title</h1>
<div class="typography">$Content</div>
<div class="row">
<div class="large-6 columns">
$Form
</div>
</div>
</div>
</div>
You can also create templates for
Security_changepassword.ss
Security_lostpassword.ss
Security_passwordsent.ss

You could extend the LoginForm class and create your own LoginForm anyway you like. You could base it off of the MemberLoginForm.php class.
Check out this article here which may help.

I know the OP asked specifically for its theme, but in case someone wants to know how to do it on the code side of things, you can use the request object to determine that, like this:
/mysite/code/Page.php
public function anyMethod() {
$value = 'default';
if (Controller::curr()->getRequest()->getURL() === 'Security/login') {
$value = 'something else';
}
return $value;
}
(On SilverStripe 4.1.0, anyway)

Related

How do I pass data up from the child page to the page calling #Body?

So I have a MainLayout with a title bar, and I want to have a parameter that allows the page to set the title bar to whatever it wants. So mainlayout calls the page through #Body, I'm confused how I would pass data up through body to the mainlayout to update the title bar.
Any help would be greatly appreciated!
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
<h3 bind="#TitleValue">#(TitleValue)</h3>
<a class="ml-md-auto">#ADService.LoggedUser().DisplayName (#*#(ADService.LoggedUser().IsMemberOf())*#Admin)</a>
</div>
<CascadingValue Value="#TitleValue" Name="TitleValue">
<div class="content px-4">
#Body
</div>
</CascadingValue>
</div>
<Footer />
#functions {
string TitleValue = "Inventory";
}
So what I want to do is pass the TitleValue down, have the page update it depending what is happening and have the title bar update with the new value.
If this isn't the way to do it, or I'm missing something, any help would be great :)
I guess the following, which is not mine, can help you:
Create a class which holds your data. Register it as singleton
service. Inject it into layout and into page. You should probably add
a notification mechanism to inform all your components that something
was changed in your data class.
You can look here...
Source and more...

Add CSS to ScalaHelpers

How do i add some CSS to the Scala Helpers, and is it possible to remove the "Required" and "Numeric" text under the textfield?
#inputText(advForm("weeknr"))
#inputText(advForm("jaar"))
#inputText(advForm("datum"))
--------------------EDIT 1------------------
When I add my own CSS, im not getting the error warnings that i used to get when I try to upload an empty form, the text used to turn red. This is the code I changed
MyPlainFieldConstructor.scala.html(only 2 lines of code):
#(elements: helper.FieldElements)
#elements.input
advPlaatsen2.scala.html:
Added this line of code
#implicitField = #{ FieldConstructor(myPlainFieldConstructor.f) }
and this is how i placed the CSS(Foundation 5):
<div class="row collapse">
<div class="small-2 columns">
<span class="prefix">Email</span>
</div>
<div class="small-4 left columns">
#inputText(advForm("email"),
'id -> "right-label",
'placeholder -> "")
</div>
</div>
This way the forms looks how I want it to look but it doesnt show me errors and it doesnt even upload my files
but when i remove this line of code:(which is above the #import helper._)
#implicitField = #{ FieldConstructor(myPlainFieldConstructor.f) }
the form works as it should but looks really bad:
To customize the html and styles of a field you can write your own field constructor. Take a look to play docs here.

How do i get an onload function on the body for a specific template using meteor.js?

I'm trying to get the following behavior for a certain template:
<body onload="someInitFunction();">
Let's say i have the following markup (i'm using mrt router, not iron-router, for {{renderPage}}):
// Main Template
<head>
<title>meteorite-knowviz</title>
</head>
<body>
{{> header}}
<div class="container-fluid">
<div class="row">
{{renderPage}}
</div>
</div>
{{> footer}}
</body>
That renderPage is the secondTemplate:
<template name="secondTemplate">
{{#if currentUser}}
<div class="col-md-2">
<div class="list-group">
<a class="list-group-item" href="{{render thirdTemplate please...}}">Third Template</a>
<a class="list-group-item" href="{{render fourthTemplate please...}}">Fourth Template</a>
</div>
</div>
// In this case let's say thirdTemplate gets rendered
{{render the choice taken above please...}}
{{/if}}
</template>
And within this template, depending on which link was clicked on, (in this case the third) there will finally be a thirdTemplate, which will show a data visualization with some help by a javascript framework, which will be in need of a <body onload="initFunction();">in order to display the data:
<template name="thirdTemplate">
<div class="col-md-5">
<h2>THIS!! section needs a "<body onload="initFunction();"> in order to work" ></h2>
</div>
<div class="col-sm-5">
<h2>Some other related content here</h2>
</div>
</template>
To sum up i have three questions:
1a. How could i get the third template to get a <body onload="initFunction();">
2a. In which way can i render different templates within the secondTemplate?
2b. Can i use a {{renderPage}} within this template even though this template is the renderedPage in the main template or should i do it in some other way?
In order to get the <body onload="initFunction();"> i had to do the following:
First add the following function to a .js file in the client folder:
Template.thirdTemplate.rendered = function() { // Template.thirdTemplate.created - also worked.
$('body').attr({
onload: 'init();'
});
}
This however got me an error saying that initFunction is not defined. In an standard html page my could work just fine, but in meteor i had to change my function from:
function initFunction(){
//what ever i wished to do
}
To:
init = function() {
//what ever i wished to do
}
Regarding the rendering of pages, iron-routing is the way to go since the router add on is not under development any more.
1a. How could i get the third template to get a <body
onload="initFunction();">
You probably want to call initFunction when the third template has been rendered, so just put your call to it in the rendered callback.
Template['thirsTemplate'].rendered = function(){
initFunction()
}
2a. In which way can i render different templates within the
secondTemplate?
2b. Can i use a {{renderPage}} within this template even though this
template is the renderedPage in the main template or should i do it in
some other way?
Listen for clicks on the links, and when one happen you manually render the desired template (possible with Meteor.render, if you need reactivity) and add it to the right node in the document. See this question.
It may be possibly to achieve with router (I don't know that package).
I think that what you want to use is the created callback, that will be called each time your template is created, and not the rendered callback, that would be called each time a change has caused the template to re-render.
Template.thirdTemplate.created = function(){
initFunction()
}
See the documentation for templates for other types of callbacks: http://docs.meteor.com/#templates_api

Using Angular Masonry in AngularJS?

I have a layout like this. I am using passsy extension for angular masonry.
<masonry column-width="200">
<div class="masonry-brick" ng-repeat="data in comments">
<div ng-switch on="data.type">
<div ng-switch-when="hoots">
<article class="hoot_main">
//content goes here
//hoot_main is the main class for this div layout
</article>
</div>
</div>
</div>
<div ng-switch on="data.type">
<div ng-switch-when="article">
<article class="hoot_main">
//content goes here
//hoot_main is the main class for this div layout
</article>
</div>
</div>
<div ng-switch on="data.type">
<div ng-switch-when="story">
<article class="hoot_main">
//content goes here
//hoot_main is the main class for this div layout
</article>
</div>
</div>
</div>
</masonry>
Browser is getting hanged whenever I use it. Debugging script with tools says element.masonry is not a function.
Any help would be appreciated!
Hmm, at the moment I work from my laptop at home and I can't get passy's version running too and can not put my finger on the issue. But this is what I can offer you for now:
I made a very simple directive based on things I've read somewhere:
app.directive('masonry', function() {
return {
restrict: 'AC',
controller: function($scope) {
return $scope.$watch(function(e) {
$scope.masonry.reloadItems();
return $scope.masonry.layout();
});
},
link: function(scope, elem, attrs) {
var container=elem[0];
var options='';
return scope.masonry = new Masonry(container,options);
}
};
As you can see it does not have a any options by now. When i'm at work on monday i will have a look at my sources on a proper dual screen display and provide you with a better version.
My wife is starting to giving me the looks and I need to put the laptop away now. :-\
You can see in this plunker that it kinda works now. Maybe this can help you. In the meantime can you add some of your json data to your question? Have a nice weekend for now!
In order to get Passy's angularjs directive working you must include all the files as listed per the index file
I had this error, fixed it by including the original Masonry code. I was also thinking this was a pure angular port.

CSS that operates like a boolean AND for multiple complex selectors?

I'm writing a Stylish user style sheet, and am trying to see if something is possible. I am customizing a page that has a structure like this:
<div class="main">
<div class="someExtraLayers">
<div class="page">
1
</div>
</div>
<div class="someOtherLayers">
<div class="post">
blah blah
</div>
<div class="post">
foo foo
</div>
<div class="post">
bar bar
</div>
</div>
</div>
Where 'someExtraLayers' and 'someOtherLayers' indicate a few levels of divs inside divs. I'm not fully replicating the page's structure here for brevity's sake.
I have this in my user CSS:
div.post:nth-child(1) {
display:block !important;
}
Essentially, I'm making visible the first post element, and this does most of what I want to do. The thing I want to add is that I only want to make that element visible if the content of the page class is 1. If it's not 1, then I don't want to display the first post element.
CSS doesn't seem to offer conditionals, or boolean ANDs, that work this way. But I'm still new-ish to CSS, so I might be missing something. If I have to use a Greasemonkey script instead, I'll do that, but I was hoping there's some CSS trickery that will let me accomplish this.
Stylish cannot do this because Stylish just injects CSS and CSS does not have a selector for text content.
To do what you want, you will have to install Greasemonkey (Firefox) or Tampermonkey (Chrome) and then a userscript can set that visibility.
Assuming that div contains only 1, then something like this complete GM/TM script will do what you want. It uses the awesome power of jQuery selectors.
You can also see a live demo of the code at jsFiddle. :
// ==UserScript==
// #name _Show the first post on page 1
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// #grant GM_addStyle
// ==/UserScript==
var pageHasOne = $("div.main:has(div.page:contains(1))");
pageHasOne.each ( function () {
var jThis = $(this); //-- this is a special var inside an .each()
var pageDiv = jThis.find ("div.page:contains(1)");
if ($.trim (pageDiv.text() ) == "1") {
//--- Show the first post div. !important is not needed here.
jThis.find ("div.post:first").css ("display", "block");
}
} );
Given the logic that jQuery javascript must use, we can see part of the reason why CSS doesn't attempt to provide selectors for this. It's beyond mission scope for CSS, but the kind of thing that javascript was made for.
Also note that this is for a static page. If the page uses AJAX for its content, the logic becomes a bit more involved.
CSS can not access HTML content.
To solve the problem, you will also need to add a class so CSS can "see" it:
HTML:
<div class="main one">
<div class="someExtraLayers">
<div class="page">
1
</div>
</div>
<div class="someOtherLayers">
<div class="post">
blah blah
</div>
<div class="post">
foo foo
</div>
<div class="post">
bar bar
</div>
</div>
</div>
CSS:
.one .post:nth-child(1) {
display:block !important;
}

Resources