How to override YUI function in moodle? - yui

I need to override M.util.init_block_hider function in moodle. The reason is to override the blockicons with my custom ones. I can see piece of code inside the function, as follows:
Y.extend(blockhider, Y.Base, blockhider.prototype, {
NAME : 'blockhider',
ATTRS : {
id : {},
preference : {},
iconVisible : {
value : M.util.image_url('t/switch_minus', 'moodle')
},
iconHidden : {
value : M.util.image_url('t/switch_plus', 'moodle')
},
block : {
setter : function(node) {
return Y.one(node);
}
}
}
});
where the urls for images are stated. I want to reuse this function and override the url in my theme so that only block icons could be replaced. Any thoughts and ideas are welcome.
Here is the complete function inside /lib/javascript-static.js file:
M.util.init_block_hider = function(Y, config) {
Y.use('base', 'node', function(Y) {
M.util.block_hider = M.util.block_hider || (function(){
var blockhider = function() {
blockhider.superclass.constructor.apply(this, arguments);
};
blockhider.prototype = {
initializer : function(config) {
this.set('block', '#'+this.get('id'));
var b = this.get('block'),
t = b.one('.title'),
a = null;
if (t && (a = t.one('.block_action'))) {
var hide = Y.Node.create('<img class="block-hider-hide" tabindex="0" alt="'+config.tooltipVisible+'" title="'+config.tooltipVisible+'" />');
hide.setAttribute('src', this.get('iconVisible')).on('click', this.updateState, this, true);
hide.on('keypress', this.updateStateKey, this, true);
var show = Y.Node.create('<img class="block-hider-show" tabindex="0" alt="'+config.tooltipHidden+'" title="'+config.tooltipHidden+'" />');
show.setAttribute('src', this.get('iconHidden')).on('click', this.updateState, this, false);
show.on('keypress', this.updateStateKey, this, false);
a.insert(show, 0).insert(hide, 0);
}
},
updateState : function(e, hide) {
M.util.set_user_preference(this.get('preference'), hide);
if (hide) {
this.get('block').addClass('hidden');
} else {
this.get('block').removeClass('hidden');
}
},
updateStateKey : function(e, hide) {
if (e.keyCode == 13) { //allow hide/show via enter key
this.updateState(this, hide);
}
}
};
Y.extend(blockhider, Y.Base, blockhider.prototype, {
NAME : 'blockhider',
ATTRS : {
id : {},
preference : {},
iconVisible : {
value : M.util.image_url('t/switch_minus', 'moodle')
},
iconHidden : {
value : M.util.image_url('t/switch_plus', 'moodle')
},
block : {
setter : function(node) {
return Y.one(node);
}
}
}
});
return blockhider;
})();
new M.util.block_hider(config);
});
};

This should work...then you just set the new vis/invis icon and call this.get('iconVisible') and it should chain through.
Y.extend(blockhider, Y.Base, blockhider.prototype, {
NAME : 'blockhider',
ATTRS : {
id : {},
preference : {},
iconVisible : {
value : M.util.image_url(this.get('visIcon'), 'moodle')
},
iconHidden : {
value : M.util.image_url(this.get('invisIcon'), 'moodle')
},
visIcon:{value: 't/switch_plus'},
invisIcon:{value: 't/switch_minus'}
block : {
setter : function(node) {
return Y.one(node);
}
}
}
});

Related

writefilesync not writing all variables to a json file

I have this code:
circular = () => { //fix circular stuff for json.stringify
seen = new WeakSet();
return (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
var gameon = 1;
var fighter1 = {"userid":"97","username":"john","items":{},"ailments":{}};
var fighter2 = {"userid":"91","username":"james","items":{},"ailments":{}};
var resume = 30;
all = {gameon:gameon,fighter1:fighter1,fighter2:fighter2,resume:resume,inturn:fighter1,outturn:fighter2};
fs.writeFileSync(file,JSON.stringify(all,circular()),{encoding:'utf8',flag:'w'});
I expect to have the next output written to file:
{
"gameon":1,
"fighter1":{
"userid":"97",
"username":"john",
"items": {},
"ailments":{}
},
"fighter2":{
"userid":"91",
"username":"james",
"items":{},
"ailments":{}
},
"resume":"",
"inturn":{
"userid":"97",
"username":"john",
"items":{},
"ailments":{}
},
"outturn":{
"userid":"91",
"username":"james",
"items":{},
"ailments":{}
}
but this is what I get instead:
{
"gameon":1,
"fighter1":{
"userid":"97",
"username":"john",
"items":{},
"ailments":{}
},
"fighter2":{
"userid":"91",
"username":"james",
"items":{},
"ailments":{}
},
"resume":""
}
Please notice how the string truncates after "resume" like it couldn't read the variables fighter1 and fighter2 despite it could do it for the first iteration.
Why is that?
Thank you.

Uncaught TypeError: Cannot set property 'rowsdata' of undefined

I am stuck at some point working with angular 2 with node js. below is my code. It couldn't set rows(variable) to this.rowsdata (variable).
I think the reason behind is that node Js uses asynchronous call. May be that's why this.rows data get undefined for rows.
/// <reference path="../typings/node/node.d.ts" />
import { Component } from 'angular2/core';
import { OnInit } from 'angular2/core';
declare var module : any;
declare var jQuery : any;
var rowsdata : any[] = [];
// self = this;
interface ROWS {
name : string,
current_balance : number
}
#Component({
selector : 'portfolioList',
templateUrl : '../app/view/portfoliolist.html',
moduleId : module.id
})
export class PortfolioList implements OnInit {
// self : any = this;
constructor() {
// var self : this;
}
ngOnInit(): any {
this.showdata();
// console.log(this.rowsdata);
}
showdata() {
console.log("called");
var portfolioList = require('../app/api/showPortfolio.js');
portfolioList.showPortfolio(function(err:any, rows:any) {
console.log(rows);
// self.rowsdata = rows;
this.rowsdata = rows;
});
// console.log(self.rowsdata);
console.log(rowsdata);
}
}
here is the showPortfolio function
exports.showPortfolio = function(callback) {
db.all(squel .select()
.from("portfolios")
.field("name")
.field("current_balance") .toString() , function(err, rows) { callback(null, rows) });
}
In your code :
portfolioList.showPortfolio(function(err:any, rows:any) {
Change this to a fat arrow:
portfolioList.showPortfolio((err:any, rows:any) => {
More
https://basarat.gitbooks.io/typescript/content/docs/arrow-functions.html
i cant post a comment with all this code, so i post an answer.
it should work like this. i've put some extra logs.
showdata() {
console.log("called");
var _this = this;
console.log(_this);
var portfolioList = require('../app/api/showPortfolio.js');
portfolioList.showPortfolio(function(err:any, rows:any) {
console.log(rows);
console.log(_this);
_this.rowsdata = rows;
});
// console.log(self.rowsdata);
console.log(rowsdata);
}
}

Magento2 Override existing js component

I want to override the existing magento2 JS Component in my theme for some more customization.
Magento_Checkout/js/view/minicart.js
Above JS component i want to override and i want to add some more operation on the remove button event.
You can try "map" of require js. I used this and working for me. following is the requirejs-config.js inside my theme.
var config = {
map: {
'*': {
'Magento_Checkout/js/view/minicart':'js/custom/minicart'
}
}
};
Modified minicart.js file is placed inside "web/js/custom" folder inside my theme.
Just Go to your theme Override Magento_Checkout there, then under web folder make path as same as core module then add your js file & do required changes. It will reflect on frontend.
You can also extend an existing Magento JS without overwriting the whole file in your module add the require-config.js
app/code/MyVendor/MyModule/view/frontend/requirejs-config.js
var config = {
config: {
mixins: {
'Magento_Checkout/js/view/minicart': {
'MyVendor_MyModule/js/minicart': true
}
}
}
};
Then add the minicart.js
app/code/MyVendor/MyModule/view/frontend/web/js/minicart.js
define([], function () {
'use strict';
return function (Component) {
return Component.extend({
/**
* #override
*/
initialize: function () {
var self = this;
return this._super();
},
MyCustomFunction: function () {
return "my function";
}
});
}
});
define(['jquery'],function ($) {
'use strict';
var mixin = {
/**
*
* #param {Column} elem
*/
initSidebar: function () {
var sidebarInitialized = false, miniCart;
miniCart = $('[data-block=\'minicart\']');
if (miniCart.data('mageSidebar')) {
miniCart.sidebar('update');
}
if (!$('[data-role=product-item]').length) {
return false;
}
miniCart.trigger('contentUpdated');
if (sidebarInitialized) {
return false;
}
sidebarInitialized = true;
miniCart.sidebar({
'targetElement': 'div.block.block-minicart',
'url': {
'checkout': window.checkout.checkoutUrl,
'update': window.checkout.updateItemQtyUrl,
'remove': window.checkout.removeItemUrl,
'loginUrl': window.checkout.customerLoginUrl,
'isRedirectRequired': window.checkout.isRedirectRequired
},
'button': {
'checkout': '#top-cart-btn-checkout',
'remove': '#mini-cart a.action.delete',
'increacseqty':'#mini-cart a.action.increase-qty',
'decreaseqty':'#mini-cart a.action.decrease-qty',
'close': '#btn-minicart-close'
},
'showcart': {
'parent': 'span.counter',
'qty': 'span.counter-number',
'label': 'span.counter-label'
},
'minicart': {
'list': '#mini-cart',
'content': '#minicart-content-wrapper',
'qty': 'div.items-total',
'subtotal': 'div.subtotal span.price',
'maxItemsVisible': window.checkout.minicartMaxItemsVisible
},
'item': {
'qty': ':input.cart-item-qty',
'button': ':button.update-cart-item'
},
'confirmMessage': $.mage.__('Are you sure you would like to remove this item from the shopping cart??')
});
return this._super();
}
};
return function (minicart) { // target == Result that Magento_Ui/.../columns returns.
return minicart.extend(mixin); // new result that all other modules receive
};
});

requireJs - Jquery UI autocomplete does not work

Im getting the following error when I try to use jqueru autocomplete together with require js:
'cannot call methods on autocomplete prior to initialization; attempted to call method '/recruiter/temp-search/api/locations/get''
I have a module which initilizes my autocomplete:
define(['jqueryUi'],function($) {
function Location() {
this.autocompleteUrl = "/recruiter/temp-search/api/locations/get";
};
Location.prototype.initAutocomplete = function($txtTown, onSuccessDelegate, countryId, regionId, ignoredInputHandler, includeCountries) {
///<param name="$txtTown" type="jQuery">input text element to decorate with autocomplete</param>
///<param name="onSuccessDelegate" type="function">Invoked with upon item selection with selected value passed as a parameter</param>
///<param name="regionId" type="int">Region constraint. Defaults to null</param>
///<param name="countryId" type="int">Country Id. Defaults to UK id</param>
///<param name="ignoredInputHandler" type="function">
/// function(string term, function success(string term, {data, result, value}[] data), function failure(string term)) delegate
/// that is invoked on autocomplete requests before user input at leaset 2 chars
///</param>
var cId = countryId ? countryId : null;
var rId = regionId ? regionId : null;
var inclCountries = includeCountries === undefined ? false : includeCountries;
var onSuccess = onSuccessDelegate ? onSuccessDelegate : function() {};
$txtTown.autocomplete(this.autocompleteUrl, {
dataType: 'json',
parse: function(data) {
/* validation Location*/
/*To remove error field check on the parentsearch.js self.elements.searchLocation.on('keyup'*/
if ($txtTown.selector === "#Location") {
if (data.Locations.length == 0 && !data.IsPostcode && $txtTown.val().length > 0) {
var locationError = "We couldn't find the location you entered";
jQuery("[data-valmsg-for = 'Location']").text(locationError);
$('#Location').closest('.search-row').find('.search-error').show();
} else {
jQuery("[data-valmsg-for = 'Location']").text("");
}
}
/**/
var rows = [];
if ($.isArray(data.Locations)) {
var locations = data.Locations;
if (locations !== null) {
for (var i = 0; i < locations.length; i++) {
rows[i] = { data: locations[i], value: locations[i], result: locations[i] };
}
}
} else {
if (data.IsPostcode) {
onSuccess(data.Location, data.Postcode);
}
}
return rows;
},
extraParams: { countryId: cId, regionId: rId, includeCountries: inclCountries },
formatItem: function(row) { return row; },
width: 'auto',
minChars: 2,
delay: 100,
max: 10,
ignoredInputHandler: ignoredInputHandler,
selectFirst: false,
cacheLength: 1,
scroll: false
}).result(function(event, row) {
onSuccess(row);
});
};
return new Location();
});
It is being called like this:
location.initAutocomplete(this.elements.searchLocation, onSuccessAutocomplete, undefined, undefined, undefined, true);
here is my config file:
require.config({
paths: {
"JqueryAutocomplete": "../scripts/jquery/plugins/jquery.autocomplete",
"jqueryValidate": "../scripts/jquery/plugins/jquery.validate",
"jqueryUi": "../scripts/jquery/plugins/jquery-ui-1.10.3.custom",
"jquery": "../scripts/jquery/jquery-1.9.1",
"knockout": "../scripts/knockout/knockout-2.3.0",
"ko": "common/knockout-extensions"
},
shim: {
"JqueryAutocomplete": {
exports: "$",
deps: ['jquery']
},
"jqueryValidate": {
exports: "$",
deps: ['jquery']
},
"jqueryUi": {
exports: "$",
deps: ['jquery']
},
"knockout-extensions": {
exports: "knockout",
deps: ['knockout']
}
}
});

populating menus from multiple collections

I'm new to backbone.js and express and I have been adapting Christophe Coenraets Wine Cellar REST API example application for my own project.
I am building a form that has several menus needing to be populated from multiple unrelated collections in mongodb.
I am able to populate one menu with one collection, but I have no idea how to get more than one collection to my form View.
Here are the files I am using to populate one menu. How do I expand this to populate two menus?
I suppose I could make a new View for every menu I want to populate - but that seems like overkill.
Can I combine two mongodb find() collections into one object, and list them separately on a page? If so, how?
thanks in advance!
/routes/modules.js contains:
exports.findAllModules = function(req, res) {
db.collection('modules', function(err, collection) {
collection.find().toArray(function(err, items) {
res.send(items);
});
});
};
/server.js contains:
app.get('/modules', module.findAllModules);
/public/js/main.js contains:
routes: {
"modules" : "list" }
...
list: function(page) {
var p = page ? parseInt(page, 10) : 1;
var moduleList = new ModuleCollection();
moduleList.fetch({success: function(){
console.log('in list function');
$("#content").html(new ModuleListView({model: moduleList, page: p}).el);
}});
this.headerView.selectMenuItem('home-menu');
},
...
utils.loadTemplate([
'ModuleListItemView' ], function() {
app = new AppRouter();
Backbone.history.start(); });
/public/models/models.js contains:
window.Module = Backbone.Model.extend({
urlRoot: "/modules",
idAttribute: "_id",
initialize: function () {
this.validators = {};
this.validators.name = function (value) {
return value.length > 0 ? {isValid: true} : {isValid: false, message: "You must enter a name"};
};
validateItem: function (key) {
return (this.validators[key]) ? this.validators[key](this.get(key)) : {isValid: true};
},
validateAll: function () {
var messages = {};
for (var key in this.validators) {
if(this.validators.hasOwnProperty(key)) {
var check = this.validators[key](this.get(key));
if (check.isValid === false) {
messages[key] = check.message;
}
}
}
return _.size(messages) > 0 ? {isValid: false, messages: messages} : {isValid: true};
},
defaults: {
_id: null,
name: ""
} });
window.ModuleCollection = Backbone.Collection.extend({
model: Module,
url: "/modules"
});
/public/js/views/modulelist.js contains:
window.ModuleListView = Backbone.View.extend({
initialize: function () {
this.render();
},
render: function () {
var modules = this.model.models;
$(this.el).html('<ul class="thumbnails"></ul>');
for (var i = 0; i < modules.length; i++) {
$('.thumbnails', this.el).append(new ModuleListItemView({model: modules[i]}).render().el);
}
return this;
} });
window.ModuleListItemView = Backbone.View.extend({
tagName: "li",
initialize: function () {
this.model.bind("change", this.render, this);
this.model.bind("destroy", this.close, this);
},
render: function () {
$(this.el).html(this.template(this.model.toJSON()));
return this;
} });
/public/tpl/ModuleListView.html contains:
Not entirely sure how your code works, but here are a few backbone tips.
If you wanna build a menu from a collection don't pass the collection as a model.
Instead of:
$("#content").html(new ModuleListView({model: moduleList, page: p}).el);
Use:
$("#content").empty().append(new ModuleListView({collection: moduleList, page: p}).el);
Instead of:
render: function () {
var modules = this.model.models;
$(this.el).html('<ul class="thumbnails"></ul>');
for (var i = 0; i < modules.length; i++) {
$('.thumbnails', this.el).append(new ModuleListItemView({model: modules[i]}).render().el);
}
return this;
}
Use:
render: function () {
this.$el.html('<ul class="thumbnails">');
this.collection.each(function(model) {
this.$('.thumbnails').append(new ModuleListItemView({model: model}).render().el);
}, this);
return this;
}
If you have no need in updating or deleting your models, it's enough to add the url path /modules only to the collection, for reading the initial modules.

Resources