How to render an object containing functions in code mirror (angular) properly - codemirror

I need to render in code mirror ( a plugin to display code snippets in the frontend ) an object containing functions, my object looks like:
{
lang:"en",
func1: function(e){
console.log(e);
},
func2: function(f){
alert(f);
}
}
I've tried using JSON.stringify with a replace, like:
JSON.stringify(finalGlobalConfigObj, function(key, value) {
if (typeof value === "function") {
return "/Function(" + value.toString() + ")/";
}
return value;
}, 4);
However, the rendering is not great because it just render the content as a String.
How can I render correctly my object that is containing functions?
I'm using code mirror inside an angular application.

Related

Wagtail - how to get tags to work with `telepath` (tags in streamfield)?

I can use tags in regular page fields without any issue. When using tags within blocks (within a streamfield), the UI works and the tags are saved BUT the current page tags do not show up when loading the page in the admin. That's because the current value is not in the template anymore, it's in a JSON loaded via telepath.
I can confirm that the tags are saved and present in the data passed to initBlockWidget in the page source but these are ignored. Also, if I used a regular text field instead of the tag-widget, I can see the saved-values in the admin.
This is the code I have (which used to be enough before the refactor with telepath).
from wagtail.admin.widgets import AdminTagWidget
class TagBlock(TextBlock):
#cached_property
def field(self):
field_kwargs = {"widget": AdminTagWidget()}
field_kwargs.update(self.field_options)
return forms.CharField(**field_kwargs)
I think the following link is what I need to complete somehow to get it to work: https://docs.wagtail.io/en/stable/reference/streamfield/widget_api.html#form-widget-client-side-api
I've tried with this:
class AdminTagWidgetAdapter(WidgetAdapter):
class Media:
js = [
"wagtailadmin/js/vendor/tag-it.js",
"js/admin/admin-tag-widget-adapter.js",
]
register(AdminTagWidgetAdapter(), AdminTagWidget)
And under js/admin/admin-tag-widget-adapter.js:
console.log("adapter"); // this shows up in the console
class BoundWidget { // copied from wagtail source code
constructor(element, name, idForLabel, initialState) {
var selector = ':input[name="' + name + '"]';
this.input = element.find(selector).addBack(selector); // find, including element itself
this.idForLabel = idForLabel;
this.setState(initialState);
}
getValue() {
return this.input.val();
}
getState() {
return this.input.val();
}
setState(state) {
this.input.val(state);
}
getTextLabel(opts) {
const val = this.getValue();
if (typeof val !== 'string') return null;
const maxLength = opts && opts.maxLength;
if (maxLength && val.length > maxLength) {
return val.substring(0, maxLength - 1) + '…';
}
return val;
}
focus() {
this.input.focus();
}
}
// my code here:
class AdminTagWidget {
constructor(html, idPattern) {
this.html = html;
this.idPattern = idPattern;
}
boundWidgetClass = BoundWidget;
render(placeholder, name, id, initialState) {
console.log("RENDER", placeholder, name, id, initialState); // this does not show
var html = this.html.replace(/__NAME__/g, name).replace(/__ID__/g, id);
var idForLabel = this.idPattern.replace(/__ID__/g, id);
var dom = $(html);
$(placeholder).replaceWith(dom);
// eslint-disable-next-line new-cap
return new this.boundWidgetClass(dom, name, idForLabel, initialState);
}
}
console.log("here") // does show in the console
// variants I've tried:
//window.telepath.register('wagtail.admin.widgets.tags.AdminTagWidget', AdminTagWidget);
//window.telepath.register('wagtail.widgets.AdminTagWidget', AdminTagWidget);
window.telepath.register('path.where.its.used.AdminTagWidget', AdminTagWidget)
The log from my custom render method does not show. It seems that I'm not calling the right path within window.telepath.register but I don't know how what the string is supposed to be...
I'm not even sure if this is the right way forward.
Notes:
it works in regular field, the question is about tags in blocks
I'm using Wagtail version 2.13.2 but I've also tried with 2.15 without any difference.
In the console, I can log window.telepath and see my custom widget. It's just not "applied" to anything
Your WidgetAdapter class needs a js_constructor attribute:
class AdminTagWidgetAdapter(WidgetAdapter):
js_constructor = 'myapp.widgets.AdminTagWidget'
class Media:
js = [
"wagtailadmin/js/vendor/tag-it.js",
"js/admin/admin-tag-widget-adapter.js",
]
Any string value will work here - it just needs to uniquely identify the class, so it's recommended to use a dotted module-like path to avoid colliding with others. This then matches the string you pass to window.telepath.register on the Javascript side:
window.telepath.register('myapp.widgets.AdminTagWidget', AdminTagWidget)

how to put verification in pageobject model in protractor

I have a code (credit to #kishanpatel) Traverse-through-each-row-for-a-column-text which will verify whether the value is added in grid or not. i want to put this in my page object. i was thinking to add the elements into page object and the if condition in a different helper file similar to selenium but i am not sure is that the right appraoch. see the details below.
if I call the mo.helper in spec.ts, it says gridcheck.ispresent() is not a function. How to handle this scenario?
code:
it('verify the grid that master obligation is added', function () {
var testvar = "'test_protractor'";
var row_check = element(by.xpath("//div[contains(text()," + testvar + ")]"));
if (row_check.isPresent()) {
row_check.getText().then(function (msg) {
if (row_check.isPresent()) {
console.log("Grid contains========== " + msg);
}
});
}
});
i have the below method in mo.ts(page object page):
this.grid = function (value) {
// var testvar = "'test_protractor'";
var row_check = element(by.xpath("//div[contains(text()," + value + ")]"));
return require('./mohelper.ts')
}
}
mohelper.ts:
require('../page/mo.ts')
var mohelper = function () {
this.gridvaluepresent = function () {
require('../page/mo.ts')
var gridcheck = mo.grid();
if(gridcheck.isPresent()) {
gridcheck.getText().then(function (msg) {
if (gridcheck.isPresent()) {
console.log("Grid contains========== " + msg);
}
})
}
}
}
module.exports = new mohelper();
spec.ts:
it('go to corresponding module and verify whether the master obligation is added ', function () {
browser.sleep(10000);
taxhome.selectmodule;
taxhome.selectmoduledropdown(1);
mo.grid("test_protractor");
mohelper.gridvaluepresent();
});
Couple of things here to be considered -
1) Most of the protractor's api methods are asynchronous i.e. they return promises you have to resolve/reject them to perform actions.
isPresent() also returns a promise, you need to resolve it-
var row_check = element(by.xpath("//div[contains(text()," + value + ")]"));
row_check.isPresent().then(function(present) {
if(present) { // it returns a boolean value
row_check.getText().then(function (msg) {
console.log("Grid contains========== " + msg);
});
}
});
2) Since you are using TypeScript , use its syntax rather than conventional js-
let row_check = element(by.xpath("//div[contains(text()," + value + ")]")); // Block scoped variable using 'let'
row_check.isPresent().then((present) => { // notice the thick arrow
if(present) {
row_check.getText().then((msg) => {
console.log("Grid contains========== " + msg);
});
}
});
3) Maintain Page Objects efficiently and readable-
All the helper methods, elements etc. for a single page should go in a single page object. Write them in separate classes, typescript uses the concept of classes and transpiles them to global functions.
moHelper.ts
import {ElementFinder, element} from 'protractor';
export class MoHelper {
public row_check: ElementFinder; // its of element finder type
gridValueCheck(value : string) {
row_check = element(by.xpath("//div[contains(text()," + value + ")]")); // please use Css selectors instead of Xpath!
row_check.isPresent().then((present) => {
if(present) {
row_check.getText().then((msg) => {
return msg; // here you are returning the msg of the row from your page!
});
}
});
}
}
Your spec.ts should validate that row msg!
import {MoHelper} from './moHelper.ts'
let mo: MoHelper = new MoHelper();
it('go to corresponding module and verify whether the master obligation is added ', () => {
browser.sleep(10000); // please refrain from using sleeps instead use Expected Conditions
taxhome.selectmodule;
taxhome.selectmoduledropdown(1);
expect(mo.gridValueCheck("test_protractor")).toEqual("Your Expected Message");
});
Please find the links for your reference to understand the above in more detail-
isPresent
Getting started with typescript
Using page objects in protractor/style guide
Expected Conditions

How to globally add a custom locator to Protractor?

I wrote a custom locator for Protractor that finds anchor elements by their ui-sref value. In my specs I just used by.addLocator to add the custom locator, but I figured this might be a cool thing to publish and have other people use it.
The goal is to add this custom locator to the global Protractor object so it can be used in any of your specs.
My initial approach was to add this functionality in the onPrepare block of the Protractor config. Something like the pseudocode below:
onPrepare: function () {
require('ui-sref-locator')(protractor); // The protractor object is available here.
}
That require statement would just execute this function:
function (ptorInstance) {
ptorInstance.by.addLocator('uiSref', function (toState, opt_parentElement) {
var using = opt_parentElement || document;
var possibleAnchors = using.querySelectorAll('a[ui-sref="' + toState +'"]');
var result = undefined;
if (possibleAnchors.length === 0) {
result = null;
} else if (possibleAnchors.length === 1) {
result = possibleAnchors[0];
} else {
result = possibleAnchors;
}
return result;
});
};
The problem is that by is not defined on the protractor object available in the onPrepare block. This means that I cannot use the .addLocator method.
Try the following:
function () {
by.addLocator('uiSref', function (toState, opt_parentElement) {
...
By should be in the global scope.
The protractor object passed to the onPrepare block has a By property. That By property has an inherited enumerable property named addLocator. My understanding of JavaScript is pretty shallow so it really threw me off that when I console.log'ed the protractor.By it returned {}, but if I did for (var propName in protractor.By) it would show me all the "hidden" properties. I'm still struggling to understand that bit.
Working code:
onPrepare: function () {
require('ui-sref-locator')(protractor); // The protractor object is available here.
}
The require would execute the function below:
function (ptor) {
ptor.By.addLocator('linkUiSref', function (toState, opt_parentElement) {
var using = opt_parentElement || document;
var possibleAnchors = using.querySelectorAll('a[ui-sref="' + toState +'"]');
var result = undefined;
if (possibleAnchors.length === 0) {
result = null;
} else if (possibleAnchors.length === 1) {
result = possibleAnchors[0];
} else {
result = possibleAnchors;
}
return result;
});
};

Using ECT template with Chaplin

Hello I want to use ect templates with the Chaplin js. I am not able to integrate the ect template the way Handlebar is integrated as per Chaplin boiler plate.Please help thanks.
I found the way for this you just need to override the render function as per the syntax of the ect template in your application base view class.
I did it in this way
render : function() {
var $templateHtml, html, templateFunc;
if (this.disposed) {
return false;
}
var data = { message : 'Hello, World!' };
html = ECT({ root : 'js/templates' }).render(this.templateName,data)
if (!this.noWrap) {
this.$el.html(html);
}
else {
$templateHtml = $(html);
if ($templateHtml.length > 1) {
throw new Error('There must be a single top-level element when ' + 'using `noWrap`.');
}
this.undelegateEvents();
this.setElement($templateHtml, true);
}
return this;
}

tinymce.dom.replace throws an exception concerning parentNode

I'm writing a tinyMce plugin which contains a section of code, replacing one element for another. I'm using the editor's dom instance to create the node I want to insert, and I'm using the same instance to do the replacement.
My code is as follows:
var nodeData =
{
"data-widgetId": data.widget.widgetKey(),
"data-instanceKey": "instance1",
src: "/content/images/icon48/cog.png",
class: "widgetPlaceholder",
title: data.widget.getInfo().name
};
var nodeToInsert = ed.dom.create("img", nodeData);
// Insert this content into the editor window
if (data.mode == 'add') {
tinymce.DOM.add(ed.getBody(), nodeToInsert);
}
else if (data.mode == 'edit' && data.selected != null) {
var instanceKey = $(data.selected).attr("data-instancekey");
var elementToReplace = tinymce.DOM.select("[data-instancekey=" + instanceKey + "]");
if (elementToReplace.length === 1) {
ed.dom.replace(elementToReplace[0], nodeToInsert);
}
else {
throw new "No element to replace with that instance key";
}
}
TinyMCE breaks during the replace, here:
replace : function(n, o, k) {
var t = this;
if (is(o, 'array'))
n = n.cloneNode(true);
return t.run(o, function(o) {
if (k) {
each(tinymce.grep(o.childNodes), function(c) {
n.appendChild(c);
});
}
return o.parentNode.replaceChild(n, o);
});
},
..with the error Cannot call method 'replaceChild' of null.
I've verified that the two argument's being passed into replace() are not null and that their parentNode fields are instantiated. I've also taken care to make sure that the elements are being created and replace using the same document instance (I understand I.E has an issue with this).
I've done all this development in Google Chrome, but I receive the same errors in Firefox 4 and IE8 also. Has anyone else come across this?
Thanks in advance
As it turns out, I was simply passing in the arguments in the wrong order. I should have been passing the node I wanted to insert first, and the node I wanted to replace second.