├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── MAINTAINING.md ├── README.md ├── icon.png ├── index.html ├── package.json ├── releng ├── arch │ ├── PKGBUILD │ ├── pack.sh │ ├── twd │ └── twd.desktop └── pack.sh ├── stage.css └── stage.js /.gitignore: -------------------------------------------------------------------------------- 1 | .*.sw* 2 | .DS_Store 3 | ~* 4 | node_modules 5 | *.nw 6 | /build 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 6 | 7 | Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 8 | 9 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 10 | 11 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 12 | 13 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 14 | 15 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The icon.png file is copyright Twitter, Inc. 2 | Every other file is released in the Public Domain. 3 | See https://passcod.name/PUBLIC.txt 4 | 5 | --- 6 | 7 | Public Domain Dedication (CC0 v1.0) 8 | https://creativecommons.org/publicdomain/zero/1.0/ 9 | 10 | 11 | This work is dedicated to the Public Domain; the author waives all of his 12 | or her rights to the work worldwide under copyright law, including all 13 | related and neighboring rights, to the extent allowed by law. 14 | 15 | 16 | == For Humans == 17 | 18 | You can copy, modify, distribute and perform the work, even for commercial 19 | purposes, all without asking permission. 20 | 21 | In no way are the patent or trademark rights of any person affected by 22 | CC0, nor are the rights that other persons may have in the work or in how 23 | the work is used, such as publicity or privacy rights. 24 | 25 | Unless expressly stated otherwise, the person who associated a work with 26 | this deed makes no warranties about the work, and disclaims liability for 27 | all uses of the work, to the fullest extent permitted by applicable law. 28 | 29 | When using or citing the work, you should not imply endorsement by the 30 | author or the affirmer. 31 | 32 | 33 | == Legal Code == 34 | 35 | CC0 1.0 Universal 36 | 37 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 38 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 39 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 40 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 41 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 42 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 43 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 44 | HEREUNDER. 45 | 46 | Statement of Purpose 47 | 48 | The laws of most jurisdictions throughout the world automatically confer 49 | exclusive Copyright and Related Rights (defined below) upon the creator 50 | and subsequent owner(s) (each and all, an "owner") of an original work of 51 | authorship and/or a database (each, a "Work"). 52 | 53 | Certain owners wish to permanently relinquish those rights to a Work for 54 | the purpose of contributing to a commons of creative, cultural and 55 | scientific works ("Commons") that the public can reliably and without fear 56 | of later claims of infringement build upon, modify, incorporate in other 57 | works, reuse and redistribute as freely as possible in any form whatsoever 58 | and for any purposes, including without limitation commercial purposes. 59 | These owners may contribute to the Commons to promote the ideal of a free 60 | culture and the further production of creative, cultural and scientific 61 | works, or to gain reputation or greater distribution for their Work in 62 | part through the use and efforts of others. 63 | 64 | For these and/or other purposes and motivations, and without any 65 | expectation of additional consideration or compensation, the person 66 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 67 | is an owner of Copyright and Related Rights in the Work, voluntarily 68 | elects to apply CC0 to the Work and publicly distribute the Work under its 69 | terms, with knowledge of his or her Copyright and Related Rights in the 70 | Work and the meaning and intended legal effect of CC0 on those rights. 71 | 72 | 1. Copyright and Related Rights. A Work made available under CC0 may be 73 | protected by copyright and related or neighboring rights ("Copyright and 74 | Related Rights"). Copyright and Related Rights include, but are not 75 | limited to, the following: 76 | 77 | i. the right to reproduce, adapt, distribute, perform, display, 78 | communicate, and translate a Work; 79 | ii. moral rights retained by the original author(s) and/or performer(s); 80 | iii. publicity and privacy rights pertaining to a person's image or 81 | likeness depicted in a Work; 82 | iv. rights protecting against unfair competition in regards to a Work, 83 | subject to the limitations in paragraph 4(a), below; 84 | v. rights protecting the extraction, dissemination, use and reuse of data 85 | in a Work; 86 | vi. database rights (such as those arising under Directive 96/9/EC of the 87 | European Parliament and of the Council of 11 March 1996 on the legal 88 | protection of databases, and under any national implementation 89 | thereof, including any amended or successor version of such 90 | directive); and 91 | vii. other similar, equivalent or corresponding rights throughout the 92 | world based on applicable law or treaty, and any national 93 | implementations thereof. 94 | 95 | 2. Waiver. To the greatest extent permitted by, but not in contravention 96 | of, applicable law, Affirmer hereby overtly, fully, permanently, 97 | irrevocably and unconditionally waives, abandons, and surrenders all of 98 | Affirmer's Copyright and Related Rights and associated claims and causes 99 | of action, whether now known or unknown (including existing as well as 100 | future claims and causes of action), in the Work (i) in all territories 101 | worldwide, (ii) for the maximum duration provided by applicable law or 102 | treaty (including future time extensions), (iii) in any current or future 103 | medium and for any number of copies, and (iv) for any purpose whatsoever, 104 | including without limitation commercial, advertising or promotional 105 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 106 | member of the public at large and to the detriment of Affirmer's heirs and 107 | successors, fully intending that such Waiver shall not be subject to 108 | revocation, rescission, cancellation, termination, or any other legal or 109 | equitable action to disrupt the quiet enjoyment of the Work by the public 110 | as contemplated by Affirmer's express Statement of Purpose. 111 | 112 | 3. Public License Fallback. Should any part of the Waiver for any reason 113 | be judged legally invalid or ineffective under applicable law, then the 114 | Waiver shall be preserved to the maximum extent permitted taking into 115 | account Affirmer's express Statement of Purpose. In addition, to the 116 | extent the Waiver is so judged Affirmer hereby grants to each affected 117 | person a royalty-free, non transferable, non sublicensable, non exclusive, 118 | irrevocable and unconditional license to exercise Affirmer's Copyright and 119 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 120 | maximum duration provided by applicable law or treaty (including future 121 | time extensions), (iii) in any current or future medium and for any number 122 | of copies, and (iv) for any purpose whatsoever, including without 123 | limitation commercial, advertising or promotional purposes (the 124 | "License"). The License shall be deemed effective as of the date CC0 was 125 | applied by Affirmer to the Work. Should any part of the License for any 126 | reason be judged legally invalid or ineffective under applicable law, such 127 | partial invalidity or ineffectiveness shall not invalidate the remainder 128 | of the License, and in such case Affirmer hereby affirms that he or she 129 | will not (i) exercise any of his or her remaining Copyright and Related 130 | Rights in the Work or (ii) assert any associated claims and causes of 131 | action with respect to the Work, in either case contrary to Affirmer's 132 | express Statement of Purpose. 133 | 134 | 4. Limitations and Disclaimers. 135 | 136 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 137 | surrendered, licensed or otherwise affected by this document. 138 | b. Affirmer offers the Work as-is and makes no representations or 139 | warranties of any kind concerning the Work, express, implied, 140 | statutory or otherwise, including without limitation warranties of 141 | title, merchantability, fitness for a particular purpose, non 142 | infringement, or the absence of latent or other defects, accuracy, or 143 | the present or absence of errors, whether or not discoverable, all to 144 | the greatest extent permissible under applicable law. 145 | c. Affirmer disclaims responsibility for clearing rights of other persons 146 | that may apply to the Work or any use thereof, including without 147 | limitation any person's Copyright and Related Rights in the Work. 148 | Further, Affirmer disclaims responsibility for obtaining any necessary 149 | consents, permissions or other rights required for any use of the 150 | Work. 151 | d. Affirmer understands and acknowledges that Creative Commons is not a 152 | party to this document and has no duty or obligation with respect to 153 | this CC0 or use of the Work. 154 | -------------------------------------------------------------------------------- /MAINTAINING.md: -------------------------------------------------------------------------------- 1 | # Maintaining this project 2 | 3 | This living document outlines what a maintainer should do when working on or 4 | around this project. It is here both as written down guidelines for existing 5 | maintainers, and as an introduction for new or prospective maintainers. 6 | 7 | **This project is also looking for a new maintainer.** The current maintainer 8 | does not have the time nor willingness to maintain this with the alacrity and 9 | care it deserves. If you are willing, they will be very happy to hand you 10 | commit and publish access. Ask! 11 | 12 | - [The project](#the-project) 13 | - [Description](#description) 14 | - [Vision](#vision) 15 | - [The specifics](#the-specifics) 16 | - [Release process](#release-process) 17 | - [The community](#the-community) 18 | - [Conduct](#conduct) 19 | - [Growth](#growth) 20 | - [Contact](#contact) 21 | - [About](#about) 22 | 23 | ## The project 24 | 25 | ### Description 26 | 27 | twd is a [Tweetdeck] wrapper for desktop use, powered by [NW.js]. At time of 28 | creation, Tweetdeck had retired all of its desktop applications, leaving users 29 | who wanted tweetdeck as a standalone application the only choice to run it in 30 | their browser, either as a separate window or just a tab. twd was born to 31 | remedy this problem for all platforms: Windows, Linux, Mac. The name is a 32 | short, consonant-only contraction, that has just enough and just the right 33 | letters that it can be recognised as standing for "Tweetdeck". 34 | 35 | While twd was the first, sister projects initially based on the same code were 36 | created later. [slk] was a [Slack] wrapper for Linux Desktop, from before Slack 37 | for Linux Beta was released. [kndl] is a [Kindle Cloud Reader] wrapper. You are 38 | not expected to maintain kndl as well as twd, but you may if you wish to. 39 | 40 | [Tweetdeck]: https://tweetdeck.twitter.com/ 41 | [NW.js]: https://github.com/nwjs/nw.js 42 | [slk]: https://github.com/passcod/slk 43 | [Slack]: https://slack.com/ 44 | [kndl]: https://github.com/passcod/kndl 45 | [Kindle Cloud Reader]: https://read.amazon.com/ 46 | 47 | ### Vision 48 | 49 | No particular vision, but two wishes: 50 | 51 | - Possibly wanting to share some code between twd and kndl, for ease of 52 | maintaining them and/or public benefit so more wrappers could be created. 53 | 54 | - Also wanting to write scripts and/or set up CIs to build and publish binaries 55 | for distribution to all three major platforms, as well as updating 56 | repositories, e.g. [AUR], an Ubuntu/Debian [PPA], a [Homebrew Cask] formula, 57 | a [Chocolatey] distribution. 58 | 59 | [AUR]: https://aur.archlinux.org/ 60 | [PPA]: https://launchpad.net/ubuntu/+ppas 61 | [Homebrew Cask]: https://caskroom.github.io/ 62 | [Chocolatey]: https://chocolatey.org/ 63 | 64 | ## The specifics 65 | 66 | ### Release process 67 | 68 | Tag the release: 69 | 70 | 1. Run `npm version ` with the appropriate level, following semver 71 | 2. Run `git push; git push --tags` 72 | 73 | Generate binaries: 74 | 75 | 1. Download the latest NW.js for all supported platforms 76 | 2. Package the source files 77 | 3. Add them to the NW.js binaries / distributions 78 | 4. Package the binaries: 79 | - tar.gz for Linux 80 | - zip for Windows and OS X 81 | 82 | Create the release: 83 | 84 | 1. Go to https://github.com/passcod/twd/releases 85 | 2. Draft a new release for the new tag 86 | 3. Upload the binaries 87 | 88 | Tweet about it! 89 | 90 | ## The community 91 | 92 | ### Conduct 93 | 94 | This project has a Code of Conduct. Maintainers are expected not only to abide 95 | by it to maintain a community that is safe and welcoming for all, but also to 96 | help in its enforcement. 97 | 98 | Enforcement sounds scary! It need not be: it can be as simple as reminding 99 | people to be kind, asking for harmful wording to be edited in comments, or 100 | contacting people privately to call them out on unfriendly behaviour and ask 101 | them to stop. 102 | 103 | If offences are more severe, though, it is expected that maintainers help by 104 | locking threads, reporting the offending parties, and/or enforcing temporary or 105 | permanent bans. 106 | 107 | Maintainers may also offer support to affected parties and re-affirm our 108 | commitment to providing a safe environment. 109 | 110 | ### Growth 111 | 112 | Much like this document is intended to help existing and new maintainers to 113 | maintain the project as best as they can, so should maintainers look for 114 | additional help, maintainers, contributors, etc as the project grows. 115 | 116 | You can give people commit access fairly easily: it can always be revoked if 117 | needed, and git keeps history fairly secure, especially as it is distributed 118 | over all contributors' computers. 119 | 120 | ## Contact 121 | 122 | If you wish to become a maintainer, or you want to contact us for some other 123 | reason, you can either send an email to the owner of the project 124 | (felix@passcod.name) or another existing maintainer, or you can open an issue 125 | on this repository. 126 | 127 | If you want to suggest changes to this document, either open an issue or 128 | propose a change using a Pull Request directly. 129 | 130 | ## About 131 | 132 | The ideas for this document came about from various discussions with and around 133 | the developer community. In particular, I would like to thank @zkat, 134 | @charlotteis, and @adampowers of the [WeAllJS](https://wealljs.org/) community. 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # twd 2 | 3 | _TweetDeck wrapper for use as desktop app._ 4 | 5 | ![Screenshot](https://stuff.passcod.name/humgur/code/twd.png) 6 | 7 | Uses [node-webkit] to provide a single-purpose window 8 | onto TweetDeck's web version. Min-width = single-col. 9 | 10 | Will not work with node-webkit < 0.10. 11 | 12 | [node-webkit]: https://github.com/rogerwang/node-webkit 13 | [release]: https://github.com/passcod/twd/releases 14 | 15 | ## running… 16 | 17 | ### …from source: 18 | 19 | ```bash 20 | $ $package_manager install node-webkit 21 | $ git clone git://github.com/passcod/twd.git 22 | $ cd twd 23 | $ nw . 24 | ``` 25 | 26 | ### ~~…on archlinux:~~ 27 | 28 | There is currently no Arch Linux package, but if someone creates it I'll be glad to link it again. 29 | 30 | ~~[AUR package](https://aur.archlinux.org/packages/twd)~~ 31 | 32 | ```bash 33 | $ yaourt -S twd 34 | $ twd 35 | ``` 36 | 37 | A `.desktop` file (for graphical menus) is also provided 38 | (see [releng/arch/twd.desktop](releng/arch/twd.desktop)). 39 | 40 | ## legal 41 | 42 | TweetDeck, Twitter, and the TweetDeck logo are trademarks 43 | of, and copyrighted to, Twitter, Inc. 44 | 45 | All other files are released in the Public Domain as per 46 | my [policy](https://passcod.name/PUBLIC.txt). 47 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/passcod/twd/b94878084745f7f4436bcfd661852e69f6994429/icon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twd", 3 | "version": "1.3.0", 4 | "description": "(Browser-)Chrome-less TweetDeck", 5 | "keywords": [ 6 | "node-webkit", 7 | "tweetdeck", 8 | "twitter", 9 | "app" 10 | ], 11 | "homepage": "https://github.com/passcod/twd", 12 | "author": "Félix Saparelli ", 13 | "contributors": [ 14 | { 15 | "name": "Félix Saparelli", 16 | "email": "twd@passcod.name" 17 | }, 18 | { 19 | "name": "Janis Jansons", 20 | "email": "janis.jansons@janhouse.lv" 21 | }, 22 | { 23 | "name": "Richard Denton", 24 | "email": "isdampe@gmail.com" 25 | }, 26 | { 27 | "name": "André 'MKody' Fernandes", 28 | "email": "im@kdy.ch" 29 | }, 30 | { 31 | "name": "Resi Respati", 32 | "email": "resir014@gmail.com" 33 | } 34 | ], 35 | "license": { 36 | "type": "Public Domain", 37 | "url": "https://passcod.name/PUBLIC.txt" 38 | }, 39 | "repository": { 40 | "type": "git", 41 | "url": "https://github.com/passcod/twd.git" 42 | }, 43 | "engines": { 44 | "node-webkit": ">=0.10.0" 45 | }, 46 | "main": "index.html", 47 | "nodejs": true, 48 | "single-instance": true, 49 | "user-agent": "Mozilla/5.0 (%osinfo) WebKit/%webkit_ver NodeWebkit/%nwver twd/%version", 50 | "window": { 51 | "icon": "icon.png", 52 | "toolbar": false, 53 | "height": 700, 54 | "width": 900, 55 | "min_width": 370, 56 | "title": "TweetDeck", 57 | "position": "center", 58 | "resizable": true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /releng/arch/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Félix Saparelli 2 | # Contributor: Aki Jenkinson 3 | pkgname=twd 4 | pkgver=%version 5 | pkgrel=1 6 | pkgdesc="%description" 7 | arch=("any") 8 | url="https://github.com/passcod/twd" 9 | license=("Public Domain") 10 | depends=("node-webkit") 11 | source=("https://github.com/passcod/twd/releases/download/v${pkgver}/twd-${pkgver}-all.nw") 12 | noextract=("twd-${pkgver}-all.nw") 13 | sha512sums=("%checksum") 14 | 15 | build() { 16 | cd $srcdir 17 | cp twd-${pkgver}-all.nw assets.zip 18 | unzip assets.zip 19 | } 20 | 21 | package() { 22 | cd $srcdir 23 | install -Dm644 twd-${pkgver}-all.nw $pkgdir/opt/twd/twd.nw 24 | install -Dm644 LICENSE $pkgdir/usr/share/licences/twd/LICENSE 25 | install -Dm644 icon.png $pkgdir/usr/share/pixmaps/twd.png 26 | install -Dm755 releng/arch/twd $pkgdir/usr/bin/twd 27 | install -Dm644 releng/arch/twd.desktop $pkgdir/usr/share/applications/twd.desktop 28 | } 29 | -------------------------------------------------------------------------------- /releng/arch/pack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | cd ../.. 4 | version=$(grep '"version"' package.json | cut -d\" -f4) 5 | description=$(grep '"description"' package.json | cut -d\" -f4) 6 | checksum=$(sha512sum build/twd-$version-all.nw | cut -d\ -f1) 7 | 8 | mkdir -p build/arch 9 | cp releng/arch/PKGBUILD build/arch/ 10 | cp build/twd-$version-all.nw build/arch/ 11 | 12 | cd build/arch 13 | sed -i "s/%version/$version/" PKGBUILD 14 | sed -i "s/%description/$description/" PKGBUILD 15 | sed -i "s/%checksum/$checksum/" PKGBUILD 16 | 17 | mkaurball -f 18 | -------------------------------------------------------------------------------- /releng/arch/twd: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | nw /opt/twd/twd.nw $@ 3 | -------------------------------------------------------------------------------- /releng/arch/twd.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Version=1.0 4 | Type=Application 5 | Exec=/usr/bin/nw /opt/twd/twd.nw 6 | Name=TweetDeck 7 | Icon=twd 8 | Categories=Network; 9 | -------------------------------------------------------------------------------- /releng/pack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | if pwd | rev | cut -d/ -f1 | grep -q gneler; then 4 | cd .. 5 | else 6 | echo "Fatal: must be run from releng." 7 | exit 1 8 | fi 9 | 10 | mkdir -p build 11 | version=$(grep '"version"' package.json | cut -d\" -f4) 12 | git ls-files | xargs zip -9 build/twd-$version-all.nw 13 | 14 | cd releng/arch && ./pack.sh 15 | -------------------------------------------------------------------------------- /stage.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | width: 100%; 4 | margin: 0; 5 | overflow: hidden; 6 | position: fixed; 7 | } 8 | 9 | iframe { 10 | border-style: none; 11 | min-height: 100%; 12 | width: 100%; 13 | } 14 | -------------------------------------------------------------------------------- /stage.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var gui = require('nw.gui'); 3 | var iframe = document.querySelector('iframe'); 4 | var win = gui.Window.get(); 5 | 6 | var handleClick = function(e) { 7 | var checkForLink = function(el) { 8 | var openLink = function(url) { 9 | gui.Shell.openExternal(url); 10 | e.preventDefault(); 11 | }; 12 | 13 | if (el.nodeName.toLowerCase() === 'a') { 14 | var href = el.getAttribute('href'); 15 | if (href !== null) { 16 | var middleButton = e.which === 2; 17 | if (middleButton || 18 | (el.target === '_blank' && 19 | el.rel !== 'user' && 20 | el.rel !== 'mediaPreview')) { 21 | openLink(href); 22 | } 23 | 24 | console.log(href, middleButton, el.target, el.rel); 25 | } 26 | } else if ((p = el.parentElement) !== null) { 27 | checkForLink(p); 28 | } 29 | }; 30 | 31 | checkForLink(e.target); 32 | }; 33 | 34 | var zoom = function () { win.zoomLevel += 1; } 35 | var unzoom = function () { win.zoomLevel -= 1; } 36 | var resetZoom = function () { win.zoomLevel = 0; } 37 | 38 | var handleKeydown = function (e) { 39 | if (e.ctrlKey) { 40 | if (e.keyCode == 187) zoom(); 41 | else if (e.keyCode == 189) unzoom(); 42 | else if (e.keyCode == 48) resetZoom(); 43 | } 44 | }; 45 | 46 | var init = function() { 47 | if (iframe && 48 | iframe.contentWindow && 49 | iframe.contentWindow.document && 50 | iframe.contentWindow.document.body && 51 | iframe.contentWindow.document.body.innerHTML) { 52 | iframe.contentWindow.document.body.addEventListener('click', handleClick, false); 53 | iframe.contentWindow.document.body.addEventListener('keydown', handleKeydown, false); 54 | } else { 55 | setTimeout(init, 100); 56 | } 57 | }; 58 | 59 | init(); 60 | }).apply(this); 61 | --------------------------------------------------------------------------------