{"id":15213005,"url":"https://github.com/alvpickmans/forge-vuer","last_synced_at":"2026-02-25T21:05:47.583Z","repository":{"id":35119008,"uuid":"174988625","full_name":"alvpickmans/forge-vuer","owner":"alvpickmans","description":"A Vue.js Component for Forge Viewer","archived":false,"fork":false,"pushed_at":"2023-01-05T22:43:39.000Z","size":351,"stargazers_count":31,"open_issues_count":13,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-10-30T13:57:04.278Z","etag":null,"topics":["autodesk","forge","viewer","vue","vuejs"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alvpickmans.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-11T11:45:26.000Z","updated_at":"2025-10-16T03:49:18.000Z","dependencies_parsed_at":"2023-01-15T14:12:43.570Z","dependency_job_id":null,"html_url":"https://github.com/alvpickmans/forge-vuer","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/alvpickmans/forge-vuer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvpickmans%2Fforge-vuer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvpickmans%2Fforge-vuer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvpickmans%2Fforge-vuer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvpickmans%2Fforge-vuer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alvpickmans","download_url":"https://codeload.github.com/alvpickmans/forge-vuer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alvpickmans%2Fforge-vuer/sbom","scorecard":{"id":187728,"data":{"date":"2025-08-11","repo":{"name":"github.com/alvpickmans/forge-vuer","commit":"4b55818d6061b7432fbb9f5c65b97cb610ce0506"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.9,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/15 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 18 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"34 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-6chw-6frg-f759","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-566m-qj78-rww5","Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j","Warn: Project is vulnerable to: GHSA-hwj9-h5mp-3pm3","Warn: Project is vulnerable to: GHSA-p493-635q-r6gr","Warn: Project is vulnerable to: GHSA-3965-hpx2-q597","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-h9rv-jmmf-4pgx","Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-5j4c-8p2g-v4jx","Warn: Project is vulnerable to: GHSA-g3ch-rx76-35fx"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T20:06:19.337Z","repository_id":35119008,"created_at":"2025-08-16T20:06:19.337Z","updated_at":"2025-08-16T20:06:19.337Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29839984,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T20:42:33.054Z","status":"ssl_error","status_checked_at":"2026-02-25T20:42:21.322Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autodesk","forge","viewer","vue","vuejs"],"created_at":"2024-09-28T09:08:40.903Z","updated_at":"2026-02-25T21:05:47.548Z","avatar_url":"https://github.com/alvpickmans.png","language":"JavaScript","readme":"![ForgeVuer](assets/images/forgeVuerLogo.png)\n# ForgeVuer \u003c!-- omit in toc --\u003e\n\nA Vue.js component providing an easy to setup, almost *\"plug and play\"* experience for Autodesk's Forge Viewer on Vue.js\n\n- [Getting Started](#getting-started)\n  - [Prerequisites](#prerequisites)\n  - [Installing](#installing)\n- [TL;DR](#tldr)\n- [Setup](#setup)\n  - [Access Token](#access-token)\n- [Properties](#properties)\n- [Events](#events)\n  - [Forge Viewer Events](#forge-viewer-events)\n  - [ForgeVuer Events](#forgevuer-events)\n- [Custom Extensions](#custom-extensions)\n- [Versioning](#versioning)\n- [License](#license)\n\n## Getting Started\n\nThese instructions will get you started on how to install, use and customize the **ForgeVuer** component.\n\n### Prerequisites\n\n- A minimal **Vue** app to use the component.\n- The latest Autodesk Forge Viewer **version 7** styling and javascript files referenced on the html `head` section.\n\n```html\n\u003chead\u003e\n    [...]\n    \u003c!-- Autodesk Forge Viewer files --\u003e\n    \u003clink rel=\"stylesheet\" href=\"https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css\" type=\"text/css\"\u003e\n    \u003cscript src=\"https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js\"\u003e\u003c/script\u003e\n    [...]\n\u003c/head\u003e\n```\n\n### Installing\n```\nnpm install forge-vuer\n```\n\n## TL;DR\n\nA minimal working setup on a SPA application:\n\n```html\n\u003c!-- App.vue--\u003e\n\u003ctemplate\u003e\n  \u003cdiv id=\"app\"\u003e\n    \u003cforge-vuer\n      :getAccessToken=\"myGetTokenMethodAsync\"\n      :urn=\"myObjectUrn\"\n    /\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nimport ForgeVuer from 'forge-vuer';\n\nexport default {\n    name: 'app',\n    components: {\n        ForgeVuer\n    },\n    data: () =\u003e {\n        return {\n            myToken:\"{A VALID, NON_EXPIRED TOKEN CAN BE USE FOR TESTING PURPOSES}\",\n            myObjectUrn: \"dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6c2Rhc2Rhc2QvYnVubnkub2Jq\",\n        }\n    },\n    methods: {\n        myGetTokenMethodAsync: async function(onSuccess){\n            // An API call to retrieve a valid token should be\n            // done here. A backend service might need to be implemented.\n\n            // For testing purposes, a valid token can be hardcoded but will \n            // last a maximum of 1 hour (3600 seconds.)\n            let token = this.myToken;\n            let expireTimeSeconds = 3599;\n            onSuccess(token, expireTimeSeconds);\n        },\n    }\n}\n\u003c/script\u003e\n```\n\n## Setup\n\n Nevertheless, it requires some level of setup in order to have a secure and stable experience.\n\n### Access Token\n\nForge Viewer requires to be associated to a valid Forge Application, and this is achieved by the use of an **access token** retrieved using the application's **CLIENT_SECRET** and **CLIENT_ID** credentials.\n\nThese credentials **MUST NOT** be exposed on the front-end as:\n- Entails a security risk for your Forge Application.\n- Making calls to Forge API from the front-end will likely return a **Cross Origin** error.\n\nInstead, a backend service should be implemented so it securely returns a valid token and expiring time. An example of an endpoint for this purpose using **Express.js** and **Axios**:\n\n```javascript\n// Backend API\nlet app = new Express();\n\napp.use(\"/api/token\", async (req, res, next) =\u003e {\n    return axios.post(\n            \"https://developer.api.autodesk.com/authentication/v1/authenticate\",\n            {\n                client_id: \"YOUR CLIENT_ID\",\n                client_secret: \"YOUR CLIENT_SECRET\",\n                grant_type: \"client_credentials\u0026\",\n                scopes: \"data:read\"\n            });\n});\n```\n```html\n\u003c!-- SPA --\u003e\n\u003ctemplate\u003e\n\n    \u003cforge-vuer\n      [...]\n\n      @getAccessToken=\"handleAccessToken\"\n    /\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n\nexport default{\n    [...]\n\n    methods: {\n        handleAccessToken: async function(onSuccess){\n            axios.get(`/api/token`)\n            .then(response =\u003e {\n                onSuccess(response.data.access_token, response.data.expires_in);\n            })\n            .catch(error =\u003e {\n                console.log(error);\n            });\n        }\n    }\n\n    [...]\n}\n\n\u003c/script\u003e\n```\n\n\n## Properties\nThe component has some properties to configure and customize it.\n\n| Prop             | Type       | Default      | Required | Description                                                                                                                                                                                                                                                                                                   |\n| ---------------- | ---------- | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `id`             | `String`   | `forge-vuer` | `false`  | This defines the `id` attribute of the DOM element that will host the Viewer                                                                                                                                                                                                                                  |\n| `getAccessToken` | `Function` | -            | `true`   | Function that will provide a valid access token to the Viewer by calling the `onSuccess` callback.                                                                                                                                                                                                            |\n| `urn`            | `String`   | -            | `false`  | Urn of the file to load. Make sure the file has already been [translated](https://forge.autodesk.com/en/docs/model-derivative/v2/tutorials/prepare-file-for-viewer/).                                                                                                                                         |\n| `options`        | `Object`   | -            | `false`  | Options used to [initialize](https://forge.autodesk.com/en/docs/viewer/v6/reference/Viewing/Initializer/#new-initializer-options-callback) the Viewer instance. The only property that will not be used is `getAccessToken`, as it is replace by the corresponding function passed as a component's property. |\n| `headless`       | `Boolean`  | `false`      | `false`  | This property defines if the viewer is meant to be use in [headless](https://forge.autodesk.com/en/docs/viewer/v6/tutorials/headless/) mode.                                                                                                                                                                  |\n| `extensions`     | `Object`   | -            | `false`  | Object containing the custom extensions. See [custom extensions](#custom-extensions) for more detail.                                                                                                                                                                                                         |\n\n\n\n## Events\nThe component exposes two types of events to which can be subscribed: original Forge Viewer Events and Custom Events.\n\n### Forge Viewer Events\n\nAs described on Forge Viewer [API documentation](https://autodeskviewer.com/viewers/latest/docs/Autodesk.Viewing.html#events), the viewer provides several events like `SELECTION_CHANGED_EVENT`, `PROGRESS_UPDATE_EVENT`, etc. The component allows to seamlessly subscribe to these event using the familiar vue syntax `v-on:` or `@` by the convention:\n- Same name of original event but all lower cased.\n- Underscores `_` replaced by hyphens/dashes `-`.\n\nAs an example:\n\n| Original Event            | Subscribed on component   |\n| ------------------------- | ------------------------- |\n| `SELECTION_CHANGED_EVENT` | `@selection-change-event` |\n| `PROGRESS_UPDATE_EVENT`   | `@progress-update-event`  |\n\nInternally, on creation it will try to map the component's events to the corresponding on the Viewer, providing an easy interface to subscribe to any original event.\nAny data associated that an event might return is encapsulated on a single object to allow for an automated mapping. This means that your subscribing function will have a single input argument containing all parameters passed by the event.\n\n```html\n\u003c!-- SPA --\u003e\n\u003ctemplate\u003e\n\n    \u003cforge-vuer\n      [...]\n\n      @progress-update-event=\"handleProgressUpdated\"\n    /\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\n\nexport default{\n    [...]\n\n    methods: {\n        handleProgressUpdated: function(eventData){\n            console.log(`Progress: ${eventData.percentage}%`)\n        }\n    }\n\n    [...]\n}\n\n\u003c/script\u003e\n```\n\n\n### ForgeVuer Events\nAdditionally, the component provides some additional events that allows to act when certain actions happen during the component's execution.\n\n| Name                | Arguments           | Description                                                                                                                                                                                                                                        |\n| ------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `error`             | `Error`             | This event is fired whenever any error that hasn't been handle in any other way (internally by Forge emitting their events or some other of these custom events). When fired, this event will have as input the actual error that has been thrown. |\n| `documentLoading`   | -                   | Event fired when a new `urn` has been provided and the process of loading its associated document starts.                                                                                                                                          |\n| `documentLoadError` | `Error`             | Fired when Forge fails to load a document. If no function is subscribed to this event, the default `Error` event will be thrown. The `Error` passed as argument contains the Forge `errorCode` reference.*                                         |\n| `viewerStarted`     | `Viewer3D` instance | Event fired when the Viewer3D has been initialized, passing this instance as function argument.                                                                                                                                                    |\n| `modelLoading`      | -                   | Fired when the model associated with the document starts to load.                                                                                                                                                                                  |\n| `modelLoaded`       | `model`             | Fired when the model is successfully loaded. The argument is a [Model](https://forge.autodesk.com/en/docs/viewer/v6/reference/Viewing/Model/) instance.                                                                                            |\n| `modelLoadError`    | `Error`             | Fired when Forge fails to load a model. If no function is subscribed to this event, the default `Error` event will be thrown. The `Error` passed as argument contains the Forge `errorCode` reference.*                                            |\n\n\u003e *For a detailed list of Forge ErrorCodes and their meaning, visit [this blog post](https://forge.autodesk.com/cloud_and_mobile/2016/01/error-codes-in-view-and-data-api.html)\n\n## Custom Extensions (6.*)\n\nOne of the most powerful features of Autodesk Forge Viewer is the ability to add custom functionality via **Extensions**. Registering custom extensions to the component's Viewer instance can be done just through the `extensions` component property. The only difference with the common [examples](https://forge.autodesk.com/en/docs/viewer/v6/tutorials/extensions/) found is that the extension implementation must be wrapped within a function so the component can register them at runtime.\n\nThis would be a simple example of custom extension:\n```js\n// Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/extensions/#step-2-write-the-extension-code\n// my-awesome-extension.js\n\nexport default function (AutodeskViewing) {\n\n    function MyAwesomeExtension(viewer, options) {\n        AutodeskViewing.Extension.call(this, viewer, options);\n    }\n\n    MyAwesomeExtension.prototype = Object.create(AutodeskViewing.Extension.prototype);\n    MyAwesomeExtension.prototype.constructor = MyAwesomeExtension;\n\n    MyAwesomeExtension.prototype.load = function () {\n        alert('MyAwesomeExtension is loaded!');\n        return true;\n    };\n\n    MyAwesomeExtension.prototype.unload = function () {\n        alert('MyAwesomeExtension is now unloaded!');\n        return true;\n    };\n\n    // Is not necessary to implicitly register the extension\n    // as this is handled by the component.\n    // Autodesk.Viewing.theExtensionManager.registerExtension('MyAwesomeExtension', MyAwesomeExtension);\n\n    // IMPORTANT to return the extension function itself.\n    return MyAwesomeExtension;\n\n}\n```\n\nIf you are comfortable and able to use ES6 classes, an extension could also be written as:\n```js\n// Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/toolbar-button/#step-1-detect-the-toolbar\n// my-custom-toolbar.js\n\nexport default function (AutodeskViewing) {\n\n    return class ToolbarExtension extends AutodeskViewing.Extension {\n        viewer;\n        options;\n        subToolbar;\n\n        constructor(viewer, options) {\n            super(viewer, options);\n            this.viewer = viewer;\n            this.options = options;\n        }\n        \n        load = function () {\n            \n            if (this.viewer.toolbar) {\n                // Toolbar is already available, create the UI\n                this.createUI();\n            } else {\n                // Toolbar hasn't been created yet, wait until we get notification of its creation\n                this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this);\n                this.viewer.addEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);\n            }\n\n            return true;\n        }\n\n        unload = function () {\n            this.viewer.toolbar.removeControl(this.subToolbar);\n            return true;\n        };\n\n        onToolbarCreated = function() {\n            this.viewer.removeEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);\n            this.onToolbarCreatedBinded = null;\n            this.createUI();\n        };\n\n        createUI = function() {\n            var viewer = this.viewer;\n\n            // Button 1\n            var button1 = new AutodeskViewing.UI.Button('my-view-front-button');\n            button1.onClick = function() {\n                viewer.setViewCube('front');\n            };\n            button1.addClass('my-view-front-button');\n            button1.setToolTip('View front');\n\n            // Button 2\n            var button2 = new AutodeskViewing.UI.Button('my-view-back-button');\n            button2.onClick = function() {\n                viewer.setViewCube('back');\n            };\n            button2.addClass('my-view-back-button');\n            button2.setToolTip('View Back');\n\n            // SubToolbar\n            this.subToolbar = new AutodeskViewing.UI.ControlGroup('my-custom-view-toolbar');\n            this.subToolbar.addControl(button1);\n            this.subToolbar.addControl(button2);\n\n            viewer.toolbar.addControl(this.subToolbar);\n        };\n    }\n\n}\n```\n\nThen, on the component implementation we just need to set the `extension` property as an object where `keys` will be the registered `id` of the extensions, and the values the imported functions.\n\n```html\n\u003c!-- SPA --\u003e\n\u003ctemplate\u003e\n    \u003cforge-vuer\n      [...]\n\n        extensions=\"{\n            'myAwesomeExtension': myAwesomeExtension,\n            'myCustomToolbar': myCustomToolbar,\n        }\"\n    /\u003e\n\u003c/template\u003e\n\n\u003cscript\u003e\nimport myAwesomeExtension from './path/to/my-awesome-extension.js';\nimport myCustomToolbar from './path/to/my-custom-toolbar.js';\n\nexport default{\n    [...]\n}\n\n\u003c/script\u003e\n```\n\n## Custom Extensions (7.*)\n\nThere has been [breaking changes](https://forge.autodesk.com/blog/breaking-change-forge-viewerloadextension) since 6.*. Also, you need [CSS classes](https://forge.autodesk.com/blog/what-icons-are-provided-viewer-stylesheet) to set the icon of the buttons.\n\n```js\n// Example from https://forge.autodesk.com/en/docs/viewer/v6/tutorials/toolbar-button/#step-1-detect-the-toolbar\n// my-custom-toolbar.js\n\nexport default function (AutodeskViewing) {\n\n    return class ToolbarExtension extends AutodeskViewing.Extension {\n        viewer;\n        options;\n        subToolbar;\n\n        constructor(viewer, options) {\n            super(viewer, options);\n            this.viewer = viewer;\n            this.options = options;\n        }\n\n        load = function () {\n            if (this.viewer.toolbar) {\n                // Toolbar is already available, create the UI\n                this.createUI();\n            } else {\n                // Toolbar hasn't been created yet, wait until we get notification of its creation\n                this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this);\n                this.viewer.addEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);\n            }\n\n            return true;\n        }\n\n        unload = function () {\n            this.viewer.toolbar.removeControl(this.subToolbar);\n            return true;\n        };\n\n        onToolbarCreated = function () {\n            this.viewer.removeEventListener(AutodeskViewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded);\n            this.onToolbarCreatedBinded = null;\n            this.createUI();\n        };\n\n        createUI = async function () {\n            let viewer = this.viewer;\n            const vC = await viewer.loadExtension('Autodesk.ViewCubeUi');\n\n            // Button 1\n            let button1 = new AutodeskViewing.UI.Button('my-view-front-button');\n            button1.onClick = function () {\n                vC.setViewCube('front');\n            };\n            button1.addClass('my-view-front-button');\n            button1.setToolTip('View front');\n            button1.setIcon('adsk-icon-first'); \n\n            // Button 2\n            let button2 = new AutodeskViewing.UI.Button('my-view-back-button');\n            button2.onClick = function () {\n                vC.setViewCube('back');\n            };\n            button2.addClass('my-view-back-button');\n            button2.setToolTip('View Back');\n            button2.setIcon('adsk-icon-second');\n\n            // SubToolbar\n            this.subToolbar = new AutodeskViewing.UI.ControlGroup('my-custom-view-toolbar');\n            this.subToolbar.addControl(button1);\n            this.subToolbar.addControl(button2);\n\n            viewer.toolbar.addControl(this.subToolbar);\n        };\n    }\n}\n```\n\nMoreover, the function for checking load module has been changed (See `/services/Utils.js`):\n```js\n        // If extension already registered\n        if (AutodeskViewing.theExtensionManager.isAvailable(name)) {\n            registeredExtensions.push(name);\n            continue;\n        }\n```\n\n## Detailed implementation note (nuxt.js, 2 legged authtication, OSS bucket approch)\n\nNote that Hub approch requires 3 legged oauth. If you are not going to implement redirection and user management, you can use OSS bucket approch instead.\nFollow session **Access Token** and perform a online 2 legged or 3 legged authentication.\nIf you are using Hub approch, follow [this guide](https://github.com/Autodesk-Forge/forge-derivatives-explorer) or upload files [here](https://derivatives.autodesk.io/), [a360](https://a360.autodesk.com/drive/app/) or [another viewer](https://viewer.autodesk.com/)\nIf you are using Bucket approch, follow [this guide](https://forge.autodesk.com/en/docs/data/v2/tutorials/app-managed-bucket/). If you are feeling puzzled, read [this article](https://forge.autodesk.com/blog/oss-manager-migrated-autodeskio-server) and manually upload the files [in their new website](https://oss-manager.autodesk.io/).\n\nIf you are using plain Vue, `/sample/index.html` will be enough for you. Host it on a web host, host domain must match with the app in forge web console.\nIf you are using SSR framework (e.g. [Nuxt](https://nuxtjs.org/) ), you are recommended to directly copy the source codes in `/src` into `/components`, even with inner folder (i.e. `/components/forge`). `/src/index.js` can be omited, as nuxt will handle it instead.\nThen wrap it into a plugin (e.g. `/plugins/forge-vuer.js`):\n\n```js\nimport Vue from 'vue';\n//import ForgeVuer from 'forge-vuer';\nimport ForgeVuer from '~/components/forge/ForgeVuer'\n\nVue.component('forge-vuer', ForgeVuer);\n```\n\nSince you have no direct access in head session, you can use `head()` to tell nuxt to add them. ([Article](https://nuxtjs.org/api/pages-head/)) \nAdding them into vue page will minimalize the effect. Extensions can be a k-v map e.g. `/pages/forge.vue`:\n```vue\n\u003ctemplate\u003e \n    \u003cno-ssr placeholder=\"Loading...\"\u003e\n        \u003cforge-vuer\n          :getAccessToken=\"handleAccessToken\"\n          :urn=\"myObjectUrn\"\n          @progress-update-event=\"updateProgress\"\n          @selection-changed-event=\"spamLog\"\n          @viewerStarted=\"spamLog\"\n          @error=\"errorLog\"\n          :style=\"mapStyle\"\n          :extensions=\"extensions\"\n        /\u003e\n    \u003c/no-ssr\u003e\n\u003c/template\u003e\n\u003cscripts\u003e\n\n\u003cscript\u003e\nimport myAwesomeExtension from \"~/components/forge/extensions/myAwesomeExtension\";\nimport myCustomToolbar from \"~/components/forge/extensions/myCustomToolbar\";\n...\nexport default {\n    head() {\n        return {\n        script: [\n            {\n            src:\n                \"https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js\"\n            } //defer: true\n        ],\n        link: [\n            {\n            rel: \"stylesheet\",\n            href:\n                \"https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css\"\n            }\n        ]\n        };\n    },\n    data() {\n        return {\n            tokenPkg: {},\n            treeNodePkg: {},\n            modelProgress: 0,\n            extensions: { \n                myAwesomeExtension, \n                myCustomToolbar \n            }\n        };\n    },\n  ...\n\u003c/scripts\u003e\n```\n\nFinally tell nuxt to load the plugin with SSR disabled (`nuxt.config.js`):\n```js\n  /*\n  ** Plugins to load before mounting the App\n  */\n  plugins: [\n    //'@/plugins/vuetify',\n    //...\n    { src: '@/plugins/forge-vuer', ssr: false },\n  ],\n```\n\n## Versioning\n\nWe use [SemVer](http://semver.org/) for versioning.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvpickmans%2Fforge-vuer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falvpickmans%2Fforge-vuer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falvpickmans%2Fforge-vuer/lists"}