OnClick Scroll JavaScript in SilverStripe - scroll

I want to make a single page website in SilverStripe. I want a smooth scroll on click using JavaScript but I can't get this to work correctly.
page.ss
<article>
<div class="bgs" style="background-image:url($BackgroundImage.URL);">
<div class="rows">
$Content
</div>
</div>
</article>
JavaScript
$('.menus-nav-item a').on('click', function() {
var $root = $('html, body'),
var $this = $(this),
href= $this.attr('href');
$root.animate({
scrollTop: $(href).offset().top - 20
}, 1000, function() {
window.location.hash = href;
});
I get the following errors:
Uncaught Error: Syntax error, unrecognized expression: /#who-we-are
and
Uncaught TypeError: Cannot read property 'top' of undefined while
calling the class attribute

found the answer!
$(function() {
$('a[href*=\\#]:not([href=\\#])').click(function() {
if (location.pathname.replace(/^\//,'') ==
this.pathname.replace(/^\//,'')
|| location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' +
this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top -54
}, 1000);
return false;
}
}
});
});
});

Related

Summernote custom button with dialog

I want to add a custom button to the Summernote toolbar that opens up a dialog that has a textbox for a URL and several checkboxes for settings. I then want to use the info from the dialog to scrape web pages and do processing on the content. The ultimate goal is to place the scraped content into the editor starting where the cursor is. I've searched and found some code on creating a custom button, but not any solid examples of implementing a dialog. I went through the summernote.js code to see how the Insert Image dialog works and that left me really confused. The test code I've got so far is in the code block, below. Thanks in advance to anyone who can help get me sorted out.
var showModalDialog = function(){
alert("Not Implemented");
};
var AddWiki = function(context) {
var ui = $.summernote.ui;
var button = ui.button({
contents: '<i class="fa fa-plus"/> Add Wiki',
tooltip: "Set a New Wiki",
class: "btn-primary",
click: function() {
showModalDialog();
}
});
return button.render();
};
$(".tw-summernote-instance textarea").summernote({
airMode: false,
dialogsInBody: false,
toolbar: [["mybutton", ["customButton"]]],
buttons: {
customButton: AddWiki
},
callbacks: {
onInit: function(e) {
var o = e.toolbar[0];
jQuery(o)
.find("button:first")
.addClass("btn-primary");
}
}
});
I found a good, simple example of what I wanted to do. Here's the code:
(function(factory) {
/* global define */
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(window.jQuery);
}
}(function($) {
$.extend($.summernote.plugins, {
'synonym': function(context) {
var self = this;
var ui = $.summernote.ui;
var $editor = context.layoutInfo.editor;
var options = context.options;
context.memo('button.synonym', function() {
return ui.button({
contents: '<i class="fa fa-snowflake-o">',
tooltip: 'Create Synonym',
click: context.createInvokeHandler('synonym.showDialog')
}).render();
});
self.initialize = function() {
var $container = options.dialogsInBody ? $(document.body) : $editor;
var body = '<div class="form-group">' +
'<label>Add Synonyms (comma - , - seperated</label>' +
'<input id="input-synonym" class="form-control" type="text" placeholder="Insert your synonym" />'
'</div>'
var footer = '<button href="#" class="btn btn-primary ext-synonym-btn">OK</button>';
self.$dialog = ui.dialog({
title: 'Create Synonym',
fade: options.dialogsFade,
body: body,
footer: footer
}).render().appendTo($container);
};
// You should remove elements on `initialize`.
self.destroy = function() {
self.$dialog.remove();
self.$dialog = null;
};
self.showDialog = function() {
self
.openDialog()
.then(function(data) {
ui.hideDialog(self.$dialog);
context.invoke('editor.restoreRange');
self.insertToEditor(data);
console.log("dialog returned: ", data)
})
.fail(function() {
context.invoke('editor.restoreRange');
});
};
self.openDialog = function() {
return $.Deferred(function(deferred) {
var $dialogBtn = self.$dialog.find('.ext-synonym-btn');
var $synonymInput = self.$dialog.find('#input-synonym')[0];
ui.onDialogShown(self.$dialog, function() {
context.triggerEvent('dialog.shown');
$dialogBtn
.click(function(event) {
event.preventDefault();
deferred.resolve({
synonym: $synonymInput.value
});
});
});
ui.onDialogHidden(self.$dialog, function() {
$dialogBtn.off('click');
if (deferred.state() === 'pending') {
deferred.reject();
}
});
ui.showDialog(self.$dialog);
});
};
this.insertToEditor = function(data) {
console.log("synonym: " + data.synonym)
var dataArr = data.synonym.split(',');
var restArr = dataArr.slice(1);
var $elem = $('<span>', {
'data-function': "addSynonym",
'data-options': '[' + restArr.join(',').trim() + ']',
'html': $('<span>', {
'text': dataArr[0],
'css': {
backgroundColor: 'yellow'
}
})
});
context.invoke('editor.insertNode', $elem[0]);
};
}
});
}));

How can we use several google recaptchas in the same page?

When i put
<script>
var renderCaptchas = function() {
grecaptcha.render(this, {
'sitekey' : {{ google_recaptcha_site_key }}
});
};
var onloadCaptchaCallback = function () {
Array.prototype.forEach.call(document.querySelectorAll('.g-recaptcha'),
renderCaptchas);
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCaptchaCallback&render=explicit" async defer></script>
I have this error :
reCAPTCHA couldn't find user-provided function: onloadCaptchaCallback
The function is yet well defined ...
If i remove
grecaptcha.render(this, {
'sitekey' : {{ google_recaptcha_site_key }}
});
Then it finds the callback ...
I use the Google ReCaptcha v2, with the checkbox "mode".
There is something strange in your loop for me and grecaptcha.render(this !? this = renderCaptchas ... no !? So the element you want to render is not good because it is not a valid html container.
<script>
var renderCaptchas = function(element) {
grecaptcha.render(element, {
'sitekey' : 'google_recaptcha_site_key'
});
};
</script>
or something like :
<script>
var onloadCaptchaCallback = function () {
[].forEach.call(document.querySelectorAll('.g-recaptcha'), function(element){
grecaptcha.render(element, {
'sitekey' : 'google_recaptcha_site_key'
});
}
});
};
</script>
How to loop over document.querySelectorAll :
How to loop through selected elements with document.querySelectorAll

Call from one widget to another widget using odoo js

Js Xml Path : module_name-static-src-xml:
<div t-name="widget_1">
<button type="button" id = "button_1" >Click</button>
<div id = "test"> </div>
</div>
<div t-name="widget_2">
<p>Second Widget</p>
</div>
Js:
odoo.define("module_name.name", function(require) {
"use strict";
var Widget = require("web.Widget");
var Widget_Extend = Widget.extend({
template: "widget_1",
start: function() {
var self = this;
$(document).ready(function(){
setTimeout(function(){
$(document).on("click", "#button_1", function() {
var widget_call = '';
widget_call = '<div id ="test"></div>'
widget_call + = '<t t-call="widget_2"/>'
$('#test').html(widget_call);
});
});
});
}
});
core.action_registry.add("module_name.name", Widget_Extend);
});
Note:
I have tried to call "widget_2" using js but i could not get what i expect. I am not sure this the way to call the widget but i have tried a lot. If any one have some other way to call the 2nd widget from 1st widget using js kindly let me know.
Anticipating all kind of information about this problem.
Thanks.
you can inherited a widget to another widget As an example, it may look like this:
// in file a.js
odoo.define('module.A', function (require) {
"use strict";
var A = ...;
return A;
});
// in file b.js
odoo.define('module.B', function (require) {
"use strict";
var A = require('module.A');
var B = ...; // something that involves A
return B;
});

angular-slick carousel not working when using promise

This is driving my crazy, the first angular-slick is not working but the second is just fine, any idea what is going on?
I created a plunkr (in case someone is looking for an example in the future), but my problem is very odd because in my code/realproject is not working so I don't know what the hell is going on, anyway! here is the plunkr: http://plnkr.co/edit/URIbhoVpm1OcLSQqISPs?p=preview
I think the problem is related to the DOM because maybe angular needs to create the html before the carousel is render, I don't know... :(
This is the outcome:
https://db.tt/noc0VgGU
Router:
(function() {
'use strict';
angular
.module('mgxApp.landing')
.config(configFunction);
configFunction.$inject = ['$routeProvider'];
function configFunction($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'app/landing/landing.html',
controller: 'homeCtrl',
controllerAs: 'hC'
});
}
})();
Controller:
(function() {
'use strict';
angular
.module('mgxApp.landing')
.controller('homeCtrl', homeCtrl);
homeCtrl.$inject = ['modalFactory', 'channelFactory'];
function homeCtrl(modalFactory, channelFactory) {
var hC = this;
hC.openAuthModal = modalFactory.openAuthModal;
hC.activeChannels;
channelFactory.allActiveChannels().then(function(activechannels){
console.log(activechannels);
hC.activeChannels = activechannels;
});
hC.w = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
hC.breakpoints = [
{
breakpoint: 768,
settings: {
slidesToShow: 2,
slidesToScroll: 2
}
}, {
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1
}
}
];
}
})();
HTML VIEW:
// NOT WORKING
<slick class="slider single-item" responsive="hC.breakpoints" slides-to-show=3 slides-to-scroll=3>
<div ng-repeat="channel in hC.activeChannels">
{{channel.get("username")}}
</div>
</slick>
// Working fine
<slick class="slider single-item" current-index="index" responsive="hC.breakpoints" slides-to-show=3 slides-to-scroll=3>
<div ng-repeat="i in hC.w">
<h3>{{ i }}</h3>
</div>
</slick>
Factory and Promise:
(function () {
'use strict';
angular
.module('mgxApp.channel')
.factory('channelFactory', channelFactory);
channelFactory.$inject = ['$rootScope', '$q'];
function channelFactory($rootScope, $q) {
var service = {
allActiveChannels : allActiveChannels
};
return service;
function allActiveChannels() {
var deferral = $q.defer();
var User = Parse.Object.extend("_User");
var query = new Parse.Query(User).limit(10);
query.find({
success: function(users) {
console.log(users);
/*for (var i = 0; i < users.length; i++) {
console.log(users[i].get("username"));
}*/
deferral.resolve(users);
},
error: function(error) {
console.warn(error);
deferral.reject();
}
});
return deferral.promise;
}
}
})();
My working code
<div tmob-slick-slider sliderData="" dynamicDataChange="true" class="utilHeightImg marqueeContainer">
<slick id="productCarousel" class="slider" settings="vm.slickAccessoriesConfig" data-slick='{"autoplay ": true, "autoplaySpeed": 4000}'>
<!-- repeat='image' -->
<div ng-repeat="slideContent in vm.slides track by $index" >
<div bind-unsafe-html="slideContent" ></div>
</div>
<!-- end repeat -->
</slick>
</div>
you have to write a directive to reinitialize the slider
angular.module('tmobileApp')
.directive('tmobSlickSlider',['$compile',function ($compile) {
return {
restrict: 'EA',
scope: true,
link: function (scope, element, attrs) {
scope.$on('MarqueesliderDataChangeEvent', function (event, data) {
$compile(element.contents())(scope);
});
}
};
}]);
Write this in your controller
hc.selectView=false; // make this hc.selectView=true when your promise get resolve
$scope.$watch('hc.selectView', function(newValue, oldValue) {
$scope.$broadcast('MarqueesliderDataChangeEvent');
});
I ended up using this solution:
Angular-slick ng-repeat $http get
I'd suggest you to use ng-if on slick element. That will only load slick directive only when data is present just by checking length of data.
Markup
<slick ng-if="ctrl.products.length">
<div ng-repeat="product in ctrl.products">
<img ng-src="{{product.image}}" alt="{{product.title}}"/>
</div>
</slick>

how to implement onpopstate? confused after reading so many things

I am loading content using AJAX, and changing URL by using pushastate, below is my code, can anybody tell me how to implement onpopstate to enable back button in my case.
HTML
<div id="tabs" style="margin:1px 0px 0px 15px;">
<ul class="tabs-ul">
<li id="boardLi" class="current-tab"><a class="current-tab" href="board.jsp">Board</a></li>
<li id="aboutLi">Info</li>
<li id="photoLi">Photo Albums</li>
</ul>
</div>
JS
$(document).ready(function() {
function loadContent(path,c,pageName){
$.ajax({ url: path, success: function(html) {
$('#ajax-content').empty().append(html);
window.history.pushState({path:''},'',pageName+'?tab='+c);
}
});
}
function checkC(target){
var c='';
if(target=='aboutme.jsp')
{c='info';}
else if(target=='board.jsp')
{c='board';}
else if(target=='photo.jsp')
{c='photo';}
else if(target=='tab.jsp')
{c='ht';}
return c;
}
$(".tabs-ul li a").on('click', function(e) {
e.preventDefault();
$('#ajax-content').empty().append("<div id='loading'><img src='images/preloader.gif' alt='Loading' /></div>");
$('.tabs-ul li a').removeClass('current-tab');
$('.tabs-ul li').removeClass('current-tab');
$(this).addClass('current-tab');
$(this).parent().addClass('current-tab');
var url = window.location.pathname;
var pageName = url.substring(url.lastIndexOf('/') + 1);
var target=$(this).attr('href');
var c=checkC(target);
loadContent(target,c,pageName);
return false;
});
var loaded = false;
window.onpopstate = function(e) {
if (!loaded) {
loaded = true;
return;
} else {
alert(window.loacation.back().pathname);
loadContent();
}
};
});
When user clicks on link, first of all I am adding removing class for loading then I am getting URL and getting the page name from that URL(saved in 'pageName'), 'target' is href attr of clicked link and 'c' is the value I will be showing in url(for example, example.com/profile.jsp?tab=info, here if the href is info.jsp then 'c' would be info), finally I am calling 'loadContent' function which loads ajax content and changes URL using pushState.

Resources