Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
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
Eugene Shen
erp5
Commits
fdcbdb06
Commit
fdcbdb06
authored
Apr 04, 2017
by
Eugene Shen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Put all DOM modifications into onStateChange
parent
17bb0e4e
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
5276 additions
and
221 deletions
+5276
-221
bt5/officejs_eyqs/PathTemplateItem/web_page_module/fast_priority_queue_js.js
...athTemplateItem/web_page_module/fast_priority_queue_js.js
+179
-0
bt5/officejs_eyqs/PathTemplateItem/web_page_module/fast_priority_queue_js.xml
...thTemplateItem/web_page_module/fast_priority_queue_js.xml
+123
-0
bt5/officejs_eyqs/PathTemplateItem/web_page_module/gadget_erp5_page_chat_box_html.html
...eItem/web_page_module/gadget_erp5_page_chat_box_html.html
+18
-1
bt5/officejs_eyqs/PathTemplateItem/web_page_module/gadget_erp5_page_chat_box_js.js
...plateItem/web_page_module/gadget_erp5_page_chat_box_js.js
+226
-219
bt5/officejs_eyqs/PathTemplateItem/web_page_module/handlebars_js.js
...js_eyqs/PathTemplateItem/web_page_module/handlebars_js.js
+4608
-0
bt5/officejs_eyqs/PathTemplateItem/web_page_module/handlebars_js.xml
...s_eyqs/PathTemplateItem/web_page_module/handlebars_js.xml
+119
-0
bt5/officejs_eyqs/bt/template_path_list
bt5/officejs_eyqs/bt/template_path_list
+3
-1
No files found.
bt5/officejs_eyqs/PathTemplateItem/web_page_module/fast_priority_queue_js.js
0 → 100644
View file @
fdcbdb06
/**
* FastPriorityQueue.js : a fast heap-based priority queue in JavaScript.
* (c) the authors
* Licensed under the Apache License, Version 2.0.
*
* Speed-optimized heap-based priority queue for modern browsers and JavaScript engines.
*
* Usage :
Installation (in shell, if you use node):
$ npm install fastpriorityqueue
Running test program (in JavaScript):
// var FastPriorityQueue = require("fastpriorityqueue");// in node
var x = new FastPriorityQueue();
x.add(1);
x.add(0);
x.add(5);
x.add(4);
x.add(3);
x.peek(); // should return 0, leaves x unchanged
x.size; // should return 5, leaves x unchanged
while(!x.isEmpty()) {
console.log(x.poll());
} // will print 0 1 3 4 5
x.trim(); // (optional) optimizes memory usage
*/
"
use strict
"
;
var
defaultcomparator
=
function
(
a
,
b
)
{
return
a
<
b
;
};
// the provided comparator function should take a, b and return *true* when a < b
function
FastPriorityQueue
(
comparator
)
{
this
.
array
=
[];
this
.
size
=
0
;
this
.
compare
=
comparator
||
defaultcomparator
;
}
// Add an element the the queue
// runs in O(log n) time
FastPriorityQueue
.
prototype
.
add
=
function
(
myval
)
{
var
i
=
this
.
size
;
this
.
array
[
this
.
size
]
=
myval
;
this
.
size
+=
1
;
var
p
;
var
ap
;
while
(
i
>
0
)
{
p
=
(
i
-
1
)
>>
1
;
ap
=
this
.
array
[
p
];
if
(
!
this
.
compare
(
myval
,
ap
))
{
break
;
}
this
.
array
[
i
]
=
ap
;
i
=
p
;
}
this
.
array
[
i
]
=
myval
;
};
// replace the content of the heap by provided array and "heapifies it"
FastPriorityQueue
.
prototype
.
heapify
=
function
(
arr
)
{
this
.
array
=
arr
;
this
.
size
=
arr
.
length
;
var
i
;
for
(
i
=
(
this
.
size
>>
1
);
i
>=
0
;
i
--
)
{
this
.
_percolateDown
(
i
);
}
};
// for internal use
FastPriorityQueue
.
prototype
.
_percolateUp
=
function
(
i
)
{
var
myval
=
this
.
array
[
i
];
var
p
;
var
ap
;
while
(
i
>
0
)
{
p
=
(
i
-
1
)
>>
1
;
ap
=
this
.
array
[
p
];
if
(
!
this
.
compare
(
myval
,
ap
))
{
break
;
}
this
.
array
[
i
]
=
ap
;
i
=
p
;
}
this
.
array
[
i
]
=
myval
;
};
// for internal use
FastPriorityQueue
.
prototype
.
_percolateDown
=
function
(
i
)
{
var
size
=
this
.
size
;
var
hsize
=
this
.
size
>>>
1
;
var
ai
=
this
.
array
[
i
];
var
l
;
var
r
;
var
bestc
;
while
(
i
<
hsize
)
{
l
=
(
i
<<
1
)
+
1
;
r
=
l
+
1
;
bestc
=
this
.
array
[
l
];
if
(
r
<
size
)
{
if
(
this
.
compare
(
this
.
array
[
r
],
bestc
))
{
l
=
r
;
bestc
=
this
.
array
[
r
];
}
}
if
(
!
this
.
compare
(
bestc
,
ai
))
{
break
;
}
this
.
array
[
i
]
=
bestc
;
i
=
l
;
}
this
.
array
[
i
]
=
ai
;
};
// Look at the top of the queue (a smallest element)
// executes in constant time
//
// This function assumes that the priority queue is
// not empty and the caller is resposible for the check.
// You can use an expression such as
// "isEmpty() ? undefined : peek()"
// if you expect to be calling peek on an empty priority queue.
//
FastPriorityQueue
.
prototype
.
peek
=
function
()
{
return
this
.
array
[
0
];
};
// remove the element on top of the heap (a smallest element)
// runs in logarithmic time
//
//
// This function assumes that the priority queue is
// not empty, and the caller is responsible for the check.
// You can use an expression such as
// "isEmpty() ? undefined : poll()"
// if you expect to be calling poll on an empty priority queue.
//
// For long-running and large priority queues, or priority queues
// storing large objects, you may want to call the trim function
// at strategic times to recover allocated memory.
FastPriorityQueue
.
prototype
.
poll
=
function
()
{
var
ans
=
this
.
array
[
0
];
if
(
this
.
size
>
1
)
{
this
.
array
[
0
]
=
this
.
array
[
--
this
.
size
];
this
.
_percolateDown
(
0
|
0
);
}
else
{
this
.
size
-=
1
;
}
return
ans
;
};
// recover unused memory (for long-running priority queues)
FastPriorityQueue
.
prototype
.
trim
=
function
()
{
this
.
array
=
this
.
array
.
slice
(
0
,
this
.
size
);
};
// Check whether the heap is empty
FastPriorityQueue
.
prototype
.
isEmpty
=
function
()
{
return
this
.
size
===
0
;
};
// just for illustration purposes
var
main
=
function
()
{
// main code
var
x
=
new
FastPriorityQueue
(
function
(
a
,
b
)
{
return
a
<
b
;
});
x
.
add
(
1
);
x
.
add
(
0
);
x
.
add
(
5
);
x
.
add
(
4
);
x
.
add
(
3
);
while
(
!
x
.
isEmpty
())
{
console
.
log
(
x
.
poll
());
}
};
\ No newline at end of file
bt5/officejs_eyqs/PathTemplateItem/web_page_module/fast_priority_queue_js.xml
0 → 100644
View file @
fdcbdb06
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Web Script"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_Access_contents_information_Permission
</string>
</key>
<value>
<tuple>
<string>
Anonymous
</string>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Associate
</string>
<string>
Auditor
</string>
<string>
Manager
</string>
<string>
Owner
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Add_portal_content_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Change_local_roles_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Modify_portal_content_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_View_Permission
</string>
</key>
<value>
<tuple>
<string>
Anonymous
</string>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Associate
</string>
<string>
Auditor
</string>
<string>
Manager
</string>
<string>
Owner
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
categories
</string>
</key>
<value>
<tuple>
<string>
classification/collaborative/team
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
content_md5
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
default_reference
</string>
</key>
<value>
<string>
fast_priority_queue.js
</string>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
fast_priority_queue_js
</string>
</value>
</item>
<item>
<key>
<string>
language
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Web Script
</string>
</value>
</item>
<item>
<key>
<string>
short_title
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string>
Fast Priority Queue JS
</string>
</value>
</item>
<item>
<key>
<string>
version
</string>
</key>
<value>
<none/>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/officejs_eyqs/PathTemplateItem/web_page_module/gadget_erp5_page_chat_box_html.html
View file @
fdcbdb06
...
...
@@ -7,8 +7,24 @@
<script
src=
"rsvp.js"
></script>
<script
src=
"renderjs.js"
></script>
<script
src=
"jiodev.js"
></script>
<script
src=
"handlebars.js"
></script>
<script
src=
"gadget_global.js"
></script>
<script
src=
"fast_priority_queue.js"
></script>
<script
src=
"gadget_erp5_page_chat_box.js"
></script>
<script
class=
"chat-list-template"
type=
"text/x-handlebars-template"
>
{{
#
each
list
}}
<
li
style
=
"
color:{{this.color}};
"
>
{{{
this
.
html
}}}
<
/li
>
{{
/
each
}}
</script>
<script
class=
"contact-list-template"
type=
"text/x-handlebars-template"
>
{{
#
each
list
}}
<
li
id
=
"
chat-contact-{{this.id}}
"
class
=
"
chat-contact {{this.class_list}}
"
>
{{
this
.
name
}}
<
/li
>
{{
/
each
}}
</script>
</head>
<body>
<div
class=
"chat-box"
>
...
...
@@ -27,7 +43,8 @@
</div>
</div>
<div
class=
"chat-right-panel"
>
<h3
class=
"chat-title center"
></h3>
<h3
class=
"chat-title center"
>
</h3>
<div
class=
"chat-max-height-wrapper"
>
<div
class=
"chat-right-panel-chat"
>
<ul
class=
"chat-list"
>
...
...
bt5/officejs_eyqs/PathTemplateItem/web_page_module/gadget_erp5_page_chat_box_js.js
View file @
fdcbdb06
/*jslint nomen: true, indent: 2, maxerr: 3, maxlen: 80 */
/*global window, document, RSVP, rJS, promiseEventListener */
(
function
(
window
,
document
,
RSVP
,
rJS
,
promiseEventListener
)
{
/*global window, document, RSVP, rJS, Handlebars,
FastPriorityQueue, promiseEventListener */
(
function
(
window
,
document
,
RSVP
,
rJS
,
Handlebars
,
FastPriorityQueue
,
promiseEventListener
)
{
"
use strict
"
;
/* Settings required:
...
...
@@ -12,6 +14,10 @@
* - default_dav_url, default: ""
*/
var
chat_list_template
,
contact_list_template
;
/* Check if a string ends with another string.
* Parameters:
* - string: the string that may or may not end with the suffix string
...
...
@@ -40,7 +46,7 @@
/* Reset a text input.
* Parameters:
* - element: the text input element to reset
* Effects: set the value of the text input to the empty string
* Effects: set the value of the text input to the empty string
* Returns: the previous value of the text input before resetting it
*/
...
...
@@ -51,27 +57,38 @@
}
/* Get the c
ontact element given by a room
.
/* Get the c
reation epoch time of a message
.
* Parameters:
* -
room: the room for which to find the element in the contact list
* -
message: the message whose creation time is desired
* Effects: nothing
* Returns: the c
ontact element corresponding to the given room
* Returns: the c
reation time of the message, in milliseconds since 1970
*/
function
get
ContactFromRoom
(
gadget
,
room
)
{
return
gadget
.
element
.
querySelector
(
"
#chat-contact-
"
+
nameToId
(
room
)
);
function
get
Time
(
message
)
{
return
new
Date
(
message
.
time
).
getTime
(
);
}
/*
Get the creation epoch time of a
message.
/*
Create a new JSON
message.
* Parameters:
* - message: the message whose creation time is desired
* - name: the name of the sender of the message
* - room: the room from where the message is sent
* - time: the epoch time at which the message is sent
* - content: the content of the message
* - color: the colour of the message in the chat
* Effects: nothing
* Returns:
the creation time of the message, in milliseconds since 1970.
* Returns:
a message object corresponding to the parameters
*/
function
getTime
(
message
)
{
return
new
Date
(
message
.
time
).
getTime
();
function
createMessage
(
param_dict
)
{
return
{
type
:
param_dict
.
type
||
"
message
"
,
name
:
param_dict
.
name
,
room
:
param_dict
.
room
,
time
:
param_dict
.
time
||
new
Date
(),
content
:
param_dict
.
content
||
""
,
color
:
param_dict
.
color
||
"
black
"
};
}
...
...
@@ -79,39 +96,37 @@
* Parameters:
* - message: the JavaScript object to display in HTML
* Effects: nothing
* Returns: a HTML representation of the given message
* Returns: a
properly escaped
HTML representation of the given message
*/
function
messageToChat
(
message
)
{
var
i
,
j
,
matches
,
image
,
link
,
link_string
,
dot_count
,
is_image
,
absolute_url
,
chat
=
document
.
createElement
(
"
li
"
)
,
var
i
,
j
,
matches
,
link_string
,
dot_count
,
is_image
,
absolute_url
,
escaped_content
=
Handlebars
.
Utils
.
escapeExpression
(
message
.
content
)
,
chat
=
{
color
:
message
.
color
,
html
:
""
}
,
image_extensions
=
[
"
.jpg
"
,
"
.png
"
,
"
.gif
"
,
"
.bmp
"
,
"
.tif
"
,
"
.svg
"
],
url_regex
=
/
((?:
https
?
:
\/\/)?(?:[\-
a-zA-Z0-9_~
\/
@
]
+
\.)
+
[\-
a-zA-Z0-9_~#?&=
\/]
+
)
/g
;
if
(
message
.
type
===
"
notification
"
)
{
chat
.
appendChild
(
document
.
createTextNode
(
message
.
content
));
chat
.
style
.
color
=
message
.
color
;
chat
.
html
=
escaped_content
;
}
else
if
(
message
.
type
===
"
message
"
)
{
// Put message in the format "[3/24/2017, 11:30:52 AM] user: message"
chat
.
appendChild
(
document
.
createTextNode
(
"
[
"
+
new
Date
(
message
.
time
).
toLocaleString
()
+
"
]
"
+
message
.
name
+
"
:
"
));
chat
.
html
=
"
[
"
+
new
Date
(
message
.
time
).
toLocaleString
()
+
"
]
"
+
message
.
name
+
"
:
"
;
// Loop through all potential URLs in the message
// matches[i] is the non-link content, matches[i + 1] is the actual link
matches
=
message
.
content
.
split
(
url_regex
);
matches
=
escaped_
content
.
split
(
url_regex
);
for
(
i
=
0
;
i
<
matches
.
length
-
1
;
i
+=
2
)
{
chat
.
appendChild
(
document
.
createTextNode
(
matches
[
i
]))
;
chat
.
html
+=
matches
[
i
]
;
// If 2d + 1 >= L, then the potential URL has only single letters,
// so ignore it to eliminate acronyms like e.g., i.e., U.S.A., etc.
link_string
=
matches
[
i
+
1
];
dot_count
=
link_string
.
match
(
/
\.
/g
).
length
;
if
(
2
*
dot_count
+
1
>=
link_string
.
length
)
{
chat
.
appendChild
(
document
.
createTextNode
(
link_string
))
;
chat
.
html
+=
link_string
;
}
else
{
is_image
=
false
;
...
...
@@ -125,9 +140,7 @@
// Create an image if the URL ends with one of the image extensions
for
(
j
=
0
;
j
<
image_extensions
.
length
;
j
+=
1
)
{
if
(
stringEndsWith
(
link_string
,
image_extensions
[
j
]))
{
image
=
document
.
createElement
(
"
img
"
);
image
.
src
=
absolute_url
;
chat
.
appendChild
(
image
);
chat
.
html
+=
(
"
<img src='
"
+
absolute_url
+
"
'>
"
);
is_image
=
true
;
break
;
}
...
...
@@ -135,17 +148,14 @@
// Otherwise, create a link
if
(
!
is_image
)
{
link
=
document
.
createElement
(
"
a
"
);
link
.
href
=
absolute_url
;
link
.
innerHTML
=
link_string
;
chat
.
appendChild
(
link
);
chat
.
html
+=
"
<a href='
"
+
absolute_url
+
"
'>
"
;
chat
.
html
+=
link_string
+
"
</a>
"
;
}
}
}
// Add the last non-link content and return the resulting chat element
chat
.
appendChild
(
document
.
createTextNode
(
matches
[
matches
.
length
-
1
]));
chat
.
style
.
color
=
message
.
color
;
// Add the last non-link content
chat
.
html
+=
matches
[
matches
.
length
-
1
];
}
return
chat
;
}
...
...
@@ -155,22 +165,34 @@
.
setState
({
name
:
null
,
// the currently active room, to show in the right panel
room
:
null
,
// keep track of references to elements in the DOM
// initialize to arbitrary values to avoid errors before loading
chat_title_element
:
{},
chat_box_element
:
{
style
:
{}},
room_gadget_element
:
{
style
:
{}},
// true if the room is a chat box, false if the room is a contact panel
is_chat
:
false
,
// a set of the names of all active rooms with number of messages in each
// e.g. {small_room: 3, large_room: 1337}
room_set
:
{},
// a dict of room IDs to the ir names, i.e. {foo_bar_com: "foo@bar.com"}
id_to_name
:
{},
// a dict of room names to whether each has unread messages
// i.e. {read_room: false, unread_room: true}
unread_room_dict
:
{},
// a
set of the names of all rooms that have unread messages with boolean
//
e.g. {read_room: false, unread_room: true
}
unread_room_se
t
:
{},
// a
dict of room names to the list of messages in each,
//
i.e. {quiet_room: [message1, message2], busy_room: [message3, ...]
}
message_list_dic
t
:
{},
// a set of XXX
// a dict of room names to the number of messages in jIO storage,
// i.e. {quiet_room: 3, busy_room: 429}
message_count_dict
:
{},
// a dict of room names to their delayRefresh promise queues
// i.e. {room: new RSVP.Queue().push(function () { return ... })}
delay_refresh_dict
:
{},
// true to use alert_icon_url, false to use default_icon_url
...
...
@@ -178,10 +200,10 @@
alert_icon_url
:
"
https://pricespy.co.nz/favicon.ico
"
,
default_icon_url
:
"
https://softinst75770.host.vifib.net/
"
+
"
erp5/web_site_module/web_chat/favicon.ico
"
,
// toggle refresh_chat to force call delayRefresh
refresh_chat
:
false
,
// toggle update to force call onStateChange
update
:
false
})
...
...
@@ -212,31 +234,28 @@
*/
.
onStateChange
(
function
(
modification_dict
)
{
var
gadget
=
this
,
i
,
room_list
=
gadget
.
element
.
querySelector
(
"
.chat-right-panel
"
).
children
,
contact_list
=
gadget
.
element
.
querySelector
(
"
.contact-list
"
).
children
,
var
i
,
contact_name
,
contact_class_list
,
chat_list
,
chat_list_element
,
gadget
=
this
,
contact_list
=
Object
.
keys
(
gadget
.
state
.
message_list_dict
)
,
message_list
=
gadget
.
state
.
message_list_dict
[
gadget
.
state
.
room
]
,
favicon_element
=
document
.
querySelector
(
"
link[rel*='icon']
"
)
||
document
.
createElement
(
"
link
"
);
||
document
.
createElement
(
"
link
"
);
// hide all room gadget elements
for
(
i
=
0
;
i
<
room_list
.
length
;
i
+=
1
)
{
if
(
room_list
[
i
].
getAttribute
(
"
data-gadget-url
"
))
{
room_list
[
i
].
style
.
display
=
"
none
"
;
}
}
// remove all styles from contact elements
// add classes to contact elements
for
(
i
=
0
;
i
<
contact_list
.
length
;
i
+=
1
)
{
if
(
contact_list
[
i
].
classList
.
contains
(
"
current
"
))
{
contact_list
[
i
].
classList
.
remove
(
"
current
"
);
contact_list
[
i
].
classList
.
remove
(
"
notify
"
);
contact_name
=
contact_list
[
i
];
contact_class_list
=
[];
if
(
gadget
.
state
.
unread_room_dict
[
contact_name
])
{
contact_class_list
.
push
(
"
notify
"
);
}
// add styles to contacts with unread messages
if
(
gadget
.
state
.
unread_room_set
[
contact_list
[
i
].
id
])
{
contact_list
[
i
].
classList
.
add
(
"
notify
"
);
if
(
contact_name
===
gadget
.
state
.
room
)
{
contact_class_list
.
push
(
"
current
"
);
}
contact_list
[
i
]
=
{
name
:
contact_name
,
id
:
nameToId
(
contact_name
),
class_list
:
contact_class_list
.
join
(
"
"
)
};
}
// set favicon depending on whether there are new unread messages
...
...
@@ -249,39 +268,46 @@
favicon_element
.
rel
=
"
shortcut icon
"
;
document
.
head
.
appendChild
(
favicon_element
);
//
add style to the current contact
//
if a chat room is active, show chat panel
if
(
modification_dict
.
hasOwnProperty
(
"
room
"
)
||
modification_dict
.
hasOwnProperty
(
"
is_chat
"
))
{
getContactFromRoom
(
gadget
,
gadget
.
state
.
room
).
classList
.
add
(
"
current
"
);
// if a chat room is active, show chat panel
gadget
.
state
.
room_gadget_element
.
style
.
display
=
"
none
"
;
if
(
gadget
.
state
.
is_chat
)
{
gadget
.
element
.
querySelector
(
"
.chat-right-panel-chat
"
)
.
style
.
display
=
"
flex
"
;
gadget
.
element
.
querySelector
(
"
.chat-title
"
)
.
textContent
=
"
Room:
"
+
gadget
.
state
.
room
;
gadget
.
state
.
chat_title_element
.
innerHTML
=
"
Room:
"
+
gadget
.
state
.
room
;
gadget
.
state
.
chat_box_element
.
style
.
display
=
"
flex
"
;
}
else
{
// otherwise, hide chat panel and show contact panel
gadget
.
element
.
querySelector
(
"
.chat-right-panel-chat
"
)
.
style
.
display
=
"
none
"
;
gadget
.
element
.
querySelector
(
"
#room-gadget-
"
+
nameToId
(
gadget
.
state
.
room
)).
style
.
display
=
"
block
"
;
gadget
.
element
.
querySelector
(
"
.chat-title
"
)
.
textContent
=
"
Contact:
"
+
gadget
.
state
.
room
;
gadget
.
state
.
chat_title_element
.
innerHTML
=
"
Contact:
"
+
gadget
.
state
.
room
;
gadget
.
state
.
chat_box_element
.
style
.
display
=
"
none
"
;
gadget
.
state
.
room_gadget_element
=
gadget
.
element
.
querySelector
(
"
#room-gadget-
"
+
nameToId
(
gadget
.
state
.
room
));
gadget
.
state
.
room_gadget_element
.
style
.
display
=
"
block
"
;
}
}
// render the contact list and chat list using Handlebars
gadget
.
element
.
querySelector
(
"
.contact-list
"
).
innerHTML
=
contact_list_template
({
list
:
contact_list
});
if
(
gadget
.
state
.
is_chat
)
{
chat_list
=
[];
for
(
i
=
0
;
i
<
message_list
.
length
;
i
+=
1
)
{
chat_list
.
push
(
messageToChat
(
message_list
[
i
]));
}
chat_list_element
=
gadget
.
element
.
querySelector
(
"
.chat-list
"
);
chat_list_element
.
innerHTML
=
chat_list_template
({
list
:
chat_list
});
chat_list_element
.
scrollTop
=
chat_list_element
.
scrollHeight
;
}
// set update to false so that setting update to true calls onStateChange
gadget
.
state
.
update
=
false
;
// refresh the current room
if
(
gadget
.
state
.
refresh_chat
)
{
gadget
.
state
.
refresh_chat
=
false
;
if
(
gadget
.
state
.
delay_refresh_dict
[
gadget
.
state
.
room
])
{
gadget
.
state
.
delay_refresh_dict
[
gadget
.
state
.
room
].
cancel
();
}
return
gadget
.
delayRefresh
(
gadget
.
state
.
room
,
0
);
gadget
.
delayRefresh
(
gadget
.
state
.
room
,
5000
);
}
})
...
...
@@ -304,6 +330,18 @@
"
jio_configurator
"
,
new
RSVP
.
Queue
()
.
push
(
function
()
{
chat_list_template
=
Handlebars
.
compile
(
Object
.
getPrototypeOf
(
gadget
).
constructor
.
__template_element
.
querySelector
(
"
.chat-list-template
"
).
innerHTML
);
contact_list_template
=
Handlebars
.
compile
(
Object
.
getPrototypeOf
(
gadget
).
constructor
.
__template_element
.
querySelector
(
"
.contact-list-template
"
).
innerHTML
);
gadget
.
state
.
chat_title_element
=
gadget
.
element
.
querySelector
(
"
.chat-title
"
);
gadget
.
state
.
chat_box_element
=
gadget
.
element
.
querySelector
(
"
.chat-right-panel-chat
"
);
return
gadget
.
updateHeader
({
page_title
:
"
OfficeJS Chat
"
});
...
...
@@ -333,7 +371,7 @@
.
push
(
function
()
{
gadget
.
element
.
querySelector
(
"
.send-form input[type='text']
"
)
.
onfocus
=
function
()
{
gadget
.
state
.
unread_room_
se
t
[
gadget
.
state
.
room
]
=
false
;
gadget
.
state
.
unread_room_
dic
t
[
gadget
.
state
.
room
]
=
false
;
return
gadget
.
changeState
({
update
:
true
});
};
return
gadget
.
createContact
(
user_email
);
...
...
@@ -349,58 +387,20 @@
* Parameters:
* - room: the name of the contact
* Effects:
* - append a new contact to the contact list
* - if the name is not blank and not a duplicate, then:
* - create a new contact to be rendered in the contact list
* - create a new room gadget
* - show the chat box
*/
.
declareMethod
(
"
createContact
"
,
function
(
room
)
{
var
gadget
=
this
;
return
gadget
.
appendContact
(
room
)
.
push
(
function
()
{
return
gadget
.
createRoom
(
room
);
})
.
push
(
function
()
{
return
gadget
.
changeState
({
room
:
room
,
is_chat
:
false
});
});
})
/* Append a new contact element to the contact list.
* Parameters:
* - room: the name of the contact
* Effects:
* - if the name is not blank and not a duplicate, then:
* - create and append a new contact element to the contact list
* - set its ID to a querySelector-safe translation of its name
* - highlight it and add an event listener to highlight it on click
* and either change to the room or the contact panel
*/
.
declareMethod
(
"
appendContact
"
,
function
(
room
)
{
var
gadget
=
this
,
contact_element
;
if
(
!
room
.
trim
())
{
throw
"
An invisible name is not allowed! You couldn't click on it!
"
;
}
if
(
g
etContactFromRoom
(
gadget
,
room
))
{
if
(
g
adget
.
state
.
message_list_dict
.
hasOwnProperty
(
room
))
{
throw
"
A contact with the same name already exists!
"
;
}
contact_element
=
document
.
createElement
(
"
li
"
);
contact_element
.
appendChild
(
document
.
createTextNode
(
room
));
contact_element
.
setAttribute
(
"
id
"
,
"
chat-contact-
"
+
nameToId
(
room
));
gadget
.
element
.
querySelector
(
"
.contact-list
"
)
.
appendChild
(
contact_element
);
contact_element
.
addEventListener
(
"
click
"
,
function
()
{
gadget
.
state
.
unread_room_set
[
room
]
=
false
;
if
(
gadget
.
state
.
room_set
[
room
]
!==
undefined
)
{
return
gadget
.
changeRoom
(
room
);
}
return
gadget
.
changeState
({
room
:
room
,
is_chat
:
false
,
update
:
true
});
},
false
);
return
gadget
.
createRoom
(
room
);
})
...
...
@@ -441,6 +441,12 @@
})
.
push
(
function
()
{
return
room_gadget
.
render
();
})
.
push
(
function
()
{
gadget
.
state
.
message_list_dict
[
room
]
=
[];
gadget
.
state
.
message_count_dict
[
room
]
=
0
;
gadget
.
state
.
id_to_name
[
"
chat-contact-
"
+
nameToId
(
room
)]
=
room
;
return
gadget
.
changeState
({
room
:
room
,
is_chat
:
false
});
});
})
...
...
@@ -449,7 +455,6 @@
* Parameters:
* - room: the name of the room to change to
* Effects:
* - changeState: room, room_set[room]
* - hide the room gadget contact panel
* - show the chat box
* - overwrite the chat box with chats from the jIO storage
...
...
@@ -459,9 +464,10 @@
var
gadget
=
this
;
return
gadget
.
changeState
({
room
:
room
,
is_chat
:
true
})
.
push
(
function
()
{
if
(
gadget
.
state
.
room_set
[
room
]
===
undefined
)
{
gadget
.
state
.
room_set
[
room
]
=
0
;
if
(
gadget
.
state
.
message_list_dict
[
room
].
length
===
0
)
{
return
gadget
.
deployMessage
({
name
:
gadget
.
state
.
name
,
room
:
gadget
.
state
.
room
,
content
:
gadget
.
state
.
name
+
"
has joined.
"
,
color
:
"
orange
"
});
...
...
@@ -481,18 +487,12 @@
.
declareMethod
(
"
deployMessage
"
,
function
(
param_dict
)
{
var
gadget
=
this
,
message
;
return
gadget
.
createMessage
(
param_dict
)
.
push
(
function
(
result
)
{
message
=
result
;
return
gadget
.
appendMessage
(
message
);
})
.
push
(
function
()
{
return
gadget
.
storeArchive
(
message
);
})
message
=
createMessage
(
param_dict
);
gadget
.
state
.
message_list_dict
[
param_dict
.
room
].
push
(
message
);
return
gadget
.
storeArchive
(
message
)
.
push
(
function
()
{
return
gadget
.
changeState
({
refresh_chat
:
true
});
})
})
;
})
...
...
@@ -505,53 +505,12 @@
*/
.
declareMethod
(
"
deployNotification
"
,
function
(
param_dict
)
{
var
gadget
=
this
;
param_dict
.
type
=
"
notification
"
;
return
gadget
.
createMessage
(
param_dict
)
.
push
(
function
(
result
)
{
return
gadget
.
appendMessage
(
result
);
});
})
/* Create a new message.
* Parameters:
* - name: the name of the sender of the message
* - room: the room from where the message is sent
* - time: the epoch time at which the message is sent
* - content: the content of the message
* - color: the colour of the message in the chat
* Effects: nothing
* Returns: a message object corresponding to the parameters
*/
.
declareMethod
(
"
createMessage
"
,
function
(
param_dict
)
{
var
gadget
=
this
;
return
{
type
:
param_dict
.
type
||
"
message
"
,
name
:
param_dict
.
name
||
gadget
.
state
.
name
,
room
:
param_dict
.
room
||
gadget
.
state
.
room
,
time
:
param_dict
.
time
||
new
Date
(),
content
:
param_dict
.
content
||
""
,
color
:
param_dict
.
color
||
"
black
"
};
})
/* Append a message to the chat.
* Parameters:
* - message: the message object to append to the chat
* Effects:
* - create a HTML chat element from the message
* - append the chat element to the chat list
* - scroll the chat list down to show the chat element
*/
.
declareMethod
(
"
appendMessage
"
,
function
(
message
)
{
var
gadget
=
this
,
container
=
gadget
.
element
.
querySelector
(
"
.chat-list
"
);
container
.
appendChild
(
messageToChat
(
message
));
container
.
scrollTop
=
container
.
scrollHeight
;
message
;
param_dict
.
type
=
"
notification
"
;
message
=
createMessage
(
param_dict
);
gadget
.
state
.
message_list_dict
[
param_dict
.
room
].
push
(
message
);
return
gadget
.
changeState
({
refresh_chat
:
true
});
})
...
...
@@ -590,30 +549,32 @@
.
declareMethod
(
"
delayRefresh
"
,
function
(
room
,
delay
)
{
var
gadget
=
this
;
console
.
log
(
room
,
delay
);
return
new
RSVP
.
Queue
()
.
push
(
function
()
{
return
RSVP
.
all
([
RSVP
.
delay
(
delay
),
//
gadget.refreshChat(room)
gadget
.
refreshChat
(
room
)
]);
})
.
push
(
function
()
{
if
(
gadget
.
state
.
delay_refresh_dict
.
hasOwnProperty
(
room
))
{
gadget
.
state
.
delay_refresh_dict
[
room
].
cancel
();
}
gadget
.
state
.
delay_refresh_dict
[
room
]
=
new
RSVP
.
Queue
()
.
push
(
function
()
{
return
gadget
.
delayRefresh
(
room
,
delay
+
5
00
);
return
gadget
.
delayRefresh
(
room
,
delay
+
100
00
);
});
})
})
;
})
/*
Overwrite the chat box
with chats from the jIO storage.
/*
Refresh the message list
with chats from the jIO storage.
* Parameters:
* - room: the room to refresh
* Effects:
* - get a sorted list of all chats in the current room from jIO storage
* -
remove the entire chat box and append all chats from jIO storag
e
* -
scroll the chat list down to show the chat element
* -
merge the list with the current messages in a priority queu
e
* -
update the current messages with the sorted message queue
*/
.
declareMethod
(
"
refreshChat
"
,
function
(
room
)
{
...
...
@@ -633,33 +594,50 @@
}]);
})
.
push
(
function
(
result_list
)
{
var
i
,
message
,
message_list
=
[],
container
=
gadget
.
element
.
querySelector
(
"
.chat-list
"
);
var
i
,
message
,
new_list
=
[],
old_list
=
gadget
.
state
.
message_list_dict
[
room
],
message_queue
=
new
FastPriorityQueue
(
function
(
lhs
,
rhs
)
{
return
getTime
(
lhs
)
<
getTime
(
rhs
);
});
if
(
result_list
.
data
.
total_rows
>
gadget
.
state
.
message_count_dict
[
room
])
{
gadget
.
state
.
message_count_dict
[
room
]
=
result_list
.
data
.
total_rows
;
gadget
.
state
.
unread_room_dict
[
room
]
=
true
;
if
(
result_list
.
data
.
total_rows
>
gadget
.
state
.
room_set
[
room
])
{
gadget
.
state
.
room_set
[
room
]
=
result_list
.
data
.
total_rows
;
gadget
.
state
.
unread_room_set
[
room
]
=
true
;
for
(
i
=
0
;
i
<
result_list
.
data
.
total_rows
;
i
+=
1
)
{
try
{
message
=
JSON
.
parse
(
result_list
.
data
.
rows
[
i
].
value
.
content
);
if
(
message
&&
typeof
message
===
"
object
"
)
{
message_
list
.
push
(
message
);
message_
queue
.
add
(
message
);
}
}
catch
(
ignore
)
{}
}
if
(
room
===
gadget
.
state
.
room
)
{
while
(
container
.
firstChild
)
{
container
.
removeChild
(
container
.
firstChild
);
}
for
(
i
=
0
;
i
<
message_list
.
length
;
i
+=
1
)
{
container
.
appendChild
(
messageToChat
(
message_list
[
i
]));
for
(
i
=
0
;
i
<
old_list
.
length
;
i
+=
1
)
{
if
(
!
message_queue
.
isEmpty
())
{
message
=
message_queue
.
poll
();
while
(
getTime
(
old_list
[
i
])
<
getTime
(
message
)
&&
i
<
old_list
.
length
)
{
new_list
.
push
(
old_list
[
i
]);
i
+=
1
;
}
while
(
getTime
(
old_list
[
i
])
===
getTime
(
message
))
{
i
+=
1
;
}
new_list
.
push
(
message
);
}
else
{
new_list
.
push
(
old_list
[
i
]);
}
container
.
scrollTop
=
container
.
scrollHeight
;
}
while
(
!
message_queue
.
isEmpty
())
{
new_list
.
push
(
message_queue
.
poll
());
}
gadget
.
state
.
message_list_dict
[
room
]
=
new_list
;
return
gadget
.
changeState
({
refresh_chat
:
true
});
}
})
})
;
})
...
...
@@ -675,7 +653,6 @@
split
=
chat
.
slice
(
1
).
split
(
"
"
),
command
=
split
.
shift
(),
argument
=
split
.
join
(
"
"
),
room_element
=
getContactFromRoom
(
gadget
,
gadget
.
state
.
room
),
promise_list
=
[],
help_list
=
[
"
Available commands:
"
,
...
...
@@ -688,10 +665,12 @@
// change to a room that has already been joined
case
"
join
"
:
if
(
gadget
.
state
.
room_set
[
argument
]
!==
undefined
)
{
if
(
gadget
.
state
.
message_list_dict
[
argument
]
>
0
)
{
return
gadget
.
changeRoom
(
argument
);
}
return
gadget
.
deployNotification
({
name
:
gadget
.
state
.
name
,
room
:
gadget
.
state
.
room
,
content
:
"
You must first be connected to room '
"
+
argument
+
"
' via a shared jIO storage to join it!
"
,
color
:
"
red
"
...
...
@@ -703,13 +682,16 @@
.
push
(
function
()
{
if
(
gadget
.
state
.
room
===
gadget
.
state
.
name
)
{
return
gadget
.
deployNotification
({
name
:
gadget
.
state
.
name
,
room
:
gadget
.
state
.
room
,
content
:
"
You cannot leave your own room!
"
,
color
:
"
red
"
});
}
gadget
.
state
.
room_set
[
gadget
.
state
.
room
]
=
undefined
;
room_element
.
parentNode
.
removeChild
(
room_element
);
delete
gadget
.
state
.
message_list_dict
[
gadget
.
state
.
room
];
return
gadget
.
deployMessage
({
name
:
gadget
.
state
.
name
,
room
:
gadget
.
state
.
room
,
content
:
gadget
.
state
.
name
+
"
has quit.
"
,
color
:
"
orange
"
})
...
...
@@ -726,6 +708,8 @@
case
"
help
"
:
for
(
i
=
0
;
i
<
help_list
.
length
;
i
+=
1
)
{
promise_list
.
push
(
gadget
.
deployNotification
({
name
:
gadget
.
state
.
name
,
room
:
gadget
.
state
.
room
,
content
:
help_list
[
i
],
color
:
"
green
"
}));
...
...
@@ -734,6 +718,8 @@
default
:
return
gadget
.
deployNotification
({
name
:
gadget
.
state
.
name
,
room
:
gadget
.
state
.
room
,
content
:
"
'
"
+
argument
+
"
' is not a valid command.
"
,
color
:
"
red
"
});
...
...
@@ -741,6 +727,22 @@
})
// Call changeRoom or changeState when a chat contact is clicked.
.
onEvent
(
"
click
"
,
function
(
event
)
{
var
gadget
=
this
,
room
;
if
(
event
.
target
.
classList
.
contains
(
"
chat-contact
"
))
{
room
=
gadget
.
state
.
id_to_name
[
event
.
target
.
id
];
gadget
.
state
.
unread_room_dict
[
room
]
=
false
;
if
(
gadget
.
state
.
message_list_dict
[
room
]
>
0
)
{
return
gadget
.
changeRoom
(
room
);
}
return
gadget
.
changeState
({
room
:
room
,
is_chat
:
false
,
update
:
true
});
}
},
false
,
false
)
// Call the appropriate function based on the form submitted.
.
onEvent
(
"
submit
"
,
function
(
event
)
{
...
...
@@ -748,8 +750,7 @@
content
;
switch
(
event
.
target
.
className
)
{
case
"
edit-form
"
:
content
=
resetInputValue
(
event
.
target
.
elements
.
content
);
return
gadget
.
changeState
({
room
:
content
});
return
gadget
.
changeState
({
is_chat
:
false
});
case
"
join-form
"
:
content
=
resetInputValue
(
event
.
target
.
elements
.
content
);
return
gadget
.
createContact
(
content
);
...
...
@@ -758,7 +759,11 @@
if
(
content
.
indexOf
(
"
/
"
)
===
0
)
{
return
gadget
.
parseCommand
(
content
);
}
return
gadget
.
deployMessage
({
content
:
content
});
return
gadget
.
deployMessage
({
name
:
gadget
.
state
.
name
,
room
:
gadget
.
state
.
room
,
content
:
content
});
}
})
...
...
@@ -776,10 +781,11 @@
})
.
push
(
function
()
{
var
promise_list
=
[],
room
;
for
(
room
in
gadget
.
state
.
room_se
t
)
{
if
(
gadget
.
state
.
room_se
t
.
hasOwnProperty
(
room
)
&&
gadget
.
state
.
room_set
[
room
]
!==
undefined
)
{
for
(
room
in
gadget
.
state
.
message_list_dic
t
)
{
if
(
gadget
.
state
.
message_list_dic
t
.
hasOwnProperty
(
room
)
&&
gadget
.
state
.
message_list_dict
[
room
]
>
0
)
{
promise_list
.
push
(
gadget
.
deployMessage
({
name
:
gadget
.
state
.
name
,
content
:
gadget
.
state
.
name
+
"
has quit.
"
,
room
:
room
,
color
:
"
orange
"
...
...
@@ -790,4 +796,5 @@
});
});
}(
window
,
document
,
RSVP
,
rJS
,
promiseEventListener
));
\ No newline at end of file
}(
window
,
document
,
RSVP
,
rJS
,
Handlebars
,
FastPriorityQueue
,
promiseEventListener
));
\ No newline at end of file
bt5/officejs_eyqs/PathTemplateItem/web_page_module/handlebars_js.js
0 → 100644
View file @
fdcbdb06
This source diff could not be displayed because it is too large. You can
view the blob
instead.
bt5/officejs_eyqs/PathTemplateItem/web_page_module/handlebars_js.xml
0 → 100644
View file @
fdcbdb06
<?xml version="1.0"?>
<ZopeData>
<record
id=
"1"
aka=
"AAAAAAAAAAE="
>
<pickle>
<global
name=
"Web Script"
module=
"erp5.portal_type"
/>
</pickle>
<pickle>
<dictionary>
<item>
<key>
<string>
_Access_contents_information_Permission
</string>
</key>
<value>
<tuple>
<string>
Anonymous
</string>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Associate
</string>
<string>
Auditor
</string>
<string>
Manager
</string>
<string>
Owner
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Add_portal_content_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Change_local_roles_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_Modify_portal_content_Permission
</string>
</key>
<value>
<tuple>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Manager
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
_View_Permission
</string>
</key>
<value>
<tuple>
<string>
Anonymous
</string>
<string>
Assignee
</string>
<string>
Assignor
</string>
<string>
Associate
</string>
<string>
Auditor
</string>
<string>
Manager
</string>
<string>
Owner
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
categories
</string>
</key>
<value>
<tuple>
<string>
classification/collaborative/team
</string>
</tuple>
</value>
</item>
<item>
<key>
<string>
content_md5
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
default_reference
</string>
</key>
<value>
<string>
handlebars.js
</string>
</value>
</item>
<item>
<key>
<string>
description
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
id
</string>
</key>
<value>
<string>
handlebars_js
</string>
</value>
</item>
<item>
<key>
<string>
language
</string>
</key>
<value>
<string>
en
</string>
</value>
</item>
<item>
<key>
<string>
portal_type
</string>
</key>
<value>
<string>
Web Script
</string>
</value>
</item>
<item>
<key>
<string>
short_title
</string>
</key>
<value>
<none/>
</value>
</item>
<item>
<key>
<string>
title
</string>
</key>
<value>
<string>
Handlebars JS
</string>
</value>
</item>
<item>
<key>
<string>
version
</string>
</key>
<value>
<string>
001
</string>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
bt5/officejs_eyqs/bt/template_path_list
View file @
fdcbdb06
web_page_module/adapter_js
web_page_module/erp5_page_launcher*
web_page_module/fast_priority_queue_js
web_page_module/gadget_erp5_chat_panel_*
web_page_module/gadget_erp5_chat_webrtc_*
web_page_module/gadget_erp5_nojquery_css
...
...
@@ -8,4 +9,5 @@ web_page_module/gadget_erp5_page_contact_*
web_page_module/gadget_erp5_page_field_listbox_widget_*
web_page_module/gadget_erp5_page_jio_*_configurator_*
web_page_module/gadget_erp5_page_jio_person_view_*
web_page_module/gadget_erp5_page_sync_*
\ No newline at end of file
web_page_module/gadget_erp5_page_sync_*
web_page_module/handlebars_js
\ No newline at end of file
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