Ace editor: how to have multiple tokens - ace-editor

I'm trying to create a mode using this two rules:
{
token: 'title',
regex: /#.*/
},
{
token: 'name',
regex: /#\w+/
}
Hovewer, the name rule will not have any effect in this example:
# Title with #name
Is there a way to make both rules work?

The first rule consumes the whole line and doesn't allow the second one to apply. For it to work, you need to create a nested state after the #
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var HighlightRules = function() {
this.$rules = {
start : [ {
token: 'comment',
regex: /#(?=.)/,
next: [{
token: 'empty',
regex: /$|^/,
next: "start"
},{
token: 'keyword',
regex: /#\w+/
},{
defaultToken : "comment"
}]
}]
};
this.normalizeRules();
};
oop.inherits(HighlightRules, TextHighlightRules);
exports.HighlightRules = HighlightRules;
});

Related

Filtering a model in FIORI leads to "f.forEach is not a function"

I am trying to read a model with a filter:
var oFilter = new sap.ui.model.Filter({
filters: [
new sap.ui.model.Filter({
path: 'attr1',
operator: sap.ui.model.FilterOperator.EQ,
value1: value
}),
new sap.ui.model.Filter({
path: 'attr2',
operator: sap.ui.model.FilterOperator.EQ,
value1: value2
})
],
and: true
});
model.read("/pathToEntitySet",
{
success: function(oData, response) {
console.log("i am here");
},
error: function(oError){
console.log(oError);
},
filters: oFilter
}
);
However, I am always getting "f.forEach is not a function" when I add filters: oFilter to the model.read operation.
I am using FF 68.5.
Any ideas where this error could be coming from?
filters expects an array. You passed a single object. Two options:
Option A: Drop the wrapper
When applying multiple filters with different paths, AND is automatically assumed. So you can simply do
const aFilter = [
new sap.ui.model.Filter({
path: 'attr1',
operator: sap.ui.model.FilterOperator.EQ,
value1: value
}),
new sap.ui.model.Filter({
path: 'attr2',
operator: sap.ui.model.FilterOperator.EQ,
value1: value2
})
];
model.read("/pathToEntitySet", {
success: ...
error: ...
filters: aFilter
});
Option B: Add another wrapper
Leave your filter as is and just put brackets around oFilter when passing it to filters:
model.read("/pathToEntitySet", {
success: ...
error: ...
filters: [oFilter]
});

JSON schema validation with perfect messages

I have divided the data entry in a REST call in 4 parts. Data can be sent to REST call via:-
headers
query params
path params
request body
So in order to validate the presence of any key in any of the above 4 parts I have created a schema in this format. So if in case I have to validate anything in query params I will add the key 'query' and then add the fields inside that, that needs to be validated
const schema = {
id: 'Users_login_post',
type: 'object',
additionalProperties: false,
properties: {
headers: {
type: 'object',
additionalProperties: false,
properties: {
Authorization: {
type: 'string',
minLength: 10,
description: 'Bearer token of the user.',
errorMessages: {
type: 'should be a string',
minLength: 'should be atleast of 23 length',
required: 'should have Authorization'
}
}
},
required: ['Authorization']
},
path: {
type: 'object',
additionalProperties: false,
properties: {
orgId: {
type: 'string',
minLength: 23,
maxLength: 36,
description: 'OrgId Id of the Organization.',
errorMessages: {
type: 'should be a string',
minLength: 'should be atleast of 23 length', // ---> B
maxLength: 'should not be more than 36 length',
required: 'should have OrgId'
}
}
},
required: ['orgId']
}
}
};
Now, in my express code, I created a request object so that I can test the validity of the JSON in this format.
router.get("/org/:orgId/abc", function(req, res){
var request = { //---> A
path: {
orgId : req.params.orgId
},
headers: {
Authorization : req.headers.Authorization
}
}
const Ajv = require('ajv');
const ajv = new Ajv({
allErrors: true,
});
let result = ajv.validate(schema, request);
console.log(ajv.errorsText());
});
And I validate the above request object (at A) against my schema using AjV.
The output what I get looks something like this:
data/headers should have required property 'Authorization', data/params/orgId should NOT be shorter than 23 characters
Now I have a list of concerns:
why the message is showing data word in the data/headers and data/params/orgId even when my variable name is request(at A)
Also why not my errormessages are used, like in case of orgId I mentioned: should be atleast of 23 length (at B) as a message, even then the message came should NOT be shorter than 23 characters.
How can I show request/headers instead of data/headers.
Also, the way I used to validate my path params, query params, header params, body param, is this the correct way, if it is not, then what can be the better way of doing the same?
Please shed some light.
Thanks in advance.
Use ajv-keywords
import Ajv from 'ajv';
import AjvKeywords from 'ajv-keywords';
// ajv-errors needed for errorMessage
import AjvErrors from 'ajv-errors';
const ajv = new Ajv.default({ allErrors: true });
AjvKeywords(ajv, "regexp");
AjvErrors(ajv);
// modification of regex by requiring Z https://www.regextester.com/97766
const ISO8601UTCRegex = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?Z$/;
const typeISO8601UTC = {
"type": "string",
"regexp": ISO8601UTCRegex.toString(),
"errorMessage": "must be string of format 1970-01-01T00:00:00Z. Got ${0}",
};
const schema = {
type: "object",
properties: {
foo: { type: "number", minimum: 0 },
timestamp: typeISO8601UTC,
},
required: ["foo", "timestamp"],
additionalProperties: false,
};
const validate = ajv.compile(schema);
const data = { foo: 1, timestamp: "2020-01-11T20:28:00" }
if (validate(data)) {
console.log(JSON.stringify(data, null, 2));
} else {
console.log(JSON.stringify(validate.errors, null, 2));
}
https://github.com/rofrol/ajv-regexp-errormessage-example
AJV cannot know the name of the variable you passed to the validate function.
However you should be able to work out from the errors array which paths have failed (and why) and construct your messages from there.
See https://ajv.js.org/#validation-errors
To use custom error messages in your schema, you need an AJV plugin: ajv-errors.
See https://github.com/epoberezkin/ajv-errors

Instafeed: skip retrieving video type posts from feed

I want to skip all video type posts from a feed that I'm gathering through the Instafeed JS plugin. Read from a few other posts that setting a filter would solve it but if I apply this (see below) I only get 2 images instead of 5. 1 of those 5 are a video type and the rest are image types. Not sure whats going on here?
var loadButton = document.getElementById('instafeed-loadmore');
var feed = new Instafeed({
get: 'user',
type: 'image',
limit: '5',
sortBy: 'most-recent',
resolution: 'standard_resolution',
userId: '',
accessToken: '',
template: '<div><img src="{{image}}" data-etc=""></div>',
filter: function(image) {
return image.type === 'image';
},
after: function() {
if (!this.hasNext()) {
loadButton.setAttribute('disabled', 'disabled');
}
},
});
loadButton.addEventListener('click', function() {
feed.next();
});
Maybe removing the resolution parameter should help. Also I dont think
type: 'image',
is a valid argument. I cant find it in the instafeed documentation as well.
TRy following
var feed = new Instafeed({
get: "user",
userId: "xxxx",
accessToken: "xxxx",
filter: function(image) {
if (image.type === "image") {
return false;
}
return true;
}
});
feed.run();

How can I add Ractive instances to a list? in a parent Ractive instance?

I already have a Ractive instance (or component - it could be either) and I want to add it to a list in another Ractive instance. Something like this:
var ListItemOne = new Ractive({
data: { key: "hello" }
});
var ListItemTwo = new Ractive({
data: { key: "world" }
});
var ractive = new Ractive({
el: "#output",
template: "#template",
data: { greeting: 'hi', name: 'there',
listItems: [
ListItemOne,
ListItemTwo
]
}
});
Template:
<p>{{greeting}} {{name}}!</p>
<ul>
{{#listItems}}
<li>{{key}}</li>
{{/listItems}}
</ul>
jsbin
Or using a method:
var ractive = new Ractive({
el: "#output",
template: "#template",
data: {
greeting: 'hi', name: 'there',
listItems: []
},
addListItem: function(listItem){
this.get('listItems').push(listItem);
}
});
ractive.addListItem(ListItemOne);
ractive.addListItem(ListItemTwo);
jsbin
Is it possible to use Ractive in this way?
Please note that I do not want this:
var ractive = new Ractive({
el: "#output",
template: "#template",
data: { greeting: 'hi', name: 'there',
listItems: [
{ key: "hello" },
{ key: "world" }
]
}
});
As I already have the Ractive instances/components, and I am using MVP to define explicitly define the interface between application and view.
The items in the list are ractive instances, so you have to call the get method to access their data if you want to use them that way (see http://jsbin.com/nomutofati/1/edit?html,js,output):
<ul>
{{#listItems}}
<li>{{this.get('key')}}</li>
{{/listItems}}
</ul>

Updating Child Panels in Sencha Touch MVC App

Developing a Sencha Touch MVC app that pulls data from json store (thats set up to a DB pulling out content from a Wordpress Blog).
Everything works up until my "detail" panel. Instead of it listening to the TPL, its just dumping some data. The data looks similar to my blog post, but is filled with other code and doesn't make much sense.
Here is a lean version of my list:
myApp.views.PostListView = Ext.extend(Ext.Panel, {
postStore: Ext.emptyFn,
postList: Ext.emptyFn,
id:'postlistview',
layout: 'card',
initComponent: function () {
/* this.newButton = new Ext.Button({
text: 'New',
ui: 'action',
handler: this.onNewNote,
scope: this
});*/
this.topToolbar = new Ext.Toolbar({
title: 'All Posts',
/* items: [
{ xtype: 'spacer' },
this.newButton
],*/
});
this.dockedItems = [ this.topToolbar ];
this.postList = new Ext.List({
store: myApp.stores.postStore,
grouped: true,
emptyText: '<div style="margin:5px;">No notes cached.</div>',
onItemDisclosure: true,
itemTpl: '<div class="list-item-title">{title}</div>' +
'<div class="list-item-narrative"><small>{body}</small></div>',
});
this.postList.on('disclose', function (record) {
this.onViewPost(record);
}, this),
this.items = [this.postList];
myApp.views.PostListView.superclass.initComponent.call(this);
},
onViewPost: function (record) {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewpost',
post: record
});
},
});
And here is the "detail" view that is called on disclosure:
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
title:'Single Post',
id:'postsingleview',
layout:'card',
style:'background:grey;',
initComponent: function () {
this.new1Button = new Ext.Button({
text: 'Back',
ui: 'back',
handler: this.onViewList,
scope: this,
dock:"left"
});
this.top1Toolbar = new Ext.Toolbar({
items: [
this.new1Button
],
title: 'Single Posts',
});
this.postSinglePanel = new Ext.Panel({
layout:'fit',
flex:1,
scroll: 'vertical',
style:'padding:10px;background:yellow;',
itemTpl: '<tpl for=".">' +
'<div class="list-item-narrative">{body}</div>' +
'</tpl>',
});
this.dockedItems = [ this.top1Toolbar, this.postSinglePanel ];
myApp.views.PostSingleView.superclass.initComponent.call(this);
},
onViewList: function () {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewlist',
});
},
});
And here is the controller that its talking to:
Ext.regController('masterController', {
'index': function (options) {
if (!myApp.views.mainView) {
myApp.views.mainView = new myApp.views.MainView();
}
myApp.views.mainView.setActiveItem(
myApp.views.postView
);
},
'viewpost': function (options) {
myApp.views.postSingleView.postSinglePanel.update(options.post);
myApp.views.postView.setActiveItem(
myApp.views.postSingleView,
{ type: 'slide', direction: 'left' }
);
},
});
myApp.controllers.masterController = Ext.ControllerManager.get('masterController');
When the data comes out, it looks similar to this:
http://i.imgur.com/QlQG8.png
(the black boxes are "redacted" content, no error code there).
In closing, I believe that the controller is "dumping" the data into "MyApp.views.PostSingleView" rather than formatting it as I request in the TPL, though I'm not sure how to fix it. Any and all help MUCH appreciated!
UPDATE: As requested, here is the RegModel:
Ext.regModel("CategoryModel", {
fields: [
{name: "id", type: "int"},
{name: "title", type: "string"},
{name: "body", type: "string"},
],
hasMany: {
model: 'Post',
name: 'posts'
}
});
And here is a sample of the json:
{
   "status":"ok",
   "post":{
      "id":1037,
      "type":"post",
      "slug":"post-title",
      "url":"http:\/\/localhost:8888\/jsontest\/PostTitle\/",
      "status":"publish",
      "title":"Post Title",
      "title_plain":"Post Title",
      "content":"<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<br \/>\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<\/p>\n<!-- PHP 5.x -->",
      "excerpt":"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat [...]",
      "date":"2011-07-29 14:17:31",
      "modified":"2011-08-30 01:33:20",
      "categories":[
         {
            "id":87,
            "slug":"the-category",
            "title":"The Category",
            "description":"",
            "parent":17,
            "post_count":5
         }
      ],
      "tags":[
      ],
      "author":{
         "id":2,
         "slug":"tom",
         "name":"tom",
         "first_name":"tom",
         "last_name":"",
         "nickname":"",
         "url":"",
         "description":""
      },
      "comments":[
      ],
      "attachments":[
      ],
      "comment_count":0,
      "comment_status":"open"
   },
   "previous_url":"http:\/\/localhost:8888\/jsontest\/next-post\/",
   "next_url":"http:\/\/localhost:8888\/jsontest\/prev-post\/"
}
Use the tpl config option of the Ext.Panel not the itemTpl which doesn't exist.
As someone has mentioned before, be careful when using a Model instance and the update method, you will need to use the model's data property.
Try using this:
myApp.views.postSingleView.postSinglePanel.update(options.post.data);
the reason is that post does not actually expose the underlying data directly, you need to use the property data for that.
Also any particular reason why you are docking the postSinglePanel? I would be very careful using too many docked items as they are a known source of bugs and layout issues.
A simple way is to write your own method to update child panels (you can also see to override the default update method)
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
initComponent: function () {
// [...]
},
// [...]
myUpdate: function(data) {
this.postSinglePanel.update(data);
this.doComponentLayout(); // not sure if necessary...
}
});
and from your controller:
Ext.regController('masterController', {
// [...]
'viewpost': function (options) {
myApp.views.postSingleView.myUpdate(options.post.data); // note the .data
// [...]
},
});

Resources