2015-10-29 07:01:35 +00:00
"use strict" ;
describe ( "Zotero.Utilities.Internal" , function ( ) {
2017-10-21 07:26:27 +00:00
var ZUI ;
before ( function ( ) {
ZUI = Zotero . Utilities . Internal ;
} ) ;
2016-09-24 10:43:57 +00:00
describe ( "#md5()" , function ( ) {
it ( "should generate hex string given file path" , function * ( ) {
var file = OS . Path . join ( getTestDataDirectory ( ) . path , 'test.png' ) ;
assert . equal (
Zotero . Utilities . Internal . md5 ( Zotero . File . pathToFile ( file ) ) ,
'93da8f1e5774c599f0942dcecf64b11c'
) ;
} )
} )
2015-10-29 07:01:35 +00:00
describe ( "#md5Async()" , function ( ) {
it ( "should generate hex string given file path" , function * ( ) {
var file = OS . Path . join ( getTestDataDirectory ( ) . path , 'test.png' ) ;
yield assert . eventually . equal (
Zotero . Utilities . Internal . md5Async ( file ) ,
'93da8f1e5774c599f0942dcecf64b11c'
) ;
2017-06-30 21:54:33 +00:00
} ) ;
it ( "should generate hex string given file path for file bigger than chunk size" , function * ( ) {
var tmpDir = Zotero . getTempDirectory ( ) . path ;
var file = OS . Path . join ( tmpDir , 'md5Async' ) ;
let encoder = new TextEncoder ( ) ;
let arr = encoder . encode ( "" . padStart ( 100000 , "a" ) ) ;
yield OS . File . writeAtomic ( file , arr ) ;
yield assert . eventually . equal (
Zotero . Utilities . Internal . md5Async ( file ) ,
'1af6d6f2f682f76f80e606aeaaee1680'
) ;
yield OS . File . remove ( file ) ;
} ) ;
2015-10-29 07:01:35 +00:00
} )
2016-02-24 06:02:30 +00:00
2016-03-28 06:35:27 +00:00
describe ( "#gzip()/gunzip()" , function ( ) {
it ( "should compress and decompress a Unicode text string" , function * ( ) {
var text = "Voilà! \u1F429" ;
var compstr = yield Zotero . Utilities . Internal . gzip ( text ) ;
assert . isAbove ( compstr . length , 0 ) ;
assert . notEqual ( compstr . length , text . length ) ;
var str = yield Zotero . Utilities . Internal . gunzip ( compstr ) ;
assert . equal ( str , text ) ;
} ) ;
} ) ;
2020-07-17 22:14:10 +00:00
describe ( "#decodeUTF8()" , function ( ) {
it ( "should properly decode binary string" , async function ( ) {
let text = String . fromCharCode . apply ( null , new Uint8Array ( [ 226 , 130 , 172 ] ) ) ;
let utf8 = Zotero . Utilities . Internal . decodeUTF8 ( text ) ;
assert . equal ( utf8 , "€" ) ;
} ) ;
} ) ;
2022-06-08 00:02:48 +00:00
describe ( "#isOnlyEmoji()" , function ( ) {
it ( "should return true for emoji" , function ( ) {
assert . isTrue ( Zotero . Utilities . Internal . isOnlyEmoji ( "🐩" ) ) ;
} ) ;
it ( "should return true for emoji with text representation that use Variation Selector-16" , function ( ) {
assert . isTrue ( Zotero . Utilities . Internal . isOnlyEmoji ( "⭐️" ) ) ;
} ) ;
it ( "should return true for emoji made up of multiple characters with ZWJ" , function ( ) {
assert . isTrue ( Zotero . Utilities . Internal . isOnlyEmoji ( "👨🌾" ) ) ;
} ) ;
it ( "should return false for integer" , function ( ) {
assert . isFalse ( Zotero . Utilities . Internal . isOnlyEmoji ( "0" ) ) ;
} ) ;
} ) ;
2016-02-24 06:02:30 +00:00
describe ( "#delayGenerator" , function ( ) {
var spy ;
before ( function ( ) {
spy = sinon . spy ( Zotero . Promise , "delay" ) ;
} ) ;
afterEach ( function ( ) {
2018-08-04 20:07:27 +00:00
spy . resetHistory ( ) ;
2016-02-24 06:02:30 +00:00
} ) ;
after ( function ( ) {
spy . restore ( ) ;
} ) ;
it ( "should delay for given amounts of time without limit" , function * ( ) {
var intervals = [ 1 , 2 ] ;
var gen = Zotero . Utilities . Internal . delayGenerator ( intervals ) ;
// When intervals are exhausted, keep using last interval
var testIntervals = intervals . slice ( ) ;
testIntervals . push ( intervals [ intervals . length - 1 ] ) ;
for ( let i of testIntervals ) {
let val = yield gen . next ( ) . value ;
assert . isTrue ( val ) ;
assert . isTrue ( spy . calledWith ( i ) ) ;
2018-08-04 20:07:27 +00:00
spy . resetHistory ( ) ;
2016-02-24 06:02:30 +00:00
}
} ) ;
it ( "should return false when maxTime is reached" , function * ( ) {
var intervals = [ 5 , 10 ] ;
var gen = Zotero . Utilities . Internal . delayGenerator ( intervals , 30 ) ;
// When intervals are exhausted, keep using last interval
var testIntervals = intervals . slice ( ) ;
testIntervals . push ( intervals [ intervals . length - 1 ] ) ;
for ( let i of testIntervals ) {
let val = yield gen . next ( ) . value ;
assert . isTrue ( val ) ;
assert . isTrue ( spy . calledWith ( i ) ) ;
2018-08-04 20:07:27 +00:00
spy . resetHistory ( ) ;
2016-02-24 06:02:30 +00:00
}
// Another interval would put us over maxTime, so return false immediately
let val = yield gen . next ( ) . value ;
assert . isFalse ( val ) ;
assert . isFalse ( spy . called ) ;
} ) ;
2017-10-21 07:26:27 +00:00
} ) ;
2018-08-30 19:13:04 +00:00
describe ( "#extractExtraFields()" , function ( ) {
2023-04-23 21:06:44 +00:00
it ( "should ignore 'Type: note', 'Type: attachment', and 'Type: annotation'" , function ( ) {
for ( let type of [ 'note' , 'attachment' , 'annotation' ] ) {
let str = ` Type: ${ type } ` ;
let { itemType , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . isNull ( itemType , type ) ;
assert . equal ( extra , ` Type: ${ type } ` , type ) ;
}
} ) ;
it ( "should ignore numeric values for Type" , function ( ) {
for ( let type of [ '3' ] ) {
let str = ` Type: ${ type } ` ;
let { itemType , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . isNull ( itemType , type ) ;
assert . equal ( extra , ` Type: ${ type } ` , type ) ;
}
2020-03-17 17:50:45 +00:00
} ) ;
2020-03-22 19:19:24 +00:00
it ( "should use the first mapped Zotero type for a CSL type" , function ( ) {
var str = 'type: personal_communication' ;
var { itemType , fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . equal ( itemType , 'letter' ) ;
} ) ;
2018-08-30 19:13:04 +00:00
it ( "should extract a field" , function ( ) {
var val = '10.1234/abcdef' ;
var str = ` DOI: ${ val } ` ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
2018-08-30 19:13:04 +00:00
assert . equal ( fields . size , 1 ) ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
assert . equal ( fields . get ( 'DOI' ) , val ) ;
assert . strictEqual ( extra , '' ) ;
} ) ;
it ( "should extract a field for a given item" , function ( ) {
var item = createUnsavedDataObject ( 'item' , { itemType : 'journalArticle' } ) ;
var val = '10.1234/abcdef' ;
var str = ` DOI: ${ val } ` ;
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str , item ) ;
assert . equal ( fields . size , 1 ) ;
assert . equal ( fields . get ( 'DOI' ) , val ) ;
assert . strictEqual ( extra , '' ) ;
} ) ;
it ( "should extract a CSL field" , function ( ) {
var val = '10.1234/abcdef' ;
var str = ` container-title: ${ val } ` ;
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . equal ( fields . size , Zotero . Schema . CSL _TEXT _MAPPINGS [ 'container-title' ] . length ) ;
assert . equal ( fields . get ( 'publicationTitle' ) , val ) ;
assert . strictEqual ( extra , '' ) ;
} ) ;
it ( "should extract a CSL field for a given item type" , function ( ) {
var item = createUnsavedDataObject ( 'item' , { itemType : 'journalArticle' } ) ;
var val = '10.1234/abcdef' ;
var str = ` container-title: ${ val } ` ;
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str , item ) ;
assert . equal ( fields . size , 1 ) ;
assert . equal ( fields . get ( 'publicationTitle' ) , val ) ;
assert . strictEqual ( extra , '' ) ;
2018-08-30 19:13:04 +00:00
} ) ;
it ( "should extract a field with different case" , function ( ) {
var val = '10.1234/abcdef' ;
var str = ` doi: ${ val } ` ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
2018-08-30 19:13:04 +00:00
assert . equal ( fields . size , 1 ) ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
assert . equal ( fields . get ( 'DOI' ) , val ) ;
assert . strictEqual ( extra , '' ) ;
2018-08-30 19:13:04 +00:00
} ) ;
it ( "should extract a field with other fields, text, and whitespace" , function ( ) {
2020-04-04 07:53:08 +00:00
var date = '2020-04-01' ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var doi = '10.1234/abcdef' ;
2020-04-04 07:53:08 +00:00
var str = ` Line 1 \n Date: ${ date } \n Foo: Bar \n DOI: ${ doi } \n \n Line 2 ` ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . equal ( fields . size , 2 ) ;
2020-04-04 07:53:08 +00:00
assert . equal ( fields . get ( 'date' ) , date ) ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
assert . equal ( fields . get ( 'DOI' ) , doi ) ;
assert . equal ( extra , 'Line 1\nFoo: Bar\n\nLine 2' ) ;
} ) ;
it ( "should extract the first instance of a field" , function ( ) {
2020-04-04 07:53:08 +00:00
var date1 = '2020-04-01' ;
var date2 = '2020-04-02' ;
var str = ` Date: ${ date1 } \n Date: ${ date2 } ` ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
2018-08-30 19:13:04 +00:00
assert . equal ( fields . size , 1 ) ;
2020-04-04 07:53:08 +00:00
assert . equal ( fields . get ( 'date' ) , date1 ) ;
assert . equal ( extra , "Date: " + date2 ) ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
} ) ;
2019-10-18 07:20:18 +00:00
it ( "shouldn't extract a field from a line that begins with a whitespace" , function ( ) {
var str = '\n number-of-pages: 11' ;
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . equal ( fields . size , 0 ) ;
} ) ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
it ( "shouldn't extract a field that already exists on the item" , function ( ) {
var item = createUnsavedDataObject ( 'item' , { itemType : 'book' } ) ;
item . setField ( 'numPages' , 10 ) ;
var str = 'number-of-pages: 11' ;
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str , item ) ;
assert . equal ( fields . size , 0 ) ;
} ) ;
2019-10-18 07:20:18 +00:00
it ( "should extract an author and add it to existing creators" , function ( ) {
var item = createUnsavedDataObject ( 'item' , { itemType : 'book' } ) ;
item . setCreator ( 0 , { creatorType : 'author' , name : 'Foo' } ) ;
var str = 'author: Bar' ;
var { fields , creators , extra } = Zotero . Utilities . Internal . extractExtraFields ( str , item ) ;
assert . equal ( fields . size , 0 ) ;
assert . lengthOf ( creators , 1 ) ;
assert . equal ( creators [ 0 ] . creatorType , 'author' ) ;
assert . equal ( creators [ 0 ] . name , 'Bar' ) ;
} ) ;
2023-03-21 10:23:16 +00:00
it ( "should extract a CSL date field" , function ( ) {
2020-03-02 06:34:27 +00:00
var str = 'issued: 2000' ;
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . equal ( fields . size , 1 ) ;
assert . equal ( fields . get ( 'date' ) , 2000 ) ;
assert . strictEqual ( extra , '' ) ;
} ) ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
it ( "should extract a CSL name" , function ( ) {
2020-03-15 17:51:04 +00:00
var str = 'container-author: Last || First' ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var { creators , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . lengthOf ( creators , 1 ) ;
assert . propertyVal ( creators [ 0 ] , 'creatorType' , 'bookAuthor' ) ;
assert . propertyVal ( creators [ 0 ] , 'firstName' , 'First' ) ;
assert . propertyVal ( creators [ 0 ] , 'lastName' , 'Last' ) ;
assert . strictEqual ( extra , '' ) ;
} ) ;
it ( "should extract a CSL name that's valid for a given item type" , function ( ) {
var item = createUnsavedDataObject ( 'item' , { itemType : 'bookSection' } ) ;
2020-03-15 17:51:04 +00:00
var str = 'container-author: Last || First' ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var { creators , extra } = Zotero . Utilities . Internal . extractExtraFields ( str , item ) ;
assert . lengthOf ( creators , 1 ) ;
assert . propertyVal ( creators [ 0 ] , 'creatorType' , 'bookAuthor' ) ;
assert . propertyVal ( creators [ 0 ] , 'firstName' , 'First' ) ;
assert . propertyVal ( creators [ 0 ] , 'lastName' , 'Last' ) ;
assert . strictEqual ( extra , '' ) ;
} ) ;
it ( "shouldn't extract a CSL name that's not valid for a given item type" , function ( ) {
var item = createUnsavedDataObject ( 'item' , { itemType : 'journalArticle' } ) ;
2020-03-15 17:51:04 +00:00
var str = 'container-author: Last || First' ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
var { creators , extra } = Zotero . Utilities . Internal . extractExtraFields ( str , item ) ;
assert . lengthOf ( creators , 0 ) ;
assert . strictEqual ( extra , str ) ;
2018-08-30 19:13:04 +00:00
} ) ;
2020-03-02 06:34:27 +00:00
it ( "should extract the citeproc-js cheater syntax" , function ( ) {
2023-03-21 10:23:16 +00:00
var issued = '{:number-of-pages:11}\n{:issued:2014}' ;
2020-03-02 06:34:27 +00:00
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( issued ) ;
assert . equal ( fields . size , 2 ) ;
assert . equal ( fields . get ( 'numPages' ) , 11 ) ;
2023-03-21 10:23:16 +00:00
assert . equal ( fields . get ( 'date' ) , 2014 ) ;
2020-03-02 06:34:27 +00:00
assert . strictEqual ( extra , '' ) ;
} ) ;
2020-04-04 07:53:08 +00:00
2020-05-12 05:00:21 +00:00
it ( "should ignore empty creator in citeproc-js cheater syntax" , function ( ) {
var str = '{:author: }\n' ;
var { fields , extra } = Zotero . Utilities . Internal . extractExtraFields ( str ) ;
assert . equal ( fields . size , 0 ) ;
assert . strictEqual ( extra , str ) ;
} ) ;
2018-08-30 19:13:04 +00:00
} ) ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
describe ( "#combineExtraFields" , function ( ) {
var originalDate = "1887" ;
var publicationPlace = "New York" ;
var doi = '10.1234/123456789' ;
var fieldMap = new Map ( ) ;
fieldMap . set ( 'originalDate' , originalDate ) ;
fieldMap . set ( 'publicationPlace' , publicationPlace ) ;
fieldMap . set ( 'DOI' , doi ) ;
2020-01-16 21:56:25 +00:00
var fieldStr = ` DOI: ${ doi } \n Original Date: ${ originalDate } \n Publication Place: ${ publicationPlace } ` ;
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
it ( "should create 'field: value' pairs from field map" , function ( ) {
var extra = "" ;
var newExtra = ZUI . combineExtraFields ( extra , fieldMap ) ;
assert . equal ( newExtra , fieldStr ) ;
} ) ;
it ( "should add fields above existing Extra content" , function ( ) {
var extra = "This is a note." ;
var newExtra = ZUI . combineExtraFields ( extra , fieldMap ) ;
assert . equal ( newExtra , fieldStr + '\n' + extra ) ;
} ) ;
it ( "should replace existing fields" , function ( ) {
var extra = "This is a note.\nOriginal Date: 1886\nFoo: Bar" ;
var newExtra = ZUI . combineExtraFields ( extra , fieldMap ) ;
assert . equal (
newExtra ,
2020-01-16 21:56:25 +00:00
fieldStr . split ( /\n/ ) . filter ( x => ! x . startsWith ( 'Original Date' ) ) . join ( "\n" )
Type/field handling overhaul
This changes the way item types, item fields, creator types, and CSL
mappings are defined and handled, in preparation for updated types and
fields.
Instead of being predefined in SQL files or code, type/field info is
read from a bundled JSON file shared with other parts of the Zotero
ecosystem [1], referred to as the "global schema". Updates to the
bundled schema file are automatically applied to the database at first
run, allowing changes to be made consistently across apps.
When syncing, invalid JSON properties are now rejected instead of being
ignored and processed later, which will allow for schema changes to be
made without causing problems in existing clients. We considered many
alternative approaches, but this approach is by far the simplest,
safest, and most transparent to the user.
For now, there are no actual changes to types and fields, since we'll
first need to do a sync cut-off for earlier versions that don't reject
invalid properties.
For third-party code, the main change is that type and field IDs should
no longer be hard-coded, since they may not be consistent in new
installs. For example, code should use `Zotero.ItemTypes.getID('note')`
instead of hard-coding `1`.
[1] https://github.com/zotero/zotero-schema
2019-05-16 08:56:46 +00:00
+ "\nThis is a note.\nOriginal Date: 1887\nFoo: Bar"
) ;
} ) ;
} ) ;
2018-08-30 19:13:04 +00:00
2017-10-21 07:26:27 +00:00
describe ( "#extractIdentifiers()" , function ( ) {
it ( "should extract ISBN-10" , async function ( ) {
var id = "0838985890" ;
var identifiers = ZUI . extractIdentifiers ( id ) ;
assert . lengthOf ( identifiers , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 0 ] ) , 1 ) ;
assert . propertyVal ( identifiers [ 0 ] , "ISBN" , id ) ;
} ) ;
it ( "should extract ISBN-13" , async function ( ) {
var identifiers = ZUI . extractIdentifiers ( "978-0838985892" ) ;
assert . lengthOf ( identifiers , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 0 ] ) , 1 ) ;
assert . propertyVal ( identifiers [ 0 ] , "ISBN" , "9780838985892" ) ;
} ) ;
it ( "should extract multiple ISBN-13s" , async function ( ) {
var identifiers = ZUI . extractIdentifiers ( "978-0838985892 9781479347711 " ) ;
assert . lengthOf ( identifiers , 2 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 0 ] ) , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 1 ] ) , 1 ) ;
assert . propertyVal ( identifiers [ 0 ] , "ISBN" , "9780838985892" ) ;
assert . propertyVal ( identifiers [ 1 ] , "ISBN" , "9781479347711" ) ;
} ) ;
it ( "should extract DOI" , async function ( ) {
var id = "10.4103/0976-500X.85940" ;
var identifiers = ZUI . extractIdentifiers ( id ) ;
assert . lengthOf ( identifiers , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 0 ] ) , 1 ) ;
assert . propertyVal ( identifiers [ 0 ] , "DOI" , id ) ;
} ) ;
it ( "should extract PMID" , async function ( ) {
2018-05-07 10:04:11 +00:00
var identifiers = ZUI . extractIdentifiers ( "1 PMID:24297125,222 3-4 1234567890, 123456789" ) ;
assert . lengthOf ( identifiers , 4 ) ;
2017-10-21 07:26:27 +00:00
assert . lengthOf ( Object . keys ( identifiers [ 0 ] ) , 1 ) ;
2018-05-07 10:04:11 +00:00
assert . lengthOf ( Object . keys ( identifiers [ 1 ] ) , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 2 ] ) , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 3 ] ) , 1 ) ;
assert . propertyVal ( identifiers [ 0 ] , "PMID" , "1" ) ;
assert . propertyVal ( identifiers [ 1 ] , "PMID" , "24297125" ) ;
assert . propertyVal ( identifiers [ 2 ] , "PMID" , "222" ) ;
assert . propertyVal ( identifiers [ 3 ] , "PMID" , "123456789" ) ;
2017-10-21 07:26:27 +00:00
} ) ;
2018-04-18 17:03:10 +00:00
it ( "should extract multiple old and new style arXivs" , async function ( ) {
2018-05-07 10:04:11 +00:00
var identifiers = ZUI . extractIdentifiers ( "0706.0044 arXiv:0706.00441v1,12345678,hep-ex/9809001v1, math.GT/0309135." ) ;
2018-04-18 17:03:10 +00:00
assert . lengthOf ( identifiers , 4 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 0 ] ) , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 1 ] ) , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 2 ] ) , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 3 ] ) , 1 ) ;
assert . propertyVal ( identifiers [ 0 ] , "arXiv" , "0706.0044" ) ;
assert . propertyVal ( identifiers [ 1 ] , "arXiv" , "0706.00441" ) ;
assert . propertyVal ( identifiers [ 2 ] , "arXiv" , "hep-ex/9809001" ) ;
assert . propertyVal ( identifiers [ 3 ] , "arXiv" , "math.GT/0309135" ) ;
} ) ;
2021-08-04 23:37:49 +00:00
it ( "should extract ADS bibcodes" , async function ( ) {
var identifiers = ZUI . extractIdentifiers ( "9 2021wfc..rept....8D, 2022MSSP..16208010Y." ) ;
assert . lengthOf ( identifiers , 2 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 0 ] ) , 1 ) ;
assert . lengthOf ( Object . keys ( identifiers [ 1 ] ) , 1 ) ;
assert . propertyVal ( identifiers [ 0 ] , "adsBibcode" , "2021wfc..rept....8D" ) ;
assert . propertyVal ( identifiers [ 1 ] , "adsBibcode" , "2022MSSP..16208010Y" ) ;
} ) ;
2017-10-21 07:26:27 +00:00
} ) ;
2018-12-16 07:11:09 +00:00
2019-10-23 23:02:50 +00:00
describe ( "#resolveLocale()" , function ( ) {
var availableLocales ;
before ( function ( ) {
2022-06-21 03:09:46 +00:00
availableLocales = Services . locale . availableLocales ;
2019-10-23 23:02:50 +00:00
} ) ;
function resolve ( locale ) {
return Zotero . Utilities . Internal . resolveLocale ( locale , availableLocales ) ;
}
it ( "should return en-US for en-US" , function ( ) {
assert . equal ( resolve ( 'en-US' ) , 'en-US' ) ;
} ) ;
it ( "should return en-US for en" , function ( ) {
assert . equal ( resolve ( 'en' ) , 'en-US' ) ;
} ) ;
it ( "should return fr-FR for fr-FR" , function ( ) {
assert . equal ( resolve ( 'fr-FR' ) , 'fr-FR' ) ;
} ) ;
it ( "should return fr-FR for fr" , function ( ) {
assert . equal ( resolve ( 'fr' ) , 'fr-FR' ) ;
} ) ;
it ( "should return ar for ar" , function ( ) {
assert . equal ( resolve ( 'ar' ) , 'ar' ) ;
} ) ;
it ( "should return pt-PT for pt" , function ( ) {
assert . equal ( resolve ( 'pt' ) , 'pt-PT' ) ;
} ) ;
it ( "should return zh-CN for zh-CN" , function ( ) {
assert . equal ( resolve ( 'zh-CN' ) , 'zh-CN' ) ;
} ) ;
it ( "should return zh-TW for zh-TW" , function ( ) {
assert . equal ( resolve ( 'zh-TW' ) , 'zh-TW' ) ;
} ) ;
it ( "should return zh-CN for zh" , function ( ) {
assert . equal ( resolve ( 'zh' ) , 'zh-CN' ) ;
} ) ;
} ) ;
2020-01-16 21:56:25 +00:00
describe ( "#camelToTitleCase()" , function ( ) {
it ( "should convert 'fooBar' to 'Foo Bar'" , function ( ) {
assert . equal ( Zotero . Utilities . Internal . camelToTitleCase ( 'fooBar' ) , 'Foo Bar' ) ;
} ) ;
it ( "should keep all-caps strings intact" , function ( ) {
assert . equal ( Zotero . Utilities . Internal . camelToTitleCase ( 'DOI' ) , 'DOI' ) ;
} ) ;
it ( "should convert 'fooBAR' to 'Foo BAR'" , function ( ) {
assert . equal ( Zotero . Utilities . Internal . camelToTitleCase ( 'fooBAR' ) , 'Foo BAR' ) ;
} ) ;
} ) ;
2018-12-16 07:11:09 +00:00
describe ( "#getNextName()" , function ( ) {
it ( "should get the next available numbered name" , function ( ) {
2018-12-27 12:11:15 +00:00
var existing = [ 'Name' , 'Name 1' , 'Name 3' ] ;
assert . equal ( Zotero . Utilities . Internal . getNextName ( 'Name' , existing ) , 'Name 2' ) ;
2018-12-16 07:11:09 +00:00
} ) ;
2018-12-27 12:11:15 +00:00
it ( "should return 'Name 1' if no numbered names" , function ( ) {
2018-12-16 07:11:09 +00:00
var existing = [ 'Name' ] ;
2018-12-27 12:11:15 +00:00
assert . equal ( Zotero . Utilities . Internal . getNextName ( 'Name' , existing ) , 'Name 1' ) ;
} ) ;
it ( "should return 'Name' if only numbered names" , function ( ) {
var existing = [ 'Name 1' , 'Name 3' ] ;
assert . equal ( Zotero . Utilities . Internal . getNextName ( 'Name' , existing ) , 'Name' ) ;
} ) ;
it ( "should trim given name if trim=true" , function ( ) {
var existing = [ 'Name' , 'Name 1' , 'Name 2' , 'Name 3' ] ;
assert . equal ( Zotero . Utilities . Internal . getNextName ( 'Name 2' , existing , true ) , 'Name 4' ) ;
2018-12-16 07:11:09 +00:00
} ) ;
} ) ;
2021-04-02 08:50:32 +00:00
describe ( "#parseURL()" , function ( ) {
var f ;
before ( ( ) => {
f = Zotero . Utilities . Internal . parseURL ;
} ) ;
describe ( "#fileName" , function ( ) {
it ( "should contain filename" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/def.html?foo=bar' ) , 'fileName' , 'def.html' ) ;
} ) ;
it ( "should be empty if no filename" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/' ) , 'fileName' , '' ) ;
} ) ;
} ) ;
describe ( "#fileExtension" , function ( ) {
it ( "should contain extension" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/def.html?foo=bar' ) , 'fileExtension' , 'html' ) ;
} ) ;
it ( "should be empty if no extension" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/def' ) , 'fileExtension' , '' ) ;
} ) ;
it ( "should be empty if no filename" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/' ) , 'fileExtension' , '' ) ;
} ) ;
} ) ;
describe ( "#fileBaseName" , function ( ) {
it ( "should contain base name" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/def.html?foo=bar' ) , 'fileBaseName' , 'def' ) ;
} ) ;
it ( "should equal filename if no extension" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/def' ) , 'fileBaseName' , 'def' ) ;
} ) ;
it ( "should be empty if no filename" , function ( ) {
assert . propertyVal ( f ( 'http://example.com/abc/' ) , 'fileBaseName' , '' ) ;
} ) ;
} ) ;
} ) ;
2022-02-18 19:38:36 +00:00
describe ( "#generateHTMLFromTemplate()" , function ( ) {
it ( "should support variables with attributes" , function ( ) {
var vars = {
v1 : '1' ,
2023-07-20 10:50:34 +00:00
v2 : pars => ` ${ pars . a1 ? ? '' } ${ pars . a2 ? ? '' } ${ pars . a3 ? ? '' } ` ,
2022-04-11 05:21:23 +00:00
v3 : ( ) => '' ,
v5 : ( ) => 'something' ,
2022-03-11 15:04:47 +00:00
ar1 : [ ] ,
ar2 : [ 1 , 2 ]
2022-02-18 19:38:36 +00:00
} ;
2023-07-20 10:50:34 +00:00
var template = ` {{ v1}}{{v2 a1= "1" a2 =' 2' a3 = "3 "}}{{v3}}{{v4}}{{if ar1}}ar1{{endif}}{{if ar2}}{{ar2}}{{endif}}{{if v5}}yes{{endif}}{{if v3}}no1{{endif}}{{if v2}}{{v2}}{{endif}} ` ;
2022-02-18 19:38:36 +00:00
var html = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
2022-04-11 05:21:23 +00:00
assert . equal ( html , '11 23 1,2yes' ) ;
2022-02-18 19:38:36 +00:00
} ) ;
2022-03-11 15:04:47 +00:00
2023-07-20 10:50:34 +00:00
it ( "should support empty string as attribute value and correctly render returned false-ish values" , function ( ) {
const vars = {
length : ( { string } ) => string . length . toString ( ) ,
} ;
const template = ` "" has a length of {{ length string="" }} and "hello" has a length of {{ length string="hello" }} ` ;
const out = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( out , '"" has a length of 0 and "hello" has a length of 5' ) ;
} ) ;
it ( "should support functions in comparison statements" , function ( ) {
const vars = {
sum : ( { a , b } ) => ( parseInt ( a ) + parseInt ( b ) ) . toString ( ) ,
fooBar : ( { isFoo } ) => ( isFoo === 'true' ? 'foo' : 'bar' ) ,
false : 'false' ,
twoWords : 'two words' ,
onlyOne : 'actually == 1'
} ;
const template = ` {{if {{ sum a="1" b="2" }} == "3"}}1 + 2 = {{sum a="1" b="2"}}{{else}}no speak math{{endif}} ` ;
const out = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( out , '1 + 2 = 3' ) ;
const template2 = '{{if false != "false"}}no{{elseif false == "false"}}yes{{else}}no{{endif}}' ;
const out2 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template2 , vars ) ;
assert . equal ( out2 , 'yes' ) ;
const template3 = '{{ if twoWords == "two words" }}yes{{else}}no{{endif}}' ;
const out3 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template3 , vars ) ;
assert . equal ( out3 , 'yes' ) ;
const template4 = '{{ if onlyOne == \'actually == 1\' }}yes{{else}}no{{endif}}' ;
const out4 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template4 , vars ) ;
assert . equal ( out4 , 'yes' ) ;
const template5 = '{{ if "3" == {{ sum a="1" b="2" }} }}yes{{else}}no{{endif}}' ;
const out5 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template5 , vars ) ;
assert . equal ( out5 , 'yes' ) ;
const template6 = '{{ if {{ sum a="1" b="2" }} }}yes{{else}}no{{endif}}' ;
const out6 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template6 , vars ) ;
assert . equal ( out6 , 'yes' ) ;
const template7 = '{{ if {{ twoWords }} }}yes{{else}}no{{endif}}' ;
const out7 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template7 , vars ) ;
assert . equal ( out7 , 'yes' ) ;
const template8 = '{{ if twoWords }}yes{{else}}no{{endif}}' ;
const out8 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template8 , vars ) ;
assert . equal ( out8 , 'yes' ) ;
const template9 = '{{ if missing }}no{{else}}yes{{endif}}' ;
const out9 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template9 , vars ) ;
assert . equal ( out9 , 'yes' ) ;
const template10 = '{{ if {{ missing foo="bar" }} }}no{{else}}yes{{endif}}' ;
const out10 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template10 , vars ) ;
assert . equal ( out10 , 'yes' ) ;
const template11 = '{{ if {{ missing foo="bar" }} == "" }}yes{{else}}no{{endif}}' ;
const out11 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template11 , vars ) ;
assert . equal ( out11 , 'yes' ) ;
const template12 = '{{ if fooBar == "bar" }}yes{{else}}no{{endif}}' ;
const out12 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template12 , vars ) ;
assert . equal ( out12 , 'yes' ) ;
const template13 = '{{ if {{ fooBar }} == "bar" }}yes{{else}}no{{endif}}' ;
const out13 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template13 , vars ) ;
assert . equal ( out13 , 'yes' ) ;
const template14 = ` {{if {{ sum a="1" b="2" }}=="3"}}1 + 2 = {{sum a="1" b="2"}}{{else}}no{{endif}} ` ;
const out14 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template14 , vars ) ;
assert . equal ( out14 , '1 + 2 = 3' ) ;
const template15 = ` {{if "two words"==twoWords}}yes{{else}}no{{endif}} ` ;
const out15 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template15 , vars ) ;
assert . equal ( out15 , 'yes' ) ;
} ) ;
it ( "should accept hyphen-case variables and attributes" , function ( ) {
const vars = {
fooBar : ( { isFoo } ) => ( isFoo === 'true' ? 'foo' : 'bar' ) ,
} ;
const template = '{{ foo-bar is-foo="true" }}{{ if {{ foo-bar is-foo="false" }} == "bar" }}{{ foo-bar is-foo="false" }}{{ endif }}' ;
const out = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( out , 'foobar' ) ;
} ) ;
it ( "should work with a condition in the middle" , function ( ) {
const vars = {
v1 : '1' ,
} ;
const template = 'test {{ if v1 == "1" }}yes{{ else }}no{{ endif }} foobar' ;
const out = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( out , 'test yes foobar' ) ;
} ) ;
it ( "missing identifiers are evaluted as empty string" , function ( ) {
const vars = {
foo : 'foo' ,
} ;
const template = '{{bar}}{{ if foo == "" }}no{{elseif foo}}{{foo}}{{else}}no{{endif}}' ;
const out = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( out , 'foo' ) ;
const template2 = 'test: {{ if bar == "" }}yes{{else}}no{{endif}}' ;
const out2 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template2 , vars ) ;
assert . equal ( out2 , 'test: yes' ) ;
} ) ;
it ( "should preserve whitespace outside of brackets" , function ( ) {
const template = ' starts }} with {{ whitespace {"test"} == \'foobar\' ' ;
const out = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , { } ) ;
assert . equal ( out , template ) ;
const vars = {
space : ' ' ,
spaceFn : ( ) => ' ' ,
} ;
const whitespace = ' {{if spaceFn}}{{else}} {{endif}}{{space}} {{space-fn}}' ;
const out2 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( whitespace , vars ) ;
assert . equal ( out2 , ' ' ) ;
} ) ;
it ( "should accept array values in logic statements" , function ( ) {
let someTags = [ 'foo' , 'bar' ] ;
const vars = {
tags : ( { join } ) => ( join ? someTags . join ( join ) : someTags ) ,
} ;
const template = '{{ if tags }}#{{ tags join=" #" }}{{else}}no tags{{endif}}' ;
const out = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( out , '#foo #bar' ) ;
someTags = [ ] ;
const out2 = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( out2 , 'no tags' ) ;
} ) ;
it ( "should throw if function returns anything else than a string (or an array which is always joined into string)" , function ( ) {
const vars = {
number : ( ) => 1 ,
logic : ( ) => true ,
array : ( ) => [ ] ,
fn : ( ) => 1 ,
} ;
assert . throws ( ( ) => Zotero . Utilities . Internal . generateHTMLFromTemplate ( '{{ number }}' , vars ) , /Identifier "number" does not evaluate to a string/ ) ;
assert . throws ( ( ) => Zotero . Utilities . Internal . generateHTMLFromTemplate ( '{{ logic }}' , vars ) , /Identifier "logic" does not evaluate to a string/ ) ;
assert . throws ( ( ) => Zotero . Utilities . Internal . generateHTMLFromTemplate ( '{{ if fn }}no{{endif}}' , vars ) , /Identifier "fn" does not evaluate to a string/ ) ;
assert . throws ( ( ) => Zotero . Utilities . Internal . generateHTMLFromTemplate ( '{{ if {{ fn foo="bar" }} }}no{{endif}}' , vars ) , /Identifier "fn" does not evaluate to a string/ ) ;
} ) ;
2022-02-18 19:38:36 +00:00
it ( "should support nested 'if' statements" , function ( ) {
var vars = {
v1 : '1' ,
v2 : 'H' ,
} ;
2023-07-20 10:50:34 +00:00
var template = ` {{if v1 == '1'}}yes1{{if x}}no{{elseif v2 == "h" }}yes2{{endif}}{{elseif v2 == "2"}}no{{else}}no{{endif}} {{if v2 == "1"}}not{{elseif x}}not{{else}}yes3{{ endif}} ` ;
2022-02-18 19:38:36 +00:00
var html = Zotero . Utilities . Internal . generateHTMLFromTemplate ( template , vars ) ;
assert . equal ( html , 'yes1yes2 yes3' ) ;
} ) ;
} ) ;
2023-07-20 10:50:34 +00:00
} ) ;