Skip to content

Commit d669057

Browse files
committed
add flags optional argument to regexp handlebar functions
so we can do case-insensitive search: #1001
1 parent 22aa403 commit d669057

File tree

6 files changed

+125
-56
lines changed

6 files changed

+125
-56
lines changed

docs/dev-docs/api.md

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ to use for ERMrest JavaScript agents.
286286
* [.table](#ERMrest.Key+table) : <code>Table</code>
287287
* [.colset](#ERMrest.Key+colset) : [<code>ColSet</code>](#ERMrest.ColSet)
288288
* [.annotations](#ERMrest.Key+annotations) : [<code>Annotations</code>](#ERMrest.Annotations)
289-
* [.comment](#ERMrest.Key+comment) : <code>Object</code>
289+
* ~~[.comment](#ERMrest.Key+comment) : <code>Object</code>~~
290290
* [.RID](#ERMrest.Key+RID) : <code>string</code>
291291
* [.constraint_names](#ERMrest.Key+constraint_names) : <code>Array</code>
292292
* [.name](#ERMrest.Key+name) : <code>string</code>
@@ -323,15 +323,9 @@ to use for ERMrest JavaScript agents.
323323
* [.rights](#ERMrest.ForeignKeyRef+rights) : <code>Object</code>
324324
* [.mapping](#ERMrest.ForeignKeyRef+mapping) : [<code>Mapping</code>](#ERMrest.Mapping)
325325
* [.constraint_names](#ERMrest.ForeignKeyRef+constraint_names) : <code>Array</code>
326-
* [.from_name](#ERMrest.ForeignKeyRef+from_name) : <code>string</code>
327-
* [.to_name](#ERMrest.ForeignKeyRef+to_name) : <code>string</code>
328-
* [.to_comment](#ERMrest.ForeignKeyRef+to_comment) : <code>string</code> \| <code>null</code>
329-
* [.from_comment](#ERMrest.ForeignKeyRef+from_comment) : <code>string</code> \| <code>null</code>
330-
* [.to_comment_display](#ERMrest.ForeignKeyRef+to_comment_display) : <code>string</code> \| <code>null</code>
331-
* [.from_comment_display](#ERMrest.ForeignKeyRef+from_comment_display) : <code>string</code> \| <code>null</code>
332326
* [.ignore](#ERMrest.ForeignKeyRef+ignore) : <code>boolean</code>
333327
* [.annotations](#ERMrest.ForeignKeyRef+annotations) : [<code>Annotations</code>](#ERMrest.Annotations)
334-
* [.comment](#ERMrest.ForeignKeyRef+comment) : <code>Object</code>
328+
* ~~[.comment](#ERMrest.ForeignKeyRef+comment) : <code>Object</code>~~
335329
* [.compressedDataSource](#ERMrest.ForeignKeyRef+compressedDataSource)
336330
* [.name](#ERMrest.ForeignKeyRef+name) : <code>string</code>
337331
* [.simple](#ERMrest.ForeignKeyRef+simple) : <code>Boolean</code>
@@ -2278,7 +2272,7 @@ get the key by the column set
22782272
* [.table](#ERMrest.Key+table) : <code>Table</code>
22792273
* [.colset](#ERMrest.Key+colset) : [<code>ColSet</code>](#ERMrest.ColSet)
22802274
* [.annotations](#ERMrest.Key+annotations) : [<code>Annotations</code>](#ERMrest.Annotations)
2281-
* [.comment](#ERMrest.Key+comment) : <code>Object</code>
2275+
* ~~[.comment](#ERMrest.Key+comment) : <code>Object</code>~~
22822276
* [.RID](#ERMrest.Key+RID) : <code>string</code>
22832277
* [.constraint_names](#ERMrest.Key+constraint_names) : <code>Array</code>
22842278
* [.name](#ERMrest.Key+name) : <code>string</code>
@@ -2312,7 +2306,9 @@ Reference to the table that this Key belongs to.
23122306
**Kind**: instance property of [<code>Key</code>](#ERMrest.Key)
23132307
<a name="ERMrest.Key+comment"></a>
23142308

2315-
#### key.comment : <code>Object</code>
2309+
#### ~~key.comment : <code>Object</code>~~
2310+
***Deprecated***
2311+
23162312
Documentation for this key
23172313

23182314
**Kind**: instance property of [<code>Key</code>](#ERMrest.Key)
@@ -2552,15 +2548,9 @@ get the foreign key of the given column set
25522548
* [.rights](#ERMrest.ForeignKeyRef+rights) : <code>Object</code>
25532549
* [.mapping](#ERMrest.ForeignKeyRef+mapping) : [<code>Mapping</code>](#ERMrest.Mapping)
25542550
* [.constraint_names](#ERMrest.ForeignKeyRef+constraint_names) : <code>Array</code>
2555-
* [.from_name](#ERMrest.ForeignKeyRef+from_name) : <code>string</code>
2556-
* [.to_name](#ERMrest.ForeignKeyRef+to_name) : <code>string</code>
2557-
* [.to_comment](#ERMrest.ForeignKeyRef+to_comment) : <code>string</code> \| <code>null</code>
2558-
* [.from_comment](#ERMrest.ForeignKeyRef+from_comment) : <code>string</code> \| <code>null</code>
2559-
* [.to_comment_display](#ERMrest.ForeignKeyRef+to_comment_display) : <code>string</code> \| <code>null</code>
2560-
* [.from_comment_display](#ERMrest.ForeignKeyRef+from_comment_display) : <code>string</code> \| <code>null</code>
25612551
* [.ignore](#ERMrest.ForeignKeyRef+ignore) : <code>boolean</code>
25622552
* [.annotations](#ERMrest.ForeignKeyRef+annotations) : [<code>Annotations</code>](#ERMrest.Annotations)
2563-
* [.comment](#ERMrest.ForeignKeyRef+comment) : <code>Object</code>
2553+
* ~~[.comment](#ERMrest.ForeignKeyRef+comment) : <code>Object</code>~~
25642554
* [.compressedDataSource](#ERMrest.ForeignKeyRef+compressedDataSource)
25652555
* [.name](#ERMrest.ForeignKeyRef+name) : <code>string</code>
25662556
* [.simple](#ERMrest.ForeignKeyRef+simple) : <code>Boolean</code>
@@ -2615,30 +2605,6 @@ use index 0 since all refCols should be of the same schema:table
26152605
The exact `names` array in foreign key definition
26162606
The constraint names for this foreign key
26172607

2618-
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
2619-
<a name="ERMrest.ForeignKeyRef+from_name"></a>
2620-
2621-
#### foreignKeyRef.from\_name : <code>string</code>
2622-
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
2623-
<a name="ERMrest.ForeignKeyRef+to_name"></a>
2624-
2625-
#### foreignKeyRef.to\_name : <code>string</code>
2626-
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
2627-
<a name="ERMrest.ForeignKeyRef+to_comment"></a>
2628-
2629-
#### foreignKeyRef.to\_comment : <code>string</code> \| <code>null</code>
2630-
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
2631-
<a name="ERMrest.ForeignKeyRef+from_comment"></a>
2632-
2633-
#### foreignKeyRef.from\_comment : <code>string</code> \| <code>null</code>
2634-
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
2635-
<a name="ERMrest.ForeignKeyRef+to_comment_display"></a>
2636-
2637-
#### foreignKeyRef.to\_comment\_display : <code>string</code> \| <code>null</code>
2638-
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
2639-
<a name="ERMrest.ForeignKeyRef+from_comment_display"></a>
2640-
2641-
#### foreignKeyRef.from\_comment\_display : <code>string</code> \| <code>null</code>
26422608
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
26432609
<a name="ERMrest.ForeignKeyRef+ignore"></a>
26442610

@@ -2650,7 +2616,9 @@ The constraint names for this foreign key
26502616
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)
26512617
<a name="ERMrest.ForeignKeyRef+comment"></a>
26522618

2653-
#### foreignKeyRef.comment : <code>Object</code>
2619+
#### ~~foreignKeyRef.comment : <code>Object</code>~~
2620+
***Deprecated***
2621+
26542622
Documentation for this foreign key reference
26552623

26562624
**Kind**: instance property of [<code>ForeignKeyRef</code>](#ERMrest.ForeignKeyRef)

docs/user-docs/handlebars.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,8 @@ This would result in:
928928

929929
The `regexFindFirst` helper will take the input regular expression and return the first matching substring from the supplied string. Will return `""` otherwise.
930930

931+
> The regular expression syntax that Javascript supports is a bit different from other languages, please refer to [MDN regular expressions document](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) for more information.
932+
931933
A simple example where we try to match the file extension `jpg` or `png` with testString="jumpng-fox.jpg":
932934
```
933935
{{#regexFindFirst testString "jpg|png"}}{{this}}{{/regexFindFirst}}
@@ -948,11 +950,19 @@ Result:
948950
"index.html"
949951
```
950952

953+
You can also use the `flags` named optional argument to pass [regular expression flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags). For example you can use the `i` flag for case-insensitive searching:
954+
```
955+
{{#regexFindFirst testString "human" flags="i" }}{{this}}{{/regexFindFirst}}
956+
```
957+
958+
> If `flags` argument is not used, by default we are using the `g` (global search) flag for the regular expression search.
951959
952960
### Findall helper
953961

954962
The `regexFindAll` helper will take the input regular expression and return all the matching substrings from the supplied string in an array. Will return `[]` otherwise.
955963

964+
> The regular expression syntax that Javascript supports is a bit different from other languages, please refer to [MDN regular expressions document](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) for more information.
965+
956966
A simple example where we try to match the file extension `jpg` or `png` with testString="jumpng-fox.jpg":
957967
```
958968
{{#each (regexFindAll testString "jpg|png")}}{{this}}\n{{/each}}
@@ -963,9 +973,20 @@ Result:
963973
"png\njpg\n"
964974
```
965975

976+
You can also use the `flags` named optional argument to pass [regular expression flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags). For example you can use the `i` flag for case-insensitive searching:
977+
```
978+
{{#regexFindAll testString "ACO1" flags="i" }}{{this}}{{/regexFindFirst}}
979+
```
980+
981+
> If `flags` argument is not used, by default we are using the `g` (global search) flag for the regular expression search.
982+
966983
### Replace helper
967984

968-
The `replace` helper will take the input regular expression (first argument) and replace all matches in the supplied string with the supplied substring (second argument). This helper behaves the same way as the `replace` function for Strings in javascript. One example would be to replace all underscores with whitespace characters for table name display.
985+
The `replace` helper will take the input regular expression (first argument) and replace all matches in the supplied string with the supplied substring (second argument). This helper behaves the same way as the `replace` function for Strings in javascript.
986+
987+
> The regular expression syntax that Javascript supports is a bit different from other languages, please refer to [MDN regular expressions document](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) for more information.
988+
989+
One example would be to replace all underscores with whitespace characters for table name display.
969990

970991
Template:
971992
```
@@ -977,6 +998,30 @@ Result:
977998
table name with underscores
978999
```
9791000

1001+
You can also use the `flags` named optional argument to pass [regular expression flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags). By default we're using the `g` flag, that's why the example above is replacing all the matches. Examples of using the `flags` named argument:
1002+
1003+
- If you only want to replace the first match, you can pass empty string for flags:
1004+
- Template:
1005+
```
1006+
{{#replace "_" " " flags=""}}table_name_with_underscores{{/replace}}
1007+
```
1008+
1009+
- Result:
1010+
```
1011+
table name_with_underscores
1012+
```
1013+
1014+
- Use the `i` flag for case-insensitive searching (in this example we're also using `g` flag to make sure we're still replacing all the matches):
1015+
- Template:
1016+
```
1017+
{{#replace "aco1" "ACO1" flags="ig"}}{{{Gene_Names}}}{{/replace}}
1018+
```
1019+
1020+
- Result (assuming `Gene_Names` is `"Aco1, ACO1"`):
1021+
```
1022+
ACO1, ACO1
1023+
```
1024+
9801025
### ToTitleCase helper
9811026

9821027
The `toTitleCase` helper will change the first character of each word (split by whitespace) in the string to a capital letter. The rest of the case of the string will remain unchanged.
@@ -1056,6 +1101,15 @@ Using the `regexMatch` function you can check whether a given value matches the
10561101
{{/if}}
10571102
```
10581103

1104+
You can also use the `flags` named optional argument to pass [regular expression flags](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#advanced_searching_with_flags). For example you can use the `i` flag for case-insensitive matching:
1105+
```
1106+
{{#if (regexMatch value "film analysis" flags="i" )}}
1107+
.. content
1108+
{{/if}}
1109+
```
1110+
1111+
> If `flags` argument is not used, by default we are using the `g` (global search) flag for the regular expression search.
1112+
10591113
### Logical Helpers
10601114

10611115
- And (`and`)

js/column.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,7 @@ Object.defineProperty(PseudoColumn.prototype, "comment", {
13901390
disp.commentRenderMarkdown,
13911391
commentDisplayMode
13921392
);
1393-
}
1393+
};
13941394

13951395
this._comment = getComment(this);
13961396
}
@@ -1992,7 +1992,7 @@ Object.defineProperty(ForeignKeyPseudoColumn.prototype, "name", {
19921992
Object.defineProperty(ForeignKeyPseudoColumn.prototype, "displayname", {
19931993
get: function () {
19941994
if (this._displayname === undefined) {
1995-
var context = this._context, foreignKey = this.foreignKey
1995+
var context = this._context, foreignKey = this.foreignKey;
19961996
var toName = foreignKey.getDisplay(context).toName;
19971997
var value, isHTML, unformatted;
19981998
if (this.sourceObject.markdown_name) {

js/utils/handlebar_helpers.js

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
return args.reduce(reducer, first);
99
};
1010

11-
var regexpFindAll = function (value, regexp) {
12-
var regexpObj = new RegExp(regexp, 'g');
11+
var regexpFindAll = function (value, regexp, flags) {
12+
var regexpObj = new RegExp(regexp, flags);
1313
var matches = value.match(regexpObj);
1414

1515
return matches;
@@ -109,11 +109,16 @@
109109
* string
110110
* {{/replace}}
111111
*
112+
* {{replace value regexp flags="ig"}}
113+
*
112114
* @returns replaces each match of the regexp with newSubstr
113115
*/
114116
replace: function (substr, newSubstr, options) {
115-
var regexpObj = new RegExp(substr, 'g');
116-
117+
var flags = 'g';
118+
if (options && isObjectAndNotNull(options.hash) && typeof options.hash.flags === 'string') {
119+
flags = options.hash.flags;
120+
}
121+
var regexpObj = new RegExp(substr, flags);
117122
return options.fn(this).replace(regexpObj, newSubstr);
118123
},
119124

@@ -122,10 +127,16 @@
122127
* .. content
123128
* {{/if}}
124129
*
130+
* {{regexMatch value regexp flags="i"}}
131+
*
125132
* @returns boolean if the value matches the regexp
126133
*/
127-
regexMatch: function (value, regexp) {
128-
var regexpObj = new RegExp(regexp);
134+
regexMatch: function (value, regexp, options) {
135+
var flags = 'g';
136+
if (options && isObjectAndNotNull(options.hash) && typeof options.hash.flags === 'string') {
137+
flags = options.hash.flags;
138+
}
139+
var regexpObj = new RegExp(regexp, flags);
129140
return regexpObj.test(value);
130141
},
131142

@@ -134,10 +145,16 @@
134145
* {{this}}
135146
* {{/each}}
136147
*
148+
* {{regexFindFirst value regexp flags="i"}}
149+
*
137150
* @returns first string from value that matches the regular expression or empty string
138151
*/
139-
regexFindFirst: function (value, regexp) {
140-
var matches = regexpFindAll(value, regexp);
152+
regexFindFirst: function (value, regexp, options) {
153+
var flags = 'g';
154+
if (options && isObjectAndNotNull(options.hash) && typeof options.hash.flags === 'string') {
155+
flags = options.hash.flags;
156+
}
157+
var matches = regexpFindAll(value, regexp, flags);
141158
return (matches && matches[0]) || "";
142159
},
143160

@@ -146,10 +163,16 @@
146163
* {{this}}
147164
* {{/each}}
148165
*
166+
* {{regexFindFirst value regexp flags="ig"}}
167+
*
149168
* @returns array of strings from value that match the regular expression or
150169
*/
151-
regexFindAll: function (value, regexp) {
152-
return regexpFindAll(value, regexp) || [];
170+
regexFindAll: function (value, regexp, options) {
171+
var flags = 'g';
172+
if (options && isObjectAndNotNull(options.hash) && typeof options.hash.flags === 'string') {
173+
flags = options.hash.flags;
174+
}
175+
return regexpFindAll(value, regexp, flags) || [];
153176
},
154177

155178
/**

js/utils/helpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@
850850
/**
851851
* Turn a comment annotaiton/string value into a proper comment object.
852852
* @param {string|null|false} comment
853-
* @param {boolean=true} isMarkdown whether the given comment should be rendered as markdown (default: true).
853+
* @param {boolean?} isMarkdown whether the given comment should be rendered as markdown (default: true).
854854
* @param {string} displayMode the display mode of the comment (inline, tooltip)
855855
* @private
856856
*/

test/specs/print_utils/tests/01.print_utils.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,11 @@ exports.execute = function (options) {
732732
var template = '{{#if (regexMatch type "jpg|png")}}image{{else}}other{{/if}}';
733733
expect(module.renderHandlebarsTemplate(template, {"type": "jpg"})).toBe("image", "missmatch for 01");
734734
expect(module.renderHandlebarsTemplate(template, {"type": "txt"})).toBe("other", "missmatch for 02");
735+
736+
var template = '{{#if (regexMatch File_Name "film analysis" flags="i")}}matched{{else}}other{{/if}}';
737+
expect(module.renderHandlebarsTemplate(template, {"File_Name": "film analysis"})).toBe("matched", "missmatch for 01");
738+
expect(module.renderHandlebarsTemplate(template, {"File_Name": "FILM Analysis"})).toBe("matched", "missmatch for 02");
739+
expect(module.renderHandlebarsTemplate(template, {"File_Name": "FILM"})).toBe("other", "missmatch for 03");
735740
});
736741

737742
it ('regexFindFirst helper', function () {
@@ -745,6 +750,9 @@ exports.execute = function (options) {
745750

746751
var template3 = '{{#regexFindFirst testString "[^\/]+$"}}{{this}}{{/regexFindFirst}}';
747752
expect(module.renderHandlebarsTemplate(template3, {"testString": "/var/www/html/index.html"}) ).toBe("index.html", "missmatch for 5th test");
753+
754+
var template4 = '{{#regexFindFirst testString "test" flags="i"}}{{this}}{{/regexFindFirst}}';
755+
expect(module.renderHandlebarsTemplate(template4, {"testString": "my very own TEST"}) ).toBe("TEST", "missmatch for 6th test");
748756
});
749757

750758
it ('regexFindAll helper', function () {
@@ -758,6 +766,12 @@ exports.execute = function (options) {
758766

759767
var template3 = '{{#each (regexFindAll testString "[^\/]+$")}}{{this}}\n{{/each}}';
760768
expect(module.renderHandlebarsTemplate(template3, {"testString": "/var/www/html/index.html"}) ).toBe("index.html\n", "missmatch for 5th test");
769+
770+
var template4 = '{{#each (regexFindAll testString "jpg|png" flags="")}}{{this}}\n{{/each}}';
771+
expect(module.renderHandlebarsTemplate(template4, {"testString": "jumpng-fox.jpg"}) ).toBe("png\n", "missmatch for 6th test");
772+
773+
var template5 = '{{#each (regexFindAll testString "jpg|png" flags="ig")}}{{this}}\n{{/each}}';
774+
expect(module.renderHandlebarsTemplate(template5, {"testString": "jumPNG-fox.JPG"}) ).toBe("PNG\nJPG\n", "missmatch for 6th test");
761775
});
762776

763777
it ('replace helper', function () {
@@ -766,6 +780,16 @@ exports.execute = function (options) {
766780
var template = '{{#replace "_" " "}}{{{string}}}{{/replace}}'
767781

768782
expect(module.renderHandlebarsTemplate(template, {string: underscoreToWhitespace})).toEqual("change this table name", "missmatch for 1st test");
783+
784+
expect(module.renderHandlebarsTemplate(
785+
'{{#replace "foo" "" flags=""}}{{{string}}}{{/replace}}',
786+
{string: 'foo example foo'})
787+
).toEqual(' example foo');
788+
789+
expect(module.renderHandlebarsTemplate(
790+
'{{#replace "foo" "" flags="ig"}}{{{string}}}{{/replace}}',
791+
{string: 'foo example FoO'})
792+
).toEqual(' example ');
769793
});
770794

771795
it ('jsonStringify helper', function () {

0 commit comments

Comments
 (0)