How to over write a function for gnome-shell which has only _init() {} - gnome-shell-extensions

from this link https://wiki.gnome.org/Projects/GnomeShell/Extensions/StepByStepTutorial if we search for inject, we notice "prototype"
But I am looking to extend/ overwrite this part, I cant user prototype in this case which is mentioned in above link/guide. So how to achieve this?
for example, I want to overwrite DEFAULT_BACKGROUND_COLOR with Clutter.Color.from_string('#00ff00')
let _systemBackground;
var SystemBackground = GObject.registerClass({
Signals: { 'loaded': {} },
}, class SystemBackground extends Meta.BackgroundActor {
_init() {
if (_systemBackground == null) {
_systemBackground = new Meta.Background({ meta_display: global.display });
_systemBackground.set_color(DEFAULT_BACKGROUND_COLOR);
}
super._init({
meta_display: global.display,
monitor: 0,
});
this.content.background = _systemBackground;
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.emit('loaded');
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(id, '[gnome-shell] SystemBackground.loaded');
}
});
OS Arch Linux, gnome-shell --version 3.38.1

_init() is a function like any other, and can be overridden on the prototype of a class the same way:
const Background = imports.ui.background;
Background.SystemBackground.prototype._init = function() {
// Chaining-up to the super-class
super._init({
meta_display: global.display,
monitor: 0,
});
// Whatever custom code you want to exectute
};

Related

./watch is compiling the JS library files mostly but one file it is always caching

I am using Ember even though I am making changes but when I run the ./watch its not producing the JavaScript file with new code - its annoying - I am making the manual change but that's not correct solution right? I made the change to the file even by opening in folder and manually updated the code on ember file - still its writing the old code in app.js file.
What could be the reason? I am using Web Pack to run ./watch and generate the app.js file.
Here is my Ember js code:
export default () => {
IMS.registerController("case.details.assignedinspector.edit", {
caseDetails: Ember.inject.controller('caseDetails'),
caseId: Ember.computed.alias('caseDetails.model.imscase.id'),
clearForm: function () {
$('.modal').modal('hide');
},
actions: {
close: function (id) {
$('.modal').modal('hide');
this.transitionToRoute('case.details');
},
async save() {
var scope = this;
//validating form
if ($("#edit-assignedinspector-form").validate()) {
var data = {
AssignedToInvestigators: Ember.get(scope, 'model.imscase.assignedToInvestigators'), //AssignedToInspectorId: $("#assignedInspectorSelect").chosen().val(),
CaseId: this.get('caseId')
};
try {
let response = await this.api('Case/UpdateAssignedInvestigators').post(data);
$('.modal').modal('hide');
toastr.success("Assigned Inspector Edit Saved.");
scope.transitionToRoute("case.details");
scope.get('caseDetails').refreshData();
scope.clearForm();
} catch (ex) {
toastr.error("Error saving Assigned Inspector.");
}
}
else {
toastr.warning("Please fix the form", "Validation failed");
}
},
didInsert: function () {
$('#edit-assignedinspector-modal').modal();
}
}
});
}
Here is how its generating the old code in app.js file:
save: function () {
var _save = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee() {
var scope, data, response;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
scope = this; //validating form
if (!$("#edit-assignedinspector-form").validate()) {
_context.next = 19;
break;
}
data = {
AssignedToInspectorId: $("#assignedInspectorSelect").chosen().val(),
CaseId: this.get('caseId')
};
_context.prev = 3;
_context.next = 6;
return this.api('Case/UpdateAssignedInspector').post(data);
case 6:
response = _context.sent;
$('.modal').modal('hide');
toastr.success("Assigned Inspector Edit Saved.");
scope.transitionToRoute("case.details");
scope.get('caseDetails').refreshData();
scope.clearForm();
_context.next = 17;
break;
case 14:
_context.prev = 14;
_context.t0 = _context["catch"](3);
toastr.error("Error saving Assigned Inspector.");
case 17:
_context.next = 20;
break;
case 19:
toastr.warning("Please fix the form", "Validation failed");
case 20:
case "end":
return _context.stop();
}
}
}, _callee, this, [[3, 14]]);
}));
function save() {
return _save.apply(this, arguments);
}
return save;
}()
It is supposed to call Case/UpdateAssignedInvestigators instead its still calling the Case/UpdateAssignedInspector, which is incorrect.

How to disable parent page of modal in angular

I have a modal window in Angular 4 that works fine but if the user clicks on the background / parent page the modal is closed.
I have found some solutions that suggest using backdrop='static' and keyboard=false when opening the modal but our modal uses a local Dialog class with a BehaviorSubject object so is opened using the .next method. I've also tried setting these attributes using div config but to no avail.
Therefore I'm looking for another solution, maybe using CSS or another setting / attribute that can be directly applied to the parent page or modal HTML.
See below for some of the relevant code.
dialog.component.ts:
constructor(private location: PlatformLocation,
private _dialog: DialogService,
private router: Router) { }
open() {
this.showDialog = true;
const body = document.body;
body.classList.add('cell-modal-open');
}
close() {
this.dialog = undefined;
}
private handleDialog(d: Dialog) {
if (!d) {
this.close();
} else if (d.template) {
if (this.showDialog) {
this.close();
}
this.dialog = d;
this.open();
}
}
ngOnInit() {
this.subscription = this
._dialog
.getDialog()
.subscribe({
next: (d) => { this.handleDialog(d); console.log('subscribed dialog') },
error: (err) => this.handleDialogError(err)
});
this.initialiseRoutingEventListeners();
}
dialog.service.ts
private d: Dialog = { template: null, size: DialogSizeEnum.XLarge };
private dialogSubject = new BehaviorSubject<Dialog>({ template: null, size: DialogSizeEnum.XLarge });
constructor() { }
showDialog(template: TemplateRef<any>, size = DialogSizeEnum.XLarge, requiresAction = false) {
Object.assign(this.d, { template: template, size: size, requiresAction: requiresAction });
if (this.d !== null) {
this.dialogSubject.next(this.d);
}
}
getDialog(): BehaviorSubject<Dialog> {
return this.dialogSubject;
}
clear() {
this.dialogSubject.next(null);
}
Any suggested approaches are welcome!
Added flag to the close() method and adding condition to only set to undefined if true (i.e. from a valid location).

Aurelia: Stylesheet loaded but not removed

In an aurelia project I have several components that import additional stylesheets, e.g. from semantic-ui. After leaving the components page, the stylesheet is still active and not removed. Is it possible to 'unload' the stylesheets?
Update (2018-03-27):
I submitted a PR to enable this as an opt-in, you can keep track of it here: https://github.com/aurelia/templating-resources/pull/344
Original answer:
A word of warning, this is untested and aurelia-internals-hacky.
What you could do is override the default CSSViewEngineHooks and CSSResource classes to keep track of the style elements it injects, and then add an beforeUnbind hook to remove the styles again.. before unbind (right after detached)
Unfortunately the CSSResource class is not exported from aurelia-templating-resources so we need to go one layer deeper and overwrite the existing style loader plugins that returns instances of CSSResource.
Here's how:
First we grab the code from aurelia-templating-resources/src/css-resource.js, put it in our own src/css-resource.js/ts and make a few tweaks to it (don't think too much of the size, it's just a copy-paste with a few small tweaks, annotated with comments):
import {ViewResources, resource, ViewCompileInstruction} from 'aurelia-templating';
import {Loader} from 'aurelia-loader';
import {Container} from 'aurelia-dependency-injection';
import {relativeToFile} from 'aurelia-path';
import {DOM, FEATURE} from 'aurelia-pal';
let cssUrlMatcher = /url\((?!['"]data)([^)]+)\)/gi;
function fixupCSSUrls(address, css) {
if (typeof css !== 'string') {
throw new Error(`Failed loading required CSS file: ${address}`);
}
return css.replace(cssUrlMatcher, (match, p1) => {
let quote = p1.charAt(0);
if (quote === '\'' || quote === '"') {
p1 = p1.substr(1, p1.length - 2);
}
return 'url(\'' + relativeToFile(p1, address) + '\')';
});
}
class CSSResource {
constructor(address: string) {
this.address = address;
this._scoped = null;
this._global = false;
this._alreadyGloballyInjected = false;
}
initialize(container: Container, target: Function): void {
this._scoped = new target(this);
}
register(registry: ViewResources, name?: string): void {
if (name === 'scoped') {
registry.registerViewEngineHooks(this._scoped);
} else {
this._global = true;
}
}
load(container: Container): Promise<CSSResource> {
return container.get(Loader)
.loadText(this.address)
.catch(err => null)
.then(text => {
text = fixupCSSUrls(this.address, text);
this._scoped.css = text;
if (this._global) {
this._alreadyGloballyInjected = true;
// DOM.injectStyles(text); <- replace this
// this is one of the two possible moments where the style is injected
// _scoped is the CSSViewEngineHooks instance, and we handle the removal there
this._scoped.styleNode = DOM.injectStyles(text);
}
});
}
}
class CSSViewEngineHooks {
constructor(owner: CSSResource) {
this.owner = owner;
this.css = null;
}
beforeCompile(content: DocumentFragment, resources: ViewResources, instruction: ViewCompileInstruction): void {
if (instruction.targetShadowDOM) {
DOM.injectStyles(this.css, content, true);
} else if (FEATURE.scopedCSS) {
let styleNode = DOM.injectStyles(this.css, content, true);
styleNode.setAttribute('scoped', 'scoped');
} else if (this._global && !this.owner._alreadyGloballyInjected) {
// DOM.injectStyles(this.css); <- replace this
// save a reference to the node so we can easily remove it later
this.styleNode = DOM.injectStyles(this.css);
this.owner._alreadyGloballyInjected = true;
}
}
// this is the hook we add, here we remove the node again
beforeUnbind(): void {
if (this._global && this.owner._alreadyGloballyInjected) {
DOM.removeNode(this.styleNode);
this.owner._alreadyGloballyInjected = false;
}
}
}
export function _createCSSResource(address: string): Function {
#resource(new CSSResource(address))
class ViewCSS extends CSSViewEngineHooks {}
return ViewCSS;
}
Then, in our main.ts/js we do the same thing aurelia-templating-resources.js does, but with our own version.
So we do this after the call to aurelia.use.standardConfiguration() etc, to override the existing one
let viewEngine = config.container.get(ViewEngine);
let styleResourcePlugin = {
fetch(address) {
return { [address]: _createCSSResource(address) };
}
};
['.css', '.less', '.sass', '.scss', '.styl'].forEach(ext => viewEngine.addResourcePlugin(ext, styleResourcePlugin));
And that should pretty much do the trick.. :)
I have found a plugin to resolve the issue:
https://github.com/jbockle/aurelia-useable-style-loader
But for the latest Webpack webpack.config.js should be a little bit different than in a plugin readme.
You should load .css files this way:
use: [
{ loader: 'style-loader', options: { injectType: 'lazyStyleTag' } },
'css-loader'
]
Instead of this:
use: ['style-loader/useable', 'css-loader']

Mongoose pre.save() async middleware not working on record creation

I am using keystone#0.2.32. I would like to change the post category to a tree structure. The below code is running well except when I create a category, it goes into a deadlock:
var keystone = require('keystone'),
Types = keystone.Field.Types;
/**
* PostCategory Model
* ==================
*/
var PostCategory = new keystone.List('PostCategory', {
autokey: { from: 'name', path: 'key', unique: true }
});
PostCategory.add({
name: { type: String, required: true },
parent: { type: Types.Relationship, ref: 'PostCategory' },
parentTree: { type: Types.Relationship, ref: 'PostCategory', many: true }
});
PostCategory.relationship({ ref: 'Post', path: 'categories' });
PostCategory.scanTree = function(item, obj, done) {
if(item.parent){
PostCategory.model.find().where('_id', item.parent).exec(function(err, cats) {
if(cats.length){
obj.parentTree.push(cats[0]);
PostCategory.scanTree(cats[0], obj, done);
}
});
}else{
done();
}
}
PostCategory.schema.pre('save', true, function (next, done) { //Parallel middleware, waiting done to be call
if (this.isModified('parent')) {
this.parentTree = [];
if(this.parent != null){
this.parentTree.push(this.parent);
PostCategory.scanTree(this, this, done);
}else
process.nextTick(done);
}else
process.nextTick(done); //here is deadlock.
next();
});
PostCategory.defaultColumns = 'name, parentTree';
PostCategory.register();
Thanks so much.
As I explained on the issue you logged on Keystone here: https://github.com/keystonejs/keystone/issues/759
This appears to be a reproducible bug in mongoose that prevents middleware from resolving when:
Parallel middleware runs that executes a query, followed by
Serial middleware runs that executes a query
Changing Keystone's autokey middleware to run in parallel mode may cause bugs in other use cases, so cannot be done. The answer is to implement your parentTree middleware in serial mode instead of parallel mode.
Also, some other things I noticed:
There is a bug in your middleware, where the first parent is added to the array twice.
The scanTree method would be better implemented as a method on the schama
You can use the findById method for a simpler parent query
The schema method looks like this:
PostCategory.schema.methods.addParents = function(target, done) {
if (this.parent) {
PostCategory.model.findById(this.parent, function(err, parent) {
if (parent) {
target.parentTree.push(parent.id);
parent.addParents(target, done);
}
});
} else {
done();
}
}
And the fixed middleware looks like this:
PostCategory.schema.pre('save', function(done) {
if (this.isModified('parent')) {
this.parentTree = [];
if (this.parent != null) {
PostCategory.scanTree(this, this, done);
} else {
process.nextTick(done);
}
} else {
process.nextTick(done);
}
});
I think it's a bug of keystone.js. I have changed schemaPlugins.js 104 line
from
this.schema.pre('save', function(next) {
to
this.schema.pre('save', true, function(next, done) {
and change from line 124 to the following,
// if has a value and is unmodified or fixed, don't update it
if ((!modified || autokey.fixed) && this.get(autokey.path)) {
process.nextTick(done);
return next();
}
var newKey = utils.slug(values.join(' ')) || this.id;
if (autokey.unique) {
r = getUniqueKey(this, newKey, done);
next();
return r;
} else {
this.set(autokey.path, newKey);
process.nextTick(done);
return next();
}
It works.

Subscription manager doesn't update collection after new subscription

In my Meteor application I have this situation in which I have a 'Settings' collection only on the client. So the publish function is:
Meteor.publish('settings', function (option) {
this.added("settings", "settings", {
bar: true,
foo: { .... }
});
this.ready();
});
Initially I subscribe like:
waintOn: function () {
return subs.subscribe('settings')
}
But when the route changes I subscribe again like
return subs.subscribe('settings', 10);
After this I see that the publish function runs, but on the client nothing happens.
For some reason the server thinks that the data did not change and decides to do nothing. So the question is how can I tell Meteor that the data has changed so it sends the data to the client. If the problem is completely different, I'm also very interested!!
UPDATE: the publish function might look like this:
Meteor.publish('settings', function (option) {
var list;
if (option === 10) {
list = [1,2,3,4,5];
}
this.added("settings", "settings", {
bar: true,
foo: list
});
this.ready();
});
UPDATE2: Expected solution:
var isNew = true;
Meteor.publish('settings', function () {
if(isNew) {
this.added("settings", "settings", {
bar: true,
foo: list
});
isNew = false;
}
else {
this.changed('settings', 'settings', {.....});
}
this.ready();
});
It would even be better if there was a function like this.exists('settings', 'settings') because the isNew variable feels a bit like a hack!
Anyway, I have it working now as follows:
try {
this.removed('settings', 'settings');
} catch(e){}
this.added('settings', 'settings', {...});
...

Resources