Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
converse.js
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
converse.js
Commits
debb773e
Commit
debb773e
authored
Jun 01, 2013
by
JC Brand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add jed.js for i18n support and wrap all strings
parent
b7ba673c
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1178 additions
and
131 deletions
+1178
-131
Libraries/jed.js
Libraries/jed.js
+1008
-0
converse.js
converse.js
+170
-131
No files found.
Libraries/jed.js
0 → 100644
View file @
debb773e
/*
jed.js
v0.5.0beta
https://github.com/SlexAxton/Jed
-----------
A gettext compatible i18n library for modern JavaScript Applications
by Alex Sexton - AlexSexton [at] gmail - @SlexAxton
WTFPL license for use
Dojo CLA for contributions
Jed offers the entire applicable GNU gettext spec'd set of
functions, but also offers some nicer wrappers around them.
The api for gettext was written for a language with no function
overloading, so Jed allows a little more of that.
Many thanks to Joshua I. Miller - unrtst@cpan.org - who wrote
gettext.js back in 2008. I was able to vet a lot of my ideas
against his. I also made sure Jed passed against his tests
in order to offer easy upgrades -- jsgettext.berlios.de
*/
(
function
(
root
,
undef
)
{
// Set up some underscore-style functions, if you already have
// underscore, feel free to delete this section, and use it
// directly, however, the amount of functions used doesn't
// warrant having underscore as a full dependency.
// Underscore 1.3.0 was used to port and is licensed
// under the MIT License by Jeremy Ashkenas.
var
ArrayProto
=
Array
.
prototype
,
ObjProto
=
Object
.
prototype
,
slice
=
ArrayProto
.
slice
,
hasOwnProp
=
ObjProto
.
hasOwnProperty
,
nativeForEach
=
ArrayProto
.
forEach
,
breaker
=
{};
// We're not using the OOP style _ so we don't need the
// extra level of indirection. This still means that you
// sub out for real `_` though.
var
_
=
{
forEach
:
function
(
obj
,
iterator
,
context
)
{
var
i
,
l
,
key
;
if
(
obj
===
null
)
{
return
;
}
if
(
nativeForEach
&&
obj
.
forEach
===
nativeForEach
)
{
obj
.
forEach
(
iterator
,
context
);
}
else
if
(
obj
.
length
===
+
obj
.
length
)
{
for
(
i
=
0
,
l
=
obj
.
length
;
i
<
l
;
i
++
)
{
if
(
i
in
obj
&&
iterator
.
call
(
context
,
obj
[
i
],
i
,
obj
)
===
breaker
)
{
return
;
}
}
}
else
{
for
(
key
in
obj
)
{
if
(
hasOwnProp
.
call
(
obj
,
key
)
)
{
if
(
iterator
.
call
(
context
,
obj
[
key
],
key
,
obj
)
===
breaker
)
{
return
;
}
}
}
}
},
extend
:
function
(
obj
)
{
this
.
forEach
(
slice
.
call
(
arguments
,
1
),
function
(
source
)
{
for
(
var
prop
in
source
)
{
obj
[
prop
]
=
source
[
prop
];
}
});
return
obj
;
}
};
// END Miniature underscore impl
// Jed is a constructor function
var
Jed
=
function
(
options
)
{
// Some minimal defaults
this
.
defaults
=
{
"
locale_data
"
:
{
"
messages
"
:
{
""
:
{
"
domain
"
:
"
messages
"
,
"
lang
"
:
"
en
"
,
"
plural_forms
"
:
"
nplurals=2; plural=(n != 1);
"
}
// There are no default keys, though
}
},
// The default domain if one is missing
"
domain
"
:
"
messages
"
};
// Mix in the sent options with the default options
this
.
options
=
_
.
extend
(
{},
this
.
defaults
,
options
);
this
.
textdomain
(
this
.
options
.
domain
);
if
(
options
.
domain
&&
!
this
.
options
.
locale_data
[
this
.
options
.
domain
]
)
{
throw
new
Error
(
'
Text domain set to non-existent domain: `
'
+
options
.
domain
+
'
`
'
);
}
};
// The gettext spec sets this character as the default
// delimiter for context lookups.
// e.g.: context\u0004key
// If your translation company uses something different,
// just change this at any time and it will use that instead.
Jed
.
context_delimiter
=
String
.
fromCharCode
(
4
);
function
getPluralFormFunc
(
plural_form_string
)
{
return
Jed
.
PF
.
compile
(
plural_form_string
||
"
nplurals=2; plural=(n != 1);
"
);
}
function
Chain
(
key
,
i18n
){
this
.
_key
=
key
;
this
.
_i18n
=
i18n
;
}
// Create a chainable api for adding args prettily
_
.
extend
(
Chain
.
prototype
,
{
onDomain
:
function
(
domain
)
{
this
.
_domain
=
domain
;
return
this
;
},
withContext
:
function
(
context
)
{
this
.
_context
=
context
;
return
this
;
},
ifPlural
:
function
(
num
,
pkey
)
{
this
.
_val
=
num
;
this
.
_pkey
=
pkey
;
return
this
;
},
fetch
:
function
(
sArr
)
{
if
(
{}.
toString
.
call
(
sArr
)
!=
'
[object Array]
'
)
{
sArr
=
[].
slice
.
call
(
arguments
);
}
return
(
sArr
&&
sArr
.
length
?
Jed
.
sprintf
:
function
(
x
){
return
x
;
}
)(
this
.
_i18n
.
dcnpgettext
(
this
.
_domain
,
this
.
_context
,
this
.
_key
,
this
.
_pkey
,
this
.
_val
),
sArr
);
}
});
// Add functions to the Jed prototype.
// These will be the functions on the object that's returned
// from creating a `new Jed()`
// These seem redundant, but they gzip pretty well.
_
.
extend
(
Jed
.
prototype
,
{
// The sexier api start point
translate
:
function
(
key
)
{
return
new
Chain
(
key
,
this
);
},
textdomain
:
function
(
domain
)
{
if
(
!
domain
)
{
return
this
.
_textdomain
;
}
this
.
_textdomain
=
domain
;
},
gettext
:
function
(
key
)
{
return
this
.
dcnpgettext
.
call
(
this
,
undef
,
undef
,
key
);
},
dgettext
:
function
(
domain
,
key
)
{
return
this
.
dcnpgettext
.
call
(
this
,
domain
,
undef
,
key
);
},
dcgettext
:
function
(
domain
,
key
/*, category */
)
{
// Ignores the category anyways
return
this
.
dcnpgettext
.
call
(
this
,
domain
,
undef
,
key
);
},
ngettext
:
function
(
skey
,
pkey
,
val
)
{
return
this
.
dcnpgettext
.
call
(
this
,
undef
,
undef
,
skey
,
pkey
,
val
);
},
dngettext
:
function
(
domain
,
skey
,
pkey
,
val
)
{
return
this
.
dcnpgettext
.
call
(
this
,
domain
,
undef
,
skey
,
pkey
,
val
);
},
dcngettext
:
function
(
domain
,
skey
,
pkey
,
val
/*, category */
)
{
return
this
.
dcnpgettext
.
call
(
this
,
domain
,
undef
,
skey
,
pkey
,
val
);
},
pgettext
:
function
(
context
,
key
)
{
return
this
.
dcnpgettext
.
call
(
this
,
undef
,
context
,
key
);
},
dpgettext
:
function
(
domain
,
context
,
key
)
{
return
this
.
dcnpgettext
.
call
(
this
,
domain
,
context
,
key
);
},
dcpgettext
:
function
(
domain
,
context
,
key
/*, category */
)
{
return
this
.
dcnpgettext
.
call
(
this
,
domain
,
context
,
key
);
},
npgettext
:
function
(
context
,
skey
,
pkey
,
val
)
{
return
this
.
dcnpgettext
.
call
(
this
,
undef
,
context
,
skey
,
pkey
,
val
);
},
dnpgettext
:
function
(
domain
,
context
,
skey
,
pkey
,
val
)
{
return
this
.
dcnpgettext
.
call
(
this
,
domain
,
context
,
skey
,
pkey
,
val
);
},
// The most fully qualified gettext function. It has every option.
// Since it has every option, we can use it from every other method.
// This is the bread and butter.
// Technically there should be one more argument in this function for 'Category',
// but since we never use it, we might as well not waste the bytes to define it.
dcnpgettext
:
function
(
domain
,
context
,
singular_key
,
plural_key
,
val
)
{
// Set some defaults
plural_key
=
plural_key
||
singular_key
;
// Use the global domain default if one
// isn't explicitly passed in
domain
=
domain
||
this
.
_textdomain
;
// Default the value to the singular case
val
=
typeof
val
==
'
undefined
'
?
1
:
val
;
var
fallback
;
// Handle special cases
// No options found
if
(
!
this
.
options
)
{
// There's likely something wrong, but we'll return the correct key for english
// We do this by instantiating a brand new Jed instance with the default set
// for everything that could be broken.
fallback
=
new
Jed
();
return
fallback
.
dcnpgettext
.
call
(
fallback
,
undefined
,
undefined
,
singular_key
,
plural_key
,
val
);
}
// No translation data provided
if
(
!
this
.
options
.
locale_data
)
{
throw
new
Error
(
'
No locale data provided.
'
);
}
if
(
!
this
.
options
.
locale_data
[
domain
]
)
{
throw
new
Error
(
'
Domain `
'
+
domain
+
'
` was not found.
'
);
}
if
(
!
this
.
options
.
locale_data
[
domain
][
""
]
)
{
throw
new
Error
(
'
No locale meta information provided.
'
);
}
// Make sure we have a truthy key. Otherwise we might start looking
// into the empty string key, which is the options for the locale
// data.
if
(
!
singular_key
)
{
throw
new
Error
(
'
No translation key found.
'
);
}
// Handle invalid numbers, but try casting strings for good measure
if
(
typeof
val
!=
'
number
'
)
{
val
=
parseInt
(
val
,
10
);
if
(
isNaN
(
val
)
)
{
throw
new
Error
(
'
The number that was passed in is not a number.
'
);
}
}
var
key
=
context
?
context
+
Jed
.
context_delimiter
+
singular_key
:
singular_key
,
locale_data
=
this
.
options
.
locale_data
,
dict
=
locale_data
[
domain
],
pluralForms
=
dict
[
""
].
plural_forms
||
(
locale_data
.
messages
||
this
.
defaults
.
locale_data
.
messages
)[
""
].
plural_forms
,
val_idx
=
getPluralFormFunc
(
pluralForms
)(
val
)
+
1
,
val_list
,
res
;
// Throw an error if a domain isn't found
if
(
!
dict
)
{
throw
new
Error
(
'
No domain named `
'
+
domain
+
'
` could be found.
'
);
}
val_list
=
dict
[
key
];
// If there is no match, then revert back to
// english style singular/plural with the keys passed in.
if
(
!
val_list
||
val_idx
>=
val_list
.
length
)
{
if
(
this
.
options
.
missing_key_callback
)
{
this
.
options
.
missing_key_callback
(
key
);
}
res
=
[
null
,
singular_key
,
plural_key
];
return
res
[
getPluralFormFunc
(
pluralForms
)(
val
)
+
1
];
}
res
=
val_list
[
val_idx
];
// This includes empty strings on purpose
if
(
!
res
)
{
res
=
[
null
,
singular_key
,
plural_key
];
return
res
[
getPluralFormFunc
(
pluralForms
)(
val
)
+
1
];
}
return
res
;
}
});
// We add in sprintf capabilities for post translation value interolation
// This is not internally used, so you can remove it if you have this
// available somewhere else, or want to use a different system.
// We _slightly_ modify the normal sprintf behavior to more gracefully handle
// undefined values.
/**
sprintf() for JavaScript 0.7-beta1
http://www.diveintojavascript.com/projects/javascript-sprintf
Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of sprintf() for JavaScript nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
var
sprintf
=
(
function
()
{
function
get_type
(
variable
)
{
return
Object
.
prototype
.
toString
.
call
(
variable
).
slice
(
8
,
-
1
).
toLowerCase
();
}
function
str_repeat
(
input
,
multiplier
)
{
for
(
var
output
=
[];
multiplier
>
0
;
output
[
--
multiplier
]
=
input
)
{
/* do nothing */
}
return
output
.
join
(
''
);
}
var
str_format
=
function
()
{
if
(
!
str_format
.
cache
.
hasOwnProperty
(
arguments
[
0
]))
{
str_format
.
cache
[
arguments
[
0
]]
=
str_format
.
parse
(
arguments
[
0
]);
}
return
str_format
.
format
.
call
(
null
,
str_format
.
cache
[
arguments
[
0
]],
arguments
);
};
str_format
.
format
=
function
(
parse_tree
,
argv
)
{
var
cursor
=
1
,
tree_length
=
parse_tree
.
length
,
node_type
=
''
,
arg
,
output
=
[],
i
,
k
,
match
,
pad
,
pad_character
,
pad_length
;
for
(
i
=
0
;
i
<
tree_length
;
i
++
)
{
node_type
=
get_type
(
parse_tree
[
i
]);
if
(
node_type
===
'
string
'
)
{
output
.
push
(
parse_tree
[
i
]);
}
else
if
(
node_type
===
'
array
'
)
{
match
=
parse_tree
[
i
];
// convenience purposes only
if
(
match
[
2
])
{
// keyword argument
arg
=
argv
[
cursor
];
for
(
k
=
0
;
k
<
match
[
2
].
length
;
k
++
)
{
if
(
!
arg
.
hasOwnProperty
(
match
[
2
][
k
]))
{
throw
(
sprintf
(
'
[sprintf] property "%s" does not exist
'
,
match
[
2
][
k
]));
}
arg
=
arg
[
match
[
2
][
k
]];
}
}
else
if
(
match
[
1
])
{
// positional argument (explicit)
arg
=
argv
[
match
[
1
]];
}
else
{
// positional argument (implicit)
arg
=
argv
[
cursor
++
];
}
if
(
/
[^
s
]
/
.
test
(
match
[
8
])
&&
(
get_type
(
arg
)
!=
'
number
'
))
{
throw
(
sprintf
(
'
[sprintf] expecting number but found %s
'
,
get_type
(
arg
)));
}
// Jed EDIT
if
(
typeof
arg
==
'
undefined
'
||
arg
===
null
)
{
arg
=
''
;
}
// Jed EDIT
switch
(
match
[
8
])
{
case
'
b
'
:
arg
=
arg
.
toString
(
2
);
break
;
case
'
c
'
:
arg
=
String
.
fromCharCode
(
arg
);
break
;
case
'
d
'
:
arg
=
parseInt
(
arg
,
10
);
break
;
case
'
e
'
:
arg
=
match
[
7
]
?
arg
.
toExponential
(
match
[
7
])
:
arg
.
toExponential
();
break
;
case
'
f
'
:
arg
=
match
[
7
]
?
parseFloat
(
arg
).
toFixed
(
match
[
7
])
:
parseFloat
(
arg
);
break
;
case
'
o
'
:
arg
=
arg
.
toString
(
8
);
break
;
case
'
s
'
:
arg
=
((
arg
=
String
(
arg
))
&&
match
[
7
]
?
arg
.
substring
(
0
,
match
[
7
])
:
arg
);
break
;
case
'
u
'
:
arg
=
Math
.
abs
(
arg
);
break
;
case
'
x
'
:
arg
=
arg
.
toString
(
16
);
break
;
case
'
X
'
:
arg
=
arg
.
toString
(
16
).
toUpperCase
();
break
;
}
arg
=
(
/
[
def
]
/
.
test
(
match
[
8
])
&&
match
[
3
]
&&
arg
>=
0
?
'
+
'
+
arg
:
arg
);
pad_character
=
match
[
4
]
?
match
[
4
]
==
'
0
'
?
'
0
'
:
match
[
4
].
charAt
(
1
)
:
'
'
;
pad_length
=
match
[
6
]
-
String
(
arg
).
length
;
pad
=
match
[
6
]
?
str_repeat
(
pad_character
,
pad_length
)
:
''
;
output
.
push
(
match
[
5
]
?
arg
+
pad
:
pad
+
arg
);
}
}
return
output
.
join
(
''
);
};
str_format
.
cache
=
{};
str_format
.
parse
=
function
(
fmt
)
{
var
_fmt
=
fmt
,
match
=
[],
parse_tree
=
[],
arg_names
=
0
;
while
(
_fmt
)
{
if
((
match
=
/^
[^\x
25
]
+/
.
exec
(
_fmt
))
!==
null
)
{
parse_tree
.
push
(
match
[
0
]);
}
else
if
((
match
=
/^
\x
25
{2}
/
.
exec
(
_fmt
))
!==
null
)
{
parse_tree
.
push
(
'
%
'
);
}
else
if
((
match
=
/^
\x
25
(?:([
1-9
]\d
*
)\$
|
\(([^\)]
+
)\))?(\+)?(
0|'
[^
$
])?(
-
)?(\d
+
)?(?:\.(\d
+
))?([
b-fosuxX
])
/
.
exec
(
_fmt
))
!==
null
)
{
if
(
match
[
2
])
{
arg_names
|=
1
;
var
field_list
=
[],
replacement_field
=
match
[
2
],
field_match
=
[];
if
((
field_match
=
/^
([
a-z_
][
a-z_
\d]
*
)
/i
.
exec
(
replacement_field
))
!==
null
)
{
field_list
.
push
(
field_match
[
1
]);
while
((
replacement_field
=
replacement_field
.
substring
(
field_match
[
0
].
length
))
!==
''
)
{
if
((
field_match
=
/^
\.([
a-z_
][
a-z_
\d]
*
)
/i
.
exec
(
replacement_field
))
!==
null
)
{
field_list
.
push
(
field_match
[
1
]);
}
else
if
((
field_match
=
/^
\[(\d
+
)\]
/
.
exec
(
replacement_field
))
!==
null
)
{
field_list
.
push
(
field_match
[
1
]);
}
else
{
throw
(
'
[sprintf] huh?
'
);
}
}
}
else
{
throw
(
'
[sprintf] huh?
'
);
}
match
[
2
]
=
field_list
;
}
else
{
arg_names
|=
2
;
}
if
(
arg_names
===
3
)
{
throw
(
'
[sprintf] mixing positional and named placeholders is not (yet) supported
'
);
}
parse_tree
.
push
(
match
);
}
else
{
throw
(
'
[sprintf] huh?
'
);
}
_fmt
=
_fmt
.
substring
(
match
[
0
].
length
);
}
return
parse_tree
;
};
return
str_format
;
})();
var
vsprintf
=
function
(
fmt
,
argv
)
{
argv
.
unshift
(
fmt
);
return
sprintf
.
apply
(
null
,
argv
);
};
Jed
.
parse_plural
=
function
(
plural_forms
,
n
)
{
plural_forms
=
plural_forms
.
replace
(
/n/g
,
n
);
return
Jed
.
parse_expression
(
plural_forms
);
};
Jed
.
sprintf
=
function
(
fmt
,
args
)
{
if
(
{}.
toString
.
call
(
args
)
==
'
[object Array]
'
)
{
return
vsprintf
(
fmt
,
[].
slice
.
call
(
args
)
);
}
return
sprintf
.
apply
(
this
,
[].
slice
.
call
(
arguments
)
);
};
Jed
.
prototype
.
sprintf
=
function
()
{
return
Jed
.
sprintf
.
apply
(
this
,
arguments
);
};
// END sprintf Implementation
// Start the Plural forms section
// This is a full plural form expression parser. It is used to avoid
// running 'eval' or 'new Function' directly against the plural
// forms.
//
// This can be important if you get translations done through a 3rd
// party vendor. I encourage you to use this instead, however, I
// also will provide a 'precompiler' that you can use at build time
// to output valid/safe function representations of the plural form
// expressions. This means you can build this code out for the most
// part.
Jed
.
PF
=
{};
Jed
.
PF
.
parse
=
function
(
p
)
{
var
plural_str
=
Jed
.
PF
.
extractPluralExpr
(
p
);
return
Jed
.
PF
.
parser
.
parse
.
call
(
Jed
.
PF
.
parser
,
plural_str
);
};
Jed
.
PF
.
compile
=
function
(
p
)
{
// Handle trues and falses as 0 and 1
function
imply
(
val
)
{
return
(
val
===
true
?
1
:
val
?
val
:
0
);
}
var
ast
=
Jed
.
PF
.
parse
(
p
);
return
function
(
n
)
{
return
imply
(
Jed
.
PF
.
interpreter
(
ast
)(
n
)
);
};
};
Jed
.
PF
.
interpreter
=
function
(
ast
)
{
return
function
(
n
)
{
var
res
;
switch
(
ast
.
type
)
{
case
'
GROUP
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
expr
)(
n
);
case
'
TERNARY
'
:
if
(
Jed
.
PF
.
interpreter
(
ast
.
expr
)(
n
)
)
{
return
Jed
.
PF
.
interpreter
(
ast
.
truthy
)(
n
);
}
return
Jed
.
PF
.
interpreter
(
ast
.
falsey
)(
n
);
case
'
OR
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
||
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
AND
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
&&
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
LT
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
<
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
GT
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
>
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
LTE
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
<=
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
GTE
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
>=
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
EQ
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
==
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
NEQ
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
!=
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
MOD
'
:
return
Jed
.
PF
.
interpreter
(
ast
.
left
)(
n
)
%
Jed
.
PF
.
interpreter
(
ast
.
right
)(
n
);
case
'
VAR
'
:
return
n
;
case
'
NUM
'
:
return
ast
.
val
;
default
:
throw
new
Error
(
"
Invalid Token found.
"
);
}
};
};
Jed
.
PF
.
extractPluralExpr
=
function
(
p
)
{
// trim first
p
=
p
.
replace
(
/^
\s\s
*/
,
''
).
replace
(
/
\s\s
*$/
,
''
);
if
(
!
/;
\s
*$/
.
test
(
p
))
{
p
=
p
.
concat
(
'
;
'
);
}
var
nplurals_re
=
/nplurals
\=(\d
+
)
;/
,
plural_re
=
/plural
\=(
.*
)
;/
,
nplurals_matches
=
p
.
match
(
nplurals_re
),
res
=
{},
plural_matches
;
// Find the nplurals number
if
(
nplurals_matches
.
length
>
1
)
{
res
.
nplurals
=
nplurals_matches
[
1
];
}
else
{
throw
new
Error
(
'
nplurals not found in plural_forms string:
'
+
p
);
}
// remove that data to get to the formula
p
=
p
.
replace
(
nplurals_re
,
""
);
plural_matches
=
p
.
match
(
plural_re
);
if
(
!
(
plural_matches
&&
plural_matches
.
length
>
1
)
)
{
throw
new
Error
(
'
`plural` expression not found:
'
+
p
);
}
return
plural_matches
[
1
];
};
/* Jison generated parser */
Jed
.
PF
.
parser
=
(
function
(){
var
parser
=
{
trace
:
function
trace
()
{
},
yy
:
{},
symbols_
:
{
"
error
"
:
2
,
"
expressions
"
:
3
,
"
e
"
:
4
,
"
EOF
"
:
5
,
"
?
"
:
6
,
"
:
"
:
7
,
"
||
"
:
8
,
"
&&
"
:
9
,
"
<
"
:
10
,
"
<=
"
:
11
,
"
>
"
:
12
,
"
>=
"
:
13
,
"
!=
"
:
14
,
"
==
"
:
15
,
"
%
"
:
16
,
"
(
"
:
17
,
"
)
"
:
18
,
"
n
"
:
19
,
"
NUMBER
"
:
20
,
"
$accept
"
:
0
,
"
$end
"
:
1
},
terminals_
:
{
2
:
"
error
"
,
5
:
"
EOF
"
,
6
:
"
?
"
,
7
:
"
:
"
,
8
:
"
||
"
,
9
:
"
&&
"
,
10
:
"
<
"
,
11
:
"
<=
"
,
12
:
"
>
"
,
13
:
"
>=
"
,
14
:
"
!=
"
,
15
:
"
==
"
,
16
:
"
%
"
,
17
:
"
(
"
,
18
:
"
)
"
,
19
:
"
n
"
,
20
:
"
NUMBER
"
},
productions_
:
[
0
,[
3
,
2
],[
4
,
5
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
3
],[
4
,
1
],[
4
,
1
]],
performAction
:
function
anonymous
(
yytext
,
yyleng
,
yylineno
,
yy
,
yystate
,
$$
,
_$
)
{
var
$0
=
$$
.
length
-
1
;
switch
(
yystate
)
{
case
1
:
return
{
type
:
'
GROUP
'
,
expr
:
$$
[
$0
-
1
]
};
break
;
case
2
:
this
.
$
=
{
type
:
'
TERNARY
'
,
expr
:
$$
[
$0
-
4
],
truthy
:
$$
[
$0
-
2
],
falsey
:
$$
[
$0
]
};
break
;
case
3
:
this
.
$
=
{
type
:
"
OR
"
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
4
:
this
.
$
=
{
type
:
"
AND
"
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
5
:
this
.
$
=
{
type
:
'
LT
'
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
6
:
this
.
$
=
{
type
:
'
LTE
'
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
7
:
this
.
$
=
{
type
:
'
GT
'
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
8
:
this
.
$
=
{
type
:
'
GTE
'
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
9
:
this
.
$
=
{
type
:
'
NEQ
'
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
10
:
this
.
$
=
{
type
:
'
EQ
'
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
11
:
this
.
$
=
{
type
:
'
MOD
'
,
left
:
$$
[
$0
-
2
],
right
:
$$
[
$0
]
};
break
;
case
12
:
this
.
$
=
{
type
:
'
GROUP
'
,
expr
:
$$
[
$0
-
1
]
};
break
;
case
13
:
this
.
$
=
{
type
:
'
VAR
'
};
break
;
case
14
:
this
.
$
=
{
type
:
'
NUM
'
,
val
:
Number
(
yytext
)
};
break
;
}
},
table
:
[{
3
:
1
,
4
:
2
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
1
:[
3
]},{
5
:[
1
,
6
],
6
:[
1
,
7
],
8
:[
1
,
8
],
9
:[
1
,
9
],
10
:[
1
,
10
],
11
:[
1
,
11
],
12
:[
1
,
12
],
13
:[
1
,
13
],
14
:[
1
,
14
],
15
:[
1
,
15
],
16
:[
1
,
16
]},{
4
:
17
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
5
:[
2
,
13
],
6
:[
2
,
13
],
7
:[
2
,
13
],
8
:[
2
,
13
],
9
:[
2
,
13
],
10
:[
2
,
13
],
11
:[
2
,
13
],
12
:[
2
,
13
],
13
:[
2
,
13
],
14
:[
2
,
13
],
15
:[
2
,
13
],
16
:[
2
,
13
],
18
:[
2
,
13
]},{
5
:[
2
,
14
],
6
:[
2
,
14
],
7
:[
2
,
14
],
8
:[
2
,
14
],
9
:[
2
,
14
],
10
:[
2
,
14
],
11
:[
2
,
14
],
12
:[
2
,
14
],
13
:[
2
,
14
],
14
:[
2
,
14
],
15
:[
2
,
14
],
16
:[
2
,
14
],
18
:[
2
,
14
]},{
1
:[
2
,
1
]},{
4
:
18
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
19
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
20
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
21
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
22
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
23
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
24
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
25
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
26
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
4
:
27
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
6
:[
1
,
7
],
8
:[
1
,
8
],
9
:[
1
,
9
],
10
:[
1
,
10
],
11
:[
1
,
11
],
12
:[
1
,
12
],
13
:[
1
,
13
],
14
:[
1
,
14
],
15
:[
1
,
15
],
16
:[
1
,
16
],
18
:[
1
,
28
]},{
6
:[
1
,
7
],
7
:[
1
,
29
],
8
:[
1
,
8
],
9
:[
1
,
9
],
10
:[
1
,
10
],
11
:[
1
,
11
],
12
:[
1
,
12
],
13
:[
1
,
13
],
14
:[
1
,
14
],
15
:[
1
,
15
],
16
:[
1
,
16
]},{
5
:[
2
,
3
],
6
:[
2
,
3
],
7
:[
2
,
3
],
8
:[
2
,
3
],
9
:[
1
,
9
],
10
:[
1
,
10
],
11
:[
1
,
11
],
12
:[
1
,
12
],
13
:[
1
,
13
],
14
:[
1
,
14
],
15
:[
1
,
15
],
16
:[
1
,
16
],
18
:[
2
,
3
]},{
5
:[
2
,
4
],
6
:[
2
,
4
],
7
:[
2
,
4
],
8
:[
2
,
4
],
9
:[
2
,
4
],
10
:[
1
,
10
],
11
:[
1
,
11
],
12
:[
1
,
12
],
13
:[
1
,
13
],
14
:[
1
,
14
],
15
:[
1
,
15
],
16
:[
1
,
16
],
18
:[
2
,
4
]},{
5
:[
2
,
5
],
6
:[
2
,
5
],
7
:[
2
,
5
],
8
:[
2
,
5
],
9
:[
2
,
5
],
10
:[
2
,
5
],
11
:[
2
,
5
],
12
:[
2
,
5
],
13
:[
2
,
5
],
14
:[
2
,
5
],
15
:[
2
,
5
],
16
:[
1
,
16
],
18
:[
2
,
5
]},{
5
:[
2
,
6
],
6
:[
2
,
6
],
7
:[
2
,
6
],
8
:[
2
,
6
],
9
:[
2
,
6
],
10
:[
2
,
6
],
11
:[
2
,
6
],
12
:[
2
,
6
],
13
:[
2
,
6
],
14
:[
2
,
6
],
15
:[
2
,
6
],
16
:[
1
,
16
],
18
:[
2
,
6
]},{
5
:[
2
,
7
],
6
:[
2
,
7
],
7
:[
2
,
7
],
8
:[
2
,
7
],
9
:[
2
,
7
],
10
:[
2
,
7
],
11
:[
2
,
7
],
12
:[
2
,
7
],
13
:[
2
,
7
],
14
:[
2
,
7
],
15
:[
2
,
7
],
16
:[
1
,
16
],
18
:[
2
,
7
]},{
5
:[
2
,
8
],
6
:[
2
,
8
],
7
:[
2
,
8
],
8
:[
2
,
8
],
9
:[
2
,
8
],
10
:[
2
,
8
],
11
:[
2
,
8
],
12
:[
2
,
8
],
13
:[
2
,
8
],
14
:[
2
,
8
],
15
:[
2
,
8
],
16
:[
1
,
16
],
18
:[
2
,
8
]},{
5
:[
2
,
9
],
6
:[
2
,
9
],
7
:[
2
,
9
],
8
:[
2
,
9
],
9
:[
2
,
9
],
10
:[
2
,
9
],
11
:[
2
,
9
],
12
:[
2
,
9
],
13
:[
2
,
9
],
14
:[
2
,
9
],
15
:[
2
,
9
],
16
:[
1
,
16
],
18
:[
2
,
9
]},{
5
:[
2
,
10
],
6
:[
2
,
10
],
7
:[
2
,
10
],
8
:[
2
,
10
],
9
:[
2
,
10
],
10
:[
2
,
10
],
11
:[
2
,
10
],
12
:[
2
,
10
],
13
:[
2
,
10
],
14
:[
2
,
10
],
15
:[
2
,
10
],
16
:[
1
,
16
],
18
:[
2
,
10
]},{
5
:[
2
,
11
],
6
:[
2
,
11
],
7
:[
2
,
11
],
8
:[
2
,
11
],
9
:[
2
,
11
],
10
:[
2
,
11
],
11
:[
2
,
11
],
12
:[
2
,
11
],
13
:[
2
,
11
],
14
:[
2
,
11
],
15
:[
2
,
11
],
16
:[
2
,
11
],
18
:[
2
,
11
]},{
5
:[
2
,
12
],
6
:[
2
,
12
],
7
:[
2
,
12
],
8
:[
2
,
12
],
9
:[
2
,
12
],
10
:[
2
,
12
],
11
:[
2
,
12
],
12
:[
2
,
12
],
13
:[
2
,
12
],
14
:[
2
,
12
],
15
:[
2
,
12
],
16
:[
2
,
12
],
18
:[
2
,
12
]},{
4
:
30
,
17
:[
1
,
3
],
19
:[
1
,
4
],
20
:[
1
,
5
]},{
5
:[
2
,
2
],
6
:[
1
,
7
],
7
:[
2
,
2
],
8
:[
1
,
8
],
9
:[
1
,
9
],
10
:[
1
,
10
],
11
:[
1
,
11
],
12
:[
1
,
12
],
13
:[
1
,
13
],
14
:[
1
,
14
],
15
:[
1
,
15
],
16
:[
1
,
16
],
18
:[
2
,
2
]}],
defaultActions
:
{
6
:[
2
,
1
]},
parseError
:
function
parseError
(
str
,
hash
)
{
throw
new
Error
(
str
);
},
parse
:
function
parse
(
input
)
{
var
self
=
this
,
stack
=
[
0
],
vstack
=
[
null
],
// semantic value stack
lstack
=
[],
// location stack
table
=
this
.
table
,
yytext
=
''
,
yylineno
=
0
,
yyleng
=
0
,
recovering
=
0
,
TERROR
=
2
,
EOF
=
1
;
//this.reductionCount = this.shiftCount = 0;
this
.
lexer
.
setInput
(
input
);
this
.
lexer
.
yy
=
this
.
yy
;
this
.
yy
.
lexer
=
this
.
lexer
;
if
(
typeof
this
.
lexer
.
yylloc
==
'
undefined
'
)
this
.
lexer
.
yylloc
=
{};
var
yyloc
=
this
.
lexer
.
yylloc
;
lstack
.
push
(
yyloc
);
if
(
typeof
this
.
yy
.
parseError
===
'
function
'
)
this
.
parseError
=
this
.
yy
.
parseError
;
function
popStack
(
n
)
{
stack
.
length
=
stack
.
length
-
2
*
n
;
vstack
.
length
=
vstack
.
length
-
n
;
lstack
.
length
=
lstack
.
length
-
n
;
}
function
lex
()
{
var
token
;
token
=
self
.
lexer
.
lex
()
||
1
;
// $end = 1
// if token isn't its numeric value, convert
if
(
typeof
token
!==
'
number
'
)
{
token
=
self
.
symbols_
[
token
]
||
token
;
}
return
token
;
}
var
symbol
,
preErrorSymbol
,
state
,
action
,
a
,
r
,
yyval
=
{},
p
,
len
,
newState
,
expected
;
while
(
true
)
{
// retreive state number from top of stack
state
=
stack
[
stack
.
length
-
1
];
// use default actions if available
if
(
this
.
defaultActions
[
state
])
{
action
=
this
.
defaultActions
[
state
];
}
else
{
if
(
symbol
==
null
)
symbol
=
lex
();
// read action for current state and first input
action
=
table
[
state
]
&&
table
[
state
][
symbol
];
}
// handle parse error
_handle_error
:
if
(
typeof
action
===
'
undefined
'
||
!
action
.
length
||
!
action
[
0
])
{
if
(
!
recovering
)
{
// Report error
expected
=
[];
for
(
p
in
table
[
state
])
if
(
this
.
terminals_
[
p
]
&&
p
>
2
)
{
expected
.
push
(
"
'
"
+
this
.
terminals_
[
p
]
+
"
'
"
);
}
var
errStr
=
''
;
if
(
this
.
lexer
.
showPosition
)
{
errStr
=
'
Parse error on line
'
+
(
yylineno
+
1
)
+
"
:
\n
"
+
this
.
lexer
.
showPosition
()
+
"
\n
Expecting
"
+
expected
.
join
(
'
,
'
)
+
"
, got '
"
+
this
.
terminals_
[
symbol
]
+
"
'
"
;
}
else
{
errStr
=
'
Parse error on line
'
+
(
yylineno
+
1
)
+
"
: Unexpected
"
+
(
symbol
==
1
/*EOF*/
?
"
end of input
"
:
(
"
'
"
+
(
this
.
terminals_
[
symbol
]
||
symbol
)
+
"
'
"
));
}
this
.
parseError
(
errStr
,
{
text
:
this
.
lexer
.
match
,
token
:
this
.
terminals_
[
symbol
]
||
symbol
,
line
:
this
.
lexer
.
yylineno
,
loc
:
yyloc
,
expected
:
expected
});
}
// just recovered from another error
if
(
recovering
==
3
)
{
if
(
symbol
==
EOF
)
{
throw
new
Error
(
errStr
||
'
Parsing halted.
'
);
}
// discard current lookahead and grab another
yyleng
=
this
.
lexer
.
yyleng
;
yytext
=
this
.
lexer
.
yytext
;
yylineno
=
this
.
lexer
.
yylineno
;
yyloc
=
this
.
lexer
.
yylloc
;
symbol
=
lex
();
}
// try to recover from error
while
(
1
)
{
// check for error recovery rule in this state
if
((
TERROR
.
toString
())
in
table
[
state
])
{
break
;
}
if
(
state
==
0
)
{
throw
new
Error
(
errStr
||
'
Parsing halted.
'
);
}
popStack
(
1
);
state
=
stack
[
stack
.
length
-
1
];
}
preErrorSymbol
=
symbol
;
// save the lookahead token
symbol
=
TERROR
;
// insert generic error symbol as new lookahead
state
=
stack
[
stack
.
length
-
1
];
action
=
table
[
state
]
&&
table
[
state
][
TERROR
];
recovering
=
3
;
// allow 3 real symbols to be shifted before reporting a new error
}
// this shouldn't happen, unless resolve defaults are off
if
(
action
[
0
]
instanceof
Array
&&
action
.
length
>
1
)
{
throw
new
Error
(
'
Parse Error: multiple actions possible at state:
'
+
state
+
'
, token:
'
+
symbol
);
}
switch
(
action
[
0
])
{
case
1
:
// shift
//this.shiftCount++;
stack
.
push
(
symbol
);
vstack
.
push
(
this
.
lexer
.
yytext
);
lstack
.
push
(
this
.
lexer
.
yylloc
);
stack
.
push
(
action
[
1
]);
// push state
symbol
=
null
;
if
(
!
preErrorSymbol
)
{
// normal execution/no error
yyleng
=
this
.
lexer
.
yyleng
;
yytext
=
this
.
lexer
.
yytext
;
yylineno
=
this
.
lexer
.
yylineno
;
yyloc
=
this
.
lexer
.
yylloc
;
if
(
recovering
>
0
)
recovering
--
;
}
else
{
// error just occurred, resume old lookahead f/ before error
symbol
=
preErrorSymbol
;
preErrorSymbol
=
null
;
}
break
;
case
2
:
// reduce
//this.reductionCount++;
len
=
this
.
productions_
[
action
[
1
]][
1
];
// perform semantic action
yyval
.
$
=
vstack
[
vstack
.
length
-
len
];
// default to $$ = $1
// default location, uses first token for firsts, last for lasts
yyval
.
_$
=
{
first_line
:
lstack
[
lstack
.
length
-
(
len
||
1
)].
first_line
,
last_line
:
lstack
[
lstack
.
length
-
1
].
last_line
,
first_column
:
lstack
[
lstack
.
length
-
(
len
||
1
)].
first_column
,
last_column
:
lstack
[
lstack
.
length
-
1
].
last_column
};
r
=
this
.
performAction
.
call
(
yyval
,
yytext
,
yyleng
,
yylineno
,
this
.
yy
,
action
[
1
],
vstack
,
lstack
);
if
(
typeof
r
!==
'
undefined
'
)
{
return
r
;
}
// pop off stack
if
(
len
)
{
stack
=
stack
.
slice
(
0
,
-
1
*
len
*
2
);
vstack
=
vstack
.
slice
(
0
,
-
1
*
len
);
lstack
=
lstack
.
slice
(
0
,
-
1
*
len
);
}
stack
.
push
(
this
.
productions_
[
action
[
1
]][
0
]);
// push nonterminal (reduce)
vstack
.
push
(
yyval
.
$
);
lstack
.
push
(
yyval
.
_$
);
// goto new state = table[STATE][NONTERMINAL]
newState
=
table
[
stack
[
stack
.
length
-
2
]][
stack
[
stack
.
length
-
1
]];
stack
.
push
(
newState
);
break
;
case
3
:
// accept
return
true
;
}
}
return
true
;
}};
/* Jison generated lexer */
var
lexer
=
(
function
(){
var
lexer
=
({
EOF
:
1
,
parseError
:
function
parseError
(
str
,
hash
)
{
if
(
this
.
yy
.
parseError
)
{
this
.
yy
.
parseError
(
str
,
hash
);
}
else
{
throw
new
Error
(
str
);
}
},
setInput
:
function
(
input
)
{
this
.
_input
=
input
;
this
.
_more
=
this
.
_less
=
this
.
done
=
false
;
this
.
yylineno
=
this
.
yyleng
=
0
;
this
.
yytext
=
this
.
matched
=
this
.
match
=
''
;
this
.
conditionStack
=
[
'
INITIAL
'
];
this
.
yylloc
=
{
first_line
:
1
,
first_column
:
0
,
last_line
:
1
,
last_column
:
0
};
return
this
;
},
input
:
function
()
{
var
ch
=
this
.
_input
[
0
];
this
.
yytext
+=
ch
;
this
.
yyleng
++
;
this
.
match
+=
ch
;
this
.
matched
+=
ch
;
var
lines
=
ch
.
match
(
/
\n
/
);
if
(
lines
)
this
.
yylineno
++
;
this
.
_input
=
this
.
_input
.
slice
(
1
);
return
ch
;
},
unput
:
function
(
ch
)
{
this
.
_input
=
ch
+
this
.
_input
;
return
this
;
},
more
:
function
()
{
this
.
_more
=
true
;
return
this
;
},
pastInput
:
function
()
{
var
past
=
this
.
matched
.
substr
(
0
,
this
.
matched
.
length
-
this
.
match
.
length
);
return
(
past
.
length
>
20
?
'
...
'
:
''
)
+
past
.
substr
(
-
20
).
replace
(
/
\n
/g
,
""
);
},
upcomingInput
:
function
()
{
var
next
=
this
.
match
;
if
(
next
.
length
<
20
)
{
next
+=
this
.
_input
.
substr
(
0
,
20
-
next
.
length
);
}
return
(
next
.
substr
(
0
,
20
)
+
(
next
.
length
>
20
?
'
...
'
:
''
)).
replace
(
/
\n
/g
,
""
);
},
showPosition
:
function
()
{
var
pre
=
this
.
pastInput
();
var
c
=
new
Array
(
pre
.
length
+
1
).
join
(
"
-
"
);
return
pre
+
this
.
upcomingInput
()
+
"
\n
"
+
c
+
"
^
"
;
},
next
:
function
()
{
if
(
this
.
done
)
{
return
this
.
EOF
;
}
if
(
!
this
.
_input
)
this
.
done
=
true
;
var
token
,
match
,
col
,
lines
;
if
(
!
this
.
_more
)
{
this
.
yytext
=
''
;
this
.
match
=
''
;
}
var
rules
=
this
.
_currentRules
();
for
(
var
i
=
0
;
i
<
rules
.
length
;
i
++
)
{
match
=
this
.
_input
.
match
(
this
.
rules
[
rules
[
i
]]);
if
(
match
)
{
lines
=
match
[
0
].
match
(
/
\n
.*/g
);
if
(
lines
)
this
.
yylineno
+=
lines
.
length
;
this
.
yylloc
=
{
first_line
:
this
.
yylloc
.
last_line
,
last_line
:
this
.
yylineno
+
1
,
first_column
:
this
.
yylloc
.
last_column
,
last_column
:
lines
?
lines
[
lines
.
length
-
1
].
length
-
1
:
this
.
yylloc
.
last_column
+
match
[
0
].
length
}
this
.
yytext
+=
match
[
0
];
this
.
match
+=
match
[
0
];
this
.
matches
=
match
;
this
.
yyleng
=
this
.
yytext
.
length
;
this
.
_more
=
false
;
this
.
_input
=
this
.
_input
.
slice
(
match
[
0
].
length
);
this
.
matched
+=
match
[
0
];
token
=
this
.
performAction
.
call
(
this
,
this
.
yy
,
this
,
rules
[
i
],
this
.
conditionStack
[
this
.
conditionStack
.
length
-
1
]);
if
(
token
)
return
token
;
else
return
;
}
}
if
(
this
.
_input
===
""
)
{
return
this
.
EOF
;
}
else
{
this
.
parseError
(
'
Lexical error on line
'
+
(
this
.
yylineno
+
1
)
+
'
. Unrecognized text.
\n
'
+
this
.
showPosition
(),
{
text
:
""
,
token
:
null
,
line
:
this
.
yylineno
});
}
},
lex
:
function
lex
()
{
var
r
=
this
.
next
();
if
(
typeof
r
!==
'
undefined
'
)
{
return
r
;
}
else
{
return
this
.
lex
();
}
},
begin
:
function
begin
(
condition
)
{
this
.
conditionStack
.
push
(
condition
);
},
popState
:
function
popState
()
{
return
this
.
conditionStack
.
pop
();
},
_currentRules
:
function
_currentRules
()
{
return
this
.
conditions
[
this
.
conditionStack
[
this
.
conditionStack
.
length
-
1
]].
rules
;
},
topState
:
function
()
{
return
this
.
conditionStack
[
this
.
conditionStack
.
length
-
2
];
},
pushState
:
function
begin
(
condition
)
{
this
.
begin
(
condition
);
}});
lexer
.
performAction
=
function
anonymous
(
yy
,
yy_
,
$avoiding_name_collisions
,
YY_START
)
{
var
YYSTATE
=
YY_START
;
switch
(
$avoiding_name_collisions
)
{
case
0
:
/* skip whitespace */
break
;
case
1
:
return
20
break
;
case
2
:
return
19
break
;
case
3
:
return
8
break
;
case
4
:
return
9
break
;
case
5
:
return
6
break
;
case
6
:
return
7
break
;
case
7
:
return
11
break
;
case
8
:
return
13
break
;
case
9
:
return
10
break
;
case
10
:
return
12
break
;
case
11
:
return
14
break
;
case
12
:
return
15
break
;
case
13
:
return
16
break
;
case
14
:
return
17
break
;
case
15
:
return
18
break
;
case
16
:
return
5
break
;
case
17
:
return
'
INVALID
'
break
;
}
};
lexer
.
rules
=
[
/^
\s
+/
,
/^
[
0-9
]
+
(\.[
0-9
]
+
)?\b
/
,
/^n
\b
/
,
/^
\|\|
/
,
/^&&/
,
/^
\?
/
,
/^:/
,
/^<=/
,
/^>=/
,
/^</
,
/^>/
,
/^!=/
,
/^==/
,
/^%/
,
/^
\(
/
,
/^
\)
/
,
/^$/
,
/^./
];
lexer
.
conditions
=
{
"
INITIAL
"
:{
"
rules
"
:[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
,
8
,
9
,
10
,
11
,
12
,
13
,
14
,
15
,
16
,
17
],
"
inclusive
"
:
true
}};
return
lexer
;})()
parser
.
lexer
=
lexer
;
return
parser
;
})();
// End parser
// Handle node, amd, and global systems
if
(
typeof
exports
!==
'
undefined
'
)
{
if
(
typeof
module
!==
'
undefined
'
&&
module
.
exports
)
{
exports
=
module
.
exports
=
Jed
;
}
exports
.
Jed
=
Jed
;
}
else
{
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
define
(
'
jed
'
,
function
()
{
return
Jed
;
});
}
// Leak a global regardless of module system
root
[
'
Jed
'
]
=
Jed
;
}
})(
this
);
converse.js
View file @
debb773e
...
...
@@ -14,6 +14,7 @@
if
(
typeof
define
===
'
function
'
&&
define
.
amd
)
{
require
.
config
({
paths
:
{
"
jed
"
:
"
Libraries/jed
"
,
"
sjcl
"
:
"
Libraries/sjcl
"
,
"
tinysort
"
:
"
Libraries/jquery.tinysort
"
,
"
underscore
"
:
"
Libraries/underscore
"
,
...
...
@@ -48,6 +49,7 @@
});
define
(
"
converse
"
,
[
"
jed
"
,
"
localstorage
"
,
"
tinysort
"
,
"
sjcl
"
,
...
...
@@ -61,7 +63,7 @@
evaluate
:
/
\{\[([\s\S]
+
?)\]\}
/g
,
interpolate
:
/
\{\{([\s\S]
+
?)\}\}
/g
};
return
factory
(
jQuery
,
_
,
console
);
return
factory
(
jQuery
,
_
,
Jed
,
console
);
}
);
}
else
{
...
...
@@ -72,16 +74,37 @@
};
root
.
converse
=
factory
(
jQuery
,
_
,
console
||
{
log
:
function
(){}});
}
}(
this
,
function
(
$
,
_
,
console
)
{
}(
this
,
function
(
$
,
_
,
Jed
,
console
)
{
var
converse
=
{};
converse
.
msg_counter
=
0
;
var
strinclude
=
function
(
str
,
needle
){
if
(
needle
===
''
)
{
return
true
;
}
if
(
str
===
null
)
{
return
false
;
}
return
String
(
str
).
indexOf
(
needle
)
!==
-
1
;
var
i18n
=
new
Jed
({
domain
:
"
messages
"
,
// This is the translation data, which is often generated by
// a po2json converter. You would ideally have one per locale
// and only pull in the locale_data that you need.
"
locale_data
"
:
{
// This is the domain key
"
messages
"
:
{
// The empty string key is used as the configuration
// block for each domain
""
:
{
"
domain
"
:
"
messages
"
,
"
lang
"
:
"
en
"
,
"
plural_forms
"
:
"
nplurals=2; plural=(n != 1);
"
}
}
}
});
var
__
=
function
(
str
)
{
var
t
=
i18n
.
translate
(
str
);
if
(
arguments
.
length
>
1
)
{
return
t
.
fetch
.
apply
(
t
,
[].
slice
.
call
(
arguments
,
1
));
}
else
{
return
t
.
fetch
();
}
};
converse
.
msg_counter
=
0
;
converse
.
autoLink
=
function
(
text
)
{
// Convert URLs into hyperlinks
var
re
=
/
((
http|https|ftp
)
:
\/\/[\w
?=&.
\/\-
;#~%
\-]
+
(?![\w\s
?&.
\/
;#~%"=
\-]
*>
))
/g
;
...
...
@@ -390,9 +413,9 @@
}
else
if
(
match
[
1
]
===
"
help
"
)
{
msgs
=
[
'
<strong>/help</strong>:
Show this menu
'
,
'
<strong>/me</strong>:
Write in the third person
'
,
'
<strong>/clear</strong>:
Remove messages
'
'
<strong>/help</strong>:
'
+
__
(
'
Show this menu
'
)
+
'
'
,
'
<strong>/me</strong>:
'
+
__
(
'
Write in the third person
'
)
+
'
'
,
'
<strong>/clear</strong>:
'
+
__
(
'
Remove messages
'
)
+
'
'
];
this
.
addHelpMessages
(
msgs
);
return
;
...
...
@@ -532,7 +555,7 @@
'
<textarea
'
+
'
type="text"
'
+
'
class="chat-textarea"
'
+
'
placeholder="
Personal message
"/>
'
+
'
placeholder="
'
+
__
(
'
Personal message
'
)
+
'
"/>
'
+
'
</form>
'
),
renderAvatar
:
function
()
{
...
...
@@ -606,21 +629,22 @@
'
click a.subscribe-to-user
'
:
'
addContactFromList
'
},
tab_template
:
_
.
template
(
'
<li><a class="s current" href="#users">
Contacts
</a></li>
'
),
tab_template
:
_
.
template
(
'
<li><a class="s current" href="#users">
'
+
__
(
'
Contacts
'
)
+
'
</a></li>
'
),
template
:
_
.
template
(
'
<form class="set-xmpp-status" action="" method="post">
'
+
'
<span id="xmpp-status-holder">
'
+
'
<select id="select-xmpp-status" style="display:none">
'
+
'
<option value="online">
Online
</option>
'
+
'
<option value="dnd">
Busy
</option>
'
+
'
<option value="away">
Away
</option>
'
+
'
<option value="offline">
Offline
</option>
'
+
'
<option value="online">
'
+
__
(
'
Online
'
)
+
'
</option>
'
+
'
<option value="dnd">
'
+
__
(
'
Busy
'
)
+
'
</option>
'
+
'
<option value="away">
'
+
__
(
'
Away
'
)
+
'
</option>
'
+
'
<option value="offline">
'
+
__
(
'
Offline
'
)
+
'
</option>
'
+
'
</select>
'
+
'
</span>
'
+
'
</form>
'
+
'
<dl class="add-converse-contact dropdown">
'
+
'
<dt id="xmpp-contact-search" class="fancy-dropdown">
'
+
'
<a class="toggle-xmpp-contact-form" href="#" title="Click to add new chat contacts">Add a contact</a>
'
+
'
<a class="toggle-xmpp-contact-form" href="#"
'
+
'
title="
'
+
__
(
'
Click to add new chat contacts
'
)
+
'
">
'
+
__
(
'
Add a contact
'
)
+
'
</a>
'
+
'
</dt>
'
+
'
<dd class="search-xmpp" style="display:none"><ul></ul></dd>
'
+
'
</dl>
'
...
...
@@ -629,8 +653,8 @@
add_contact_template
:
_
.
template
(
'
<li>
'
+
'
<form class="add-xmpp-contact">
'
+
'
<input type="text" name="identifier" class="username" placeholder="
Contact username
"/>
'
+
'
<button type="submit">
Add
</button>
'
+
'
<input type="text" name="identifier" class="username" placeholder="
'
+
__
(
'
Contact username
'
)
+
'
"/>
'
+
'
<button type="submit">
'
+
__
(
'
Add
'
)
+
'
</button>
'
+
'
</form>
'
+
'
<li>
'
),
...
...
@@ -638,8 +662,8 @@
search_contact_template
:
_
.
template
(
'
<li>
'
+
'
<form class="search-xmpp-contact">
'
+
'
<input type="text" name="identifier" class="username" placeholder="
Contact name
"/>
'
+
'
<button type="submit">
Search
</button>
'
+
'
<input type="text" name="identifier" class="username" placeholder="
'
+
__
(
'
Contact name
'
)
+
'
"/>
'
+
'
<button type="submit">
'
+
__
(
'
Search
'
)
+
'
</button>
'
+
'
</form>
'
+
'
<li>
'
),
...
...
@@ -674,14 +698,14 @@
$ul
.
find
(
'
li.found-user
'
).
remove
();
$ul
.
find
(
'
li.chat-info
'
).
remove
();
if
(
!
data
.
length
)
{
$ul
.
append
(
'
<li class="chat-info">
No users found
</li>
'
);
$ul
.
append
(
'
<li class="chat-info">
'
+
__
(
'
No users found
'
)
+
'
</li>
'
);
}
$
(
data
).
each
(
function
(
idx
,
obj
)
{
$ul
.
append
(
$
(
'
<li class="found-user"></li>
'
)
.
append
(
$
(
'
<a class="subscribe-to-user" href="#" title="
Click to add as a chat contact
"></a>
'
)
$
(
'
<a class="subscribe-to-user" href="#" title="
'
+
__
(
'
Click to add as a chat contact
'
)
+
'
"></a>
'
)
.
attr
(
'
data-recipient
'
,
Strophe
.
escapeNode
(
obj
.
id
)
+
'
@
'
+
converse
.
domain
)
.
text
(
obj
.
fullname
)
)
...
...
@@ -744,61 +768,63 @@
},
room_template
:
_
.
template
(
'
<dd class="available-chatroom">
'
+
'
<a class="open-room" data-room-jid="{{jid}}" title="Click to open this room" href="#">{{name}}</a>
'
+
'
<a class="room-info" data-room-jid="{{jid}}" title="Show more information on this room" href="#"> </a>
'
+
'
<a class="open-room" data-room-jid="{{jid}}"
'
+
'
title="
'
+
__
(
'
Click to open this room
'
)
+
'
" href="#">{{name}}</a>
'
+
'
<a class="room-info" data-room-jid="{{jid}}"
'
+
'
title="
'
+
__
(
'
Show more information on this room
'
)
+
'
" href="#"> </a>
'
+
'
</dd>
'
),
room_description_template
:
_
.
template
(
'
<div class="room-info">
'
+
'
<p class="room-info"><strong>
Description:
</strong> {{desc}}</p>
'
+
'
<p class="room-info"><strong>
Occupants:
</strong> {{occ}}</p>
'
+
'
<p class="room-info"><strong>
Features:
</strong> <ul>
'
+
'
<p class="room-info"><strong>
'
+
__
(
'
Description:
'
)
+
'
</strong> {{desc}}</p>
'
+
'
<p class="room-info"><strong>
'
+
__
(
'
Occupants:
'
)
+
'
</strong> {{occ}}</p>
'
+
'
<p class="room-info"><strong>
'
+
__
(
'
Features:
'
)
+
'
</strong> <ul>
'
+
'
{[ if (passwordprotected) { ]}
'
+
'
<li class="room-info locked">
Requires authentication
</li>
'
+
'
<li class="room-info locked">
'
+
__
(
'
Requires authentication
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (hidden) { ]}
'
+
'
<li class="room-info">
Hidden
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Hidden
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (membersonly) { ]}
'
+
'
<li class="room-info">
Requires an invitation
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Requires an invitation
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (moderated) { ]}
'
+
'
<li class="room-info">
Moderated
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Moderated
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (nonanonymous) { ]}
'
+
'
<li class="room-info">
Non-anonymous
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Non-anonymous
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (open) { ]}
'
+
'
<li class="room-info">
Open room
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Open room
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (persistent) { ]}
'
+
'
<li class="room-info">
Permanent room
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Permanent room
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (publicroom) { ]}
'
+
'
<li class="room-info">
Public
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Public
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (semianonymous) { ]}
'
+
'
<li class="room-info">
Semi-anonymous
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Semi-anonymous
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (temporary) { ]}
'
+
'
<li class="room-info">
Temporary room
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Temporary room
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
{[ if (unmoderated) { ]}
'
+
'
<li class="room-info">
Unmoderated
</li>
'
+
'
<li class="room-info">
'
+
__
(
'
Unmoderated
'
)
+
'
</li>
'
+
'
{[ } ]}
'
+
'
</p>
'
+
'
</div>
'
),
tab_template
:
_
.
template
(
'
<li><a class="s" href="#chatrooms">
Rooms
</a></li>
'
),
tab_template
:
_
.
template
(
'
<li><a class="s" href="#chatrooms">
'
+
__
(
'
Rooms
'
)
+
'
</a></li>
'
),
template
:
_
.
template
(
'
<form class="add-chatroom" action="" method="post">
'
+
'
<input type="text" name="chatroom" class="new-chatroom-name" placeholder="
Room name
"/>
'
+
'
<input type="text" name="nick" class="new-chatroom-nick" placeholder="
Nickname
"/>
'
+
'
<input type="{{ server_input_type }}" name="server" class="new-chatroom-server" placeholder="
Server
"/>
'
+
'
<input type="submit" name="join" value="
Join
"/>
'
+
'
<input type="button" name="show" id="show-rooms" value="
Show rooms
"/>
'
+
'
<input type="text" name="chatroom" class="new-chatroom-name" placeholder="
'
+
__
(
'
Room name
'
)
+
'
"/>
'
+
'
<input type="text" name="nick" class="new-chatroom-nick" placeholder="
'
+
__
(
'
Nickname
'
)
+
'
"/>
'
+
'
<input type="{{ server_input_type }}" name="server" class="new-chatroom-server" placeholder="
'
+
__
(
'
Server
'
)
+
'
"/>
'
+
'
<input type="submit" name="join" value="
'
+
__
(
'
Join
'
)
+
'
"/>
'
+
'
<input type="button" name="show" id="show-rooms" value="
'
+
__
(
'
Show rooms
'
)
+
'
"/>
'
+
'
</form>
'
+
'
<dl id="available-chatrooms"></dl>
'
),
...
...
@@ -1063,7 +1089,7 @@
}
}
});
converse
.
xmppstatusview
=
new
converse
.
XMPPStatusView
({
'
model
'
:
converse
.
xmppstatus
})
converse
.
xmppstatusview
=
new
converse
.
XMPPStatusView
({
'
model
'
:
converse
.
xmppstatus
})
;
converse
.
xmppstatusview
.
render
();
this
.
roomspanel
=
new
converse
.
RoomsPanel
();
this
.
roomspanel
.
$parent
=
this
.
$el
;
...
...
@@ -1112,12 +1138,12 @@
case
'
help
'
:
$chat_content
=
this
.
$el
.
find
(
'
.chat-content
'
);
msgs
=
[
'
<strong>/help</strong>:
Show this menu
'
,
'
<strong>/me</strong>:
Write in the third person
'
,
'
<strong>/topic</strong>:
Set chatroom topic
'
,
'
<strong>/kick</strong>:
Kick user from chatroom
'
,
'
<strong>/ban</strong>:
Ban user from chatroom
'
,
'
<strong>/clear</strong>:
Remove messages
'
'
<strong>/help</strong>:
'
+
__
(
'
Show this menu
'
)
+
'
'
,
'
<strong>/me</strong>:
'
+
__
(
'
Write in the third person
'
)
+
'
'
,
'
<strong>/topic</strong>:
'
+
__
(
'
Set chatroom topic
'
)
+
'
'
,
'
<strong>/kick</strong>:
'
+
__
(
'
Kick user from chatroom
'
)
+
'
'
,
'
<strong>/ban</strong>:
'
+
__
(
'
Ban user from chatroom
'
)
+
'
'
,
'
<strong>/clear</strong>:
'
+
__
(
'
Remove messages
'
)
+
'
'
];
this
.
addHelpMessages
(
msgs
);
break
;
...
...
@@ -1143,7 +1169,7 @@
'
<div class="chat-content"></div>
'
+
'
<form class="sendXMPPMessage" action="" method="post">
'
+
'
<textarea type="text" class="chat-textarea"
'
+
'
placeholder="
Message
"/>
'
+
'
placeholder="
'
+
__
(
'
Message
'
)
+
'
"/>
'
+
'
</form>
'
+
'
</div>
'
+
'
<div class="participants">
'
+
...
...
@@ -1257,8 +1283,8 @@
}));
}
}
$form
.
append
(
'
<input type="submit" value="
Save
"/>
'
);
$form
.
append
(
'
<input type="button" value="
Cancel
"/>
'
);
$form
.
append
(
'
<input type="submit" value="
'
+
__
(
'
Save
'
)
+
'
"/>
'
);
$form
.
append
(
'
<input type="button" value="
'
+
__
(
'
Cancel
'
)
+
'
"/>
'
);
$form
.
on
(
'
submit
'
,
$
.
proxy
(
this
.
saveConfiguration
,
this
));
$form
.
find
(
'
input[type=button]
'
).
on
(
'
click
'
,
$
.
proxy
(
this
.
cancelConfiguration
,
this
));
},
...
...
@@ -1305,7 +1331,7 @@
},
onErrorConfigSaved
:
function
(
stanza
)
{
this
.
insertStatusNotification
(
"
An error occurred while trying to save the form.
"
);
this
.
insertStatusNotification
(
__
(
"
An error occurred while trying to save the form.
"
)
);
},
cancelConfiguration
:
function
(
ev
)
{
...
...
@@ -1351,9 +1377,9 @@
this
.
$el
.
find
(
'
.chat-body
'
).
append
(
$
(
'
<div class="chatroom-form-container">
'
+
'
<form class="chatroom-form">
'
+
'
<legend>
This chat room requires a password
</legend>
'
+
'
<label>
Password:
<input type="password" name="password"/></label>
'
+
'
<input type="submit"/>
'
+
'
<legend>
'
+
__
(
'
This chatroom requires a password
'
)
+
'
</legend>
'
+
'
<label>
'
+
__
(
'
Password:
'
)
+
'
<input type="password" name="password"/></label>
'
+
'
<input type="submit"
value="
'
+
__
(
'
Submit
'
)
+
'
/>
'
+
'
</form>
'
+
'
</div>
'
));
this
.
$el
.
find
(
'
.chatroom-form
'
).
on
(
'
submit
'
,
$
.
proxy
(
this
.
submitPassword
,
this
));
...
...
@@ -1367,34 +1393,44 @@
},
infoMessages
:
{
100
:
'
This room is not anonymous
'
,
102
:
'
This room now shows unavailable members
'
,
103
:
'
This room does not show unavailable members
'
,
104
:
'
Non-privacy-related room configuration has changed
'
,
170
:
'
Room logging is now enabled
'
,
171
:
'
Room logging is now disabled
'
,
172
:
'
This room is now non-anonymous
'
,
173
:
'
This room is now semi-anonymous
'
,
174
:
'
This room is now fully-anonymous
'
,
201
:
'
A new room has been created
'
,
210
:
'
Your nickname has been changed
'
100
:
__
(
'
This room is not anonymous
'
)
,
102
:
__
(
'
This room now shows unavailable members
'
)
,
103
:
__
(
'
This room does not show unavailable members
'
)
,
104
:
__
(
'
Non-privacy-related room configuration has changed
'
)
,
170
:
__
(
'
Room logging is now enabled
'
)
,
171
:
__
(
'
Room logging is now disabled
'
)
,
172
:
__
(
'
This room is now non-anonymous
'
)
,
173
:
__
(
'
This room is now semi-anonymous
'
)
,
174
:
__
(
'
This room is now fully-anonymous
'
)
,
201
:
__
(
'
A new room has been created
'
)
,
210
:
__
(
'
Your nickname has been changed
'
)
},
actionInfoMessages
:
{
301
:
'
has been banned
'
,
307
:
'
has been kicked out
'
,
321
:
"
has been removed because of an affiliation change
"
,
322
:
"
has been removed for not being a member
"
// # For translations: %1$s will be replaced with the user's nickname
// # Don't translate "strong"
// # Example: <strong>jcbrand</strong> has been banned
301
:
i18n
.
translate
(
'
<strong>%1$s</strong> has been banned
'
),
// # For translations: %1$s will be replaced with the user's nickname
// # Don't translate "strong"
// # Example: <strong>jcbrand</strong> has been kicked out
307
:
i18n
.
translate
(
'
<strong>%1$s</strong> has been kicked out
'
),
// # For translations: %1$s will be replaced with the user's nickname
// # Don't translate "strong"
// # Example: <strong>jcbrand</strong> has been removed because of an affiliasion change
321
:
i18n
.
translate
(
"
<strong>%1$s</strong> has been removed because of an affiliation change
"
),
// # For translations: %1$s will be replaced with the user's nickname
// # Don't translate "strong"
// # Example: <strong>jcbrand</strong> has been removed for not being a member
322
:
i18n
.
translate
(
"
<strong>%1$s</strong> has been removed for not being a member
"
)
},
disconnectMessages
:
{
301
:
'
You have been banned from this room
'
,
307
:
'
You have been kicked from this room
'
,
321
:
"
You have been removed from this room because of an affiliation change
"
,
322
:
"
You have been removed from this room because the room
"
+
"
has changed to members-only and you're not a member
"
,
332
:
"
You have been removed from this room because the MUC
"
+
"
(Multi-user chat) service is being shut down.
"
301
:
__
(
'
You have been banned from this room
'
),
307
:
__
(
'
You have been kicked from this room
'
),
321
:
__
(
"
You have been removed from this room because of an affiliation change
"
),
322
:
__
(
"
You have been removed from this room because the room has changed to members-only and you're not a member
"
),
332
:
__
(
"
You have been removed from this room because the MUC (Multi-user chat) service is being shut down.
"
)
},
showStatusMessages
:
function
(
$el
,
is_self
)
{
...
...
@@ -1418,10 +1454,9 @@
info_msgs
.
push
(
this
.
infoMessages
[
stat
]);
}
else
if
(
_
.
contains
(
_
.
keys
(
this
.
actionInfoMessages
),
stat
))
{
action_msgs
.
push
(
'
<strong>
'
+
Strophe
.
unescapeNode
(
Strophe
.
getResourceFromJid
(
$el
.
attr
(
'
from
'
)))
+
'
</strong>
'
+
this
.
actionInfoMessages
[
stat
]);
this
.
actionInfoMessages
[
stat
].
fetch
(
Strophe
.
unescapeNode
(
Strophe
.
getResourceFromJid
(
$el
.
attr
(
'
from
'
)))
));
}
}
}
...
...
@@ -1429,7 +1464,7 @@
for
(
i
=
0
;
i
<
disconnect_msgs
.
length
;
i
++
)
{
this
.
showDisconnectMessage
(
disconnect_msgs
[
i
]);
}
this
.
model
.
set
(
'
connected
'
,
false
)
this
.
model
.
set
(
'
connected
'
,
false
)
;
return
;
}
this
.
renderChatArea
();
...
...
@@ -1451,25 +1486,25 @@
if
(
$error
.
find
(
'
not-authorized
'
).
length
)
{
this
.
renderPasswordForm
();
}
else
if
(
$error
.
find
(
'
registration-required
'
).
length
)
{
this
.
showDisconnectMessage
(
'
You are not on the member list of this room
'
);
this
.
showDisconnectMessage
(
__
(
'
You are not on the member list of this room
'
)
);
}
else
if
(
$error
.
find
(
'
forbidden
'
).
length
)
{
this
.
showDisconnectMessage
(
'
You have been banned from this room
'
);
this
.
showDisconnectMessage
(
__
(
'
You have been banned from this room
'
)
);
}
}
else
if
(
$error
.
attr
(
'
type
'
)
==
'
modify
'
)
{
if
(
$error
.
find
(
'
jid-malformed
'
).
length
)
{
this
.
showDisconnectMessage
(
'
No nickname was specified
'
);
this
.
showDisconnectMessage
(
__
(
'
No nickname was specified
'
)
);
}
}
else
if
(
$error
.
attr
(
'
type
'
)
==
'
cancel
'
)
{
if
(
$error
.
find
(
'
not-allowed
'
).
length
)
{
this
.
showDisconnectMessage
(
'
You are not allowed to create new rooms
'
);
this
.
showDisconnectMessage
(
__
(
'
You are not allowed to create new rooms
'
)
);
}
else
if
(
$error
.
find
(
'
not-acceptable
'
).
length
)
{
this
.
showDisconnectMessage
(
"
Your nickname doesn't conform to this room's policies
"
);
this
.
showDisconnectMessage
(
__
(
"
Your nickname doesn't conform to this room's policies
"
)
);
}
else
if
(
$error
.
find
(
'
conflict
'
).
length
)
{
this
.
showDisconnectMessage
(
"
Your nickname is already taken
"
);
this
.
showDisconnectMessage
(
__
(
"
Your nickname is already taken
"
)
);
}
else
if
(
$error
.
find
(
'
item-not-found
'
).
length
)
{
this
.
showDisconnectMessage
(
"
This room does not (yet) exist
"
);
this
.
showDisconnectMessage
(
__
(
"
This room does not (yet) exist
"
)
);
}
else
if
(
$error
.
find
(
'
service-unavailable
'
).
length
)
{
this
.
showDisconnectMessage
(
"
This room has reached it's maximum number of occupants
"
);
this
.
showDisconnectMessage
(
__
(
"
This room has reached it's maximum number of occupants
"
)
);
}
}
},
...
...
@@ -1482,7 +1517,7 @@
$item
;
if
(
$presence
.
attr
(
'
type
'
)
===
'
error
'
)
{
this
.
model
.
set
(
'
connected
'
,
false
)
this
.
model
.
set
(
'
connected
'
,
false
)
;
this
.
showErrorMessage
(
$presence
.
find
(
'
error
'
),
room
);
}
else
{
this
.
model
.
set
(
'
connected
'
,
true
);
...
...
@@ -1544,7 +1579,9 @@
this
.
showStatusMessages
(
$message
);
if
(
subject
)
{
this
.
$el
.
find
(
'
.chatroom-topic
'
).
text
(
subject
).
attr
(
'
title
'
,
subject
);
$chat_content
.
append
(
this
.
info_template
({
'
message
'
:
'
Topic set by
'
+
sender
+
'
to:
'
+
subject
}));
// # For translators: the %1$s and %2$s parts will get replaced by the user and topic text respectively
// # Example: Topic set by JC Brand to: Hello World!
$chat_content
.
append
(
this
.
info_template
({
'
message
'
:
__
(
'
Topic set by %1$s to: %2$s
'
,
sender
,
subject
)}));
}
if
(
!
body
)
{
return
true
;
}
this
.
appendMessage
(
$chat_content
,
...
...
@@ -1560,13 +1597,13 @@
occupant_template
:
_
.
template
(
'
<li class="{{role}}"
'
+
'
{[ if (role === "moderator") { ]}
'
+
'
title="
This user is a moderator
"
'
+
'
title="
'
+
__
(
'
This user is a moderator
'
)
+
'
"
'
+
'
{[ } ]}
'
+
'
{[ if (role === "participant") { ]}
'
+
'
title="
This user can send messages in this room
"
'
+
'
title="
'
+
__
(
'
This user can send messages in this room
'
)
+
'
"
'
+
'
{[ } ]}
'
+
'
{[ if (role === "visitor") { ]}
'
+
'
title="
This user can NOT send messages in this room
"
'
+
'
title="
'
+
__
(
'
This user can NOT send messages in this room
'
)
+
'
"
'
+
'
{[ } ]}
'
+
'
>{{nick}}</li>
'
),
...
...
@@ -1770,12 +1807,12 @@
},
template
:
_
.
template
(
'
<a class="open-chat" title="
Click to chat with this contact
" href="#">{{ fullname }}</a>
'
+
'
<a class="remove-xmpp-contact" title="
Click to remove this contact
" href="#"></a>
'
),
'
<a class="open-chat" title="
'
+
__
(
'
Click to chat with this contact
'
)
+
'
" href="#">{{ fullname }}</a>
'
+
'
<a class="remove-xmpp-contact" title="
'
+
__
(
'
Click to remove this contact
'
)
+
'
" href="#"></a>
'
),
pending_template
:
_
.
template
(
'
<span>{{ fullname }}</span>
'
+
'
<a class="remove-xmpp-contact" title="
Click to remove this contact
" href="#"></a>
'
),
'
<a class="remove-xmpp-contact" title="
'
+
__
(
'
Click to remove this contact
'
)
+
'
" href="#"></a>
'
),
request_template
:
_
.
template
(
'
<div>{{ fullname }}</div>
'
+
'
<button type="button" class="accept-xmpp-request">
'
+
...
...
@@ -2137,9 +2174,9 @@
chatbox
.
save
(
changes
);
},
template
:
_
.
template
(
'
<dt id="xmpp-contact-requests">
Contact requests
</dt>
'
+
'
<dt id="xmpp-contacts">
My contacts
</dt>
'
+
'
<dt id="pending-xmpp-contacts">
Pending contacts
</dt>
'
),
template
:
_
.
template
(
'
<dt id="xmpp-contact-requests">
'
+
__
(
'
Contact requests
'
)
+
'
</dt>
'
+
'
<dt id="xmpp-contacts">
'
+
__
(
'
My contacts
'
)
+
'
</dt>
'
+
'
<dt id="pending-xmpp-contacts">
'
+
__
(
'
Pending contacts
'
)
+
'
</dt>
'
),
render
:
function
(
item
)
{
var
$my_contacts
=
this
.
$el
.
find
(
'
#xmpp-contacts
'
),
...
...
@@ -2290,16 +2327,17 @@
change_status_message_template
:
_
.
template
(
'
<form id="set-custom-xmpp-status">
'
+
'
<input type="text" class="custom-xmpp-status" {{ status_message }}" placeholder="Custom status"/>
'
+
'
<button type="submit">Save</button>
'
+
'
<input type="text" class="custom-xmpp-status" {{ status_message }}"
'
+
'
placeholder="
'
+
__
(
'
Custom status
'
)
+
'
"/>
'
+
'
<button type="submit">
'
+
__
(
'
Save
'
)
+
'
</button>
'
+
'
</form>
'
),
status_template
:
_
.
template
(
'
<div class="xmpp-status">
'
+
'
<a class="choose-xmpp-status {{ chat_status }}" data-value="{{status_message}}" href="#" title="
Click to change your chat status
">
'
+
'
<a class="choose-xmpp-status {{ chat_status }}" data-value="{{status_message}}" href="#" title="
'
+
__
(
'
Click to change your chat status
'
)
+
'
">
'
+
'
{{ status_message }}
'
+
'
</a>
'
+
'
<a class="change-xmpp-status-message" href="#"
Title="Click here to write a custom status message
"></a>
'
+
'
<a class="change-xmpp-status-message" href="#"
title="
'
+
__
(
'
Click here to write a custom status message
'
)
+
'
"></a>
'
+
'
</div>
'
),
renderStatusChangeForm
:
function
(
ev
)
{
...
...
@@ -2343,8 +2381,10 @@
if
(
!
(
_
.
has
(
model
.
changed
,
'
status
'
))
&&
!
(
_
.
has
(
model
.
changed
,
'
status_message
'
)))
{
return
;
}
var
stat
=
model
.
get
(
'
status
'
),
status_message
=
model
.
get
(
'
status_message
'
)
||
"
I am
"
+
this
.
getPrettyStatus
(
stat
);
var
stat
=
model
.
get
(
'
status
'
);
// # For translators: the %1$s part gets replaced with the status
// # Example, I am online
var
status_message
=
model
.
get
(
'
status_message
'
)
||
__
(
"
I am %1$s
"
,
this
.
getPrettyStatus
(
stat
));
this
.
$el
.
find
(
'
#fancy-xmpp-status-select
'
).
html
(
this
.
status_template
({
'
chat_status
'
:
stat
,
...
...
@@ -2378,7 +2418,7 @@
this
.
$el
.
html
(
this
.
choose_template
());
this
.
$el
.
find
(
'
#fancy-xmpp-status-select
'
)
.
html
(
this
.
status_template
({
'
status_message
'
:
"
I am
"
+
this
.
getPrettyStatus
(
chat_status
),
'
status_message
'
:
__
(
"
I am %1$s
"
,
this
.
getPrettyStatus
(
chat_status
)
),
'
chat_status
'
:
chat_status
}));
// iterate through all the <option> elements and add option values
...
...
@@ -2449,18 +2489,18 @@
'
submit form#converse-login
'
:
'
authenticate
'
},
tab_template
:
_
.
template
(
'
<li><a class="current" href="#login">
Sign in
</a></li>
'
),
'
<li><a class="current" href="#login">
'
+
__
(
'
Sign in
'
)
+
'
</a></li>
'
),
template
:
_
.
template
(
'
<form id="converse-login">
'
+
'
<label>
XMPP/Jabber Username:
</label>
'
+
'
<label>
'
+
__
(
'
XMPP/Jabber Username:
'
)
+
'
</label>
'
+
'
<input type="text" id="jid">
'
+
'
<label>
Password:
</label>
'
+
'
<label>
'
+
__
(
'
Password:
'
)
+
'
</label>
'
+
'
<input type="password" id="password">
'
+
'
<input class="login-submit" type="submit" value="
Log In
">
'
+
'
<input class="login-submit" type="submit" value="
'
+
__
(
'
Log In
'
)
+
'
">
'
+
'
</form">
'
),
bosh_url_input
:
_
.
template
(
'
<label>
BOSH Service URL:
</label>
'
+
'
<label>
'
+
__
(
'
BOSH Service URL:
'
)
+
'
</label>
'
+
'
<input type="text" id="bosh_service_url">
'
),
connect
:
function
(
$form
,
jid
,
password
)
{
...
...
@@ -2472,29 +2512,29 @@
}
connection
.
connect
(
jid
,
password
,
$
.
proxy
(
function
(
status
,
message
)
{
if
(
status
===
Strophe
.
Status
.
CONNECTED
)
{
console
.
log
(
'
Connected
'
);
console
.
log
(
__
(
'
Connected
'
)
);
converse
.
onConnected
(
connection
);
}
else
if
(
status
===
Strophe
.
Status
.
DISCONNECTED
)
{
if
(
$button
)
{
$button
.
show
().
siblings
(
'
img
'
).
remove
();
}
converse
.
giveFeedback
(
'
Disconnected
'
,
'
error
'
);
converse
.
giveFeedback
(
__
(
'
Disconnected
'
)
,
'
error
'
);
this
.
connect
(
null
,
connection
.
jid
,
connection
.
pass
);
}
else
if
(
status
===
Strophe
.
Status
.
Error
)
{
if
(
$button
)
{
$button
.
show
().
siblings
(
'
img
'
).
remove
();
}
converse
.
giveFeedback
(
'
Error
'
,
'
error
'
);
converse
.
giveFeedback
(
__
(
'
Error
'
)
,
'
error
'
);
}
else
if
(
status
===
Strophe
.
Status
.
CONNECTING
)
{
converse
.
giveFeedback
(
'
Connecting
'
);
converse
.
giveFeedback
(
__
(
'
Connecting
'
)
);
}
else
if
(
status
===
Strophe
.
Status
.
CONNFAIL
)
{
if
(
$button
)
{
$button
.
show
().
siblings
(
'
img
'
).
remove
();
}
converse
.
giveFeedback
(
'
Connection Failed
'
,
'
error
'
);
converse
.
giveFeedback
(
__
(
'
Connection Failed
'
)
,
'
error
'
);
}
else
if
(
status
===
Strophe
.
Status
.
AUTHENTICATING
)
{
converse
.
giveFeedback
(
'
Authenticating
'
);
converse
.
giveFeedback
(
__
(
'
Authenticating
'
)
);
}
else
if
(
status
===
Strophe
.
Status
.
AUTHFAIL
)
{
if
(
$button
)
{
$button
.
show
().
siblings
(
'
img
'
).
remove
();
}
converse
.
giveFeedback
(
'
Authentication Failed
'
,
'
error
'
);
converse
.
giveFeedback
(
__
(
'
Authentication Failed
'
)
,
'
error
'
);
}
else
if
(
status
===
Strophe
.
Status
.
DISCONNECTING
)
{
converse
.
giveFeedback
(
'
Disconnecting
'
,
'
error
'
);
converse
.
giveFeedback
(
__
(
'
Disconnecting
'
)
,
'
error
'
);
}
else
if
(
status
===
Strophe
.
Status
.
ATTACHED
)
{
console
.
log
(
'
Attached
'
);
console
.
log
(
__
(
'
Attached
'
)
);
}
},
this
));
},
...
...
@@ -2591,7 +2631,6 @@
this
.
domain
=
Strophe
.
getDomainFromJid
(
this
.
connection
.
jid
);
this
.
features
=
new
this
.
Features
();
// Set up the roster
this
.
roster
=
new
this
.
RosterItems
();
this
.
roster
.
localStorage
=
new
Backbone
.
LocalStorage
(
...
...
@@ -2626,7 +2665,7 @@
}
this
.
windowState
=
e
.
type
;
},
this
));
this
.
giveFeedback
(
'
Online Contacts
'
);
this
.
giveFeedback
(
__
(
'
Online Contacts
'
)
);
};
converse
.
initialize
=
function
(
settings
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment