Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cribjs
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
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Cédric Le Ninivin
cribjs
Commits
a1ab9293
Commit
a1ab9293
authored
Jun 08, 2020
by
Cédric Le Ninivin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update RSVP and RenderJS to latest version
parent
0c29519c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1552 additions
and
874 deletions
+1552
-874
lib/renderjs.js
lib/renderjs.js
+1442
-776
lib/rsvp.js
lib/rsvp.js
+110
-98
No files found.
lib/renderjs.js
View file @
a1ab9293
...
@@ -665,30 +665,216 @@ if (typeof document.contains !== 'function') {
...
@@ -665,30 +665,216 @@ if (typeof document.contains !== 'function') {
return
this
.
documentElement
.
contains
(
node
);
return
this
.
documentElement
.
contains
(
node
);
}
}
}
}
;
/*! RenderJs */
;(
function
(
DOMParser
)
{
/*jslint nomen: true*/
"
use strict
"
;
try
{
if
((
new
window
.
URL
(
"
../a
"
,
"
https://example.com/
"
)).
href
===
"
https://example.com/a
"
)
{
return
;
}
}
catch
(
ignore
)
{}
var
isAbsoluteOrDataURL
=
/^
(?:[
a-z
]
+:
)?\/\/
|data:/i
;
function
resolveUrl
(
url
,
base_url
)
{
var
doc
,
base
,
link
,
html
=
"
<!doctype><html><head></head></html>
"
;
if
(
url
&&
base_url
)
{
doc
=
(
new
DOMParser
()).
parseFromString
(
html
,
'
text/html
'
);
base
=
doc
.
createElement
(
'
base
'
);
link
=
doc
.
createElement
(
'
link
'
);
doc
.
head
.
appendChild
(
base
);
doc
.
head
.
appendChild
(
link
);
base
.
href
=
base_url
;
link
.
href
=
url
;
return
link
.
href
;
}
return
url
;
}
function
URL
(
url
,
base
)
{
if
(
base
!==
undefined
)
{
if
(
!
isAbsoluteOrDataURL
.
test
(
base
))
{
throw
new
TypeError
(
"
Failed to construct 'URL': Invalid base URL
"
);
}
url
=
resolveUrl
(
url
,
base
);
}
if
(
!
isAbsoluteOrDataURL
.
test
(
url
))
{
throw
new
TypeError
(
"
Failed to construct 'URL': Invalid URL
"
);
}
this
.
href
=
url
;
}
URL
.
prototype
.
href
=
""
;
if
(
window
.
URL
&&
window
.
URL
.
createObjectURL
)
{
URL
.
createObjectURL
=
window
.
URL
.
createObjectURL
;
}
if
(
window
.
URL
&&
window
.
URL
.
revokeObjectURL
)
{
URL
.
revokeObjectURL
=
window
.
URL
.
revokeObjectURL
;
}
window
.
URL
=
URL
;
}(
DOMParser
));;
/*
* Copyright 2012, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*
/*
* renderJs - Generic Gadget library renderer.
* renderJs - Generic Gadget library renderer.
* http
://www.renderjs.org/documentation
* http
s://renderjs.nexedi.com/
*/
*/
(
function
(
document
,
window
,
RSVP
,
DOMParser
,
Channel
,
MutationObserver
,
(
function
wrapRenderJS
(
document
,
window
,
RSVP
,
DOMParser
,
Channel
,
Node
,
FileReader
,
Blob
)
{
MutationObserver
,
Node
,
FileReader
,
Blob
,
navigator
,
Event
,
URL
)
{
"
use strict
"
;
"
use strict
"
;
// Error propagation in jschannel uses JSON.stringify
// Sadly, ...
// JSON.stringify(new TypeError('lala')) -> '{}'
// Change the browser default behaviour to propagate at least the message
// See https://stackoverflow.com/a/18391400
if
(
!
Error
.
prototype
.
hasOwnProperty
(
'
toJSON
'
))
{
Object
.
defineProperty
(
Error
.
prototype
,
'
toJSON
'
,
{
value
:
function
()
{
var
alt
=
{};
Object
.
getOwnPropertyNames
(
this
).
forEach
(
function
(
key
)
{
alt
[
key
]
=
this
[
key
];
},
this
);
return
alt
;
},
configurable
:
true
,
writable
:
true
});
}
/////////////////////////////////////////////////////////////////
// Error
/////////////////////////////////////////////////////////////////
function
ScopeError
(
message
)
{
this
.
name
=
"
scopeerror
"
;
if
((
message
!==
undefined
)
&&
(
typeof
message
!==
"
string
"
))
{
throw
new
TypeError
(
'
You must pass a string.
'
);
}
this
.
message
=
message
||
"
Scope Error
"
;
}
ScopeError
.
prototype
=
new
Error
();
ScopeError
.
prototype
.
constructor
=
ScopeError
;
function
ensurePushableQueue
(
callback
,
argument_list
,
context
)
{
var
result
;
try
{
result
=
callback
.
apply
(
context
,
argument_list
);
}
catch
(
e
)
{
return
new
RSVP
.
Queue
(
RSVP
.
reject
(
e
));
}
if
(
result
instanceof
RSVP
.
Queue
)
{
return
result
;
}
return
new
RSVP
.
Queue
(
result
);
}
function
readBlobAsDataURL
(
blob
)
{
function
readBlobAsDataURL
(
blob
)
{
var
fr
=
new
FileReader
();
var
fr
=
new
FileReader
();
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
return
new
RSVP
.
Promise
(
function
waitFormDataURLRead
(
resolve
,
reject
)
{
fr
.
addEventListener
(
"
load
"
,
function
(
evt
)
{
fr
.
addEventListener
(
"
load
"
,
function
handleDataURLRead
(
evt
)
{
resolve
(
evt
.
target
.
result
);
resolve
(
evt
.
target
.
result
);
});
});
fr
.
addEventListener
(
"
error
"
,
reject
);
fr
.
addEventListener
(
"
error
"
,
reject
);
fr
.
readAsDataURL
(
blob
);
fr
.
readAsDataURL
(
blob
);
},
function
()
{
},
function
cancelReadBlobAsDataURL
()
{
fr
.
abort
();
fr
.
abort
();
});
});
}
}
function
loopEventListener
(
target
,
type
,
useCapture
,
callback
,
prevent_default
)
{
//////////////////////////
// Infinite event listener (promise is never resolved)
// eventListener is removed when promise is cancelled/rejected
//////////////////////////
var
handle_event_callback
,
callback_promise
;
if
(
prevent_default
===
undefined
)
{
prevent_default
=
true
;
}
function
cancelResolver
()
{
if
((
callback_promise
!==
undefined
)
&&
(
typeof
callback_promise
.
cancel
===
"
function
"
))
{
callback_promise
.
cancel
();
}
}
function
canceller
()
{
if
(
handle_event_callback
!==
undefined
)
{
target
.
removeEventListener
(
type
,
handle_event_callback
,
useCapture
);
}
cancelResolver
();
}
function
itsANonResolvableTrap
(
resolve
,
reject
)
{
var
result
;
handle_event_callback
=
function
handleEventCallback
(
evt
)
{
if
(
prevent_default
)
{
evt
.
stopPropagation
();
evt
.
preventDefault
();
}
cancelResolver
();
try
{
result
=
callback
(
evt
);
}
catch
(
e
)
{
return
reject
(
e
);
}
callback_promise
=
new
RSVP
.
Queue
(
result
)
.
push
(
undefined
,
function
handleEventCallbackError
(
error
)
{
// Prevent rejecting the loop, if the result cancelled itself
if
(
!
(
error
instanceof
RSVP
.
CancellationError
))
{
canceller
();
reject
(
error
);
}
});
};
target
.
addEventListener
(
type
,
handle_event_callback
,
useCapture
);
}
return
new
RSVP
.
Promise
(
itsANonResolvableTrap
,
canceller
);
}
function
promiseAnimationFrame
()
{
var
request_id
;
function
canceller
()
{
window
.
cancelAnimationFrame
(
request_id
);
}
function
resolver
(
resolve
)
{
request_id
=
window
.
requestAnimationFrame
(
resolve
);
}
return
new
RSVP
.
Promise
(
resolver
,
canceller
);
}
function
ajax
(
url
)
{
function
ajax
(
url
)
{
var
xhr
;
var
xhr
;
function
resolver
(
resolve
,
reject
)
{
function
resolver
(
resolve
,
reject
)
{
...
@@ -729,14 +915,54 @@ if (typeof document.contains !== 'function') {
...
@@ -729,14 +915,54 @@ if (typeof document.contains !== 'function') {
return
new
RSVP
.
Promise
(
resolver
,
canceller
);
return
new
RSVP
.
Promise
(
resolver
,
canceller
);
}
}
var
gadget_model_dict
=
{},
var
gadget_model_d
efer_d
ict
=
{},
javascript_registration_dict
=
{},
javascript_registration_dict
=
{},
stylesheet_registration_dict
=
{},
stylesheet_registration_dict
=
{},
gadget_loading_klass
,
gadget_loading_klass_list
=
[],
loading_klass_promise
,
renderJS
,
renderJS
,
Monitor
,
Monitor
,
isAbsoluteOrDataURL
=
new
RegExp
(
'
^(?:[a-z]+:)?//|data:
'
,
'
i
'
);
Mutex
,
scope_increment
=
0
,
isAbsoluteOrDataURL
=
new
RegExp
(
'
^(?:[a-z]+:)?//|data:
'
,
'
i
'
),
is_page_unloaded
=
false
,
error_list
=
[],
all_dependency_loaded_deferred
;
window
.
addEventListener
(
'
error
'
,
function
handleGlobalError
(
error
)
{
error_list
.
push
(
error
);
});
window
.
addEventListener
(
'
beforeunload
'
,
function
handleBeforeUnload
()
{
// XXX If another listener cancel the page unload,
// it will not restore renderJS crash report
is_page_unloaded
=
true
;
});
/////////////////////////////////////////////////////////////////
// Mutex
/////////////////////////////////////////////////////////////////
Mutex
=
function
createMutex
()
{
if
(
!
(
this
instanceof
Mutex
))
{
return
new
Mutex
();
}
this
.
_latest_promise
=
null
;
};
Mutex
.
prototype
=
{
constructor
:
Mutex
,
lockAndRun
:
function
lockMutexAndRun
(
callback
)
{
var
previous_promise
=
this
.
_latest_promise
;
if
(
previous_promise
===
null
)
{
this
.
_latest_promise
=
RSVP
.
resolve
(
callback
());
}
else
{
this
.
_latest_promise
=
this
.
_latest_promise
.
always
(
function
()
{
return
callback
();
});
}
return
this
.
_latest_promise
;
}
};
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// Helper functions
// Helper functions
...
@@ -750,23 +976,111 @@ if (typeof document.contains !== 'function') {
...
@@ -750,23 +976,111 @@ if (typeof document.contains !== 'function') {
}
}
function
letsCrash
(
e
)
{
function
letsCrash
(
e
)
{
if
(
e
.
constructor
===
XMLHttpRequest
)
{
var
i
,
e
=
{
body
,
readyState
:
e
.
readyState
,
container
,
status
:
e
.
status
,
paragraph
,
statusText
:
e
.
statusText
,
link
,
response_headers
:
e
.
getAllResponseHeaders
()
error
;
};
if
(
is_page_unloaded
)
{
/*global console*/
console
.
info
(
'
-- Error dropped, as page is unloaded
'
);
console
.
info
(
e
);
return
;
}
}
if
(
e
.
constructor
===
Array
||
e
.
constructor
===
String
||
error_list
.
push
(
e
);
e
.
constructor
===
Object
)
{
// Add error handling stack
try
{
error_list
.
push
(
new
Error
(
'
stopping renderJS
'
));
e
=
JSON
.
stringify
(
e
);
}
catch
(
ignore
)
{
body
=
document
.
getElementsByTagName
(
'
body
'
)[
0
];
while
(
body
.
firstChild
)
{
body
.
removeChild
(
body
.
firstChild
);
}
container
=
document
.
createElement
(
"
section
"
);
paragraph
=
document
.
createElement
(
"
h1
"
);
paragraph
.
textContent
=
'
Unhandled Error
'
;
container
.
appendChild
(
paragraph
);
paragraph
=
document
.
createElement
(
"
p
"
);
paragraph
.
textContent
=
'
Please report this error to the support team
'
;
container
.
appendChild
(
paragraph
);
paragraph
=
document
.
createElement
(
"
p
"
);
paragraph
.
textContent
=
'
Location:
'
;
link
=
document
.
createElement
(
"
a
"
);
link
.
href
=
link
.
textContent
=
window
.
location
.
toString
();
paragraph
.
appendChild
(
link
);
container
.
appendChild
(
paragraph
);
paragraph
=
document
.
createElement
(
"
p
"
);
paragraph
.
textContent
=
'
User-agent:
'
+
navigator
.
userAgent
;
container
.
appendChild
(
paragraph
);
paragraph
=
document
.
createElement
(
"
p
"
);
paragraph
.
textContent
=
'
Date:
'
+
new
Date
(
Date
.
now
()).
toISOString
();
container
.
appendChild
(
paragraph
);
body
.
appendChild
(
container
);
for
(
i
=
0
;
i
<
error_list
.
length
;
i
+=
1
)
{
error
=
error_list
[
i
];
if
(
error
instanceof
Event
)
{
error
=
{
string
:
error
.
toString
(),
message
:
error
.
message
,
type
:
error
.
type
,
target
:
error
.
target
};
if
(
error
.
target
!==
undefined
)
{
error_list
.
splice
(
i
+
1
,
0
,
error
.
target
);
}
}
}
if
(
error
instanceof
XMLHttpRequest
)
{
error
=
{
message
:
error
.
toString
(),
readyState
:
error
.
readyState
,
status
:
error
.
status
,
statusText
:
error
.
statusText
,
response
:
error
.
response
,
responseUrl
:
error
.
responseUrl
,
response_headers
:
error
.
getAllResponseHeaders
()
};
}
if
(
error
.
constructor
===
Array
||
error
.
constructor
===
String
||
error
.
constructor
===
Object
)
{
try
{
error
=
JSON
.
stringify
(
error
);
}
catch
(
ignore
)
{
}
}
container
=
document
.
createElement
(
"
section
"
);
paragraph
=
document
.
createElement
(
"
h2
"
);
paragraph
.
textContent
=
error
.
message
||
error
;
container
.
appendChild
(
paragraph
);
if
(
error
.
fileName
!==
undefined
)
{
paragraph
=
document
.
createElement
(
"
p
"
);
paragraph
.
textContent
=
'
File:
'
+
error
.
fileName
+
'
:
'
+
error
.
lineNumber
;
container
.
appendChild
(
paragraph
);
}
if
(
error
.
stack
!==
undefined
)
{
paragraph
=
document
.
createElement
(
"
pre
"
);
paragraph
.
textContent
=
'
Stack:
'
+
error
.
stack
;
container
.
appendChild
(
paragraph
);
}
body
.
appendChild
(
container
);
}
}
document
.
getElementsByTagName
(
'
body
'
)[
0
].
textContent
=
e
;
// XXX Do not crash the application if it fails
// XXX Do not crash the application if it fails
// Where to write the error?
// Where to write the error?
/*global console*/
/*global console*/
...
@@ -787,12 +1101,11 @@ if (typeof document.contains !== 'function') {
...
@@ -787,12 +1101,11 @@ if (typeof document.contains !== 'function') {
ResolvedMonitorError
.
prototype
=
new
Error
();
ResolvedMonitorError
.
prototype
=
new
Error
();
ResolvedMonitorError
.
prototype
.
constructor
=
ResolvedMonitorError
;
ResolvedMonitorError
.
prototype
.
constructor
=
ResolvedMonitorError
;
Monitor
=
function
()
{
Monitor
=
function
createMonitor
()
{
var
monitor
=
this
,
var
monitor
=
this
,
promise_list
=
[],
promise_list
=
[],
promise
,
promise
,
reject
,
reject
,
notify
,
resolved
;
resolved
;
if
(
!
(
this
instanceof
Monitor
))
{
if
(
!
(
this
instanceof
Monitor
))
{
...
@@ -809,8 +1122,8 @@ if (typeof document.contains !== 'function') {
...
@@ -809,8 +1122,8 @@ if (typeof document.contains !== 'function') {
promise_list
=
[];
promise_list
=
[];
}
}
promise
=
new
RSVP
.
Promise
(
function
(
done
,
fail
,
progress
)
{
promise
=
new
RSVP
.
Promise
(
function
promiseMonitor
(
done
,
fail
)
{
reject
=
function
(
rejectedReason
)
{
reject
=
function
rejectMonitor
(
rejectedReason
)
{
if
(
resolved
)
{
if
(
resolved
)
{
return
;
return
;
}
}
...
@@ -820,36 +1133,28 @@ if (typeof document.contains !== 'function') {
...
@@ -820,36 +1133,28 @@ if (typeof document.contains !== 'function') {
canceller
();
canceller
();
return
fail
(
rejectedReason
);
return
fail
(
rejectedReason
);
};
};
notify
=
progress
;
},
canceller
);
},
canceller
);
monitor
.
cancel
=
function
()
{
monitor
.
cancel
=
function
cancelMonitor
()
{
if
(
resolved
)
{
if
(
resolved
)
{
return
;
return
;
}
}
resolved
=
true
;
resolved
=
true
;
promise
.
cancel
();
promise
.
cancel
();
promise
.
fail
(
function
(
rejectedReason
)
{
promise
.
fail
(
function
rejectMonitorPromise
(
rejectedReason
)
{
monitor
.
isRejected
=
true
;
monitor
.
isRejected
=
true
;
monitor
.
rejectedReason
=
rejectedReason
;
monitor
.
rejectedReason
=
rejectedReason
;
});
});
};
};
monitor
.
then
=
function
()
{
monitor
.
then
=
promise
.
then
.
bind
(
promise
);
return
promise
.
then
.
apply
(
promise
,
arguments
);
monitor
.
fail
=
promise
.
fail
.
bind
(
promise
);
};
monitor
.
fail
=
function
()
{
return
promise
.
fail
.
apply
(
promise
,
arguments
);
};
monitor
.
monitor
=
function
(
promise_to_monitor
)
{
monitor
.
monitor
=
function
startMonitor
(
promise_to_monitor
)
{
if
(
resolved
)
{
if
(
resolved
)
{
throw
new
ResolvedMonitorError
();
throw
new
ResolvedMonitorError
();
}
}
var
queue
=
new
RSVP
.
Queue
()
var
queue
=
new
RSVP
.
Queue
(
promise_to_monitor
)
.
push
(
function
()
{
.
push
(
function
handlePromiseToMonitorSuccess
(
fulfillmentValue
)
{
return
promise_to_monitor
;
})
.
push
(
function
(
fulfillmentValue
)
{
// Promise to monitor is fullfilled, remove it from the list
// Promise to monitor is fullfilled, remove it from the list
var
len
=
promise_list
.
length
,
var
len
=
promise_list
.
length
,
sub_promise_to_monitor
,
sub_promise_to_monitor
,
...
@@ -863,19 +1168,9 @@ if (typeof document.contains !== 'function') {
...
@@ -863,19 +1168,9 @@ if (typeof document.contains !== 'function') {
}
}
}
}
promise_list
=
new_promise_list
;
promise_list
=
new_promise_list
;
},
function
(
rejectedReason
)
{
},
function
handlePromiseToMonitorError
(
rejectedReason
)
{
if
(
rejectedReason
instanceof
RSVP
.
CancellationError
)
{
if
(
!
(
promise_to_monitor
.
isFulfilled
&&
promise_to_monitor
.
isRejected
))
{
// The queue could be cancelled before the first push is run
promise_to_monitor
.
cancel
();
}
}
reject
(
rejectedReason
);
reject
(
rejectedReason
);
throw
rejectedReason
;
throw
rejectedReason
;
},
function
(
notificationValue
)
{
notify
(
notificationValue
);
return
notificationValue
;
});
});
promise_list
.
push
(
queue
);
promise_list
.
push
(
queue
);
...
@@ -902,131 +1197,326 @@ if (typeof document.contains !== 'function') {
...
@@ -902,131 +1197,326 @@ if (typeof document.contains !== 'function') {
RenderJSGadget
.
prototype
.
__required_css_list
=
[];
RenderJSGadget
.
prototype
.
__required_css_list
=
[];
RenderJSGadget
.
prototype
.
__required_js_list
=
[];
RenderJSGadget
.
prototype
.
__required_js_list
=
[];
function
create
Monitor
(
g
)
{
function
deleteGadget
Monitor
(
g
)
{
if
(
g
.
__monitor
!==
undefined
)
{
if
(
g
.
hasOwnProperty
(
'
__monitor
'
)
)
{
g
.
__monitor
.
cancel
();
g
.
__monitor
.
cancel
();
delete
g
.
__monitor
;
g
.
__job_list
=
[];
}
}
}
function
createGadgetMonitor
(
g
)
{
g
.
__monitor
=
new
Monitor
();
g
.
__monitor
=
new
Monitor
();
g
.
__monitor
.
fail
(
function
(
error
)
{
g
.
__job_dict
=
{};
g
.
__job_triggered
=
false
;
g
.
__monitor
.
fail
(
function
handleGadgetMonitorError
(
error
)
{
if
(
!
(
error
instanceof
RSVP
.
CancellationError
))
{
if
(
!
(
error
instanceof
RSVP
.
CancellationError
))
{
return
g
.
aq_reportServiceError
(
error
);
return
g
.
aq_reportServiceError
(
error
);
}
}
}).
fail
(
function
(
error
)
{
// Crash the application if the acquisition generates an error.
// Crash the application if the acquisition generates an error.
}).
fail
(
letsCrash
);
return
letsCrash
(
error
);
});
}
}
function
clearGadgetInternalParameters
(
g
)
{
function
clearGadgetInternalParameters
(
gadget
)
{
g
.
__sub_gadget_dict
=
{};
gadget
.
__sub_gadget_dict
=
{};
createMonitor
(
g
);
gadget
.
__job_list
=
[];
if
(
gadget
.
__json_state
!==
undefined
)
{
gadget
.
state
=
JSON
.
parse
(
gadget
.
__json_state
);
}
}
}
function
loadSubGadgetDOMDeclaration
(
g
)
{
function
loadSubGadgetDOMDeclaration
()
{
var
element_list
=
g
.
__element
.
querySelectorAll
(
'
[data-gadget-scope
]
'
),
var
element_list
=
this
.
element
.
querySelectorAll
(
'
[data-gadget-url
]
'
),
element
,
element
,
promise_list
=
[],
promise_list
=
[],
scope
,
scope
,
url
,
url
,
sandbox
,
sandbox
,
i
;
i
,
context
=
this
;
function
prepareReportGadgetDeclarationError
(
scope
)
{
return
function
reportGadgetDeclarationError
(
error
)
{
var
aq_dict
=
context
.
__acquired_method_dict
||
{},
method_name
=
'
reportGadgetDeclarationError
'
;
if
(
aq_dict
.
hasOwnProperty
(
method_name
))
{
return
aq_dict
[
method_name
].
apply
(
context
,
[
arguments
,
scope
]);
}
throw
error
;
};
}
for
(
i
=
0
;
i
<
element_list
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
element_list
.
length
;
i
+=
1
)
{
element
=
element_list
[
i
];
element
=
element_list
[
i
];
scope
=
element
.
getAttribute
(
"
data-gadget-scope
"
);
scope
=
element
.
getAttribute
(
"
data-gadget-scope
"
);
url
=
element
.
getAttribute
(
"
data-gadget-url
"
);
url
=
element
.
getAttribute
(
"
data-gadget-url
"
);
sandbox
=
element
.
getAttribute
(
"
data-gadget-sandbox
"
);
sandbox
=
element
.
getAttribute
(
"
data-gadget-sandbox
"
);
if
((
scope
!==
null
)
&&
(
url
!==
null
))
{
if
(
url
!==
null
)
{
promise_list
.
push
(
g
.
declareGadget
(
url
,
{
promise_list
.
push
(
element
:
element
,
context
.
declareGadget
(
url
,
{
scope
:
scope
||
undefined
,
element
:
element
,
sandbox
:
sandbox
||
undefined
scope
:
scope
||
undefined
,
}));
sandbox
:
sandbox
||
undefined
})
.
push
(
undefined
,
prepareReportGadgetDeclarationError
(
scope
))
);
}
}
}
}
return
RSVP
.
all
(
promise_list
);
return
RSVP
.
all
(
promise_list
);
}
}
RenderJSGadget
.
__ready_list
=
[
clearGadgetInternalParameters
,
RenderJSGadget
.
__ready_list
=
[];
loadSubGadgetDOMDeclaration
];
RenderJSGadget
.
ready
=
function
ready
(
callback
)
{
RenderJSGadget
.
ready
=
function
(
callback
)
{
this
.
__ready_list
.
push
(
callback
);
this
.
__ready_list
.
push
(
callback
);
return
this
;
return
this
;
};
};
RenderJSGadget
.
setState
=
function
setState
(
state_dict
)
{
this
.
prototype
.
__json_state
=
JSON
.
stringify
(
state_dict
);
return
this
;
};
RenderJSGadget
.
onStateChange
=
function
onStateChange
(
callback
)
{
this
.
prototype
.
__state_change_callback
=
callback
;
return
this
;
};
RenderJSGadget
.
__service_list
=
[];
RenderJSGadget
.
__service_list
=
[];
RenderJSGadget
.
declareService
=
function
(
callback
)
{
RenderJSGadget
.
declareService
=
function
declareService
(
callback
)
{
this
.
__service_list
.
push
(
callback
);
this
.
__service_list
.
push
(
callback
);
return
this
;
return
this
;
};
};
RenderJSGadget
.
onEvent
=
function
onEvent
(
type
,
callback
,
use_capture
,
prevent_default
)
{
this
.
__service_list
.
push
(
function
startLoopEventListenerService
()
{
return
loopEventListener
(
this
.
element
,
type
,
use_capture
,
callback
.
bind
(
this
),
prevent_default
);
});
return
this
;
};
RenderJSGadget
.
onLoop
=
function
onLoop
(
callback
,
delay
)
{
if
(
delay
===
undefined
)
{
delay
=
0
;
}
this
.
__service_list
.
push
(
function
handleServiceCallback
()
{
var
queue_loop
=
new
RSVP
.
Queue
(),
context
=
this
,
wait
=
function
waitForLoopIteration
()
{
queue_loop
.
push
(
function
waitNextOnLoopDelay
()
{
return
RSVP
.
delay
(
delay
);
})
.
push
(
function
waitNextOnLoopAnimationFrame
()
{
// Only loop when the app has the focus
return
promiseAnimationFrame
();
})
.
push
(
function
executeOnLoopCallback
()
{
return
callback
.
apply
(
context
,
[]);
})
.
push
(
wait
);
};
wait
();
return
queue_loop
;
});
return
this
;
};
function
runJob
(
gadget
,
name
,
callback
,
argument_list
)
{
if
(
gadget
.
__job_dict
.
hasOwnProperty
(
name
))
{
gadget
.
__job_dict
[
name
].
cancel
();
}
var
job_promise
=
ensurePushableQueue
(
callback
,
argument_list
,
gadget
);
gadget
.
__job_dict
[
name
]
=
job_promise
;
// gadget.__monitor.monitor(job_promise
gadget
.
__monitor
.
monitor
(
new
RSVP
.
Queue
(
job_promise
)
.
push
(
undefined
,
function
handleJobError
(
error
)
{
// Do not crash monitor if the job has been cancelled
// by a new execution
if
(
!
(
error
instanceof
RSVP
.
CancellationError
))
{
throw
error
;
}
}));
}
function
startService
(
gadget
)
{
function
startService
(
gadget
)
{
if
(((
gadget
.
constructor
.
__service_list
.
length
===
0
)
&&
(
!
gadget
.
constructor
.
__job_declared
))
||
(
gadget
.
hasOwnProperty
(
'
__monitor
'
)))
{
return
;
}
createGadgetMonitor
(
gadget
);
gadget
.
__monitor
.
monitor
(
new
RSVP
.
Queue
()
gadget
.
__monitor
.
monitor
(
new
RSVP
.
Queue
()
.
push
(
function
()
{
.
push
(
function
monitorAllServiceList
()
{
var
i
,
var
i
,
service_list
=
gadget
.
constructor
.
__service_list
;
service_list
=
gadget
.
constructor
.
__service_list
,
job_list
=
gadget
.
__job_list
;
for
(
i
=
0
;
i
<
service_list
.
length
;
i
+=
1
)
{
for
(
i
=
0
;
i
<
service_list
.
length
;
i
+=
1
)
{
gadget
.
__monitor
.
monitor
(
service_list
[
i
].
apply
(
gadget
));
gadget
.
__monitor
.
monitor
(
service_list
[
i
].
apply
(
gadget
));
}
}
for
(
i
=
0
;
i
<
job_list
.
length
;
i
+=
1
)
{
runJob
(
gadget
,
job_list
[
i
][
0
],
job_list
[
i
][
1
],
job_list
[
i
][
2
]);
}
gadget
.
__job_list
=
[];
gadget
.
__job_triggered
=
true
;
})
})
);
);
}
}
function
registerMethod
(
gadget_klass
,
method_name
,
method_type
)
{
if
(
!
gadget_klass
.
hasOwnProperty
(
'
__method_type_dict
'
))
{
gadget_klass
.
__method_type_dict
=
{};
}
gadget_klass
.
__method_type_dict
[
method_name
]
=
method_type
;
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareMethod
// RenderJSGadget.declareJob
// gadget internal method, which trigger execution
// of a function inside a service
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
RenderJSGadget
.
declareMethod
=
function
(
name
,
callback
)
{
RenderJSGadget
.
declareJob
=
function
declareJob
(
name
,
callback
)
{
this
.
prototype
[
name
]
=
function
()
{
this
.
__job_declared
=
true
;
this
.
prototype
[
name
]
=
function
triggerJob
()
{
var
context
=
this
,
var
context
=
this
,
argument_list
=
arguments
;
argument_list
=
arguments
;
return
new
RSVP
.
Queue
()
if
(
context
.
__job_triggered
)
{
.
push
(
function
()
{
runJob
(
context
,
name
,
callback
,
argument_list
);
return
callback
.
apply
(
context
,
argument_list
);
}
else
{
});
context
.
__job_list
.
push
([
name
,
callback
,
argument_list
]);
}
};
};
registerMethod
(
this
,
name
,
'
job
'
);
// Allow chain
return
this
;
};
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareMethod
/////////////////////////////////////////////////////////////////
RenderJSGadget
.
declareMethod
=
function
declareMethod
(
name
,
callback
,
options
)
{
this
.
prototype
[
name
]
=
function
triggerMethod
()
{
var
context
=
this
,
argument_list
=
arguments
,
mutex_name
;
function
waitForMethodCallback
()
{
return
callback
.
apply
(
context
,
argument_list
);
}
if
((
options
!==
undefined
)
&&
(
options
.
hasOwnProperty
(
'
mutex
'
)))
{
mutex_name
=
'
__mutex_
'
+
options
.
mutex
;
if
(
!
context
.
hasOwnProperty
(
mutex_name
))
{
context
[
mutex_name
]
=
new
Mutex
();
}
return
ensurePushableQueue
(
context
[
mutex_name
].
lockAndRun
,
[
waitForMethodCallback
],
context
[
mutex_name
]);
}
return
ensurePushableQueue
(
callback
,
argument_list
,
context
);
};
registerMethod
(
this
,
name
,
'
method
'
);
// Allow chain
// Allow chain
return
this
;
return
this
;
};
};
RenderJSGadget
RenderJSGadget
.
declareMethod
(
'
getInterfaceList
'
,
function
()
{
.
declareMethod
(
'
getInterfaceList
'
,
function
getInterfaceList
()
{
// Returns the list of gadget prototype
// Returns the list of gadget prototype
return
this
.
__interface_list
;
return
this
.
__interface_list
;
})
})
.
declareMethod
(
'
getRequiredCSSList
'
,
function
()
{
.
declareMethod
(
'
getMethodList
'
,
function
getMethodList
(
type
)
{
// Returns the list of gadget methods
var
key
,
method_list
=
[],
method_dict
=
this
.
constructor
.
__method_type_dict
||
{};
for
(
key
in
method_dict
)
{
if
(
method_dict
.
hasOwnProperty
(
key
))
{
if
((
type
===
undefined
)
||
(
type
===
method_dict
[
key
]))
{
method_list
.
push
(
key
);
}
}
}
return
method_list
;
})
.
declareMethod
(
'
getRequiredCSSList
'
,
function
getRequiredCSSList
()
{
// Returns a list of CSS required by the gadget
// Returns a list of CSS required by the gadget
return
this
.
__required_css_list
;
return
this
.
__required_css_list
;
})
})
.
declareMethod
(
'
getRequiredJSList
'
,
function
()
{
.
declareMethod
(
'
getRequiredJSList
'
,
function
getRequiredJSList
()
{
// Returns a list of JS required by the gadget
// Returns a list of JS required by the gadget
return
this
.
__required_js_list
;
return
this
.
__required_js_list
;
})
})
.
declareMethod
(
'
getPath
'
,
function
()
{
.
declareMethod
(
'
getPath
'
,
function
getPath
()
{
// Returns the path of the code of a gadget
// Returns the path of the code of a gadget
return
this
.
__path
;
return
this
.
__path
;
})
})
.
declareMethod
(
'
getTitle
'
,
function
()
{
.
declareMethod
(
'
getTitle
'
,
function
getTitle
()
{
// Returns the title of a gadget
// Returns the title of a gadget
return
this
.
__title
;
return
this
.
__title
;
})
})
.
declareMethod
(
'
getElement
'
,
function
()
{
.
declareMethod
(
'
getElement
'
,
function
getElement
()
{
// Returns the DOM Element of a gadget
// Returns the DOM Element of a gadget
if
(
this
.
__element
===
undefined
)
{
// XXX Kept for compatibility. Use element property directly
if
(
this
.
element
===
undefined
)
{
throw
new
Error
(
"
No element defined
"
);
throw
new
Error
(
"
No element defined
"
);
}
}
return
this
.
__element
;
return
this
.
element
;
});
})
.
declareMethod
(
'
changeState
'
,
function
changeState
(
state_dict
)
{
var
context
=
this
,
key
,
modified
=
false
,
previous_cancelled
=
context
.
hasOwnProperty
(
'
__modification_dict
'
),
modification_dict
;
if
(
previous_cancelled
)
{
modification_dict
=
context
.
__modification_dict
;
modified
=
true
;
}
else
{
modification_dict
=
{};
}
for
(
key
in
state_dict
)
{
if
(
state_dict
.
hasOwnProperty
(
key
)
&&
(
state_dict
[
key
]
!==
context
.
state
[
key
]))
{
context
.
state
[
key
]
=
state_dict
[
key
];
modification_dict
[
key
]
=
state_dict
[
key
];
modified
=
true
;
}
}
if
(
modified
&&
context
.
__state_change_callback
!==
undefined
)
{
context
.
__modification_dict
=
modification_dict
;
return
ensurePushableQueue
(
context
.
__state_change_callback
,
[
modification_dict
],
context
)
.
push
(
function
handleStateChangeSuccess
(
result
)
{
delete
context
.
__modification_dict
;
return
result
;
});
}
},
{
mutex
:
'
changestate
'
});
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareAcquiredMethod
// RenderJSGadget.declareAcquiredMethod
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
function
acquire
(
child_gadget
,
method_name
,
argument_list
)
{
function
acquire
(
child_gadget
,
method_name
,
argument_list
)
{
var
gadget
=
this
,
var
gadget
=
this
,
// Do not specify default __acquired_method_dict on prototype
// to prevent modifying this default value (with
// allowPublicAcquiredMethod for example)
aq_dict
=
gadget
.
__acquired_method_dict
||
{},
key
,
key
,
gadget_scope
;
gadget_scope
;
if
(
!
aq_dict
.
hasOwnProperty
(
method_name
))
{
// "aq_dynamic is not defined"
return
gadget
.
__aq_parent
(
method_name
,
argument_list
);
}
for
(
key
in
gadget
.
__sub_gadget_dict
)
{
for
(
key
in
gadget
.
__sub_gadget_dict
)
{
if
(
gadget
.
__sub_gadget_dict
.
hasOwnProperty
(
key
))
{
if
(
gadget
.
__sub_gadget_dict
.
hasOwnProperty
(
key
))
{
if
(
gadget
.
__sub_gadget_dict
[
key
]
===
child_gadget
)
{
if
(
gadget
.
__sub_gadget_dict
[
key
]
===
child_gadget
)
{
...
@@ -1034,19 +1524,13 @@ if (typeof document.contains !== 'function') {
...
@@ -1034,19 +1524,13 @@ if (typeof document.contains !== 'function') {
}
}
}
}
}
}
return
new
RSVP
.
Queue
()
.
push
(
function
()
{
return
ensurePushableQueue
(
// Do not specify default __acquired_method_dict on prototype
aq_dict
[
method_name
],
// to prevent modifying this default value (with
[
argument_list
,
gadget_scope
],
// allowPublicAcquiredMethod for example)
gadget
var
aq_dict
=
gadget
.
__acquired_method_dict
||
{};
)
if
(
aq_dict
.
hasOwnProperty
(
method_name
))
{
.
push
(
undefined
,
function
handleAcquireMethodError
(
error
)
{
return
aq_dict
[
method_name
].
apply
(
gadget
,
[
argument_list
,
gadget_scope
]);
}
throw
new
renderJS
.
AcquisitionError
(
"
aq_dynamic is not defined
"
);
})
.
push
(
undefined
,
function
(
error
)
{
if
(
error
instanceof
renderJS
.
AcquisitionError
)
{
if
(
error
instanceof
renderJS
.
AcquisitionError
)
{
return
gadget
.
__aq_parent
(
method_name
,
argument_list
);
return
gadget
.
__aq_parent
(
method_name
,
argument_list
);
}
}
...
@@ -1055,27 +1539,30 @@ if (typeof document.contains !== 'function') {
...
@@ -1055,27 +1539,30 @@ if (typeof document.contains !== 'function') {
}
}
RenderJSGadget
.
declareAcquiredMethod
=
RenderJSGadget
.
declareAcquiredMethod
=
function
(
name
,
method_name_to_acquire
)
{
function
declareAcquiredMethod
(
name
,
method_name_to_acquire
)
{
this
.
prototype
[
name
]
=
function
()
{
this
.
prototype
[
name
]
=
function
acquireMethod
()
{
var
argument_list
=
Array
.
prototype
.
slice
.
call
(
arguments
,
0
),
var
argument_list
=
Array
.
prototype
.
slice
.
call
(
arguments
,
0
),
gadget
=
this
;
gadget
=
this
;
return
new
RSVP
.
Queue
()
return
ensurePushableQueue
(
.
push
(
function
()
{
gadget
.
__aq_parent
,
return
gadget
.
__aq_parent
(
method_name_to_acquire
,
argument_list
);
[
method_name_to_acquire
,
argument_list
],
});
gadget
);
};
};
registerMethod
(
this
,
name
,
'
acquired_method
'
);
// Allow chain
// Allow chain
return
this
;
return
this
;
};
};
RenderJSGadget
.
declareAcquiredMethod
(
"
aq_reportServiceError
"
,
RenderJSGadget
.
declareAcquiredMethod
(
"
aq_reportServiceError
"
,
"
reportServiceError
"
);
"
reportServiceError
"
);
RenderJSGadget
.
declareAcquiredMethod
(
"
aq_reportGadgetDeclarationError
"
,
"
reportGadgetDeclarationError
"
);
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// RenderJSGadget.allowPublicAcquisition
// RenderJSGadget.allowPublicAcquisition
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
RenderJSGadget
.
allowPublicAcquisition
=
RenderJSGadget
.
allowPublicAcquisition
=
function
(
method_name
,
callback
)
{
function
allowPublicAcquisition
(
method_name
,
callback
)
{
this
.
prototype
.
__acquired_method_dict
[
method_name
]
=
callback
;
this
.
prototype
.
__acquired_method_dict
[
method_name
]
=
callback
;
// Allow chain
// Allow chain
...
@@ -1084,10 +1571,11 @@ if (typeof document.contains !== 'function') {
...
@@ -1084,10 +1571,11 @@ if (typeof document.contains !== 'function') {
// Set aq_parent on gadget_instance which call acquire on parent_gadget
// Set aq_parent on gadget_instance which call acquire on parent_gadget
function
setAqParent
(
gadget_instance
,
parent_gadget
)
{
function
setAqParent
(
gadget_instance
,
parent_gadget
)
{
gadget_instance
.
__aq_parent
=
function
(
method_name
,
argument_list
)
{
gadget_instance
.
__aq_parent
=
return
acquire
.
apply
(
parent_gadget
,
[
gadget_instance
,
method_name
,
function
__aq_parent
(
method_name
,
argument_list
)
{
argument_list
]);
return
acquire
.
apply
(
parent_gadget
,
[
gadget_instance
,
method_name
,
};
argument_list
]);
};
}
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
...
@@ -1100,71 +1588,69 @@ if (typeof document.contains !== 'function') {
...
@@ -1100,71 +1588,69 @@ if (typeof document.contains !== 'function') {
}
}
RenderJSGadget
.
call
(
this
);
RenderJSGadget
.
call
(
this
);
}
}
RenderJSEmbeddedGadget
.
__ready_list
=
RenderJSGadget
.
__ready_list
.
slice
()
;
RenderJSEmbeddedGadget
.
__ready_list
=
[]
;
RenderJSEmbeddedGadget
.
__service_list
=
RenderJSEmbeddedGadget
.
__service_list
=
RenderJSGadget
.
__service_list
.
slice
();
RenderJSGadget
.
__service_list
.
slice
();
RenderJSEmbeddedGadget
.
ready
=
RenderJSEmbeddedGadget
.
ready
=
RenderJSGadget
.
ready
;
RenderJSGadget
.
ready
;
RenderJSEmbeddedGadget
.
setState
=
RenderJSGadget
.
setState
;
RenderJSEmbeddedGadget
.
onStateChange
=
RenderJSGadget
.
onStateChange
;
RenderJSEmbeddedGadget
.
declareService
=
RenderJSEmbeddedGadget
.
declareService
=
RenderJSGadget
.
declareService
;
RenderJSGadget
.
declareService
;
RenderJSEmbeddedGadget
.
onEvent
=
RenderJSGadget
.
onEvent
;
RenderJSEmbeddedGadget
.
onLoop
=
RenderJSGadget
.
onLoop
;
RenderJSEmbeddedGadget
.
prototype
=
new
RenderJSGadget
();
RenderJSEmbeddedGadget
.
prototype
=
new
RenderJSGadget
();
RenderJSEmbeddedGadget
.
prototype
.
constructor
=
RenderJSEmbeddedGadget
;
RenderJSEmbeddedGadget
.
prototype
.
constructor
=
RenderJSEmbeddedGadget
;
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// privateDeclarePublicGadget
// privateDeclarePublicGadget
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
function
privateDeclarePublicGadget
(
url
,
options
,
parent_gadget
)
{
function
createPrivateInstanceFromKlass
(
Klass
,
options
,
parent_gadget
,
var
gadget_instance
;
old_element
)
{
if
(
options
.
element
===
undefined
)
{
// Get the gadget class and instanciate it
options
.
element
=
document
.
createElement
(
"
div
"
);
var
i
,
gadget_instance
,
template_node_list
=
Klass
.
__template_element
.
body
.
childNodes
,
fragment
=
document
.
createDocumentFragment
();
gadget_instance
=
new
Klass
();
gadget_instance
.
element
=
options
.
element
;
gadget_instance
.
state
=
{};
for
(
i
=
0
;
i
<
template_node_list
.
length
;
i
+=
1
)
{
fragment
.
appendChild
(
template_node_list
[
i
].
cloneNode
(
true
)
);
}
}
gadget_instance
.
element
.
appendChild
(
fragment
);
function
loadDependency
(
method
,
url
)
{
setAqParent
(
gadget_instance
,
parent_gadget
);
return
function
()
{
clearGadgetInternalParameters
(
gadget_instance
);
return
method
(
url
);
if
(
old_element
!==
undefined
)
{
};
// Add gadget to the DOM if needed
// Do it when all DOM modifications are done
old_element
.
parentNode
.
replaceChild
(
options
.
element
,
old_element
);
}
}
return
gadget_instance
;
}
return
new
RSVP
.
Queue
()
function
privateDeclarePublicGadget
(
url
,
options
,
parent_gadget
,
.
push
(
function
()
{
old_element
)
{
return
renderJS
.
declareGadgetKlass
(
url
);
var
klass
=
renderJS
.
declareGadgetKlass
(
url
);
})
// gadget loading should not be interrupted
// Get the gadget class and instanciate it
// if not, gadget's definition will not be complete
.
push
(
function
(
Klass
)
{
//.then will return another promise
var
i
,
//so loading_klass_promise can't be cancel
template_node_list
=
Klass
.
__template_element
.
body
.
childNodes
;
if
(
typeof
klass
.
then
===
'
function
'
)
{
gadget_loading_klass
=
Klass
;
return
klass
.
then
(
function
createAsyncPrivateInstanceFromKlass
(
Klass
)
{
gadget_instance
=
new
Klass
();
return
createPrivateInstanceFromKlass
(
Klass
,
options
,
parent_gadget
,
gadget_instance
.
__element
=
options
.
element
;
old_element
);
for
(
i
=
0
;
i
<
template_node_list
.
length
;
i
+=
1
)
{
gadget_instance
.
__element
.
appendChild
(
template_node_list
[
i
].
cloneNode
(
true
)
);
}
setAqParent
(
gadget_instance
,
parent_gadget
);
// Load dependencies if needed
return
RSVP
.
all
([
gadget_instance
.
getRequiredJSList
(),
gadget_instance
.
getRequiredCSSList
()
]);
})
// Load all JS/CSS
.
push
(
function
(
all_list
)
{
var
q
=
new
RSVP
.
Queue
(),
i
;
// Load JS
for
(
i
=
0
;
i
<
all_list
[
0
].
length
;
i
+=
1
)
{
q
.
push
(
loadDependency
(
renderJS
.
declareJS
,
all_list
[
0
][
i
]));
}
// Load CSS
for
(
i
=
0
;
i
<
all_list
[
1
].
length
;
i
+=
1
)
{
q
.
push
(
loadDependency
(
renderJS
.
declareCSS
,
all_list
[
1
][
i
]));
}
return
q
;
})
.
push
(
function
()
{
return
gadget_instance
;
});
});
}
return
createPrivateInstanceFromKlass
(
klass
,
options
,
parent_gadget
,
old_element
);
}
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
...
@@ -1176,29 +1662,38 @@ if (typeof document.contains !== 'function') {
...
@@ -1176,29 +1662,38 @@ if (typeof document.contains !== 'function') {
}
}
RenderJSGadget
.
call
(
this
);
RenderJSGadget
.
call
(
this
);
}
}
RenderJSIframeGadget
.
__ready_list
=
RenderJSGadget
.
__ready_list
.
slice
()
;
RenderJSIframeGadget
.
__ready_list
=
[]
;
RenderJSIframeGadget
.
ready
=
RenderJSIframeGadget
.
ready
=
RenderJSGadget
.
ready
;
RenderJSGadget
.
ready
;
RenderJSIframeGadget
.
__service_list
=
RenderJSGadget
.
__service_list
.
slice
();
RenderJSIframeGadget
.
setState
=
RenderJSGadget
.
setState
;
RenderJSIframeGadget
.
onStateChange
=
RenderJSGadget
.
onStateChange
;
RenderJSIframeGadget
.
__service_list
=
[];
RenderJSIframeGadget
.
declareService
=
RenderJSIframeGadget
.
declareService
=
RenderJSGadget
.
declareService
;
RenderJSGadget
.
declareService
;
RenderJSIframeGadget
.
onEvent
=
RenderJSGadget
.
onEvent
;
RenderJSIframeGadget
.
onLoop
=
RenderJSGadget
.
onLoop
;
RenderJSIframeGadget
.
prototype
=
new
RenderJSGadget
();
RenderJSIframeGadget
.
prototype
=
new
RenderJSGadget
();
RenderJSIframeGadget
.
prototype
.
constructor
=
RenderJSIframeGadget
;
RenderJSIframeGadget
.
prototype
.
constructor
=
RenderJSIframeGadget
;
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// privateDeclareIframeGadget
// privateDeclareIframeGadget
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
function
privateDeclareIframeGadget
(
url
,
options
,
parent_gadget
)
{
function
privateDeclareIframeGadget
(
url
,
options
,
parent_gadget
,
old_element
)
{
var
gadget_instance
,
var
gadget_instance
,
iframe
,
iframe
,
iframe_loading_deferred
=
RSVP
.
defer
();
iframe_loading_deferred
=
RSVP
.
defer
();
if
(
o
ptions
.
element
===
undefined
)
{
if
(
o
ld_
element
===
undefined
)
{
throw
new
Error
(
"
DOM element is required to create Iframe Gadget
"
+
throw
new
Error
(
"
DOM element is required to create Iframe Gadget
"
+
url
);
url
);
}
}
// Check if the element is attached to the DOM
// Check if the element is attached to the DOM
if
(
!
document
.
contains
(
o
ptions
.
element
))
{
if
(
!
document
.
contains
(
o
ld_
element
))
{
throw
new
Error
(
"
The parent element is not attached to the DOM for
"
+
throw
new
Error
(
"
The parent element is not attached to the DOM for
"
+
url
);
url
);
}
}
...
@@ -1206,86 +1701,103 @@ if (typeof document.contains !== 'function') {
...
@@ -1206,86 +1701,103 @@ if (typeof document.contains !== 'function') {
gadget_instance
=
new
RenderJSIframeGadget
();
gadget_instance
=
new
RenderJSIframeGadget
();
setAqParent
(
gadget_instance
,
parent_gadget
);
setAqParent
(
gadget_instance
,
parent_gadget
);
iframe
=
document
.
createElement
(
"
iframe
"
);
iframe
=
document
.
createElement
(
"
iframe
"
);
iframe
.
addEventListener
(
'
error
'
,
function
handleIframeError
(
error
)
{
iframe_loading_deferred
.
reject
(
error
);
});
iframe
.
addEventListener
(
'
load
'
,
function
handleIframeLoad
()
{
return
RSVP
.
timeout
(
5000
)
.
fail
(
function
triggerIframeTimeout
()
{
iframe_loading_deferred
.
reject
(
new
Error
(
'
Timeout while loading:
'
+
url
)
);
});
});
// gadget_instance.element.setAttribute("seamless", "seamless");
// gadget_instance.element.setAttribute("seamless", "seamless");
iframe
.
setAttribute
(
"
src
"
,
url
);
iframe
.
setAttribute
(
"
src
"
,
url
);
gadget_instance
.
__path
=
url
;
gadget_instance
.
__path
=
url
;
gadget_instance
.
__
element
=
options
.
element
;
gadget_instance
.
element
=
options
.
element
;
// Attach it to the DOM
gadget_instance
.
state
=
{};
options
.
element
.
appendChild
(
iframe
);
options
.
element
.
appendChild
(
iframe
);
clearGadgetInternalParameters
(
gadget_instance
);
// Add gadget to the DOM if needed
// Do it when all DOM modifications are done
old_element
.
parentNode
.
replaceChild
(
options
.
element
,
old_element
);
// XXX Manage unbind when deleting the gadget
// XXX Manage unbind when deleting the gadget
// Create the communication channel with the iframe
// Create the communication channel with the iframe
gadget_instance
.
__chan
=
Channel
.
build
({
gadget_instance
.
__chan
=
Channel
.
build
({
window
:
iframe
.
contentWindow
,
window
:
iframe
.
contentWindow
,
origin
:
"
*
"
,
// origin: (new URL(url, window.location)).origin,
origin
:
'
*
'
,
scope
:
"
renderJS
"
scope
:
"
renderJS
"
});
});
// Create new method from the declareMethod call inside the iframe
// Create new method from the declareMethod call inside the iframe
gadget_instance
.
__chan
.
bind
(
"
declareMethod
"
,
gadget_instance
.
__chan
.
bind
(
function
(
trans
,
method_name
)
{
"
declareMethod
"
,
gadget_instance
[
method_name
]
=
function
()
{
function
handleChannelDeclareMethod
(
trans
,
method_name
)
{
gadget_instance
[
method_name
]
=
function
triggerChannelDeclareMethod
()
{
var
argument_list
=
arguments
,
var
argument_list
=
arguments
,
wait_promise
=
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
wait_promise
=
new
RSVP
.
Promise
(
gadget_instance
.
__chan
.
call
({
function
handleChannelCall
(
resolve
,
reject
)
{
method
:
"
methodCall
"
,
gadget_instance
.
__chan
.
call
({
params
:
[
method
:
"
methodCall
"
,
method_name
,
params
:
[
Array
.
prototype
.
slice
.
call
(
argument_list
,
0
)],
method_name
,
success
:
function
(
s
)
{
Array
.
prototype
.
slice
.
call
(
argument_list
,
0
)],
resolve
(
s
);
success
:
resolve
,
},
error
:
reject
error
:
function
(
e
)
{
});
reject
(
e
);
}
}
);
});
});
return
ensurePushableQueue
(
function
waitForChannelCall
()
{
return
new
RSVP
.
Queue
()
return
wait_promise
;
.
push
(
function
()
{
});
return
wait_promise
;
});
};
};
return
"
OK
"
;
return
"
OK
"
;
});
}
);
// Wait for the iframe to be loaded before continuing
// Wait for the iframe to be loaded before continuing
gadget_instance
.
__chan
.
bind
(
"
ready
"
,
function
(
trans
)
{
gadget_instance
.
__chan
.
bind
(
"
ready
"
,
function
handleChannelReady
(
trans
)
{
iframe_loading_deferred
.
resolve
(
gadget_instance
);
iframe_loading_deferred
.
resolve
(
gadget_instance
);
return
"
OK
"
;
return
"
OK
"
;
});
});
gadget_instance
.
__chan
.
bind
(
"
failed
"
,
function
(
trans
,
params
)
{
gadget_instance
.
__chan
.
bind
(
"
failed
"
,
iframe_loading_deferred
.
reject
(
params
);
function
handleChannelFail
(
trans
,
params
)
{
return
"
OK
"
;
iframe_loading_deferred
.
reject
(
params
);
});
return
"
OK
"
;
gadget_instance
.
__chan
.
bind
(
"
acquire
"
,
function
(
trans
,
params
)
{
});
gadget_instance
.
__aq_parent
.
apply
(
gadget_instance
,
params
)
gadget_instance
.
__chan
.
bind
(
"
acquire
"
,
.
then
(
function
(
g
)
{
function
handleChannelAcquire
(
trans
,
params
)
{
trans
.
complete
(
g
);
new
RSVP
.
Queue
()
}).
fail
(
function
(
e
)
{
.
push
(
function
()
{
trans
.
error
(
e
.
toString
());
return
gadget_instance
.
__aq_parent
.
apply
(
gadget_instance
,
params
);
});
})
trans
.
delayReturn
(
true
);
.
then
(
trans
.
complete
)
});
.
fail
(
function
handleChannelAcquireError
(
e
)
{
trans
.
error
(
e
.
toString
());
});
trans
.
delayReturn
(
true
);
});
return
RSVP
.
any
([
return
iframe_loading_deferred
.
promise
;
iframe_loading_deferred
.
promise
,
// Timeout to prevent non renderJS embeddable gadget
// XXX Maybe using iframe.onload/onerror would be safer?
RSVP
.
timeout
(
5000
)
]);
}
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// privateDeclareDataUrlGadget
// privateDeclareDataUrlGadget
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
function
privateDeclareDataUrlGadget
(
url
,
options
,
parent_gadget
)
{
function
privateDeclareDataUrlGadget
(
url
,
options
,
parent_gadget
,
old_element
)
{
return
new
RSVP
.
Queue
()
return
new
RSVP
.
Queue
()
.
push
(
function
()
{
.
push
(
function
waitForDataUrlAjax
()
{
return
ajax
(
url
);
return
ajax
(
url
);
})
})
.
push
(
function
(
xhr
)
{
.
push
(
function
handleDataURLAjaxResponse
(
xhr
)
{
// Insert a "base" element, in order to resolve all relative links
// Insert a "base" element, in order to resolve all relative links
// which could get broken with a data url
// which could get broken with a data url
var
doc
=
(
new
DOMParser
()).
parseFromString
(
xhr
.
responseText
,
var
doc
=
(
new
DOMParser
()).
parseFromString
(
xhr
.
responseText
,
...
@@ -1298,20 +1810,63 @@ if (typeof document.contains !== 'function') {
...
@@ -1298,20 +1810,63 @@ if (typeof document.contains !== 'function') {
{
type
:
"
text/html;charset=UTF-8
"
});
{
type
:
"
text/html;charset=UTF-8
"
});
return
readBlobAsDataURL
(
blob
);
return
readBlobAsDataURL
(
blob
);
})
})
.
push
(
function
(
data_url
)
{
.
push
(
function
handleDataURL
(
data_url
)
{
return
privateDeclareIframeGadget
(
data_url
,
options
,
parent_gadget
);
return
privateDeclareIframeGadget
(
data_url
,
options
,
parent_gadget
,
old_element
);
});
});
}
}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// RenderJSGadget.declareGadget
// RenderJSGadget.declareGadget
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
function
setGadgetInstanceHTMLContext
(
gadget_instance
,
options
,
parent_gadget
,
url
,
old_element
,
scope
)
{
var
i
,
queue
;
function
ready_executable_wrapper
(
fct
)
{
return
function
executeReadyWrapper
()
{
return
fct
.
call
(
gadget_instance
,
gadget_instance
);
};
}
function
ready_wrapper
()
{
// Always set the parent reference when all ready are finished
// in case the gadget declaration is cancelled
// (and ready are not finished)
gadget_instance
.
element
.
_gadget
=
gadget_instance
;
parent_gadget
.
__sub_gadget_dict
[
scope
]
=
gadget_instance
;
if
(
document
.
contains
(
gadget_instance
.
element
))
{
startService
(
gadget_instance
);
}
// Always return the gadget instance after ready function
return
gadget_instance
;
}
if
(
gadget_instance
.
constructor
.
__ready_list
.
length
)
{
queue
=
new
RSVP
.
Queue
();
// Trigger calling of all ready callback
for
(
i
=
0
;
i
<
gadget_instance
.
constructor
.
__ready_list
.
length
;
i
+=
1
)
{
// Put a timeout?
queue
.
push
(
ready_executable_wrapper
(
gadget_instance
.
constructor
.
__ready_list
[
i
]
));
}
queue
.
push
(
ready_wrapper
);
return
queue
;
}
return
ready_wrapper
();
}
RenderJSGadget
RenderJSGadget
.
declareMethod
(
'
declareGadget
'
,
function
(
url
,
options
)
{
.
declareMethod
(
'
declareGadget
'
,
function
declareGadget
(
url
,
options
)
{
var
queue
,
var
parent_gadget
=
this
,
parent_gadget
=
this
,
method
,
local_loading_klass_promise
,
result
,
previous_loading_klass_promise
=
loading_klass_promise
;
scope
,
old_element
;
if
(
options
===
undefined
)
{
if
(
options
===
undefined
)
{
options
=
{};
options
=
{};
...
@@ -1319,99 +1874,75 @@ if (typeof document.contains !== 'function') {
...
@@ -1319,99 +1874,75 @@ if (typeof document.contains !== 'function') {
if
(
options
.
sandbox
===
undefined
)
{
if
(
options
.
sandbox
===
undefined
)
{
options
.
sandbox
=
"
public
"
;
options
.
sandbox
=
"
public
"
;
}
}
if
(
options
.
element
===
undefined
)
{
options
.
element
=
document
.
createElement
(
'
div
'
);
}
else
if
(
typeof
options
.
element
===
'
string
'
)
{
options
.
element
=
document
.
createElement
(
options
.
element
);
}
else
if
(
options
.
element
.
parentNode
)
{
old_element
=
options
.
element
;
// Clean up the element content
// Remove all existing event listener
options
.
element
=
old_element
.
cloneNode
(
false
);
}
else
{
throw
new
Error
(
'
No need to manually provide a DOM element
'
+
'
without a parentNode:
'
+
url
);
}
// transform url to absolute url if it is relative
// transform url to absolute url if it is relative
url
=
renderJS
.
getAbsoluteURL
(
url
,
this
.
__path
);
url
=
renderJS
.
getAbsoluteURL
(
url
,
this
.
__path
);
// Change the global variable to update the loading queue
loading_klass_promise
=
new
RSVP
.
Queue
()
// Wait for previous gadget loading to finish first
.
push
(
function
()
{
return
previous_loading_klass_promise
;
})
.
push
(
undefined
,
function
()
{
// Forget previous declareGadget error
return
;
})
.
push
(
function
()
{
var
method
;
if
(
options
.
sandbox
===
"
public
"
)
{
method
=
privateDeclarePublicGadget
;
}
else
if
(
options
.
sandbox
===
"
iframe
"
)
{
method
=
privateDeclareIframeGadget
;
}
else
if
(
options
.
sandbox
===
"
dataurl
"
)
{
method
=
privateDeclareDataUrlGadget
;
}
else
{
throw
new
Error
(
"
Unsupported sandbox options '
"
+
options
.
sandbox
+
"
'
"
);
}
return
method
(
url
,
options
,
parent_gadget
);
})
// Set the HTML context
.
push
(
function
(
gadget_instance
)
{
// Drop the current loading klass info used by selector
gadget_loading_klass
=
undefined
;
return
gadget_instance
;
})
.
push
(
undefined
,
function
(
e
)
{
// Drop the current loading klass info used by selector
// even in case of error
gadget_loading_klass
=
undefined
;
throw
e
;
});
local_loading_klass_promise
=
loading_klass_promise
;
queue
=
new
RSVP
.
Queue
()
.
push
(
function
()
{
return
local_loading_klass_promise
;
})
// Set the HTML context
.
push
(
function
(
gadget_instance
)
{
var
i
;
// Trigger calling of all ready callback
function
ready_wrapper
()
{
return
gadget_instance
;
}
for
(
i
=
0
;
i
<
gadget_instance
.
constructor
.
__ready_list
.
length
;
i
+=
1
)
{
// Put a timeout?
queue
.
push
(
gadget_instance
.
constructor
.
__ready_list
[
i
]);
// Always return the gadget instance after ready function
queue
.
push
(
ready_wrapper
);
}
// Store local reference to the gadget instance
// Store local reference to the gadget instance
if
(
options
.
scope
!==
undefined
)
{
scope
=
options
.
scope
;
parent_gadget
.
__sub_gadget_dict
[
options
.
scope
]
=
gadget_instance
;
if
(
scope
===
undefined
)
{
gadget_instance
.
__element
.
setAttribute
(
"
data-gadget-scope
"
,
scope
=
'
RJS_
'
+
scope_increment
;
options
.
scope
);
scope_increment
+=
1
;
}
while
(
parent_gadget
.
__sub_gadget_dict
.
hasOwnProperty
(
scope
))
{
scope
=
'
RJS_
'
+
scope_increment
;
// Put some attribute to ease page layout comprehension
scope_increment
+=
1
;
gadget_instance
.
__element
.
setAttribute
(
"
data-gadget-url
"
,
url
);
}
gadget_instance
.
__element
.
setAttribute
(
"
data-gadget-sandbox
"
,
}
options
.
sandbox
);
options
.
element
.
setAttribute
(
"
data-gadget-scope
"
,
scope
);
gadget_instance
.
__element
.
_gadget
=
gadget_instance
;
// Put some attribute to ease page layout comprehension
if
(
document
.
contains
(
gadget_instance
.
__element
))
{
options
.
element
.
setAttribute
(
"
data-gadget-url
"
,
url
);
// Put a timeout
options
.
element
.
setAttribute
(
"
data-gadget-sandbox
"
,
options
.
sandbox
);
queue
.
push
(
startService
);
}
if
(
options
.
sandbox
===
"
public
"
)
{
// Always return the gadget instance after ready function
method
=
privateDeclarePublicGadget
;
queue
.
push
(
ready_wrapper
);
}
else
if
(
options
.
sandbox
===
"
iframe
"
)
{
method
=
privateDeclareIframeGadget
;
return
gadget_instance
;
}
else
if
(
options
.
sandbox
===
"
dataurl
"
)
{
});
method
=
privateDeclareDataUrlGadget
;
return
queue
;
}
else
{
})
throw
new
Error
(
"
Unsupported sandbox options '
"
+
.
declareMethod
(
'
getDeclaredGadget
'
,
function
(
gadget_scope
)
{
options
.
sandbox
+
"
'
"
);
if
(
!
this
.
__sub_gadget_dict
.
hasOwnProperty
(
gadget_scope
))
{
throw
new
Error
(
"
Gadget scope '
"
+
gadget_scope
+
"
' is not known.
"
);
}
}
return
this
.
__sub_gadget_dict
[
gadget_scope
];
result
=
method
(
url
,
options
,
parent_gadget
,
old_element
);
// Set the HTML context
if
(
typeof
result
.
then
===
'
function
'
)
{
return
new
RSVP
.
Queue
(
result
)
.
push
(
function
setAsyncGadgetInstanceHTMLContext
(
gadget_instance
)
{
return
setGadgetInstanceHTMLContext
(
gadget_instance
,
options
,
parent_gadget
,
url
,
old_element
,
scope
);
});
}
return
setGadgetInstanceHTMLContext
(
result
,
options
,
parent_gadget
,
url
,
old_element
,
scope
);
})
})
.
declareMethod
(
'
dropGadget
'
,
function
(
gadget_scope
)
{
.
declareMethod
(
'
getDeclaredGadget
'
,
function
getDeclaredGadget
(
gadget_scope
)
{
if
(
!
this
.
__sub_gadget_dict
.
hasOwnProperty
(
gadget_scope
))
{
throw
new
ScopeError
(
"
Gadget scope '
"
+
gadget_scope
+
"
' is not known.
"
);
}
return
this
.
__sub_gadget_dict
[
gadget_scope
];
})
.
declareMethod
(
'
dropGadget
'
,
function
dropGadget
(
gadget_scope
)
{
if
(
!
this
.
__sub_gadget_dict
.
hasOwnProperty
(
gadget_scope
))
{
if
(
!
this
.
__sub_gadget_dict
.
hasOwnProperty
(
gadget_scope
))
{
throw
new
Error
(
"
Gadget scope '
"
+
gadget_scope
+
"
' is not known.
"
);
throw
new
ScopeError
(
"
Gadget scope '
"
+
gadget_scope
+
"
' is not known.
"
);
}
}
// http://perfectionkills.com/understanding-delete/
// http://perfectionkills.com/understanding-delete/
delete
this
.
__sub_gadget_dict
[
gadget_scope
];
delete
this
.
__sub_gadget_dict
[
gadget_scope
];
...
@@ -1420,12 +1951,12 @@ if (typeof document.contains !== 'function') {
...
@@ -1420,12 +1951,12 @@ if (typeof document.contains !== 'function') {
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS selector
// renderJS selector
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
=
function
(
selector
)
{
renderJS
=
function
getLoadingGadget
(
selector
)
{
var
result
;
var
result
;
if
(
selector
===
window
)
{
if
(
selector
===
window
)
{
// window is the 'this' value when loading a javascript file
// window is the 'this' value when loading a javascript file
// In this case, use the current loading gadget constructor
// In this case, use the current loading gadget constructor
result
=
gadget_loading_klass
;
result
=
gadget_loading_klass
_list
[
0
]
;
}
}
if
(
result
===
undefined
)
{
if
(
result
===
undefined
)
{
throw
new
Error
(
"
Unknown selector '
"
+
selector
+
"
'
"
);
throw
new
Error
(
"
Unknown selector '
"
+
selector
+
"
'
"
);
...
@@ -1436,7 +1967,7 @@ if (typeof document.contains !== 'function') {
...
@@ -1436,7 +1967,7 @@ if (typeof document.contains !== 'function') {
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS.AcquisitionError
// renderJS.AcquisitionError
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
.
AcquisitionError
=
function
(
message
)
{
renderJS
.
AcquisitionError
=
function
createAcquisitionError
(
message
)
{
this
.
name
=
"
AcquisitionError
"
;
this
.
name
=
"
AcquisitionError
"
;
if
((
message
!==
undefined
)
&&
(
typeof
message
!==
"
string
"
))
{
if
((
message
!==
undefined
)
&&
(
typeof
message
!==
"
string
"
))
{
throw
new
TypeError
(
'
You must pass a string.
'
);
throw
new
TypeError
(
'
You must pass a string.
'
);
...
@@ -1450,19 +1981,9 @@ if (typeof document.contains !== 'function') {
...
@@ -1450,19 +1981,9 @@ if (typeof document.contains !== 'function') {
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS.getAbsoluteURL
// renderJS.getAbsoluteURL
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
.
getAbsoluteURL
=
function
(
url
,
base_url
)
{
renderJS
.
getAbsoluteURL
=
function
getAbsoluteURL
(
url
,
base_url
)
{
var
doc
,
base
,
link
,
if
(
base_url
&&
url
)
{
html
=
"
<!doctype><html><head></head></html>
"
;
return
new
URL
(
url
,
base_url
).
href
;
if
(
url
&&
base_url
&&
!
isAbsoluteOrDataURL
.
test
(
url
))
{
doc
=
(
new
DOMParser
()).
parseFromString
(
html
,
'
text/html
'
);
base
=
doc
.
createElement
(
'
base
'
);
link
=
doc
.
createElement
(
'
link
'
);
doc
.
head
.
appendChild
(
base
);
doc
.
head
.
appendChild
(
link
);
base
.
href
=
base_url
;
link
.
href
=
url
;
return
link
.
href
;
}
}
return
url
;
return
url
;
};
};
...
@@ -1470,27 +1991,39 @@ if (typeof document.contains !== 'function') {
...
@@ -1470,27 +1991,39 @@ if (typeof document.contains !== 'function') {
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS.declareJS
// renderJS.declareJS
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
.
declareJS
=
function
(
url
)
{
renderJS
.
declareJS
=
function
declareJS
(
url
,
container
,
pop
)
{
// https://www.html5rocks.com/en/tutorials/speed/script-loading/
// Prevent infinite recursion if loading render.js
// Prevent infinite recursion if loading render.js
// more than once
// more than once
var
result
;
var
result
;
if
(
javascript_registration_dict
.
hasOwnProperty
(
url
))
{
if
(
javascript_registration_dict
.
hasOwnProperty
(
url
))
{
result
=
RSVP
.
resolve
();
result
=
RSVP
.
resolve
();
}
else
{
}
else
{
result
=
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
javascript_registration_dict
[
url
]
=
null
;
var
newScript
;
result
=
new
RSVP
.
Promise
(
newScript
=
document
.
createElement
(
'
script
'
);
function
waitForJSLoadEvent
(
resolve
,
reject
)
{
newScript
.
type
=
'
text/javascript
'
;
var
newScript
;
newScript
.
src
=
url
;
newScript
=
document
.
createElement
(
'
script
'
);
newScript
.
onload
=
function
()
{
newScript
.
async
=
false
;
javascript_registration_dict
[
url
]
=
null
;
newScript
.
type
=
'
text/javascript
'
;
resolve
();
newScript
.
onload
=
function
triggerJSLoaded
()
{
};
if
(
pop
===
true
)
{
newScript
.
onerror
=
function
(
e
)
{
// Drop the current loading klass info used by selector
reject
(
e
);
gadget_loading_klass_list
.
shift
();
};
}
document
.
head
.
appendChild
(
newScript
);
resolve
();
});
};
newScript
.
onerror
=
function
triggerJSNotLoaded
(
e
)
{
if
(
pop
===
true
)
{
// Drop the current loading klass info used by selector
gadget_loading_klass_list
.
shift
();
}
reject
(
e
);
};
newScript
.
src
=
url
;
container
.
appendChild
(
newScript
);
}
);
}
}
return
result
;
return
result
;
};
};
...
@@ -1498,7 +2031,7 @@ if (typeof document.contains !== 'function') {
...
@@ -1498,7 +2031,7 @@ if (typeof document.contains !== 'function') {
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS.declareCSS
// renderJS.declareCSS
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
.
declareCSS
=
function
(
url
)
{
renderJS
.
declareCSS
=
function
declareCSS
(
url
,
container
)
{
// https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js
// https://github.com/furf/jquery-getCSS/blob/master/jquery.getCSS.js
// No way to cleanly check if a css has been loaded
// No way to cleanly check if a css has been loaded
// So, always resolve the promise...
// So, always resolve the promise...
...
@@ -1507,20 +2040,18 @@ if (typeof document.contains !== 'function') {
...
@@ -1507,20 +2040,18 @@ if (typeof document.contains !== 'function') {
if
(
stylesheet_registration_dict
.
hasOwnProperty
(
url
))
{
if
(
stylesheet_registration_dict
.
hasOwnProperty
(
url
))
{
result
=
RSVP
.
resolve
();
result
=
RSVP
.
resolve
();
}
else
{
}
else
{
result
=
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
result
=
new
RSVP
.
Promise
(
function
waitForCSSLoadEvent
(
resolve
,
reject
)
{
var
link
;
var
link
;
link
=
document
.
createElement
(
'
link
'
);
link
=
document
.
createElement
(
'
link
'
);
link
.
rel
=
'
stylesheet
'
;
link
.
rel
=
'
stylesheet
'
;
link
.
type
=
'
text/css
'
;
link
.
type
=
'
text/css
'
;
link
.
href
=
url
;
link
.
href
=
url
;
link
.
onload
=
function
()
{
link
.
onload
=
function
triggerCSSLoaded
()
{
stylesheet_registration_dict
[
url
]
=
null
;
stylesheet_registration_dict
[
url
]
=
null
;
resolve
();
resolve
();
};
};
link
.
onerror
=
function
(
e
)
{
link
.
onerror
=
reject
;
reject
(
e
);
container
.
appendChild
(
link
);
};
document
.
head
.
appendChild
(
link
);
});
});
}
}
return
result
;
return
result
;
...
@@ -1529,77 +2060,146 @@ if (typeof document.contains !== 'function') {
...
@@ -1529,77 +2060,146 @@ if (typeof document.contains !== 'function') {
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS.declareGadgetKlass
// renderJS.declareGadgetKlass
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
.
declareGadgetKlass
=
function
(
url
)
{
var
result
;
function
parse
(
xhr
)
{
function
parse
(
xhr
,
url
)
{
var
tmp_constructor
,
var
tmp_constructor
,
key
,
key
,
parsed_html
;
parsed_html
;
if
(
!
gadget_model_dict
.
hasOwnProperty
(
url
))
{
// Class inheritance
// Class inheritance
tmp_constructor
=
function
createSuperKlass
()
{
tmp_constructor
=
function
()
{
RenderJSGadget
.
call
(
this
);
RenderJSGadget
.
call
(
this
);
};
};
tmp_constructor
.
__ready_list
=
[];
tmp_constructor
.
__ready_list
=
RenderJSGadget
.
__ready_list
.
slice
();
tmp_constructor
.
__service_list
=
RenderJSGadget
.
__service_list
.
slice
();
tmp_constructor
.
__service_list
=
RenderJSGadget
.
__service_list
.
slice
();
tmp_constructor
.
declareMethod
=
tmp_constructor
.
declareMethod
=
RenderJSGadget
.
declareMethod
;
RenderJSGadget
.
declareMethod
;
tmp_constructor
.
declareJob
=
tmp_constructor
.
declareAcquiredMethod
=
RenderJSGadget
.
declareJob
;
RenderJSGadget
.
declareAcquiredMethod
;
tmp_constructor
.
declareAcquiredMethod
=
tmp_constructor
.
allowPublicAcquisition
=
RenderJSGadget
.
declareAcquiredMethod
;
RenderJSGadget
.
allowPublicAcquisition
;
tmp_constructor
.
allowPublicAcquisition
=
tmp_constructor
.
ready
=
RenderJSGadget
.
allowPublicAcquisition
;
RenderJSGadget
.
ready
;
tmp_constructor
.
ready
=
tmp_constructor
.
declareService
=
RenderJSGadget
.
ready
;
RenderJSGadget
.
declareService
;
tmp_constructor
.
setState
=
tmp_constructor
.
prototype
=
new
RenderJSGadget
();
RenderJSGadget
.
setState
;
tmp_constructor
.
prototype
.
constructor
=
tmp_constructor
;
tmp_constructor
.
onStateChange
=
tmp_constructor
.
prototype
.
__path
=
url
;
RenderJSGadget
.
onStateChange
;
tmp_constructor
.
prototype
.
__acquired_method_dict
=
{};
tmp_constructor
.
declareService
=
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest
RenderJSGadget
.
declareService
;
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
tmp_constructor
.
onEvent
=
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
RenderJSGadget
.
onEvent
;
tmp_constructor
.
__template_element
=
tmp_constructor
.
onLoop
=
(
new
DOMParser
()).
parseFromString
(
xhr
.
responseText
,
"
text/html
"
);
RenderJSGadget
.
onLoop
;
parsed_html
=
renderJS
.
parseGadgetHTMLDocument
(
tmp_constructor
.
prototype
=
new
RenderJSGadget
();
tmp_constructor
.
__template_element
,
tmp_constructor
.
prototype
.
constructor
=
tmp_constructor
;
url
tmp_constructor
.
prototype
.
__path
=
url
;
);
tmp_constructor
.
prototype
.
__acquired_method_dict
=
{};
for
(
key
in
parsed_html
)
{
// https://developer.mozilla.org/en-US/docs/HTML_in_XMLHttpRequest
if
(
parsed_html
.
hasOwnProperty
(
key
))
{
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
tmp_constructor
.
prototype
[
'
__
'
+
key
]
=
parsed_html
[
key
];
// https://developer.mozilla.org/en-US/docs/Code_snippets/HTML_to_DOM
}
tmp_constructor
.
__template_element
=
}
(
new
DOMParser
()).
parseFromString
(
xhr
.
responseText
,
"
text/html
"
);
parsed_html
=
renderJS
.
parseGadgetHTMLDocument
(
gadget_model_dict
[
url
]
=
tmp_constructor
;
tmp_constructor
.
__template_element
,
url
,
true
);
for
(
key
in
parsed_html
)
{
if
(
parsed_html
.
hasOwnProperty
(
key
))
{
tmp_constructor
.
prototype
[
'
__
'
+
key
]
=
parsed_html
[
key
];
}
}
return
gadget_model_dict
[
url
];
}
}
// Check if there is a HTML declared subgadget
if
(
tmp_constructor
.
__template_element
.
querySelectorAll
(
'
[data-gadget-url]
'
).
length
)
{
tmp_constructor
.
__ready_list
.
push
(
loadSubGadgetDOMDeclaration
);
}
return
tmp_constructor
;
}
if
(
gadget_model_dict
.
hasOwnProperty
(
url
))
{
renderJS
.
declareGadgetKlass
=
function
declareGadgetKlass
(
url
)
{
var
tmp_constructor
,
defer
;
if
(
gadget_model_defer_dict
.
hasOwnProperty
(
url
))
{
// Return klass object if it already exists
// Return klass object if it already exists
result
=
RSVP
.
resolve
(
gadget_model_dict
[
url
]);
if
(
gadget_model_defer_dict
[
url
].
hasOwnProperty
(
'
defer_list
'
))
{
}
else
{
// Klass not yet loaded.
// Fetch the HTML page and parse it
// Add a new defer
result
=
new
RSVP
.
Queue
()
defer
=
RSVP
.
defer
();
.
push
(
function
()
{
gadget_model_defer_dict
[
url
].
defer_list
.
push
(
defer
);
return
ajax
(
url
);
return
defer
.
promise
;
})
}
.
push
(
function
(
xhr
)
{
if
(
gadget_model_defer_dict
[
url
].
is_resolved
)
{
return
parse
(
xhr
);
return
gadget_model_defer_dict
[
url
].
result
;
});
}
throw
gadget_model_defer_dict
[
url
].
result
;
}
}
return
result
;
gadget_model_defer_dict
[
url
]
=
{
defer_list
:
[]
};
// Fetch the HTML page and parse it
return
new
RSVP
.
Queue
()
.
push
(
function
waitForGadgetKlassAjax
()
{
return
ajax
(
url
);
})
.
push
(
function
handleGadgetKlassAjax
(
result
)
{
tmp_constructor
=
parse
(
result
,
url
);
var
fragment
=
document
.
createDocumentFragment
(),
promise_list
=
[],
i
,
js_list
=
tmp_constructor
.
prototype
.
__required_js_list
,
css_list
=
tmp_constructor
.
prototype
.
__required_css_list
;
// Load JS
if
(
js_list
.
length
)
{
gadget_loading_klass_list
.
push
(
tmp_constructor
);
for
(
i
=
0
;
i
<
js_list
.
length
-
1
;
i
+=
1
)
{
promise_list
.
push
(
renderJS
.
declareJS
(
js_list
[
i
],
fragment
));
}
promise_list
.
push
(
renderJS
.
declareJS
(
js_list
[
i
],
fragment
,
true
));
}
// Load CSS
for
(
i
=
0
;
i
<
css_list
.
length
;
i
+=
1
)
{
promise_list
.
push
(
renderJS
.
declareCSS
(
css_list
[
i
],
fragment
));
}
document
.
head
.
appendChild
(
fragment
);
return
RSVP
.
all
(
promise_list
);
})
.
push
(
function
handleGadgetKlassLoadingSuccess
()
{
var
i
,
len
=
gadget_model_defer_dict
[
url
].
defer_list
.
length
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
gadget_model_defer_dict
[
url
].
defer_list
[
i
].
resolve
(
tmp_constructor
);
}
delete
gadget_model_defer_dict
[
url
].
defer_list
;
gadget_model_defer_dict
[
url
].
result
=
tmp_constructor
;
gadget_model_defer_dict
[
url
].
is_resolved
=
true
;
return
tmp_constructor
;
})
.
push
(
undefined
,
function
handleGadgetKlassLoadingError
(
e
)
{
// Drop the current loading klass info used by selector
// even in case of error
var
i
,
len
=
gadget_model_defer_dict
[
url
].
defer_list
.
length
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
gadget_model_defer_dict
[
url
].
defer_list
[
i
].
reject
(
e
);
}
delete
gadget_model_defer_dict
[
url
].
defer_list
;
gadget_model_defer_dict
[
url
].
result
=
e
;
gadget_model_defer_dict
[
url
].
is_resolved
=
false
;
throw
e
;
});
};
};
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS.clearGadgetKlassList
// renderJS.clearGadgetKlassList
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// For test purpose only
// For test purpose only
renderJS
.
clearGadgetKlassList
=
function
()
{
renderJS
.
clearGadgetKlassList
=
function
clearGadgetKlassList
()
{
gadget_model_dict
=
{};
gadget_model_d
efer_d
ict
=
{};
javascript_registration_dict
=
{};
javascript_registration_dict
=
{};
stylesheet_registration_dict
=
{};
stylesheet_registration_dict
=
{};
};
};
...
@@ -1607,57 +2207,102 @@ if (typeof document.contains !== 'function') {
...
@@ -1607,57 +2207,102 @@ if (typeof document.contains !== 'function') {
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// renderJS.parseGadgetHTMLDocument
// renderJS.parseGadgetHTMLDocument
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
.
parseGadgetHTMLDocument
=
function
(
document_element
,
url
)
{
renderJS
.
parseGadgetHTMLDocument
=
var
settings
=
{
function
parseGadgetHTMLDocument
(
document_element
,
url
,
title
:
""
,
update_relative_url
)
{
interface_list
:
[],
var
settings
=
{
required_css_list
:
[],
title
:
""
,
required_js_list
:
[]
interface_list
:
[],
},
required_css_list
:
[],
i
,
required_js_list
:
[],
element
;
path
:
url
},
if
(
!
url
||
!
isAbsoluteOrDataURL
.
test
(
url
))
{
i
,
throw
new
Error
(
"
The url should be absolute:
"
+
url
);
element
,
}
element_list
,
j
,
if
(
document_element
.
nodeType
===
9
)
{
url_attribute_list
=
[
'
src
'
,
'
href
'
,
'
srcset
'
],
settings
.
title
=
document_element
.
title
;
url_attribute
,
base_found
=
false
;
if
(
document_element
.
head
!==
null
)
{
for
(
i
=
0
;
i
<
document_element
.
head
.
children
.
length
;
i
+=
1
)
{
if
(
!
url
||
!
isAbsoluteOrDataURL
.
test
(
url
))
{
element
=
document_element
.
head
.
children
[
i
];
throw
new
Error
(
"
The url should be absolute:
"
+
url
);
if
(
element
.
href
!==
null
)
{
}
// XXX Manage relative URL during extraction of URLs
// element.href returns absolute URL in firefox but "" in chrome;
if
(
update_relative_url
===
undefined
)
{
if
(
element
.
rel
===
"
stylesheet
"
)
{
update_relative_url
=
false
;
settings
.
required_css_list
.
push
(
}
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
"
href
"
),
url
)
);
if
(
document_element
.
nodeType
===
9
)
{
}
else
if
(
element
.
nodeName
===
"
SCRIPT
"
&&
settings
.
title
=
document_element
.
title
;
(
element
.
type
===
"
text/javascript
"
||
!
element
.
type
))
{
if
(
document_element
.
head
!==
null
)
{
settings
.
required_js_list
.
push
(
for
(
i
=
0
;
i
<
document_element
.
head
.
children
.
length
;
i
+=
1
)
{
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
"
src
"
),
url
)
element
=
document_element
.
head
.
children
[
i
];
);
if
(
element
.
href
!==
null
)
{
}
else
if
(
element
.
rel
===
// XXX Manage relative URL during extraction of URLs
"
http://www.renderjs.org/rel/interface
"
)
{
// element.href returns absolute URL in firefox but "" in chrome;
settings
.
interface_list
.
push
(
if
(
element
.
rel
===
"
stylesheet
"
)
{
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
"
href
"
),
url
)
settings
.
required_css_list
.
push
(
);
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
"
href
"
),
settings
.
path
)
);
}
else
if
(
element
.
nodeName
===
"
SCRIPT
"
&&
(
element
.
type
===
"
text/javascript
"
||
!
element
.
type
))
{
settings
.
required_js_list
.
push
(
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
"
src
"
),
settings
.
path
)
);
}
else
if
(
element
.
rel
===
"
http://www.renderjs.org/rel/interface
"
)
{
settings
.
interface_list
.
push
(
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
"
href
"
),
settings
.
path
)
);
}
else
if
((
element
.
nodeName
===
"
BASE
"
)
&&
!
base_found
&&
element
.
getAttribute
(
"
href
"
))
{
settings
.
path
=
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
"
href
"
),
settings
.
path
);
// Only use the first base element found
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base#Usage_notes
base_found
=
true
;
}
}
}
}
}
}
}
if
(
update_relative_url
&&
(
document_element
.
body
!==
null
))
{
// Resolve all relativeurl configure in the dom as absolute from
// the gadget url
for
(
j
=
0
;
j
<
url_attribute_list
.
length
;
j
+=
1
)
{
url_attribute
=
url_attribute_list
[
j
];
element_list
=
document_element
.
body
.
querySelectorAll
(
'
[
'
+
url_attribute
+
'
]
'
);
for
(
i
=
0
;
i
<
element_list
.
length
;
i
+=
1
)
{
element
=
element_list
[
i
];
element
.
setAttribute
(
url_attribute
,
renderJS
.
getAbsoluteURL
(
element
.
getAttribute
(
url_attribute
),
settings
.
path
));
}
}
}
}
else
{
throw
new
Error
(
"
The first parameter should be an HTMLDocument
"
);
}
}
}
else
{
return
settings
;
throw
new
Error
(
"
The first parameter should be an HTMLDocument
"
);
};
}
return
settings
;
};
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
// global
// global
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
renderJS
.
Mutex
=
Mutex
;
renderJS
.
ScopeError
=
ScopeError
;
window
.
rJS
=
window
.
renderJS
=
renderJS
;
window
.
rJS
=
window
.
renderJS
=
renderJS
;
window
.
__RenderJSGadget
=
RenderJSGadget
;
window
.
__RenderJSGadget
=
RenderJSGadget
;
window
.
__RenderJSEmbeddedGadget
=
RenderJSEmbeddedGadget
;
window
.
__RenderJSEmbeddedGadget
=
RenderJSEmbeddedGadget
;
...
@@ -1667,358 +2312,379 @@ if (typeof document.contains !== 'function') {
...
@@ -1667,358 +2312,379 @@ if (typeof document.contains !== 'function') {
// Bootstrap process. Register the self gadget.
// Bootstrap process. Register the self gadget.
///////////////////////////////////////////////////
///////////////////////////////////////////////////
function
bootstrap
()
{
// Detect when all JS dependencies have been loaded
var
url
=
removeHash
(
window
.
location
.
href
),
all_dependency_loaded_deferred
=
new
RSVP
.
defer
();
tmp_constructor
,
// Manually initializes the self gadget if the DOMContentLoaded event
// is triggered before everything was ready.
// (For instance, the HTML-tag for the self gadget gets inserted after
// page load)
renderJS
.
manualBootstrap
=
function
manualBootstrap
()
{
all_dependency_loaded_deferred
.
resolve
();
};
document
.
addEventListener
(
'
DOMContentLoaded
'
,
all_dependency_loaded_deferred
.
resolve
,
false
);
function
configureMutationObserver
(
TmpConstructor
,
url
,
root_gadget
)
{
// XXX HTML properties can only be set when the DOM is fully loaded
var
settings
=
renderJS
.
parseGadgetHTMLDocument
(
document
,
url
),
j
,
key
,
fragment
=
document
.
createDocumentFragment
();
for
(
key
in
settings
)
{
if
(
settings
.
hasOwnProperty
(
key
))
{
TmpConstructor
.
prototype
[
'
__
'
+
key
]
=
settings
[
key
];
}
}
TmpConstructor
.
__template_element
=
document
.
createElement
(
"
div
"
);
root_gadget
.
element
=
document
.
body
;
root_gadget
.
state
=
{};
for
(
j
=
0
;
j
<
root_gadget
.
element
.
childNodes
.
length
;
j
+=
1
)
{
fragment
.
appendChild
(
root_gadget
.
element
.
childNodes
[
j
].
cloneNode
(
true
)
);
}
TmpConstructor
.
__template_element
.
appendChild
(
fragment
);
return
RSVP
.
all
([
root_gadget
.
getRequiredJSList
(),
root_gadget
.
getRequiredCSSList
()])
.
then
(
function
handleRequireDependencyList
(
all_list
)
{
var
i
,
js_list
=
all_list
[
0
],
css_list
=
all_list
[
1
];
for
(
i
=
0
;
i
<
js_list
.
length
;
i
+=
1
)
{
javascript_registration_dict
[
js_list
[
i
]]
=
null
;
}
for
(
i
=
0
;
i
<
css_list
.
length
;
i
+=
1
)
{
stylesheet_registration_dict
[
css_list
[
i
]]
=
null
;
}
gadget_loading_klass_list
.
shift
();
}).
then
(
function
createMutationObserver
()
{
// select the target node
var
target
=
document
.
querySelector
(
'
body
'
),
// create an observer instance
observer
=
new
MutationObserver
(
function
observeMutatios
(
mutations
)
{
var
i
,
k
,
len
,
len2
,
node
,
added_list
;
mutations
.
forEach
(
function
observerMutation
(
mutation
)
{
if
(
mutation
.
type
===
'
childList
'
)
{
len
=
mutation
.
removedNodes
.
length
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
node
=
mutation
.
removedNodes
[
i
];
if
(
node
.
nodeType
===
Node
.
ELEMENT_NODE
)
{
if
(
node
.
hasAttribute
(
"
data-gadget-url
"
)
&&
(
node
.
_gadget
!==
undefined
))
{
deleteGadgetMonitor
(
node
.
_gadget
);
}
added_list
=
node
.
querySelectorAll
(
"
[data-gadget-url]
"
);
len2
=
added_list
.
length
;
for
(
k
=
0
;
k
<
len2
;
k
+=
1
)
{
node
=
added_list
[
k
];
if
(
node
.
_gadget
!==
undefined
)
{
deleteGadgetMonitor
(
node
.
_gadget
);
}
}
}
}
len
=
mutation
.
addedNodes
.
length
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
node
=
mutation
.
addedNodes
[
i
];
if
(
node
.
nodeType
===
Node
.
ELEMENT_NODE
)
{
if
(
node
.
hasAttribute
(
"
data-gadget-url
"
)
&&
(
node
.
_gadget
!==
undefined
))
{
if
(
document
.
contains
(
node
))
{
startService
(
node
.
_gadget
);
}
}
added_list
=
node
.
querySelectorAll
(
"
[data-gadget-url]
"
);
len2
=
added_list
.
length
;
for
(
k
=
0
;
k
<
len2
;
k
+=
1
)
{
node
=
added_list
[
k
];
if
(
document
.
contains
(
node
))
{
if
(
node
.
_gadget
!==
undefined
)
{
startService
(
node
.
_gadget
);
}
}
}
}
}
}
});
}),
// configuration of the observer:
config
=
{
childList
:
true
,
subtree
:
true
,
attributes
:
false
,
characterData
:
false
};
// pass in the target node, as well as the observer options
observer
.
observe
(
target
,
config
);
return
root_gadget
;
});
}
function
createLastAcquisitionGadget
()
{
var
last_acquisition_gadget
=
new
RenderJSGadget
();
last_acquisition_gadget
.
__acquired_method_dict
=
{
reportServiceError
:
function
reportServiceError
(
param_list
)
{
letsCrash
(
param_list
[
0
]);
}
};
// Stop acquisition on the last acquisition gadget
// Do not put this on the klass, as their could be multiple instances
last_acquisition_gadget
.
__aq_parent
=
function
__aq_parent
(
method_name
)
{
throw
new
renderJS
.
AcquisitionError
(
"
No gadget provides
"
+
method_name
);
};
return
last_acquisition_gadget
;
}
/*
function notifyAllMethodToParent() {
;
}
*/
function
createLoadingGadget
(
url
)
{
var
TmpConstructor
,
root_gadget
,
root_gadget
,
loading_gadget_promise
=
new
RSVP
.
Queue
(),
declare_method_count
=
0
,
embedded_channel
,
embedded_channel
,
notifyReady
,
notifyDeclareMethod
,
notifyDeclareMethod
,
gadget_ready
=
false
,
declare_method_list_waiting
,
iframe_top_gadget
,
loading_result
,
last_acquisition_gadget
;
channel_defer
,
real_result_list
;
// gadget_failed = false,
// connection_ready = false;
// Create the gadget class for the current url
// Create the gadget class for the current url
if
(
gadget_model_dict
.
hasOwnProperty
(
url
))
{
if
(
gadget_model_d
efer_d
ict
.
hasOwnProperty
(
url
))
{
throw
new
Error
(
"
bootstrap should not be called twice
"
);
throw
new
Error
(
"
bootstrap should not be called twice
"
);
}
}
loading_klass_promise
=
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
last_acquisition_gadget
=
new
RenderJSGadget
();
// Create the root gadget instance and put it in the loading stack
last_acquisition_gadget
.
__acquired_method_dict
=
{
TmpConstructor
=
RenderJSEmbeddedGadget
;
getTopURL
:
function
()
{
TmpConstructor
.
__ready_list
=
[];
return
url
;
TmpConstructor
.
__service_list
=
RenderJSGadget
.
__service_list
.
slice
();
},
TmpConstructor
.
prototype
.
__path
=
url
;
reportServiceError
:
function
(
param_list
)
{
root_gadget
=
new
TmpConstructor
();
letsCrash
(
param_list
[
0
]);
setAqParent
(
root_gadget
,
createLastAcquisitionGadget
());
declare_method_list_waiting
=
[
"
getInterfaceList
"
,
"
getRequiredCSSList
"
,
"
getRequiredJSList
"
,
"
getPath
"
,
"
getTitle
"
,
"
getMethodList
"
];
// Inform parent gadget about declareMethod calls here.
notifyDeclareMethod
=
function
notifyDeclareMethod
(
name
)
{
declare_method_list_waiting
.
push
(
name
);
};
real_result_list
=
[
TmpConstructor
,
root_gadget
,
embedded_channel
,
declare_method_list_waiting
];
if
(
window
.
self
===
window
.
top
)
{
loading_result
=
real_result_list
;
}
else
{
channel_defer
=
RSVP
.
defer
();
loading_result
=
RSVP
.
any
([
channel_defer
.
promise
,
new
RSVP
.
Queue
()
.
push
(
function
waitForParentChannelCreation
()
{
// Expect the channel to parent to be usable after 1 second
// If not, consider the gadget as the root
// Drop all iframe channel communication
return
RSVP
.
delay
(
1000
);
})
.
push
(
function
handleParentChannelCreation
()
{
real_result_list
[
2
]
=
undefined
;
return
real_result_list
;
})
]);
// Create the communication channel
embedded_channel
=
Channel
.
build
({
window
:
window
.
parent
,
origin
:
"
*
"
,
scope
:
"
renderJS
"
,
onReady
:
function
onChannelReady
()
{
var
k
,
len
;
// Channel is ready, so now declare all methods
notifyDeclareMethod
=
function
notifyDeclareMethod
(
name
)
{
declare_method_list_waiting
.
push
(
new
RSVP
.
Promise
(
function
promiseChannelDeclareMethodCall
(
resolve
,
reject
)
{
embedded_channel
.
call
({
method
:
"
declareMethod
"
,
params
:
name
,
success
:
resolve
,
error
:
reject
});
}
)
);
};
len
=
declare_method_list_waiting
.
length
;
for
(
k
=
0
;
k
<
len
;
k
+=
1
)
{
notifyDeclareMethod
(
declare_method_list_waiting
[
k
]);
}
channel_defer
.
resolve
(
real_result_list
);
}
}
};
});
// Stop acquisition on the last acquisition gadget
real_result_list
[
2
]
=
embedded_channel
;
// Do not put this on the klass, as their could be multiple instances
}
last_acquisition_gadget
.
__aq_parent
=
function
(
method_name
)
{
throw
new
renderJS
.
AcquisitionError
(
// Surcharge declareMethod to inform parent window
"
No gadget provides
"
+
method_name
TmpConstructor
.
declareMethod
=
function
declareMethod
(
name
,
callback
,
options
)
{
var
result
=
RenderJSGadget
.
declareMethod
.
apply
(
this
,
[
name
,
callback
,
options
]
);
);
};
notifyDeclareMethod
(
name
);
return
result
;
};
//we need to determine tmp_constructor's value before exit bootstrap
TmpConstructor
.
declareService
=
//because of function : renderJS
RenderJSGadget
.
declareService
;
//but since the channel checking is async,
TmpConstructor
.
declareJob
=
//we can't use code structure like:
RenderJSGadget
.
declareJob
;
// if channel communication is ok
TmpConstructor
.
onEvent
=
// tmp_constructor = RenderJSGadget
RenderJSGadget
.
onEvent
;
// else
TmpConstructor
.
onLoop
=
// tmp_constructor = RenderJSEmbeddedGadget
RenderJSGadget
.
onLoop
;
if
(
window
.
self
===
window
.
top
)
{
TmpConstructor
.
declareAcquiredMethod
=
// XXX Copy/Paste from declareGadgetKlass
RenderJSGadget
.
declareAcquiredMethod
;
tmp_constructor
=
function
()
{
TmpConstructor
.
allowPublicAcquisition
=
RenderJSGadget
.
call
(
this
);
RenderJSGadget
.
allowPublicAcquisition
;
};
tmp_constructor
.
declareMethod
=
RenderJSGadget
.
declareMethod
;
TmpConstructor
.
prototype
.
__acquired_method_dict
=
{};
tmp_constructor
.
declareAcquiredMethod
=
gadget_loading_klass_list
.
push
(
TmpConstructor
);
RenderJSGadget
.
declareAcquiredMethod
;
tmp_constructor
.
allowPublicAcquisition
=
return
loading_result
;
RenderJSGadget
.
allowPublicAcquisition
;
}
tmp_constructor
.
__ready_list
=
RenderJSGadget
.
__ready_list
.
slice
();
tmp_constructor
.
ready
=
RenderJSGadget
.
ready
;
tmp_constructor
.
__service_list
=
RenderJSGadget
.
__service_list
.
slice
();
tmp_constructor
.
declareService
=
RenderJSGadget
.
declareService
;
tmp_constructor
.
prototype
=
new
RenderJSGadget
();
tmp_constructor
.
prototype
.
constructor
=
tmp_constructor
;
tmp_constructor
.
prototype
.
__path
=
url
;
gadget_model_dict
[
url
]
=
tmp_constructor
;
// Create the root gadget instance and put it in the loading stack
root_gadget
=
new
gadget_model_dict
[
url
]();
setAqParent
(
root_gadget
,
last_acquisition_gadget
);
}
else
{
function
triggerReadyList
(
TmpConstructor
,
root_gadget
)
{
// Create the communication channel
// XXX Probably duplicated
embedded_channel
=
Channel
.
build
({
var
i
,
window
:
window
.
parent
,
ready_queue
=
new
RSVP
.
Queue
();
origin
:
"
*
"
,
scope
:
"
renderJS
"
});
// Create the root gadget instance and put it in the loading stack
tmp_constructor
=
RenderJSEmbeddedGadget
;
tmp_constructor
.
__ready_list
=
RenderJSGadget
.
__ready_list
.
slice
();
tmp_constructor
.
__service_list
=
RenderJSGadget
.
__service_list
.
slice
();
tmp_constructor
.
prototype
.
__path
=
url
;
root_gadget
=
new
RenderJSEmbeddedGadget
();
// Notify parent about gadget instanciation
notifyReady
=
function
()
{
if
((
declare_method_count
===
0
)
&&
(
gadget_ready
===
true
))
{
embedded_channel
.
notify
({
method
:
"
ready
"
});
}
};
// Inform parent gadget about declareMethod calls here.
function
ready_executable_wrapper
(
fct
)
{
notifyDeclareMethod
=
function
(
name
)
{
return
function
wrapReadyFunction
()
{
declare_method_count
+=
1
;
return
fct
.
call
(
root_gadget
,
root_gadget
);
embedded_channel
.
call
({
};
method
:
"
declareMethod
"
,
}
params
:
name
,
TmpConstructor
.
ready
(
function
startServiceInReady
()
{
success
:
function
()
{
return
startService
(
root_gadget
);
declare_method_count
-=
1
;
});
notifyReady
();
},
error
:
function
()
{
declare_method_count
-=
1
;
}
});
};
notifyDeclareMethod
(
"
getInterfaceList
"
);
for
(
i
=
0
;
i
<
TmpConstructor
.
__ready_list
.
length
;
i
+=
1
)
{
notifyDeclareMethod
(
"
getRequiredCSSList
"
);
// Put a timeout?
notifyDeclareMethod
(
"
getRequiredJSList
"
);
ready_queue
notifyDeclareMethod
(
"
getPath
"
);
.
push
(
ready_executable_wrapper
(
TmpConstructor
.
__ready_list
[
i
]));
notifyDeclareMethod
(
"
getTitle
"
);
}
return
ready_queue
;
// Surcharge declareMethod to inform parent window
}
tmp_constructor
.
declareMethod
=
function
(
name
,
callback
)
{
var
result
=
RenderJSGadget
.
declareMethod
.
apply
(
this
,
[
name
,
callback
]
);
notifyDeclareMethod
(
name
);
return
result
;
};
tmp_constructor
.
declareService
=
function
finishAqParentConfiguration
(
TmpConstructor
,
root_gadget
,
RenderJSGadget
.
declareService
;
embedded_channel
)
{
tmp_constructor
.
declareAcquiredMethod
=
// Define __aq_parent to inform parent window
RenderJSGadget
.
declareAcquiredMethod
;
root_gadget
.
__aq_parent
=
tmp_constructor
.
allowPublicAcquisition
=
TmpConstructor
.
prototype
.
__aq_parent
=
function
aq_parent
(
method_name
,
RenderJSGadget
.
allowPublicAcquisition
;
argument_list
,
time_out
)
{
//Default: Define __aq_parent to inform parent window
return
new
RSVP
.
Promise
(
tmp_constructor
.
prototype
.
__aq_parent
=
function
(
method_name
,
function
waitForChannelAcquire
(
resolve
,
reject
)
{
argument_list
,
time_out
)
{
return
new
RSVP
.
Promise
(
function
(
resolve
,
reject
)
{
embedded_channel
.
call
({
embedded_channel
.
call
({
method
:
"
acquire
"
,
method
:
"
acquire
"
,
params
:
[
params
:
[
method_name
,
method_name
,
argument_list
argument_list
],
],
success
:
function
(
s
)
{
success
:
resolve
,
resolve
(
s
);
error
:
reject
,
},
error
:
function
(
e
)
{
reject
(
e
);
},
timeout
:
time_out
timeout
:
time_out
});
});
});
};
}
tmp_constructor
.
prototype
.
__acquired_method_dict
=
{};
gadget_loading_klass
=
tmp_constructor
;
function
init
()
{
// XXX HTML properties can only be set when the DOM is fully loaded
var
settings
=
renderJS
.
parseGadgetHTMLDocument
(
document
,
url
),
j
,
key
;
for
(
key
in
settings
)
{
if
(
settings
.
hasOwnProperty
(
key
))
{
tmp_constructor
.
prototype
[
'
__
'
+
key
]
=
settings
[
key
];
}
}
}
);
tmp_constructor
.
__template_element
=
document
.
createElement
(
"
div
"
);
};
root_gadget
.
__element
=
document
.
body
;
for
(
j
=
0
;
j
<
root_gadget
.
__element
.
childNodes
.
length
;
j
+=
1
)
{
tmp_constructor
.
__template_element
.
appendChild
(
root_gadget
.
__element
.
childNodes
[
j
].
cloneNode
(
true
)
);
}
RSVP
.
all
([
root_gadget
.
getRequiredJSList
(),
root_gadget
.
getRequiredCSSList
()])
.
then
(
function
(
all_list
)
{
var
i
,
js_list
=
all_list
[
0
],
css_list
=
all_list
[
1
];
for
(
i
=
0
;
i
<
js_list
.
length
;
i
+=
1
)
{
javascript_registration_dict
[
js_list
[
i
]]
=
null
;
}
for
(
i
=
0
;
i
<
css_list
.
length
;
i
+=
1
)
{
stylesheet_registration_dict
[
css_list
[
i
]]
=
null
;
}
gadget_loading_klass
=
undefined
;
}).
then
(
function
()
{
// select the target node
var
target
=
document
.
querySelector
(
'
body
'
),
// create an observer instance
observer
=
new
MutationObserver
(
function
(
mutations
)
{
var
i
,
k
,
len
,
len2
,
node
,
added_list
;
mutations
.
forEach
(
function
(
mutation
)
{
if
(
mutation
.
type
===
'
childList
'
)
{
len
=
mutation
.
removedNodes
.
length
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
node
=
mutation
.
removedNodes
[
i
];
if
(
node
.
nodeType
===
Node
.
ELEMENT_NODE
)
{
if
(
node
.
hasAttribute
(
"
data-gadget-url
"
)
&&
(
node
.
_gadget
!==
undefined
))
{
createMonitor
(
node
.
_gadget
);
}
added_list
=
node
.
querySelectorAll
(
"
[data-gadget-url]
"
);
len2
=
added_list
.
length
;
for
(
k
=
0
;
k
<
len2
;
k
+=
1
)
{
node
=
added_list
[
k
];
if
(
node
.
_gadget
!==
undefined
)
{
createMonitor
(
node
.
_gadget
);
}
}
}
}
len
=
mutation
.
addedNodes
.
length
;
for
(
i
=
0
;
i
<
len
;
i
+=
1
)
{
node
=
mutation
.
addedNodes
[
i
];
if
(
node
.
nodeType
===
Node
.
ELEMENT_NODE
)
{
if
(
node
.
hasAttribute
(
"
data-gadget-url
"
)
&&
(
node
.
_gadget
!==
undefined
))
{
if
(
document
.
contains
(
node
))
{
startService
(
node
.
_gadget
);
}
}
added_list
=
node
.
querySelectorAll
(
"
[data-gadget-url]
"
);
len2
=
added_list
.
length
;
for
(
k
=
0
;
k
<
len2
;
k
+=
1
)
{
node
=
added_list
[
k
];
if
(
document
.
contains
(
node
))
{
if
(
node
.
_gadget
!==
undefined
)
{
startService
(
node
.
_gadget
);
}
}
}
}
}
}
// bind calls to renderJS method on the instance
});
embedded_channel
.
bind
(
"
methodCall
"
,
function
methodCall
(
trans
,
v
)
{
}),
root_gadget
[
v
[
0
]].
apply
(
root_gadget
,
v
[
1
])
// configuration of the observer:
.
push
(
trans
.
complete
,
config
=
{
function
handleMethodCallError
(
e
)
{
childList
:
true
,
trans
.
error
(
e
.
toString
());
subtree
:
true
,
attributes
:
false
,
characterData
:
false
};
// pass in the target node, as well as the observer options
observer
.
observe
(
target
,
config
);
return
root_gadget
;
}).
then
(
resolve
,
function
(
e
)
{
reject
(
e
);
console
.
error
(
e
);
throw
e
;
});
});
}
trans
.
delayReturn
(
true
);
document
.
addEventListener
(
'
DOMContentLoaded
'
,
init
,
false
);
});
});
}
loading_gadget_promise
function
bootstrap
(
url
)
{
.
push
(
function
()
{
// Create the loading gadget
return
loading_klass_promise
;
var
wait_for_gadget_loaded
=
createLoadingGadget
(
url
),
TmpConstructor
,
root_gadget
,
embedded_channel
,
declare_method_list_waiting
;
// Wait for the loading gadget to be created
return
new
RSVP
.
Queue
(
wait_for_gadget_loaded
)
.
push
(
function
handleLoadingGadget
(
result_list
)
{
TmpConstructor
=
result_list
[
0
];
root_gadget
=
result_list
[
1
];
embedded_channel
=
result_list
[
2
];
declare_method_list_waiting
=
result_list
[
3
];
// Wait for all the gadget dependencies to be loaded
return
all_dependency_loaded_deferred
.
promise
;
})
})
.
push
(
function
(
root_gadget
)
{
.
push
(
function
waitForDeclareMethodList
()
{
var
i
;
// Wait for all methods to be correctly declared
return
RSVP
.
all
(
declare_method_list_waiting
);
function
ready_wrapper
()
{
})
return
root_gadget
;
.
push
(
function
waitForMutationObserver
(
result_list
)
{
if
(
embedded_channel
!==
undefined
)
{
finishAqParentConfiguration
(
TmpConstructor
,
root_gadget
,
embedded_channel
);
}
}
// Check all DOM modifications to correctly start/stop services
if
(
window
.
top
!==
window
.
self
)
{
return
configureMutationObserver
(
TmpConstructor
,
url
,
root_gadget
);
//checking channel should be done before sub gadget's declaration
})
//__ready_list:
.
push
(
function
waitForReadyList
()
{
//0: clearGadgetInternalParameters
clearGadgetInternalParameters
(
root_gadget
);
//1: loadSubGadgetDOMDeclaration
TmpConstructor
.
__ready_list
.
unshift
(
loadSubGadgetDOMDeclaration
);
//.....
// Trigger all ready functions
tmp_constructor
.
__ready_list
.
splice
(
1
,
0
,
function
()
{
return
triggerReadyList
(
TmpConstructor
,
root_gadget
);
return
root_gadget
.
__aq_parent
(
'
getTopURL
'
,
[],
100
)
})
.
then
(
function
(
topURL
)
{
.
push
(
function
notifyReady
()
{
var
base
=
document
.
createElement
(
'
base
'
);
if
(
embedded_channel
!==
undefined
)
{
base
.
href
=
topURL
;
embedded_channel
.
notify
({
method
:
"
ready
"
});
base
.
target
=
"
_top
"
;
document
.
head
.
appendChild
(
base
);
//the channel is ok
//so bind calls to renderJS method on the instance
embedded_channel
.
bind
(
"
methodCall
"
,
function
(
trans
,
v
)
{
root_gadget
[
v
[
0
]].
apply
(
root_gadget
,
v
[
1
])
.
then
(
function
(
g
)
{
trans
.
complete
(
g
);
}).
fail
(
function
(
e
)
{
trans
.
error
(
e
.
toString
());
});
trans
.
delayReturn
(
true
);
});
})
.
fail
(
function
(
error
)
{
if
(
error
===
"
timeout_error
"
)
{
//the channel fail
//we consider current gadget is parent gadget
//redifine last acquisition gadget
iframe_top_gadget
=
true
;
setAqParent
(
root_gadget
,
last_acquisition_gadget
);
}
else
{
throw
error
;
}
});
});
}
}
})
tmp_constructor
.
ready
(
function
(
g
)
{
.
push
(
undefined
,
function
handleBootstrapError
(
e
)
{
return
startService
(
g
);
letsCrash
(
e
);
});
if
(
embedded_channel
!==
undefined
)
{
embedded_channel
.
notify
({
method
:
"
failed
"
,
params
:
e
.
toString
()});
loading_gadget_promise
.
push
(
ready_wrapper
);
for
(
i
=
0
;
i
<
tmp_constructor
.
__ready_list
.
length
;
i
+=
1
)
{
// Put a timeout?
loading_gadget_promise
.
push
(
tmp_constructor
.
__ready_list
[
i
])
// Always return the gadget instance after ready function
.
push
(
ready_wrapper
);
}
}
throw
e
;
});
});
if
(
window
.
self
===
window
.
top
)
{
loading_gadget_promise
.
fail
(
function
(
e
)
{
letsCrash
(
e
);
throw
e
;
});
}
else
{
// Inform parent window that gadget is correctly loaded
loading_gadget_promise
.
then
(
function
()
{
gadget_ready
=
true
;
notifyReady
();
})
.
fail
(
function
(
e
)
{
//top gadget in iframe
if
(
iframe_top_gadget
)
{
letsCrash
(
e
);
}
else
{
embedded_channel
.
notify
({
method
:
"
failed
"
,
params
:
e
.
toString
()});
}
throw
e
;
});
}
}
}
bootstrap
();
bootstrap
(
removeHash
(
window
.
location
.
href
)
);
}(
document
,
window
,
RSVP
,
DOMParser
,
Channel
,
MutationObserver
,
Node
,
}(
document
,
window
,
RSVP
,
DOMParser
,
Channel
,
MutationObserver
,
Node
,
FileReader
,
Blob
));
FileReader
,
Blob
,
navigator
,
Event
,
URL
));
\ No newline at end of file
\ No newline at end of file
lib/rsvp.js
View file @
a1ab9293
...
@@ -60,7 +60,7 @@ define("rsvp/all",
...
@@ -60,7 +60,7 @@ define("rsvp/all",
}
}
}
}
return
new
Promise
(
function
(
resolve
,
reject
,
notify
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
var
results
=
[],
remaining
=
promises
.
length
,
var
results
=
[],
remaining
=
promises
.
length
,
promise
,
remaining_count
=
promises
.
length
-
expected_count
;
promise
,
remaining_count
=
promises
.
length
-
expected_count
;
...
@@ -90,12 +90,6 @@ define("rsvp/all",
...
@@ -90,12 +90,6 @@ define("rsvp/all",
}
}
}
}
function
notifier
(
index
)
{
return
function
(
value
)
{
notify
({
"
index
"
:
index
,
"
value
"
:
value
});
};
}
function
cancelAll
(
rejectionValue
)
{
function
cancelAll
(
rejectionValue
)
{
reject
(
rejectionValue
);
reject
(
rejectionValue
);
canceller
();
canceller
();
...
@@ -105,7 +99,7 @@ define("rsvp/all",
...
@@ -105,7 +99,7 @@ define("rsvp/all",
promise
=
promises
[
i
];
promise
=
promises
[
i
];
if
(
promise
&&
typeof
promise
.
then
===
'
function
'
)
{
if
(
promise
&&
typeof
promise
.
then
===
'
function
'
)
{
promise
.
then
(
resolver
(
i
),
cancelAll
,
notifier
(
i
)
);
promise
.
then
(
resolver
(
i
),
cancelAll
);
}
else
{
}
else
{
resolveAll
(
i
,
promise
);
resolveAll
(
i
,
promise
);
}
}
...
@@ -135,6 +129,29 @@ define("rsvp/async",
...
@@ -135,6 +129,29 @@ define("rsvp/async",
var
async
;
var
async
;
var
local
=
(
typeof
global
!==
'
undefined
'
)
?
global
:
this
;
var
local
=
(
typeof
global
!==
'
undefined
'
)
?
global
:
this
;
function
checkNativePromise
()
{
if
(
typeof
Promise
===
"
function
"
&&
typeof
Promise
.
resolve
===
"
function
"
)
{
try
{
/* global Promise */
var
promise
=
new
Promise
(
function
(){});
if
({}.
toString
.
call
(
promise
)
===
"
[object Promise]
"
)
{
return
true
;
}
}
catch
(
e
)
{}
}
return
false
;
}
function
useNativePromise
()
{
var
nativePromise
=
Promise
.
resolve
();
return
function
(
callback
,
arg
)
{
nativePromise
.
then
(
function
()
{
callback
(
arg
);
});
};
}
// old node
// old node
function
useNextTick
()
{
function
useNextTick
()
{
return
function
(
callback
,
arg
)
{
return
function
(
callback
,
arg
)
{
...
@@ -190,7 +207,9 @@ define("rsvp/async",
...
@@ -190,7 +207,9 @@ define("rsvp/async",
};
};
}
}
if
(
typeof
setImmediate
===
'
function
'
)
{
if
(
checkNativePromise
())
{
async
=
useNativePromise
();
}
else
if
(
typeof
setImmediate
===
'
function
'
)
{
async
=
useSetImmediate
();
async
=
useSetImmediate
();
}
else
if
(
typeof
process
!==
'
undefined
'
&&
{}.
toString
.
call
(
process
)
===
'
[object process]
'
)
{
}
else
if
(
typeof
process
!==
'
undefined
'
&&
{}.
toString
.
call
(
process
)
===
'
[object process]
'
)
{
async
=
useNextTick
();
async
=
useNextTick
();
...
@@ -360,10 +379,10 @@ define("rsvp/events",
...
@@ -360,10 +379,10 @@ define("rsvp/events",
__exports__
.
EventTarget
=
EventTarget
;
__exports__
.
EventTarget
=
EventTarget
;
});
});
define
(
"
rsvp/hash
"
,
define
(
"
rsvp/hash
"
,
[
"
rsvp/
defer
"
,
"
exports
"
],
[
"
rsvp/
promise
"
,
"
exports
"
],
function
(
__dependency1__
,
__exports__
)
{
function
(
__dependency1__
,
__exports__
)
{
"
use strict
"
;
"
use strict
"
;
var
defer
=
__dependency1__
.
defer
;
var
Promise
=
__dependency1__
.
Promise
;
function
size
(
object
)
{
function
size
(
object
)
{
var
s
=
0
;
var
s
=
0
;
...
@@ -376,38 +395,61 @@ define("rsvp/hash",
...
@@ -376,38 +395,61 @@ define("rsvp/hash",
}
}
function
hash
(
promises
)
{
function
hash
(
promises
)
{
var
results
=
{},
deferred
=
defer
(),
remaining
=
size
(
promises
);
if
(
remaining
===
0
)
{
function
canceller
()
{
deferred
.
resolve
({});
var
promise
,
key
;
for
(
key
in
promises
)
{
if
(
promises
.
hasOwnProperty
(
key
))
{
promise
=
promises
[
key
];
if
(
promise
&&
typeof
promise
.
then
===
'
function
'
&&
typeof
promise
.
cancel
===
'
function
'
)
{
promise
.
cancel
();
}
}
}
}
}
var
resolver
=
function
(
prop
)
{
return
new
Promise
(
function
(
resolve
,
reject
)
{
return
function
(
value
)
{
var
results
=
{},
remaining
=
size
(
promises
),
resolveAll
(
prop
,
value
);
promise
;
};
};
var
resolveAll
=
function
(
prop
,
value
)
{
if
(
remaining
===
0
)
{
results
[
prop
]
=
value
;
resolve
(
results
);
if
(
--
remaining
===
0
)
{
deferred
.
resolve
(
results
);
}
}
};
var
rejectAll
=
function
(
error
)
{
function
resolver
(
key
)
{
deferred
.
reject
(
error
);
return
function
(
value
)
{
};
resolveAll
(
key
,
value
);
};
}
for
(
var
prop
in
promises
)
{
function
resolveAll
(
key
,
value
)
{
if
(
promises
[
prop
]
&&
typeof
promises
[
prop
].
then
===
'
function
'
)
{
results
[
key
]
=
value
;
promises
[
prop
].
then
(
resolver
(
prop
),
rejectAll
);
if
(
--
remaining
===
0
)
{
}
else
{
resolve
(
results
);
resolveAll
(
prop
,
promises
[
prop
]);
}
}
function
cancelAll
(
rejectionValue
)
{
reject
(
rejectionValue
);
canceller
();
}
for
(
var
prop
in
promises
)
{
promise
=
promises
[
prop
];
if
(
promise
&&
typeof
promise
.
then
===
'
function
'
)
{
promise
.
then
(
resolver
(
prop
),
cancelAll
);
}
else
{
resolveAll
(
prop
,
promise
);
}
}
}
}
return
deferred
.
promise
;
},
canceller
);
}
}
...
@@ -504,11 +546,6 @@ define("rsvp/promise",
...
@@ -504,11 +546,6 @@ define("rsvp/promise",
reject
(
promise
,
value
);
reject
(
promise
,
value
);
};
};
var
notifyPromise
=
function
(
value
)
{
if
(
resolved
)
{
return
;
}
notify
(
promise
,
value
);
};
this
.
on
(
'
promise:failed
'
,
function
(
event
)
{
this
.
on
(
'
promise:failed
'
,
function
(
event
)
{
this
.
trigger
(
'
error
'
,
{
detail
:
event
.
detail
});
this
.
trigger
(
'
error
'
,
{
detail
:
event
.
detail
});
},
this
);
},
this
);
...
@@ -519,6 +556,7 @@ define("rsvp/promise",
...
@@ -519,6 +556,7 @@ define("rsvp/promise",
// For now, simply reject the promise and does not propagate the cancel
// For now, simply reject the promise and does not propagate the cancel
// to parent or children
// to parent or children
if
(
resolved
)
{
return
;
}
if
(
resolved
)
{
return
;
}
promise
.
isCancelled
=
true
;
if
(
canceller
!==
undefined
)
{
if
(
canceller
!==
undefined
)
{
try
{
try
{
canceller
();
canceller
();
...
@@ -532,7 +570,7 @@ define("rsvp/promise",
...
@@ -532,7 +570,7 @@ define("rsvp/promise",
};
};
try
{
try
{
resolver
(
resolvePromise
,
rejectPromise
,
notifyPromise
);
resolver
(
resolvePromise
,
rejectPromise
);
}
catch
(
e
)
{
}
catch
(
e
)
{
rejectPromise
(
e
);
rejectPromise
(
e
);
}
}
...
@@ -550,6 +588,7 @@ define("rsvp/promise",
...
@@ -550,6 +588,7 @@ define("rsvp/promise",
if
(
promise
.
isFulfilled
)
{
return
;
}
if
(
promise
.
isFulfilled
)
{
return
;
}
if
(
promise
.
isRejected
)
{
return
;
}
if
(
promise
.
isRejected
)
{
return
;
}
if
(
promise
.
isCancelled
)
{
return
;
}
if
(
hasCallback
)
{
if
(
hasCallback
)
{
try
{
try
{
...
@@ -577,31 +616,16 @@ define("rsvp/promise",
...
@@ -577,31 +616,16 @@ define("rsvp/promise",
}
}
};
};
var
invokeNotifyCallback
=
function
(
promise
,
callback
,
event
)
{
var
value
;
if
(
typeof
callback
===
'
function
'
)
{
try
{
value
=
callback
(
event
.
detail
);
}
catch
(
e
)
{
// stop propagating
return
;
}
notify
(
promise
,
value
);
}
else
{
notify
(
promise
,
event
.
detail
);
}
};
Promise
.
prototype
=
{
Promise
.
prototype
=
{
constructor
:
Promise
,
constructor
:
Promise
,
isCancelled
:
undefined
,
isRejected
:
undefined
,
isRejected
:
undefined
,
isFulfilled
:
undefined
,
isFulfilled
:
undefined
,
rejectedReason
:
undefined
,
rejectedReason
:
undefined
,
fulfillmentValue
:
undefined
,
fulfillmentValue
:
undefined
,
then
:
function
(
done
,
fail
,
progress
)
{
then
:
function
(
done
,
fail
)
{
this
.
off
(
'
error
'
,
onerror
);
this
.
off
(
'
error
'
,
onerror
);
var
thenPromise
=
new
this
.
constructor
(
function
()
{},
var
thenPromise
=
new
this
.
constructor
(
function
()
{},
...
@@ -629,10 +653,6 @@ define("rsvp/promise",
...
@@ -629,10 +653,6 @@ define("rsvp/promise",
invokeCallback
(
'
reject
'
,
thenPromise
,
fail
,
event
);
invokeCallback
(
'
reject
'
,
thenPromise
,
fail
,
event
);
});
});
this
.
on
(
'
promise:notified
'
,
function
(
event
)
{
invokeNotifyCallback
(
thenPromise
,
progress
,
event
);
});
return
thenPromise
;
return
thenPromise
;
},
},
...
@@ -720,21 +740,15 @@ define("rsvp/promise",
...
@@ -720,21 +740,15 @@ define("rsvp/promise",
});
});
}
}
function
notify
(
promise
,
value
)
{
config
.
async
(
function
()
{
promise
.
trigger
(
'
promise:notified
'
,
{
detail
:
value
});
});
}
__exports__
.
Promise
=
Promise
;
__exports__
.
Promise
=
Promise
;
});
});
define
(
"
rsvp/queue
"
,
define
(
"
rsvp/queue
"
,
[
"
rsvp/promise
"
,
"
rsvp/
timeout
"
,
"
exports
"
],
[
"
rsvp/promise
"
,
"
rsvp/
resolve
"
,
"
exports
"
],
function
(
__dependency1__
,
__dependency2__
,
__exports__
)
{
function
(
__dependency1__
,
__dependency2__
,
__exports__
)
{
"
use strict
"
;
"
use strict
"
;
var
Promise
=
__dependency1__
.
Promise
;
var
Promise
=
__dependency1__
.
Promise
;
var
delay
=
__dependency2__
.
delay
;
var
resolve
=
__dependency2__
.
resolve
;
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
function
ResolvedQueueError
(
message
)
{
function
ResolvedQueueError
(
message
)
{
...
@@ -747,7 +761,7 @@ define("rsvp/queue",
...
@@ -747,7 +761,7 @@ define("rsvp/queue",
ResolvedQueueError
.
prototype
=
new
Error
();
ResolvedQueueError
.
prototype
=
new
Error
();
ResolvedQueueError
.
prototype
.
constructor
=
ResolvedQueueError
;
ResolvedQueueError
.
prototype
.
constructor
=
ResolvedQueueError
;
var
Queue
=
function
()
{
var
Queue
=
function
(
thenable
)
{
var
queue
=
this
,
var
queue
=
this
,
promise_list
=
[],
promise_list
=
[],
promise
,
promise
,
...
@@ -760,11 +774,31 @@ define("rsvp/queue",
...
@@ -760,11 +774,31 @@ define("rsvp/queue",
}
}
function
canceller
()
{
function
canceller
()
{
for
(
var
i
=
0
;
i
<
2
;
i
++
)
{
for
(
var
i
=
promise_list
.
length
;
i
>
0
;
i
--
)
{
promise_list
[
i
].
cancel
();
promise_list
[
i
-
1
].
cancel
();
}
}
}
}
function
checkPromise
(
next_promise
)
{
promise_list
.
push
(
next_promise
);
// Handle pop
promise_list
.
push
(
next_promise
.
then
(
function
(
fulfillmentValue
)
{
promise_list
.
splice
(
0
,
2
);
if
(
promise_list
.
length
===
0
)
{
fulfill
(
fulfillmentValue
);
}
else
{
return
fulfillmentValue
;
}
},
function
(
rejectedReason
)
{
promise_list
.
splice
(
0
,
2
);
if
(
promise_list
.
length
===
0
)
{
reject
(
rejectedReason
);
}
else
{
throw
rejectedReason
;
}
}));
}
promise
=
new
Promise
(
function
(
done
,
fail
)
{
promise
=
new
Promise
(
function
(
done
,
fail
)
{
fulfill
=
function
(
fulfillmentValue
)
{
fulfill
=
function
(
fulfillmentValue
)
{
if
(
resolved
)
{
return
;}
if
(
resolved
)
{
return
;}
...
@@ -782,13 +816,7 @@ define("rsvp/queue",
...
@@ -782,13 +816,7 @@ define("rsvp/queue",
};
};
},
canceller
);
},
canceller
);
promise_list
.
push
(
delay
());
checkPromise
(
resolve
(
thenable
));
promise_list
.
push
(
promise_list
[
0
].
then
(
function
()
{
promise_list
.
splice
(
0
,
2
);
if
(
promise_list
.
length
===
0
)
{
fulfill
();
}
}));
queue
.
cancel
=
function
()
{
queue
.
cancel
=
function
()
{
if
(
resolved
)
{
return
;}
if
(
resolved
)
{
return
;}
...
@@ -811,25 +839,9 @@ define("rsvp/queue",
...
@@ -811,25 +839,9 @@ define("rsvp/queue",
throw
new
ResolvedQueueError
();
throw
new
ResolvedQueueError
();
}
}
next_promise
=
last_promise
.
then
(
done
,
fail
);
promise_list
.
push
(
next_promise
);
// Handle pop
// Handle pop
promise_list
.
push
(
next_promise
.
then
(
function
(
fulfillmentValue
)
{
checkPromise
(
last_promise
.
then
(
done
,
fail
));
promise_list
.
splice
(
0
,
2
);
if
(
promise_list
.
length
===
0
)
{
fulfill
(
fulfillmentValue
);
}
else
{
return
fulfillmentValue
;
}
},
function
(
rejectedReason
)
{
promise_list
.
splice
(
0
,
2
);
if
(
promise_list
.
length
===
0
)
{
reject
(
rejectedReason
);
}
else
{
throw
rejectedReason
;
}
}));
return
this
;
return
this
;
};
};
...
@@ -985,4 +997,4 @@ define("rsvp",
...
@@ -985,4 +997,4 @@ define("rsvp",
__exports__
.
reject
=
reject
;
__exports__
.
reject
=
reject
;
});
});
window
.
RSVP
=
requireModule
(
"
rsvp
"
);
window
.
RSVP
=
requireModule
(
"
rsvp
"
);
})(
window
);
})(
window
);
\ 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