├── .editorconfig ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bower.json ├── build.html ├── css ├── font-awesome.min.css ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 └── ml-lodlive.css ├── data └── ieee-skos.xml ├── dist ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── ml-lodlive.all.css ├── ml-lodlive.complete.js ├── ml-lodlive.deps.js ├── ml-lodlive.js └── ml-lodlive.min.js ├── favicon.png ├── gulpfile.js ├── img └── ajax-loader.gif ├── import-rdf.sh ├── index.html ├── js ├── deps │ └── jquery.jcanvas.js ├── lib │ └── lodlive.core.js └── profile │ ├── lodlive.profile-localhost-example.js │ ├── profile.example.js │ └── profile.marklogic.js ├── karma.conf.js ├── lodlive.xqy ├── package.json ├── robots.txt ├── src ├── draggable.js ├── http-client.js ├── ref-store.js ├── renderer.js ├── sparql-client.js └── utils.js ├── test-marklogic.html ├── test ├── fixtures │ ├── basic-results.json │ └── will-smith.json └── spec │ ├── http-client.js │ ├── lodlive.js │ ├── ref-store.js │ └── sparql-client.js └── tester.html /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.project 2 | node_modules/ 3 | ml-lodlive.tar.gz 4 | coverage 5 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "browser": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "immed": true, 7 | "indent": 2, 8 | "latedef": "nofunc", 9 | "newcap": true, 10 | "quotmark": "single", 11 | "undef": true, 12 | "unused": "vars", 13 | "strict": true, 14 | "trailing": true, 15 | "maxerr": 200, 16 | "globals": { 17 | "angular": false, 18 | "google": false, 19 | "$": false, 20 | "jQuery": false, 21 | "console": false, 22 | "alert": false, 23 | "LodLiveUtils": false, 24 | "escape": false, 25 | "unescape": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ml-lodlive 2 | 3 | ml-lodlive welcomes new contributors. This document will guide you 4 | through the process. 5 | 6 | - [Question or Problem?](#question) 7 | - [Issues and Bugs](#issue) 8 | - [Feature Requests](#feature) 9 | - [Submission Guidelines](#submit) 10 | 11 | ## Got a Question or Problem? 12 | 13 | If you have questions about how to use ml-lodlive, check our documentation on the [Wiki][wiki]. Alternatively, check [Stack Overflow][mlstack] to see if it has been answered there, and post your question there if not. Please tag it with MarkLogic, and AngularJS. 14 | 15 | ## Found an Issue? 16 | 17 | If you find a bug in the source code or a mistake in the documentation, you can help us by 18 | submitting an issue to our [GitHub Issue Tracker][issue tracker]. Even better you can submit a Pull Request 19 | with a fix for the issue you filed. 20 | 21 | ## Want a Feature? 22 | 23 | You can request a new feature by submitting an issue to our [GitHub Issue Tracker][issue tracker]. If you 24 | would like to implement a new feature then first create a new issue and discuss it with one of our 25 | project maintainers. 26 | 27 | ## Submission Guidelines 28 | 29 | ### Submitting an Issue 30 | 31 | Before you submit your issue search the archive, maybe your question was already answered. 32 | 33 | If your issue appears to be a bug, and hasn't been reported, open a new issue. 34 | Help us to maximize the effort we can spend fixing issues and adding new 35 | features, by not reporting duplicate issues. Providing the following information will increase the 36 | chances of your issue being dealt with quickly: 37 | 38 | * **Overview of the Issue** - if an error is being thrown a stack trace helps 39 | * **Motivation for or Use Case** - explain why this is a bug for you 40 | * **ml-lodlive Version** - is it a named version or from our master branch 41 | * **Browser** - Chrome, FireFox, Safari? details help 42 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 43 | causing the problem (line of code or commit) 44 | 45 | ### Submitting a Pull Request 46 | 47 | #### Fork ml-lodlive 48 | 49 | Fork the project [on GitHub](https://github.com/withjam/ml-lodlive/fork) and clone 50 | your copy. 51 | 52 | ```sh 53 | $ git clone git@github.com:username/ml-lodlive.git 54 | $ cd ml-lodlive 55 | $ git remote add upstream git://github.com/withjam/ml-lodlive.git 56 | ``` 57 | 58 | All bug fixes and new features go into the master branch. 59 | 60 | We ask that you open an issue in the [issue tracker][] and get agreement from 61 | at least one of the project maintainers before you start coding. 62 | 63 | Nothing is more frustrating than seeing your hard work go to waste because 64 | your vision does not align with that of a project maintainer. 65 | 66 | #### Create a branch for your changes 67 | 68 | Okay, so you have decided to fix something. Create a feature branch 69 | and start hacking: 70 | 71 | ```sh 72 | $ git checkout -b my-feature-branch -t origin/master 73 | ``` 74 | 75 | #### Formatting code 76 | 77 | We use [.editorconfig][] to configure our editors for proper code formatting. If you don't 78 | use a tool that supports editorconfig be sure to configure your editor to use the settings 79 | equivalent to our .editorconfig file. 80 | 81 | #### Commit your changes 82 | 83 | Make sure git knows your name and email address: 84 | 85 | ```sh 86 | $ git config --global user.name "J. Random User" 87 | $ git config --global user.email "j.random.user@example.com" 88 | ``` 89 | 90 | Writing good commit logs is important. A commit log should describe what 91 | changed and why. Follow these guidelines when writing one: 92 | 93 | 1. The first line should be 50 characters or less and contain a short 94 | description of the change including the Issue number prefixed by a hash (#). 95 | 2. Keep the second line blank. 96 | 3. Wrap all other lines at 72 columns. 97 | 98 | A good commit log looks like this: 99 | 100 | ``` 101 | Fixing Issue #123: make the whatchamajigger work in MarkLogic 8 102 | 103 | Body of commit message is a few lines of text, explaining things 104 | in more detail, possibly giving some background about the issue 105 | being fixed, etc etc. 106 | 107 | The body of the commit message can be several paragraphs, and 108 | please do proper word-wrap and keep columns shorter than about 109 | 72 characters or so. That way `git log` will show things 110 | nicely even when it is indented. 111 | ``` 112 | 113 | The header line should be meaningful; it is what other people see when they 114 | run `git shortlog` or `git log --oneline`. 115 | 116 | #### Rebase your repo 117 | 118 | Use `git rebase` (not `git merge`) to sync your work from time to time. 119 | 120 | ```sh 121 | $ git fetch upstream 122 | $ git rebase upstream/master 123 | ``` 124 | 125 | #### Push your changes 126 | 127 | ```sh 128 | $ git push origin my-feature-branch 129 | ``` 130 | 131 | #### Submit the pull request 132 | 133 | Go to https://github.com/username/ml-lodlive and select your feature branch. Click 134 | the 'Pull Request' button and fill out the form. 135 | 136 | Pull requests are usually reviewed within a few days. If you get comments 137 | that need to be to addressed, apply your changes in a separate commit and push that to your 138 | feature branch. Post a comment in the pull request afterwards; GitHub does 139 | not send out notifications when you add commits to existing pull requests. 140 | 141 | That's it! Thank you for your contribution! 142 | 143 | #### After your pull request is merged 144 | 145 | After your pull request is merged, you can safely delete your branch and pull the changes 146 | from the main (upstream) repository: 147 | 148 | * Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows: 149 | 150 | ```shell 151 | git push origin --delete my-feature-branch 152 | ``` 153 | 154 | * Check out the master branch: 155 | 156 | ```shell 157 | git checkout master -f 158 | ``` 159 | 160 | * Delete the local branch: 161 | 162 | ```shell 163 | git branch -D my-feature-branch 164 | ``` 165 | 166 | * Update your master with the latest upstream version: 167 | 168 | ```shell 169 | git pull --ff upstream master 170 | ``` 171 | 172 | [wiki]: https://github.com/withjam/ml-lodlive/wiki 173 | [mlstack]: http://stackoverflow.com/questions/tagged/marklogic 174 | [issue tracker]: https://github.com/withjam/ml-lodlive/issues 175 | [.editorconfig]: http://editorconfig.org/ -------------------------------------------------------------------------------- /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 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ML LodLive 2 | ========= 3 | 4 | An RDF browser capable of consuming and generating SPARQL. Explore connections between nodes in an easy, visual tool that can be dropped into any existing HTML application. Based on the [LodLive](https://github.com/dvcama/LodLive) library 5 | 6 | What's Different 7 | ================ 8 | 9 | The original LodLive library was a complete application with multiple UI screens. It allowed you to select from various SPARQL endpoints, search, and browse. It also included a myriad of third-party dependencies. That version of LodLive has been refactored to be more modular, easier to include in an existing application, and require minimal dependencies. The various components of LodLive are also being isolated so that future enhancement may be possible. 10 | 11 | Dependencies 12 | ============ 13 | 14 | Requires: jQuery > 1.9/2.0 (you must include this in your site if it's not in use already) 15 | 16 | 17 | Installation 18 | ============ 19 | 20 | ml-lodlive has been narrowed down to a minimal set of files for inclusion in any application. The easiest way to get the latest version of ml-lodlive is using bower: 21 | 22 | ``` 23 | bower install --save ml-lodlive 24 | ``` 25 | 26 | Once part of your project, you have only to include the css and js files to get started. If you are using the vanguard team's slush generator then 'wiredep' will take care of this part for you, otherwise add the following components to your index.html page. 27 | 28 | ```html 29 | 30 | 31 | 32 | 33 | 34 | // include jquery before ml-lodlive 35 | 36 | 37 | 38 | ``` 39 | 40 | Profile 41 | ======= 42 | 43 | At first glance, the profile object is a bit overwhelming. However, there are only a few configuration options you need to focus on in order to get ml-lodlive connected. The other options included in the profile help you control the SPARQL queries that are generated - so that you can have it fit your data - and UI elements that will appear such as tool bar icons and any custom functions. 44 | 45 | In order to connect ml-lodlive to your MarkLogic REST server instance, you need to configure: the location of the server, whether or not it will use jsonp, and any additional paramters you need to send. You can use js/profile.marklogic.js as a starting point if you wish, or you can create your own profile object. It is often easiest to load it as a separate file but you can choose to build it programatically as well. 46 | 47 | First, you need to set up your profile's connection endpoint. This is done as follows: 48 | 49 | ```js 50 | MyProfileObject.connection['http:'].endpoint = 'http://my.marklogic.server/lodlive.xqy'; // it can be an absolute path if using jsonp 51 | 52 | MyProfileObject.connection['http:'].endpoint = '/v1/graphs/sparql'; // to use the out-of-the-box MarkLogic SPARQL support 53 | MyProfileObject.connection['http:'].accepts = 'application/sparql-results+json'; // for regular XHR requests be sure to add this header to receive json response 54 | 55 | MyProfileObject.endpoints.jsonp = false | true; // depending on if you are using jsonp 56 | MyProfileObject.endpoints.all = ''; // and additional query params you wish to include in every request 57 | ``` 58 | 59 | With just these options set in your profile object, you should be able to create a new instance of ml-lodlive and see your SPARQL data. The configuration also contains options for coloring nodes, displaying titles, labeling relationship lines, and UI options that can all be tailored to fit your app and your data. 60 | 61 | Initialization 62 | ============== 63 | 64 | In order to create a new instance of ml-lodlive you need two things: a valid profile object (configuration), and a starting iri. Lodlive is designed to allow browsing nodes and relationships in your data, but requires a starting node for context. 65 | 66 | ml-lodlive uses jQuery to create a plugin-style method for attaching an instance to a DOM element. The usage is quite straightforward: 67 | 68 | ```js 69 | jQuery('selector').lodlive({ profile: MyProfileObject, firstUri: 'http://my.first.iri', ignoreBnodes: true }); 70 | ``` 71 | 72 | The firstUri can be any object iri that exists in your triples and can be built programatically. ignoreBnodes is a onetime option that tells the instance to hide or display bnodes as linked relationships. 73 | 74 | This is all it takes to render the initial view of LodLive from which point users can click around relationships to explore your triples data. 75 | 76 | Configuration 77 | ============= 78 | 79 | Configuration is accomplished by the profile object that is passed into the ml-lodlive constructor. It contains the endpoint settings necessary for retrieving data, but offers many customization options. 80 | 81 | SPARQL 82 | ------ 83 | 84 | ml-lodlive generates SPARQL queries for the retrieval of data that is displayed on screen. Each of the SPARQL statements generated can be controlled via the profile. 85 | 86 | ### findSubject 87 | 88 | findSubject is used to display a node in the UI. Through it, ml-lodlive can construct the title and all of the linked relationships. ml-lodlive groups relationships by predicate and will display a grouped icon as a link from the node if there are more than 3 of the same group. 89 | 90 | ### document 91 | 92 | document is used to generate the docInfo properties displayed when clicking the docInfo toolbar. This is an option feature but is useful for viewing details about the node that aren't included in the node rendering. This can be anything from additional names to descriptions, images, or external links. Note that the docInfo viewer is also customizable if your document properties require special treatment on the UI. 93 | 94 | ### inverse 95 | 96 | ml-lodlive can acknowledge inverse relationships if configured to do so. This sparql query will be used to detect if any of the open nodes are inversely related to the current node. 97 | 98 | UI 99 | -- 100 | 101 | Certain UI elements can be configured via the profile. 102 | 103 | ### nodeIcons 104 | 105 | nodeIcons are the top-level icons that are displayed as action items above each node. You can use as many or as few (even 0) as you'd like. There are a few builtin icons that can be used by name, or you can create your own. Using a builtin looks as follows: 106 | 107 | ```js 108 | MyProfileObject.UI.nodeIcons = [{ builtin: 'docInfo'}, { builtin: 'tools' }]; // show docInfo and tools icons 109 | 110 | 111 | MyProfileObject.UI.nodeIcons = [{ builtin: 'tools' }, 112 | { 113 | icon: 'fa fa-circle-o', // icon property is a css class setting that should result in an icon (usually fa or glyphicon) 114 | title: 'My title', // this title property is displayed to the user if they hover over the icon 115 | handler: function(node, instance) { 116 | // your custom function 117 | // node: is the current node DOM object 118 | // instance: is the instance of ml-lodlive 119 | // you can manipulate the properties of the DOM 'node' for a visual effect, generate additional DOM, or interact with the 'instance' of ml-lodlive 120 | } 121 | }] 122 | ``` 123 | 124 | This would create two icons, one for the builtin docInfo function and one for the builtin tools function. Tools is a special function that will display a second-level set of action icons. This is useful for having additional icons while avoiding cluter on the node rendering. The icons displayed via the 'tools' builtin are configured separately. 125 | 126 | ### tools 127 | 128 | Similar to the nodeIcons, tools are a second-level of nodeIcons toggled by clicking the 'tools' nodeIcon. Note that if you configure tools but do not include 'tools' as a nodeIcon, the tools will not be accessible. 129 | 130 | ```js 131 | MyProfileObject.UI.tools = [ { builtin: 'close'}, { builtin: 'rootNode'}, { builtin: 'expand' }]; 132 | ``` 133 | 134 | ### docInfo 135 | 136 | docInfo is a function handler invoked when the user clicks the docInfo nodeIcon. Note that you must include the builtin 'docInfo' in your nodeIcon setup for this to be reached. 137 | 138 | ### nodeHover 139 | 140 | nodeHover is a function handler invoked when the node is hovered via the cursor. You may choose to do something or ignore completely. 141 | 142 | ### relationships 143 | 144 | This allows you to color the related node icons based on a string-match to the predicate. 145 | 146 | ```js 147 | MyProfileObject.UI.relationships: { 148 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': { 149 | color: '#000' 150 | } 151 | } 152 | ``` 153 | 154 | The above example would color each related node circle #000 that was of the predicate 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'. You can do this for as many predicates as you wish. 155 | 156 | 157 | Dataset 158 | ======== 159 | 160 | Included in the repository is a sample of SKOS data. This can be loaded into MarkLogic as RDF triples and can the be exposed via a standard REST application in MarkLogic. If accessing this REST endpoint from a different host or port it will be necessary to install the lodlive.xqy module at the root of the /modules directory for that REST server. Additionally, update your lodlive profile so that the lodlive.xqy url is used as the base. 161 | 162 | License 163 | ======= 164 | 165 | Apache 2.0 166 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ml-lodlive", 3 | "version": "0.4.2", 4 | "homepage": "https://github.com/withjam/ml-lodlive", 5 | "authors": [ 6 | "Matt Pileggi " 7 | ], 8 | "description": "RDF browser and visualization tool. Inspired by the LodLive library but nearly completely rewritten to be easier to add to PoCs and demos", 9 | "main": [ 10 | "css/ml-lodlive.css", 11 | "dist/ml-lodlive.complete.js" 12 | ], 13 | "keywords": [ 14 | "RDF", 15 | "triples", 16 | "MarkLogic", 17 | "LodLive", 18 | "mllodlive" 19 | ], 20 | "license": "Apache-2.0", 21 | "ignore": [ 22 | "**/.*", 23 | "node_modules", 24 | "bower_components", 25 | "test", 26 | "tests" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /build.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LodLive Testing 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */@font-face{font-family:'FontAwesome';src:url('fonts/fontawesome-webfont.eot?v=4.3.0');src:url('fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} -------------------------------------------------------------------------------- /css/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/css/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /css/ml-lodlive.css: -------------------------------------------------------------------------------- 1 | .lodlive-graph-container { 2 | width: 110%; 3 | height: 110%; 4 | overflow: scroll; 5 | background-color: #c7c7c7; 6 | font-family: 'Open Sans', Verdana, sans-serif; 7 | font-size: 10px; 8 | position: relative; 9 | } 10 | 11 | .lodlive-graph-container a, .lodlive-graph-container a:visited { color: #FFF; } 12 | 13 | .lodlive-graph-context { 14 | position: relative; 15 | width: 300%; 16 | height: 300%; 17 | } 18 | 19 | .lodlive-node { 20 | position: absolute; 21 | z-index: 97; 22 | } 23 | 24 | .lodlive-node .ll-node-anchor { 25 | position: relative; 26 | height: 0; 27 | top: 0; 28 | left: 0; 29 | width: 0; 30 | } 31 | 32 | .lodlive-node .lodlive-node-label { 33 | width: 126px; 34 | height: 126px; 35 | position: relative; 36 | border-radius: 65px; 37 | background: none; 38 | background-color: #369; 39 | top: 0; 40 | left: 0; 41 | color: #FFF; 42 | } 43 | 44 | .lodlive-node .boxTitle { 45 | position: relative; 46 | top: 50%; 47 | transform: translateY(-50%); 48 | margin: auto; 49 | height: auto; 50 | line-height: 13px; 51 | width: 90%; 52 | color: #FFF; 53 | text-align: center; 54 | text-overflow: ellipsis; 55 | overflow: hidden; 56 | } 57 | 58 | .lodlive-node .actionBox { 59 | background: #FFF; 60 | box-shadow: 1px 1px 2px; 61 | border-radius: 5px; 62 | cursor: pointer; 63 | position: absolute; 64 | width: 20px; 65 | height: 20px; 66 | border: 0; 67 | z-index: 100; 68 | font-size: 14px; 69 | color: #369; 70 | text-align: center; 71 | line-height: 20px; 72 | } 73 | .lodlive-node .actionBox:nth-last-child(-n+4) { top: -4px; left: 27px; } 74 | .lodlive-node .actionBox:nth-last-child(-n+3) { top: -9px; left: 54px; } 75 | .lodlive-node .actionBox:nth-last-child(-n+2) { top: 0; left: 80px; } 76 | .lodlive-node .actionBox:last-child { top: 18px; left: 104px; } 77 | 78 | .lodlive-node .lodlive-toolbox-wrapper { position: relative; height: 0; width: 0; } 79 | .lodlive-node .lodlive-toolbox { position: absolute; right: -20px; top: -3em; white-space: nowrap; width: auto; } 80 | .lodlive-node .lodlive-toolbox .innerActionBox { background: #FFF; color: #369; display: inline-block; float: none; height: 20px; width: 20px; border-radius: 2px; opacity: 0.75 } 81 | .lodlive-node .lodlive-toolbox .innerActionBox:hover { opacity: 1.0 } 82 | 83 | .lodlive-node .relatedBox, .lodlive-node .groupedRelatedBox { 84 | position: absolute; 85 | z-index: 101; 86 | text-align: center; 87 | cursor: pointer; 88 | color: #369; 89 | } 90 | 91 | .lodlive-node .relatedBox:before { 92 | content: "\f111"; 93 | font-family: FontAwesome; 94 | font-size: 14px; 95 | } 96 | 97 | .lodlive-node .groupedRelatedBox:before { 98 | content: "\f0a3"; 99 | font-family: FontAwesome; 100 | font-size: 16px; 101 | } 102 | .lodlive-node .thisiscsscircle { background: #369; width: 14px; height: 14px; border-radius: 14px; } 103 | 104 | .lodlive-docinfo { 105 | position: absolute; 106 | top: 0; 107 | right: 5px; 108 | max-width: 20%; 109 | max-height: 75%; 110 | overflow: auto; 111 | z-index: 150; 112 | } 113 | .lodlive-docinfo .section { 114 | padding: 0.75em; 115 | background: #FFF; 116 | color: #000; 117 | margin: 1px 0; 118 | font-size: 12px; 119 | } 120 | .lodlive-docinfo .section:first-child { border-radius: 8px 0 0 0; } 121 | .lodlive-docinfo .section:last-child { border-radius: 0 0 0 8px; } 122 | .lodlive-docinfo .section label { font-weight: bold; } 123 | .lodlive-docinfo .section div { text-indent: 2em; margin: 0.5em 0 0; } 124 | 125 | .lodlive-message-container { 126 | position: absolute; 127 | bottom: 0; 128 | left: 0; 129 | z-index: 150; 130 | background-color: #FFF; 131 | padding: 1.25em; 132 | font-size: 13px; 133 | border-radius: 0 8px 0 0; 134 | } 135 | 136 | .lodlive-node.pinned .lodlive-node-label { border: dashed 1px white; background-color: #9CF; } 137 | 138 | .lodlive-node .page .pageNext { 139 | background-position: -1390px -412px; 140 | cursor: pointer; 141 | position: absolute; 142 | width: 16px; 143 | height: 16px; 144 | border: 0; 145 | z-index: 101; 146 | text-align: center; 147 | } 148 | 149 | .lodlive-node .page .pagePrev { 150 | background-position: -1414px -410px; 151 | cursor: pointer; 152 | position: absolute; 153 | width: 16px; 154 | height: 16px; 155 | border: 0; 156 | z-index: 101; 157 | text-align: center; 158 | } 159 | -------------------------------------------------------------------------------- /dist/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/dist/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/dist/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/dist/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/dist/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/dist/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /dist/ml-lodlive.all.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */@font-face{font-family:'FontAwesome';src:url('fonts/fontawesome-webfont.eot?v=4.3.0');src:url('fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} 5 | .lodlive-graph-container { 6 | width: 110%; 7 | height: 110%; 8 | overflow: scroll; 9 | background-color: #c7c7c7; 10 | font-family: 'Open Sans', Verdana, sans-serif; 11 | font-size: 10px; 12 | position: relative; 13 | } 14 | 15 | .lodlive-graph-container a, .lodlive-graph-container a:visited { color: #FFF; } 16 | 17 | .lodlive-graph-context { 18 | position: relative; 19 | width: 300%; 20 | height: 300%; 21 | } 22 | 23 | .lodlive-node { 24 | position: absolute; 25 | z-index: 97; 26 | } 27 | 28 | .lodlive-node .ll-node-anchor { 29 | position: relative; 30 | height: 0; 31 | top: 0; 32 | left: 0; 33 | width: 0; 34 | } 35 | 36 | .lodlive-node .lodlive-node-label { 37 | width: 126px; 38 | height: 126px; 39 | position: relative; 40 | border-radius: 65px; 41 | background: none; 42 | background-color: #369; 43 | top: 0; 44 | left: 0; 45 | color: #FFF; 46 | } 47 | 48 | .lodlive-node .boxTitle { 49 | position: relative; 50 | top: 50%; 51 | transform: translateY(-50%); 52 | margin: auto; 53 | height: auto; 54 | line-height: 13px; 55 | width: 90%; 56 | color: #FFF; 57 | text-align: center; 58 | text-overflow: ellipsis; 59 | overflow: hidden; 60 | } 61 | 62 | .lodlive-node .actionBox { 63 | background: #FFF; 64 | box-shadow: 1px 1px 2px; 65 | border-radius: 5px; 66 | cursor: pointer; 67 | position: absolute; 68 | width: 20px; 69 | height: 20px; 70 | border: 0; 71 | z-index: 100; 72 | font-size: 14px; 73 | color: #369; 74 | text-align: center; 75 | line-height: 20px; 76 | } 77 | .lodlive-node .actionBox:nth-last-child(-n+4) { top: -4px; left: 27px; } 78 | .lodlive-node .actionBox:nth-last-child(-n+3) { top: -9px; left: 54px; } 79 | .lodlive-node .actionBox:nth-last-child(-n+2) { top: 0; left: 80px; } 80 | .lodlive-node .actionBox:last-child { top: 18px; left: 104px; } 81 | 82 | .lodlive-node .lodlive-toolbox-wrapper { position: relative; height: 0; width: 0; } 83 | .lodlive-node .lodlive-toolbox { position: absolute; right: -20px; top: -3em; white-space: nowrap; width: auto; } 84 | .lodlive-node .lodlive-toolbox .innerActionBox { background: #FFF; color: #369; display: inline-block; float: none; height: 20px; width: 20px; border-radius: 2px; opacity: 0.75 } 85 | .lodlive-node .lodlive-toolbox .innerActionBox:hover { opacity: 1.0 } 86 | 87 | .lodlive-node .relatedBox, .lodlive-node .groupedRelatedBox { 88 | position: absolute; 89 | z-index: 101; 90 | text-align: center; 91 | cursor: pointer; 92 | color: #369; 93 | } 94 | 95 | .lodlive-node .relatedBox:before { 96 | content: "\f111"; 97 | font-family: FontAwesome; 98 | font-size: 14px; 99 | } 100 | 101 | .lodlive-node .groupedRelatedBox:before { 102 | content: "\f0a3"; 103 | font-family: FontAwesome; 104 | font-size: 16px; 105 | } 106 | .lodlive-node .thisiscsscircle { background: #369; width: 14px; height: 14px; border-radius: 14px; } 107 | 108 | .lodlive-docinfo { 109 | position: absolute; 110 | top: 0; 111 | right: 5px; 112 | max-width: 20%; 113 | max-height: 75%; 114 | overflow: auto; 115 | z-index: 150; 116 | } 117 | .lodlive-docinfo .section { 118 | padding: 0.75em; 119 | background: #FFF; 120 | color: #000; 121 | margin: 1px 0; 122 | font-size: 12px; 123 | } 124 | .lodlive-docinfo .section:first-child { border-radius: 8px 0 0 0; } 125 | .lodlive-docinfo .section:last-child { border-radius: 0 0 0 8px; } 126 | .lodlive-docinfo .section label { font-weight: bold; } 127 | .lodlive-docinfo .section div { text-indent: 2em; margin: 0.5em 0 0; } 128 | 129 | .lodlive-message-container { 130 | position: absolute; 131 | bottom: 0; 132 | left: 0; 133 | z-index: 150; 134 | background-color: #FFF; 135 | padding: 1.25em; 136 | font-size: 13px; 137 | border-radius: 0 8px 0 0; 138 | } 139 | 140 | .lodlive-node.pinned .lodlive-node-label { border: dashed 1px white; background-color: #9CF; } 141 | 142 | .lodlive-node .page .pageNext { 143 | background-position: -1390px -412px; 144 | cursor: pointer; 145 | position: absolute; 146 | width: 16px; 147 | height: 16px; 148 | border: 0; 149 | z-index: 101; 150 | text-align: center; 151 | } 152 | 153 | .lodlive-node .page .pagePrev { 154 | background-position: -1414px -410px; 155 | cursor: pointer; 156 | position: absolute; 157 | width: 16px; 158 | height: 16px; 159 | border: 0; 160 | z-index: 101; 161 | text-align: center; 162 | } 163 | -------------------------------------------------------------------------------- /dist/ml-lodlive.deps.js: -------------------------------------------------------------------------------- 1 | /* 2 | jCanvas v13.11.21 3 | Copyright 2013 Caleb Evans 4 | Released under the MIT license 5 | */ 6 | (function(d,Ka,sa,da,ta,A,E,f,D){function L(c){Y(this,c);return this}function J(c){c?Y(L.prototype,c):J.prefs=L.prototype=Y({},ia);return this}function K(c){return c&&c.getContext?c.getContext("2d"):f}function ja(c){c=Y({},c);c.masks=c.masks.slice(0);return c}function ea(c,b){var a;c.save();a=ja(b.transforms);b.savedTransforms.push(a)}function U(c,b,a){$(a.fillStyle)?b.fillStyle=a.fillStyle.call(c,a):b.fillStyle=a.fillStyle;$(a.strokeStyle)?b.strokeStyle=a.strokeStyle.call(c,a):b.strokeStyle=a.strokeStyle; 7 | b.lineWidth=a.strokeWidth;a.rounded?b.lineCap=b.lineJoin="round":(b.lineCap=a.strokeCap,b.lineJoin=a.strokeJoin,b.miterLimit=a.miterLimit);b.shadowOffsetX=a.shadowX;b.shadowOffsetY=a.shadowY;b.shadowBlur=a.shadowBlur;b.shadowColor=a.shadowColor;b.globalAlpha=a.opacity;b.globalCompositeOperation=a.compositing;a.imageSmoothing&&(b.webkitImageSmoothingEnabled=b.mozImageSmoothingEnabled=a.imageSmoothing)}function ua(c,b,a){a.mask&&(a.autosave&&ea(c,b),c.clip(),b.transforms.masks.push(a._args))}function X(c, 8 | b,a){a.closed&&b.closePath();a.shadowStroke&&0!==a.strokeWidth?(b.stroke(),b.fill(),b.shadowColor="transparent",b.shadowBlur=0,b.stroke()):(b.fill(),"transparent"!==a.fillStyle&&(b.shadowColor="transparent"),0!==a.strokeWidth&&b.stroke());a.closed||b.closePath();a._transformed&&b.restore();a.mask&&(c=P(c),ua(b,c,a))}function va(c,b,a){b._toRad=b.inDegrees?M/180:1;c.translate(b.x,b.y);c.rotate(b.rotate*b._toRad);c.translate(-b.x,-b.y);a&&(a.rotate+=b.rotate*b._toRad)}function wa(c,b,a){1!==b.scale&& 9 | (b.scaleX=b.scaleY=b.scale);c.translate(b.x,b.y);c.scale(b.scaleX,b.scaleY);c.translate(-b.x,-b.y);a&&(a.scaleX*=b.scaleX,a.scaleY*=b.scaleY)}function xa(c,b,a){b.translate&&(b.translateX=b.translateY=b.translate);c.translate(b.translateX,b.translateY);a&&(a.translateX+=b.translateX,a.translateY+=b.translateY)}function Q(c,b,a,e,h){a._toRad=a.inDegrees?M/180:1;a.arrowAngle*=a._toRad;a._transformed=A;b.save();h===D&&(h=e);a.fromCenter||a._centered||(a.x+=e/2,a.y+=h/2,a._centered=A);a.rotate&&va(b, 10 | a,{});1===a.scale&&1===a.scaleX&&1===a.scaleY||wa(b,a,{});(a.translate||a.translateX||a.translateY)&&xa(b,a,{})}function P(c){var b;fa._canvas===c&&fa._data?b=fa._data:(b=d.data(c,"jCanvas"),b||(b={canvas:c,layers:[],layer:{names:{},groups:{}},intersecting:[],lastIntersected:f,cursor:d(c).css("cursor"),drag:{},event:{type:f,x:f,y:f},events:{},transforms:ja(ma),savedTransforms:[],animating:E,animated:f,pos:0,pixelRatio:1,scaled:!1},d.data(c,"jCanvas",b)),fa._canvas=c,fa._data=b);return b}function ya(c, 11 | b,a){for(var e in J.events)J.events.hasOwnProperty(e)&&(a[e]||a.cursors&&a.cursors[e])&&za(c,b,a,e)}function za(c,b,a,e){e=Aa(e);J.events[e](c,b);a._event=A}function Ba(c,b,a){var e,h,g;if(a.draggable||a.cursor||a.cursors){e=["mousedown","mousemove","mouseup"];for(g=0;ga&&(c.now[a]=Na(c.now[a]));1!==c.start[3]||1!==c.end[3]?c.now="rgba("+c.now.join(",")+ 16 | ")":(c.now.slice(0,3),c.now="rgb("+c.now.join(",")+")");c.elem.nodeName?c.elem.style[c.prop]=c.now:c.elem[c.prop]=c.now}function Aa(c){void 0!==window.ontouchstart&&pa[c]&&(c=pa[c]);return c}function Oa(c){J.events[c]=function(b,a){var e,h;h=a.event;e="mouseover"===c||"mouseout"===c?"mousemove":c;a.events[e]||(b.bind(e+".jCanvas",function(a){h.x=a.offsetX;h.y=a.offsetY;h.type=e;h.event=a;b.drawLayers({resetFire:A});a.preventDefault()}),a.events[e]=A)}}function V(c,b,a){var e,h,g,d;(a=a._args)&&a._event&& 17 | (c=P(c),e=c.event,e.x!==f&&e.y!==f&&(g=e.x*c.pixelRatio,d=e.y*c.pixelRatio,h=b.isPointInPath(g,d)||b.isPointInStroke&&b.isPointInStroke(g,d)),b=c.transforms,a.eventX=a.mouseX=e.x,a.eventY=a.mouseY=e.y,a.event=e.event,e=c.transforms.rotate,g=a.eventX,d=a.eventY,0!==e?(a._eventX=g*R(-e)-d*T(-e),a._eventY=d*R(-e)+g*T(-e)):(a._eventX=g,a._eventY=d),a._eventX/=b.scaleX,a._eventY/=b.scaleY,h&&c.intersecting.push(a),a.intersects=h)}function Fa(c){for(;0>c;)c+=2*M;return c}function Ga(c,b,a,e,h,g,d){var f, 18 | z,y;a.arrowRadius&&!a.closed&&(y=Pa(d-h,g-e),y-=M,f=a.strokeWidth*R(y),z=a.strokeWidth*T(y),c=g+a.arrowRadius*R(y+a.arrowAngle/2),e=d+a.arrowRadius*T(y+a.arrowAngle/2),h=g+a.arrowRadius*R(y-a.arrowAngle/2),a=d+a.arrowRadius*T(y-a.arrowAngle/2),b.moveTo(c-f,e-z),b.lineTo(g-f,d-z),b.lineTo(h-f,a-z),b.moveTo(g-f,d-z),b.lineTo(g+f,d+z))}function ha(c,b,a,e,h,g,d,f,z,y,F){a.startArrow&&Ga(c,b,a,e,h,g,d);a.endArrow&&Ga(c,b,a,f,z,y,F)}function Ha(c,b){isNaN(Number(b.fontSize))||(b.fontSize+="px");c.font= 19 | b.fontStyle+" "+b.fontSize+" "+b.fontFamily}function Ia(c,b,a,e){var h,g;if(Z.text===a.text&&Z.fontStyle===a.fontStyle&&Z.fontSize===a.fontSize&&Z.fontFamily===a.fontFamily&&Z.maxWidth===a.maxWidth&&Z.lineHeight===a.lineHeight)a.width=Z.width,a.height=Z.height;else{a.width=b.measureText(e[0]).width;for(g=1;ga.width&&(a.width=h);b=c.style.fontSize;c.style.fontSize=a.fontSize;a.height=ta(d.css(c,"fontSize"))*e.length*a.lineHeight;c.style.fontSize=b}}function Ja(c, 20 | b){var a=b.maxWidth,e=b.text.split("\n"),h=[],g,d,f,z,y;for(f=0;fa&&(""!==d&&g.push(d),d=""),d+=y[z],z!==y.length-1&&(d+=" ");g.push(d)}h=h.concat(g.join("\n").replace(/( (\n))|( $)/gi,"$2").split("\n"))}return h}var ia,Y=d.extend,ba=d.inArray,aa=d.type,$=d.isFunction,Na=da.round,M=da.PI,T=da.sin,R=da.cos,Pa=da.atan2,Qa=d.event.fix,pa,qa,la,fa={}, 21 | Z={},ra={},ma={rotate:0,scaleX:1,scaleY:1,translateX:0,translateY:0,masks:[]},ga,oa;d.fn.jCanvas=J;J.events={};ia={align:"center",arrowAngle:90,arrowRadius:0,autosave:A,baseline:"middle",bringToFront:E,ccw:E,closed:E,compositing:"source-over",concavity:0,cornerRadius:0,count:1,cropFromCenter:A,cursor:f,cursors:f,disableEvents:E,draggable:E,dragGroups:f,group:f,groups:f,data:{},each:f,end:360,fillStyle:"transparent",fireDragGroupEvents:E,fontStyle:"normal",fontSize:"12pt",fontFamily:"sans-serif",fromCenter:A, 22 | fn:f,height:f,imageSmoothing:A,inDegrees:A,index:f,lineHeight:1,layer:E,load:f,mask:E,maxWidth:f,miterLimit:10,name:f,opacity:1,r1:f,r2:f,radius:0,repeat:"repeat",respectAlign:E,rotate:0,rounded:E,scale:1,scaleX:1,scaleY:1,shadowBlur:0,shadowColor:"transparent",shadowStroke:!1,shadowX:0,shadowY:0,sHeight:f,sides:0,source:"",spread:0,start:0,strokeCap:"butt",strokeJoin:"miter",strokeStyle:"transparent",strokeWidth:1,sWidth:f,sx:f,sy:f,text:"",translate:0,translateX:0,translateY:0,type:f,visible:A, 23 | width:f,x:0,y:0};J();J.extend=function(c){J.defaults=Y(ia,c.props);J();c.name&&(d.fn[c.name]=function a(e){var h,g,d,f;for(g=0;gc&&(c=a.length+c),h=a[c];else if("regexp"===e)for(b=0;bb&&(b=h.length+b),a.index=b;return this};d.fn.removeLayer=function(c){var b,a,e,h,g;for(a=0;aC-l-2*v&&(v=(C-l)/2),0>q-u-2*v&&(v=(q-u)/2),t.moveTo(l+v,u),t.lineTo(C-v,u),t.arc(C-v,u+v,v,3*M/2,2*M,E),t.lineTo(C,q-v),t.arc(C-v,q-v,v,0,M/2,E),t.lineTo(l+v,q),t.arc(l+v,q-v,v,M/2,M,E),t.lineTo(l,u+v),t.arc(l+v,u+v,v,M,3*M/ 44 | 2,E)):t.rect(l,u,B.width,B.height),V(this[f],t,B),X(this[f],t,B));return this};d.fn.drawArc=function y(d){var f,B,l,u,C,q,v,p,k,n,m;for(f=0;fr.sy-r.sHeight/2&&(r.sy=r.sHeight/ 55 | 2),r.sy+r.sHeight/2>G.height&&(r.sy=G.height-r.sHeight/2),0>r.sx-r.sWidth/2&&(r.sx=r.sWidth/2),r.sx+r.sWidth/2>G.width&&(r.sx=G.width-r.sWidth/2),Q(m[p],n,r,r.width,r.height),n.drawImage(G,r.sx-r.sWidth/2,r.sy-r.sHeight/2,r.sWidth,r.sHeight,r.x-r.width/2,r.y-r.height/2,r.width,r.height)):(Q(m[p],n,r,r.width,r.height),n.drawImage(G,r.x-r.width/2,r.y-r.height/2,r.width,r.height));n.beginPath();n.rect(r.x-r.width/2,r.y-r.height/2,r.width,r.height);V(m[p],n,r);n.closePath();r._transformed&&n.restore(); 56 | ua(n,s,r);r.load&&r.load.call(k,w);r.layer&&(r._args._masks=s.transforms.masks.slice(0),r._next&&d(k).drawLayers({clear:E,resetFire:A,index:r._next}))}}var m=this,x,w,s,I,S,W,G,M,J;for(w=0;w")[0],w.width=x.width,w.height=x.height,p=K(w),I.call(w,p),k()):(p=I.getContext,I.src||p?w=I:(w=new sa,w.src=I),w.complete||p?k():(d(w).bind("load",k),w.src=w.src))):s=f;return s};d.fn.createGradient=function(d){var k,n=[],m,x,w,s,I,A,E;d=new L(d);if(k=K(this[0])){d.x1=d.x1||0;d.y1=d.y1||0;d.x2=d.x2||0;d.y2=d.y2||0;k=d.r1!==f||d.r2!==f?k.createRadialGradient(d.x1,d.y1, 58 | d.r1,d.x2,d.y2,d.r2):k.createLinearGradient(d.x1,d.y1,d.x2,d.y2);for(s=1;d["c"+s]!==D;s+=1)d["s"+s]!==D?n.push(d["s"+s]):n.push(f);m=n.length;n[0]===f&&(n[0]=0);n[m-1]===f&&(n[m-1]=1);for(s=0;sw&&(n[I]=n[s])}else n[s]===f&&(E+=1,n[s]=x+(w-x)/A*E);k.addColorStop(n[s],d["c"+(s+1)])}}else k=f;return k};d.fn.setPixels=function k(d){var m,x,w,s,A,E,D,G,J;for(x=0;x")[0].getContext;J.defaults=ia;J.transformShape=Q;J.detectEvents=V;J.closePath=X;J.getTouchEventName=Aa;d.jCanvas=J})(jQuery,document,Image,Math,parseFloat,!0,!1,null); 62 | -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/favicon.png -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var concat = require('gulp-concat'); 3 | var uglify = require('gulp-uglify'); 4 | var rename = require('gulp-rename'); 5 | var tar = require('gulp-tar'); 6 | var gzip = require('gulp-gzip'); 7 | var addsrc = require('gulp-add-src'); 8 | var browserify = require('browserify'); 9 | var buffer = require('vinyl-buffer'); 10 | var source = require('vinyl-source-stream'); 11 | 12 | gulp.task('deps', function() { 13 | return gulp.src(['./js/deps/*.js', '!./js/deps/jquery-ui-1.9.2.min.js']) 14 | .pipe(concat('ml-lodlive.deps.js')) 15 | .pipe(gulp.dest('./dist')); 16 | }); 17 | 18 | gulp.task('scripts', function() { 19 | return browserify({ entries: [ './js/lib/lodlive.core.js' ] }).bundle() 20 | .pipe(source('ml-lodlive-components.js')) 21 | .pipe(buffer()) 22 | .pipe(concat('ml-lodlive.js')) 23 | .pipe(gulp.dest('./dist/')) 24 | .pipe(uglify()) 25 | .pipe(rename('ml-lodlive.min.js')) 26 | .pipe(gulp.dest('./dist/')); 27 | }); 28 | 29 | gulp.task('fonts', function() { 30 | return gulp.src('./css/fonts/**/*') 31 | .pipe(gulp.dest('./dist/fonts/')); 32 | }); 33 | 34 | gulp.task('styles', [ 'fonts' ], function() { 35 | return gulp.src('./css/*.css') 36 | .pipe(concat('ml-lodlive.all.css')) 37 | .pipe(gulp.dest('./dist/')); 38 | }); 39 | 40 | gulp.task('build', ['scripts', 'deps', 'styles'], function() { 41 | return gulp.src(['./dist/ml-lodlive.js', './dist/ml-lodlive.deps.js']) 42 | .pipe(concat('ml-lodlive.complete.js')) 43 | .pipe(gulp.dest('./dist/')); 44 | }); 45 | 46 | gulp.task('package', ['build'], function() { 47 | return gulp.src(['./dist/ml-lodlive.complete.js', './dist/ml-lodlive.all.css', './dist/fonts/*.*'], { base: './'}) 48 | .pipe(tar('ml-lodlive.tar')) 49 | .pipe(gzip()) 50 | .pipe(gulp.dest('./')); 51 | }); -------------------------------------------------------------------------------- /img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withjam/ml-lodlive/dd9a97ce49f6d0b5d57099a4d4fcae9b75814195/img/ajax-loader.gif -------------------------------------------------------------------------------- /import-rdf.sh: -------------------------------------------------------------------------------- 1 | mlcp.sh import \ 2 | -username admin \ 3 | -password admin \ 4 | -host lodlive-ml1 \ 5 | -port 8041 \ 6 | -mode local \ 7 | -input_file_path data/ieee-skos.xml \ 8 | -input_file_type RDF \ 9 | -output_uri_prefix /skos/ \ -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ML LodLive - Extensible RDF Browser 5 | 6 | 7 | 12 | 13 | 14 |
15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 36 | 37 | -------------------------------------------------------------------------------- /js/deps/jquery.jcanvas.js: -------------------------------------------------------------------------------- 1 | /* 2 | jCanvas v13.11.21 3 | Copyright 2013 Caleb Evans 4 | Released under the MIT license 5 | */ 6 | (function(d,Ka,sa,da,ta,A,E,f,D){function L(c){Y(this,c);return this}function J(c){c?Y(L.prototype,c):J.prefs=L.prototype=Y({},ia);return this}function K(c){return c&&c.getContext?c.getContext("2d"):f}function ja(c){c=Y({},c);c.masks=c.masks.slice(0);return c}function ea(c,b){var a;c.save();a=ja(b.transforms);b.savedTransforms.push(a)}function U(c,b,a){$(a.fillStyle)?b.fillStyle=a.fillStyle.call(c,a):b.fillStyle=a.fillStyle;$(a.strokeStyle)?b.strokeStyle=a.strokeStyle.call(c,a):b.strokeStyle=a.strokeStyle; 7 | b.lineWidth=a.strokeWidth;a.rounded?b.lineCap=b.lineJoin="round":(b.lineCap=a.strokeCap,b.lineJoin=a.strokeJoin,b.miterLimit=a.miterLimit);b.shadowOffsetX=a.shadowX;b.shadowOffsetY=a.shadowY;b.shadowBlur=a.shadowBlur;b.shadowColor=a.shadowColor;b.globalAlpha=a.opacity;b.globalCompositeOperation=a.compositing;a.imageSmoothing&&(b.webkitImageSmoothingEnabled=b.mozImageSmoothingEnabled=a.imageSmoothing)}function ua(c,b,a){a.mask&&(a.autosave&&ea(c,b),c.clip(),b.transforms.masks.push(a._args))}function X(c, 8 | b,a){a.closed&&b.closePath();a.shadowStroke&&0!==a.strokeWidth?(b.stroke(),b.fill(),b.shadowColor="transparent",b.shadowBlur=0,b.stroke()):(b.fill(),"transparent"!==a.fillStyle&&(b.shadowColor="transparent"),0!==a.strokeWidth&&b.stroke());a.closed||b.closePath();a._transformed&&b.restore();a.mask&&(c=P(c),ua(b,c,a))}function va(c,b,a){b._toRad=b.inDegrees?M/180:1;c.translate(b.x,b.y);c.rotate(b.rotate*b._toRad);c.translate(-b.x,-b.y);a&&(a.rotate+=b.rotate*b._toRad)}function wa(c,b,a){1!==b.scale&& 9 | (b.scaleX=b.scaleY=b.scale);c.translate(b.x,b.y);c.scale(b.scaleX,b.scaleY);c.translate(-b.x,-b.y);a&&(a.scaleX*=b.scaleX,a.scaleY*=b.scaleY)}function xa(c,b,a){b.translate&&(b.translateX=b.translateY=b.translate);c.translate(b.translateX,b.translateY);a&&(a.translateX+=b.translateX,a.translateY+=b.translateY)}function Q(c,b,a,e,h){a._toRad=a.inDegrees?M/180:1;a.arrowAngle*=a._toRad;a._transformed=A;b.save();h===D&&(h=e);a.fromCenter||a._centered||(a.x+=e/2,a.y+=h/2,a._centered=A);a.rotate&&va(b, 10 | a,{});1===a.scale&&1===a.scaleX&&1===a.scaleY||wa(b,a,{});(a.translate||a.translateX||a.translateY)&&xa(b,a,{})}function P(c){var b;fa._canvas===c&&fa._data?b=fa._data:(b=d.data(c,"jCanvas"),b||(b={canvas:c,layers:[],layer:{names:{},groups:{}},intersecting:[],lastIntersected:f,cursor:d(c).css("cursor"),drag:{},event:{type:f,x:f,y:f},events:{},transforms:ja(ma),savedTransforms:[],animating:E,animated:f,pos:0,pixelRatio:1,scaled:!1},d.data(c,"jCanvas",b)),fa._canvas=c,fa._data=b);return b}function ya(c, 11 | b,a){for(var e in J.events)J.events.hasOwnProperty(e)&&(a[e]||a.cursors&&a.cursors[e])&&za(c,b,a,e)}function za(c,b,a,e){e=Aa(e);J.events[e](c,b);a._event=A}function Ba(c,b,a){var e,h,g;if(a.draggable||a.cursor||a.cursors){e=["mousedown","mousemove","mouseup"];for(g=0;ga&&(c.now[a]=Na(c.now[a]));1!==c.start[3]||1!==c.end[3]?c.now="rgba("+c.now.join(",")+ 16 | ")":(c.now.slice(0,3),c.now="rgb("+c.now.join(",")+")");c.elem.nodeName?c.elem.style[c.prop]=c.now:c.elem[c.prop]=c.now}function Aa(c){void 0!==window.ontouchstart&&pa[c]&&(c=pa[c]);return c}function Oa(c){J.events[c]=function(b,a){var e,h;h=a.event;e="mouseover"===c||"mouseout"===c?"mousemove":c;a.events[e]||(b.bind(e+".jCanvas",function(a){h.x=a.offsetX;h.y=a.offsetY;h.type=e;h.event=a;b.drawLayers({resetFire:A});a.preventDefault()}),a.events[e]=A)}}function V(c,b,a){var e,h,g,d;(a=a._args)&&a._event&& 17 | (c=P(c),e=c.event,e.x!==f&&e.y!==f&&(g=e.x*c.pixelRatio,d=e.y*c.pixelRatio,h=b.isPointInPath(g,d)||b.isPointInStroke&&b.isPointInStroke(g,d)),b=c.transforms,a.eventX=a.mouseX=e.x,a.eventY=a.mouseY=e.y,a.event=e.event,e=c.transforms.rotate,g=a.eventX,d=a.eventY,0!==e?(a._eventX=g*R(-e)-d*T(-e),a._eventY=d*R(-e)+g*T(-e)):(a._eventX=g,a._eventY=d),a._eventX/=b.scaleX,a._eventY/=b.scaleY,h&&c.intersecting.push(a),a.intersects=h)}function Fa(c){for(;0>c;)c+=2*M;return c}function Ga(c,b,a,e,h,g,d){var f, 18 | z,y;a.arrowRadius&&!a.closed&&(y=Pa(d-h,g-e),y-=M,f=a.strokeWidth*R(y),z=a.strokeWidth*T(y),c=g+a.arrowRadius*R(y+a.arrowAngle/2),e=d+a.arrowRadius*T(y+a.arrowAngle/2),h=g+a.arrowRadius*R(y-a.arrowAngle/2),a=d+a.arrowRadius*T(y-a.arrowAngle/2),b.moveTo(c-f,e-z),b.lineTo(g-f,d-z),b.lineTo(h-f,a-z),b.moveTo(g-f,d-z),b.lineTo(g+f,d+z))}function ha(c,b,a,e,h,g,d,f,z,y,F){a.startArrow&&Ga(c,b,a,e,h,g,d);a.endArrow&&Ga(c,b,a,f,z,y,F)}function Ha(c,b){isNaN(Number(b.fontSize))||(b.fontSize+="px");c.font= 19 | b.fontStyle+" "+b.fontSize+" "+b.fontFamily}function Ia(c,b,a,e){var h,g;if(Z.text===a.text&&Z.fontStyle===a.fontStyle&&Z.fontSize===a.fontSize&&Z.fontFamily===a.fontFamily&&Z.maxWidth===a.maxWidth&&Z.lineHeight===a.lineHeight)a.width=Z.width,a.height=Z.height;else{a.width=b.measureText(e[0]).width;for(g=1;ga.width&&(a.width=h);b=c.style.fontSize;c.style.fontSize=a.fontSize;a.height=ta(d.css(c,"fontSize"))*e.length*a.lineHeight;c.style.fontSize=b}}function Ja(c, 20 | b){var a=b.maxWidth,e=b.text.split("\n"),h=[],g,d,f,z,y;for(f=0;fa&&(""!==d&&g.push(d),d=""),d+=y[z],z!==y.length-1&&(d+=" ");g.push(d)}h=h.concat(g.join("\n").replace(/( (\n))|( $)/gi,"$2").split("\n"))}return h}var ia,Y=d.extend,ba=d.inArray,aa=d.type,$=d.isFunction,Na=da.round,M=da.PI,T=da.sin,R=da.cos,Pa=da.atan2,Qa=d.event.fix,pa,qa,la,fa={}, 21 | Z={},ra={},ma={rotate:0,scaleX:1,scaleY:1,translateX:0,translateY:0,masks:[]},ga,oa;d.fn.jCanvas=J;J.events={};ia={align:"center",arrowAngle:90,arrowRadius:0,autosave:A,baseline:"middle",bringToFront:E,ccw:E,closed:E,compositing:"source-over",concavity:0,cornerRadius:0,count:1,cropFromCenter:A,cursor:f,cursors:f,disableEvents:E,draggable:E,dragGroups:f,group:f,groups:f,data:{},each:f,end:360,fillStyle:"transparent",fireDragGroupEvents:E,fontStyle:"normal",fontSize:"12pt",fontFamily:"sans-serif",fromCenter:A, 22 | fn:f,height:f,imageSmoothing:A,inDegrees:A,index:f,lineHeight:1,layer:E,load:f,mask:E,maxWidth:f,miterLimit:10,name:f,opacity:1,r1:f,r2:f,radius:0,repeat:"repeat",respectAlign:E,rotate:0,rounded:E,scale:1,scaleX:1,scaleY:1,shadowBlur:0,shadowColor:"transparent",shadowStroke:!1,shadowX:0,shadowY:0,sHeight:f,sides:0,source:"",spread:0,start:0,strokeCap:"butt",strokeJoin:"miter",strokeStyle:"transparent",strokeWidth:1,sWidth:f,sx:f,sy:f,text:"",translate:0,translateX:0,translateY:0,type:f,visible:A, 23 | width:f,x:0,y:0};J();J.extend=function(c){J.defaults=Y(ia,c.props);J();c.name&&(d.fn[c.name]=function a(e){var h,g,d,f;for(g=0;gc&&(c=a.length+c),h=a[c];else if("regexp"===e)for(b=0;bb&&(b=h.length+b),a.index=b;return this};d.fn.removeLayer=function(c){var b,a,e,h,g;for(a=0;aC-l-2*v&&(v=(C-l)/2),0>q-u-2*v&&(v=(q-u)/2),t.moveTo(l+v,u),t.lineTo(C-v,u),t.arc(C-v,u+v,v,3*M/2,2*M,E),t.lineTo(C,q-v),t.arc(C-v,q-v,v,0,M/2,E),t.lineTo(l+v,q),t.arc(l+v,q-v,v,M/2,M,E),t.lineTo(l,u+v),t.arc(l+v,u+v,v,M,3*M/ 44 | 2,E)):t.rect(l,u,B.width,B.height),V(this[f],t,B),X(this[f],t,B));return this};d.fn.drawArc=function y(d){var f,B,l,u,C,q,v,p,k,n,m;for(f=0;fr.sy-r.sHeight/2&&(r.sy=r.sHeight/ 55 | 2),r.sy+r.sHeight/2>G.height&&(r.sy=G.height-r.sHeight/2),0>r.sx-r.sWidth/2&&(r.sx=r.sWidth/2),r.sx+r.sWidth/2>G.width&&(r.sx=G.width-r.sWidth/2),Q(m[p],n,r,r.width,r.height),n.drawImage(G,r.sx-r.sWidth/2,r.sy-r.sHeight/2,r.sWidth,r.sHeight,r.x-r.width/2,r.y-r.height/2,r.width,r.height)):(Q(m[p],n,r,r.width,r.height),n.drawImage(G,r.x-r.width/2,r.y-r.height/2,r.width,r.height));n.beginPath();n.rect(r.x-r.width/2,r.y-r.height/2,r.width,r.height);V(m[p],n,r);n.closePath();r._transformed&&n.restore(); 56 | ua(n,s,r);r.load&&r.load.call(k,w);r.layer&&(r._args._masks=s.transforms.masks.slice(0),r._next&&d(k).drawLayers({clear:E,resetFire:A,index:r._next}))}}var m=this,x,w,s,I,S,W,G,M,J;for(w=0;w")[0],w.width=x.width,w.height=x.height,p=K(w),I.call(w,p),k()):(p=I.getContext,I.src||p?w=I:(w=new sa,w.src=I),w.complete||p?k():(d(w).bind("load",k),w.src=w.src))):s=f;return s};d.fn.createGradient=function(d){var k,n=[],m,x,w,s,I,A,E;d=new L(d);if(k=K(this[0])){d.x1=d.x1||0;d.y1=d.y1||0;d.x2=d.x2||0;d.y2=d.y2||0;k=d.r1!==f||d.r2!==f?k.createRadialGradient(d.x1,d.y1, 58 | d.r1,d.x2,d.y2,d.r2):k.createLinearGradient(d.x1,d.y1,d.x2,d.y2);for(s=1;d["c"+s]!==D;s+=1)d["s"+s]!==D?n.push(d["s"+s]):n.push(f);m=n.length;n[0]===f&&(n[0]=0);n[m-1]===f&&(n[m-1]=1);for(s=0;sw&&(n[I]=n[s])}else n[s]===f&&(E+=1,n[s]=x+(w-x)/A*E);k.addColorStop(n[s],d["c"+(s+1)])}}else k=f;return k};d.fn.setPixels=function k(d){var m,x,w,s,A,E,D,G,J;for(x=0;x")[0].getContext;J.defaults=ia;J.transformShape=Q;J.detectEvents=V;J.closePath=X;J.getTouchEventName=Aa;d.jCanvas=J})(jQuery,document,Image,Math,parseFloat,!0,!1,null); 62 | -------------------------------------------------------------------------------- /js/profile/lodlive.profile-localhost-example.js: -------------------------------------------------------------------------------- 1 | /* 2 | just an example of configuration useful to redirect all the request on the same endpoint 3 | */ 4 | 5 | $.jStorage.set('profile', { 6 | // parametri di connessione agli endpoint 7 | 'connection' : { 8 | /*matching all the requested URIs*/ 9 | 'http://' : { 10 | description : { 11 | en : 'just a test' 12 | }, 13 | useForInverseSameAs : true, 14 | /*change this*/ 15 | endpoint : 'http://localhost:8890/sparql', 16 | examples : [{ 17 | label : 'test 1', 18 | uri : 'http://mysite.com/aaa' 19 | }, { 20 | label : 'test 2', 21 | uri : 'http://your.com/bbbb' 22 | }] 23 | } 24 | }, 25 | arrows : { 26 | 'http://www.w3.org/2002/07/owl#sameAs' : 'isSameAs', 27 | 'http://purl.org/dc/terms/isPartOf' : 'isPartOf', 28 | 'http://purl.org/dc/elements/1.1/type' : 'isType', 29 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : 'isType' 30 | }, 31 | uriSubstitutor : [{ 32 | findStr : 'mpii.de/yago/resource/', 33 | replaceStr : 'yago-knowledge.org/resource/' 34 | }], 35 | 36 | // configurazione standard per la rappresentazione di un documento 37 | // utilizzata nel caso manchi una specifica configurazione per la classe 38 | 'default' : { 39 | sparql : { 40 | allClasses : 'SELECT DISTINCT ?object WHERE {[] a ?object}', 41 | findSubject : 'SELECT DISTINCT ?subject WHERE { {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} } LIMIT 1 ', 42 | documentUri : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object} ORDER BY ?property', 43 | document : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 44 | bnode : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 45 | inverse : 'SELECT DISTINCT * WHERE {?object ?property <{URI}>.} LIMIT 100', 46 | inverseSameAs : 'SELECT DISTINCT * WHERE {{?object <{URI}> } UNION { ?object <{URI}>}}' 47 | }, 48 | endpoint : 'http://labs.regesta.com/resourceProxy/', 49 | document : { 50 | className : 'standard', 51 | titleProperties : ['http://dati.senato.it/osr/titolo', 'http://www.w3.org/2004/02/skos/core#notation', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#value', 'http://www.geonames.org/ontology#name', 'http://purl.org/dc/elements/1.1/title', 'http://purl.org/dc/terms/title', 'http://www.w3.org/2000/01/rdf-schema#label', 'http://www.w3.org/2004/02/skos/core#prefLabel', 'http://logd.tw.rpi.edu/source/visualizing-org/dataset/2010-global-agenda-council-interlinkage-survey/vocab/enhancement/1/how_councils_interlink', 'http://rdf.freebase.com/ns/type.object.name', 'http://spcdata.digitpa.gov.it/nome_cognome', 'http://xmlns.com/foaf/0.1/firstName', 'http://xmlns.com/foaf/0.1/lastName', 'http://xmlns.com/foaf/0.1/surname', 'http://xmlns.com/foaf/0.1/name', 'http://purl.org/dc/terms/description', 'http://www.geonames.org/ontology/officialName'] 52 | }, // http://www.w3.org/2000/01/rdf-schema#label 53 | images : { 54 | properties : ['http://www.w3.org/2006/vcard/ns#photo', 'http://xmlns.com/foaf/0.1/depiction', 'http://dbpedia.org/ontology/thumbnail', 'http://dbpedia.org/property/logo', 'http://linkedgeodata.org/ontology/schemaIcon'] 55 | }, 56 | maps : { 57 | longs : ['http://www.w3.org/2003/01/geo/wgs84_pos#long'], 58 | lats : ['http://www.w3.org/2003/01/geo/wgs84_pos#lat'], 59 | points : ['http://www.georss.org/georss/point'] 60 | }, 61 | weblinks : { 62 | properties : ['http://www.w3.org/ns/dcat#accessURL', 'http://xmlns.com/foaf/0.1/mbox', 'http://rdfs.org/sioc/ns#links_to', 'http://it.dbpedia.org/property/url', 'http://data.nytimes.com/elements/search_api_query', 'http://www.w3.org/2000/01/rdf-schema#isDefinedBy', 'http://xmlns.com/foaf/0.1/page', 'http://xmlns.com/foaf/0.1/homepage', 'http://purl.org/dc/terms/isReferencedBy', 'http://purl.org/dc/elements/1.1/relation', 'http://dbpedia.org/ontology/wikiPageExternalLink', 'http://data.nytimes.com/elements/topicPage'] 63 | } 64 | }, 65 | 66 | 'http://www.w3.org/2002/07/owl#Class' : { 67 | document : { 68 | className : 'Class'/*, 69 | titleProperties : ['http://purl.org/dc/elements/1.1/title', 'http://www.w3.org/2000/01/rdf-schema#label']*/ 70 | } 71 | }, 72 | 'http://www.w3.org/2002/07/owl#ObjectProperty' : { 73 | document : { 74 | className : 'ObjectProperty' 75 | } 76 | }, 77 | 'http://www.w3.org/2002/07/owl#Restriction' : { 78 | document : { 79 | className : 'DatatypeProperty' 80 | } 81 | }, 82 | 'http://www.w3.org/2002/07/owl#DatatypeProperty' : { 83 | document : { 84 | className : 'DatatypeProperty' 85 | } 86 | }, 87 | 'http://www.w3.org/2002/07/owl#Property' : { 88 | document : { 89 | className : 'Property' 90 | } 91 | }, 92 | 'http://www.w3.org/ns/locn#Address' : { 93 | document : { 94 | titleProperties : ['http://www.w3.org/ns/locn#fullAddress'] 95 | } 96 | } 97 | 98 | }); 99 | if (!document.lodliveVars) { 100 | document.lodliveVars = {}; 101 | } 102 | 103 | $.jStorage.set('boxTemplate', '
'); 104 | $.jStorage.set('relationsLimit', 25); 105 | $.jStorage.set('doStats', $.jStorage.get('doStats', true)); 106 | $.jStorage.set('doInverse', $.jStorage.get('doAutoExpand', true)); 107 | $.jStorage.set('doAutoExpand', $.jStorage.get('doAutoExpand', true)); 108 | $.jStorage.set('doAutoSameas', $.jStorage.get('doAutoSameas', true)); 109 | $.jStorage.set('doCollectImages', $.jStorage.get('doCollectImages', true)); 110 | $.jStorage.set('doDrawMap', $.jStorage.get('doDrawMap', true)); 111 | $.jStorage.set('showInfoConsole', $.jStorage.get('showInfoConsole', true)); 112 | 113 | $.jStorage.set('endpoints', { 114 | all : 'output=json&format=application/json&timeout=0', 115 | arcSparql : 'output=json&jsonp=lodlive', 116 | sesame : 'Accept=application/sparql-results%2Bjson' 117 | }); 118 | -------------------------------------------------------------------------------- /js/profile/profile.example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var ExampleProfile = {}; 3 | 4 | // LodLive will match connection by the base URL of the query used, so the key must match the URL 5 | ExampleProfile.connection = { 6 | // http matches all http requests, so this will be the only connection settings used 7 | 'http:' : { 8 | description : { 9 | it : 'DBpedia is a community effort to extract structured information from Wikipedia and to make this information available on the Web. DBpedia allows you to ask sophisticated queries against Wikipedia, and to link other data sets on the Web to Wikipedia data.', 10 | en : 'DBpedia is a community effort to extract structured information from Wikipedia and to make this information available on the Web. DBpedia allows you to ask sophisticated queries against Wikipedia, and to link other data sets on the Web to Wikipedia data.' 11 | }, 12 | sparql : { 13 | allClasses : 'SELECT DISTINCT ?object WHERE {[] a ?object} ORDER BY ?object LIMIT 50 ', 14 | findSubject : 'SELECT DISTINCT ?subject WHERE { {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} } LIMIT 1', 15 | documentUri : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object.FILTER ((( isIRI(?object) && ?property != )|| ?property = || ?property = || ?property = || ?property = || ?property = ))} ORDER BY ?property', 16 | document : 'SELECT DISTINCT * WHERE {{<{URI}> ?property ?object. FILTER(!isLiteral(?object))} UNION {<{URI}> ?property ?object.FILTER(isLiteral(?object)).FILTER(lang(?object) ="it")} UNION {<{URI}> ?property ?object.FILTER(isLiteral(?object)).FILTER(lang(?object) ="en")}} ORDER BY ?property', 17 | bnode : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 18 | inverse : 'SELECT DISTINCT * WHERE {?object ?property <{URI}> FILTER(REGEX(STR(?object),\'//dbpedia.org\'))} LIMIT 100', 19 | inverseSameAs : 'SELECT DISTINCT * WHERE {?object <{URI}> FILTER(REGEX(STR(?object),\'//dbpedia.org\'))}' 20 | }, 21 | useForInverseSameAs : true, 22 | endpoint : 'http://dbpedia.org/sparql', 23 | } 24 | }; 25 | 26 | // here we define the known relationships so that labels will appear 27 | ExampleProfile.arrows = { 28 | 'http://www.w3.org/2002/07/owl#sameAs' : 'isSameAs', 29 | 'http://purl.org/dc/terms/isPartOf' : 'isPartOf', 30 | 'http://purl.org/dc/elements/1.1/type' : 'isType', 31 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : 'isType' 32 | }; 33 | 34 | // this is the default data configuration, this is important. It informs LodLive how to construct queries and how to read the data that comes back 35 | ExampleProfile.default = { 36 | sparql : { 37 | allClasses : 'SELECT DISTINCT ?object WHERE {[] a ?object}', 38 | findSubject : 'SELECT DISTINCT ?subject WHERE { {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} } LIMIT 1 ', 39 | documentUri : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object} ORDER BY ?property', 40 | document : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 41 | bnode : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 42 | inverse : 'SELECT DISTINCT * WHERE {?object ?property <{URI}>.} LIMIT 100', 43 | inverseSameAs : 'SELECT DISTINCT * WHERE {{?object <{URI}> } UNION { ?object <{URI}>}}' 44 | }, 45 | endpoint : 'http://labs.regesta.com/resourceProxy/', 46 | document : { 47 | className : 'standard', 48 | titleName: 'none', 49 | titleProperties : ['http://xmlns.com/foaf/0.1/name'] 50 | }, // http://www.w3.org/2000/01/rdf-schema#label 51 | }; 52 | 53 | ExampleProfile.UI = { 54 | ignoreBnodes: true, 55 | nodeIcons: [ 56 | { builtin: 'tools' }, 57 | { builtin: 'docInfo' }, 58 | { 59 | icon: 'fa fa-refresh', 60 | title: 'Randomize node color', 61 | handler: function(node, inst) { 62 | // http://www.paulirish.com/2009/random-hex-color-code-snippets/ 63 | var nextColor = '#'+Math.floor(Math.random()*16777216).toString(16); 64 | node.find('.lodlive-node-label').css('backgroundColor', nextColor); 65 | } 66 | } 67 | ], 68 | tools: [ 69 | { builtin: 'remove' }, 70 | { builtin: 'rootNode'}, 71 | { builtin: 'expand' } 72 | ], 73 | // docInfo: function() {}, 74 | nodeHover: function() {}, 75 | relationships: { 76 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': { 77 | color: '#000' 78 | }, 79 | 'http://www.w3.org/2004/02/skos/core#broader': { 80 | color: '#69C' 81 | }, 82 | 'http://www.w3.org/2004/02/skos/core#related': { 83 | color: '#FFF444' 84 | } 85 | } 86 | }; 87 | 88 | ExampleProfile.endpoints = { 89 | all : 'output=json&format=json&timeout=0', 90 | jsonp: true 91 | }; 92 | -------------------------------------------------------------------------------- /js/profile/profile.marklogic.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var MarkLogicProfile = {}; 3 | 4 | // LodLive will match connection by the base URL of the query used, so the key must match the URL 5 | MarkLogicProfile.connection = { 6 | // http matches all http requests, so this will be the only connection settings used 7 | 'http:' : { 8 | sparqlX : { 9 | allClasses : 'SELECT DISTINCT ?object WHERE {[] a ?object}', 10 | findSubject : 'SELECT DISTINCT ?subject WHERE { {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} } LIMIT 1 ', 11 | documentUri : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object} ORDER BY ?property', 12 | document : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 13 | bnode : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 14 | inverse : 'SELECT DISTINCT * WHERE {?object ?property <{URI}>.} LIMIT 100', 15 | inverseSameAs : 'SELECT DISTINCT * WHERE {{?object <{URI}> } UNION { ?object <{URI}>}}' 16 | }, 17 | // endpoint : "http://localhost:8321/lodlive.xqy", 18 | endpoint : 'http://lodlive-ml1:8040/lodlive.xqy', 19 | description : { 20 | en : 'MarkLogic LodLive' 21 | } 22 | } 23 | }; 24 | 25 | // here we define the known relationships so that labels will appear 26 | MarkLogicProfile.arrows = { 27 | 'http://www.w3.org/2002/07/owl#sameAs' : 'isSameAs', 28 | 'http://purl.org/dc/terms/isPartOf' : 'isPartOf', 29 | 'http://purl.org/dc/elements/1.1/type' : 'isType', 30 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : 'isType', 31 | 'http://ieee.org/concept/coContrib' : 'Contributor To', 32 | 'http://ieee.org/concept/hasAffiliation' : 'Has Affiliation', 33 | }; 34 | 35 | // this is the default data configuration, this is important. It informs LodLive how to construct queries and how to read the data that comes back 36 | MarkLogicProfile.default = { 37 | sparql : { 38 | allClasses : 'SELECT DISTINCT ?object WHERE {[] < ?object}', 39 | findSubject : 'SELECT DISTINCT ?subject WHERE { {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} UNION {?subject a <{CLASS}>; ?object. FILTER(regex(str(?object),\'{VALUE}\',\'i\'))} } LIMIT 1 ', 40 | documentUri : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object} ORDER BY ?property', 41 | document : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 42 | bnode : 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 43 | inverse : 'SELECT DISTINCT * WHERE {?object ?property <{URI}>.} LIMIT 100', 44 | inverseSameAs : 'SELECT DISTINCT * WHERE {{?object <{URI}> } UNION { ?object <{URI}>}}' 45 | }, 46 | endpoint : 'http://labs.regesta.com/resourceProxy/', 47 | document : { 48 | className : 'standard', 49 | titleProperties : [ 50 | 'http://www.w3.org/2004/02/skos/core#prefLabel', 51 | 'http://xmlns.com/foaf/0.1/name', 52 | 'http://purl.org/dc/elements/1.1/title' 53 | ] 54 | }, // http://www.w3.org/2000/01/rdf-schema#label 55 | }; 56 | 57 | MarkLogicProfile.UI = { 58 | ignoreBnodes: true, 59 | nodeIcons: [ 60 | { builtin: 'tools' }, 61 | { builtin: 'docInfo' }, 62 | { 63 | icon: 'fa fa-thumb-tack', 64 | title: 'Pin in SPARQL', 65 | handler: function(node, inst) { 66 | var icon = this, pinner = inst.container.find('.rsuite-pinner'), pos, to, uri = node.attr('rel'); 67 | // make sure pinned exists on the instance 68 | function doTypeAhead(inp,uri) { 69 | var val = inp.val(); 70 | var resdiv = pinner.find('.rsuite-pinner-results').empty().addClass('loading'); 71 | var sparql = 'SELECT ?subject ?title WHERE { ' + 72 | '?subject <' + uri +'>; '+ 73 | ' ?title FILTER(contains(?title,"' + val + '")) '+ 74 | '}'; 75 | // console.log('sparql', sparql); 76 | //do the search 77 | $.ajax({ 78 | url: inst.options.connection['http:'].endpoint + '?' + inst.options.endpoints.all + '&query=' + encodeURIComponent(sparql), 79 | contentType: 'json', 80 | dataType: inst.getAjaxDataType(), 81 | success: function(resp) { 82 | var b = resp.results.bindings; 83 | if (!b.length) { 84 | resdiv.html('
no matches
'); 85 | return; 86 | } 87 | for (var i=0; i < b.length; i++) { 88 | $('
' + b[i].title.value + '
' ) 89 | .addClass(inst.rsuitePinned.indexOf(b[i].subject.value) > -1 ? 'rsuite-is-pinned' : '') 90 | .appendTo(resdiv); 91 | } 92 | }, 93 | error: function() { console.log('error', arguments); } 94 | }); 95 | } 96 | if (!pinner.length) { 97 | pinner = $('
').hide().appendTo(inst.container); 98 | var pinpanel = $('
').appendTo(pinner); 99 | pinpanel.append(''); 100 | pinpanel.append('
'); 101 | pinpanel.append('
type to search
'); 102 | pinpanel.append(''); 103 | pinpanel.find('.rsuite-pinner-text').on('keyup', function(evt) { 104 | //handle type ahead if not a modifier key 105 | if (evt.which && (evt.which >= 46 || evt.which === 8)) { 106 | var inp = $(this); 107 | clearTimeout(to); 108 | to = setTimeout(function() { doTypeAhead(inp, pinner.attr('pinner-uri')); },250); //timeout so val() gives the latest value 109 | } 110 | }); 111 | pinner.on('click',function(evt) { 112 | var t = $(evt.target); 113 | console.log('target',t); 114 | if (t.is('.rsuite-pinner-btn')) { 115 | pinner.fadeOut('fast'); 116 | } else { 117 | evt.preventDefault(); 118 | evt.stopPropagation(); 119 | } 120 | return false; 121 | }); 122 | pinpanel.on('click', '.rsuite-pinner-result-item', function() { 123 | var item = $(this), uri = item.data('pinned-value'), ind = inst.rsuitePinned.indexOf(uri), pinType = item.data('pinned-type'); 124 | console.log('uri %s, pinned index %d', uri, ind); 125 | item.toggleClass('rsuite-is-pinned'); 126 | // if it's in the array, remove it 127 | if (ind > -1) { 128 | inst.rsuitePinned.splice(ind,1); 129 | inst.rsuitePinTypes[pinType]--; 130 | if (item.parent('.rsuite-pinner-pinned').length) { 131 | item.slideUp('fast', function() { item.remove(); }); 132 | pinner.find('.rsuite-pinner-results .rsuite-pinner-result-item[data-pinned-value="' + uri + '"]').removeClass('rsuite-is-pinned'); 133 | } else { // remove it from the pinned results if it's there 134 | pinner.find('.rsuite-pinner-pinned .rsuite-pinner-result-item[data-pinned-value="' + uri + '"]').slideUp('fast', function() { $(this).remove(); }); 135 | } 136 | } else { 137 | inst.rsuitePinned.push(uri); 138 | if (!inst.rsuitePinTypes.hasOwnProperty(pinType)) { 139 | inst.rsuitePinTypes[pinType] = 0; 140 | } 141 | inst.rsuitePinTypes[pinType]++; 142 | pinner.find('.rsuite-pinner-pinned').append(item.clone()); 143 | } 144 | console.log('pintype %s, count %d', pinType, inst.rsuitePinTypes[pinType]); 145 | if (inst.rsuitePinTypes[pinType]) { 146 | inst.context.find('.lodlive-node[rel="'+pinType+'"]').addClass('pinned'); 147 | } else { 148 | inst.context.find('.lodlive-node[rel="'+pinType+'"]').removeClass('pinned'); 149 | } 150 | }); 151 | inst.context.parent().on('scroll', function() { console.log('on scroll'); pinner.fadeOut('fast'); }); 152 | if (!inst.rsuitePinned) { 153 | inst.rsuitePinned = []; // an array of each pinned iri 154 | inst.rsuitePinTypes = {}; // object collection of pinned types to highlight nodes 155 | } 156 | } else { 157 | pinner.find('.rsuite-pinner-results').empty(); 158 | } 159 | if (pinner.attr('pinner-uri') !== uri) { 160 | pinner.attr('pinner-uri', uri); 161 | pinner.fadeIn('fast'); 162 | pinner.find('.rsuite-pinner-pinned .rsuite-pinner-result-item').show().not('[data-pinned-type="' + uri +'"]').hide(); 163 | } else { 164 | clearTimeout(to); // just for safe measure 165 | pinner.fadeToggle('fast'); 166 | } 167 | pos = icon.offset(); 168 | pinner.css({ left: pos.left + 20, top: pos.top - 8 }); 169 | pinner.find('.rsuite-pinner-text').val('').focus(); 170 | } 171 | } 172 | ], 173 | tools: [ 174 | { builtin: 'close' }, 175 | { builtin: 'rootNode'}, 176 | { builtin: 'expand' } 177 | ], 178 | // docInfo: function() {}, 179 | nodeHover: function() {}, 180 | relationships: { 181 | 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type': { 182 | color: '#000' 183 | }, 184 | 'http://www.w3.org/2004/02/skos/core#broader': { 185 | color: '#69C' 186 | }, 187 | 'http://www.w3.org/2004/02/skos/core#related': { 188 | color: '#FFF444' 189 | }, 190 | 'http://ieee.org/concept/hasAffiliation': { 191 | color: '#588F27' 192 | }, 193 | 'http://ieee.org/concept/coContrib' : { 194 | color:'#DD4492' 195 | }, 196 | 'http://purl.org/dc/elements/1.1/contributor' : { 197 | color:'#04756F' 198 | }, 199 | 'http://ieee.org/concept/hasFundingAward' : { 200 | color:'#B9121B' 201 | }, 202 | 'http://ieee.org/concept/hasFunder' : { 203 | color:'#588F27' 204 | }, 205 | 'http://purl.org/d' : { 206 | color:'#04BFBF' 207 | } 208 | } 209 | }; 210 | 211 | MarkLogicProfile.endpoints = { 212 | all : 'output=json&format=json&timeout=0', 213 | jsonp: true 214 | }; 215 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Oct 14 2015 12:50:33 GMT-0400 (EDT) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai', 'sinon', 'fixture', 'browserify'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | 'node_modules/jquery/dist/jquery.js', 19 | 'node_modules/sinon-chai/lib/sinon-chai.js', 20 | 'src/*.js', 21 | 'js/deps/*.js', 22 | 'js/lib/*.js', 23 | 'js/profile/profile.example.js', 24 | 'test/**/*.js', 25 | 'test/fixtures/*.json' 26 | ], 27 | 28 | 29 | // list of files to exclude 30 | exclude: [], 31 | 32 | 33 | // preprocess matching files before serving them to the browser 34 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 35 | preprocessors: { 36 | 'js/lib/*.js': ['coverage'], 37 | 'js/lib/lodlive.core.js': ['browserify'], 38 | 'src/*.js': ['coverage', 'browserify'], 39 | '**/*.json': ['json_fixtures'] 40 | }, 41 | 42 | 43 | browserify: { 44 | debug: true, 45 | transform: [ 'browserify-istanbul' ] 46 | }, 47 | 48 | 49 | // test results reporter to use 50 | // possible values: 'dots', 'progress' 51 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 52 | reporters: ['progress', 'coverage'], 53 | 54 | 55 | coverageReporter: { 56 | reporters: [ 57 | // enable this once there's some moderate level of coverage ;) 58 | // { type : 'text-summary' }, 59 | { type : 'lcov', dir : 'coverage/' } 60 | ] 61 | }, 62 | 63 | 64 | jsonFixturesPreprocessor: { 65 | variableName: '__json__' 66 | }, 67 | 68 | 69 | // web server port 70 | port: 9876, 71 | 72 | 73 | // enable / disable colors in the output (reporters and logs) 74 | colors: true, 75 | 76 | 77 | // level of logging 78 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 79 | logLevel: config.LOG_INFO, 80 | 81 | 82 | // enable / disable watching file and executing tests whenever any file changes 83 | autoWatch: false, 84 | 85 | 86 | // start these browsers 87 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 88 | browsers: ['PhantomJS'], 89 | 90 | 91 | // Continuous Integration mode 92 | // if true, Karma captures browsers, runs the tests and exits 93 | singleRun: true 94 | }) 95 | } 96 | -------------------------------------------------------------------------------- /lodlive.xqy: -------------------------------------------------------------------------------- 1 | xquery version "1.0-ml"; 2 | 3 | 4 | import module namespace semmod = "http://marklogic.com/rest-api/models/semantics" 5 | at "/MarkLogic/rest-api/models/semantics-model.xqy"; 6 | import module namespace eput = "http://marklogic.com/rest-api/lib/endpoint-util" 7 | at "/MarkLogic/rest-api/lib/endpoint-util.xqy"; 8 | 9 | declare option xdmp:mapping "false"; 10 | 11 | let $params := map:map() 12 | let $_ := for $i in xdmp:get-request-field-names() return map:put($params, $i, xdmp:get-request-field($i)) 13 | let $headers := eput:get-request-headers() 14 | 15 | let $result := semmod:sparql-query($headers,$params,()) 16 | let $response := semmod:results-payload($headers,$params,$result) 17 | let $_ := xdmp:set-response-content-type($response[1]) 18 | 19 | return ( 20 | if (map:get($params, "callback")) then fn:concat(map:get($params, "callback"), "(") else (), 21 | $response[2], 22 | if (map:get($params, "callback")) then ")" else () 23 | 24 | ) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ml-lodlive", 3 | "version": "0.3.1", 4 | "repository": "https://github.com/withjam/ml-lodlive.git", 5 | "license": "Apache-2.0", 6 | "scripts": { 7 | "test": "karma start" 8 | }, 9 | "devDependencies": { 10 | "browserify": "^11.1.0", 11 | "browserify-istanbul": "^0.2.1", 12 | "chai": "^3.3.0", 13 | "gulp": "^3.9.0", 14 | "gulp-add-src": "^0.2.0", 15 | "gulp-concat": "^2.4.3", 16 | "gulp-gzip": "0.0.8", 17 | "gulp-rename": "^1.2.0", 18 | "gulp-tar": "^1.3.2", 19 | "gulp-uglify": "^1.1.0", 20 | "jquery": "^2.1.4", 21 | "karma": "^0.13.10", 22 | "karma-browserify": "^4.3.0", 23 | "karma-chai": "^0.1.0", 24 | "karma-coverage": "^0.5.2", 25 | "karma-fixture": "^0.2.5", 26 | "karma-json-fixtures-preprocessor": "0.0.5", 27 | "karma-mocha": "^0.2.0", 28 | "karma-phantomjs-launcher": "^0.2.0", 29 | "karma-sinon": "^1.0.4", 30 | "mocha": "^2.3.3", 31 | "phantomjs": "^1.9.18", 32 | "sinon": "^1.17.1", 33 | "sinon-chai": "^2.8.0", 34 | "vinyl-buffer": "^1.0.0", 35 | "vinyl-source-stream": "^1.1.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / -------------------------------------------------------------------------------- /src/draggable.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function enableDrag(container, context, draggableSelector, dragStart) { 4 | var $window = $(window); 5 | var parent = context.parent(); 6 | var dragState = {}; 7 | var dragStop = null; 8 | 9 | // watch mouse move events on the container to move anything being dragged 10 | container.on('mousemove', function(event) { 11 | var cx = event.clientX; 12 | var cy = event.clientY; 13 | var lastx = dragState.lastx; 14 | var lasty = dragState.lasty; 15 | dragState.lastx = cx; 16 | dragState.lasty = cy; 17 | 18 | // dragging a node 19 | if (dragState.target) { 20 | if (!dragState.isDragging) { 21 | // just started the drag 22 | dragState.isDragging = true; 23 | dragStop = dragStart(dragState); 24 | 25 | // cache positions that won't change while dragging 26 | dragState.scrollX = parent.scrollLeft() + $window.scrollLeft() - parent.offset().left - dragState.offsetX; 27 | dragState.scrollY = parent.scrollTop() + $window.scrollTop() - parent.offset().top - dragState.offsetY; 28 | } 29 | 30 | requestAnimationFrame(function() { 31 | dragState.target && dragState.target.css({ 32 | left: cx + dragState.scrollX, 33 | top: cy + dragState.scrollY 34 | }); 35 | }); 36 | } else if (dragState.panning) { 37 | requestAnimationFrame(function() { 38 | parent.scrollLeft(parent.scrollLeft() + lastx - cx); 39 | parent.scrollTop(parent.scrollTop() + lasty - cy); 40 | }); 41 | } 42 | }); 43 | 44 | container.on('mousedown', draggableSelector, function(event) { 45 | // mark the node as being dragged using event-delegation 46 | dragState.target = $(this); 47 | dragState.panning = false; 48 | 49 | // store offset of event so node moves properly 50 | dragState.offsetX = event.offsetX; 51 | dragState.offsetY = event.offsetY; 52 | 53 | event.stopPropagation(); 54 | event.preventDefault(); 55 | }); 56 | 57 | container.on('mousedown', function(event) { 58 | dragState.target = null; 59 | dragState.panning = true; 60 | event.stopPropagation(); 61 | event.preventDefault(); 62 | }); 63 | 64 | function cancelDrag() { 65 | if (dragStop) dragStop(); 66 | dragStop = null; 67 | dragState.isDragging = false; 68 | dragState.target = null; 69 | dragState.panning = false; 70 | } 71 | 72 | container.on('mouseup', cancelDrag); 73 | 74 | $(document).on('keydown', function(event) { 75 | // esc key 76 | if (event.keyCode === 27) { 77 | cancelDrag(); 78 | } 79 | }); 80 | } 81 | 82 | module.exports = enableDrag; 83 | -------------------------------------------------------------------------------- /src/http-client.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var httpClientFactory = { 4 | /* 5 | * Create a new httpClient instance 6 | * 7 | * @param {Object} connection - connection configuration 8 | * @prop {String} connection.endpoint - the request endpoint URL 9 | * @prop {Object|String} connection.defaultParams - the default URL params 10 | * @prop {Object} connection.headers - request headers 11 | * @prop {Boolean} jsonp - make a JSONP request instead of AJAX 12 | * @return {Function} an httpClient instance 13 | */ 14 | create: function(connection) { 15 | if (!connection.endpoint) { 16 | throw new Error('missing required connection.endpoint for httpClient'); 17 | } 18 | 19 | function parseParams(params) { 20 | if (!connection.defaultParams) { 21 | return $.param(params) 22 | } else if (typeof connection.defaultParams === 'object') { 23 | return $.param($.extend({}, connection.defaultParams, params)) 24 | } else { 25 | return connection.defaultParams + '&' + $.param(params) 26 | } 27 | } 28 | 29 | /** 30 | * Makes an http request 31 | * 32 | * @param {Object} params - URL params 33 | * @param {Object} callbacks 34 | * 35 | * @prop {Function} callbacks.beforeSend 36 | * @prop {Function} callbacks.success 37 | * @prop {Function} callbacks.error 38 | */ 39 | return function httpClient(params, callbacks) { 40 | 41 | var fullUrl = connection.endpoint + '?' + parseParams(params); 42 | var afterSend; 43 | 44 | $.ajax({ 45 | url: fullUrl, 46 | contentType: 'application/json', 47 | dataType: connection.jsonp ? 'jsonp': 'json', 48 | headers: connection.headers || {}, 49 | beforeSend: function() { 50 | if (callbacks.beforeSend) afterSend = callbacks.beforeSend(); 51 | }, 52 | success: function() { 53 | if (afterSend) afterSend(); 54 | if (callbacks.success) callbacks.success.apply(null, arguments); 55 | }, 56 | error: function() { 57 | if (afterSend) afterSend(); 58 | if (callbacks.error) callbacks.error.apply(null, arguments); 59 | } 60 | }); 61 | } 62 | } 63 | }; 64 | 65 | module.exports = httpClientFactory; 66 | 67 | // temporary, for testing 68 | if (!window.httpClientFactory) { 69 | window.httpClientFactory = httpClientFactory; 70 | } 71 | -------------------------------------------------------------------------------- /src/ref-store.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function LodLiveRefStore() {} 4 | 5 | /** 6 | * Gets the Ids of all active objects with references from `subject` 7 | * 8 | * @param {String} subject - the Id of an active subject 9 | * @return {Array} object Ids 10 | */ 11 | LodLiveRefStore.prototype.getObjectRefs = function(subject) { 12 | return this.storeIds['gen' + subject] || []; 13 | }; 14 | 15 | /** 16 | * Sets `objects` as the list of references from `subject` 17 | * 18 | * @param {String} subject - the Id of an active subject 19 | * @param {Array} objects - the Ids of `subject`'s objects 20 | */ 21 | LodLiveRefStore.prototype.setObjectRefs = function(subject, objects) { 22 | this.storeIds['gen' + subject] = objects; 23 | } 24 | 25 | /** 26 | * Adds an active object reference from `subject` 27 | * 28 | * @param {String} subject - the Id of an active subject 29 | * @param {String} object - the Id of an object of `subject` 30 | */ 31 | LodLiveRefStore.prototype.addObjectRef = function(subject, object) { 32 | var objects = this.getObjectRefs(subject); 33 | 34 | if (objects.indexOf(object) === -1) { 35 | objects.push(object); 36 | } 37 | 38 | this.setObjectRefs(subject, objects); 39 | }; 40 | 41 | /** 42 | * Removes an active object reference from `subject` 43 | * 44 | * @param {String} subject - the Id of an active subject 45 | * @param {String} object - the Id of an object of `subject` 46 | */ 47 | LodLiveRefStore.prototype.removeObjectRef = function(subject, object) { 48 | var objects = this.getObjectRefs(subject); 49 | var index = objects.indexOf(object); 50 | 51 | if (index > -1) { 52 | objects.splice(index, 1); 53 | } 54 | }; 55 | 56 | /** 57 | * Removes all references to `object` 58 | * 59 | * @param {String} object - the Id of an object 60 | */ 61 | LodLiveRefStore.prototype.removeAsObject = function(object) { 62 | delete this.storeIds['rev' + object]; 63 | }; 64 | 65 | /** 66 | * Gets the Ids of all active subjects with references to `object` 67 | * 68 | * @param {String} object - the Id of an active object 69 | * @return {Array} subject Ids 70 | */ 71 | LodLiveRefStore.prototype.getSubjectRefs = function(object) { 72 | return this.storeIds['rev' + object] || []; 73 | }; 74 | 75 | /** 76 | * Sets `subjects` as the list of references from `object` 77 | * 78 | * @param {String} subjects - the Ids of `object`'s subjects 79 | * @param {Array} object - the Id of an active object 80 | */ 81 | LodLiveRefStore.prototype.setSubjectRefs = function(object, subjects) { 82 | this.storeIds['rev' + object] = subjects; 83 | } 84 | 85 | /** 86 | * Adds an active subject reference to `object` 87 | * 88 | * @param {String} object - the Id of an active object 89 | * @param {String} subject - the Id of a subject of `object` 90 | */ 91 | LodLiveRefStore.prototype.addSubjectRef = function(object, subject) { 92 | var subjects = this.getSubjectRefs(object); 93 | 94 | if (subjects.indexOf(subject) === -1) { 95 | subjects.push(subject); 96 | } 97 | 98 | this.setSubjectRefs(object, subjects); 99 | }; 100 | 101 | /** 102 | * Removes an active subject reference from `object` 103 | * 104 | * @param {String} object - the Id of an active object 105 | * @param {String} subject - the Id of a subject of `object` 106 | */ 107 | LodLiveRefStore.prototype.removeSubjectRef = function(object, subject) { 108 | var subjects = this.getSubjectRefs(object); 109 | var index = subjects.indexOf(subject); 110 | 111 | if (index > -1) { 112 | subjects.splice(index, 1); 113 | } 114 | }; 115 | 116 | /** 117 | * Removes all references from `subject` 118 | * 119 | * @param {String} subject - the Id of an subject 120 | */ 121 | LodLiveRefStore.prototype.removeAsSubject = function(subject) { 122 | delete this.storeIds['gen' + subject]; 123 | }; 124 | 125 | var refStoreFactory = { 126 | create: function () { 127 | var store = Object.create(LodLiveRefStore.prototype); 128 | store.storeIds = {}; 129 | return store; 130 | } 131 | }; 132 | 133 | module.exports = refStoreFactory; 134 | 135 | // temporary, for testing 136 | if (!window.refStoreFactory) { 137 | window.refStoreFactory = refStoreFactory; 138 | } 139 | -------------------------------------------------------------------------------- /src/sparql-client.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var defaultQueries = { 4 | documentUri: 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object} ORDER BY ?property', 5 | document: 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 6 | bnode: 'SELECT DISTINCT * WHERE {<{URI}> ?property ?object}', 7 | inverse: 'SELECT DISTINCT * WHERE {?object ?property <{URI}>.} LIMIT 100', 8 | inverseSameAs: 'SELECT DISTINCT * WHERE {{?object <{URI}> } UNION { ?object <{URI}>}}' 9 | }; 10 | 11 | function parseResults(bindings) { 12 | var info = { uris: [], bnodes: [], values: [] }; 13 | 14 | $.each(bindings, function(key, value) { 15 | var newVal = {}; 16 | newVal[value.property.value] = value.object.value; 17 | if (value.object.type === 'uri') { 18 | info.uris.push(newVal); 19 | } else if (value.object.type === 'bnode') { 20 | info.bnodes.push(newVal); 21 | } else { 22 | info.values.push(newVal); 23 | } 24 | }); 25 | 26 | return info; 27 | } 28 | 29 | function SparqlClient(httpClientFactory, options) { 30 | if (!(this instanceof SparqlClient)) { 31 | return new SparqlClient(httpClientFactory, options); 32 | } 33 | 34 | this.httpClient = httpClientFactory.create(options.connection); 35 | 36 | this.getQueryTemplate = function(axis) { 37 | return options.queries && options.queries[axis] ? 38 | options.queries[axis] : 39 | defaultQueries[axis]; 40 | }; 41 | } 42 | 43 | SparqlClient.prototype.getQuery = function getQuery(axis, iri) { 44 | return this.getQueryTemplate(axis) 45 | .replace(/\{URI\}/ig, iri.replace(/^.*~~/, '')); 46 | }; 47 | 48 | SparqlClient.prototype.document = function document(iri, callbacks) { 49 | var axis = 'document'; 50 | var query = this.getQuery(axis, iri); 51 | 52 | return this.httpClient({ query: query }, { 53 | beforeSend: callbacks.beforeSend, 54 | error: callbacks.error, 55 | success : function(json) { 56 | if ( !(json && json.results && json.results.bindings) ) { 57 | console.error(json); 58 | return callbacks.error(new Error('malformed results')); 59 | } 60 | 61 | callbacks.success( parseResults(json.results.bindings) ); 62 | } 63 | }); 64 | }; 65 | 66 | SparqlClient.prototype.bnode = function bnode(iri, callbacks) { 67 | var axis = 'bnode'; 68 | var query = this.getQuery(axis, iri); 69 | 70 | return this.httpClient({ query: query }, { 71 | beforeSend: callbacks.beforeSend, 72 | error: callbacks.error, 73 | success : function(json) { 74 | if ( !(json && json.results && json.results.bindings) ) { 75 | console.error(json); 76 | return callbacks.error(new Error('malformed results')); 77 | } 78 | 79 | callbacks.success( parseResults(json.results.bindings) ); 80 | } 81 | }); 82 | }; 83 | 84 | SparqlClient.prototype.documentUri = function documentUri(iri, callbacks) { 85 | var axis = 'documentUri'; 86 | var query = this.getQuery(axis, iri); 87 | 88 | return this.httpClient({ query: query }, { 89 | beforeSend: callbacks.beforeSend, 90 | error: callbacks.error, 91 | success : function(json) { 92 | if ( !(json && json.results && json.results.bindings) ) { 93 | console.error(json); 94 | return callbacks.error(new Error('malformed results')); 95 | } 96 | 97 | callbacks.success( parseResults(json.results.bindings) ); 98 | } 99 | }); 100 | }; 101 | 102 | SparqlClient.prototype.inverse = function inverse(iri, callbacks) { 103 | var axis = 'inverse'; 104 | var query = this.getQuery(axis, iri); 105 | 106 | return this.httpClient({ query: query }, { 107 | beforeSend: callbacks.beforeSend, 108 | error: callbacks.error, 109 | success : function(json) { 110 | if ( !(json && json.results && json.results.bindings) ) { 111 | console.error(json); 112 | return callbacks.error(new Error('malformed results')); 113 | } 114 | 115 | callbacks.success( parseResults(json.results.bindings) ); 116 | } 117 | }); 118 | }; 119 | 120 | SparqlClient.prototype.inverseSameAs = function inverseSameAs(iri, callbacks) { 121 | var axis = 'inverseSameAs'; 122 | var query = this.getQuery(axis, iri); 123 | 124 | return this.httpClient({ query: query }, callbacks); 125 | }; 126 | 127 | 128 | var sparqlClientFactory = { 129 | create: function(httpClientFactory, options) { 130 | return new SparqlClient(httpClientFactory, options); 131 | } 132 | }; 133 | 134 | module.exports = sparqlClientFactory; 135 | 136 | // temporary, for testing 137 | if (!window.sparqlClientFactory) { 138 | window.sparqlClientFactory = sparqlClientFactory; 139 | } 140 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _translations = {}; 4 | 5 | /** 6 | * Register a set of translations, for example ('en-us', { greeting: 'Hello' }) 7 | */ 8 | function registerTranslation(langKey, data) { 9 | _translations[langKey] = data; 10 | } 11 | 12 | function setDefaultTranslation(langKey) { 13 | _translations['default'] = _translations[langKey] || _translations['default']; 14 | } 15 | 16 | function lang(obj, langKey) { 17 | var lang = langKey ? _translations[langKey] || _translations['default'] : _translations['default']; 18 | return (lang && lang[obj]) || obj; 19 | } 20 | 21 | // TODO: remove 22 | function breakLines(msg) { 23 | msg = msg.replace(/\//g, '/ '); 24 | msg = msg.replace(/&/g, '& '); 25 | msg = msg.replace(/%/g, '% '); 26 | return msg; 27 | } 28 | 29 | function hashFunc(str) { 30 | if (!str) { return str; } 31 | for(var r=0, i=0; i lastHash ? str.substring(lastSlash + 1) : str.substring(lastHash + 1); 42 | } 43 | 44 | function circleChords(radius, steps, centerX, centerY, breakAt, onlyElement) { 45 | var values = []; 46 | var i = 0; 47 | if (onlyElement) { 48 | // ottimizzo i cicli evitando di calcolare elementi che non 49 | // servono 50 | i = onlyElement; 51 | var radian = (2 * Math.PI) * (i / steps); 52 | values.push([centerX + radius * Math.cos(radian), centerY + radius * Math.sin(radian)]); 53 | } else { 54 | for (; i < steps; i++) { 55 | // calcolo le coodinate lungo il cerchio del box per 56 | // posizionare 57 | // strumenti ed altre risorse 58 | var radian = (2 * Math.PI) * (i / steps); 59 | values.push([centerX + radius * Math.cos(radian), centerY + radius * Math.sin(radian)]); 60 | } 61 | } 62 | return values; 63 | } 64 | 65 | var LodLiveUtils = { 66 | registerTranslation: registerTranslation, 67 | setDefaultTranslation: setDefaultTranslation, 68 | lang: lang, 69 | breakLines: breakLines, 70 | hashFunc: hashFunc, 71 | shortenKey: shortenKey, 72 | circleChords: circleChords 73 | }; 74 | 75 | module.exports = LodLiveUtils; 76 | 77 | if (!window.LodLiveUtils) { 78 | window.LodLiveUtils = LodLiveUtils; 79 | } 80 | -------------------------------------------------------------------------------- /test-marklogic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LodLive Testing 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /test/fixtures/basic-results.json: -------------------------------------------------------------------------------- 1 | { "head": { "link": [], "vars": ["property", "object"] }, 2 | "results": { "distinct": false, "ordered": true, "bindings": [ 3 | { "property": { "type": "uri", "value": "http://dbpedia.org/ontology/alias" } , "object": { "type": "literal", "xml:lang": "en", "value": "Smith, Will" }}, 4 | { "property": { "type": "uri", "value": "http://dbpedia.org/ontology/birthPlace" } , "object": { "type": "uri", "value": "http://dbpedia.org/resource/Pennsylvania" }}, 5 | { "property": { "type": "uri", "value": "http://purl.org/voc/vrank#hasRank" } , "object": { "type": "bnode", "value": "nodeID://b20469592" }} ] } } 6 | -------------------------------------------------------------------------------- /test/spec/http-client.js: -------------------------------------------------------------------------------- 1 | describe('httpClient', function () { 2 | before(function () { 3 | this.sandbox = sinon.sandbox.create() 4 | }) 5 | 6 | afterEach(function () { 7 | this.sandbox.restore() 8 | }) 9 | 10 | it('should exist', function () { 11 | expect(window.httpClientFactory).not.to.be.undefined 12 | }) 13 | 14 | it('should throw an error if missing endpoint', function () { 15 | var fn = function () { httpClientFactory.create({}) } 16 | expect(fn).to.throw('missing required connection.endpoint for httpClient') 17 | }) 18 | 19 | it('should create a client', function () { 20 | var httpClient = httpClientFactory.create({ endpoint: 'here' }) 21 | expect(httpClient).not.to.be.undefined 22 | 23 | httpClient({}, {}) 24 | }) 25 | 26 | it('should use connection configuration', function () { 27 | var self = this 28 | var ajax = this.sandbox.stub($, 'ajax') 29 | var connection = { 30 | endpoint: 'endpoint', 31 | defaultParams: 'param=value', 32 | headers: { Accept: 'accepts' } 33 | } 34 | var httpClient = httpClientFactory.create(connection) 35 | 36 | httpClient({ query: 'QUERY' }, {}) 37 | 38 | expect(ajax).to.have.been.calledOnce 39 | 40 | var args = ajax.args[0][0] 41 | expect(args.url).to.equal('endpoint?param=value&query=QUERY') 42 | expect(args.contentType).to.equal('application/json') 43 | expect(args.headers.Accept).to.equal('accepts') 44 | expect(args.dataType).to.equal('json') 45 | 46 | args.beforeSend() 47 | args.success() 48 | args.error() 49 | }) 50 | 51 | it('should invoke callbacks', function () { 52 | var self = this 53 | var ajax = this.sandbox.stub($, 'ajax') 54 | var afterSend = this.sandbox.stub() 55 | var callbacks = { 56 | beforeSend: self.sandbox.stub().returns(afterSend), 57 | success: self.sandbox.stub(), 58 | error: self.sandbox.stub() 59 | } 60 | var connection = { 61 | endpoint: 'endpoint', 62 | defaultParams: { param: 'value' }, 63 | jsonp: true 64 | } 65 | 66 | var httpClient = httpClientFactory.create(connection) 67 | 68 | httpClient({ query: 'QUERY' }, callbacks) 69 | 70 | expect(ajax).to.have.been.calledOnce 71 | 72 | var args = ajax.args[0][0] 73 | 74 | expect(args.url).to.equal('endpoint?param=value&query=QUERY') 75 | 76 | args.beforeSend() 77 | expect(callbacks.beforeSend).to.have.been.calledOnce 78 | 79 | args.success() 80 | expect(afterSend).to.have.been.calledOnce 81 | expect(callbacks.success).to.have.been.calledOnce 82 | 83 | args.error() 84 | expect(afterSend).to.have.been.calledTwice 85 | expect(callbacks.error).to.have.been.calledOnce 86 | }) 87 | }) 88 | -------------------------------------------------------------------------------- /test/spec/lodlive.js: -------------------------------------------------------------------------------- 1 | describe('lodlive', function () { 2 | before(function () { 3 | this.sandbox = sinon.sandbox.create(); 4 | this.fixtures = { 5 | willSmith: fixture.load('test/fixtures/will-smith.json') 6 | }; 7 | 8 | var requests = this.requests = []; 9 | this.xhr = sinon.useFakeXMLHttpRequest(); 10 | this.xhr.onCreate = function (xhr) { 11 | requests.push(xhr); 12 | }; 13 | }); 14 | 15 | after(function () { 16 | this.xhr.restore(); 17 | }); 18 | 19 | beforeEach(function () { 20 | var fixture = '
'; 21 | document.body.insertAdjacentHTML('afterbegin', fixture); 22 | }); 23 | 24 | afterEach(function () { 25 | this.requests.length = 0; 26 | this.sandbox.restore(); 27 | document.body.removeChild(document.getElementById('graph')); 28 | }); 29 | 30 | it('should init', function () { 31 | var firstBox = this.sandbox.spy(LodLiveRenderer.prototype, 'firstBox'); 32 | var openDoc = this.sandbox.spy(LodLive.prototype, 'openDoc'); 33 | 34 | var firstUri = 'http://dbpedia.org/resource/Will_Smith'; 35 | 36 | // disable jsonp to force XHR 37 | ExampleProfile.endpoints.jsonp = false; 38 | jQuery('#graph').lodlive({ profile: ExampleProfile, firstUri: firstUri }); 39 | 40 | expect(firstBox).to.have.been.calledOnce; 41 | expect(openDoc).to.have.been.calledOnce; 42 | 43 | expect(this.requests.length).to.equal(1); 44 | expect(this.requests[0].url).to.match(/^http:\/\/dbpedia.org\/sparql/); 45 | 46 | expect($('#graph .lodlive-graph-container').length).to.equal(1); 47 | expect($('#graph .lodlive-graph-context').length).to.equal(1); 48 | expect($('#graph .lodlive-node').length).to.equal(1); 49 | 50 | var node = $('#graph .lodlive-node').first(); 51 | expect(node.attr('rel')).to.equal(firstUri); 52 | expect(node.data('endpoint')).to.equal('http://dbpedia.org/sparql'); 53 | }); 54 | 55 | it('should render sparql results', function () { 56 | var firstBox = this.sandbox.spy(LodLiveRenderer.prototype, 'firstBox'); 57 | var openDoc = this.sandbox.spy(LodLive.prototype, 'openDoc'); 58 | var format = this.sandbox.spy(LodLive.prototype, 'format'); 59 | var addNewDoc = this.sandbox.spy(LodLive.prototype, 'addNewDoc'); 60 | var formatDoc = this.sandbox.spy(LodLive.prototype, 'formatDoc'); 61 | 62 | var firstUri = 'http://dbpedia.org/resource/Will_Smith'; 63 | 64 | // disable jsonp to force XHR 65 | ExampleProfile.endpoints.jsonp = false; 66 | // ExampleProfile.debugOn = true; 67 | jQuery('#graph').lodlive({ profile: ExampleProfile, firstUri: firstUri }); 68 | jQuery('#graph').data('lodlive-instance').doInverse = false; 69 | 70 | expect(firstBox).to.have.been.calledOnce; 71 | expect(openDoc).to.have.been.calledOnce; 72 | 73 | expect(this.requests.length).to.equal(1); 74 | 75 | this.requests[0].respond(200, { 76 | "Content-Type": "application/json" 77 | }, 78 | JSON.stringify(this.fixtures.willSmith) 79 | ); 80 | 81 | expect(format).to.have.been.calledOnce; 82 | 83 | expect($('#graph .box').length).to.equal(1); 84 | expect($('#graph .lodlive-node .groupedRelatedBox').length).to.equal(6); 85 | expect($('#graph .lodlive-node .relatedBox').length).to.equal(84); 86 | 87 | $('#graph .lodlive-node .relatedBox').first().trigger('click'); 88 | 89 | expect(addNewDoc).to.have.been.calledOnce; 90 | expect(openDoc).to.have.been.calledTwice; 91 | 92 | expect(this.requests.length).to.equal(2); 93 | 94 | expect($('#graph .box').length).to.equal(2); 95 | 96 | expect($('.lodlive-docinfo').length).to.equal(0); 97 | 98 | $('#graph .docInfo').first().trigger('click'); 99 | 100 | expect(this.requests.length).to.equal(3); 101 | 102 | this.requests[2].respond(200, { 103 | "Content-Type": "application/json" 104 | }, 105 | JSON.stringify(this.fixtures.willSmith) 106 | ); 107 | 108 | expect(formatDoc).to.have.been.calledOnce; 109 | 110 | expect($('.lodlive-docinfo').length).to.equal(1); 111 | expect($('.lodlive-docinfo .section').length).to.equal(15); 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /test/spec/ref-store.js: -------------------------------------------------------------------------------- 1 | describe('ref-store', function () { 2 | it('should exist', function () { 3 | expect(window.refStoreFactory).not.to.be.undefined 4 | }) 5 | 6 | it('should create an instance', function () { 7 | var refs = refStoreFactory.create() 8 | expect(refStoreFactory).not.to.be.undefined 9 | }) 10 | 11 | it('should set subject refs', function () { 12 | var refs = refStoreFactory.create() 13 | var x = [1, 2] 14 | 15 | refs.setSubjectRefs('a', x) 16 | expect(refs.getSubjectRefs('a')).to.equal(x) 17 | }) 18 | 19 | it('should add subject refs', function () { 20 | var refs = refStoreFactory.create() 21 | 22 | refs.addSubjectRef('a', 'b') 23 | expect(refs.getSubjectRefs('a')[0]).to.equal('b') 24 | 25 | refs.addSubjectRef('a', 'z') 26 | expect(refs.getSubjectRefs('a')[1]).to.equal('z') 27 | }) 28 | 29 | it('should not add add duplicate subject ref', function () { 30 | var refs = refStoreFactory.create() 31 | 32 | refs.addSubjectRef('a', 'b') 33 | refs.addSubjectRef('a', 'b') 34 | expect(refs.getSubjectRefs('a').length).to.equal(1) 35 | expect(refs.getSubjectRefs('a')[0]).to.equal('b') 36 | }) 37 | 38 | it('should remove subject refs', function () { 39 | var refs = refStoreFactory.create() 40 | var x = [1, 2] 41 | 42 | refs.setSubjectRefs('a', x) 43 | refs.removeSubjectRef('a', 2) 44 | expect(refs.getSubjectRefs('a').length).to.equal(1) 45 | }) 46 | 47 | it('should not remove non-existent subject ref', function () { 48 | var refs = refStoreFactory.create() 49 | var x = [1, 2] 50 | 51 | refs.setSubjectRefs('a', x) 52 | refs.removeSubjectRef('a', 3) 53 | expect(refs.getSubjectRefs('a').length).to.equal(2) 54 | }) 55 | 56 | it('should remove id as object', function () { 57 | var refs = refStoreFactory.create() 58 | var x = [1, 2] 59 | 60 | refs.setSubjectRefs('a', x) 61 | refs.removeAsObject('a') 62 | expect(refs.getSubjectRefs('a').length).to.equal(0) 63 | }) 64 | 65 | it('should set object refs', function () { 66 | var refs = refStoreFactory.create() 67 | var x = [0, 'd'] 68 | 69 | refs.setObjectRefs('x', x) 70 | expect(refs.getObjectRefs('x')).to.equal(x) 71 | }) 72 | 73 | it('should add object refs', function () { 74 | var refs = refStoreFactory.create() 75 | 76 | refs.addObjectRef('d', 'q') 77 | expect(refs.getObjectRefs('d')[0]).to.equal('q') 78 | 79 | refs.addObjectRef('d', 'm') 80 | expect(refs.getObjectRefs('d')[1]).to.equal('m') 81 | }) 82 | 83 | it('should not duplicate object refs', function () { 84 | var refs = refStoreFactory.create() 85 | 86 | refs.addObjectRef('d', 'q') 87 | refs.addObjectRef('d', 'q') 88 | expect(refs.getObjectRefs('d').length).to.equal(1) 89 | expect(refs.getObjectRefs('d')[0]).to.equal('q') 90 | }) 91 | 92 | it('should remove object refs', function () { 93 | var refs = refStoreFactory.create() 94 | var x = [0, 'd'] 95 | 96 | refs.setObjectRefs('x',x) 97 | refs.removeObjectRef('x','d') 98 | expect(refs.getObjectRefs('x').length).to.equal(1) 99 | }) 100 | 101 | it('should not remove non-existent object refs', function () { 102 | var refs = refStoreFactory.create() 103 | var x = [0, 'd'] 104 | 105 | refs.setObjectRefs('x',x) 106 | refs.removeObjectRef('x','z') 107 | expect(refs.getObjectRefs('x').length).to.equal(2) 108 | }) 109 | 110 | it('should remove id as subject', function () { 111 | var refs = refStoreFactory.create() 112 | var x = [0, 'd'] 113 | 114 | refs.setObjectRefs('x',x) 115 | refs.removeAsSubject('x') 116 | expect(refs.getObjectRefs('x').length).to.equal(0) 117 | }) 118 | }) 119 | -------------------------------------------------------------------------------- /test/spec/sparql-client.js: -------------------------------------------------------------------------------- 1 | describe('sparqlClient', function () { 2 | before(function () { 3 | this.sandbox = sinon.sandbox.create() 4 | this.fixtures = { 5 | basicResults: fixture.load('test/fixtures/basic-results.json') 6 | } 7 | this.makeFactory = function(stub) { 8 | return { 9 | create: function() { return stub } 10 | } 11 | } 12 | }) 13 | 14 | afterEach(function () { 15 | this.sandbox.restore() 16 | }) 17 | 18 | it('should exist', function () { 19 | expect(window.sparqlClientFactory).not.to.be.undefined 20 | }) 21 | 22 | it('should create a client', function () { 23 | var sparqlClient = sparqlClientFactory.create(this.makeFactory({}), {}) 24 | expect(sparqlClient).not.to.be.undefined 25 | }) 26 | 27 | it('should parse queries and make request', function () { 28 | var profile = { queries: { document: 'QUERY' } } 29 | var httpStub = this.sandbox.stub() 30 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 31 | 32 | sparqlClient.document('', {}) 33 | expect(httpStub).to.have.been.calledOnce 34 | expect(httpStub.args[0][0].query).to.equal('QUERY') 35 | }) 36 | 37 | it('should yield an error with invalid results (document)', function () { 38 | var profile = { queries: { document: 'QUERY' } } 39 | var httpStub = this.sandbox.stub() 40 | var errorStub = this.sandbox.stub() 41 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 42 | 43 | sparqlClient.document('', { error: errorStub }) 44 | 45 | expect(httpStub).to.have.been.calledOnce 46 | expect(httpStub.args[0][0].query).to.equal('QUERY') 47 | 48 | var success = httpStub.args[0][1].success 49 | success({ results: { data: {} } }) 50 | 51 | expect(errorStub).to.have.been.calledOnce 52 | expect(errorStub.args[0][0]).to.match(/malformed results/) 53 | }) 54 | 55 | it('should parse results (document)', function () { 56 | var profile = { queries: { document: 'QUERY' } } 57 | var httpStub = this.sandbox.stub() 58 | var successStub = this.sandbox.stub() 59 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 60 | 61 | sparqlClient.document('', { success: successStub }) 62 | 63 | expect(httpStub).to.have.been.calledOnce 64 | expect(httpStub.args[0][0].query).to.equal('QUERY') 65 | 66 | var success = httpStub.args[0][1].success 67 | success(this.fixtures.basicResults) 68 | 69 | expect(successStub).to.have.been.calledOnce 70 | var args = successStub.args[0][0]; 71 | 72 | expect(args.uris.length).to.equal(1) 73 | expect(args.values.length).to.equal(1) 74 | expect(args.bnodes.length).to.equal(1) 75 | }) 76 | 77 | it('should yield an error with invalid results (documentUri)', function () { 78 | var profile = { queries: { documentUri: 'QUERY' } } 79 | var httpStub = this.sandbox.stub() 80 | var errorStub = this.sandbox.stub() 81 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 82 | 83 | sparqlClient.documentUri('', { error: errorStub }) 84 | 85 | expect(httpStub).to.have.been.calledOnce 86 | expect(httpStub.args[0][0].query).to.equal('QUERY') 87 | 88 | var success = httpStub.args[0][1].success 89 | success({ results: { data: {} } }) 90 | 91 | expect(errorStub).to.have.been.calledOnce 92 | expect(errorStub.args[0][0]).to.match(/malformed results/) 93 | }) 94 | 95 | it('should parse results (documentUri)', function () { 96 | var profile = { queries: { documentUri: 'QUERY' } } 97 | var httpStub = this.sandbox.stub() 98 | var successStub = this.sandbox.stub() 99 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 100 | 101 | sparqlClient.documentUri('', { success: successStub }) 102 | 103 | expect(httpStub).to.have.been.calledOnce 104 | expect(httpStub.args[0][0].query).to.equal('QUERY') 105 | 106 | var success = httpStub.args[0][1].success 107 | success(this.fixtures.basicResults) 108 | 109 | expect(successStub).to.have.been.calledOnce 110 | var args = successStub.args[0][0]; 111 | 112 | expect(args.uris.length).to.equal(1) 113 | expect(args.values.length).to.equal(1) 114 | expect(args.bnodes.length).to.equal(1) 115 | }) 116 | 117 | it('should yield an error with invalid results (inverse)', function () { 118 | var profile = { queries: { inverse: 'QUERY' } } 119 | var httpStub = this.sandbox.stub() 120 | var errorStub = this.sandbox.stub() 121 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 122 | 123 | sparqlClient.inverse('', { error: errorStub }) 124 | 125 | expect(httpStub).to.have.been.calledOnce 126 | expect(httpStub.args[0][0].query).to.equal('QUERY') 127 | 128 | var success = httpStub.args[0][1].success 129 | success({ results: { data: {} } }) 130 | 131 | expect(errorStub).to.have.been.calledOnce 132 | expect(errorStub.args[0][0]).to.match(/malformed results/) 133 | }) 134 | 135 | it('should parse results (inverse)', function () { 136 | var profile = { queries: { inverse: 'QUERY' } } 137 | var httpStub = this.sandbox.stub() 138 | var successStub = this.sandbox.stub() 139 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 140 | 141 | sparqlClient.inverse('', { success: successStub }) 142 | 143 | expect(httpStub).to.have.been.calledOnce 144 | expect(httpStub.args[0][0].query).to.equal('QUERY') 145 | 146 | var success = httpStub.args[0][1].success 147 | success(this.fixtures.basicResults) 148 | 149 | expect(successStub).to.have.been.calledOnce 150 | var args = successStub.args[0][0]; 151 | 152 | expect(args.uris.length).to.equal(1) 153 | expect(args.values.length).to.equal(1) 154 | expect(args.bnodes.length).to.equal(1) 155 | }) 156 | 157 | it('should parse queries and make request (inverseSameAs)', function () { 158 | var profile = { queries: { inverseSameAs: 'QUERY' } } 159 | var httpStub = this.sandbox.stub() 160 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 161 | 162 | sparqlClient.inverseSameAs('', {}) 163 | expect(httpStub).to.have.been.calledOnce 164 | expect(httpStub.args[0][0].query).to.equal('QUERY') 165 | }) 166 | 167 | it('should fallback to default queries and make request', function () { 168 | var httpStub = this.sandbox.stub() 169 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), {}) 170 | 171 | sparqlClient.bnode('', {}) 172 | expect(httpStub).to.have.been.calledOnce 173 | expect(httpStub.args[0][0].query).to.equal('SELECT DISTINCT * WHERE {<> ?property ?object}') 174 | }) 175 | 176 | it('should substitute IRIs', function () { 177 | var profile = { queries: { inverse: 'QUERY {URI}' } } 178 | var httpStub = this.sandbox.stub() 179 | var sparqlClient = sparqlClientFactory.create(this.makeFactory(httpStub), profile) 180 | 181 | sparqlClient.inverse('test', {}) 182 | expect(httpStub).to.have.been.calledOnce 183 | expect(httpStub.args[0][0].query).to.equal('QUERY test') 184 | }) 185 | }) 186 | -------------------------------------------------------------------------------- /tester.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LodLive Testing 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | --------------------------------------------------------------------------------