├── .editorconfig
├── .gitattributes
├── .gitignore
├── .pr-preview.json
├── LICENSE
├── README.md
├── examples
├── ReadMe.txt
├── black480-Ad.png
├── black480-Content.png
├── black480.png
├── create_video_with_ffmpeg.sh
├── creatives
│ ├── banner_nonlinear.html
│ ├── banner_nonlinear.js
│ ├── base_simid_creative.js
│ ├── extender.html
│ ├── extender.js
│ ├── google_maps_client.js
│ ├── hover_nonlinear.html
│ ├── hover_nonlinear.js
│ ├── selector.html
│ ├── selector.js
│ ├── simid_map.css
│ ├── simid_map.html
│ ├── simid_map_creative.js
│ ├── simid_overlay.html
│ ├── simid_overlay.js
│ ├── survey.html
│ ├── survey.js
│ ├── testers_nonlinear.html
│ └── testers_nonlinear.js
├── media
│ ├── Big_Buck_Bunny.mp4
│ ├── IAB.mp4
│ ├── IAB480-small.mp4
│ ├── IAB480-smaller.mp4
│ ├── IAB480.mp4
│ ├── LearnMoreEndCard.jpg
│ ├── black_countdown.mp4
│ ├── fakeAd.mp4
│ ├── fakeContent.mp4
│ ├── shortAd.mp4
│ ├── sintel_trailer-480p.mp4
│ └── visitSiteEndCard.jpg
├── player
│ ├── simid_player.html
│ └── simid_player.js
└── simid_protocol.js
├── images
├── IABTechLabLogo.jpg
├── collapse-non-linear-workflow.png
├── dgrm-Creative-clickThru.png
├── dgrm-Creative-collapseNonlinear.png
├── dgrm-Creative-expandNonlinear.png
├── dgrm-Creative-requestNavigation.png
├── dgrm-creative-requestNavigation.png
├── dgrm-init-normal.png
├── dgrm-init-reject-timeout.png
├── dgrm-init-reject.png
├── dgrm-init-resolve-delay.png
├── dgrm-init-resolve-timeout.png
├── dgrm-init-special.png
├── dgrm-requestChangeAdDuration-known.png
├── dgrm-requestChangeAdDuration-unknown.png
├── dgrm-requestSkip.png
├── dgrm-requestStop.png
├── dgrm-session-init-sequence.png
├── dgrm-simid-initialization.png
├── dgrm-startCreative-normal.png
├── dgrm-startCreative-reject.png
├── expand-non-linear-workflow.png
├── infinity-duration-value.png
├── init-normal-flow-gray.png
├── init-normal-flow.png
├── init-reject.png
├── init-resolve-timeout.png
├── init-special-cases.png
├── non-linear-intro.png
├── nonlinear-user-experience.png
├── positive-duration-value.png
├── simid_diagram_1_overlay.png
├── simid_diagram_2_api_models.png
├── simid_diagram_3_assets.png
├── simid_diagram_4_loading.png
├── source
│ ├── simid_diagram_1_overlay.ai
│ ├── simid_diagram_2_api_models.ai
│ ├── simid_diagram_3_assets.ai
│ └── simid_diagram_4_loading.ai
├── startCreative-normal.png
└── startCreative-reject.png
├── index.bs
├── index.html
├── scripts
├── build.sh
└── watch.sh
├── simid-1.0.1.html
├── simid-1.0.1.images
├── IABTechLabLogo.jpg
├── dgrm-init-normal.png
├── dgrm-init-reject-timeout.png
├── dgrm-init-reject.png
├── dgrm-init-resolve-delay.png
├── dgrm-init-special.png
├── dgrm-requestChangeAdDuration-known.png
├── dgrm-requestChangeAdDuration-unknown.png
├── dgrm-requestSkip.png
├── dgrm-requestStop.png
├── dgrm-session-init-sequence.png
├── dgrm-simid-initialization.png
├── dgrm-startCreative-normal.png
├── dgrm-startCreative-reject.png
├── infinity-duration-value.png
├── init-normal-flow-gray.png
├── init-normal-flow.png
├── init-reject.png
├── init-resolve-timeout.png
├── init-special-cases.png
├── positive-duration-value.png
├── simid_diagram_1_overlay.png
├── simid_diagram_2_api_models.png
├── simid_diagram_3_assets.png
├── simid_diagram_4_loading.png
├── startCreative-normal.png
└── startCreative-reject.png
├── simid-1.0.html
├── simid-1.0.images
├── IABTechLabLogo.jpg
├── simid_diagram_1_overlay.png
├── simid_diagram_2_api_models.png
├── simid_diagram_3_assets.png
├── simid_diagram_4_loading.png
└── source
│ ├── simid_diagram_1_overlay.ai
│ ├── simid_diagram_2_api_models.ai
│ ├── simid_diagram_3_assets.ai
│ └── simid_diagram_4_loading.ai
├── simid-1.1.0.html
└── simid-1.1.0.images
├── IABTechLabLogo.jpg
├── collapse-non-linear-workflow.png
├── dgrm-Creative-clickThru.png
├── dgrm-Creative-collapseNonlinear.png
├── dgrm-Creative-expandNonlinear.png
├── dgrm-Creative-requestNavigation.png
├── dgrm-init-normal.png
├── dgrm-init-reject-timeout.png
├── dgrm-init-reject.png
├── dgrm-init-resolve-delay.png
├── dgrm-init-resolve-timeout.png
├── dgrm-init-special.png
├── dgrm-requestChangeAdDuration-known.png
├── dgrm-requestChangeAdDuration-unknown.png
├── dgrm-requestSkip.png
├── dgrm-requestStop.png
├── dgrm-session-init-sequence.png
├── dgrm-simid-initialization.png
├── dgrm-startCreative-normal.png
├── dgrm-startCreative-reject.png
├── expand-non-linear-workflow.png
├── infinity-duration-value.png
├── init-normal-flow-gray.png
├── init-normal-flow.png
├── init-reject.png
├── init-resolve-timeout.png
├── init-special-cases.png
├── non-linear-intro.png
├── nonlinear-user-experience.png
├── positive-duration-value.png
├── simid_diagram_1_overlay.png
├── simid_diagram_2_api_models.png
├── simid_diagram_3_assets.png
├── simid_diagram_4_loading.png
├── source
├── simid_diagram_1_overlay.ai
├── simid_diagram_2_api_models.ai
├── simid_diagram_3_assets.ai
└── simid_diagram_4_loading.ai
├── startCreative-normal.png
└── startCreative-reject.png
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_style = tab
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 | max_line_length = 80
11 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.bs diff=html linguist-language=HTML
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | // index.html
2 |
--------------------------------------------------------------------------------
/.pr-preview.json:
--------------------------------------------------------------------------------
1 | {
2 | "src_file": "index.bs",
3 | "type": "bikeshed",
4 | "title": "SIVIC"
5 | }
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | Copyright 2021 IAB Technology Laboratory, Inc
179 |
180 | Licensed under the Apache License, Version 2.0 (the "License");
181 | you may not use this file except in compliance with the License.
182 | You may obtain a copy of the License at
183 |
184 | http://www.apache.org/licenses/LICENSE-2.0
185 |
186 | Unless required by applicable law or agreed to in writing, software
187 | distributed under the License is distributed on an "AS IS" BASIS,
188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189 | See the License for the specific language governing permissions and
190 | limitations under the License.
191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Secure Interactive Media Interface Definition (SIMID)
2 |
3 | The latest human-readable version is available at https://interactiveadvertisingbureau.github.io/SIMID/
4 |
5 | * [SIMID version 1.0](https://interactiveadvertisingbureau.github.io/SIMID/simid-1.0.html)
6 | * [SIMID version 1.0.1]( https://interactiveadvertisingbureau.github.io/SIMID/simid-1.0.1.html)
7 | * [SIMID version 1.1]( https://interactiveadvertisingbureau.github.io/SIMID/simid-1.1.0.html)
8 |
9 | The sample implementation is available at https://interactiveadvertisingbureau.github.io/SIMID/examples/player/simid_player.html
10 |
11 | Home page on iabtechlab.com - https://iabtechlab.com/SIMID
12 |
13 | ## Contributing
14 |
15 | 1. Check out this repository to your local machine.
16 |
17 | 2. Run `scripts/watch.sh` inside your local copy. This will automatically build `index.html` every time you save a change to `index.bs`.
18 |
19 | 3. Create a branch to store specific edits you want to contribute.
20 |
21 | 4. Make changes to `index.bs` and check the updated version of `index.html` for your changes.
22 |
23 | 5. Commit your changes and file a pull request to get them reviewed and merged.
24 |
--------------------------------------------------------------------------------
/examples/ReadMe.txt:
--------------------------------------------------------------------------------
1 | In order to try out the example ad.
2 | 1. Start up a web browser, for example:
3 | python3 -m http.server
4 | 2. navigate to http://localhost:8000/examples/player/simid_player.html
5 | 3. Press the "Start ad playback" button.
6 |
--------------------------------------------------------------------------------
/examples/black480-Ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/black480-Ad.png
--------------------------------------------------------------------------------
/examples/black480-Content.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/black480-Content.png
--------------------------------------------------------------------------------
/examples/black480.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/black480.png
--------------------------------------------------------------------------------
/examples/create_video_with_ffmpeg.sh:
--------------------------------------------------------------------------------
1 | # Generates a black video with a countdown timer.
2 | # Requires ffmpeg
3 |
4 | fps=10;
5 | seconds=30;
6 | mantissaDigits=1;
7 | fontSize=200;
8 | fontFile="/usr/share/fonts/truetype/msttcorefonts/timesbd.ttf"
9 |
10 |
11 | ffmpeg -loop 1 -i black480-Ad.png -c:v libx264 \
12 | -r $fps -t $seconds -pix_fmt yuv420p \
13 | -vf "fps=$fps,drawtext=fontfile=$fontFile:fontcolor=yellow:fontsize=$fontSize:x=(w-text_w)/2:y=(h-text_h)/2:text='%{eif\:($seconds-t)\:d}.%{eif\:(mod($seconds-t, 1)*pow(10,$mantissaDigits))\:d\:$mantissaDigits}'"\
14 | fakeAd.mp4;
15 |
16 | seconds=120;
17 | ffmpeg -loop 1 -i black480-Content.png -c:v libx264 \
18 | -r $fps -t $seconds -pix_fmt yuv420p \
19 | -vf "fps=$fps,drawtext=fontfile=$fontFile:fontcolor=green:fontsize=$fontSize:x=(w-text_w)/2:y=(h-text_h)/2:text='%{eif\:($seconds-t)\:d}.%{eif\:(mod($seconds-t, 1)*pow(10,$mantissaDigits))\:d\:$mantissaDigits}'"\
20 | fakeContent.mp4;
21 |
--------------------------------------------------------------------------------
/examples/creatives/banner_nonlinear.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
57 |
58 |
--------------------------------------------------------------------------------
/examples/creatives/banner_nonlinear.js:
--------------------------------------------------------------------------------
1 | const Y_OFFSET_PERCENTAGE = .7;
2 | const X_OFFSET_PERCENTAGE = .15;
3 | const WIDTH_PERCENTAGE = .7;
4 | const HEIGHT_PERCENTAGE = .15;
5 |
6 | /**
7 | * A sample SIMID non-linear ad for a banner ad that shows a website when clicked on.
8 | * P.S: Not all websites can be shown and they would need to allow the x-frame-options
9 | * header to sameorigin for the ad to display correctly. More information here:
10 | * https://web.dev/samesite-cookies-explained/
11 | */
12 | class BannerNonLinear extends BaseSimidCreative {
13 | constructor() {
14 | super();
15 |
16 | /**
17 | * The desired text on the banner.
18 | * @private {?string}
19 | */
20 | this.bannerText_ = null;
21 |
22 | /**
23 | * The web URL to be displayed.
24 | * @private {?string}
25 | */
26 | this.webUrl_ = null;
27 |
28 | this.addButtonClickActions_();
29 | }
30 |
31 | /** @override */
32 | onInit(eventData) {
33 | this.updateInternalOnInit(eventData);
34 | this.validateAndParseAdParams_(eventData);
35 | this.updateCreativeWithParams_();
36 | this.dynamicResize_();
37 | }
38 |
39 | /**
40 | * Checks validity of ad parameters and rejects with proper message if invalid.
41 | * @param {!Object} eventData an object that contains information details for a particular event
42 | * such as event type, unique Ids, creativeData and environmentData.
43 | * @private
44 | */
45 | validateAndParseAdParams_(eventData) {
46 | if (!this.creativeData.adParameters) {
47 | this.simidProtocol.reject(eventData, {
48 | errorCode: CreativeErrorCode.UNSPECIFIED,
49 | message: 'Ad parameters not found'
50 | });
51 | return;
52 | }
53 |
54 | let adParams = "";
55 | try {
56 | adParams = JSON.parse(this.creativeData.adParameters);
57 | } catch (exception) {
58 | this.simidProtocol.reject(eventData, {
59 | errorCode: CreativeErrorCode.CREATIVE_INTERNAL_ERROR,
60 | message: 'Invalid JSON input for ad parameters'
61 | });
62 | return;
63 | }
64 |
65 | this.bannerText_ = adParams['bannerText'];
66 | this.webUrl_ = adParams['webUrl'];
67 |
68 | if (!this.webUrl_) {
69 | this.simidProtocol.reject(eventData, {
70 | errorCode: CreativeErrorCode.UNSPECIFIED,
71 | message: 'Required field webUrl not found'
72 | });
73 | return;
74 | }
75 |
76 | this.simidProtocol.resolve(eventData, {});
77 | }
78 |
79 | updateCreativeWithParams_() {
80 | document.getElementById('ad_text').textContent = this.bannerText_;
81 | document.getElementById('webpage_container').src = this.webUrl_;
82 | }
83 |
84 | /**
85 | * Adds actions to different buttons available on the overlay.
86 | * @private
87 | */
88 | addButtonClickActions_() {
89 | this.sendMessageOnButtonClick_('close_ad', CreativeMessage.REQUEST_STOP);
90 |
91 | this.sendMessageOnButtonClick_('ad_text', CreativeMessage.EXPAND_NONLINEAR, () => {
92 | document.getElementById('ad_text').classList.add('hidden');
93 | document.getElementById('content_box').classList.remove('hidden');
94 | });
95 |
96 | this.sendMessageOnButtonClick_('minimize_ad', CreativeMessage.COLLAPSE_NONLINEAR, () => {
97 | document.getElementById('ad_text').classList.remove('hidden');
98 | document.getElementById('content_box').classList.add('hidden');
99 | });
100 | }
101 |
102 | /**
103 | * Sends a SIMID message whenever an element is clicked.
104 | * @param {String} elementName The name of the element.
105 | * @param {String} message The message to send to the player.
106 | * @param {?Function} callback This gets executed after the message to the player is sent.
107 | * @private
108 | */
109 | sendMessageOnButtonClick_(elementName, message, callback) {
110 | const sendMessageFunction = () => {
111 | this.simidProtocol.sendMessage(message);
112 | if (callback) {callback()};
113 | }
114 | document.getElementById(elementName).addEventListener(
115 | 'click', sendMessageFunction);
116 | }
117 |
118 | /**
119 | * Repositions the banner ad according to the dimensions of the video player
120 | * by calculating desired dimensions and sending a resize request to creative.
121 | * @private
122 | */
123 | dynamicResize_() {
124 | // This ad requests that the player resize it and move it, so that it is centered within the player.
125 | let creativeDimensions = {};
126 | creativeDimensions.x = this.environmentData.videoDimensions.width * X_OFFSET_PERCENTAGE;
127 | creativeDimensions.y = this.environmentData.videoDimensions.height * Y_OFFSET_PERCENTAGE;
128 | creativeDimensions.width = this.environmentData.videoDimensions.width * WIDTH_PERCENTAGE;
129 | creativeDimensions.height = this.environmentData.videoDimensions.height * HEIGHT_PERCENTAGE;
130 | const params = {
131 | videoDimensions: this.environmentData.videoDimensions,
132 | creativeDimensions: creativeDimensions
133 | };
134 | this.requestResize(params);
135 | }
136 | }
--------------------------------------------------------------------------------
/examples/creatives/base_simid_creative.js:
--------------------------------------------------------------------------------
1 | /*
2 | * A subclass of a SIMID ad that implements functionality that will
3 | * be the same for all simid ads.
4 | */
5 | class BaseSimidCreative {
6 | constructor() {
7 | /**
8 | * Data about the creative, not known until after init.
9 | * @protected {?Object}
10 | */
11 | this.creativeData = null;
12 |
13 | /**
14 | * Data about the environment the creative plays in, not known until after init.
15 | * @protected {?Object}
16 | */
17 | this.environmentData = null;
18 |
19 | /**
20 | * The most recent video state from the player.
21 | * @protected {?Object}
22 | */
23 | this.videoState = {
24 | currentSrc:'',
25 | currentTime: -1, // Time not yet known
26 | duration: -1, // duration unknown
27 | ended: false,
28 | muted: false,
29 | paused: false,
30 | volume: 0.5,
31 | fullscreen: false
32 | }
33 |
34 |
35 | /**
36 | * The simid version, once the player makes it known.
37 | * @protected {String}
38 | */
39 | this.simidVersion = '';
40 |
41 | /**
42 | * The protocol for sending and receiving messages.
43 | * @protected {!SimidProtocol}
44 | */
45 | this.simidProtocol = new SimidProtocol();
46 |
47 | this.addListeners_();
48 | }
49 |
50 | /**
51 | * Sets up the creative to listen for messages from the player
52 | * @private
53 | */
54 | addListeners_() {
55 | this.simidProtocol.addListener(PlayerMessage.INIT, this.onInit.bind(this));
56 | this.simidProtocol.addListener(PlayerMessage.START_CREATIVE, this.onStart.bind(this));
57 | this.simidProtocol.addListener(PlayerMessage.FATAL_ERROR, this.onFatalError.bind(this));
58 | this.simidProtocol.addListener(PlayerMessage.AD_STOPPED, this.onAdStopped.bind(this));
59 | this.simidProtocol.addListener(PlayerMessage.AD_SKIPPED, this.onAdSkipped.bind(this));
60 | this.simidProtocol.addListener(PlayerMessage.LOG, this.onReceivePlayerLog.bind(this));
61 | this.simidProtocol.addListener(PlayerMessage.RESIZE, this.onReceiveResize.bind(this));
62 | // Handlers with different video events.
63 | this.simidProtocol.addListener(MediaMessage.DURATION_CHANGE, this.onDurationChange.bind(this));
64 | this.simidProtocol.addListener(MediaMessage.ENDED, this.onVideoEnded.bind(this));
65 | this.simidProtocol.addListener(MediaMessage.ERROR, this.onVideoError.bind(this));
66 | this.simidProtocol.addListener(MediaMessage.PAUSE, this.onPause.bind(this));
67 | this.simidProtocol.addListener(MediaMessage.PLAY, this.onPlay.bind(this));
68 | this.simidProtocol.addListener(MediaMessage.PLAYING, this.onPlaying.bind(this));
69 | this.simidProtocol.addListener(MediaMessage.SEEKED, this.onSeeked.bind(this));
70 | this.simidProtocol.addListener(MediaMessage.SEEKING, this.onSeeking.bind(this));
71 | this.simidProtocol.addListener(MediaMessage.TIME_UPDATE, this.onTimeUpdate.bind(this));
72 | this.simidProtocol.addListener(MediaMessage.VOLUME_CHANGE, this.onVolumeChange.bind(this));
73 | }
74 |
75 | ready() {
76 | this.simidProtocol.createSession();
77 | }
78 |
79 | /**
80 | * Receives init message from the player.
81 | * @param {!Object} eventData Data from the event.
82 | * @protected
83 | */
84 | onInit(eventData) {
85 | this.updateInternalOnInit(eventData);
86 | this.simidProtocol.resolve(eventData, {});
87 | }
88 |
89 | /**
90 | * Updates internal data on initialization call.
91 | *
92 | * Note: When overriding the onInit function and not wishing
93 | * to always resolve, subclasses may instead use this function.
94 | * @param {!Object} eventData Data from the event.
95 | * @protected
96 | */
97 | updateInternalOnInit(eventData) {
98 | this.creativeData = eventData.args.creativeData;
99 | this.environmentData = eventData.args.environmentData;
100 | this.videoState.muted = this.environmentData.muted;
101 | this.videoState.volume = this.environmentData.volume;
102 | }
103 |
104 | /**
105 | * Receives start message from the player.
106 | * @param {!Object} eventData Data from the event.
107 | * @protected
108 | */
109 | onStart(eventData) {
110 | // Acknowledge that the ad is started.
111 | this.simidProtocol.resolve(eventData, {});
112 | console.log('Simid creative started.')
113 | }
114 |
115 | /**
116 | * Called when the creative receives the fatal error message from the player.
117 | * @protected
118 | */
119 | onFatalError(eventData) {
120 | // After resolving the iframe with this ad should be cleaned up.
121 | this.simidProtocol.resolve(eventData, {});
122 | }
123 |
124 | /**
125 | * Called when the creative receives the stop message from the player.
126 | * @protected
127 | */
128 | onAdStopped(eventData) {
129 | // After resolving the iframe with this ad should be cleaned up.
130 | this.simidProtocol.resolve(eventData, {});
131 | }
132 |
133 | /**
134 | * Called when the creative receives the skip message from the player.
135 | * @protected
136 | */
137 | onAdSkipped(eventData) {
138 | // After resolving the iframe with this ad should be cleaned up.
139 | this.simidProtocol.resolve(eventData, {});
140 | }
141 |
142 | /**
143 | * Called when the creative receives a resize message from the player.
144 | * @param {!Object} eventData Data from the event.
145 | * @protected
146 | */
147 | onReceiveResize(eventData) {
148 | this.environmentData.creativeDimensions = eventData.args.creativeDimensions;
149 | this.environmentData.videoDimensions = eventData.args.videoDimensions;
150 | }
151 |
152 | /**
153 | * Opens the click through url and lets the player know about it.
154 | * @protected
155 | */
156 | clickThru() {
157 |
158 | }
159 |
160 | /**
161 | * Asks the player for the state of the video element.
162 | * @protected
163 | */
164 | fetchMediaState() {
165 | this.simidProtocol.sendMessage(CreativeMessage.GET_MEDIA_STATE, {})
166 | .then((data) => this.onGetMediaStateResolve(data));
167 | }
168 |
169 | /**
170 | * @protected
171 | */
172 | onGetMediaStateResolve(data) {
173 | this.videoState = data;
174 | }
175 |
176 | /**
177 | * @protected
178 | */
179 | onDurationChange(data) {
180 | this.videoState.duration = data.args.duration;
181 | }
182 |
183 | /**
184 | * @protected
185 | */
186 | onVideoEnded() {
187 | this.videoState.ended = true;
188 | }
189 |
190 | /**
191 | * @protected
192 | */
193 | onVideoError() {
194 | // no op for this example
195 | }
196 |
197 | /**
198 | * @protected
199 | */
200 | onPause() {
201 | this.videoState.paused = true;
202 | }
203 |
204 | /**
205 | * @protected
206 | */
207 | onPlay() {
208 | this.videoState.paused = false;
209 | }
210 |
211 | /**
212 | * @protected
213 | */
214 | onPlaying() {
215 | this.videoState.paused = false;
216 | }
217 |
218 | /**
219 | * @protected
220 | */
221 | onSeeked() {
222 | // no op for this example
223 | }
224 |
225 | /**
226 | * @protected
227 | */
228 | onSeeking() {
229 | // no op for this example
230 | }
231 |
232 | /**
233 | * @protected
234 | */
235 | onTimeUpdate(data) {
236 | this.videoState.currentTime = data.args.currentTime;
237 | }
238 |
239 | /**
240 | * @protected
241 | */
242 | onVolumeChange(data) {
243 | this.videoState.volume = data.args.volume;
244 | }
245 |
246 | onReceivePlayerLog(data) {
247 | const logMessage = data.args.message;
248 | console.log("Received message from player: " + logMessage);
249 | }
250 |
251 | /**
252 | * Sends message requesting to resize creative based off of given resizeParameters
253 | * @param {!Object} resizeParams An object with the video & creative dimensions.
254 | */
255 | requestResize(resizeParams) {
256 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_RESIZE, resizeParams).then( () => {
257 | this.environmentData.creativeDimensions = resizeParams.creativeDimensions;
258 | this.environmentData.videoDimensions = resizeParams.videoDimensions;
259 | });
260 | }
261 | }
262 |
--------------------------------------------------------------------------------
/examples/creatives/extender.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
89 |
90 |
--------------------------------------------------------------------------------
/examples/creatives/extender.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A sample SIMID ad demonstrating a selector.
3 | */
4 | class Extender extends BaseSimidCreative {
5 | constructor() {
6 | super();
7 |
8 | /** True if the player said it would extend duration. */
9 | this.extendDuration_ = false;
10 | }
11 |
12 | /** @override */
13 | onStart(eventData) {
14 | super.onStart(eventData);
15 | // Don't fetch the media state right away in case the video is not yet loaded.
16 | setTimeout(() => {
17 | this.fetchMediaState();
18 | }, 1500);
19 | }
20 |
21 | /** @override */
22 | onGetMediaStateResolve(data) {
23 | super.onGetMediaStateResolve(data);
24 | const mediaDuration = data['duration'];
25 | const params = {
26 | 'duration': mediaDuration + 5,
27 | };
28 |
29 | // Ask the player if we can extend duration 5 seconds to show end cards.
30 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_CHANGE_AD_DURATION, params).then(() => {
31 | this.extendDuration_ = true;
32 | }).catch(() => {
33 | console.log('Player does not support requested duration change.');
34 | });
35 | }
36 |
37 | onVideoEnded() {
38 | if (this.extendDuration_) {
39 | this.showEndCards();
40 | }
41 | }
42 |
43 | showEndCards() {
44 | const firstTag = document.getElementById('firstTag');
45 | firstTag.classList.remove('hidden');
46 | firstTag.classList.add('fade-in');
47 | const secondTag = document.getElementById('secondTag');
48 | secondTag.classList.remove('hidden');
49 | secondTag.classList.add('fade-in');
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/examples/creatives/google_maps_client.js:
--------------------------------------------------------------------------------
1 | const DEFAULT_MAP_LAT = 37.422004;
2 | const DEFAULT_MAP_LNG = -122.081402;
3 | const DEFAULT_ZOOM = 13;
4 | const DEFAULT_LOCATION_NUM_DISPLAYED = 4;
5 | const MARKER_SIZE = 25;
6 |
7 | /**
8 | * This class handles all map related functionality, including
9 | * displaying the map, calculating & displaying directions, tracking all
10 | * interactions with the map, logging error messages with SimidProtocol,
11 | * and handling any errors that result from the Maps API.
12 | */
13 | class GoogleMapsClient {
14 | /**
15 | * A GoogleMapsClient object handles
16 | * @param {!string} query The search query string.
17 | * @param {!string} markerUrl The marker image url.
18 | * @param {?google.maps.LatLng} coordinates User coordinates.
19 | * @param {!SimidProtocol} simidProtocol The SimidProtocol object.
20 | * @param {!function} onMapsClientComplete A function that determine's the object's behavior in case
21 | * of an error.
22 | * @param {!Element} travelMethod The HTML element containing the travel method drop down menu.
23 | * @param {!Element} timeDisplay The HTML div where the travel time is to be displayed.
24 | */
25 | constructor(query, markerUrl, simidProtocol, onMapsClientComplete, travelMethod,
26 | timeDisplay, coordinates = new google.maps.LatLng(DEFAULT_MAP_LAT, DEFAULT_MAP_LNG)) {
27 | /**
28 | * The LatLng coordinates representing the user's current location.
29 | * @private @const {!google.maps.LatLng}
30 | */
31 | this.currentLocation_ = coordinates;
32 | /**
33 | * The string representing the search query.
34 | * @private @const {string}
35 | */
36 | this.searchQuery_ = query;
37 | /**
38 | * The desired marker image's string URL.
39 | * @private @const {string}
40 | */
41 | this.markerImage_ = markerUrl;
42 | /**
43 | * The DirectionsRenderer object that displays directions from
44 | * the given request.
45 | * @private @const {!google.maps.DirectionsRenderer}
46 | */
47 | this.directionsRenderer_ = new google.maps.DirectionsRenderer();
48 | /**
49 | * A SimidProtocol object from creative.
50 | * @private @const {!SimidProtocol}
51 | */
52 | this.simidProtocol = simidProtocol;
53 | /**
54 | * The function that determines the class's behavior in case of an API error.
55 | * @private @const {!function}
56 | */
57 | this.onMapsClientComplete_ = onMapsClientComplete;
58 | /**
59 | * The element from the document where the travel method selector lives.
60 | * @private @const {!Element}
61 | */
62 | this.travelMethodElement_ = travelMethod;
63 | /**
64 | * The element from the document where the time display div lives.
65 | * @private @const {!Element}
66 | */
67 | this.timeDisplayElement_ = timeDisplay;
68 | /**
69 | * A map object from the Google Maps API.
70 | * @private {?google.maps.Map}
71 | */
72 | this.map_ = null;
73 | /**
74 | * The LatLng coordinates representing the location most recently
75 | * selected by the user, defaulting to the closest location.
76 | * @private {?google.maps.LatLng}
77 | */
78 | this.activeLocation_ = null;
79 | }
80 |
81 | /**
82 | * Loads a map object that currently defaults to a hardcoded location.
83 | * @param {!Element} mapElement The div within the main document where the map is to be displayed.
84 | */
85 | displayMap(mapElement) {
86 | this.map_ = new google.maps.Map(mapElement, {
87 | zoom: DEFAULT_ZOOM,
88 | center: this.currentLocation_
89 | });
90 | this.findNearby_();
91 | }
92 |
93 | /**
94 | * Searches for the closest corresponding locations based off of the given search parameter,
95 | * and places pins on the map that represent the closest locations.
96 | * @private
97 | */
98 | findNearby_() {
99 | const request = {
100 | location: this.currentLocation_,
101 | name: this.searchQuery_,
102 | openNow: true,
103 | rankBy: google.maps.places.RankBy.DISTANCE
104 | };
105 | const placeService = new google.maps.places.PlacesService(this.map_);
106 | placeService.nearbySearch(request, this.displayResults_.bind(this));
107 | }
108 |
109 | /**
110 | * Displays the closest advertisement's locations to a user's current location.
111 | * @param {!Array} results An array of Place Results from the search query.
112 | * @param {!google.maps.places.PlacesServiceStatus} status The status returned
113 | * by the PlacesService on the completion of its searches.
114 | * @private
115 | */
116 | displayResults_(results, status) {
117 | if (status == google.maps.places.PlacesServiceStatus.OK) {
118 | //Active location is set to the closest location to start.
119 | this.activeLocation_ = results[0].geometry.location;
120 | for (let i = 0; i < DEFAULT_LOCATION_NUM_DISPLAYED; i++) {
121 | this.placeMapMarker_(results[i]);
122 | }
123 | this.displayDirections_();
124 | } else {
125 | const statusErrorMessage = {
126 | message: "ERROR: Failed to complete search: " + status,
127 | };
128 | this.simidProtocol.sendMessage(CreativeMessage.LOG, statusErrorMessage);
129 | this.onMapsClientComplete_();
130 | }
131 | }
132 |
133 | /**
134 | * Creates and displays a marker on the map representing a given place.
135 | * @param {!Object} place A Place Result object.
136 | * @private
137 | */
138 | placeMapMarker_(place) {
139 | const placeIcon = {
140 | url: this.markerImage_,
141 | scaledSize: new google.maps.Size(MARKER_SIZE, MARKER_SIZE)
142 | };
143 | const placeMarker = new google.maps.Marker({
144 | map: this.map_,
145 | position: place.geometry.location,
146 | icon: placeIcon
147 | });
148 | ///Recalculate directions if a different active marker is selected.
149 | placeMarker.addListener('click', () => {
150 | this.activeLocation_ = place.geometry.location;
151 | this.displayDirections_();
152 | });
153 | }
154 |
155 | /**
156 | * Displays the route between the starting loaction and destination
157 | * based off of the selected travel mode.
158 | * @private
159 | */
160 | displayDirections_() {
161 | this.directionsRenderer_.setMap(this.map_);
162 | this.calculateRoute_();
163 | this.calculateTravelTime_()
164 | this.travelMethodElement_.addEventListener("change", () => {
165 | this.calculateRoute_();
166 | this.calculateTravelTime_();
167 | });
168 | }
169 |
170 | /**
171 | * Calculates the route between the user's current location and current
172 | * active location based off of the selected travel mode.
173 | * @private
174 | */
175 | calculateRoute_() {
176 | const dirService = new google.maps.DirectionsService();
177 | const selectedMode = this.travelMethodElement_.value;
178 | dirService.route(
179 | {
180 | origin: this.currentLocation_,
181 | destination: this.activeLocation_,
182 | travelMode: [selectedMode]
183 | },
184 | (response, status) => {
185 | if (status == "OK") {
186 | this.directionsRenderer_.setDirections(response);
187 | } else {
188 | const directionsErrorMessage = {
189 | message: "ERROR: Failed to load directions: " + status,
190 | };
191 | this.simidProtocol.sendMessage(CreativeMessage.LOG, directionsErrorMessage);
192 | }
193 | }
194 | );
195 | }
196 |
197 | /**
198 | * Calculates the time it takes to travel from the origin to the destination.
199 | * @private
200 | */
201 | calculateTravelTime_() {
202 | const travelMode = this.travelMethodElement_.value;
203 | const matrixService = new google.maps.DistanceMatrixService();
204 | matrixService.getDistanceMatrix(
205 | {
206 | origins: [this.currentLocation_],
207 | destinations: [this.activeLocation_],
208 | travelMode: [travelMode],
209 | unitSystem: google.maps.UnitSystem.IMPERIAL
210 | }, this.getTravelTime_.bind(this));
211 | }
212 |
213 | /**
214 | * Gets the travel time from the distanceMatrix response.
215 | * @param {!google.maps.DistanceMatrixResponse} response An object containing
216 | * distance and duration information for the given origin & destination.
217 | * @param {!google.maps.DistanceMatrixStatus} travelStatus The status returned
218 | * by the Distance Matrix on the completion of its calculations.
219 | * @private
220 | */
221 | getTravelTime_(response, travelStatus) {
222 | if (travelStatus == 'OK') {
223 | const results = response.rows[0].elements;
224 | this.displayTravelTimes_(results[results.length - 1].duration.text);
225 | }
226 | }
227 |
228 | /**
229 | * Adds the travel time to the creative display.
230 | * @param {string} timeString The string object representing travel time.
231 | * @private
232 | */
233 | displayTravelTimes_(timeString) {
234 | const transportMethod = this.travelMethodElement_.value.toLowerCase();
235 | this.timeDisplayElement_.innerText = "By "+transportMethod+": " + timeString;
236 | }
237 | }
--------------------------------------------------------------------------------
/examples/creatives/hover_nonlinear.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
33 |
34 |
35 |
36 |
Hover over banner to expand
37 |
38 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/creatives/hover_nonlinear.js:
--------------------------------------------------------------------------------
1 | const DIMENSION_GROWTH = 1.4;
2 | const OFFSET_SHIFT = .2;
3 | const EDGE_DIMENSION_GROWTH = 1.2;
4 |
5 | /** This creative expands and collapses when the user hovers over the banner. */
6 | class HoverNonLinear extends BaseSimidCreative {
7 | constructor() {
8 | super();
9 |
10 | this.initialDimensions_ = null;
11 | this.videoDimensionWidth_ = null;
12 | this.videoDimensionHeight_ = null;
13 | }
14 |
15 | /** @override */
16 | onInit(eventData) {
17 | super.onInit(eventData);
18 | this.initialDimensions_ = this.environmentData.creativeDimensions;
19 | this.videoDimensionHeight_ = this.environmentData.videoDimensions.height;
20 | this.videoDimensionWidth_ = this.environmentData.videoDimensions.width;
21 | }
22 |
23 | /** @override */
24 | onStart(eventData) {
25 | super.onStart(eventData);
26 | this.addActions_();
27 | }
28 |
29 | /**
30 | * Adds actions to different buttons available on the overlay.
31 | * @private
32 | */
33 | addActions_() {
34 | this.sendMessageOnClick_('close_ad', CreativeMessage.REQUEST_STOP);
35 | this.onHover_('content_container', 'mouseover');
36 | this.onMouseOut_('content_container', 'mouseout');
37 | }
38 |
39 | /**
40 | * Sends a SIMID message whenever an element is clicked.
41 | * @param {String} elementName The name of the element.
42 | * @param {String} message The message to send to the player.
43 | * @private
44 | */
45 | sendMessageOnClick_(elementName, message) {
46 | const sendMessageFunction = () => {this.simidProtocol.sendMessage(message);}
47 | document.getElementById(elementName).addEventListener('click', sendMessageFunction);
48 | }
49 |
50 | /**
51 | * Adds a hover event listener to the contents of the iframe that expands the iframe.
52 | * @param {String} elementName The name of the element.
53 | * @param {Event} event The event performed on the element.
54 | * @private
55 | */
56 | onHover_(elementName, event) {
57 | const expandOnHoverFunction = () => {
58 | const newDimensions = {};
59 | let resizeParams = {};
60 |
61 | let desiredX;
62 | let desiredWidth;
63 | let desiredY;
64 | let desiredHeight;
65 | let fullCreativeWidth;
66 | let fullCreativeHeight;
67 |
68 | //Width grows 20%
69 | desiredWidth = this.initialDimensions_.width * DIMENSION_GROWTH;
70 | desiredX = parseInt(this.initialDimensions_.x) - parseInt(this.initialDimensions_.width * OFFSET_SHIFT);
71 |
72 | //Makes sure x offset fits in the player
73 | if (desiredX <= 0) {
74 | desiredX = 0;
75 | desiredWidth = this.initialDimensions_.width * EDGE_DIMENSION_GROWTH;
76 | }
77 | if (desiredX > this.videoDimensionWidth_) {
78 | return;
79 | }
80 |
81 | //Makes sure width fits in the player
82 | fullCreativeWidth = desiredX + desiredWidth;
83 | if (fullCreativeWidth > this.videoDimensionWidth_) {
84 | fullCreativeWidth = this.videoDimensionWidth_;
85 | desiredWidth = fullCreativeWidth - desiredX;
86 | }
87 |
88 | //Height grows 20%
89 | desiredHeight = this.initialDimensions_.height * DIMENSION_GROWTH;
90 | desiredY = parseInt(this.initialDimensions_.y) - parseInt(this.initialDimensions_.height * OFFSET_SHIFT);
91 |
92 | //Makes sure y offset fits in the player
93 | if (desiredY <= 0) {
94 | desiredY = 0;
95 | desiredHeight = this.initialDimensions_.height * EDGE_DIMENSION_GROWTH;
96 | }
97 | if (desiredY > this.videoDimensionHeight_) {
98 | return;
99 | }
100 |
101 | //Makes sure height fits in the player
102 | fullCreativeHeight = desiredY + desiredHeight;
103 | if (fullCreativeHeight > this.videoDimensionHeight_) {
104 | fullCreativeHeight = this.videoDimensionHeight_;
105 | desiredHeight = fullCreativeHeight - desiredY;
106 | }
107 |
108 | newDimensions.x = desiredX;
109 | newDimensions.y = desiredY;
110 | newDimensions.width = desiredWidth;
111 | newDimensions.height = desiredHeight;
112 |
113 | resizeParams = {
114 | creativeDimensions: newDimensions,
115 | videoDimensions: this.environmentData.videoDimensions,
116 | };
117 |
118 | this.requestResize(resizeParams);
119 | }
120 | document.getElementById(elementName).addEventListener(event, expandOnHoverFunction);
121 | }
122 |
123 | /**
124 | * Adds a mouse out event listener to the contents of the iframe that shrinks the iframe
125 | * back to its original size.
126 | * @param {String} elementName The name of the element.
127 | * @param {Event} event The event performed on the element.
128 | * @private
129 | */
130 | onMouseOut_(elementName, event) {
131 | const collpaseOnMouseOutFunction = () => {
132 | const restoreParams = {
133 | creativeDimensions: this.initialDimensions_,
134 | videoDimensions: this.environmentData.videoDimensions,
135 | };
136 |
137 | this.requestResize(restoreParams);
138 | }
139 | document.getElementById(elementName).addEventListener(event, collpaseOnMouseOutFunction);
140 | }
141 | }
--------------------------------------------------------------------------------
/examples/creatives/selector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
68 |
69 |
70 |
71 |
72 |
73 |
Select a Shorter Ad
74 |
75 |
76 |
82 |
83 |
--------------------------------------------------------------------------------
/examples/creatives/selector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A sample SIMID ad demonstrating a selector.
3 | */
4 | class SimidSelector extends BaseSimidCreative {
5 | constructor() {
6 | super();
7 | /**
8 | * True if the user has clicked an ad.
9 | * @private {boolean}
10 | */
11 | this.adSelected_ = false;
12 | }
13 | /** @override */
14 | onStart(eventData) {
15 | super.onStart(eventData);
16 | setTimeout(() => {
17 | this.showElements();
18 | this.openVideoWhenClicked();
19 | }, 1000);
20 |
21 | // Give the user 10 seconds to select a shorter ad or continue with default ad.
22 | setTimeout(() => {
23 | if (!this.adSelected_) {
24 | this.hideElements();
25 | }
26 | }, 10000);
27 | }
28 |
29 | /**
30 | * Causes two videos and a title (text) element to animate over the video.
31 | */
32 | showElements() {
33 | document.getElementById('title').classList.add('showing');
34 | document.getElementById('video1').classList.add('showing');
35 | document.getElementById('video2').classList.add('showing');
36 | }
37 |
38 | /**
39 | * Causes all overlayed elements to animate off the main video.
40 | */
41 | hideElements() {
42 | document.getElementById('title').classList.remove('showing');
43 | document.getElementById('video1').classList.remove('showing');
44 | document.getElementById('video2').classList.remove('showing');
45 | }
46 |
47 | /**
48 | * Asks the ad video to pause, plays the selected video and then ends the ad
49 | * once the selected video is played
50 | */
51 | onVideoClicked (clickedVid, unclickedVid) {
52 | console.log('vid clicked');
53 | this.adSelected_ = true;
54 |
55 | // Request that the ad playback pauses and then wait for the player to resolve.
56 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_PAUSE).then(() => {
57 | // Set the clicked video to take up the entire video area.
58 | clickedVid.classList.add('fullSize');
59 |
60 | // Remove the unused elements.
61 | clickedVid.classList.remove('showing');
62 | unclickedVid.classList.remove('showing');
63 | document.getElementById('title').classList.remove('showing');
64 | clickedVid.classList.remove('showing');
65 |
66 | // When the clicked video ends terminate the ad.
67 | clickedVid.addEventListener('ended', () => this.onEnded());
68 |
69 | // Start playback of the clicked video. This should work on all
70 | // browsers, since there was a user intent to play the video.
71 | clickedVid.play();
72 | });
73 | }
74 |
75 | /**
76 | * Sets up click listeners on the video elements. When a video element
77 | * is clicked on, onVideo clicked is called.
78 | */
79 | openVideoWhenClicked() {
80 | const video1 = document.getElementById('video1');
81 | const video2 = document.getElementById('video2');
82 |
83 | video1.addEventListener('click', () => this.onVideoClicked(video1, video2));
84 | video2.addEventListener('click', () => this.onVideoClicked(video2, video1));
85 | }
86 |
87 | onEnded() {
88 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_STOP);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/examples/creatives/simid_map.css:
--------------------------------------------------------------------------------
1 | /* Styling for maps creative */
2 |
3 | /*Styling for initial state */
4 | button {
5 | background: rgba(0,0,0,0.5);
6 | border: 1px solid rgba(255,255,255,0.5);
7 | border-right: 0;
8 | box-sizing: content-box;
9 | color: #fff;
10 | font-size: 18px;
11 | line-height: normal;
12 | min-width: 0;
13 | padding: 10px 6px 8px 10px;
14 | width: auto;
15 | text-align: center;
16 | transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
17 | text-shadow: 0 0 4px rgba(0,0,0,0.75);
18 | cursor: pointer;
19 | }
20 |
21 | button:hover {
22 | background: rgba(0,0,0,0.7);
23 | }
24 |
25 | #findNearest{
26 | position: absolute;
27 | bottom: 10px;
28 | left: 10px;
29 | padding: 15px;
30 | }
31 |
32 | .hidden {
33 | visibility: hidden;
34 | }
35 |
36 | #travelMethod {
37 | padding: 4px;
38 | background: rgba(0,0,0,0.5);
39 | border: 1px solid rgba(255,255,255,0.5);
40 | color: white;
41 | font-size: 18px;
42 | margin-left: 11px;
43 | top: 60px;
44 | position: absolute;
45 | }
46 |
47 | #timeDisplay {
48 | position: absolute;
49 | top: 65px;
50 | right: 200px;
51 | padding: 5px;
52 | border: 1px solid black;
53 | background-color: rgba(0,0,0,0.6);
54 | color: white;
55 | max-width: 110px;
56 | text-align: center;
57 | transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
58 | text-shadow: 0 0 4px rgba(0,0,0,0.75);
59 | font-size: 16px;
60 | }
61 |
62 | #returnToAd {
63 | position: absolute;
64 | bottom: 10px;
65 | left: 10px;
66 | padding: 15px;
67 | }
68 |
69 | #skipAd {
70 | position: absolute;
71 | bottom: 10px;
72 | right: 10px;
73 | padding: 15px;
74 | padding-right: 30px;
75 | padding-left: 30px;
76 | }
77 |
78 | /*Allows map to display*/
79 | html, body {
80 | height: 100%;
81 | margin: 0;
82 | padding: 0;
83 | }
84 |
85 | /*
86 | * Display the map in the center of the iframe,
87 | * scaled to allow button display
88 | */
89 | #map {
90 | height: 90%;
91 | width: 100%;
92 | margin: auto;
93 | top: 180px;
94 | -ms-transform: translateY(-50%);
95 | transform: translateY(-50%);
96 | zoom: 1.15;
97 | overflow: visible !important;
98 | }
99 |
100 | .gm-style-mtc {
101 | top: 2px;
102 | }
103 |
104 | div.gm-style-mtc div {
105 | padding: 0px 12px !important;;
106 | }
107 |
108 | div.gm-svpc {
109 | top: 165px !important;
110 | }
111 |
112 | div.gmnoprint {
113 | top: 50px;
114 | }
115 |
116 | div.gmnoprint div {
117 | position: inherit;
118 | }
--------------------------------------------------------------------------------
/examples/creatives/simid_map.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
20 |
22 |
23 |
--------------------------------------------------------------------------------
/examples/creatives/simid_map_creative.js:
--------------------------------------------------------------------------------
1 | const AdParamKeys = {
2 | BUTTON_LABEL: 'buttonLabel',
3 | SEARCH_QUERY: 'searchQuery',
4 | MARKER: 'marker',
5 | COORDINATES: 'userCoordinates'
6 | };
7 |
8 | const TRAVEL_METHOD = "travelMethod";
9 | const TIME_DISPLAY = "timeDisplay";
10 | const FIND_NEAREST_TEMPLATE_TEXT = "Find Nearest ";
11 | const DEFAULT_BUTTON_LABEL = "Location";
12 | const TRANSPORT_METHODS = ["Driving", "Walking", "Bicycling", "Transit"];
13 |
14 | /**
15 | * A sample SIMID ad that shows a map of nearby locations.
16 | */
17 | class SimidMapCreative extends BaseSimidCreative {
18 | constructor() {
19 | super();
20 |
21 | /**
22 | * A Simid Map object where all of the Maps API calls are handled
23 | * @private {!SimidMap}
24 | */
25 | this.googleMapsClient_ = null;
26 | /**
27 | * The desired marker image's string URL.
28 | * @private {?string}
29 | */
30 | this.markerUrl_ = null;
31 | /**
32 | * The string representing the search query.
33 | * @private {?string}
34 | */
35 | this.query_ = null;
36 | /**
37 | * The LatLng coordinates representing the user's current location.
38 | * @private {?google.maps.LatLng}
39 | */
40 | this.coordinates_ = null;
41 | }
42 |
43 | /** @override */
44 | onInit(eventData) {
45 | this.updateInternalOnInit(eventData);
46 | this.validateAndParseAdParams_(eventData);
47 | }
48 |
49 | /**
50 | * Checks validity of ad parameters and rejects with proper message if invalid.
51 | * @param eventData an object that contains information details for a particular event
52 | * such as event type, unique Ids, creativeData and environmentData.
53 | * @private
54 | */
55 | validateAndParseAdParams_(eventData) {
56 | if (this.creativeData.adParameters == "") {
57 | this.simidProtocol.reject(eventData, {errorCode: CreativeErrorCode.UNSPECIFIED,
58 | message: "Ad parameters not found"});
59 | return;
60 | }
61 |
62 | let adParams = "";
63 | try {
64 | adParams = JSON.parse(this.creativeData.adParameters);
65 | } catch (exception) {
66 | this.simidProtocol.reject(eventData, {errorCode: CreativeErrorCode.CREATIVE_INTERNAL_ERROR,
67 | message: "Invalid JSON input for ad parameters"});
68 | return;
69 | }
70 | this.buttonLabel_ = adParams[AdParamKeys.BUTTON_LABEL];
71 | this.query_ = adParams[AdParamKeys.SEARCH_QUERY];
72 | this.markerUrl_ = adParams[AdParamKeys.MARKER];
73 | this.coordinates_ = adParams[AdParamKeys.COORDINATES];
74 |
75 | if (!this.query_) {
76 | this.simidProtocol.reject(eventData, {errorCode: CreativeErrorCode.UNSPECIFIED,
77 | message: `Required field ${AdParamKeys.SEARCH_QUERY} not found`});
78 | return;
79 | }
80 | this.simidProtocol.resolve(eventData, {});
81 | }
82 |
83 | /** @override */
84 | onStart(eventData) {
85 | super.onStart(eventData);
86 | this.specifyButtonFeatures_(this.buttonLabel_);
87 | }
88 |
89 | /**
90 | * Sets the text of the Find Nearest button and assigns it a click functionality.
91 | * @param {string=} buttonLabel Refers to the value given to the BUTTON_LABEL key in
92 | * the AdParamKeys object. The value should be representative of the advertised product's
93 | * category and can be specified by the advertisers. If the value is not specified,
94 | * then BUTTON_LABEL's value will default to Location.
95 | * @private
96 | */
97 | specifyButtonFeatures_(buttonLabel = DEFAULT_BUTTON_LABEL) {
98 | const findNearestButton = document.getElementById('findNearest');
99 | findNearestButton.innerText = FIND_NEAREST_TEMPLATE_TEXT + buttonLabel;
100 | findNearestButton.focus();
101 | findNearestButton.onclick = () => this.prepareCreative_();
102 | }
103 |
104 | prepareCreative_() {
105 | findNearest.classList.add("hidden");
106 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_PAUSE).then(() => {
107 | const onMapsClientComplete = () => {this.playAd_()};
108 | this.createMapState_();
109 | this.googleMapsClient_ = new GoogleMapsClient(this.query_,
110 | this.markerUrl_, this.simidProtocol, onMapsClientComplete, document.getElementById(TRAVEL_METHOD),
111 | document.getElementById(TIME_DISPLAY), this.coordinates_);
112 | this.googleMapsClient_.displayMap(document.getElementById('map'));
113 | this.googleMapsClient_.addMapListener();
114 | }).catch(() => {
115 | const pauseErrorMessage = {
116 | message: "WARNING: Request to pause ad failed",
117 | };
118 | this.simidProtocol.sendMessage(CreativeMessage.LOG, pauseErrorMessage);
119 | });
120 | }
121 |
122 | /**
123 | * Creates the Skip To Content and Return To Ad buttons once the user
124 | * grants permission to access their location and the map appears.
125 | * @private
126 | */
127 | createMapState_() {
128 | const returnToAdButton = document.createElement("button");
129 | returnToAdButton.textContent = "Return To Ad";
130 | returnToAdButton.id = "returnToAd";
131 | returnToAdButton.focus();
132 | returnToAdButton.onclick = () => this.playAd_(returnToAdButton);
133 |
134 | const skipAdButton = document.createElement("button");
135 | skipAdButton.id = "skipAd";
136 | skipAdButton.textContent = "Skip Ad";
137 | skipAdButton.onclick = () => this.playContent_();
138 |
139 | const adContainer = document.getElementById('adContainer');
140 | adContainer.appendChild(returnToAdButton);
141 | adContainer.appendChild(skipAdButton);
142 | this.createTravelDisplay_();
143 | }
144 |
145 | /**
146 | * Creates an option element representing a mode of travel.
147 | * @param {!string} travelMode A string representing the
148 | * given mode of travel.
149 | * @private
150 | */
151 | createTravelOption_(travelMode) {
152 | const travelOption = document.createElement("option");
153 | travelOption.value = travelMode.toUpperCase();
154 | travelOption.text = travelMode;
155 | return travelOption;
156 | }
157 |
158 | /**
159 | * Creates a drop down menu where users can choose between
160 | * different modes of travel to display directions for, and
161 | * creates area for travel time to be displayed.
162 | * @private
163 | */
164 | createTravelDisplay_() {
165 | const travelChoicesContainer = document.getElementById('adContainer');
166 | const travelMethod = document.createElement('select');
167 | travelMethod.id = TRAVEL_METHOD;
168 | const timeDisplay = document.createElement("div");
169 | timeDisplay.id = TIME_DISPLAY;
170 | TRANSPORT_METHODS.forEach((transportType) => {
171 | const newOption = this.createTravelOption_(transportType);
172 | travelMethod.add(newOption);
173 | });
174 | travelChoicesContainer.append(travelMethod);
175 | travelChoicesContainer.append(timeDisplay);
176 | }
177 |
178 | /**
179 | * Continues to play the ad if user clicks on Return To Ad button.
180 | * @param {!Element} returnToAdButton Refers to the button that takes
181 | * a user back to the video ad.
182 | * @private
183 | */
184 | playAd_(returnToAdButton) {
185 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_PLAY);
186 | returnToAdButton.classList.add("hidden");
187 | const mapDiv = document.getElementById("map");
188 | mapDiv.classList.add("hidden");
189 | const travelDisplay = document.getElementById(TRAVEL_METHOD);
190 | const timeDisplay = document.getElementById(TIME_DISPLAY);
191 | travelDisplay.classList.add("hidden");
192 | timeDisplay.classList.add("hidden");
193 | }
194 |
195 | /**
196 | * Returns to video content if user clicks on Skip To Content button.
197 | * @private
198 | */
199 | playContent_() {
200 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_SKIP);
201 | }
202 | }
--------------------------------------------------------------------------------
/examples/creatives/simid_overlay.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Sample Simid Ad
23 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/examples/creatives/simid_overlay.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A sample SIMID ad that shows an overlay
3 | */
4 | class SimidOverlay extends BaseSimidCreative {
5 | constructor() {
6 | super();
7 |
8 | this.informationElem_ = document.getElementById('information');
9 |
10 | this.addButtonClickActions_();
11 | }
12 |
13 | /** @override */
14 | onTimeUpdate(data) {
15 | super.onTimeUpdate(data);
16 | this.informationElem_.innerHTML = 'Current Ad Time ' + this.videoState.currentTime;
17 | }
18 |
19 | /**
20 | * Adds actions to different buttons available on the overlay.
21 | */
22 | addButtonClickActions_() {
23 | this.sendMessageOnButtonClick_('request_play', CreativeMessage.REQUEST_PLAY);
24 | this.sendMessageOnButtonClick_('request_pause', CreativeMessage.REQUEST_PAUSE);
25 | this.sendMessageOnButtonClick_('request_full_screen', CreativeMessage.REQUEST_FULL_SCREEN);
26 | this.sendMessageOnButtonClick_('fatal_error', CreativeMessage.FATAL_ERROR);
27 | this.sendMessageOnButtonClick_('request_skip', CreativeMessage.REQUEST_SKIP);
28 | this.sendMessageOnButtonClick_('request_stop', CreativeMessage.REQUEST_STOP);
29 | this.sendMessageOnLog_();
30 | this.sendMessageOnChangeDurationClick_();
31 | }
32 |
33 | /**
34 | * Listens for a click event on a button
35 | * @param {String} elementName The name of the element.
36 | * @param {String} message The message to send to the player.
37 | * @private
38 | */
39 | sendMessageOnButtonClick_(elementName, message) {
40 | const sendMessageFunction = () => {this.simidProtocol.sendMessage(message);}
41 | document.getElementById(elementName).addEventListener(
42 | 'click', sendMessageFunction.bind(this));
43 | }
44 |
45 | /**
46 | * Listens for a click event on the log button and sends the
47 | * message contained in the input field to the player.
48 | * @private
49 | */
50 | sendMessageOnLog_() {
51 | const sendLogFunction = () => {
52 | const logInputMessage = document.getElementById('log_input').value;
53 | const logMessage = {
54 | message: logInputMessage,
55 | };
56 | this.simidProtocol.sendMessage(CreativeMessage.LOG, logMessage);
57 | }
58 | document.getElementById('log_button').addEventListener(
59 | 'click', sendLogFunction.bind(this));
60 | }
61 |
62 | sendMessageOnChangeDurationClick_() {
63 | const sendAdDurationFunction = () => {
64 | const durationInput = document.getElementById('change_duration_input').value;
65 | const params = {
66 | 'duration': durationInput,
67 | };
68 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_CHANGE_AD_DURATION, params).catch(() => {
69 | console.log('Player does not support requested duration change.');
70 | });
71 | }
72 | document.getElementById('change_duration_button').addEventListener(
73 | 'click', sendAdDurationFunction.bind(this));
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/examples/creatives/survey.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
56 |
57 |
58 |
59 |
60 |
61 |
Sample SIMID Survey Ad
62 |
63 |
64 |
65 |
66 |
67 |
68 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/examples/creatives/survey.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A sample SIMID ad that shows how to impliment a survey.
3 | */
4 | class SimidSurvey extends BaseSimidCreative {
5 | constructor() {
6 | super();
7 |
8 | /**
9 | * The current Question being asked.
10 | * @private
11 | */
12 | this.currentQuestion_ = -1;
13 |
14 | /**
15 | * A list of questions to be asked. Default is no questions.
16 | * @private
17 | */
18 | this.surveyQuestions_ = [];
19 |
20 | // listen to all buttons.
21 | for (let i = 0; i <= 2; i++) {
22 | const button = document.getElementById('option' + i);
23 | if (button) {
24 | // This examples just shows the next question. A true
25 | // implementation would record answers somehow.
26 | button.onclick = this.showNextQuestion.bind(this);
27 | }
28 | }
29 | }
30 |
31 | /**
32 | * Shows the current question
33 | */
34 | showQuestion() {
35 | const questionData = this.surveyQuestions_[this.currentQuestion_];
36 | const questionElement = document.getElementById('current-question');
37 | questionElement.innerHTML = questionData.question;
38 | for (let i = 0; i <= 2; i++) {
39 | const button = document.getElementById('option' + i);
40 | button.innerHTML = questionData.answers[i];
41 | }
42 | document.getElementById('question').classList.add('showing');
43 | }
44 |
45 | /** @override */
46 | onStart(eventData) {
47 | super.onStart(eventData);
48 | this.surveyQuestions_ = JSON.parse(this.creativeData.adParameters);
49 | this.showNextQuestion();
50 | }
51 |
52 | /**
53 | * Shows the next question.
54 | */
55 | showNextQuestion() {
56 | document.getElementById('question').classList.remove('showing');
57 | this.currentQuestion_ ++;
58 | if (this.currentQuestion_ >= this.surveyQuestions_.length) {
59 | // If the user answers all the questions skip the rest of the ad.
60 | this.simidProtocol.sendMessage(CreativeMessage.REQUEST_SKIP);
61 | return;
62 | }
63 | setTimeout(() => this.showQuestion(), 1000);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/examples/creatives/testers_nonlinear.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
94 |
--------------------------------------------------------------------------------
/examples/creatives/testers_nonlinear.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A sample SIMID nonlinear ad that shows an overlay of
3 | * buttons to showcase functionality
4 | */
5 | class TestersNonLinear extends BaseSimidCreative {
6 | constructor() {
7 | super();
8 |
9 | this.addButtonClickActions_();
10 | }
11 |
12 | /**
13 | * Adds actions to different buttons available on the overlay.
14 | */
15 | addButtonClickActions_() {
16 | this.sendMessageOnButtonClick_("close_ad", CreativeMessage.REQUEST_STOP);
17 | this.sendMessageOnButtonClick_("expand_button", CreativeMessage.EXPAND_NONLINEAR);
18 | this.sendMessageOnButtonClick_("collapse_button", CreativeMessage.COLLAPSE_NONLINEAR);
19 | }
20 |
21 | /**
22 | * Listens for a click event on a button
23 | * @param {String} elementName The name of the element.
24 | * @param {String} message The message to send to the player.
25 | * @private
26 | */
27 | sendMessageOnButtonClick_(elementName, message) {
28 | const sendMessageFunction = () => {this.simidProtocol.sendMessage(message);}
29 | document.getElementById(elementName).addEventListener(
30 | 'click', sendMessageFunction.bind(this));
31 | }
32 |
33 | /** When creative asks to resize itself, this sends a message to the player. */
34 | onRequestResize() {
35 | const creativeDimensions = {};
36 |
37 | creativeDimensions.x = document.getElementById('resize_x_val').value;
38 | creativeDimensions.y = document.getElementById('resize_y_val').value;
39 | creativeDimensions.width = document.getElementById('resize_width').value;
40 | creativeDimensions.height = document.getElementById('resize_height').value;
41 |
42 | const resizeParams = {
43 | videoDimensions: this.environmentData.videoDimensions,
44 | creativeDimensions: creativeDimensions
45 | };
46 |
47 | this.requestResize(resizeParams);
48 | }
49 | }
--------------------------------------------------------------------------------
/examples/media/Big_Buck_Bunny.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/Big_Buck_Bunny.mp4
--------------------------------------------------------------------------------
/examples/media/IAB.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/IAB.mp4
--------------------------------------------------------------------------------
/examples/media/IAB480-small.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/IAB480-small.mp4
--------------------------------------------------------------------------------
/examples/media/IAB480-smaller.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/IAB480-smaller.mp4
--------------------------------------------------------------------------------
/examples/media/IAB480.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/IAB480.mp4
--------------------------------------------------------------------------------
/examples/media/LearnMoreEndCard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/LearnMoreEndCard.jpg
--------------------------------------------------------------------------------
/examples/media/black_countdown.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/black_countdown.mp4
--------------------------------------------------------------------------------
/examples/media/fakeAd.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/fakeAd.mp4
--------------------------------------------------------------------------------
/examples/media/fakeContent.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/fakeContent.mp4
--------------------------------------------------------------------------------
/examples/media/shortAd.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/shortAd.mp4
--------------------------------------------------------------------------------
/examples/media/sintel_trailer-480p.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/sintel_trailer-480p.mp4
--------------------------------------------------------------------------------
/examples/media/visitSiteEndCard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/InteractiveAdvertisingBureau/SIMID/897a2a738c5310871c1a3fe67410ba74a96f5b97/examples/media/visitSiteEndCard.jpg
--------------------------------------------------------------------------------
/examples/player/simid_player.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | A very simple SIMID player
4 |
5 |
6 |
34 |
214 |
215 |
216 |
217 |
218 |